canon 0.2.8 → 0.2.11

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 (95) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec-opal +7 -0
  3. data/.rubocop_todo.yml +25 -73
  4. data/Rakefile +37 -0
  5. data/lib/canon/cache.rb +16 -27
  6. data/lib/canon/cli.rb +1 -1
  7. data/lib/canon/color_detector.rb +3 -5
  8. data/lib/canon/comparison/compare_profile.rb +1 -4
  9. data/lib/canon/comparison/dimensions/attribute_order_dimension.rb +2 -6
  10. data/lib/canon/comparison/dimensions/attribute_presence_dimension.rb +2 -6
  11. data/lib/canon/comparison/dimensions/attribute_values_dimension.rb +2 -6
  12. data/lib/canon/comparison/dimensions/comments_dimension.rb +2 -6
  13. data/lib/canon/comparison/dimensions/element_position_dimension.rb +2 -6
  14. data/lib/canon/comparison/dimensions/structural_whitespace_dimension.rb +2 -6
  15. data/lib/canon/comparison/dimensions/text_content_dimension.rb +3 -5
  16. data/lib/canon/comparison/format_detector.rb +29 -20
  17. data/lib/canon/comparison/html_comparator.rb +20 -29
  18. data/lib/canon/comparison/html_compare_profile.rb +3 -10
  19. data/lib/canon/comparison/html_parser.rb +1 -1
  20. data/lib/canon/comparison/json_comparator.rb +8 -0
  21. data/lib/canon/comparison/node_inspector.rb +117 -86
  22. data/lib/canon/comparison/strategies/semantic_tree_match_strategy.rb +6 -8
  23. data/lib/canon/comparison/whitespace_sensitivity.rb +55 -193
  24. data/lib/canon/comparison/xml_comparator/attribute_comparator.rb +19 -2
  25. data/lib/canon/comparison/xml_comparator/attribute_filter.rb +5 -10
  26. data/lib/canon/comparison/xml_comparator/child_comparison.rb +4 -4
  27. data/lib/canon/comparison/xml_comparator/diff_node_builder.rb +40 -8
  28. data/lib/canon/comparison/xml_comparator/namespace_comparator.rb +14 -28
  29. data/lib/canon/comparison/xml_comparator/node_parser.rb +14 -13
  30. data/lib/canon/comparison/xml_comparator/node_type_comparator.rb +30 -58
  31. data/lib/canon/comparison/xml_comparator.rb +63 -85
  32. data/lib/canon/comparison/xml_node_comparison.rb +15 -15
  33. data/lib/canon/comparison/yaml_comparator.rb +8 -0
  34. data/lib/canon/comparison.rb +24 -24
  35. data/lib/canon/config/profile_loader.rb +13 -13
  36. data/lib/canon/config.rb +29 -5
  37. data/lib/canon/diff/diff_classifier.rb +7 -41
  38. data/lib/canon/diff/diff_line.rb +1 -1
  39. data/lib/canon/diff/diff_line_builder.rb +2 -0
  40. data/lib/canon/diff/diff_node_enricher.rb +22 -24
  41. data/lib/canon/diff/diff_node_mapper.rb +10 -8
  42. data/lib/canon/diff/formatting_detector.rb +3 -2
  43. data/lib/canon/diff/node_serializer.rb +23 -30
  44. data/lib/canon/diff/path_builder.rb +24 -37
  45. data/lib/canon/diff/source_locator.rb +0 -3
  46. data/lib/canon/diff/xml_serialization_formatter.rb +8 -84
  47. data/lib/canon/diff_formatter/by_line/base_formatter.rb +7 -7
  48. data/lib/canon/diff_formatter/by_line/json_formatter.rb +1 -1
  49. data/lib/canon/diff_formatter/by_line/simple_formatter.rb +1 -1
  50. data/lib/canon/diff_formatter/by_line/xml_formatter.rb +2 -2
  51. data/lib/canon/diff_formatter/by_line/yaml_formatter.rb +1 -1
  52. data/lib/canon/diff_formatter/by_line_formatter.rb +1 -1
  53. data/lib/canon/diff_formatter/by_object/base_formatter.rb +23 -17
  54. data/lib/canon/diff_formatter/by_object/xml_formatter.rb +127 -11
  55. data/lib/canon/diff_formatter/by_object_formatter.rb +2 -6
  56. data/lib/canon/diff_formatter/debug_output.rb +12 -24
  57. data/lib/canon/diff_formatter/diff_detail_formatter/color_helper.rb +2 -2
  58. data/lib/canon/diff_formatter/diff_detail_formatter/dimension_formatter.rb +3 -3
  59. data/lib/canon/diff_formatter/diff_detail_formatter/location_extractor.rb +26 -27
  60. data/lib/canon/diff_formatter/diff_detail_formatter/node_utils.rb +146 -318
  61. data/lib/canon/diff_formatter/diff_detail_formatter.rb +28 -20
  62. data/lib/canon/diff_formatter/legend.rb +2 -2
  63. data/lib/canon/diff_formatter/pretty_diff_formatter.rb +2 -2
  64. data/lib/canon/diff_formatter/theme.rb +4 -4
  65. data/lib/canon/diff_formatter.rb +17 -13
  66. data/lib/canon/formatters/html_formatter.rb +1 -1
  67. data/lib/canon/formatters/html_formatter_base.rb +1 -1
  68. data/lib/canon/formatters/xml_formatter.rb +7 -32
  69. data/lib/canon/html/data_model.rb +2 -2
  70. data/lib/canon/pretty_printer/html.rb +1 -1
  71. data/lib/canon/pretty_printer/xml.rb +16 -7
  72. data/lib/canon/pretty_printer/xml_normalized.rb +9 -3
  73. data/lib/canon/rspec_matchers.rb +2 -2
  74. data/lib/canon/tree_diff/adapters/html_adapter.rb +1 -1
  75. data/lib/canon/tree_diff/adapters/xml_adapter.rb +1 -1
  76. data/lib/canon/tree_diff/core/tree_node.rb +1 -3
  77. data/lib/canon/tree_diff/operation_converter.rb +7 -7
  78. data/lib/canon/tree_diff/operations/operation_detector.rb +4 -0
  79. data/lib/canon/validators/base_validator.rb +5 -8
  80. data/lib/canon/validators/html_validator.rb +3 -8
  81. data/lib/canon/validators/xml_validator.rb +3 -8
  82. data/lib/canon/version.rb +1 -1
  83. data/lib/canon/xml/data_model.rb +132 -138
  84. data/lib/canon/xml/namespace_helper.rb +5 -0
  85. data/lib/canon/xml/node.rb +2 -1
  86. data/lib/canon/xml/nodes/root_node.rb +4 -0
  87. data/lib/canon/xml/nodes/text_node.rb +6 -1
  88. data/lib/canon/xml/sax_builder.rb +5 -7
  89. data/lib/canon/xml/whitespace_normalizer.rb +2 -2
  90. data/lib/canon/xml_backend.rb +49 -0
  91. data/lib/canon/xml_parsing.rb +283 -0
  92. data/lib/canon.rb +3 -1
  93. data/lib/tasks/benchmark_runner.rb +1 -1
  94. data/lib/tasks/performance_helpers.rb +1 -1
  95. metadata +9 -6
@@ -283,22 +283,8 @@ module Canon
283
283
  content = node.value.to_s
284
284
  preview = content.length > 30 ? "#{content[0..27]}..." : content
285
285
  "<!--#{preview}-->"
286
- elsif node.respond_to?(:name)
286
+ elsif Canon::XmlParsing.xml_node?(node) || node.is_a?(Canon::Xml::Node)
287
287
  "<#{node.name}>"
288
- elsif node.respond_to?(:content)
289
- content = node.content.to_s
290
- if content.length > 30
291
- "\"#{content[0..27]}...\""
292
- else
293
- "\"#{content || ''}\""
294
- end
295
- elsif node.respond_to?(:text)
296
- text = node.text.to_s
297
- if text.length > 30
298
- "\"#{text[0..27]}...\""
299
- else
300
- "\"#{text || ''}\""
301
- end
302
288
  else
303
289
  node.class.name
304
290
  end
@@ -311,14 +297,16 @@ module Canon
311
297
 
312
298
  # For attribute differences, show which attributes differ
313
299
  if diff.dimension == :attribute_whitespace &&
314
- node1.respond_to?(:attributes) && node2.respond_to?(:attributes)
300
+ (Canon::XmlParsing.xml_node?(node1) || node1.is_a?(Canon::Xml::Node)) &&
301
+ (Canon::XmlParsing.xml_node?(node2) || node2.is_a?(Canon::Xml::Node))
315
302
  attrs1 = format_attributes(node1)
316
303
  attrs2 = format_attributes(node2)
317
304
  return ["<#{node1.name}> #{attrs1}", "<#{node2.name}> #{attrs2}"]
318
305
  end
319
306
 
320
307
  # For element differences, show element names
321
- if node1.respond_to?(:name) && node2.respond_to?(:name)
308
+ if (Canon::XmlParsing.xml_node?(node1) || node1.is_a?(Canon::Xml::Node)) &&
309
+ (Canon::XmlParsing.xml_node?(node2) || node2.is_a?(Canon::Xml::Node))
322
310
  if node1.name == node2.name
323
311
  # Same element name, different content
324
312
  end
@@ -340,7 +328,7 @@ module Canon
340
328
  end
341
329
 
342
330
  def format_attributes(node)
343
- return "" unless node.respond_to?(:attributes)
331
+ return "" unless Canon::XmlParsing.xml_node?(node) || node.is_a?(Canon::Xml::Node)
344
332
 
345
333
  attrs = node.attributes
346
334
  return "" if attrs.empty?
@@ -350,9 +338,9 @@ module Canon
350
338
  name = if key.is_a?(String)
351
339
  key
352
340
  else
353
- (key.respond_to?(:name) ? key.name : key.to_s)
341
+ key.name
354
342
  end
355
- value = val.respond_to?(:value) ? val.value : val.to_s
343
+ value = val.is_a?(String) ? val : val.value
356
344
  "#{name}=\"#{value}\""
357
345
  end.sort
358
346
 
@@ -365,10 +353,10 @@ module Canon
365
353
  end
366
354
 
367
355
  def get_node_content(node)
368
- if node.respond_to?(:content)
369
- node.content.to_s
370
- elsif node.respond_to?(:text)
371
- node.text.to_s
356
+ if Canon::XmlParsing.xml_node?(node)
357
+ Canon::XmlParsing.text_content(node).to_s
358
+ elsif node.is_a?(Canon::Xml::Node)
359
+ node.text_content.to_s
372
360
  else
373
361
  ""
374
362
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "rainbow"
3
+ require "rainbow" unless RUBY_ENGINE == "opal"
4
4
 
5
5
  module Canon
6
6
  class DiffFormatter
@@ -19,7 +19,7 @@ module Canon
19
19
  def self.colorize(text, color, use_color, bold: false)
20
20
  return text unless use_color
21
21
 
22
- presenter = Rainbow(text).send(color)
22
+ presenter = Rainbow(text).public_send(color)
23
23
  presenter = presenter.bright if bold
24
24
  presenter.to_s
25
25
  end
@@ -707,7 +707,7 @@ expand_difference: false)
707
707
  # @param diff [DiffNode, Hash] Difference node
708
708
  # @return [Symbol] Dimension
709
709
  def self.extract_dimension(diff)
710
- if diff.respond_to?(:dimension)
710
+ if diff.is_a?(Canon::Diff::DiffNode)
711
711
  diff.dimension
712
712
  elsif diff.is_a?(Hash)
713
713
  diff[:dimension] || diff[:diff_code] || :unknown
@@ -721,7 +721,7 @@ expand_difference: false)
721
721
  # @param diff [DiffNode, Hash] Difference node
722
722
  # @return [Object] Node1
723
723
  def self.extract_node1(diff)
724
- if diff.respond_to?(:node1)
724
+ if diff.is_a?(Canon::Diff::DiffNode)
725
725
  diff.node1
726
726
  elsif diff.is_a?(Hash)
727
727
  diff[:node1]
@@ -733,7 +733,7 @@ expand_difference: false)
733
733
  # @param diff [DiffNode, Hash] Difference node
734
734
  # @return [Object] Node2
735
735
  def self.extract_node2(diff)
736
- if diff.respond_to?(:node2)
736
+ if diff.is_a?(Canon::Diff::DiffNode)
737
737
  diff.node2
738
738
  elsif diff.is_a?(Hash)
739
739
  diff[:node2]
@@ -17,12 +17,12 @@ module Canon
17
17
  return "" unless diff
18
18
 
19
19
  # Prefer pre-computed path if available (populated by MetadataEnricher)
20
- if diff.respond_to?(:path) && !diff.path.nil? && !diff.path.empty?
21
- return "Location: #{diff.path}"
20
+ if diff.is_a?(Canon::Diff::DiffNode) && diff.path && !diff.path.empty?
21
+ return diff.path
22
22
  end
23
23
 
24
24
  # Fall back to extracting from nodes
25
- node = if diff.respond_to?(:node1)
25
+ node = if diff.is_a?(Canon::Diff::DiffNode)
26
26
  diff.node1 || diff.node2
27
27
  elsif diff.is_a?(Hash)
28
28
  diff[:node1] || diff[:node2]
@@ -30,8 +30,7 @@ module Canon
30
30
 
31
31
  return "" unless node
32
32
 
33
- xpath = extract_xpath(node)
34
- xpath.empty? ? "" : "Location: #{xpath}"
33
+ extract_xpath(node)
35
34
  end
36
35
 
37
36
  # Extract XPath from a node
@@ -66,24 +65,26 @@ module Canon
66
65
  current = node
67
66
 
68
67
  while current
69
- break unless current.respond_to?(:name)
70
-
71
- name = current.name
68
+ name = case current
69
+ when Canon::Xml::Node, Nokogiri::XML::Node
70
+ current.name
71
+ else
72
+ break
73
+ end
72
74
  break if name.nil? || name.empty?
73
75
 
74
- # Calculate position among siblings
75
76
  index = calculate_sibling_index(current, name)
76
77
  parts.unshift("#{name}[#{index}]")
77
78
 
78
- # Move to parent
79
- current = if current.respond_to?(:parent)
79
+ current = case current
80
+ when Canon::Xml::Node, Nokogiri::XML::Node
80
81
  current.parent
81
- elsif current.respond_to?(:parent_node)
82
- current.parent_node
82
+ else
83
+ break
83
84
  end
84
85
 
85
- # Stop at document root
86
- break if current.respond_to?(:document) && current == current.document
86
+ break if current.is_a?(Nokogiri::XML::Document) ||
87
+ current.is_a?(Canon::Xml::Nodes::RootNode)
87
88
  end
88
89
 
89
90
  parts.empty? ? "" : "/#{parts.join('/')}"
@@ -95,24 +96,22 @@ module Canon
95
96
  # @param name [String] Node name
96
97
  # @return [Integer] 1-based index
97
98
  def self.calculate_sibling_index(node, name)
98
- return 1 unless node.respond_to?(:parent) || node.respond_to?(:parent_node)
99
-
100
- parent = if node.respond_to?(:parent)
99
+ parent = case node
100
+ when Canon::Xml::Node, Nokogiri::XML::Node
101
101
  node.parent
102
- elsif node.respond_to?(:parent_node)
103
- node.parent_node
104
102
  end
105
103
 
106
104
  return 1 unless parent
107
105
 
108
- # Get siblings with same name
109
- siblings = if parent.respond_to?(:children)
106
+ siblings = case parent
107
+ when Canon::Xml::Node, Nokogiri::XML::Node
110
108
  parent.children.select do |n|
111
- n.respond_to?(:name) && n.name == name
112
- end
113
- elsif parent.respond_to?(:child_nodes)
114
- parent.child_nodes.select do |n|
115
- n.respond_to?(:name) && n.name == name
109
+ case n
110
+ when Canon::Xml::Node, Nokogiri::XML::Node
111
+ n.name == name
112
+ else
113
+ false
114
+ end
116
115
  end
117
116
  else
118
117
  [node]