Class: TreeDiff
- Inherits:
-
Object
- Object
- TreeDiff
- Defined in:
- lib/tree_diff.rb
Defined Under Namespace
Classes: Change
Constant Summary collapse
- Mold =
A container for each copied attribute from the source object by each path.
Class.new
Class Method Summary collapse
-
.attribute_paths ⇒ Array
All paths to be walked expressed as arrays, ending in each observed attribute.
-
.condition(path) {|original_object| ... } ⇒ void
Adds a condition to an attribute that dictates whether an attribute is compared.
-
.conditions ⇒ Array
All conditions defined via
.condition. -
.observations ⇒ Array
Holds the original object tree definitions passed to
.observe. -
.observe(*defs) ⇒ void
Defines the full tree of relationships and attributes this TreeDiff class observes.
Instance Method Summary collapse
-
#changed?(path) ⇒ Boolean
Compare all observed paths, find the given path, and check if its value has changed.
-
#changed_paths ⇒ Array of Arrays
Get a collection of changed paths only.
-
#changes ⇒ Array
Walk all observed paths and compare each resulting value.
-
#changes_as_objects ⇒ Array of TreeDiff::Change
Walk all observed paths and compare each resulting value.
-
#changes_at(path) ⇒ TreeDiff::Change
Find a change by its path.
-
#initialize(original_object) ⇒ TreeDiff
constructor
Prepares a new comparision.
-
#saw_any_change? ⇒ Boolean
Check if there is any change at all, otherwise each observed attribute is considered equal before and after the change.
Constructor Details
#initialize(original_object) ⇒ TreeDiff
Prepares a new comparision. Creates a mold/mock of the object being diffed as the 'old' state according to the
relationship tree defined via .observe. Each attribute's value is copied via serializing and deserializing
via Marshal.
99 100 101 102 103 104 105 |
# File 'lib/tree_diff.rb', line 99 def initialize(original_object) check_observations self.class.class_variable_set(:@@conditions, []) @old_object_as_mold = create_mold Mold.new, original_object, self.class.observations @current_object = original_object end |
Class Method Details
.attribute_paths ⇒ Array
All paths to be walked expressed as arrays, ending in each observed attribute. These are generated upon
calling .observe.
64 65 66 67 |
# File 'lib/tree_diff.rb', line 64 def self.attribute_paths class_variable_set(:@@attribute_paths, nil) unless class_variable_defined?(:@@attribute_paths) class_variable_get(:@@attribute_paths) end |
.condition(path) {|original_object| ... } ⇒ void
This method returns an undefined value.
Adds a condition to an attribute that dictates whether an attribute is compared. The given block is invoked just before trying to call the attribute to get a comparable value. Called twice per attribute, once for the old value and once for the new.
class MyDiffClass < TreeDiff
observe details: :order_status
condition [:details, :order_status] do |order|
order.order_status == 'delivered'
end
end
49 50 51 52 |
# File 'lib/tree_diff.rb', line 49 def self.condition(path, &condition) class_variable_set(:@@conditions, []) unless conditions conditions << [path, condition] end |
.conditions ⇒ Array
All conditions defined via .condition.
71 72 73 74 |
# File 'lib/tree_diff.rb', line 71 def self.conditions class_variable_set(:@@conditions, nil) unless class_variable_defined?(:@@conditions) class_variable_get(:@@conditions) end |
.observations ⇒ Array
Holds the original object tree definitions passed to .observe.
56 57 58 59 |
# File 'lib/tree_diff.rb', line 56 def self.observations class_variable_set(:@@observations, nil) unless class_variable_defined?(:@@observations) class_variable_get(:@@observations) end |
.observe(*defs) ⇒ void
This method returns an undefined value.
Defines the full tree of relationships and attributes this TreeDiff class observes. Pass a structure of arrays and
hashes, similar to a strong_params #permit definition.
class MyDiffClass < TreeDiff
observe :order_number, :available_at, line_items: [:description, :price, tags: [:name]]
end
26 27 28 29 30 |
# File 'lib/tree_diff.rb', line 26 def self.observe(*defs) class_variable_set(:@@observations, defs) class_variable_set(:@@attribute_paths, []) observe_chain [], defs end |
Instance Method Details
#changed?(path) ⇒ Boolean
Compare all observed paths, find the given path, and check if its value has changed.
131 132 133 |
# File 'lib/tree_diff.rb', line 131 def changed?(path) changes_at(path).present? end |
#changed_paths ⇒ Array of Arrays
Get a collection of changed paths only.
152 153 154 |
# File 'lib/tree_diff.rb', line 152 def changed_paths changes_as_objects.map(&:path) end |
#changes ⇒ Array
Walk all observed paths and compare each resulting value. Returns a structure like:
[{path: [:line_items, :description], old: ["thing", "other thing"], new: ["other thing", "new thing"]},
{path: [:line_items, :price_usd_cents], old: [1234, 5678], new: [5678, 1357]},
{path: [:line_items, :item_categories, :description], old: ['foo', 'bar'], new: ['foo']}]
124 125 126 |
# File 'lib/tree_diff.rb', line 124 def changes iterate_observations(@old_object_as_mold, @current_object) end |
#changes_as_objects ⇒ Array of TreeDiff::Change
Walk all observed paths and compare each resulting value. Returns a structure like:
146 147 148 |
# File 'lib/tree_diff.rb', line 146 def changes_as_objects changes.map { |c| Change.new(c.fetch(:path), c.fetch(:old), c.fetch(:new)) } end |
#changes_at(path) ⇒ TreeDiff::Change
Find a change by its path.
159 160 161 162 |
# File 'lib/tree_diff.rb', line 159 def changes_at(path) arrayed_path = Array(path) changes_as_objects.detect { |c| c.path == arrayed_path } end |
#saw_any_change? ⇒ Boolean
Check if there is any change at all, otherwise each observed attribute is considered equal before and after the change.
110 111 112 |
# File 'lib/tree_diff.rb', line 110 def saw_any_change? changes.present? end |