canon 0.3.38 → 0.3.40

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: dc55555287eb70fb4fc5201029aea89c2af55d8a9df26549d1d17b639a6de5de
4
- data.tar.gz: 59ac3ba881495f29ee1355eda305da05d03d62a5611aa738404bf029f66d1721
3
+ metadata.gz: 7ceb43d90065cc39a64f8c74b6317dd9f8752aaa807ec7869ae3188c9e494b43
4
+ data.tar.gz: d6375f29977244331faff0d8dd54396d52494133d77e4286011804a63bd1d23f
5
5
  SHA512:
6
- metadata.gz: 6b2d535b82b40ece128bea902b603b1b43c06c7bf4f40535f651e3b43c24674345de4e0c0767380fd6fc50d2986dc80ecf0e2c1b2d5286a7dd02524d65641920
7
- data.tar.gz: '09af782d9c914502a54ca9b961448c89502bb20c3cffa93ec9268b7afc72099bcea2dcc2f7f8e36ccbf7fd6a6f8e3320ced5b7edfd67f7d70d0f5f95e7cf8d85'
6
+ metadata.gz: bed4791632c2d75f6db4e89e5c991b05a92593fdfaa16d7b20c21dbf5be3070914b0b4214567e9ca3045db8f9d3a8312a218acca28574214d76d817ee09706fd
7
+ data.tar.gz: 0d3f8b7bad01bd3bd1e089f5488dac9cd23ca9761ab287ad3f5f0340e918262e5b4fcf63c4bb64ddb427e19c3e1bec878b0bef9aaf93b596c5a2a1f125dadd99
@@ -67,8 +67,8 @@ module Canon
67
67
  output = []
68
68
 
69
69
  # Detect non-ASCII characters
70
- all_text = (lines1 + lines2).join
71
- non_ascii = Legend.detect_non_ascii(all_text, @visualization_map)
70
+ non_ascii = Legend.detect_non_ascii(doc1, @visualization_map)
71
+ non_ascii.merge!(Legend.detect_non_ascii(doc2, @visualization_map))
72
72
 
73
73
  # Add Unicode legend if needed
74
74
  unless non_ascii.empty?
@@ -19,8 +19,8 @@ module Canon
19
19
  lines2 = doc2.split("\n", -1)
20
20
 
21
21
  # Detect non-ASCII characters in the diff
22
- all_text = (lines1 + lines2).join
23
- non_ascii = Legend.detect_non_ascii(all_text, @visualization_map)
22
+ non_ascii = Legend.detect_non_ascii(doc1, @visualization_map)
23
+ non_ascii.merge!(Legend.detect_non_ascii(doc2, @visualization_map))
24
24
 
25
25
  # Add Unicode legend if any non-ASCII characters detected
26
26
  unless non_ascii.empty?
@@ -72,9 +72,11 @@ module Canon
72
72
 
73
73
  output = []
74
74
 
75
- # Detect non-ASCII characters
76
- all_text = (lines1 + lines2).join
77
- non_ascii = Legend.detect_non_ascii(all_text, @visualization_map)
75
+ # Detect non-ASCII characters — scan the source strings
76
+ # directly; joining the split lines back into one document
77
+ # per render was pure garbage.
78
+ non_ascii = Legend.detect_non_ascii(doc1, @visualization_map)
79
+ non_ascii.merge!(Legend.detect_non_ascii(doc2, @visualization_map))
78
80
 
79
81
  # Add Unicode legend if needed
80
82
  unless non_ascii.empty?
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.3.38"
4
+ VERSION = "0.3.40"
5
5
  end
@@ -78,7 +78,7 @@ module Canon
78
78
  return nil unless root
79
79
 
80
80
  skeleton = doc.children.filter_map do |child|
81
- next if child.equal?(root)
81
+ next if Canon::XmlParsing.same_engine_node?(child, root)
82
82
 
83
83
  case child
84
84
  when Moxml::Comment, Moxml::ProcessingInstruction then child.to_s
@@ -149,7 +149,7 @@ module Canon
149
149
  def add_document_children(root, children, document_element,
150
150
  skip_types = [])
151
151
  children.each do |child|
152
- next if child.equal?(document_element)
152
+ next if Canon::XmlParsing.same_engine_node?(child, document_element)
153
153
  next if skip_types.any? { |type| child.is_a?(type) }
