canon 0.2.11 → 0.2.12

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 (148) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +12 -22
  3. data/Rakefile +5 -2
  4. data/lib/canon/cache.rb +3 -1
  5. data/lib/canon/cli.rb +0 -3
  6. data/lib/canon/commands/diff_command.rb +0 -6
  7. data/lib/canon/commands/format_command.rb +0 -4
  8. data/lib/canon/commands.rb +9 -0
  9. data/lib/canon/comparison/child_realignment.rb +0 -2
  10. data/lib/canon/comparison/compare_profile.rb +30 -36
  11. data/lib/canon/comparison/comparison_result.rb +0 -2
  12. data/lib/canon/comparison/diff_node_builder.rb +353 -0
  13. data/lib/canon/comparison/dimensions/dimension.rb +51 -0
  14. data/lib/canon/comparison/dimensions/dimension_set.rb +49 -0
  15. data/lib/canon/comparison/dimensions/registry.rb +101 -60
  16. data/lib/canon/comparison/dimensions.rb +15 -46
  17. data/lib/canon/comparison/html_comparator.rb +18 -141
  18. data/lib/canon/comparison/html_compare_profile.rb +15 -18
  19. data/lib/canon/comparison/json_comparator.rb +4 -165
  20. data/lib/canon/comparison/json_parser.rb +0 -2
  21. data/lib/canon/comparison/markup_comparator.rb +14 -210
  22. data/lib/canon/comparison/match_options/base_resolver.rb +18 -29
  23. data/lib/canon/comparison/match_options/json_resolver.rb +4 -28
  24. data/lib/canon/comparison/match_options/xml_resolver.rb +4 -45
  25. data/lib/canon/comparison/match_options/yaml_resolver.rb +4 -30
  26. data/lib/canon/comparison/match_options.rb +13 -88
  27. data/lib/canon/comparison/pipeline.rb +269 -0
  28. data/lib/canon/comparison/profile_definition.rb +0 -2
  29. data/lib/canon/comparison/ruby_object_comparator.rb +1 -1
  30. data/lib/canon/comparison/strategies/match_strategy_factory.rb +9 -58
  31. data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +4 -11
  32. data/lib/canon/comparison/strategies.rb +16 -0
  33. data/lib/canon/comparison/xml_comparator/attribute_comparator.rb +0 -3
  34. data/lib/canon/comparison/xml_comparator/attribute_filter.rb +0 -3
  35. data/lib/canon/comparison/xml_comparator/child_comparison.rb +0 -6
  36. data/lib/canon/comparison/xml_comparator/namespace_comparator.rb +1 -6
  37. data/lib/canon/comparison/xml_comparator/node_parser.rb +0 -4
  38. data/lib/canon/comparison/xml_comparator.rb +4 -492
  39. data/lib/canon/comparison/xml_comparator_helpers.rb +21 -0
  40. data/lib/canon/comparison/xml_node_comparison.rb +4 -119
  41. data/lib/canon/comparison/yaml_comparator.rb +0 -3
  42. data/lib/canon/comparison.rb +143 -266
  43. data/lib/canon/config/config_dsl.rb +159 -0
  44. data/lib/canon/config/env_provider.rb +0 -3
  45. data/lib/canon/config/env_schema.rb +48 -58
  46. data/lib/canon/config/profile_loader.rb +0 -1
  47. data/lib/canon/config.rb +116 -468
  48. data/lib/canon/diff/diff_block_builder.rb +0 -2
  49. data/lib/canon/diff/diff_classifier.rb +0 -5
  50. data/lib/canon/diff/diff_context.rb +0 -2
  51. data/lib/canon/diff/diff_context_builder.rb +0 -2
  52. data/lib/canon/diff/diff_line_builder.rb +0 -3
  53. data/lib/canon/diff/diff_node_enricher.rb +0 -4
  54. data/lib/canon/diff/diff_node_mapper.rb +0 -4
  55. data/lib/canon/diff/diff_report_builder.rb +0 -4
  56. data/lib/canon/diff/formatting_detector.rb +0 -1
  57. data/lib/canon/diff/node_serializer.rb +0 -7
  58. data/lib/canon/diff.rb +39 -0
  59. data/lib/canon/diff_formatter/by_line/base_formatter.rb +4 -17
  60. data/lib/canon/diff_formatter/by_line/html_formatter.rb +7 -19
  61. data/lib/canon/diff_formatter/by_line/json_formatter.rb +0 -3
  62. data/lib/canon/diff_formatter/by_line/simple_formatter.rb +0 -3
  63. data/lib/canon/diff_formatter/by_line/xml_formatter.rb +7 -26
  64. data/lib/canon/diff_formatter/by_line/yaml_formatter.rb +0 -3
  65. data/lib/canon/diff_formatter/by_object/base_formatter.rb +8 -15
  66. data/lib/canon/diff_formatter/by_object/json_formatter.rb +0 -2
  67. data/lib/canon/diff_formatter/by_object/xml_formatter.rb +0 -2
  68. data/lib/canon/diff_formatter/by_object/yaml_formatter.rb +0 -2
  69. data/lib/canon/diff_formatter/debug_output.rb +0 -2
  70. data/lib/canon/diff_formatter/diff_detail_formatter/dimension_formatter.rb +24 -58
  71. data/lib/canon/diff_formatter/diff_detail_formatter/location_extractor.rb +0 -2
  72. data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +1 -2
  73. data/lib/canon/diff_formatter/diff_detail_formatter/text_utils.rb +1 -7
  74. data/lib/canon/diff_formatter/diff_detail_formatter.rb +0 -7
  75. data/lib/canon/diff_formatter/diff_detail_formatter_helpers.rb +23 -0
  76. data/lib/canon/diff_formatter.rb +11 -9
  77. data/lib/canon/formatters/html4_formatter.rb +0 -2
  78. data/lib/canon/formatters/html5_formatter.rb +0 -2
  79. data/lib/canon/formatters/html_formatter.rb +0 -3
  80. data/lib/canon/formatters/json_formatter.rb +0 -1
  81. data/lib/canon/formatters/xml_formatter.rb +0 -4
  82. data/lib/canon/formatters/yaml_formatter.rb +0 -1
  83. data/lib/canon/formatters.rb +16 -0
  84. data/lib/canon/html/data_model.rb +0 -10
  85. data/lib/canon/html.rb +4 -3
  86. data/lib/canon/options/cli_generator.rb +0 -2
  87. data/lib/canon/options/registry.rb +0 -2
  88. data/lib/canon/options.rb +9 -0
  89. data/lib/canon/pretty_printer/html.rb +0 -1
  90. data/lib/canon/pretty_printer/xml_normalized.rb +0 -2
  91. data/lib/canon/pretty_printer.rb +12 -0
  92. data/lib/canon/tree_diff/adapters/html_adapter.rb +1 -1
  93. data/lib/canon/tree_diff/adapters.rb +14 -0
  94. data/lib/canon/tree_diff/core/attribute_comparator.rb +0 -6
  95. data/lib/canon/tree_diff/core/node_signature.rb +1 -1
  96. data/lib/canon/tree_diff/core/tree_node.rb +12 -5
  97. data/lib/canon/tree_diff/core.rb +17 -0
  98. data/lib/canon/tree_diff/matchers/hash_matcher.rb +0 -7
  99. data/lib/canon/tree_diff/matchers/similarity_matcher.rb +1 -5
  100. data/lib/canon/tree_diff/matchers/structural_propagator.rb +1 -5
  101. data/lib/canon/tree_diff/matchers.rb +15 -0
  102. data/lib/canon/tree_diff/operation_converter.rb +0 -8
  103. data/lib/canon/tree_diff/operation_converter_helpers/metadata_enricher.rb +2 -12
  104. data/lib/canon/tree_diff/operation_converter_helpers/post_processor.rb +13 -7
  105. data/lib/canon/tree_diff/operation_converter_helpers/reason_builder.rb +2 -2
  106. data/lib/canon/tree_diff/operation_converter_helpers/update_change_handler.rb +4 -6
  107. data/lib/canon/tree_diff/operation_converter_helpers.rb +18 -0
  108. data/lib/canon/tree_diff/operations/operation_detector.rb +2 -5
  109. data/lib/canon/tree_diff/operations.rb +13 -0
  110. data/lib/canon/tree_diff.rb +26 -27
  111. data/lib/canon/validators/base_validator.rb +0 -2
  112. data/lib/canon/validators/html_validator.rb +0 -1
  113. data/lib/canon/validators/json_validator.rb +0 -1
  114. data/lib/canon/validators/xml_validator.rb +0 -1
  115. data/lib/canon/validators/yaml_validator.rb +0 -1
  116. data/lib/canon/validators.rb +12 -0
  117. data/lib/canon/version.rb +1 -1
  118. data/lib/canon/xml/c14n.rb +0 -4
  119. data/lib/canon/xml/data_model.rb +0 -10
  120. data/lib/canon/xml/line_range_mapper.rb +0 -2
  121. data/lib/canon/xml/nodes/attribute_node.rb +0 -2
  122. data/lib/canon/xml/nodes/comment_node.rb +0 -2
  123. data/lib/canon/xml/nodes/element_node.rb +0 -2
  124. data/lib/canon/xml/nodes/namespace_node.rb +0 -2
  125. data/lib/canon/xml/nodes/processing_instruction_node.rb +0 -2
  126. data/lib/canon/xml/nodes/root_node.rb +0 -2
  127. data/lib/canon/xml/nodes/text_node.rb +0 -2
  128. data/lib/canon/xml/nodes.rb +19 -0
  129. data/lib/canon/xml/processor.rb +0 -5
  130. data/lib/canon/xml/sax_builder.rb +0 -7
  131. data/lib/canon/xml.rb +33 -0
  132. data/lib/canon/xml_backend.rb +50 -14
  133. data/lib/canon/xml_parsing.rb +4 -2
  134. data/lib/canon.rb +25 -15
  135. data/lib/tasks/performance.rake +0 -58
  136. data/lib/tasks/performance_comparator.rb +132 -65
  137. data/lib/tasks/performance_helpers.rb +4 -249
  138. data/lib/tasks/performance_report.rb +309 -0
  139. metadata +24 -11
  140. data/lib/canon/comparison/dimensions/attribute_order_dimension.rb +0 -64
  141. data/lib/canon/comparison/dimensions/attribute_presence_dimension.rb +0 -64
  142. data/lib/canon/comparison/dimensions/attribute_values_dimension.rb +0 -167
  143. data/lib/canon/comparison/dimensions/base_dimension.rb +0 -107
  144. data/lib/canon/comparison/dimensions/comments_dimension.rb +0 -117
  145. data/lib/canon/comparison/dimensions/element_position_dimension.rb +0 -86
  146. data/lib/canon/comparison/dimensions/structural_whitespace_dimension.rb +0 -115
  147. data/lib/canon/comparison/dimensions/text_content_dimension.rb +0 -102
  148. data/lib/canon/comparison/xml_comparator/diff_node_builder.rb +0 -300
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "node_inspector"
4
-
5
3
  module Canon
