tree_diff 1.1.1 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +58 -1
- data/lib/tree_diff.rb +5 -4
- data/test/tree_diff_test.rb +27 -0
- data/tree_diff.gemspec +2 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 275453852f6c76b905b0f39363e622763473bbaf81ad6ff527d49a0a03711a9d
|
4
|
+
data.tar.gz: daf3a58eaf867ec2c308747b04bffec7befe7df8336ca9f49b4d49e472ad3caa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: feacaeada2e4d4b0298bace2d3441835f0cac924bec321a50c228edcd4e746ff0fed1d50ee59eef091864e2619915395cc5c05e04ea6fc3c0be91aa362e730ac
|
7
|
+
data.tar.gz: 0dc668bad79c7a76b2fab3d19da7fbf532b384188e0023b55f594f19bcdf9f14d000b5179583fc4bc381717f0168b316246b78b81cdc753c824ec3a5b0869c17
|
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# Tree Diff
|
2
2
|
|
3
|
-
Compare large object trees. Like a generic and standalone ActiveModel::Dirty,
|
3
|
+
Compare large object trees. Like a generic and standalone ActiveModel::Dirty, but completely ORM agnostic.
|
4
|
+
|
5
|
+
The gem is still new and I'm still adding features, but it's stable and released.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
@@ -41,3 +43,58 @@ gem install tree_diff
|
|
41
43
|
end
|
42
44
|
```
|
43
45
|
|
46
|
+
3. `handle_stuff` will only be executed if any of the observed attributes changed -- `my_diff.saw_any_change?`. To see what the actual changes were, use `my_diff.changes`.
|
47
|
+
|
48
|
+
## Defining conditions
|
49
|
+
|
50
|
+
Sometimes you don't want to make attribute comparisons if the object receiving the method is in a certain state:
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
class MyDiffClass < TreeDiff
|
54
|
+
observe :reference_code
|
55
|
+
|
56
|
+
condition [:reference_code] do |thing|
|
57
|
+
thing.status == 'enabled'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
```
|
61
|
+
|
62
|
+
This will only call and compare `:reference_code` if Thing's status is `"enabled"`. This works as expected for associations:
|
63
|
+
|
64
|
+
```ruby
|
65
|
+
class MyDiffClass < TreeDiff
|
66
|
+
observe items: [:id, tags: [{categories: [:name, :is_active]}]]
|
67
|
+
|
68
|
+
condition [:tags, :categories, :name] do |category|
|
69
|
+
category.is_active
|
70
|
+
end
|
71
|
+
end
|
72
|
+
```
|
73
|
+
|
74
|
+
The object passed to the block is always the receiver of the attribute method. It's an instance of the second to the last segment of the call chain.
|
75
|
+
|
76
|
+
Bear in mind the condition is called on both the mold of the object in its "old" state and the current full object. Because TreeDiff works off of call chains only, the "old" object is nothing but a mock, meaning you can only use other attributes you've observed in your conditions. Otherwise, you can add a virtual attribute.
|
77
|
+
|
78
|
+
## Virtual Attributes
|
79
|
+
|
80
|
+
*NOTE*: Not implemented yet, work in progress.
|
81
|
+
|
82
|
+
If you want to create conditions using attributes that are not observed, you can add them as virtual attributes. That will define the method on the Mold (mock) object so it can be safely called.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
class MyDiffClass < TreeDiff
|
86
|
+
observe items: [:id, tags: [{categories: [:name]}]]
|
87
|
+
|
88
|
+
virtual_attributes [:tags, :categories, :is_active],
|
89
|
+
[:tags, :categories, :created_at]
|
90
|
+
|
91
|
+
|
92
|
+
condition [:tags, :categories, :name] do |category|
|
93
|
+
category.is_active && category.created_at > 1.year.ago
|
94
|
+
end
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
## Documentation / Reference
|
99
|
+
|
100
|
+
**[RubyDoc](https://www.rubydoc.info/gems/tree_diff)**
|
data/lib/tree_diff.rb
CHANGED
@@ -47,8 +47,10 @@ class TreeDiff
|
|
47
47
|
#
|
48
48
|
# @return [void]
|
49
49
|
def self.condition(path, &condition)
|
50
|
-
class_variable_set(:@@conditions, []) unless conditions
|
51
|
-
|
50
|
+
class_variable_set(:@@conditions, []) unless class_variable_defined?(:@@conditions)
|
51
|
+
c = class_variable_get(:@@conditions)
|
52
|
+
c << [path, condition]
|
53
|
+
class_variable_set(:@@conditions, c)
|
52
54
|
end
|
53
55
|
|
54
56
|
# Holds the original object tree definitions passed to `.observe`.
|
@@ -69,7 +71,7 @@ class TreeDiff
|
|
69
71
|
# All conditions defined via `.condition`.
|
70
72
|
# @return [Array]
|
71
73
|
def self.conditions
|
72
|
-
class_variable_set(:@@conditions,
|
74
|
+
class_variable_set(:@@conditions, []) unless class_variable_defined?(:@@conditions)
|
73
75
|
class_variable_get(:@@conditions)
|
74
76
|
end
|
75
77
|
|
@@ -99,7 +101,6 @@ class TreeDiff
|
|
99
101
|
def initialize(original_object)
|
100
102
|
check_observations
|
101
103
|
|
102
|
-
self.class.class_variable_set(:@@conditions, [])
|
103
104
|
@old_object_as_mold = create_mold Mold.new, original_object, self.class.observations
|
104
105
|
@current_object = original_object
|
105
106
|
end
|
data/test/tree_diff_test.rb
CHANGED
@@ -7,6 +7,14 @@ class TreeDiffTest < Minitest::Test
|
|
7
7
|
observe :at, :quantity
|
8
8
|
end
|
9
9
|
|
10
|
+
class ConditionalDiff < TreeDiff
|
11
|
+
observe :number, line_items: [:description, :price_usd_cents, item_categories: [:short_name, :description]]
|
12
|
+
|
13
|
+
condition [:line_items, :item_categories, :short_name] do |category|
|
14
|
+
category.description == 'foo'
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
10
18
|
class OrderDiff < TreeDiff
|
11
19
|
observe :number, line_items: [:description, :price_usd_cents, item_categories: [:description]]
|
12
20
|
end
|
@@ -140,6 +148,25 @@ class TreeDiffTest < Minitest::Test
|
|
140
148
|
:new => ["not_that_bad"]}], diff.changes
|
141
149
|
end
|
142
150
|
|
151
|
+
def test_honors_conditions
|
152
|
+
foo_category = ItemCategory.new(description: 'foo', short_name: 'Cool category')
|
153
|
+
bar_category = ItemCategory.new(description: 'bar', short_name: 'Not very cool category')
|
154
|
+
|
155
|
+
line_item = LineItem.new(item_categories: [foo_category, bar_category])
|
156
|
+
order = Order.create!(line_items: [line_item])
|
157
|
+
|
158
|
+
diff = ConditionalDiff.new(order)
|
159
|
+
assert_empty diff.changes
|
160
|
+
|
161
|
+
order.update!(line_items_attributes: [{id: line_item.id,
|
162
|
+
item_categories_attributes: [{id: foo_category.id, description: 'foo',
|
163
|
+
short_name: 'Cool category'},
|
164
|
+
{id: bar_category.id, description: 'bar',
|
165
|
+
short_name: 'another value'}]}])
|
166
|
+
|
167
|
+
assert_equal false, diff.changed_paths.include?([:line_items, :item_categories, :short_name])
|
168
|
+
end
|
169
|
+
|
143
170
|
def test_abstract_class
|
144
171
|
e = assert_raises RuntimeError do
|
145
172
|
TreeDiff.new(Object.new)
|
data/tree_diff.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = 'tree_diff'
|
3
|
-
s.version = '1.1.
|
4
|
-
s.date = '2019-
|
3
|
+
s.version = '1.1.2'
|
4
|
+
s.date = '2019-08-23'
|
5
5
|
s.summary = "Observe attribute changes in big complex object trees, like a generic & standalone ActiveModel::Dirty"
|
6
6
|
s.description = "Given a tree of relationships in a similar format to strong params, analyzes attribute changes by " \
|
7
7
|
"call chain. Call just before and after you make a change. Completely ORM and framework agnostic."
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tree_diff
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Nelson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|