154
154
 
155
155
  node = yield child
@@ -63,6 +63,33 @@ module Canon
63
63
  end
64
64
  end
65
65
 
66
+ # Same underlying engine node? Wrapper identity first (correct
67
+ # everywhere wrappers are unified). Fallback: moxml 0.5.36-0.5.39
68
+ # wrap Document#root and Document#children entries in DIFFERENT
69
+ # wrapper classes for one node (NativeNode vs the FFI Element —
70
+ # moxml#216), so identity fails exactly where consumers exclude
71
+ # the document element from children; the shared C pointer
72
+ # address is the stable identity. Inert once wrappers unify.
73
+ def same_engine_node?(left, right)
74
+ return true if left.equal?(right)
75
+ return false unless defined?(::Moxml::Node) &&
76
+ left.is_a?(::Moxml::Node) && right.is_a?(::Moxml::Node)
77
+
78
+ address_left = moxml_node_address(left)
79
+ address_right = moxml_node_address(right)
80
+ !address_left.nil? && address_left == address_right
81
+ end
82
+
83
+ def moxml_node_address(wrapper)
84
+ native = wrapper.native
85
+ case native
86
+ when ::Leptris::XML::NativeNode then native.address
87
+ when ::Leptris::XML::Node then native.c_ptr.address
88
+ end
89
+ rescue StandardError
90
+ nil
91
+ end
92
+
66
93
  # --- Type checks (any recognized engine node) ---
67
94
 
68
95
  def document?(obj)
@@ -225,6 +225,13 @@ compare_against: nil)
225
225
  failure_means: "Slow formatting affects serialization performance. C14N is critical for digital signatures and XML canonicalization.",
226
226
  compare_against: "Previous branch (main).",
227
227
  },
228
+ by_line_rendering: {
229
+ name: "By-Line Rendering",
230
+ icon: "🖨️",
231
+ description: "Verbose by_line diff rendering (enricher, line builder, formatters). Referees the #86 rendering lane.",
232
+ failure_means: "Slow diff display affects developer-facing CLI output and CI failure reports.",
233
+ compare_against: "Previous branch (main). Inputs: documents with scattered value differences.",
234
+ },
228
235
  data_comparison: {
229
236
  name: "Data Comparison",
230
237
  icon: "🧮",
@@ -272,6 +279,9 @@ compare_against: nil)
272
279
  { name: "JSON", method: :json_format, desc: "JSON formatting" },
273
280
  { name: "YAML", method: :yaml_format, desc: "YAML formatting" },
274
281
  ],
282
+ by_line_rendering: [
283
+ { name: "XML", method: :by_line_render_xml, desc: "by_line XML render" },
284
+ ],
275
285
  data_comparison: [
276
286
  { name: "JSON", method: :json_compare_equivalent,
277
287
  desc: "JSON equivalence" },
@@ -568,6 +578,18 @@ compare_against: nil)
568
578
  yaml = DataGenerator.generate_yaml(items: @items)
569
579
  data = YAML.safe_load(yaml, permitted_classes: [Time])
570
580
  measure { Canon.format_yaml(data) }
581
+ when :by_line_render_xml
582
+ xml1 = DataGenerator.generate_xml(items: @items)
583
+ xml2 = DataGenerator.generate_xml(items: @items)
584
+ formatter = Canon::DiffFormatter.new(mode: :by_line,
585
+ display_preprocessing: :pretty_print,
586
+ use_color: false)
587
+ result = Canon::Comparison.equivalent?(xml1, xml2, format: :xml,
588
+ verbose: true)
589
+ measure do
590
+ formatter.format(result.differences, :xml,
591
+ doc1: xml1, doc2: xml2)
592
+ end
571
593
  when :json_compare_equivalent
572
594
  json1 = DataGenerator.generate_json(items: @items)
573
595
  json2 = DataGenerator.generate_json(items: @items)
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.3.38
4
+ version: 0.3.40
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-09-14 00:00:00.000000000 Z
11
+ date: 2026-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs
@@ -44,14 +44,14 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 0.5.0
47
+ version: 0.5.41
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 0.5.0
54
+ version: 0.5.41
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: nokogiri
57
57
  requirement: !ruby/object:Gem::Requirement