diff --git a/lib/disposable/twin/changed.rb b/lib/disposable/twin/changed.rb index f386ff2..bb5938b 100644 --- a/lib/disposable/twin/changed.rb +++ b/lib/disposable/twin/changed.rb @@ -1,41 +1,32 @@ module Disposable::Twin::Changed - class Changes < Hash - def changed?(name=nil) - return true if name.nil? and values.find { |val| val == true } # TODO: this could be speed-improved, of course. + def changes(name=nil) + _find_changed_twins!(_changes) - !! self[name.to_s] - end - end - - - def changed?(*args) # not recommended for external use? - changed.changed?(*args) + return _changes unless name + _changes[name.to_s] end -# FIXME: can we make #changed the only public concept? so we don't need to find twice? + def changed?(name=nil) + _find_changed_twins!(_changes) - # this is usually called only once in Sync::SkipUnchanged, per twin. - def changed - _find_changed_twins!(@_changes) - - @_changes + (name.nil? && _changes.values.any?) || _changes.has_key?(name.to_s) end private - def initialize(model, *args) - super # Setup#initialize. - @_changes = Changes.new # override changed from initialize. - end - def _changed - @_changes ||= Changes.new # FIXME: why do we need to re-initialize here? + attr_reader :_changes + def initialize(model, *args) + super # Setup#initialize. + @_changes = {} # override changed from initialize. end def write_property(name, value, dfn) old_value = field_read(name) + return if old_value == value super.tap do - _changed[name.to_s] = old_value != value + @_changes ||= {} + _changes[name.to_s] = [old_value, value] end end @@ -44,7 +35,14 @@ def _find_changed_twins!(changes) # FIXME: this will change soon. don't touch. next unless twin = send(dfn.getter) next unless twin.changed? - changes[dfn[:name]] = true + if twin.is_a?(Disposable::Twin::Collection) + changes[dfn[:name]] = [] + twin.each do |item| + changes[dfn[:name]] << item.changes + end + else + changes[dfn[:name]] = twin.changes + end end end -end \ No newline at end of file +end diff --git a/test/twin/changed_test.rb b/test/twin/changed_test.rb index 1121642..1e7fe43 100644 --- a/test/twin/changed_test.rb +++ b/test/twin/changed_test.rb @@ -63,17 +63,53 @@ class Album < Disposable::Twin twin.artist.name = "No Fun At All" expect(twin.changed?(:name)).must_equal true + expect(twin.changes(:name)).must_equal ["The Rest Is Silence", "Out Of Bounds"] + expect(twin.changes).must_equal({ + "name" => ["The Rest Is Silence", "Out Of Bounds"], + "artist" => { "name" => ["Randy", "No Fun At All"] }, + "songs" => [ + {"title" => ["Broken", "I Have Seen"]}, + { + "title" => ["Broken", "In A Rhyme"], + "composer" => { + "name" => [2, "Ingemar Jansson & Mikael Danielsson"] + } + } + ] + }) expect(twin.changed?).must_equal true expect(twin.songs[0].changed?).must_equal true expect(twin.songs[0].changed?(:title)).must_equal true + expect(twin.songs[0].changes(:title)).must_equal ["Broken", "I Have Seen"] + expect(twin.songs[0].changes).must_equal({ + "title" => ["Broken", "I Have Seen"] + }) + expect(twin.songs[1].changed?).must_equal true expect(twin.songs[1].changed?(:title)).must_equal true + expect(twin.songs[1].changes(:title)).must_equal ["Broken", "In A Rhyme"] + expect(twin.songs[1].changes).must_equal({ + "title" => ["Broken", "In A Rhyme"], + "composer" => { + "name" => [2, "Ingemar Jansson & Mikael Danielsson"] + } + }) expect(twin.songs[1].composer.changed?(:name)).must_equal true + expect(twin.songs[1].composer.changes(:name)).must_equal( + [2, "Ingemar Jansson & Mikael Danielsson"] + ) + expect(twin.songs[1].composer.changes).must_equal({ + "name" => [2, "Ingemar Jansson & Mikael Danielsson"] + }) expect(twin.songs[1].composer.changed?).must_equal true expect(twin.artist.changed?(:name)).must_equal true + expect(twin.artist.changes(:name)).must_equal ["Randy", "No Fun At All"] + expect(twin.artist.changes).must_equal({ + "name" => ["Randy", "No Fun At All"] + }) expect(twin.artist.changed?).must_equal true # you can also ask for nested twins by name. diff --git a/test/twin/struct_test.rb b/test/twin/struct_test.rb index 2d39bde..7929847 100644 --- a/test/twin/struct_test.rb +++ b/test/twin/struct_test.rb @@ -26,7 +26,7 @@ class Song < Disposable::Twin it { expect(Song.new({number: 3}, {cool?: true}).number).must_equal 3 } # with string key and false value - it { Song.new('number' => 3, 'cool?' => false).cool?.must_equal false } + it { expect(Song.new('number' => 3, 'cool?' => false).cool?).must_equal false } describe "writing" do