leptris 1.9.7 → 1.9.9

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: '001396e9d1eca04e38bc3223964f4d8b8aa22f7672d32d6dc936f4730db35c60'
4
- data.tar.gz: a4a24591d60276ea69fc9be41cd1b30aa6ac66df1cb77aa9f258489f2a8e7f28
3
+ metadata.gz: b2e2451251a0c5aec3567f67ed11c48f1b48d1a9f3622bc8c3fe62f03192c185
4
+ data.tar.gz: 6be47e0deac36287f736e5b6b7b9755ce4b1e2e4e3986959caa750c5072bcada
5
5
  SHA512:
6
- metadata.gz: 94b3e177f5419851483df347346993d6e42b9eb7a2ed7cca238804547cd65ab81ef7cdd3de04fe9898493f35e13178b359b99aecf653aea379a5714be088fc87
7
- data.tar.gz: d30f779432c68c767754e55d2695e53c920e94d3f37b31603a76841c4c462b4afd62f192ba02de647ba762b4c4be59748615803fbdaedd570dd69c3ab5a488bd
6
+ metadata.gz: a352efddd7e68f48e17d7126bf1d003d8da0c2eb5cdf09be1c7c7d42b739a761208792e4b45033cd7dfd928123ff7db80c8d629a0f625554d778c7c6b822e4df
7
+ data.tar.gz: 71c3504e8592fab25b026c68d25300c2420c22e932546257dd6d5cc819c47b9cf3ff82cbd80136d55e8250efe1c6b835a82d336b341d3cdbbcde8177ff16933d
data/CHANGELOG.md CHANGED
@@ -5,6 +5,49 @@ All notable changes to Leptris will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.9.9] - 2026-08-26
9
+
10
+ ### Changed
11
+
12
+ - **CI gates the symbol audit**: the build workflow runs
13
+ `rake compile audit:symbols` before the suite — upstream surface
14
+ drift now fails CI on the PR that first sees it instead of
15
+ relying on someone remembering to run it. The task skips
16
+ gracefully where nm is unavailable (Windows).
17
+ - **benchmark/leptris_vs_nokogiri.rb prints live provenance**
18
+ (library, gem, nokogiri, ruby versions) instead of a frozen
19
+ footer claiming "v0.12.0 / 176 specs".
20
+ - README: the `#search` dispatch description now matches the
21
+ heuristic the code implements (path-prefix → xpath; everything
22
+ else translates as CSS, commas included).
23
+
24
+ ### Meta
25
+
26
+ - **ADR 0006** records the ruby-variant packaging policy as
27
+ practiced since 1.9.0: the `ruby` platform gem ships as the
28
+ fallback/source variant without a vendored library, safe under
29
+ the eager-load failure mode (issue #49) — clarifying the 1.9.0
30
+ changelog's "platform variants only" phrasing without rewriting
31
+ history.
32
+
33
+ ## [1.9.8] - 2026-08-26
34
+
35
+ ### Added
36
+
37
+ - **`rake audit:symbols`**: the lockstep drift detector as an
38
+ executable step — `nm -gU` on the vendored library vs the ffi.rb
39
+ attach list, failing with both directions of drift (ADR 0001's
40
+ enforcement arm; previously prose plus ad-hoc pipelines).
41
+
42
+ ### Changed
43
+
44
+ - ffi.rb attaches the five header-declared exports past cleanups
45
+ had dropped (element_children, serialize_document,
46
+ xpath_ns_set_add, xpath_result_get, xpath_result_get_nodes) —
47
+ mirror-only, supersession noted inline. The audit now runs green:
48
+ **224/224 symbols in lockstep**. Pull-attribute batch fetch asked
49
+ upstream (leptris/leptris#562).
50
+
8
51
  ## [1.9.7] - 2026-08-26
9
52
 
10
53
  ### Added
data/CLAUDE.md CHANGED
@@ -91,6 +91,7 @@ lib/leptris/xml/css_to_xpath.rb — minimal CSS translation
91
91
  check both before proposing refactors; they exist so reviews
92
92
  stop re-deriving settled questions.
93
93
  - libleptris public headers (`src/include/leptris/*.h`) are the
94
- contract; when symbols change, bump lockstep and audit
95
- attached-vs-exported (`nm -gU` on a fresh build).
94
+ contract; when symbols change, bump lockstep and run
95
+ `rake audit:symbols` (attached == exported on the vendored
96
+ library; fails listing both directions of drift).
96
97
  - Upstream issues worth tracking live at leptris/leptris.
data/README.adoc CHANGED
@@ -169,14 +169,15 @@ against a readonly document is legal; mutating the frozen one is not.
169
169
 
170
170
  == Searching: XPath and CSS
171
171
 
172
- `Document` and `Element` (via `Leptris::XML::Searchable`) support:
172
+ `Document`, `Element`, and `DocumentFragment` (via
173
+ `Leptris::XML::Searchable`) support:
173
174
 
174
175
  [horizontal]
175
176
  `#xpath(*exprs)` :: evaluate XPath; returns `NodeSet`, `true`/`false`, `Float`, or `String` depending on the expression.
176
177
  `#at_xpath(*exprs)` :: first match (or scalar), like `xpath(*exprs).first`.
177
- `#css(*selectors)` :: minimal CSS-to-XPath translation, then `xpath`.
178
+ `#css(*selectors)` :: minimal CSS-to-XPath translation, then `xpath`. Receiver-relative (Nokogiri semantics): scoped to the element or fragment, document-wide from a Document.
178
179
  `#at_css(*selectors)` :: first match of `css`.
179
- `#search(*exprs)` :: dispatches on syntax — `/`-prefixed or `,`-separated `xpath`, otherwise `css`.
180
+ `#search(*exprs)` :: dispatches on syntax — path-prefixed expressions (`/`, `.`, `..`) go to `xpath`; everything else translates as CSS (comma unions included).
180
181
  `#at(*exprs)` :: first match of `search`.
181
182
 
182
183
  [source,ruby]
@@ -190,6 +191,11 @@ doc.at_xpath("string(//book[1]/@id)") # => "b1"
190
191
  doc.css("book[lang='en'] title") # => NodeSet[<title>Refactoring</title>]
191
192
  doc.at_css("book#b1 title") # => <title>Refactoring</title> (id selector)
192
193
  doc.css("book:first-child") # first <book>
194
+
195
+ # css is receiver-relative: scoped to the receiver, not the document
196
+ doc.root.at_css("book").css("title") # titles under THAT book only
197
+ frag = doc.fragment("<a x='1'><n/></a>")
198
+ frag.css("a > n") # searches the fragment
193
199
  ----
194
200
 
195
201
  XPath result type follows XPath 1.0 semantics:
data/Rakefile CHANGED
@@ -49,6 +49,45 @@ task spec: :compile unless ENV.key?("LEPTRIS_LIB_PATH")
49
49
 
50
50
  task default: :spec
51
51
 
52
+ # Lockstep drift detector (ADR 0001): ffi.rb mirrors the public
53
+ # header, so attached == exported must hold on the vendored library.
54
+ # Run after `rake compile` and before any lockstep release.
55
+ namespace :audit do
56
+ desc "Fail when ffi.rb attachments and library exports drift"
57
+ task :symbols do
58
+ lib = Dir.glob("lib/libleptris.{dylib,so,dll}").first
59
+ unless system("which nm > /dev/null 2>&1")
60
+ puts "audit:symbols: skipped (nm unavailable on this platform)"
61
+ next
62
+ end
63
+ unless lib
64
+ abort "audit:symbols: vendored library not found — run rake compile"
65
+ end
66
+ exported = `nm -gU #{lib}`
67
+ .lines.map { |l| l.split[2] }.compact
68
+ .map { |n| n.sub(/\A_/, "") }
69
+ .select { |n| n.start_with?("leptris_") }
70
+ .map { |n| n.sub(/\Aleptris_/, "") }.sort
71
+ attached = File.read("lib/leptris/xml/ffi.rb")
72
+ .scan(/attach_function :leptris_([a-z_0-9]+)/).flatten.sort
73
+ unattached = exported - attached
74
+ unexported = attached - exported
75
+ unless unattached.empty?
76
+ puts "exported but NOT attached (upstream surface drift):"
77
+ unattached.each { |s| puts " leptris_#{s}" }
78
+ end
79
+ unless unexported.empty?
80
+ puts "attached but NOT exported (stale attachment):"
81
+ unexported.each { |s| puts " leptris_#{s}" }
82
+ end
83
+ if unattached.empty? && unexported.empty?
84
+ puts "audit:symbols: #{attached.length}/#{exported.length} symbols in lockstep"
85
+ else
86
+ abort "audit:symbols: drift detected"
87
+ end
88
+ end
89
+ end
90
+
52
91
  require "rubygems/package_task"
53
92
 
54
93
  desc "Build the pure-Ruby gem"
@@ -0,0 +1,25 @@
1
+ # ADR 0006: the ruby-platform variant ships as the fallback, unvendored
2
+
3
+ ## Context
4
+ The 1.9.0-era CHANGELOG said "never publishes ruby-platform releases
5
+ without the vendored library — platform variants only", and an early
6
+ fix removed the `gem:native:any` task. The 1.9.0 lockstep restored
7
+ the `ruby` matrix entry deliberately, and every release since has
8
+ published the variant — practice contradicting the recorded policy.
9
+
10
+ ## Decision
11
+ The `ruby`-platform gem ships as the fallback/source variant WITHOUT
12
+ a vendored library, by design. It is safe because library resolution
13
+ is eager (issue #49): on a machine without a usable libleptris the
14
+ gem fails at `require` with the actionable remedy (install the
15
+ platform-specific variant or set LEPTRIS_LIB_PATH) instead of deep
16
+ inside Document.parse. Bundler prefers platform-specific gems
17
+ wherever they exist (9 of 10 published variants are precompiled);
18
+ the ruby variant serves source installs and exotic platforms that
19
+ accept providing their own library.
20
+
21
+ ## Consequences
22
+ Do not re-propose removing the `platform: any` release leg without
23
+ new evidence that bundler misresolves it in practice. A future
24
+ change to the eager-load behavior (ADR 0005 ordering aside) must
25
+ keep the ruby variant failing loudly at require time.
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.7"
4
+ VERSION = "1.9.9"
5
5
  end
@@ -173,6 +173,10 @@ module Leptris
173
173
  # count-only query returning the TOTAL across every child kind.
174
174
  attach_function :leptris_node_children,
175
175
  [:leptris_node_ref, :pointer, :size_t], :size_t
176
+ # Element-only batch; mirror-only — fetch_children rides the
177
+ # all-kind node_children above.
178
+ attach_function :leptris_element_children,
179
+ [:leptris_element, :pointer, :size_t], :size_t
176
180
  attach_function :leptris_node_as_element,
177
181
  [:leptris_node_ref], :leptris_element
178
182
  attach_function :leptris_element_as_node,
@@ -402,6 +406,12 @@ module Leptris
402
406
  # which (element / synthetic attribute / text / other).
403
407
  attach_function :leptris_xpath_result_node_kind,
404
408
  [:leptris_xpath_result, :size_t], :int
409
+ # Pre-_ex variants, superseded by xpath_result_get_nodes_ex /
410
+ # xpath_result_get_node; mirror-only (ADR 0001).
411
+ attach_function :leptris_xpath_result_get,
412
+ [:leptris_xpath_result, :size_t], :leptris_element
413
+ attach_function :leptris_xpath_result_get_nodes,
414
+ [:leptris_xpath_result, :pointer, :size_t], :size_t
405
415
  attach_function :leptris_xpath_result_get_node,
406
416
  [:leptris_xpath_result, :size_t], :leptris_node_ref
407
417
  attach_function :leptris_xpath_result_node_name,
@@ -447,6 +457,10 @@ module Leptris
447
457
  [:leptris_xpath_ns_set], :void
448
458
  # One-call constructor: flat array of 2*pair_count alternating
449
459
  # prefix/URI strings.
460
+ # Per-pair add; superseded by ns_set_new_from_pairs (one call);
461
+ # mirror-only (ADR 0001).
462
+ attach_function :leptris_xpath_ns_set_add,
463
+ [:leptris_xpath_ns_set, :string, :string], :leptris_status
450
464
  attach_function :leptris_xpath_ns_set_new_from_pairs,
451
465
  [:pointer, :size_t], :leptris_xpath_ns_set
452
466
  attach_function :leptris_xpath_eval_ns,
@@ -507,6 +521,10 @@ module Leptris
507
521
 
508
522
  attach_function :leptris_document_serialize,
509
523
  [:leptris_document, :pointer], :pointer
524
+ # Deprecated automatic-options alias (header: prefer
525
+ # leptris_document_serialize); mirror-only.
526
+ attach_function :leptris_serialize_document,
527
+ [:leptris_document], :pointer
510
528
  # libleptris >= 1.9.0: caller-buffer serialization with options
511
529
  # (leptris#541). buf=NULL is a size query; the size-query +
512
530
  # fill pair reuses one serialization through a per-document
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.7
4
+ version: 1.9.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-08-25 00:00:00.000000000 Z
11
+ date: 2026-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -74,6 +74,7 @@ files:
74
74
  - docs/adr/0003-readonly-memoization-pattern.md
75
75
  - docs/adr/0004-lifetime-guard.md
76
76
  - docs/adr/0005-autoload-manifest-ordering.md
77
+ - docs/adr/0006-ruby-variant-policy.md
77
78
  - leptris.gemspec
78
79
  - lib/leptris.rb
79
80
  - lib/leptris/version.rb