6
4
  module Comparison
7
5
  # XML Node Comparison Utilities
@@ -78,18 +76,9 @@ differences)
78
76
  differences)
79
77
  end
80
78
 
81
- # Filter children based on options
82
- #
83
- # Removes nodes that should be excluded from comparison based on
84
- # options like :ignore_nodes, :ignore_comments, etc.
85
- #
86
- # @param children [Array] Array of child nodes
87
- # @param opts [Hash] Comparison options
88
- # @return [Array] Filtered array of children
79
+ # Filter children delegates to MarkupComparator.
89
80
  def self.filter_children(children, opts)
90
- children.reject do |child|
91
- node_excluded?(child, opts)
92
- end
81
+ MarkupComparator.filter_children(children, opts)
93
82
  end
94
83
 
95
84
  # Build a side-specific opts copy that activates the pretty-print
@@ -193,70 +182,9 @@ diff_children, differences)
193
182
 
194
183
  # Private helper methods
195
184
 
196
- # Check if a node should be excluded from comparison
197
- #
198
- # @param node [Object] Node to check
199
- # @param opts [Hash] Comparison options
200
- # @return [Boolean] true if node should be excluded
185
+ # Check if a node should be excluded delegates to MarkupComparator.
201
186
  def self.node_excluded?(node, opts)
202
- return false if node.nil?
203
-
204
- return true if opts[:ignore_nodes]&.include?(node)
205
- return true if opts[:ignore_comments] && comment_node?(node)
206
- return true if opts[:ignore_text_nodes] && text_node?(node)
207
-
208
- # Check match options
209
- match_opts = opts[:match_opts]
210
- return false unless match_opts
211
-
212
- # Filter comments based on match options and format
213
- # HTML: Filter comments to avoid spurious differences from zip pairing
214
- # BUT only when not in verbose mode (verbose needs differences recorded)
215
- # XML: Don't filter comments (allow informative differences to be recorded)
216
- if match_opts[:comments] == :ignore && comment_node?(node)
217
- # In verbose mode, don't filter comments - we want to record the differences
218
- return false if opts[:verbose]
219
-
220
- # Only filter comments for HTML, not XML (when not verbose)
221
- format = opts[:format] || match_opts[:format]
222
- if %i[html html4 html5].include?(format)
223
- return true
224
- end
225
- end
226
-
227
- # Strip whitespace-only text nodes based on parent element configuration.
228
- # Use preserve_whitespace_elements / strip_whitespace_elements to control.
229
- # Blacklist (strip) > preserve > collapse > format defaults.
230
- return false unless text_node?(node) && node.parent
231
- return false unless MatchOptions.normalize_text(node_text(node)).empty?
232
-
233
- # HTML-specific: NBSP (U+00A0) is never insignificant whitespace —
234
- # it always renders as a visible non-breaking space.
235
- format = opts[:format] || match_opts[:format]
236
- if %i[html html4 html5].include?(format)
237
- return false if WhitespaceSensitivity.contains_nbsp?(node_text(node))
238
-
239
- # Whitespace between inline element siblings is semantically
240
- # significant (renders as a visible gap) and must not be stripped.
241
- return false if WhitespaceSensitivity.inline_whitespace_significant?(node)
242
- end
243
-
244
- return true unless WhitespaceSensitivity.whitespace_preserved?(
245
- node.parent, match_opts
246
- )
247
-
248
- # When the pretty-print-side flag is active (set by opts_for_side in
249
- # ChildComparison.compare), drop whitespace-only text nodes that start
250
- # with "\n" inside :collapse elements — they are structural indentation
251
- # from the pretty-printer, not content. Space-only nodes (no "\n") are
252
- # real inline content and are kept for normalised comparison.
253
- # :preserve elements are always left unchanged.
254
- if match_opts[:_pretty_print_side_active]
255
- ws_class = WhitespaceSensitivity.classify_text_node(node, opts)
256
- return true if ws_class == :collapse && node_text(node).start_with?("\n")
257
- end
258
-
259
- false
187
+ MarkupComparator.node_excluded?(node, opts)
260
188
  end
261
189
 
262
190
  # Check if this is a comment vs non-comment comparison
@@ -337,9 +265,6 @@ diff_children, differences)
337
265
  # Dispatch by Canon::Xml::Node type
338
266
  def self.dispatch_canon_node_type(node1, node2, opts, child_opts,
339
267
  diff_children, differences)
340
- # Import XmlComparator to use its comparison methods
341
- require_relative "xml_comparator"
342
-
343
268
  case node1.node_type
344
269
  when :root
345
270
  XmlComparator.compare_children(node1, node2, opts, child_opts,
@@ -364,8 +289,6 @@ diff_children, differences)
364
289
  # Dispatch by legacy Nokogiri/Moxml node type
365
290
  def self.dispatch_legacy_node_type(node1, node2, opts, child_opts,
366
291
  diff_children, differences)
367
- require_relative "xml_comparator"
368
-
369
292
  if Canon::XmlParsing.document?(node1)
370
293
  XmlComparator.compare_document_nodes(node1, node2, opts, child_opts,
371
294
  diff_children, differences)
@@ -401,47 +324,9 @@ diff_children, differences)
401
324
  differences)
402
325
  return unless opts[:verbose]
403
326
 
404
- require_relative "xml_comparator"
405
327
  XmlComparator.add_difference(node1, node2, diff1, diff2, dimension,
406
328
  opts, differences)
407
329
  end
408
-
409
- # Serialize a Canon::Xml::Node to XML string
410
- #
411
- # This utility method handles serialization of different node types
412
- # to their string representation for display and debugging purposes.
413
- #
414
- # @param node [Canon::Xml::Node, Object] Node to serialize
415
- # @return [String] XML string representation
416
- def self.serialize_node_to_xml(node)
417
- case node
418
- when Canon::Xml::Nodes::RootNode
419
- # Serialize all children of root
420
- node.children.map { |child| serialize_node_to_xml(child) }.join
421
- when Canon::Xml::Nodes::ElementNode
422
- # Serialize element with attributes and children
423
- attrs = node.attribute_nodes.map do |a|
424
- " #{a.name}=\"#{a.value}\""
425
- end.join
426
- children_xml = node.children.map do |c|
427
- serialize_node_to_xml(c)
428
- end.join
429
-
430
- if children_xml.empty?
431
- "<#{node.name}#{attrs}/>"
432
- else
433
- "<#{node.name}#{attrs}>#{children_xml}</#{node.name}>"
434
- end
435
- when Canon::Xml::Nodes::TextNode
436
- node.value
437
- when Canon::Xml::Nodes::CommentNode
438
- "<!--#{node.value}-->"
439
- when Canon::Xml::Nodes::ProcessingInstructionNode
440
- "<?#{node.target} #{node.data}?>"
441
- else
442
- node.to_s
443
- end
444
- end
445
330
  end
446
331
  end
447
332
  end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "yaml"
4
- require_relative "match_options"
5
- require_relative "comparison_result"
6
- require_relative "ruby_object_comparator"
7
4
 
8
5
  module Canon
9
6
  module Comparison