canon 0.3.29 → 0.3.30

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: ff4b9d6b5a57176d2d382f7b0d730047161920dfb4cb4004b58d60bba9c0edab
4
- data.tar.gz: ed8dfddca4d957fbc3fbb1e62dbd1b03032c661e82c06513304d2abcf4e288cc
3
+ metadata.gz: 308416a45e76807d58f00f40a88d5d6f53617d2a9dac468da8add04fa8175a2f
4
+ data.tar.gz: 2fa30986100df7b8238263546513705513635bd6c39f1552f0e0f8774f510f5f
5
5
  SHA512:
6
- metadata.gz: 778faacee321541b7d8ceef7c3497969080243acd01fc01bde3902deb68b7664e5ed966a230fc969766cfb32aefe76c81be9d7ae8a86d6b0f0ea870a6ed32cf1
7
- data.tar.gz: a3a42291c8100b20362c273c34778abdb4f22eec057c616e54daa60b77e4272c9fe5742fa352874ffc1145c0800e89f6c00800d8938bfcf2af364cff9c71ba9f
6
+ metadata.gz: 0ffdb20ffc91117fdf24afb405f1684aea837316c1481ed5cc7e435bff4bf5d409876d9ca5851e187d3cd128b192ce3516b49114e6ac5d56a327dd87330f0ec9
7
+ data.tar.gz: aaeac239ac4707d8034eb92c8205753e3ec94ff203bf0b4023c33d0b7a92d57742e632ee29998de5a2ed041e45ea7bf2453b2479bb24ed9b9164dacba8db4ab1
data/CLAUDE.md CHANGED
@@ -143,6 +143,10 @@ Engine parity is complete through libleptris 1.9.8 / leptris-ruby 1.9.33 / moxml
143
143
 
144
144
  Engine A/B testing: `CANON_XML_BACKEND=nokogiri bundle exec rspec` (or `=moxml` to force leptris when it isn't the resolved default). The default suite must stay green under BOTH values; the only expected pendings are the upstream-tracked ones. The benchmark header (`rake performance:quick`) reports the active engine.
145
145
 
146
+ ### C14N Engines
147
+
148
+ `Canon::Xml::C14n.canonicalize` stays on canon's Ruby C14N 1.1 processor by default. leptris' native C-side C14N 1.1 is ~50x faster on large documents and byte-identical on the main corpus, but diverges from the spec on edge cases (attribute ordering, prefix preservation, `>`/tab escaping, document-level PIs — leptris#1015, all pinned in `spec/canon/xml/c14n_engine_parity_spec.rb`). `CANON_C14N_BACKEND=leptris` opts in; when the parity gate runs clean the default flips. `canonicalize_subset` and `with_comments: true` always use the Ruby processor.
149
+
146
150
  ### YAML Engines
147
151
 
148
152
  `Canon::YamlBackend` selects the YAML engine: `:psych` (default) or `:yeptris` (FFI over libyeptris, the YAML counterpart of the leptris XML stack — `CANON_YAML_BACKEND=yeptris` opts in; the optional `yeptris` Gemfile group must be enabled). `Canon::YamlParsing` is the single gateway for string loads; `Canon::JsonParsing` mirrors it for JSON (the same yeptris engine serves both — `Yeptris::YAML.load` auto-detects JSON and routes to the native C-API materializer; JSON falls back to stdlib unless `YamlBackend.yeptris_native?`, since the FFI ladder is ~29x slower than the stdlib C extension). `YAML.dump` stays on Psych everywhere — canonical output bytes are canon's product and the writers differ. **JSON defaults to the strict yeptris surface whenever the native materializer is installed** (yeptris 0.1.13.4 ships platform gems — zero compilation, zero env; parity spec-pinned to `JSON.parse` upstream). The YAML default stays `:psych` until the yeptris Psych-parity gaps close (yeptris-ruby#30 sexagesimal scalars, #31 >64-bit integers — #29 empty documents was fixed in 0.1.12); `spec/canon/yaml_engine_parity_spec.rb` is the executable gate, with upstream-tracked cases pending. Never `require "yeptris/psych"` — it rebinds the global `::Psych` constant for the whole process; only the namespaced `Yeptris::YAML` API is used.
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.29"
4
+ VERSION = "0.3.30"
5
5
  end
@@ -10,6 +10,10 @@ module Canon
10
10
  # @param with_comments [Boolean] Include comments in canonical form
11
11
  # @return [String] Canonical form in UTF-8
12
12
  def self.canonicalize(xml, with_comments: false)
13
+ if (native = native_canonicalize(xml, with_comments))
14
+ return native
15
+ end
16
+
13
17
  # Build XPath data model
14
18
  root_node = DataModel.from_xml(xml)
15
19
 
@@ -18,6 +22,46 @@ module Canon
18
22
  processor.process(root_node)
19
23
  end
20
24
 
25
+ # leptris' C-side C14N 1.1 — ~50x faster than the Ruby processor
26
+ # but NOT yet byte-identical on canon's edge-case corpus
27
+ # (attribute ordering, `>` escaping, document-level PIs, one
28
+ # prefix case — leptris#1015; the parity spec pins
29
+ # each). Opt-in via CANON_C14N_BACKEND=leptris until those
30
+ # close; comments mode keeps the Ruby path regardless (the
31
+ # native seam exposes no with-comments form).
32
+ def self.native_canonicalize(xml, with_comments)
33
+ return nil if with_comments
34
+ return nil if RUBY_ENGINE == "opal"
35
+ return nil unless ENV["CANON_C14N_BACKEND"].to_s.casecmp("leptris").zero?
36
+ return nil unless Canon::XmlBackend.moxml? &&
37
+ Canon::XmlParsing.moxml_adapter_name == :leptris
38
+ return nil unless native_c14n_available?
39
+
40
+ doc = Canon::XmlParsing.moxml_context.parse(xml, readonly: true,
41
+ strict: false)
42
+ begin
43
+ doc.native.canonicalize(::Leptris::XML::FFI::C14N_1_1, nil,
44
+ mode: ::Leptris::XML::FFI::C14N_MODE_CANONICAL)
45
+ ensure
46
+ doc.free
47
+ end
48
+ rescue StandardError
49
+ # Malformed inputs are the Ruby path's domain (recovery parse
50
+ # + parse_errors surfacing), not the native lane's.
51
+ nil
52
+ end
53
+
54
+ def self.native_c14n_available?
55
+ return @native_c14n_available unless @native_c14n_available.nil?
56
+
57
+ @native_c14n_available = defined?(::Leptris::XML::FFI::C14N_1_1) &&
58
+ ::Leptris::XML::FFI.constants.include?(:C14N_MODE_CANONICAL)
59
+ end
60
+
61
+ def self.reset_native_probe!
62
+ @native_c14n_available = nil
63
+ end
64
+
21
65
  # Canonicalize a document subset selected by XPath expression.
22
66
  #
23
67
  # Implements W3C C14N 1.1 subset canonicalization:
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.29
4
+ version: 0.3.30
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-09 00:00:00.000000000 Z
11
+ date: 2026-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: diff-lcs