canon 0.1.22 → 0.1.23

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ba5fabd7a7d0057f365952f8aecc01381ef88f2f1dd28679e9e8947945b54104
4
- data.tar.gz: 3e4119f7fc69a7c2534957c7654b6a567a868208179262fc921ea1266b5a1a6c
3
+ metadata.gz: '08086e588946bb0f5f39a8235984058b5a5e8aea956b9652e0e366ff84500232'
4
+ data.tar.gz: bb078d67c1a68da1ca88b3d29fde336e291b0ff95186ade125ee1ccfb1a82de4
5
5
  SHA512:
6
- metadata.gz: 44a74c7bb2010a2aa22855258affa6889003585edba717538bb579c63f6694757b21b74bc929b07bd0f87660f0bb3bd02f158b0a91be18017e938100f1fee491
7
- data.tar.gz: be61d26774ae22a5547b2ba0ec1d578b11d37be0899add26d7f14ac63c197637568b74a9d0cad76535e5ab6a82d297af7b917f225f972361f09549964917576b
6
+ metadata.gz: 35f7888d948f86fa4b504b060ee6d9976dc38b32232e8c86b9b8986ee08448cdad265fe4d091e810e5f63f0b0702e125317e07d15761b5cd6404905190546234
7
+ data.tar.gz: 4f57564289fdff8c73020f3ed9f9184b363688062cf1b89baea79f0d25c57905bcbc225b5e946afeb30305b91402b557ae65ce61b99a0d63b8bb1c569ec2d57f
data/.rubocop_todo.yml CHANGED
@@ -1,6 +1,6 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2026-03-31 12:44:31 UTC using RuboCop version 1.86.0.
3
+ # on 2026-04-01 00:03:16 UTC using RuboCop version 1.86.0.
4
4
  # The point is for the user to remove these configuration records
5
5
  # one by one as the offenses are removed from the code base.
6
6
  # Note that changes in the inspected code, or installation of new
@@ -11,20 +11,32 @@ Gemspec/RequiredRubyVersion:
11
11
  Exclude:
12
12
  - 'canon.gemspec'
13
13
 
14
- # Offense count: 1
14
+ # Offense count: 2
15
15
  # This cop supports safe autocorrection (--autocorrect).
16
- # Configuration parameters: EmptyLineBetweenMethodDefs, EmptyLineBetweenClassDefs, EmptyLineBetweenModuleDefs, DefLikeMacros, AllowAdjacentOneLineDefs, NumberOfEmptyLines.
17
- Layout/EmptyLineBetweenDefs:
16
+ # Configuration parameters: EnforcedStyleAlignWith.
17
+ # SupportedStylesAlignWith: either, start_of_block, start_of_line
18
+ Layout/BlockAlignment:
18
19
  Exclude:
19
- - 'lib/canon/diff_formatter/by_line/xml_formatter.rb'
20
+ - 'lib/canon/tree_diff/matchers/hash_matcher.rb'
21
+ - 'spec/canon/hash_matcher_regression_spec.rb'
20
22
 
21
- # Offense count: 1
23
+ # Offense count: 2
22
24
  # This cop supports safe autocorrection (--autocorrect).
23
- Layout/EmptyLines:
25
+ Layout/BlockEndNewline:
24
26
  Exclude:
25
- - 'lib/canon/diff_formatter/by_line/xml_formatter.rb'
27
+ - 'lib/canon/tree_diff/matchers/hash_matcher.rb'
28
+ - 'spec/canon/hash_matcher_regression_spec.rb'
29
+
30
+ # Offense count: 4
31
+ # This cop supports safe autocorrection (--autocorrect).
32
+ # Configuration parameters: Width, EnforcedStyleAlignWith, AllowedPatterns.
33
+ # SupportedStylesAlignWith: start_of_line, relative_to_receiver
34
+ Layout/IndentationWidth:
35
+ Exclude:
36
+ - 'lib/canon/tree_diff/matchers/hash_matcher.rb'
37
+ - 'spec/canon/hash_matcher_regression_spec.rb'
26
38
 
