super_diff 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +0 -1
  3. data/lib/super_diff.rb +27 -6
  4. data/lib/super_diff/active_record.rb +7 -7
  5. data/lib/super_diff/active_record/differs/active_record_relation.rb +3 -13
  6. data/lib/super_diff/active_record/object_inspection.rb +2 -6
  7. data/lib/super_diff/active_record/object_inspection/inspection_tree_builders.rb +16 -0
  8. data/lib/super_diff/active_record/object_inspection/{inspectors → inspection_tree_builders}/active_record_model.rb +19 -20
  9. data/lib/super_diff/active_record/object_inspection/{inspectors → inspection_tree_builders}/active_record_relation.rb +9 -8
  10. data/lib/super_diff/active_record/operation_tree_flatteners.rb +10 -0
  11. data/lib/super_diff/active_record/operation_tree_flatteners/active_record_relation.rb +17 -0
  12. data/lib/super_diff/active_record/operation_trees/active_record_relation.rb +8 -7
  13. data/lib/super_diff/active_support.rb +8 -8
  14. data/lib/super_diff/active_support/differs/hash_with_indifferent_access.rb +3 -13
  15. data/lib/super_diff/active_support/object_inspection.rb +2 -6
  16. data/lib/super_diff/active_support/object_inspection/{inspectors.rb → inspection_tree_builders.rb} +2 -2
  17. data/lib/super_diff/active_support/object_inspection/inspection_tree_builders/hash_with_indifferent_access.rb +37 -0
  18. data/lib/super_diff/active_support/operation_tree_builders/hash_with_indifferent_access.rb +17 -0
  19. data/lib/super_diff/active_support/operation_tree_flatteners.rb +10 -0
  20. data/lib/super_diff/active_support/operation_tree_flatteners/hash_with_indifferent_access.rb +17 -0
  21. data/lib/super_diff/active_support/operation_trees/hash_with_indifferent_access.rb +4 -7
  22. data/lib/super_diff/colorized_document_extensions.rb +9 -6
  23. data/lib/super_diff/configuration.rb +81 -8
  24. data/lib/super_diff/csi.rb +1 -2
  25. data/lib/super_diff/csi/four_bit_color.rb +0 -2
  26. data/lib/super_diff/differs/array.rb +1 -1
  27. data/lib/super_diff/differs/base.rb +3 -21
  28. data/lib/super_diff/differs/custom_object.rb +1 -1
  29. data/lib/super_diff/differs/default_object.rb +1 -1
  30. data/lib/super_diff/differs/hash.rb +1 -1
  31. data/lib/super_diff/differs/main.rb +1 -7
  32. data/lib/super_diff/differs/multiline_string.rb +1 -1
  33. data/lib/super_diff/differs/time_like.rb +1 -1
  34. data/lib/super_diff/equality_matchers/array.rb +2 -2
  35. data/lib/super_diff/equality_matchers/default.rb +2 -2
  36. data/lib/super_diff/equality_matchers/hash.rb +2 -2
  37. data/lib/super_diff/equality_matchers/multiline_string.rb +2 -2
  38. data/lib/super_diff/equality_matchers/primitive.rb +4 -7
  39. data/lib/super_diff/equality_matchers/singleline_string.rb +2 -2
  40. data/lib/super_diff/helpers.rb +52 -2
  41. data/lib/super_diff/line.rb +83 -0
  42. data/lib/super_diff/object_inspection.rb +12 -1
  43. data/lib/super_diff/object_inspection/inspection_tree.rb +183 -81
  44. data/lib/super_diff/object_inspection/inspection_tree_builders.rb +44 -0
  45. data/lib/super_diff/object_inspection/inspection_tree_builders/array.rb +38 -0
  46. data/lib/super_diff/object_inspection/inspection_tree_builders/base.rb +27 -0
  47. data/lib/super_diff/object_inspection/inspection_tree_builders/custom_object.rb +37 -0
  48. data/lib/super_diff/object_inspection/inspection_tree_builders/default_object.rb +63 -0
  49. data/lib/super_diff/object_inspection/{inspectors → inspection_tree_builders}/defaults.rb +1 -2
  50. data/lib/super_diff/object_inspection/inspection_tree_builders/hash.rb +46 -0
  51. data/lib/super_diff/object_inspection/{inspectors → inspection_tree_builders}/main.rb +5 -10
  52. data/lib/super_diff/object_inspection/inspection_tree_builders/primitive.rb +21 -0
  53. data/lib/super_diff/object_inspection/{inspectors → inspection_tree_builders}/time_like.rb +19 -18
  54. data/lib/super_diff/object_inspection/nodes.rb +33 -32
  55. data/lib/super_diff/object_inspection/nodes/as_lines_when_rendering_to_lines.rb +97 -0
  56. data/lib/super_diff/object_inspection/nodes/as_prefix_when_rendering_to_lines.rb +27 -0
  57. data/lib/super_diff/object_inspection/nodes/as_prelude_when_rendering_to_lines.rb +27 -0
  58. data/lib/super_diff/object_inspection/nodes/as_single_line.rb +33 -0
  59. data/lib/super_diff/object_inspection/nodes/base.rb +55 -20
  60. data/lib/super_diff/object_inspection/nodes/inspection.rb +47 -7
  61. data/lib/super_diff/object_inspection/nodes/nesting.rb +16 -5
  62. data/lib/super_diff/object_inspection/nodes/only_when.rb +54 -0
  63. data/lib/super_diff/object_inspection/nodes/text.rb +16 -2
  64. data/lib/super_diff/object_inspection/nodes/when_empty.rb +21 -6
  65. data/lib/super_diff/object_inspection/nodes/when_non_empty.rb +20 -5
  66. data/lib/super_diff/object_inspection/nodes/when_rendering_to_lines.rb +27 -0
  67. data/lib/super_diff/object_inspection/nodes/when_rendering_to_string.rb +27 -0
  68. data/lib/super_diff/object_inspection/prefix_for_next_node.rb +6 -0
  69. data/lib/super_diff/object_inspection/prelude_for_next_node.rb +6 -0
  70. data/lib/super_diff/operation_tree_builders/array.rb +7 -10
  71. data/lib/super_diff/operation_tree_builders/base.rb +6 -6
  72. data/lib/super_diff/operation_tree_builders/custom_object.rb +5 -2
  73. data/lib/super_diff/operation_tree_builders/default_object.rb +1 -1
  74. data/lib/super_diff/operation_tree_builders/hash.rb +0 -7
  75. data/lib/super_diff/operation_tree_builders/multiline_string.rb +2 -6
  76. data/lib/super_diff/operation_tree_flatteners.rb +20 -0
  77. data/lib/super_diff/operation_tree_flatteners/array.rb +15 -0
  78. data/lib/super_diff/operation_tree_flatteners/base.rb +54 -0
  79. data/lib/super_diff/operation_tree_flatteners/collection.rb +139 -0
  80. data/lib/super_diff/operation_tree_flatteners/custom_object.rb +28 -0
  81. data/lib/super_diff/operation_tree_flatteners/default_object.rb +32 -0
  82. data/lib/super_diff/operation_tree_flatteners/hash.rb +41 -0
  83. data/lib/super_diff/operation_tree_flatteners/multiline_string.rb +17 -0
  84. data/lib/super_diff/operation_trees/array.rb +4 -7
  85. data/lib/super_diff/operation_trees/base.rb +39 -16
  86. data/lib/super_diff/operation_trees/custom_object.rb +4 -8
  87. data/lib/super_diff/operation_trees/default_object.rb +28 -13
  88. data/lib/super_diff/operation_trees/hash.rb +4 -7
  89. data/lib/super_diff/operation_trees/main.rb +1 -1
  90. data/lib/super_diff/operation_trees/multiline_string.rb +4 -7
  91. data/lib/super_diff/operations/binary_operation.rb +1 -6
  92. data/lib/super_diff/operations/unary_operation.rb +2 -30
  93. data/lib/super_diff/recursion_guard.rb +3 -3
  94. data/lib/super_diff/rspec.rb +12 -13
  95. data/lib/super_diff/rspec/monkey_patches.rb +2 -2
  96. data/lib/super_diff/rspec/object_inspection.rb +4 -1
  97. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders.rb +44 -0
  98. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/collection_containing_exactly.rb +9 -8
  99. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/collection_including.rb +9 -8
  100. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/double.rb +103 -0
  101. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/hash_including.rb +36 -0
  102. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/instance_of.rb +3 -5
  103. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/kind_of.rb +3 -5
  104. data/lib/super_diff/rspec/object_inspection/{inspectors → inspection_tree_builders}/object_having_attributes.rb +10 -12
  105. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/primitive.rb +10 -0
  106. data/lib/super_diff/rspec/object_inspection/inspection_tree_builders/value_within.rb +33 -0
  107. data/lib/super_diff/rspec/operation_tree_builders/collection_containing_exactly.rb +0 -3
  108. data/lib/super_diff/tiered_lines.rb +4 -0
  109. data/lib/super_diff/tiered_lines_elider.rb +490 -0
  110. data/lib/super_diff/tiered_lines_formatter.rb +79 -0
  111. data/lib/super_diff/version.rb +1 -1
  112. data/spec/examples.txt +407 -410
  113. data/spec/integration/rails/active_support_spec.rb +19 -0
  114. data/spec/integration/rspec/contain_exactly_matcher_spec.rb +12 -6
  115. data/spec/integration/rspec/eq_matcher_spec.rb +22 -88
  116. data/spec/integration/rspec/have_attributes_matcher_spec.rb +6 -7
  117. data/spec/integration/rspec/match_array_matcher_spec.rb +14 -7
  118. data/spec/integration/rspec/match_matcher_spec.rb +10 -5
  119. data/spec/spec_helper.rb +1 -0
  120. data/spec/support/command_runner.rb +15 -25
  121. data/spec/support/helpers.rb +21 -0
  122. data/spec/support/integration/helpers.rb +2 -0
  123. data/spec/support/integration/matchers/produce_output_when_run_matcher.rb +3 -3
  124. data/spec/support/integration/test_programs/base.rb +36 -10
  125. data/spec/support/shared_examples/active_record.rb +3 -2
  126. data/spec/support/shared_examples/active_support.rb +65 -0
  127. data/spec/support/shared_examples/elided_diffs.rb +914 -0
  128. data/spec/support/shared_examples/hash_with_indifferent_access.rb +16 -16
  129. data/spec/support/unit/helpers.rb +15 -0
  130. data/spec/support/unit/matchers/match_output.rb +41 -0
  131. data/spec/unit/active_record/object_inspection_spec.rb +273 -0
  132. data/spec/unit/equality_matchers/main_spec.rb +51 -71
  133. data/spec/unit/helpers_spec.rb +61 -0
  134. data/spec/unit/operation_tree_flatteners/array_spec.rb +604 -0
  135. data/spec/unit/operation_tree_flatteners/custom_object_spec.rb +667 -0
  136. data/spec/unit/operation_tree_flatteners/default_object_spec.rb +687 -0
  137. data/spec/unit/operation_tree_flatteners/hash_spec.rb +632 -0
  138. data/spec/unit/operation_tree_flatteners/multiline_string_spec.rb +121 -0
  139. data/spec/unit/rspec/object_inspection_spec.rb +446 -0
  140. data/spec/unit/super_diff_spec.rb +1488 -846
  141. data/spec/unit/tiered_lines_elider_spec.rb +6356 -0
  142. data/spec/unit/tiered_lines_formatter_spec.rb +193 -0
  143. metadata +88 -50
  144. data/lib/super_diff/active_record/diff_formatters.rb +0 -10
  145. data/lib/super_diff/active_record/diff_formatters/active_record_relation.rb +0 -23
  146. data/lib/super_diff/active_record/object_inspection/inspectors.rb +0 -16
  147. data/lib/super_diff/active_support/diff_formatters.rb +0 -10
  148. data/lib/super_diff/active_support/diff_formatters/hash_with_indifferent_access.rb +0 -36
  149. data/lib/super_diff/active_support/object_inspection/inspectors/hash_with_indifferent_access.rb +0 -28
  150. data/lib/super_diff/diff_formatters.rb +0 -14
  151. data/lib/super_diff/diff_formatters/array.rb +0 -21
  152. data/lib/super_diff/diff_formatters/base.rb +0 -33
  153. data/lib/super_diff/diff_formatters/custom_object.rb +0 -30
  154. data/lib/super_diff/diff_formatters/default_object.rb +0 -46
  155. data/lib/super_diff/diff_formatters/defaults.rb +0 -10
  156. data/lib/super_diff/diff_formatters/hash.rb +0 -34
  157. data/lib/super_diff/diff_formatters/main.rb +0 -41
  158. data/lib/super_diff/object_inspection/inspectors.rb +0 -23
  159. data/lib/super_diff/object_inspection/inspectors/array.rb +0 -32
  160. data/lib/super_diff/object_inspection/inspectors/base.rb +0 -36
  161. data/lib/super_diff/object_inspection/inspectors/custom_object.rb +0 -37
  162. data/lib/super_diff/object_inspection/inspectors/default_object.rb +0 -61
  163. data/lib/super_diff/object_inspection/inspectors/hash.rb +0 -32
  164. data/lib/super_diff/object_inspection/inspectors/primitive.rb +0 -28
  165. data/lib/super_diff/object_inspection/inspectors/string.rb +0 -23
  166. data/lib/super_diff/object_inspection/nodes/break.rb +0 -15
  167. data/lib/super_diff/object_inspection/nodes/when_multiline.rb +0 -22
  168. data/lib/super_diff/object_inspection/nodes/when_singleline.rb +0 -24
  169. data/lib/super_diff/rspec/object_inspection/inspectors.rb +0 -40
  170. data/lib/super_diff/rspec/object_inspection/inspectors/hash_including.rb +0 -36
  171. data/lib/super_diff/rspec/object_inspection/inspectors/primitive.rb +0 -13
  172. data/lib/super_diff/rspec/object_inspection/inspectors/value_within.rb +0 -29
  173. data/spec/support/object_id.rb +0 -27
  174. data/spec/support/ruby_versions.rb +0 -11
@@ -2,11 +2,8 @@ module SuperDiff
2
2
  module EqualityMatchers
3
3
  class Primitive < Base
4
4
  def self.applies_to?(value)
5
- value.is_a?(Symbol) ||
6
- value.is_a?(Numeric) ||
7
- # TODO: Test this
8
- value == true ||
9
- value == false
5
+ # TODO: Test all of these options
6
+ SuperDiff.primitive?(value)
10
7
  end
11
8
 
12
9
  def fail
@@ -17,14 +14,14 @@ module SuperDiff
17
14
  Helpers.style(
18
15
  :expected,
19
16
  "Expected: " +
20
- SuperDiff.inspect_object(expected, as_single_line: true),
17
+ SuperDiff.inspect_object(expected, as_lines: false),
21
18
  )
22
19
  }
23
20
  #{
24
21
  Helpers.style(
25
22
  :actual,
26
23
  " Actual: " +
27
- SuperDiff.inspect_object(actual, as_single_line: true),
24
+ SuperDiff.inspect_object(actual, as_lines: false),
28
25
  )
29
26
  }
30
27
  OUTPUT
@@ -13,14 +13,14 @@ module SuperDiff
13
13
  Helpers.style(
14
14
  :expected,
15
15
  "Expected: " +
16
- SuperDiff.inspect_object(expected, as_single_line: true),
16
+ SuperDiff.inspect_object(expected, as_lines: false),
17
17
  )
18
18
  }
19
19
  #{
20
20
  Helpers.style(
21
21
  :actual,
22
22
  " Actual: " +
23
- SuperDiff.inspect_object(actual, as_single_line: true),
23
+ SuperDiff.inspect_object(actual, as_lines: false),
24
24
  )
25
25
  }
26
26
  OUTPUT
@@ -1,7 +1,9 @@
1
1
  module SuperDiff
2
2
  module Helpers
3
+ extend self
4
+
3
5
  # TODO: Simplify this
4
- def self.style(*args, color_enabled: true, **opts, &block)
6
+ def style(*args, color_enabled: true, **opts, &block)
5
7
  klass =
6
8
  if color_enabled && Csi.color_enabled?
7
9
  Csi::ColorizedDocument
@@ -20,7 +22,7 @@ module SuperDiff
20
22
  document
21
23
  end
22
24
 
23
- def self.plural_type_for(value)
25
+ def plural_type_for(value)
24
26
  case value
25
27
  when Numeric then "numbers"
26
28
  when String then "strings"
@@ -28,5 +30,53 @@ module SuperDiff
28
30
  else "objects"
29
31
  end
30
32
  end
33
+
34
+ def jruby?
35
+ defined?(JRUBY_VERSION)
36
+ end
37
+
38
+ def ruby_version_matches?(version_string)
39
+ Gem::Requirement.new(version_string).satisfied_by?(
40
+ Gem::Version.new(RUBY_VERSION),
41
+ )
42
+ end
43
+
44
+ if jruby?
45
+ def object_address_for(object)
46
+ # Source: <https://github.com/jruby/jruby/blob/master/core/src/main/java/org/jruby/RubyBasicObject.java>
47
+ "0x%x" % object.hash
48
+ end
49
+ elsif ruby_version_matches?(">= 2.7.0")
50
+ require "json"
51
+ require "objspace"
52
+
53
+ def object_address_for(object)
54
+ # Sources: <https://bugs.ruby-lang.org/issues/15408> and <https://bugs.ruby-lang.org/issues/15626#Object-ID>
55
+ address = JSON.parse(ObjectSpace.dump(object))["address"]
56
+ "0x%016x" % Integer(address, 16)
57
+ end
58
+ else
59
+ def object_address_for(object)
60
+ "0x%016x" % (object.object_id * 2)
61
+ end
62
+ end
63
+
64
+ def with_slice_of_array_replaced(array, range, replacement)
65
+ beginning =
66
+ if range.begin > 0
67
+ array[Range.new(0, range.begin - 1)]
68
+ else
69
+ []
70
+ end
71
+
72
+ ending =
73
+ if range.end <= array.length - 1
74
+ array[Range.new(range.end + 1, array.length - 1)]
75
+ else
76
+ []
77
+ end
78
+
79
+ beginning + [replacement] + ending
80
+ end
31
81
  end
32
82
  end
@@ -0,0 +1,83 @@
1
+ module SuperDiff
2
+ class Line
3
+ extend AttrExtras.mixin
4
+
5
+ ICONS = { delete: "-", insert: "+", noop: " " }.freeze
6
+ COLORS = { insert: :actual, delete: :expected, noop: :plain }.freeze
7
+
8
+ rattr_initialize(
9
+ [
10
+ :type!,
11
+ :indentation_level!,
12
+ :value!,
13
+ prefix: "",
14
+ add_comma: false,
15
+ children: [],
16
+ elided: false,
17
+ collection_bookend: nil,
18
+ complete_bookend: nil,
19
+ ],
20
+ )
21
+ attr_query :add_comma?
22
+ attr_query :elided?
23
+
24
+ def clone_with(overrides = {})
25
+ self.class.new(
26
+ type: type,
27
+ indentation_level: indentation_level,
28
+ prefix: prefix,
29
+ value: value,
30
+ add_comma: add_comma?,
31
+ children: children,
32
+ elided: elided?,
33
+ collection_bookend: collection_bookend,
34
+ complete_bookend: complete_bookend,
35
+ **overrides,
36
+ )
37
+ end
38
+
39
+ def icon
40
+ ICONS.fetch(type)
41
+ end
42
+
43
+ def color
44
+ COLORS.fetch(type)
45
+ end
46
+
47
+ def with_comma
48
+ clone_with(add_comma: true)
49
+ end
50
+
51
+ def as_elided
52
+ clone_with(elided: true)
53
+ end
54
+
55
+ def with_value_prepended(prelude)
56
+ clone_with(value: prelude + value)
57
+ end
58
+
59
+ def with_value_appended(suffix)
60
+ clone_with(value: value + suffix)
61
+ end
62
+
63
+ def prefixed_with(prefix)
64
+ clone_with(prefix: prefix + self.prefix)
65
+ end
66
+
67
+ def with_complete_bookend(complete_bookend)
68
+ clone_with(complete_bookend: complete_bookend)
69
+ end
70
+
71
+ def opens_collection?
72
+ collection_bookend == :open
73
+ end
74
+
75
+ def closes_collection?
76
+ collection_bookend == :close
77
+ end
78
+
79
+ def complete_bookend?
80
+ complete_bookend != nil
81
+ end
82
+ end
83
+ end
@@ -1,7 +1,18 @@
1
1
  module SuperDiff
2
2
  module ObjectInspection
3
3
  autoload :InspectionTree, "super_diff/object_inspection/inspection_tree"
4
- autoload :Inspectors, "super_diff/object_inspection/inspectors"
4
+ autoload(
5
+ :InspectionTreeBuilders,
6
+ "super_diff/object_inspection/inspection_tree_builders",
7
+ )
5
8
  autoload :Nodes, "super_diff/object_inspection/nodes"
9
+ autoload(
10
+ :PrefixForNextNode,
11
+ "super_diff/object_inspection/prefix_for_next_node",
12
+ )
13
+ autoload(
14
+ :PreludeForNextNode,
15
+ "super_diff/object_inspection/prelude_for_next_node",
16
+ )
6
17
  end
7
18
  end
@@ -3,7 +3,8 @@ module SuperDiff
3
3
  class InspectionTree
4
4
  include Enumerable
5
5
 
6
- def initialize(&block)
6
+ def initialize(disallowed_node_names: [], &block)
7
+ @disallowed_node_names = disallowed_node_names
7
8
  @nodes = []
8
9
 
9
10
  if block
@@ -11,6 +12,12 @@ module SuperDiff
11
12
  end
12
13
  end
13
14
 
15
+ Nodes.registry.each do |node_class|
16
+ define_method(node_class.method_name) do |*args, **options, &block|
17
+ add_node(node_class, *args, **options, &block)
18
+ end
19
+ end
20
+
14
21
  def each(&block)
