Adding configuration support and changing 'couchrest-type' key to 'model' along with config options
This commit is contained in:
parent
5c21de8586
commit
85cd1308bc
|
@ -1,6 +1,8 @@
|
||||||
== Next Version
|
== Next Version
|
||||||
|
|
||||||
* Major enhancements
|
* Major enhancements
|
||||||
|
* IMPORTANT: Model's class name key changed from 'couchrest-type' to 'model'
|
||||||
|
* Support for configuration module and "model_type_key" option for overriding model's type key
|
||||||
|
|
||||||
* Minor enhancements
|
* Minor enhancements
|
||||||
* Fixing find("") issue (thanks epochwolf)
|
* Fixing find("") issue (thanks epochwolf)
|
||||||
|
|
|
@ -4,6 +4,7 @@ module CouchRest
|
||||||
|
|
||||||
extend ActiveModel::Naming
|
extend ActiveModel::Naming
|
||||||
|
|
||||||
|
include CouchRest::Model::Configuration
|
||||||
include CouchRest::Model::Persistence
|
include CouchRest::Model::Persistence
|
||||||
include CouchRest::Model::Callbacks
|
include CouchRest::Model::Callbacks
|
||||||
include CouchRest::Model::DocumentQueries
|
include CouchRest::Model::DocumentQueries
|
||||||
|
@ -37,7 +38,7 @@ module CouchRest
|
||||||
|
|
||||||
# Accessors
|
# Accessors
|
||||||
attr_accessor :casted_by
|
attr_accessor :casted_by
|
||||||
|
|
||||||
|
|
||||||
# Instantiate a new CouchRest::Model::Base by preparing all properties
|
# Instantiate a new CouchRest::Model::Base by preparing all properties
|
||||||
# using the provided document hash.
|
# using the provided document hash.
|
||||||
|
@ -50,7 +51,7 @@ module CouchRest
|
||||||
prepare_all_attributes(doc, options)
|
prepare_all_attributes(doc, options)
|
||||||
super(doc)
|
super(doc)
|
||||||
unless self['_id'] && self['_rev']
|
unless self['_id'] && self['_rev']
|
||||||
self['couchrest-type'] = self.class.to_s
|
self[self.model_type_key] = self.class.to_s
|
||||||
end
|
end
|
||||||
after_initialize if respond_to?(:after_initialize)
|
after_initialize if respond_to?(:after_initialize)
|
||||||
end
|
end
|
||||||
|
|
49
lib/couchrest/model/configuration.rb
Normal file
49
lib/couchrest/model/configuration.rb
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
module CouchRest
|
||||||
|
|
||||||
|
# CouchRest Model Configuration support, stolen from Carrierwave by jnicklas
|
||||||
|
# http://github.com/jnicklas/carrierwave/blob/master/lib/carrierwave/uploader/configuration.rb
|
||||||
|
|
||||||
|
module Model
|
||||||
|
module Configuration
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
add_config :model_type_key
|
||||||
|
|
||||||
|
configure do |config|
|
||||||
|
config.model_type_key = 'model'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
|
||||||
|
def add_config(name)
|
||||||
|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
|
||||||
|
def self.#{name}(value=nil)
|
||||||
|
@#{name} = value if value
|
||||||
|
return @#{name} if self.object_id == #{self.object_id} || defined?(@#{name})
|
||||||
|
name = superclass.#{name}
|
||||||
|
return nil if name.nil? && !instance_variable_defined?("@#{name}")
|
||||||
|
@#{name} = name && !name.is_a?(Module) && !name.is_a?(Symbol) && !name.is_a?(Numeric) && !name.is_a?(TrueClass) && !name.is_a?(FalseClass) ? name.dup : name
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.#{name}=(value)
|
||||||
|
@#{name} = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def #{name}
|
||||||
|
self.class.#{name}
|
||||||
|
end
|
||||||
|
RUBY
|
||||||
|
end
|
||||||
|
|
||||||
|
def configure
|
||||||
|
yield self
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ module CouchRest
|
||||||
"views" => {
|
"views" => {
|
||||||
'all' => {
|
'all' => {
|
||||||
'map' => "function(doc) {
|
'map' => "function(doc) {
|
||||||
if (doc['couchrest-type'] == '#{self.to_s}') {
|
if (doc['#{self.model_type_key}'] == '#{self.to_s}') {
|
||||||
emit(doc['_id'],1);
|
emit(doc['_id'],1);
|
||||||
}
|
}
|
||||||
}"
|
}"
|
||||||
|
|
|
@ -8,21 +8,21 @@ module CouchRest
|
||||||
|
|
||||||
module ClassMethods
|
module ClassMethods
|
||||||
|
|
||||||
# Load all documents that have the "couchrest-type" field equal to the
|
# Load all documents that have the model_type_key's field equal to the
|
||||||
# name of the current class. Take the standard set of
|
# name of the current class. Take the standard set of
|
||||||
# CouchRest::Database#view options.
|
# CouchRest::Database#view options.
|
||||||
def all(opts = {}, &block)
|
def all(opts = {}, &block)
|
||||||
view(:all, opts, &block)
|
view(:all, opts, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the number of documents that have the "couchrest-type" field
|
# Returns the number of documents that have the model_type_key's field
|
||||||
# equal to the name of the current class. Takes the standard set of
|
# equal to the name of the current class. Takes the standard set of
|
||||||
# CouchRest::Database#view options
|
# CouchRest::Database#view options
|
||||||
def count(opts = {}, &block)
|
def count(opts = {}, &block)
|
||||||
all({:raw => true, :limit => 0}.merge(opts), &block)['total_rows']
|
all({:raw => true, :limit => 0}.merge(opts), &block)['total_rows']
|
||||||
end
|
end
|
||||||
|
|
||||||
# Load the first document that have the "couchrest-type" field equal to
|
# Load the first document that have the model_type_key's field equal to
|
||||||
# the name of the current class.
|
# the name of the current class.
|
||||||
#
|
#
|
||||||
# ==== Returns
|
# ==== Returns
|
||||||
|
|
|
@ -97,7 +97,7 @@ module CouchRest
|
||||||
# ==== Returns
|
# ==== Returns
|
||||||
# a document instance
|
# a document instance
|
||||||
def create_from_database(doc = {})
|
def create_from_database(doc = {})
|
||||||
base = (doc['couchrest-type'].blank? || doc['couchrest-type'] == self.to_s) ? self : doc['couchrest-type'].constantize
|
base = (doc[model_type_key].blank? || doc[model_type_key] == self.to_s) ? self : doc[model_type_key].constantize
|
||||||
base.new(doc, :directly_set_attributes => true)
|
base.new(doc, :directly_set_attributes => true)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ module CouchRest
|
||||||
# view_by :tags,
|
# view_by :tags,
|
||||||
# :map =>
|
# :map =>
|
||||||
# "function(doc) {
|
# "function(doc) {
|
||||||
# if (doc['couchrest-type'] == 'Post' && doc.tags) {
|
# if (doc['model'] == 'Post' && doc.tags) {
|
||||||
# doc.tags.forEach(function(tag){
|
# doc.tags.forEach(function(tag){
|
||||||
# emit(doc.tag, 1);
|
# emit(doc.tag, 1);
|
||||||
# });
|
# });
|
||||||
|
@ -39,7 +39,7 @@ module CouchRest
|
||||||
# function:
|
# function:
|
||||||
#
|
#
|
||||||
# function(doc) {
|
# function(doc) {
|
||||||
# if (doc['couchrest-type'] == 'Post' && doc.date) {
|
# if (doc['model'] == 'Post' && doc.date) {
|
||||||
# emit(doc.date, null);
|
# emit(doc.date, null);
|
||||||
# }
|
# }
|
||||||
# }
|
# }
|
||||||
|
@ -77,7 +77,7 @@ module CouchRest
|
||||||
ducktype = opts.delete(:ducktype)
|
ducktype = opts.delete(:ducktype)
|
||||||
unless ducktype || opts[:map]
|
unless ducktype || opts[:map]
|
||||||
opts[:guards] ||= []
|
opts[:guards] ||= []
|
||||||
opts[:guards].push "(doc['couchrest-type'] == '#{self.to_s}')"
|
opts[:guards].push "(doc['#{model_type_key}'] == '#{self.to_s}')"
|
||||||
end
|
end
|
||||||
keys.push opts
|
keys.push opts
|
||||||
design_doc.view_by(*keys)
|
design_doc.view_by(*keys)
|
||||||
|
|
|
@ -48,6 +48,7 @@ require "couchrest/model/collection"
|
||||||
require "couchrest/model/attribute_protection"
|
require "couchrest/model/attribute_protection"
|
||||||
require "couchrest/model/attributes"
|
require "couchrest/model/attributes"
|
||||||
require "couchrest/model/associations"
|
require "couchrest/model/associations"
|
||||||
|
require "couchrest/model/configuration"
|
||||||
|
|
||||||
# Monkey patches applied to couchrest
|
# Monkey patches applied to couchrest
|
||||||
require "couchrest/model/support/couchrest"
|
require "couchrest/model/support/couchrest"
|
||||||
|
|
|
@ -150,7 +150,7 @@ describe "Model Attributes" do
|
||||||
it "Base#all should not strip protected attributes" do
|
it "Base#all should not strip protected attributes" do
|
||||||
# all creates a CollectionProxy
|
# all creates a CollectionProxy
|
||||||
docs = WithProtected.all(:key => @user.id)
|
docs = WithProtected.all(:key => @user.id)
|
||||||
docs.size.should == 1
|
docs.length.should == 1
|
||||||
reloaded = docs.first
|
reloaded = docs.first
|
||||||
verify_attrs reloaded
|
verify_attrs reloaded
|
||||||
end
|
end
|
||||||
|
|
|
@ -36,7 +36,7 @@ describe "Model Base" do
|
||||||
|
|
||||||
it "should not failed on a nil value in argument" do
|
it "should not failed on a nil value in argument" do
|
||||||
@obj = Basic.new(nil)
|
@obj = Basic.new(nil)
|
||||||
@obj.should == { 'couchrest-type' => 'Basic' }
|
@obj.should_not be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
87
spec/couchrest/configuration_spec.rb
Normal file
87
spec/couchrest/configuration_spec.rb
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
require File.expand_path('../../spec_helper', __FILE__)
|
||||||
|
require File.join(FIXTURE_PATH, 'more', 'cat')
|
||||||
|
|
||||||
|
describe CouchRest::Model::Base do
|
||||||
|
|
||||||
|
before do
|
||||||
|
@class = Class.new(CouchRest::Model::Base)
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.configure' do
|
||||||
|
it "should set a configuration parameter" do
|
||||||
|
@class.add_config :foo_bar
|
||||||
|
@class.configure do |config|
|
||||||
|
config.foo_bar = 'monkey'
|
||||||
|
end
|
||||||
|
@class.foo_bar.should == 'monkey'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '.add_config' do
|
||||||
|
|
||||||
|
it "should add a class level accessor" do
|
||||||
|
@class.add_config :foo_bar
|
||||||
|
@class.foo_bar = 'foo'
|
||||||
|
@class.foo_bar.should == 'foo'
|
||||||
|
end
|
||||||
|
|
||||||
|
['foo', :foo, 45, ['foo', :bar]].each do |val|
|
||||||
|
it "should be inheritable for a #{val.class}" do
|
||||||
|
@class.add_config :foo_bar
|
||||||
|
@child_class = Class.new(@class)
|
||||||
|
|
||||||
|
@class.foo_bar = val
|
||||||
|
@class.foo_bar.should == val
|
||||||
|
@child_class.foo_bar.should == val
|
||||||
|
|
||||||
|
@child_class.foo_bar = "bar"
|
||||||
|
@child_class.foo_bar.should == "bar"
|
||||||
|
|
||||||
|
@class.foo_bar.should == val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
it "should add an instance level accessor" do
|
||||||
|
@class.add_config :foo_bar
|
||||||
|
@class.foo_bar = 'foo'
|
||||||
|
@class.new.foo_bar.should == 'foo'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should add a convenient in-class setter" do
|
||||||
|
@class.add_config :foo_bar
|
||||||
|
@class.foo_bar "monkey"
|
||||||
|
@class.foo_bar.should == "monkey"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe "General examples" do
|
||||||
|
|
||||||
|
before(:all) do
|
||||||
|
@default_model_key = 'model'
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should set default configuration options on Model::Base" do
|
||||||
|
CouchRest::Model::Base.model_type_key.should eql(@default_model_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should provide options from instance" do
|
||||||
|
cat = Cat.new
|
||||||
|
cat.model_type_key.should eql(@default_model_key)
|
||||||
|
end
|
||||||
|
|
||||||
|
it "should be possible to override on class using configure method" do
|
||||||
|
Cat.instance_eval do
|
||||||
|
configure do |config|
|
||||||
|
config.model_type_key = 'cat-type'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
CouchRest::Model::Base.model_type_key.should eql(@default_model_key)
|
||||||
|
Cat.model_type_key.should eql('cat-type')
|
||||||
|
cat = Cat.new
|
||||||
|
cat.model_type_key.should eql('cat-type')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -25,7 +25,7 @@ describe "Model Persistence" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should instantialize document of different type" do
|
it "should instantialize document of different type" do
|
||||||
doc = Article.create_from_database({'_id' => 'testitem2', '_rev' => 123, 'couchrest-type' => 'WithTemplateAndUniqueID', 'name' => 'my test'})
|
doc = Article.create_from_database({'_id' => 'testitem2', '_rev' => 123, Article.model_type_key => 'WithTemplateAndUniqueID', 'name' => 'my test'})
|
||||||
doc.class.should eql(WithTemplateAndUniqueID)
|
doc.class.should eql(WithTemplateAndUniqueID)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ describe "Model Persistence" do
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should set the type" do
|
it "should set the type" do
|
||||||
@sobj['couchrest-type'].should == 'Basic'
|
@sobj[@sobj.model_type_key].should == 'Basic'
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should accept true or false on save for validation" do
|
it "should accept true or false on save for validation" do
|
||||||
|
|
|
@ -92,8 +92,8 @@ describe "Subclassing a Model" do
|
||||||
OnlineCourse.design_doc['views'].keys.should_not include('by_title')
|
OnlineCourse.design_doc['views'].keys.should_not include('by_title')
|
||||||
end
|
end
|
||||||
|
|
||||||
it "should have an all view with a guard clause for couchrest-type == subclass name in the map function" do
|
it "should have an all view with a guard clause for model == subclass name in the map function" do
|
||||||
OnlineCourse.design_doc['views']['all']['map'].should =~ /if \(doc\['couchrest-type'\] == 'OnlineCourse'\)/
|
OnlineCourse.design_doc['views']['all']['map'].should =~ /if \(doc\['model'\] == 'OnlineCourse'\)/
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
2
spec/fixtures/more/article.rb
vendored
2
spec/fixtures/more/article.rb
vendored
|
@ -9,7 +9,7 @@ class Article < CouchRest::Model::Base
|
||||||
view_by :tags,
|
view_by :tags,
|
||||||
:map =>
|
:map =>
|
||||||
"function(doc) {
|
"function(doc) {
|
||||||
if (doc['couchrest-type'] == 'Article' && doc.tags) {
|
if (doc['#{model_type_key}'] == 'Article' && doc.tags) {
|
||||||
doc.tags.forEach(function(tag){
|
doc.tags.forEach(function(tag){
|
||||||
emit(tag, 1);
|
emit(tag, 1);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue