diff --git a/history.txt b/history.txt index d7e157f..13199f0 100644 --- a/history.txt +++ b/history.txt @@ -1,6 +1,8 @@ == Next Version * 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 * Fixing find("") issue (thanks epochwolf) diff --git a/lib/couchrest/model/base.rb b/lib/couchrest/model/base.rb index 2a5c602..8a7350b 100644 --- a/lib/couchrest/model/base.rb +++ b/lib/couchrest/model/base.rb @@ -4,6 +4,7 @@ module CouchRest extend ActiveModel::Naming + include CouchRest::Model::Configuration include CouchRest::Model::Persistence include CouchRest::Model::Callbacks include CouchRest::Model::DocumentQueries @@ -37,7 +38,7 @@ module CouchRest # Accessors attr_accessor :casted_by - + # Instantiate a new CouchRest::Model::Base by preparing all properties # using the provided document hash. @@ -50,7 +51,7 @@ module CouchRest prepare_all_attributes(doc, options) super(doc) unless self['_id'] && self['_rev'] - self['couchrest-type'] = self.class.to_s + self[self.model_type_key] = self.class.to_s end after_initialize if respond_to?(:after_initialize) end diff --git a/lib/couchrest/model/configuration.rb b/lib/couchrest/model/configuration.rb new file mode 100644 index 0000000..c468a02 --- /dev/null +++ b/lib/couchrest/model/configuration.rb @@ -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 + + diff --git a/lib/couchrest/model/design_doc.rb b/lib/couchrest/model/design_doc.rb index 244fba0..cedba14 100644 --- a/lib/couchrest/model/design_doc.rb +++ b/lib/couchrest/model/design_doc.rb @@ -31,7 +31,7 @@ module CouchRest "views" => { 'all' => { 'map' => "function(doc) { - if (doc['couchrest-type'] == '#{self.to_s}') { + if (doc['#{self.model_type_key}'] == '#{self.to_s}') { emit(doc['_id'],1); } }" diff --git a/lib/couchrest/model/document_queries.rb b/lib/couchrest/model/document_queries.rb index 3cc2673..48ec485 100644 --- a/lib/couchrest/model/document_queries.rb +++ b/lib/couchrest/model/document_queries.rb @@ -8,21 +8,21 @@ module CouchRest 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 # CouchRest::Database#view options. def all(opts = {}, &block) view(:all, opts, &block) 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 # CouchRest::Database#view options def count(opts = {}, &block) all({:raw => true, :limit => 0}.merge(opts), &block)['total_rows'] 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. # # ==== Returns diff --git a/lib/couchrest/model/persistence.rb b/lib/couchrest/model/persistence.rb index a48955a..372148d 100644 --- a/lib/couchrest/model/persistence.rb +++ b/lib/couchrest/model/persistence.rb @@ -97,7 +97,7 @@ module CouchRest # ==== Returns # a document instance 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) end diff --git a/lib/couchrest/model/views.rb b/lib/couchrest/model/views.rb index 68e55bd..74a8660 100644 --- a/lib/couchrest/model/views.rb +++ b/lib/couchrest/model/views.rb @@ -23,7 +23,7 @@ module CouchRest # view_by :tags, # :map => # "function(doc) { - # if (doc['couchrest-type'] == 'Post' && doc.tags) { + # if (doc['model'] == 'Post' && doc.tags) { # doc.tags.forEach(function(tag){ # emit(doc.tag, 1); # }); @@ -39,7 +39,7 @@ module CouchRest # function: # # function(doc) { - # if (doc['couchrest-type'] == 'Post' && doc.date) { + # if (doc['model'] == 'Post' && doc.date) { # emit(doc.date, null); # } # } @@ -77,7 +77,7 @@ module CouchRest ducktype = opts.delete(:ducktype) unless ducktype || opts[:map] opts[:guards] ||= [] - opts[:guards].push "(doc['couchrest-type'] == '#{self.to_s}')" + opts[:guards].push "(doc['#{model_type_key}'] == '#{self.to_s}')" end keys.push opts design_doc.view_by(*keys) diff --git a/lib/couchrest_model.rb b/lib/couchrest_model.rb index 0a3d657..d161368 100644 --- a/lib/couchrest_model.rb +++ b/lib/couchrest_model.rb @@ -48,6 +48,7 @@ require "couchrest/model/collection" require "couchrest/model/attribute_protection" require "couchrest/model/attributes" require "couchrest/model/associations" +require "couchrest/model/configuration" # Monkey patches applied to couchrest require "couchrest/model/support/couchrest" diff --git a/spec/couchrest/attribute_protection_spec.rb b/spec/couchrest/attribute_protection_spec.rb index c940b93..47e50a8 100644 --- a/spec/couchrest/attribute_protection_spec.rb +++ b/spec/couchrest/attribute_protection_spec.rb @@ -150,7 +150,7 @@ describe "Model Attributes" do it "Base#all should not strip protected attributes" do # all creates a CollectionProxy docs = WithProtected.all(:key => @user.id) - docs.size.should == 1 + docs.length.should == 1 reloaded = docs.first verify_attrs reloaded end diff --git a/spec/couchrest/base_spec.rb b/spec/couchrest/base_spec.rb index cd5fd4d..e10d9be 100644 --- a/spec/couchrest/base_spec.rb +++ b/spec/couchrest/base_spec.rb @@ -36,7 +36,7 @@ describe "Model Base" do it "should not failed on a nil value in argument" do @obj = Basic.new(nil) - @obj.should == { 'couchrest-type' => 'Basic' } + @obj.should_not be_nil end end diff --git a/spec/couchrest/configuration_spec.rb b/spec/couchrest/configuration_spec.rb new file mode 100644 index 0000000..d0e681b --- /dev/null +++ b/spec/couchrest/configuration_spec.rb @@ -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 diff --git a/spec/couchrest/persistence_spec.rb b/spec/couchrest/persistence_spec.rb index 6723653..9c8cb2e 100644 --- a/spec/couchrest/persistence_spec.rb +++ b/spec/couchrest/persistence_spec.rb @@ -25,7 +25,7 @@ describe "Model Persistence" do end 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) end @@ -114,7 +114,7 @@ describe "Model Persistence" do end it "should set the type" do - @sobj['couchrest-type'].should == 'Basic' + @sobj[@sobj.model_type_key].should == 'Basic' end it "should accept true or false on save for validation" do diff --git a/spec/couchrest/subclass_spec.rb b/spec/couchrest/subclass_spec.rb index 8344b90..333c383 100644 --- a/spec/couchrest/subclass_spec.rb +++ b/spec/couchrest/subclass_spec.rb @@ -92,8 +92,8 @@ describe "Subclassing a Model" do OnlineCourse.design_doc['views'].keys.should_not include('by_title') end - it "should have an all view with a guard clause for couchrest-type == subclass name in the map function" do - OnlineCourse.design_doc['views']['all']['map'].should =~ /if \(doc\['couchrest-type'\] == 'OnlineCourse'\)/ + 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\['model'\] == 'OnlineCourse'\)/ end end diff --git a/spec/fixtures/more/article.rb b/spec/fixtures/more/article.rb index 3a7a405..ef8ce2a 100644 --- a/spec/fixtures/more/article.rb +++ b/spec/fixtures/more/article.rb @@ -9,7 +9,7 @@ class Article < CouchRest::Model::Base view_by :tags, :map => "function(doc) { - if (doc['couchrest-type'] == 'Article' && doc.tags) { + if (doc['#{model_type_key}'] == 'Article' && doc.tags) { doc.tags.forEach(function(tag){ emit(tag, 1); });