15
22
  nodes.each(&block)
16
23
  end
@@ -19,129 +26,224 @@ module SuperDiff
19
26
  @_before_each_callbacks ||= Hash.new { |h, k| h[k] = [] }
20
27
  end
21
28
 
22
- def evaluate(object, as_single_line:, indent_level:)
23
- nodes.reduce("") do |str, node|
24
- str << node.evaluate(
25
- object,
26
- as_single_line: as_single_line,
27
- indent_level: indent_level,
28
- )
29
+ def render_to_string(object)
30
+ nodes.reduce("") do |string, node|
31
+ result = node.render_to_string(object)
32
+ string + result
29
33
  end
30
34
  end
31
35
 
32
- def evaluate_block(object, &block)
33
- instance_exec(object, &block)
34
- end
35
-
36
- def add_text(*args, &block)
37
- add_node :text, *args, &block
38
- end
39
-
40
- def when_multiline(&block)
41
- add_node :when_multiline, &block
42
- end
43
-
44
- def when_singleline(&block)
45
- add_node :when_singleline, &block
46
- end
47
-
48
- def add_break(*args, &block)
49
- add_node :break, *args, &block
50
- end
51
-
52
- def nested(&block)
53
- add_node :nesting, &block
54
- end
55
-
56
- def when_empty(&block)
57
- add_node :when_empty, &block
36
+ def render_to_lines(object, type:, indentation_level:)
37
+ nodes.
38
+ each_with_index.
39
+ reduce([TieredLines.new, "", ""]) do |
40
+ (tiered_lines, prelude, prefix),
41
+ (node, index)
42
+ |
43
+ UpdateTieredLines.call(
44
+ object: object,
45
+ type: type,
46
+ indentation_level: indentation_level,
47
+ nodes: nodes,
48
+ tiered_lines: tiered_lines,
49
+ prelude: prelude,
50
+ prefix: prefix,
51
+ node: node,
52
+ index: index,
53
+ )
54
+ end.
55
+ first
58
56
  end
59
57
 
60
- def when_non_empty(&block)
61
- add_node :when_non_empty, &block
58
+ def evaluate_block(object, &block)
59
+ instance_exec(object, &block)
62
60
  end
63
61
 
64
62
  def insert_array_inspection_of(array)
65
- # FIXME: why must this be inside the `nested`?
66
- add_break
67
-
68
63
  insert_separated_list(array) do |value|
69
- add_inspection_of value
64
+ # Have to do these shenanigans so that if value is a hash, Ruby
65
+ # doesn't try to interpret it as keyword args
66
+ if SuperDiff::Helpers.ruby_version_matches?(">= 2.7.1")
67
+ add_inspection_of(value, **{})
68
+ else
69
+ add_inspection_of(*[value, {}])
70
+ end
70
71
  end
71
72
  end
72
73
 
73
- def insert_hash_inspection_of(hash, initial_break: " ")
74
- # FIXME: why must this be inside the `nested`?
75
- add_break initial_break
74
+ def insert_hash_inspection_of(hash)
75
+ keys = hash.keys
76
76
 
77
- format_keys_as_kwargs = hash.keys.all? do |key|
77
+ format_keys_as_kwargs = keys.all? do |key|
78
78
  key.is_a?(Symbol)
79
79
  end
80
80
 
81
- insert_separated_list(hash) do |(key, value)|
81
+ insert_separated_list(keys) do |key|
82
82
  if format_keys_as_kwargs
83
- add_text key
84
- add_text ": "
83
+ as_prefix_when_rendering_to_lines do
84
+ add_text "#{key}: "
85
+ end
85
86
  else
86
- add_inspection_of key
87
- add_text " => "
87
+ as_prefix_when_rendering_to_lines do
88
+ add_inspection_of key, as_lines: false
89
+ add_text " => "
90
+ end
88
91
  end
89
92
 
90
- add_inspection_of value
93
+ # Have to do these shenanigans so that if hash[key] is a hash, Ruby
94
+ # doesn't try to interpret it as keyword args
95
+ if SuperDiff::Helpers.ruby_version_matches?(">= 2.7.1")
96
+ add_inspection_of(hash[key], **{})
97
+ else
98
+ add_inspection_of(*[hash[key], {}])
99
+ end
91
100
  end
92
101
  end
93
102
 
94
- def insert_separated_list(enumerable, separator: ",")
103
+ def insert_separated_list(enumerable, &block)
95
104
  enumerable.each_with_index do |value, index|
96
- if index > 0
97
- if separator.is_a?(Nodes::Base)
98
- append_node separator
99
- else
100
- add_text separator
105
+ as_lines_when_rendering_to_lines(
106
+ add_comma: index < enumerable.size - 1,
107
+ ) do
108
+ if index > 0
109
+ when_rendering_to_string do
110
+ add_text " "
111
+ end
101
112
  end
102
113
 
103
- add_break " "
114
+ evaluate_block(value, &block)
104
115
  end
105
-
106
- yield value
107
- end
108
- end
109
-
110
- def add_inspection_of(value = nil, &block)
111
- if block
112
- add_node :inspection, &block
113
- else
114
- add_node :inspection, value
115
- end
116
- end
117
-
118
- def apply_tree(tree)
119
- tree.each do |node|
120
- append_node(node.clone_with(tree: self))
121
116
  end
122
117
  end
123
118
 
124
119
  private
125
120
 
126
- attr_reader :nodes
121
+ attr_reader :disallowed_node_names, :nodes
127
122
 
