Fix syck cannot dump DirtyMinded Strings #50

Merged
merged 3 commits into from Jan 11, 2012
@@ -148,7 +148,10 @@ def track(resource, property)
# Catch any direct assignment (#set), and any Resource#reload (set!).
def set!(resource, value)
- hook_value(resource, value) unless value.kind_of? Hooker
+ # Do not extend non observed value classes
+ if Hooker::MUTATION_METHODS.keys.detect { |klass| value.kind_of?(klass) }
emmanuel
emmanuel Dec 7, 2011 Owner

It seems like there are only a few types that could have String, Hash, or Array values: YAML and JSON are the only two I can think of.

It would be nice to not do this iteration on Property#set! calls for Property instances that don't have to worry about this, but I'm not sure how to manage that.

mbj
mbj Dec 7, 2011 Owner

We could do MUTATION_METHODS.key?(value.class), but this will not catch subclasses.

This iteration will not be done on all Property instances, since the DirtyMinder is only included in DataMapper::Property::{Yaml,Json} ? So I do not get your point here.

emmanuel
emmanuel Dec 7, 2011 Owner

Oh, sorry. I forgot the bigger context. I thought that DirtyMinder got included in more Property subclasses, and I didn't check before commenting.

Thanks for the correction :)

+ hook_value(resource, value) unless value.kind_of? Hooker
+ end
super
end
@@ -64,6 +64,24 @@
end
end
end
+
+ describe 'with inventions as a string' do
+ before :all do
+ object = "Foo and Bar" #.freeze
+ @resource.inventions = object
+ end
+
+ describe 'when dumped and loaded again' do
+ before :all do
+ @resource.save.should be(true)
+ @resource.reload
+ end
+
+ it 'has correct inventions' do
+ @resource.inventions.should == 'Foo and Bar'
+ end
+ end
+ end
end
end
end
@@ -0,0 +1,64 @@
+require 'spec_helper'
+require 'dm-types/support/dirty_minder'
+
+describe DataMapper::Property::DirtyMinder,'set!' do
+
+ let(:property_class) do
+ Class.new(DataMapper::Property::Object) do
+ include DataMapper::Property::DirtyMinder
+ end
+ end
+
+ let(:model) do
+ property_class = self.property_class
+ Class.new do
+ include DataMapper::Resource
+ property :id,DataMapper::Property::Serial
+ property :name,property_class
+
+ def self.name; 'FredsClass'; end
+ end
+ end
+
+ let(:resource) { model.new }
+
+ let(:object) { model.properties[:name] }
+
+ subject { object.set!(resource,value) }
+
+ shared_examples_for 'a non hooked value' do
+ it 'should not extend value with hook' do
+ value.should_not be_kind_of(DataMapper::Property::DirtyMinder::Hooker)
+ end
+ end
+
+ shared_examples_for 'a hooked value' do
+ it 'should extend value with hook' do
+ value.should be_kind_of(DataMapper::Property::DirtyMinder::Hooker)
+ end
+ end
+
+ before do
+ subject
+ end
+
+ context 'when setting nil' do
+ let(:value) { nil }
+ it_should_behave_like 'a non hooked value'
+ end
+
+ context 'when setting a String' do
+ let(:value) { "The fred" }
+ it_should_behave_like 'a non hooked value'
+ end
+
+ context 'when setting an Array' do
+ let(:value) { ["The fred"] }
+ it_should_behave_like 'a hooked value'
+ end
+
+ context 'when setting a Hash' do
+ let(:value) { {"The" => "fred"} }
+ it_should_behave_like 'a hooked value'
+ end
+end