diff --git a/history.md b/history.md index 8c457e9..62b8542 100644 --- a/history.md +++ b/history.md @@ -2,6 +2,9 @@ ## 1.1.0 - 2011-06-XX +* Major Fixes + * CastedModel no longer requires a Hash. Automatically includes all required methods. + * Minor Fixes * Validation callbacks now support context (thanks kostia) * Document comparisons now performed using database and document ID (pointer by neocsr) diff --git a/lib/couchrest/model/base.rb b/lib/couchrest/model/base.rb index 7b6255a..66f3b66 100644 --- a/lib/couchrest/model/base.rb +++ b/lib/couchrest/model/base.rb @@ -81,10 +81,6 @@ module CouchRest super end - def persisted? - !new? - end - def to_key new? ? nil : [id] end diff --git a/lib/couchrest/model/casted_model.rb b/lib/couchrest/model/casted_model.rb index 0074e18..e445f96 100644 --- a/lib/couchrest/model/casted_model.rb +++ b/lib/couchrest/model/casted_model.rb @@ -1,9 +1,9 @@ module CouchRest::Model module CastedModel - extend ActiveSupport::Concern included do + include CouchRest::Attributes include CouchRest::Model::Configuration include CouchRest::Model::Properties include CouchRest::Model::PropertyProtection @@ -19,23 +19,17 @@ module CouchRest::Model def base_doc? false # Can never be base doc! end + + # Initialize a new Casted Model. Accepts the same + # options as CouchRest::Model::Base for preparing and initializing + # attributes. + def initialize(keys = {}, options = {}) + super() + prepare_all_attributes(keys, options) + end end end - def initialize(keys = {}) - raise StandardError unless self.is_a? Hash - prepare_all_attributes(keys) - super() - end - - def []= key, value - super(key.to_s, value) - end - - def [] key - super(key.to_s) - end - # False if the casted model has already # been saved in the containing document def new? diff --git a/lib/couchrest/model/persistence.rb b/lib/couchrest/model/persistence.rb index 03a9ee8..a9e0a75 100644 --- a/lib/couchrest/model/persistence.rb +++ b/lib/couchrest/model/persistence.rb @@ -28,7 +28,8 @@ module CouchRest # Trigger the callbacks (before, after, around) # only if the document isn't new def update(options = {}) - raise "Calling #{self.class.name}#update on document that has not been created!" if self.new? + raise "Cannot save a destroyed document!" if destroyed? + raise "Calling #{self.class.name}#update on document that has not been created!" if new? return false unless perform_validations(options) return true if !self.disable_dirty && !self.changed? _run_update_callbacks do @@ -69,6 +70,10 @@ module CouchRest !!@_destroyed end + def persisted? + !new? && !destroyed? + end + # Update the document's attributes and save. For example: # # doc.update_attributes :name => "Fred" diff --git a/lib/couchrest/model/properties.rb b/lib/couchrest/model/properties.rb index 133e9b9..93cd447 100644 --- a/lib/couchrest/model/properties.rb +++ b/lib/couchrest/model/properties.rb @@ -168,7 +168,7 @@ module CouchRest # check if this property is going to casted type = options.delete(:type) || options.delete(:cast_as) if block_given? - type = Class.new(Hash) do + type = Class.new do include CastedModel end if block.arity == 1 # Traditional, with options diff --git a/spec/fixtures/models/cat.rb b/spec/fixtures/models/cat.rb index 481bc37..d8e5584 100644 --- a/spec/fixtures/models/cat.rb +++ b/spec/fixtures/models/cat.rb @@ -1,6 +1,6 @@ -class CatToy < Hash - include ::CouchRest::Model::CastedModel +class CatToy + include CouchRest::Model::CastedModel property :name diff --git a/spec/unit/casted_model_spec.rb b/spec/unit/casted_model_spec.rb index 9e47ab0..5c8b6f5 100644 --- a/spec/unit/casted_model_spec.rb +++ b/spec/unit/casted_model_spec.rb @@ -1,7 +1,7 @@ # encoding: utf-8 require "spec_helper" -class WithCastedModelMixin < Hash +class WithCastedModelMixin include CouchRest::Model::CastedModel property :name property :no_value @@ -9,11 +9,17 @@ class WithCastedModelMixin < Hash property :casted_attribute, WithCastedModelMixin end +class OldFashionedMixin < Hash + include CouchRest::Model::CastedModel + property :name +end + class DummyModel < CouchRest::Model::Base use_database TEST_SERVER.default_database raise "Default DB not set" if TEST_SERVER.default_database.nil? property :casted_attribute, WithCastedModelMixin property :keywords, [String] + property :old_casted_attribute, OldFashionedMixin property :sub_models do |child| child.property :title end @@ -22,7 +28,7 @@ class DummyModel < CouchRest::Model::Base end end -class WithCastedCallBackModel < Hash +class WithCastedCallBackModel include CouchRest::Model::CastedModel property :name property :run_before_validation @@ -155,6 +161,33 @@ describe CouchRest::Model::CastedModel do end end + # Basic testing for an old fashioned casted hash + describe "old hash casted as attribute" do + before :each do + @obj = DummyModel.new(:old_casted_attribute => {:name => 'Testing'}) + @casted_obj = @obj.old_casted_attribute + end + it "should be available from its parent" do + @casted_obj.should be_an_instance_of(OldFashionedMixin) + end + + it "should have the getters defined" do + @casted_obj.name.should == 'Testing' + end + + it "should know who casted it" do + @casted_obj.casted_by.should == @obj + end + + it "should know which property casted it" do + @casted_obj.casted_by_property.should == @obj.properties.detect{|p| p.to_s == 'old_casted_attribute'} + end + + it "should return nil for the unknown attribute" do + @casted_obj["unknown"].should be_nil + end + end + describe "casted as an array of a different type" do before(:each) do @obj = DummyModel.new(:keywords => ['couch', 'sofa', 'relax', 'canapé']) diff --git a/spec/unit/dirty_spec.rb b/spec/unit/dirty_spec.rb index f527d9c..ceadb16 100644 --- a/spec/unit/dirty_spec.rb +++ b/spec/unit/dirty_spec.rb @@ -1,6 +1,6 @@ require "spec_helper" -class WithCastedModelMixin < Hash +class WithCastedModelMixin include CouchRest::Model::CastedModel property :name property :details, Object, :default => {}