128
- def add_node(type, *args, &block)
129
- append_node(build_node(type, *args, &block))
123
+ def add_node(node_class, *args, **options, &block)
124
+ if disallowed_node_names.include?(node_class.name)
125
+ raise DisallowedNodeError.create(node_name: node_class.name)
126
+ end
127
+
128
+ append_node(build_node(node_class, *args, **options, &block))
130
129
  end
131
130
 
132
131
  def append_node(node)
133
132
  nodes.push(node)
134
133
  end
135
134
 
136
- def build_node(type, *args, &block)
137
- Nodes.fetch(type).new(self, *args, &block)
135
+ def build_node(node_class, *args, **options, &block)
136
+ node_class.new(self, *args, **options, &block)
138
137
  end
139
138
 
140
- class BlockArgument
139
+ class UpdateTieredLines
141
140
  extend AttrExtras.mixin
142
141
 
143
- rattr_initialize [:object!, :as_single_line!]
144
- attr_query :as_single_line?
142
+ method_object [
143
+ :object!,
144
+ :type!,
145
+ :indentation_level!,
146
+ :nodes!,
147
+ :tiered_lines!,
148
+ :prelude!,
149
+ :prefix!,
150
+ :node!,
151
+ :index!
152
+ ]
153
+
154
+ def call
155
+ if rendering.is_a?(Array)
156
+ concat_with_lines
157
+ elsif rendering.is_a?(PrefixForNextNode)
158
+ add_to_prefix
159
+ elsif tiered_lines.any?
160
+ add_to_last_line
161
+ elsif index < nodes.size - 1 || rendering.is_a?(PreludeForNextNode)
162
+ add_to_prelude
163
+ else
164
+ add_to_lines
165
+ end
166
+ end
167
+
168
+ private
169
+
170
+ def concat_with_lines
171
+ additional_lines = prefix_with(
172
+ prefix,
173
+ prepend_with(prelude, rendering),
174
+ )
175
+ [tiered_lines + additional_lines, "", ""]
176
+ end
177
+
178
+ def prefix_with(prefix, text)
179
+ if prefix.empty?
180
+ text
181
+ else
182
+ [text[0].prefixed_with(prefix)] + text[1..-1]
183
+ end
184
+ end
185
+
186
+ def prepend_with(prelude, text)
187
+ if prelude.empty?
188
+ text
189
+ else
190
+ [text[0].with_value_prepended(prelude)] + text[1..-1]
191
+ end
192
+ end
193
+
194
+ def add_to_prefix
195
+ [tiered_lines, prelude, rendering + prefix]
196
+ end
197
+
198
+ def add_to_last_line
199
+ new_lines = tiered_lines[0..-2] + [
200
+ tiered_lines[-1].with_value_appended(rendering),
201
+ ]
202
+ [new_lines, prelude, prefix]
203
+ end
204
+
205
+ def add_to_prelude
206
+ [tiered_lines, prelude + rendering, prefix]
207
+ end
208
+
209
+ def add_to_lines
210
+ new_lines = tiered_lines + [
211
+ Line.new(
212
+ type: type,
213
+ indentation_level: indentation_level,
214
+ value: rendering,
215
+ ),
216
+ ]
217
+ [new_lines, prelude, prefix]
218
+ end
219
+
220
+ def rendering
221
+ if defined?(@_rendering)
222
+ @_rendering
223
+ else
224
+ @_rendering = node.render(
225
+ object,
226
+ preferably_as_lines: true,
227
+ type: type,
228
+ indentation_level: indentation_level,
229
+ )
230
+ end
231
+ end
232
+ end
233
+
234
+ class DisallowedNodeError < StandardError
235
+ def self.create(node_name:)
236
+ allocate.tap do |error|
237
+ error.node_name = node_name
238
+ error.__send__(:initialize)
239
+ end
240
+ end
241
+
242
+ attr_accessor :node_name
243
+
244
+ def initialize(_message = nil)
245
+ super("#{node_name} is not allowed to be used here!")
246
+ end
145
247
  end
146
248
  end
147
249
  end