From 96f8d1aa96c92536f935dde1b84df5e862e4f191 Mon Sep 17 00:00:00 2001 From: Eric Watson Date: Mon, 25 May 2009 11:16:48 -0500 Subject: [PATCH] Fixing CastedModel bug that modified casted objects Also refactored code for skipping casting of nil-valued properties Added and re-arranged specs --- lib/couchrest/mixins/properties.rb | 6 +-- .../more/casted_extended_doc_spec.rb | 49 ++++++++++++++++--- 2 files changed, 45 insertions(+), 10 deletions(-) diff --git a/lib/couchrest/mixins/properties.rb b/lib/couchrest/mixins/properties.rb index e4a94e3..16643ed 100644 --- a/lib/couchrest/mixins/properties.rb +++ b/lib/couchrest/mixins/properties.rb @@ -39,9 +39,10 @@ module CouchRest self.class.properties.each do |property| next unless property.casted key = self.has_key?(property.name) ? property.name : property.name.to_sym + # Don't cast the property unless it has a value + next unless self[key] target = property.type if target.is_a?(Array) - next unless self[key] klass = ::CouchRest.constantize(target[0]) self[property.name] = self[key].collect do |value| # Auto parse Time objects @@ -56,8 +57,7 @@ module CouchRest else # Let people use :send as a Time parse arg klass = ::CouchRest.constantize(target) - # Only cast this key if it has a value. Otherwise, leave nil. - self[key].nil? ? nil : klass.send(property.init_method, self[key]) + klass.send(property.init_method, self[key].dup) end self[property.name].casted_by = self if self[property.name].respond_to?(:casted_by) end diff --git a/spec/couchrest/more/casted_extended_doc_spec.rb b/spec/couchrest/more/casted_extended_doc_spec.rb index f9c4b33..51afd77 100644 --- a/spec/couchrest/more/casted_extended_doc_spec.rb +++ b/spec/couchrest/more/casted_extended_doc_spec.rb @@ -18,23 +18,58 @@ end describe "casting an extended document" do + before(:each) do + @driver = Driver.new(:name => 'Matt') + @car = Car.new(:name => 'Renault 306', :driver => @driver) + end + + it "should retain all properties of the casted attribute" do + @car.driver.should == @driver + end + + it "should let the casted document know who casted it" do + @car.driver.casted_by.should == @car + end +end + +describe "assigning a value to casted attribute after initializing an object" do + before(:each) do @car = Car.new(:name => 'Renault 306') @driver = Driver.new(:name => 'Matt') end - # it "should not create an empty casted object" do - # @car.driver.should be_nil - # end + it "should not create an empty casted object" do + @car.driver.should be_nil + end - it "should let you assign the casted attribute after instantializing an object" do + # Note that this isn't casting the attribute, it's just assigning it a value + # (see "should not cast attribute") + it "should let you assign the value" do @car.driver = @driver @car.driver.name.should == 'Matt' end - it "should let the casted document who casted it" do - Car.new(:name => 'Renault 306', :driver => @driver) - @car.driver.casted_by.should == @car + it "should not cast attribute" do + @car.driver = JSON.parse(JSON.generate(@driver)) + @car.driver.should_not be_instance_of(Driver) + end + +end + +describe "casting an extended document from parsed JSON" do + + before(:each) do + @driver = Driver.new(:name => 'Matt') + @car = Car.new(:name => 'Renault 306', :driver => @driver) + @new_car = Car.new(JSON.parse(JSON.generate(@car))) + end + + it "should cast casted attribute" do + @new_car.driver.should be_instance_of(Driver) end + it "should retain all properties of the casted attribute" do + @new_car.driver.should == @driver + end end \ No newline at end of file