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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 36d4d811a88254040e9ccd3693b1e4c5e667cdf83c5cfa14b3ec1fa94a52f23f
4
- data.tar.gz: 4e6ab356040d07e5db26f5f828456e4b52196e4202e39c32dfb3c17f8d23ef9d
3
+ metadata.gz: 275453852f6c76b905b0f39363e622763473bbaf81ad6ff527d49a0a03711a9d
4
+ data.tar.gz: daf3a58eaf867ec2c308747b04bffec7befe7df8336ca9f49b4d49e472ad3caa
5
5
  SHA512:
6
- metadata.gz: 6c067170e623ee334dea672c92f28ec2dc8692facc9d8a139353b541fc7ce67e0faef09dea321ea49465b31ff3b086f7e0f33c1970b43b6d7a8632fab1493ad4
7
- data.tar.gz: 72c485c7563360466b9f82210c2ba7505a90d663a7569877597e9813c3ffdfeddca95e3cd017520d7b0319533f3895cda76bd02d938338a23fd2942c81fee7e9
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, though completely ORM agnostic.
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
- conditions << [path, condition]
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, nil) unless class_variable_defined?(:@@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
@@ -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.1'
4
- s.date = '2019-07-13'
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.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-07-13 00:00:00.000000000 Z
11
+ date: 2019-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest