Skip to content

Commit 181b102

Browse files
authored
Remove instance_eval from InspectionTree (#210)
The InspectionTree class defines methods that create nodes in the tree. Some of these methods take a block which is `instance_eval`'ed inside of a new subtree. This use of `instance_eval` may seem to create a very clean and easy to use API on the surface, but it quickly breaks down if, as you are defining your InspectionTree, you need to extract methods inside of your InspectionTreeBuilder and then reference them. _Not_ `instance_eval`'ing creates footguns, but it also removes the magic and mystery around how InspectionTree works.
1 parent 599ffbd commit 181b102

File tree

22 files changed

+432
-253
lines changed

22 files changed

+432
-253
lines changed

lib/super_diff/active_record/object_inspection/inspection_tree_builders/active_record_model.rb

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,27 +8,39 @@ def self.applies_to?(value)
88
end
99

1010
def call
11-
SuperDiff::ObjectInspection::InspectionTree.new do
12-
as_lines_when_rendering_to_lines(collection_bookend: :open) do
13-
add_text { |object| "#<#{object.class} " }
11+
SuperDiff::ObjectInspection::InspectionTree.new do |t1|
12+
t1.as_lines_when_rendering_to_lines(
13+
collection_bookend: :open
14+
) do |t2|
15+
t2.add_text "#<#{object.class} "
1416

15-
when_rendering_to_lines { add_text "{" }
17+
# stree-ignore
18+
t2.when_rendering_to_lines do |t3|
19+
t3.add_text "{"
20+
end
1621
end
1722

18-
nested do |object|
19-
insert_separated_list(
23+
t1.nested do |t2|
24+
t2.insert_separated_list(
2025
["id"] + (object.attributes.keys.sort - ["id"])
21-
) do |name|
22-
as_prefix_when_rendering_to_lines { add_text "#{name}: " }
26+
) do |t3, name|
27+
t3.as_prefix_when_rendering_to_lines do |t4|
28+
t4.add_text "#{name}: "
29+
end
2330

24-
add_inspection_of object.read_attribute(name)
31+
t3.add_inspection_of object.read_attribute(name)
2532
end
2633
end
2734

28-
as_lines_when_rendering_to_lines(collection_bookend: :close) do
29-
when_rendering_to_lines { add_text "}" }
35+
t1.as_lines_when_rendering_to_lines(
36+
collection_bookend: :close
37+
) do |t2|
38+
# stree-ignore
39+
t2.when_rendering_to_lines do |t3|
40+
t3.add_text "}"
41+
end
3042

31-
add_text ">"
43+
t2.add_text ">"
3244
end
3345
end
3446
end

lib/super_diff/active_record/object_inspection/inspection_tree_builders/active_record_relation.rb

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,24 @@ def self.applies_to?(value)
88
end
99

1010
def call
11-
SuperDiff::ObjectInspection::InspectionTree.new do
12-
as_lines_when_rendering_to_lines(collection_bookend: :open) do
13-
add_text "#<ActiveRecord::Relation ["
11+
SuperDiff::ObjectInspection::InspectionTree.new do |t1|
12+
# stree-ignore
13+
t1.as_lines_when_rendering_to_lines(
14+
collection_bookend: :open
15+
) do |t2|
16+
t2.add_text "#<ActiveRecord::Relation ["
1417
end
1518

16-
nested { |array| insert_array_inspection_of(array) }
19+
# stree-ignore
20+
t1.nested do |t2|
21+
t2.insert_array_inspection_of(object)
22+
end
1723

18-
as_lines_when_rendering_to_lines(collection_bookend: :close) do
19-
add_text "]>"
24+
# stree-ignore
25+
t1.as_lines_when_rendering_to_lines(
26+
collection_bookend: :close
27+
) do |t2|
28+
t2.add_text "]>"
2029
end
2130
end
2231
end

lib/super_diff/active_support/object_inspection/inspection_tree_builders/hash_with_indifferent_access.rb

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,34 @@ def self.applies_to?(value)
88
end
99

1010
def call
11-
SuperDiff::ObjectInspection::InspectionTree.new do
12-
as_lines_when_rendering_to_lines(collection_bookend: :open) do
13-
add_text "#<HashWithIndifferentAccess {"
11+
SuperDiff::ObjectInspection::InspectionTree.new do |t1|
12+
# stree-ignore
13+
t1.as_lines_when_rendering_to_lines(
14+
collection_bookend: :open
15+
) do |t2|
16+
t2.add_text "#<HashWithIndifferentAccess {"
1417
end
1518

16-
when_rendering_to_string { add_text " " }
19+
# stree-ignore
20+
t1.when_rendering_to_string do |t2|
21+
t2.add_text " "
22+
end
1723

18-
nested { |hash| insert_hash_inspection_of(hash) }
24+
# stree-ignore
25+
t1.nested do |t2|
26+
t2.insert_hash_inspection_of(object)
27+
end
1928

20-
when_rendering_to_string { add_text " " }
29+
# stree-ignore
30+
t1.when_rendering_to_string do |t2|
31+
t2.add_text " "
32+
end
2133

22-
as_lines_when_rendering_to_lines(collection_bookend: :close) do
23-
add_text "}>"
34+
# stree-ignore
35+
t1.as_lines_when_rendering_to_lines(
36+
collection_bookend: :close
37+
) do |t2|
38+
t2.add_text "}>"
2439
end
2540
end
2641
end

lib/super_diff/active_support/object_inspection/inspection_tree_builders/ordered_options.rb

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,34 @@ def self.applies_to?(value)
88
end
99

1010
def call
11-
SuperDiff::ObjectInspection::InspectionTree.new do
12-
as_lines_when_rendering_to_lines(collection_bookend: :open) do
13-
add_text "#<OrderedOptions {"
11+
SuperDiff::ObjectInspection::InspectionTree.new do |t1|
12+
# stree-ignore
13+
t1.as_lines_when_rendering_to_lines(
14+
collection_bookend: :open
15+
) do |t2|
16+
t2.add_text "#<OrderedOptions {"
1417
end
1518

16-
when_rendering_to_string { add_text " " }
19+
# stree-ignore
20+
t1.when_rendering_to_string do |t2|
21+
t2.add_text " "
22+
end
1723

18-
nested do |ordered_options|
19-
insert_hash_inspection_of(ordered_options.to_hash)
24+
# stree-ignore
25+
t1.nested do |t2|
26+
t2.insert_hash_inspection_of(object.to_hash)
2027
end
2128

22-
when_rendering_to_string { add_text " " }
29+
# stree-ignore
30+
t1.when_rendering_to_string do |t2|
31+
t2.add_text " "
32+
end
2333

24-
as_lines_when_rendering_to_lines(collection_bookend: :close) do
25-
add_text "}>"
34+
# stree-ignore
35+
t1.as_lines_when_rendering_to_lines(
36+
collection_bookend: :close
37+
) do |t2|
38+
t2.add_text "}>"
2639
end
2740
end
2841
end

lib/super_diff/object_inspection/inspection_tree.rb

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ def initialize(disallowed_node_names: [], &block)
77
@disallowed_node_names = disallowed_node_names
88
@nodes = []
99

10-
instance_eval(&block) if block
10+
evaluate_block(&block) if block
1111
end
1212

1313
Nodes.registry.each do |node_class|
@@ -26,8 +26,7 @@ def before_each_callbacks
2626

2727
def render_to_string(object)
2828
nodes.reduce("") do |string, node|
29-
result = node.render_to_string(object)
30-
string + result
29+
string + node.render_to_string(object)
3130
end
3231
end
3332

@@ -52,43 +51,45 @@ def render_to_lines(object, type:, indentation_level:)
5251
.first
5352
end
5453

55-
def evaluate_block(object, &block)
56-
instance_exec(object, &block)
54+
def evaluate_block(*args, &block)
55+
block.call(self, *args)
5756
end
5857

5958
def insert_array_inspection_of(array)
60-
insert_separated_list(array) do |value|
59+
insert_separated_list(array) do |t, value|
6160
# Have to do these shenanigans so that if value is a hash, Ruby
6261
# doesn't try to interpret it as keyword args
6362
if SuperDiff::Helpers.ruby_version_matches?(">= 2.7.1")
64-
add_inspection_of(value, **{})
63+
t.add_inspection_of(value, **{})
6564
else
66-
add_inspection_of(*[value, {}])
65+
t.add_inspection_of(*[value, {}])
6766
end
6867
end
6968
end
7069

7170
def insert_hash_inspection_of(hash)
7271
keys = hash.keys
73-
7472
format_keys_as_kwargs = keys.all? { |key| key.is_a?(Symbol) }
7573

76-
insert_separated_list(keys) do |key|
74+
insert_separated_list(keys) do |t1, key|
7775
if format_keys_as_kwargs
78-
as_prefix_when_rendering_to_lines { add_text "#{key}: " }
76+
# stree-ignore
77+
t1.as_prefix_when_rendering_to_lines do |t2|
78+
t2.add_text "#{key}: "
79+
end
7980
else
80-
as_prefix_when_rendering_to_lines do
81-
add_inspection_of key, as_lines: false
82-
add_text " => "
81+
t1.as_prefix_when_rendering_to_lines do |t2|
82+
t2.add_inspection_of key, as_lines: false
83+
t2.add_text " => "
8384
end
8485
end
8586

8687
# Have to do these shenanigans so that if hash[key] is a hash, Ruby
8788
# doesn't try to interpret it as keyword args
8889
if SuperDiff::Helpers.ruby_version_matches?(">= 2.7.1")
89-
add_inspection_of(hash[key], **{})
90+
t1.add_inspection_of(hash[key], **{})
9091
else
91-
add_inspection_of(*[hash[key], {}])
92+
t1.add_inspection_of(*[hash[key], {}])
9293
end
9394
end
9495
end
@@ -97,10 +98,14 @@ def insert_separated_list(enumerable, &block)
9798
enumerable.each_with_index do |value, index|
9899
as_lines_when_rendering_to_lines(
99100
add_comma: index < enumerable.size - 1
100-
) do
101-
when_rendering_to_string { add_text " " } if index > 0
102-
103-
evaluate_block(value, &block)
101+
) do |t1|
102+
if index > 0
103+
# stree-ignore
104+
t1.when_rendering_to_string do |t2|
105+
t2.add_text " "
106+
end
107+
end
108+
t1.evaluate_block(value, &block)
104109
end
105110
end
106111
end