27
- # Offense count: 1094
39
+ # Offense count: 1103
28
40
  # This cop supports safe autocorrection (--autocorrect).
29
41
  # Configuration parameters: Max, AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
30
42
  # URISchemes: http, https
@@ -76,7 +88,7 @@ Lint/UselessConstantScoping:
76
88
  Exclude:
77
89
  - 'lib/canon/diff_formatter/theme.rb'
78
90
 
79
- # Offense count: 297
91
+ # Offense count: 298
80
92
  # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
81
93
  Metrics/AbcSize:
82
94
  Enabled: false
@@ -92,7 +104,7 @@ Metrics/BlockLength:
92
104
  Metrics/BlockNesting:
93
105
  Max: 4
94
106
 
95
- # Offense count: 261
107
+ # Offense count: 262
96
108
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
97
109
  Metrics/CyclomaticComplexity:
98
110
  Enabled: false
@@ -107,7 +119,7 @@ Metrics/MethodLength:
107
119
  Metrics/ParameterLists:
108
120
  Max: 10
109
121
 
110
- # Offense count: 212
122
+ # Offense count: 213
111
123
  # Configuration parameters: AllowedMethods, AllowedPatterns, Max.
112
124
  Metrics/PerceivedComplexity:
113
125
  Enabled: false
@@ -146,7 +158,7 @@ Performance/CollectionLiteralInLoop:
146
158
  RSpec/ContextWording:
147
159
  Enabled: false
148
160
 
149
- # Offense count: 33
161
+ # Offense count: 34
150
162
  # Configuration parameters: IgnoredMetadata.
151
163
  RSpec/DescribeClass:
152
164
  Enabled: false
@@ -157,7 +169,7 @@ RSpec/DescribeMethod:
157
169
  - 'spec/canon/comparison/multiple_differences_spec.rb'
158
170
  - 'spec/canon/diff_formatter/character_map_customization_spec.rb'
159
171
 
160
- # Offense count: 736
172
+ # Offense count: 741
161
173
  # Configuration parameters: CountAsOne.
162
174
  RSpec/ExampleLength:
163
175
  Max: 44
@@ -209,7 +221,7 @@ RSpec/MultipleDescribes:
209
221
  Exclude:
210
222
  - 'spec/canon/comparison/match_options_spec.rb'
211
223
 
212
- # Offense count: 590
224
+ # Offense count: 595
213
225
  RSpec/MultipleExpectations:
214
226
  Max: 15
215
227
 
@@ -273,6 +285,18 @@ RSpec/VerifiedDoubles:
273
285
  - 'spec/canon/diff_formatter/diff_detail_formatter_spec.rb'
274
286
  - 'spec/canon/tree_diff/operation_converter_spec.rb'
275
287
 
288
+ # Offense count: 2
289
+ # This cop supports safe autocorrection (--autocorrect).
290
+ # Configuration parameters: EnforcedStyle, ProceduralMethods, FunctionalMethods, AllowedMethods, AllowedPatterns, AllowBracesOnProceduralOneLiners, BracesRequiredMethods.
291
+ # SupportedStyles: line_count_based, semantic, braces_for_chaining, always_braces
292
+ # ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object
293
+ # FunctionalMethods: let, let!, subject, watch
294
+ # AllowedMethods: lambda, proc, it
295
+ Style/BlockDelimiters:
296
+ Exclude:
297
+ - 'lib/canon/tree_diff/matchers/hash_matcher.rb'
298
+ - 'spec/canon/hash_matcher_regression_spec.rb'
299
+
276
300
  # Offense count: 1
277
301
  # This cop supports safe autocorrection (--autocorrect).
278
302
  # Configuration parameters: EnforcedStyle, AllowComments.
@@ -497,22 +497,9 @@ module Canon
497
497
 
498
498
  private
499
499
 
500
- # Deep dup a hash, handling nested hashes and arrays
500
+ # Delegate to module-level deep_dup
501
501
  def deep_dup(obj)
502
- case obj
503
- when Hash
504
- obj.transform_values { |v| deep_dup(v) }
505
- when Array
506
- obj.map { |v| deep_dup(v) }
507
- when String, Symbol, Numeric, TrueClass, FalseClass, NilClass
508
- obj
509
- else
510
- begin
511
- obj.dup
512
- rescue StandardError
513
- obj
514
- end
515
- end
502
+ Theme.deep_dup(obj)
516
503
  end
517
504
 
518
505
  def deep_merge!(target, source)
@@ -606,9 +593,29 @@ module Canon
606
593
  # @param name [Symbol] Theme name
607
594
  # @return [Hash] Theme hash
608
595
  # @raise [ArgumentError] if theme not found
596
+ # Deep copy a value, handling nested hashes and arrays
597
+ def self.deep_dup(obj)
598
+ case obj
599
+ when Hash
600
+ obj.transform_values { |v| deep_dup(v) }
601
+ when Array
602
+ obj.map { |v| deep_dup(v) }
603
+ when String, Symbol, Numeric, TrueClass, FalseClass, NilClass
604
+ obj
605
+ else
606
+ begin
607
+ obj.dup
608
+ rescue StandardError
609
+ obj
610
+ end
611
+ end
612
+ end
613
+
609
614
  def self.[](name)
610
- THEMES[name] || raise(ArgumentError,
611
- "Unknown theme: #{name}. Valid: #{THEMES.keys}")
615
+ theme = THEMES[name] || raise(ArgumentError,
616
+ "Unknown theme: #{name}. Valid: #{THEMES.keys}")
617
+ # Return a deep copy to prevent mutation of theme constants
618
+ deep_dup(theme)
612
619
  end
613
620
 
614
621
  # List available theme names
@@ -93,19 +93,34 @@ module Canon
93
93
  end
94
94
  return if candidates.empty?
95
95
 
96
- best_match = find_best_match(node2, candidates)
97
- return unless best_match
98
-
99
- if @matching.add(best_match, node2)
100
- @matched_tree1 << best_match
101
- @matched_tree2 << node2
102
- propagate_to_ancestors(best_match, node2)
96
+ # When multiple candidates have identical signatures (common with
97
+ # duplicate subtrees like MathML formulas), sort by sibling position
98
+ # proximity to prefer matching nodes at the same position within
99
+ # their parent. This reduces cross-matching that causes cascading
100
+ # prefix closure failures.
101
+ if candidates.size > 1
102
+ pos2 = node2.position || 0
103
+ candidates = candidates.sort_by do |c|
104
+ pos1 = c.position || 0
105
+ (pos1 - pos2).abs
106
+ end
103
107
  end
104
- end
105
108
 
106
- # @return [TreeNode, nil]
107
- def find_best_match(node2, candidates)
108
- candidates.find { |node1| subtrees_match?(node1, node2) }
109
+ # Try each candidate until one passes both subtree matching
110
+ # AND the prefix closure constraint in matching.add.
111
+ # When multiple candidates have identical subtrees (e.g., labels
112
+ # with the same text child), the first may fail prefix closure
113
+ # due to ancestor cross-matching, but a later candidate succeeds.
114
+ candidates.each do |candidate|
115
+ next unless subtrees_match?(candidate, node2)
116
+
117
+ if @matching.add(candidate, node2)
118
+ @matched_tree1 << candidate
119
+ @matched_tree2 << node2
120
+ propagate_to_ancestors(candidate, node2)
121
+ return
122
+ end
123
+ end
109
124
  end
110
125
 
111
126
  def subtrees_match?(node1, node2)
data/lib/canon/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Canon
4
- VERSION = "0.1.22"
4
+ VERSION = "0.1.23"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.22
4
+ version: 0.1.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-03-31 00:00:00.000000000 Z
11
+ date: 2026-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs