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.
101 102 103 104 105 106 |
# File 'lib/tree_diff.rb', line 101 def initialize(original_object) check_observations @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.
66 67 68 69 |
# File 'lib/tree_diff.rb', line 66 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 53 54 |
# File 'lib/tree_diff.rb', line 49 def self.condition(path, &condition) class_variable_set(:@@conditions, []) unless class_variable_defined?(:@@conditions) c = class_variable_get(:@@conditions) c << [path, condition] class_variable_set(:@@conditions, c) end |
.conditions ⇒ Array
All conditions defined via .condition.
73 74 75 76 |
# File 'lib/tree_diff.rb', line 73 def self.conditions class_variable_set(:@@conditions, []) unless class_variable_defined?(:@@conditions) class_variable_get(:@@conditions) end |
.observations ⇒ Array
Holds the original object tree definitions passed to .observe.
58 59 60 61 |
# File 'lib/tree_diff.rb', line 58 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.
132 133 134 |
# File 'lib/tree_diff.rb', line 132 def changed?(path) changes_at(path).present? end |
#changed_paths ⇒ Array of Arrays
Get a collection of changed paths only.
153 154 155 |
# File 'lib/tree_diff.rb', line 153 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']}]
125 126 127 |
# File 'lib/tree_diff.rb', line 125 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:
147 148 149 |
# File 'lib/tree_diff.rb', line 147 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.
160 161 162 163 |
# File 'lib/tree_diff.rb', line 160 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.
111 112 113 |
# File 'lib/tree_diff.rb', line 111 def saw_any_change? changes.present? end |