lib/super_diff/object_inspection/inspection_tree_builders/array.rb

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,46 @@ def self.applies_to?(value)
77
end
88

99
def call
10-
empty = -> { object.empty? }
11-
nonempty = -> { !object.empty? }
12-
13-
InspectionTree.new do
14-
only_when empty do
15-
as_lines_when_rendering_to_lines { add_text "[]" }
10+
InspectionTree.new do |t1|
11+
t1.only_when empty do |t2|
12+
# stree-ignore
13+
t2.as_lines_when_rendering_to_lines do |t3|
14+
t3.add_text "[]"
15+
end
1616
end
1717

18-
only_when nonempty do
19-
as_lines_when_rendering_to_lines(collection_bookend: :open) do
20-
add_text "["
18+
t1.only_when nonempty do |t2|
19+
# stree-ignore
20+
t2.as_lines_when_rendering_to_lines(
21+
collection_bookend: :open
22+
) do |t3|
23+
t3.add_text "["
2124
end
2225

23-
nested { |array| insert_array_inspection_of(array) }
26+
# stree-ignore
27+
t2.nested do |t3|
28+
t3.insert_array_inspection_of(object)
29+
end
2430

25-
as_lines_when_rendering_to_lines(collection_bookend: :close) do
26-
add_text "]"
31+
# stree-ignore
32+
t2.as_lines_when_rendering_to_lines(
33+
collection_bookend: :close
34+
) do |t3|
35+
t3.add_text "]"
2736
end
2837
end
2938
end
3039
end
40+
41+
private
42+
43+
def empty
44+
-> { object.empty? }
45+
end
46+
47+
def nonempty
48+
-> { !object.empty? }
49+
end
3150
end
3251
end
3352
end

lib/super_diff/object_inspection/inspection_tree_builders/custom_object.rb

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,31 @@ def self.applies_to?(value)
77
end
88

99
def call
10-
InspectionTree.new do
11-
as_lines_when_rendering_to_lines(collection_bookend: :open) do
12-
add_text { |object| "#<#{object.class} " }
10+
InspectionTree.new do |t1|
11+
t1.as_lines_when_rendering_to_lines(
12+
collection_bookend: :open
13+
) do |t2|
14+
t2.add_text "#<#{object.class} "
1315

14-
when_rendering_to_lines { add_text "{" }
16+
# stree-ignore
17+
t2.when_rendering_to_lines do |t3|
18+
t3.add_text "{"
19+
end
1520
end
1621

17-
nested do |object|
18-
insert_hash_inspection_of(object.attributes_for_super_diff)
22+
t1.nested do |t2|
23+
t2.insert_hash_inspection_of(object.attributes_for_super_diff)
1924
end
2025

21-
as_lines_when_rendering_to_lines(collection_bookend: :close) do
22-
when_rendering_to_lines { add_text "}" }
26+
t1.as_lines_when_rendering_to_lines(
27+
collection_bookend: :close
28+
) do |t2|
29+
# stree-ignore
30+
t2.when_rendering_to_lines do |t3|
31+
t3.add_text "}"
32+
end
2333

24-
add_text ">"
34+
t2.add_text ">"
2535
end
2636
end
2737
end

0 commit comments

Comments
 (0)