Skip to content

Commit 5197240

Browse files
committed
Improve support for diffing hashes inside monadic constructors
Remove curly braces where possible
1 parent 3e08c2d commit 5197240

File tree

3 files changed

+220
-62
lines changed

3 files changed

+220
-62
lines changed

changelog.yml

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,10 @@
8888
8989
```
9090
Success(
91-
{
92-
- a: 2,
93-
+ a: 1,
94-
- c: 2
95-
+ b: 2
96-
}
91+
- a: 2,
92+
+ a: 1,
93+
- c: 2
94+
+ b: 2
9795
)
9896
```
9997

lib/dry/monads/extensions/super_diff.rb

Lines changed: 151 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,24 @@ module SuperDiff
1919
Try::Value
2020
].freeze
2121

22-
EXTRACT_VALUE = {
22+
EXTRACT_VALUE_MAP = {
2323
Result::Success => lambda(&:value!),
2424
Result::Failure => lambda(&:failure),
2525
Maybe::Some => lambda(&:value!),
2626
Maybe::None => lambda { |_| Unit },
2727
Try::Value => lambda(&:value!)
2828
}.freeze
2929

30+
EXTRACT_VALUE = lambda do |v|
31+
EXTRACT_VALUE_MAP[v.class].(v)
32+
end
33+
3034
IS_ARRAY = lambda do |v|
31-
EXTRACT_VALUE[v.class].(v).is_a?(::Array)
35+
EXTRACT_VALUE.(v).is_a?(::Array)
36+
end
37+
38+
IS_HASH = lambda do |v|
39+
EXTRACT_VALUE.(v).is_a?(::Hash)
3240
end
3341

3442
TOKEN_MAP = {
@@ -39,30 +47,18 @@ module SuperDiff
3947
Try::Value => "Value"
4048
}.freeze
4149

42-
class Array < ::SimpleDelegator
43-
def is_a?(klass) = klass <= Array
50+
class Tuple < ::SimpleDelegator
51+
def is_a?(klass) = klass <= Tuple
4452
end
4553

46-
module OTFlatteners
47-
class RegularConstructor < ::SuperDiff::Basic::OperationTreeFlatteners::CustomObject
48-
private
49-
50-
def initialize(...)
51-
super
52-
53-
@klass = operation_tree.underlying_object.class
54-
end
55-
56-
protected
57-
58-
def open_token = "#{TOKEN_MAP[@klass]}("
59-
60-
def close_token = ")"
54+
class Dict < ::SimpleDelegator
55+
def is_a?(klass) = klass <= Dict
56+
end
6157

62-
def item_prefix_for(_) = ""
63-
end
58+
module OTFlatteners
59+
module MonasAsCollectionConstructor
60+
def call = tiered_lines
6461

65-
class Array < ::SuperDiff::Basic::OperationTreeFlatteners::Array
6662
protected
6763

6864
def build_tiered_lines = inner_lines
@@ -81,13 +77,37 @@ def open_token = ""
8177
def close_token = ""
8278
end
8379

84-
class ArrayConstructor < RegularConstructor
80+
class RegularConstructor < ::SuperDiff::Basic::OperationTreeFlatteners::CustomObject
81+
private
82+
83+
def initialize(...)
84+
super
85+
86+
@klass = operation_tree.underlying_object.class
87+
end
88+
89+
def open_token = "#{TOKEN_MAP[@klass]}("
90+
91+
def close_token = ")"
92+
93+
def item_prefix_for(_) = ""
94+
end
95+
96+
class TupleConstructor < RegularConstructor
8597
private
8698

8799
def open_token = "#{TOKEN_MAP[@klass]}["
88100

89101
def close_token = "]"
90102
end
103+
104+
class Tuple < ::SuperDiff::Basic::OperationTreeFlatteners::Array
105+
include MonasAsCollectionConstructor
106+
end
107+
108+
class Dict < ::SuperDiff::Basic::OperationTreeFlatteners::Hash
109+
include MonasAsCollectionConstructor
110+
end
91111
end
92112

93113
module OT
@@ -97,21 +117,27 @@ def self.applies_to?(value) = VALUES.include?(value.class)
97117
def operation_tree_flattener_class = OTFlatteners::RegularConstructor
98118
end
99119

100-
class ArrayConstructor < RegularConstructor
120+
class TupleConstructor < RegularConstructor
101121
def self.applies_to?(value) = super && IS_ARRAY.call(value)
102122

103-
def operation_tree_flattener_class = OTFlatteners::ArrayConstructor
123+
def operation_tree_flattener_class = OTFlatteners::TupleConstructor
124+
end
125+
126+
class Tuple < ::SuperDiff::Basic::OperationTrees::Array
127+
def self.applies_to?(value) = value.is_a?(::Dry::Monads::SuperDiff::Tuple)
128+
129+
def operation_tree_flattener_class = OTFlatteners::Tuple
104130
end
105131

106-
class Array < ::SuperDiff::Basic::OperationTrees::Array
107-
def self.applies_to?(value) = value.is_a?(::Dry::Monads::SuperDiff::Array)
132+
class Dict < ::SuperDiff::Basic::OperationTrees::Hash
133+
def self.applies_to?(value) = value.is_a?(::Dry::Monads::SuperDiff::Dict)
108134

109-
def operation_tree_flattener_class = OTFlatteners::Array
135+
def operation_tree_flattener_class = OTFlatteners::Dict
110136
end
111137
end
112138

113139
module OTBuilders
114-
class RegularConstructors < ::SuperDiff::Basic::OperationTreeBuilders::CustomObject
140+
class CompareDefault < ::SuperDiff::Basic::OperationTreeBuilders::CustomObject
115141
def self.applies_to?(expected, actual)
116142
VALUES.include?(expected.class) &&
117143
actual.instance_of?(expected.class)
@@ -133,7 +159,7 @@ def establish_expected_and_actual_attributes
133159
end
134160

135161
def get_value(object)
136-
v = EXTRACT_VALUE[object.class].(object)
162+
v = EXTRACT_VALUE.(object)
137163

138164
if Unit.equal?(v)
139165
EMPTY_HASH
@@ -143,59 +169,92 @@ def get_value(object)
143169
end
144170
end
145171

146-
class Array < ::SuperDiff::Basic::OperationTreeBuilders::Array
172+
class Tuple < ::SuperDiff::Basic::OperationTreeBuilders::Array
147173
def self.applies_to?(expected, actual)
148-
expected.is_a?(::Dry::Monads::SuperDiff::Array) &&
174+
expected.is_a?(::Dry::Monads::SuperDiff::Tuple) &&
149175
actual.instance_of?(expected.class)
150176
end
151177

152178
private
153179

154180
def operation_tree
155-
@operation_tree ||= OT::Array.new([])
181+
@operation_tree ||= OT::Tuple.new([])
156182
end
157183
end
158184

159-
class ArrayConstructors < RegularConstructors
185+
class Dict < ::SuperDiff::Basic::OperationTreeBuilders::Hash
186+
def self.applies_to?(expected, actual)
187+
expected.is_a?(::Dry::Monads::SuperDiff::Dict) &&
188+
actual.instance_of?(expected.class)
189+
end
190+
191+
private
192+
193+
def build_operation_tree = OT::Dict.new([])
194+
end
195+
196+
class CompareTuples < CompareDefault
160197
def self.applies_to?(expected, actual)
161198
super && IS_ARRAY.call(expected) && IS_ARRAY.call(actual)
162199
end
163200

164201
private
165202

166203
def get_value(object)
167-
v = EXTRACT_VALUE[object.class].(object)
204+
v = EXTRACT_VALUE.(object)
168205

169-
{value: ::Dry::Monads::SuperDiff::Array.new(v)}
206+
{value: ::Dry::Monads::SuperDiff::Tuple.new(v)}
170207
end
171208

172209
def build_operation_tree
173-
OT::ArrayConstructor.new([], underlying_object: actual)
210+
OT::TupleConstructor.new([], underlying_object: actual)
211+
end
212+
end
213+
214+
class CompareDicts < CompareDefault
215+
def self.applies_to?(expected, actual)
216+
super && IS_HASH.call(expected) && IS_HASH.call(actual)
217+
end
218+
219+
private
220+
221+
def get_value(object)
222+
v = EXTRACT_VALUE.(object)
223+
224+
{value: ::Dry::Monads::SuperDiff::Dict.new(v)}
174225
end
175226
end
176227
end
177228

178229
module Differs
179-
class RegularConstructors < ::SuperDiff::Basic::Differs::CustomObject
230+
class CompareDefault < ::SuperDiff::Basic::Differs::CustomObject
180231
def self.applies_to?(expected, actual)
181232
VALUES.include?(expected.class) &&
182233
expected.instance_of?(actual.class)
183234
end
184235

185-
def operation_tree_builder_class = OTBuilders::RegularConstructors
236+
def operation_tree_builder_class = OTBuilders::CompareDefault
186237
end
187238

188-
class ArrayConstructors < RegularConstructors
239+
class CompareTuples < CompareDefault
189240
def self.applies_to?(expected, actual)
190241
super && IS_ARRAY.call(expected) && IS_ARRAY.call(actual)
191242
end
192243

193-
def operation_tree_builder_class = OTBuilders::ArrayConstructors
244+
def operation_tree_builder_class = OTBuilders::CompareTuples
245+
end
246+
247+
class CompareDicts < CompareDefault
248+
def self.applies_to?(expected, actual)
249+
super && IS_HASH.call(expected) && IS_HASH.call(actual)
250+
end
251+
252+
def operation_tree_builder_class = OTBuilders::CompareDicts
194253
end
195254
end
196255

197256
module ITBuilders
198-
class RegularConstructors < ::SuperDiff::Basic::InspectionTreeBuilders::CustomObject
257+
class RegularConstructor < ::SuperDiff::Basic::InspectionTreeBuilders::CustomObject
199258
def self.applies_to?(object)
200259
VALUES.include?(object.class)
201260
end
@@ -204,7 +263,7 @@ def call
204263
build_tree do |t2|
205264
t2.add_text("#{TOKEN_MAP[object.class]}(")
206265

207-
v = EXTRACT_VALUE[object.class].(object)
266+
v = EXTRACT_VALUE.(object)
208267

209268
unless Unit.equal?(v)
210269
t2.nested do |t3|
@@ -227,15 +286,53 @@ def build_tree(&block)
227286
end
228287
end
229288

230-
class ArrayConstructors < RegularConstructors
289+
class TupleConstructor < RegularConstructor
231290
def self.applies_to?(object) = super && IS_ARRAY.call(object)
232291

233292
def call
234293
build_tree do |t2|
235294
t2.add_text(TOKEN_MAP[object.class])
236295

237296
t2.nested do |t3|
238-
t3.add_inspection_of EXTRACT_VALUE[object.class].(object)
297+
t3.add_inspection_of EXTRACT_VALUE.(object)
298+
end
299+
end
300+
end
301+
end
302+
303+
class DictConstructor < RegularConstructor
304+
def self.applies_to?(object) = super && IS_HASH.call(object)
305+
306+
def call
307+
build_tree do |t2|
308+
t2.add_text("#{TOKEN_MAP[object.class]}(")
309+
310+
t2.nested do |t3|
311+
t3.add_inspection_of ::Dry::Monads::SuperDiff::Dict.new(
312+
EXTRACT_VALUE.(object)
313+
)
314+
end
315+
316+
t2.add_text(")")
317+
end
318+
end
319+
end
320+
321+
class Dict < ::SuperDiff::Basic::InspectionTreeBuilders::Hash
322+
def self.applies_to?(object) = object.is_a?(::Dry::Monads::SuperDiff::Dict)
323+
324+
def call
325+
::SuperDiff::Core::InspectionTree.new do |t1|
326+
t1.only_when empty do |t2|
327+
t2.as_lines_when_rendering_to_lines do |t3|
328+
t3.add_text "{}"
329+
end
330+
end
331+
332+
t1.only_when nonempty do |t2|
333+
t2.nested do |t3|
334+
t3.insert_hash_inspection_of(object)
335+
end
239336
end
240337
end
241338
end
@@ -247,14 +344,18 @@ def call
247344

248345
SuperDiff.configuration.tap do |config|
249346
config.prepend_extra_differ_classes(
250-
Dry::Monads::SuperDiff::Differs::ArrayConstructors,
251-
Dry::Monads::SuperDiff::Differs::RegularConstructors
347+
Dry::Monads::SuperDiff::Differs::CompareTuples,
348+
Dry::Monads::SuperDiff::Differs::CompareDicts,
349+
Dry::Monads::SuperDiff::Differs::CompareDefault
252350
)
253351
config.prepend_extra_inspection_tree_builder_classes(
254-
Dry::Monads::SuperDiff::ITBuilders::ArrayConstructors,
255-
Dry::Monads::SuperDiff::ITBuilders::RegularConstructors
352+
Dry::Monads::SuperDiff::ITBuilders::TupleConstructor,
353+
Dry::Monads::SuperDiff::ITBuilders::DictConstructor,
354+
Dry::Monads::SuperDiff::ITBuilders::RegularConstructor,
355+
Dry::Monads::SuperDiff::ITBuilders::Dict
256356
)
257357
config.prepend_extra_operation_tree_builder_classes(
258-
Dry::Monads::SuperDiff::OTBuilders::Array
358+
Dry::Monads::SuperDiff::OTBuilders::Tuple,
359+
Dry::Monads::SuperDiff::OTBuilders::Dict
259360
)
260361
end

0 commit comments

Comments
 (0)