canon 0.1.7 → 0.1.9
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.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +69 -92
- data/README.adoc +13 -13
- data/docs/.lycheeignore +69 -0
- data/docs/Gemfile +1 -0
- data/docs/_config.yml +90 -1
- data/docs/advanced/diff-classification.adoc +82 -2
- data/docs/advanced/extending-canon.adoc +193 -0
- data/docs/features/match-options/index.adoc +239 -1
- data/docs/internals/diffnode-enrichment.adoc +611 -0
- data/docs/internals/index.adoc +251 -0
- data/docs/lychee.toml +13 -6
- data/docs/understanding/architecture.adoc +749 -33
- data/docs/understanding/comparison-pipeline.adoc +122 -0
- data/lib/canon/cache.rb +129 -0
- data/lib/canon/comparison/dimensions/attribute_order_dimension.rb +68 -0
- data/lib/canon/comparison/dimensions/attribute_presence_dimension.rb +68 -0
- data/lib/canon/comparison/dimensions/attribute_values_dimension.rb +171 -0
- data/lib/canon/comparison/dimensions/base_dimension.rb +107 -0
- data/lib/canon/comparison/dimensions/comments_dimension.rb +121 -0
- data/lib/canon/comparison/dimensions/element_position_dimension.rb +90 -0
- data/lib/canon/comparison/dimensions/registry.rb +77 -0
- data/lib/canon/comparison/dimensions/structural_whitespace_dimension.rb +119 -0
- data/lib/canon/comparison/dimensions/text_content_dimension.rb +96 -0
- data/lib/canon/comparison/dimensions.rb +54 -0
- data/lib/canon/comparison/format_detector.rb +87 -0
- data/lib/canon/comparison/html_comparator.rb +70 -26
- data/lib/canon/comparison/html_compare_profile.rb +8 -2
- data/lib/canon/comparison/html_parser.rb +80 -0
- data/lib/canon/comparison/json_comparator.rb +12 -0
- data/lib/canon/comparison/json_parser.rb +19 -0
- data/lib/canon/comparison/markup_comparator.rb +293 -0
- data/lib/canon/comparison/match_options/base_resolver.rb +150 -0
- data/lib/canon/comparison/match_options/json_resolver.rb +82 -0
- data/lib/canon/comparison/match_options/xml_resolver.rb +151 -0
- data/lib/canon/comparison/match_options/yaml_resolver.rb +87 -0
- data/lib/canon/comparison/match_options.rb +68 -463
- data/lib/canon/comparison/profile_definition.rb +149 -0
- data/lib/canon/comparison/ruby_object_comparator.rb +180 -0
- data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +7 -10
- data/lib/canon/comparison/whitespace_sensitivity.rb +208 -0
- data/lib/canon/comparison/xml_comparator/attribute_comparator.rb +177 -0
- data/lib/canon/comparison/xml_comparator/attribute_filter.rb +136 -0
- data/lib/canon/comparison/xml_comparator/child_comparison.rb +197 -0
- data/lib/canon/comparison/xml_comparator/diff_node_builder.rb +115 -0
- data/lib/canon/comparison/xml_comparator/namespace_comparator.rb +186 -0
- data/lib/canon/comparison/xml_comparator/node_parser.rb +79 -0
- data/lib/canon/comparison/xml_comparator/node_type_comparator.rb +102 -0
- data/lib/canon/comparison/xml_comparator.rb +97 -684
- data/lib/canon/comparison/xml_node_comparison.rb +319 -0
- data/lib/canon/comparison/xml_parser.rb +19 -0
- data/lib/canon/comparison/yaml_comparator.rb +3 -3
- data/lib/canon/comparison.rb +265 -110
- data/lib/canon/diff/diff_classifier.rb +101 -2
- data/lib/canon/diff/diff_node.rb +32 -2
- data/lib/canon/diff/formatting_detector.rb +1 -1
- data/lib/canon/diff/node_serializer.rb +191 -0
- data/lib/canon/diff/path_builder.rb +143 -0
- data/lib/canon/diff_formatter/by_line/base_formatter.rb +251 -0
- data/lib/canon/diff_formatter/by_line/html_formatter.rb +6 -248
- data/lib/canon/diff_formatter/by_line/xml_formatter.rb +38 -229
- data/lib/canon/diff_formatter/diff_detail_formatter/color_helper.rb +30 -0
- data/lib/canon/diff_formatter/diff_detail_formatter/dimension_formatter.rb +579 -0
- data/lib/canon/diff_formatter/diff_detail_formatter/location_extractor.rb +121 -0
- data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +253 -0
- data/lib/canon/diff_formatter/diff_detail_formatter/text_utils.rb +61 -0
- data/lib/canon/diff_formatter/diff_detail_formatter.rb +31 -1028
- data/lib/canon/diff_formatter.rb +1 -1
- data/lib/canon/rspec_matchers.rb +38 -9
- data/lib/canon/tree_diff/operation_converter.rb +92 -338
- data/lib/canon/tree_diff/operation_converter_helpers/metadata_enricher.rb +71 -0
- data/lib/canon/tree_diff/operation_converter_helpers/post_processor.rb +103 -0
- data/lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb +168 -0
- data/lib/canon/tree_diff/operation_converter_helpers/update_change_handler.rb +188 -0
- data/lib/canon/version.rb +1 -1
- data/lib/canon/xml/data_model.rb +24 -13
- metadata +48 -2
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Canon
|
|
4
|
+
module Comparison
|
|
5
|
+
# XML Node Comparison Utilities
|
|
6
|
+
#
|
|
7
|
+
# Provides public comparison methods for XML/HTML nodes.
|
|
8
|
+
# This module extracts shared comparison logic that was previously
|
|
9
|
+
# accessed via send() from HtmlComparator.
|
|
10
|
+
module XmlNodeComparison
|
|
11
|
+
# Main comparison dispatcher for XML nodes
|
|
12
|
+
#
|
|
13
|
+
# This method handles the high-level comparison logic, delegating
|
|
14
|
+
# to specific comparison methods based on node types.
|
|
15
|
+
#
|
|
16
|
+
# @param node1 [Object] First node
|
|
17
|
+
# @param node2 [Object] Second node
|
|
18
|
+
# @param opts [Hash] Comparison options
|
|
19
|
+
# @param child_opts [Hash] Options for child comparison
|
|
20
|
+
# @param diff_children [Boolean] Whether to diff children
|
|
21
|
+
# @param differences [Array] Array to append differences to
|
|
22
|
+
# @return [Symbol] Comparison result constant
|
|
23
|
+
def self.compare_nodes(node1, node2, opts, child_opts, diff_children,
|
|
24
|
+
differences)
|
|
25
|
+
# Handle DocumentFragment nodes - compare their children instead
|
|
26
|
+
if node1.is_a?(Nokogiri::XML::DocumentFragment) &&
|
|
27
|
+
node2.is_a?(Nokogiri::XML::DocumentFragment)
|
|
28
|
+
return compare_document_fragments(node1, node2, opts, child_opts,
|
|
29
|
+
diff_children, differences)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Check if nodes should be excluded
|
|
33
|
+
return Comparison::EQUIVALENT if node_excluded?(node1, opts) &&
|
|
34
|
+
node_excluded?(node2, opts)
|
|
35
|
+
|
|
36
|
+
if node_excluded?(node1, opts) || node_excluded?(node2, opts)
|
|
37
|
+
add_difference(node1, node2, Comparison::MISSING_NODE,
|
|
38
|
+
Comparison::MISSING_NODE, :text_content, opts,
|
|
39
|
+
differences)
|
|
40
|
+
return Comparison::MISSING_NODE
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Check node types match
|
|
44
|
+
unless same_node_type?(node1, node2)
|
|
45
|
+
add_difference(node1, node2, Comparison::UNEQUAL_NODES_TYPES,
|
|
46
|
+
Comparison::UNEQUAL_NODES_TYPES, :text_content, opts,
|
|
47
|
+
differences)
|
|
48
|
+
return Comparison::UNEQUAL_NODES_TYPES
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
# Dispatch based on node type
|
|
52
|
+
dispatch_by_node_type(node1, node2, opts, child_opts, diff_children,
|
|
53
|
+
differences)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Filter children based on options
|
|
57
|
+
#
|
|
58
|
+
# Removes nodes that should be excluded from comparison based on
|
|
59
|
+
# options like :ignore_nodes, :ignore_comments, etc.
|
|
60
|
+
#
|
|
61
|
+
# @param children [Array] Array of child nodes
|
|
62
|
+
# @param opts [Hash] Comparison options
|
|
63
|
+
# @return [Array] Filtered array of children
|
|
64
|
+
def self.filter_children(children, opts)
|
|
65
|
+
children.reject do |child|
|
|
66
|
+
node_excluded?(child, opts)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Compare document fragments by comparing their children
|
|
71
|
+
#
|
|
72
|
+
# @param node1 [Nokogiri::XML::DocumentFragment] First fragment
|
|
73
|
+
# @param node2 [Nokogiri::XML::DocumentFragment] Second fragment
|
|
74
|
+
# @param opts [Hash] Comparison options
|
|
75
|
+
# @param child_opts [Hash] Options for child comparison
|
|
76
|
+
# @param diff_children [Boolean] Whether to diff children
|
|
77
|
+
# @param differences [Array] Array to append differences to
|
|
78
|
+
# @return [Symbol] Comparison result constant
|
|
79
|
+
def self.compare_document_fragments(node1, node2, opts, child_opts,
|
|
80
|
+
diff_children, differences)
|
|
81
|
+
childrenode1 = node1.children.to_a
|
|
82
|
+
childrenode2 = node2.children.to_a
|
|
83
|
+
|
|
84
|
+
if childrenode1.length != childrenode2.length
|
|
85
|
+
add_difference(node1, node2, Comparison::UNEQUAL_ELEMENTS,
|
|
86
|
+
Comparison::UNEQUAL_ELEMENTS, :text_content, opts,
|
|
87
|
+
differences)
|
|
88
|
+
Comparison::UNEQUAL_ELEMENTS
|
|
89
|
+
elsif childrenode1.empty?
|
|
90
|
+
Comparison::EQUIVALENT
|
|
91
|
+
else
|
|
92
|
+
# Compare each pair of children
|
|
93
|
+
result = Comparison::EQUIVALENT
|
|
94
|
+
childrenode1.zip(childrenode2).each do |child1, child2|
|
|
95
|
+
child_result = compare_nodes(child1, child2, opts, child_opts,
|
|
96
|
+
diff_children, differences)
|
|
97
|
+
result = child_result unless result == Comparison::EQUIVALENT
|
|
98
|
+
end
|
|
99
|
+
result
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Dispatch comparison based on node type
|
|
104
|
+
#
|
|
105
|
+
# @param node1 [Object] First node
|
|
106
|
+
# @param node2 [Object] Second node
|
|
107
|
+
# @param opts [Hash] Comparison options
|
|
108
|
+
# @param child_opts [Hash] Options for child comparison
|
|
109
|
+
# @param diff_children [Boolean] Whether to diff children
|
|
110
|
+
# @param differences [Array] Array to append differences to
|
|
111
|
+
# @return [Symbol] Comparison result constant
|
|
112
|
+
def self.dispatch_by_node_type(node1, node2, opts, child_opts,
|
|
113
|
+
diff_children, differences)
|
|
114
|
+
# Canon::Xml::Node types use .node_type method that returns symbols
|
|
115
|
+
# Nokogiri also has .node_type but returns integers, so check for Symbol
|
|
116
|
+
if node1.respond_to?(:node_type) && node2.respond_to?(:node_type) &&
|
|
117
|
+
node1.node_type.is_a?(Symbol) && node2.node_type.is_a?(Symbol)
|
|
118
|
+
dispatch_canon_node_type(node1, node2, opts, child_opts,
|
|
119
|
+
diff_children, differences)
|
|
120
|
+
# Moxml/Nokogiri types use .element?, .text?, etc. methods
|
|
121
|
+
else
|
|
122
|
+
dispatch_legacy_node_type(node1, node2, opts, child_opts,
|
|
123
|
+
diff_children, differences)
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# Private helper methods
|
|
128
|
+
|
|
129
|
+
# Check if a node should be excluded from comparison
|
|
130
|
+
#
|
|
131
|
+
# @param node [Object] Node to check
|
|
132
|
+
# @param opts [Hash] Comparison options
|
|
133
|
+
# @return [Boolean] true if node should be excluded
|
|
134
|
+
def self.node_excluded?(node, opts)
|
|
135
|
+
return false if node.nil?
|
|
136
|
+
return true if opts[:ignore_nodes]&.include?(node)
|
|
137
|
+
return true if opts[:ignore_comments] && comment_node?(node)
|
|
138
|
+
return true if opts[:ignore_text_nodes] && text_node?(node)
|
|
139
|
+
|
|
140
|
+
# Check structural_whitespace match option
|
|
141
|
+
match_opts = opts[:match_opts]
|
|
142
|
+
return false unless match_opts
|
|
143
|
+
|
|
144
|
+
# Filter out whitespace-only text nodes based on structural_whitespace setting
|
|
145
|
+
# - :ignore or :normalize: Filter all whitespace-only text nodes
|
|
146
|
+
# - :strict: Preserve all whitespace-only text nodes (don't filter any)
|
|
147
|
+
if text_node?(node) && %i[ignore
|
|
148
|
+
normalize].include?(match_opts[:structural_whitespace])
|
|
149
|
+
text = node_text(node)
|
|
150
|
+
return true if MatchOptions.normalize_text(text).empty?
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
false
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Check if two nodes are of the same type
|
|
157
|
+
#
|
|
158
|
+
# @param node1 [Object] First node
|
|
159
|
+
# @param node2 [Object] Second node
|
|
160
|
+
# @return [Boolean] true if nodes are same type
|
|
161
|
+
def self.same_node_type?(node1, node2)
|
|
162
|
+
return false if node1.class != node2.class
|
|
163
|
+
|
|
164
|
+
# For Nokogiri/Canon::Xml nodes, check node type
|
|
165
|
+
if node1.respond_to?(:node_type) && node2.respond_to?(:node_type)
|
|
166
|
+
node1.node_type == node2.node_type
|
|
167
|
+
else
|
|
168
|
+
true
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
# Check if a node is a comment node
|
|
173
|
+
#
|
|
174
|
+
# @param node [Object] Node to check
|
|
175
|
+
# @return [Boolean] true if node is a comment
|
|
176
|
+
def self.comment_node?(node)
|
|
177
|
+
node.respond_to?(:comment?) && node.comment? ||
|
|
178
|
+
node.respond_to?(:node_type) && node.node_type == :comment
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
# Check if a node is a text node
|
|
182
|
+
#
|
|
183
|
+
# @param node [Object] Node to check
|
|
184
|
+
# @return [Boolean] true if node is a text node
|
|
185
|
+
def self.text_node?(node)
|
|
186
|
+
node.respond_to?(:text?) && node.text? &&
|
|
187
|
+
!node.respond_to?(:element?) ||
|
|
188
|
+
node.respond_to?(:node_type) && node.node_type == :text
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
# Extract text content from a node
|
|
192
|
+
#
|
|
193
|
+
# @param node [Object] Node to extract text from
|
|
194
|
+
# @return [String] Text content
|
|
195
|
+
def self.node_text(node)
|
|
196
|
+
return "" unless node
|
|
197
|
+
|
|
198
|
+
if node.respond_to?(:content)
|
|
199
|
+
node.content.to_s
|
|
200
|
+
elsif node.respond_to?(:text)
|
|
201
|
+
node.text.to_s
|
|
202
|
+
elsif node.respond_to?(:value)
|
|
203
|
+
node.value.to_s
|
|
204
|
+
else
|
|
205
|
+
""
|
|
206
|
+
end
|
|
207
|
+
end
|
|
208
|
+
|
|
209
|
+
# Dispatch by Canon::Xml::Node type
|
|
210
|
+
def self.dispatch_canon_node_type(node1, node2, opts, child_opts,
|
|
211
|
+
diff_children, differences)
|
|
212
|
+
# Import XmlComparator to use its comparison methods
|
|
213
|
+
require_relative "xml_comparator"
|
|
214
|
+
|
|
215
|
+
case node1.node_type
|
|
216
|
+
when :root
|
|
217
|
+
XmlComparator.compare_children(node1, node2, opts, child_opts,
|
|
218
|
+
diff_children, differences)
|
|
219
|
+
when :element
|
|
220
|
+
XmlComparator.compare_element_nodes(node1, node2, opts, child_opts,
|
|
221
|
+
diff_children, differences)
|
|
222
|
+
when :text
|
|
223
|
+
XmlComparator.compare_text_nodes(node1, node2, opts, differences)
|
|
224
|
+
when :comment
|
|
225
|
+
XmlComparator.compare_comment_nodes(node1, node2, opts, differences)
|
|
226
|
+
when :cdata
|
|
227
|
+
XmlComparator.compare_text_nodes(node1, node2, opts, differences)
|
|
228
|
+
when :processing_instruction
|
|
229
|
+
XmlComparator.compare_processing_instruction_nodes(node1, node2,
|
|
230
|
+
opts, differences)
|
|
231
|
+
else
|
|
232
|
+
Comparison::EQUIVALENT
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
# Dispatch by legacy Nokogiri/Moxml node type
|
|
237
|
+
def self.dispatch_legacy_node_type(node1, node2, opts, child_opts,
|
|
238
|
+
diff_children, differences)
|
|
239
|
+
# Import XmlComparator to use its comparison methods
|
|
240
|
+
require_relative "xml_comparator"
|
|
241
|
+
|
|
242
|
+
if node1.respond_to?(:element?) && node1.element?
|
|
243
|
+
XmlComparator.compare_element_nodes(node1, node2, opts, child_opts,
|
|
244
|
+
diff_children, differences)
|
|
245
|
+
elsif node1.respond_to?(:text?) && node1.text?
|
|
246
|
+
XmlComparator.compare_text_nodes(node1, node2, opts, differences)
|
|
247
|
+
elsif node1.respond_to?(:comment?) && node1.comment?
|
|
248
|
+
XmlComparator.compare_comment_nodes(node1, node2, opts, differences)
|
|
249
|
+
elsif node1.respond_to?(:cdata?) && node1.cdata?
|
|
250
|
+
XmlComparator.compare_text_nodes(node1, node2, opts, differences)
|
|
251
|
+
elsif node1.respond_to?(:processing_instruction?) && node1.processing_instruction?
|
|
252
|
+
XmlComparator.compare_processing_instruction_nodes(node1, node2,
|
|
253
|
+
opts, differences)
|
|
254
|
+
elsif node1.respond_to?(:root)
|
|
255
|
+
XmlComparator.compare_document_nodes(node1, node2, opts, child_opts,
|
|
256
|
+
diff_children, differences)
|
|
257
|
+
else
|
|
258
|
+
Comparison::EQUIVALENT
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# Add a difference to the differences array
|
|
263
|
+
#
|
|
264
|
+
# @param node1 [Object] First node
|
|
265
|
+
# @param node2 [Object] Second node
|
|
266
|
+
# @param diff1 [Symbol] Difference type for node1
|
|
267
|
+
# @param diff2 [Symbol] Difference type for node2
|
|
268
|
+
# @param dimension [Symbol] The dimension of the difference
|
|
269
|
+
# @param opts [Hash] Comparison options
|
|
270
|
+
# @param differences [Array] Array to append difference to
|
|
271
|
+
def self.add_difference(node1, node2, diff1, diff2, dimension, opts,
|
|
272
|
+
differences)
|
|
273
|
+
return unless opts[:verbose]
|
|
274
|
+
|
|
275
|
+
require_relative "xml_comparator"
|
|
276
|
+
XmlComparator.add_difference(node1, node2, diff1, diff2, dimension,
|
|
277
|
+
opts, differences)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
# Serialize a Canon::Xml::Node to XML string
|
|
281
|
+
#
|
|
282
|
+
# This utility method handles serialization of different node types
|
|
283
|
+
# to their string representation for display and debugging purposes.
|
|
284
|
+
#
|
|
285
|
+
# @param node [Canon::Xml::Node, Object] Node to serialize
|
|
286
|
+
# @return [String] XML string representation
|
|
287
|
+
def self.serialize_node_to_xml(node)
|
|
288
|
+
if node.is_a?(Canon::Xml::Nodes::RootNode)
|
|
289
|
+
# Serialize all children of root
|
|
290
|
+
node.children.map { |child| serialize_node_to_xml(child) }.join
|
|
291
|
+
elsif node.is_a?(Canon::Xml::Nodes::ElementNode)
|
|
292
|
+
# Serialize element with attributes and children
|
|
293
|
+
attrs = node.attribute_nodes.map do |a|
|
|
294
|
+
" #{a.name}=\"#{a.value}\""
|
|
295
|
+
end.join
|
|
296
|
+
children_xml = node.children.map do |c|
|
|
297
|
+
serialize_node_to_xml(c)
|
|
298
|
+
end.join
|
|
299
|
+
|
|
300
|
+
if children_xml.empty?
|
|
301
|
+
"<#{node.name}#{attrs}/>"
|
|
302
|
+
else
|
|
303
|
+
"<#{node.name}#{attrs}>#{children_xml}</#{node.name}>"
|
|
304
|
+
end
|
|
305
|
+
elsif node.is_a?(Canon::Xml::Nodes::TextNode)
|
|
306
|
+
node.value
|
|
307
|
+
elsif node.is_a?(Canon::Xml::Nodes::CommentNode)
|
|
308
|
+
"<!--#{node.value}-->"
|
|
309
|
+
elsif node.is_a?(Canon::Xml::Nodes::ProcessingInstructionNode)
|
|
310
|
+
"<?#{node.target} #{node.data}?>"
|
|
311
|
+
elsif node.respond_to?(:to_xml)
|
|
312
|
+
node.to_xml
|
|
313
|
+
else
|
|
314
|
+
node.to_s
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
end
|
|
319
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Canon
|
|
4
|
+
module Comparison
|
|
5
|
+
# Public API for XML parsing operations
|
|
6
|
+
# Provides access to parsing functionality without using send()
|
|
7
|
+
class XmlParser
|
|
8
|
+
# Parse an object to Canon::Xml::Node with preprocessing
|
|
9
|
+
#
|
|
10
|
+
# @param obj [String, Object] Object to parse
|
|
11
|
+
# @param preprocessing [Symbol] Preprocessing mode
|
|
12
|
+
# @return [Canon::Xml::Node] Parsed node
|
|
13
|
+
def self.parse_node(obj, preprocessing = :none)
|
|
14
|
+
# Delegate to XmlComparator's private method via public API
|
|
15
|
+
XmlComparator::NodeParser.parse(obj, preprocessing)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "yaml"
|
|
4
|
-
require_relative "json_comparator"
|
|
5
4
|
require_relative "match_options"
|
|
6
5
|
require_relative "comparison_result"
|
|
6
|
+
require_relative "ruby_object_comparator"
|
|
7
7
|
|
|
8
8
|
module Canon
|
|
9
9
|
module Comparison
|
|
@@ -60,8 +60,8 @@ module Canon
|
|
|
60
60
|
obj2 = parse_yaml(yaml2)
|
|
61
61
|
|
|
62
62
|
differences = []
|
|
63
|
-
result =
|
|
64
|
-
|
|
63
|
+
result = RubyObjectComparator.compare_objects(obj1, obj2, opts,
|
|
64
|
+
differences, "")
|
|
65
65
|
|
|
66
66
|
if opts[:verbose]
|
|
67
67
|
# Format YAML for display
|