leptris 1.9.8 → 1.9.10

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: 8f306f9bc45d304b82c3db1ac2936dcc0d708b21d2caf595e4a9484da5c6b48a
4
- data.tar.gz: ce9b04f6f1e91e6dffd1ff68ce70967b8b2bcff8351132db2f3312e4b534e803
3
+ metadata.gz: 4e7dca7e58492747ba0b5843937a7a8a914afa52f4f7271e2b808d1b895a2ded
4
+ data.tar.gz: bf399063035b7cacd20893813e89f85582594ef7644ab8b2ef076772cc40c094
5
5
  SHA512:
6
- metadata.gz: 40618f16214157768b018c774816f738a8cbce00e757286822a69f22f71413605c165448a22644b1ff5cc66a387ce63d6e2c496167b8049f2e80ab7cdf124582
7
- data.tar.gz: f3c5d00e54f051510d76db44582806252ccf84091c9c9eb11915fc43675282721f4224fada0331f45616250be411362f981d545fb5de47bfcaadfaf09a4954bb
6
+ metadata.gz: df766bafa6dc7d590909f4f6d2a475446115b5d9cd1d57605558654959e699188f1a36329248c653b501e5e432a9a604533e01dd476e9b350a5510be27fa7ca3
7
+ data.tar.gz: c0c8f0f164ceadd0c24d476ca8c4948582e091379f7f976a0fdbfc073d482a97c8a80bf29ad6601f2ad474e0fd4464c5e903cb382b56350be2a6c07a1ef0ecf6
data/CHANGELOG.md CHANGED
@@ -5,6 +5,47 @@ 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.10] - 2026-08-26
9
+
10
+ ### Changed
11
+
12
+ - **README: Migrating from Nokogiri, caught up to the 1.9.x
13
+ surface** — the notable-differences list now covers the lifetime
14
+ contract (UseAfterFreeError on freed-document reads/mutations),
15
+ readonly mode, recover parsing + last_error_position, searchable
16
+ fragments, receiver-relative css, and expanded-name attribute
17
+ access, each with the migrating reader's context.
18
+ - **Spec organization**: the eight-round perf_surface_spec grab-bag
19
+ splits into one file per concern (seam_and_reads,
20
+ sax_and_query_paths, lifetime_contract, fragment_and_position,
21
+ receiver_relative_css). Suite count unchanged at 274; each file
22
+ is one scannable context.
23
+
24
+ ## [1.9.9] - 2026-08-26
25
+
26
+ ### Changed
27
+
28
+ - **CI gates the symbol audit**: the build workflow runs
29
+ `rake compile audit:symbols` before the suite — upstream surface
30
+ drift now fails CI on the PR that first sees it instead of
31
+ relying on someone remembering to run it. The task skips
32
+ gracefully where nm is unavailable (Windows).
33
+ - **benchmark/leptris_vs_nokogiri.rb prints live provenance**
34
+ (library, gem, nokogiri, ruby versions) instead of a frozen
35
+ footer claiming "v0.12.0 / 176 specs".
36
+ - README: the `#search` dispatch description now matches the
37
+ heuristic the code implements (path-prefix → xpath; everything
38
+ else translates as CSS, commas included).
39
+
40
+ ### Meta
41
+
42
+ - **ADR 0006** records the ruby-variant packaging policy as
43
+ practiced since 1.9.0: the `ruby` platform gem ships as the
44
+ fallback/source variant without a vendored library, safe under
45
+ the eager-load failure mode (issue #49) — clarifying the 1.9.0
46
+ changelog's "platform variants only" phrasing without rewriting
47
+ history.
48
+
8
49
  ## [1.9.8] - 2026-08-26
9
50
 
10
51
  ### Added
data/README.adoc CHANGED
@@ -177,7 +177,7 @@ against a readonly document is legal; mutating the frozen one is not.
177
177
  `#at_xpath(*exprs)` :: first match (or scalar), like `xpath(*exprs).first`.
178
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.
179
179
  `#at_css(*selectors)` :: first match of `css`.
180
- `#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).
181
181
  `#at(*exprs)` :: first match of `search`.
182
182
 
183
183
  [source,ruby]
@@ -410,7 +410,26 @@ Notable differences:
410
410
  * `Node#children` includes whitespace text nodes (same as Nokogiri); use
411
411
  `#element_children` or `#first_element_child` to skip them.
412
412
  * CSS support is intentionally minimal — for advanced selectors, drop to
413
- `xpath`.
413
+ `xpath`. `css` is receiver-relative (Nokogiri semantics): scoped to
414
+ an element or fragment, document-wide from a Document.
415
+ * `DocumentFragment` is searchable (`fragment.xpath/at_xpath/css/at_css/search`)
416
+ — Nokogiri fragment parity.
417
+ * Expanded-name attribute access: `Element#attribute_ns(uri, local)` /
418
+ `#has_attribute_ns?(uri, local)` — XML Namespaces 1.0 semantics
419
+ (cross-prefix match, nil URI matches no-namespace, xmlns invisible).
420
+ * `Leptris::XML.parse(xml, recover: true)` returns an empty document
421
+ with the failure recorded on the thread-global last error instead of
422
+ raising ParseError — libxml2 `XML_PARSE_RECOVER` semantics. The
423
+ companion `Document#last_error_position` returns `[line, column]`.
424
+ * `Leptris::XML.parse(xml, readonly: true)` (or `Document#readonly!`)
425
+ freezes the document for reading: mutations raise ReadOnlyError, read
426
+ methods memoize aggressively. Faster steady state; no Nokogiri
427
+ equivalent.
428
+ * **Lifetime contract**: a borrowed handle used after the owning
429
+ document has been freed (or GC'd) raises `Leptris::XML::UseAfterFreeError`.
430
+ Nokogiri is silent on this — migrating code that holds Node references
431
+ past Document disposal will see the error; silence-replace-UAF patterns
432
+ from Nokogiri do not apply.
414
433
  * No `Nokogiri::HTML` or `Nokogiri::CSS` parser. Leptris is XML-only.
415
434
  * No XSLT, no RelaxNG / DTD validation, no schema caching.
416
435
  * No built-in JRuby / TruffleRuby support — only CRuby via `ffi`.
data/Rakefile CHANGED
@@ -55,9 +55,27 @@ task default: :spec
55
55
  namespace :audit do
56
56
  desc "Fail when ffi.rb attachments and library exports drift"
57
57
  task :symbols do
58
+ # nm cannot read MSVC PE export tables (every symbol reports as
59
+ # unexported -> guaranteed false drift), so Windows skips: the
60
+ # darwin/linux CI legs enforce the mirror — any one platform's
61
+ # build of the same C surface suffices.
62
+ if Gem.win_platform?
63
+ puts "audit:symbols: skipped on Windows (PE export tables); " \
64
+ "darwin/linux legs enforce the mirror"
65
+ next
66
+ end
67
+ # Probe nm without a shell: the multi-arg system() execs
68
+ # directly, so there is no which/redirect syntax to be
69
+ # platform-hostile. File::NULL is NUL where it must be; a
70
+ # missing binary is falsy either way (ENOENT rescue belts the
71
+ # older spawn behavior).
72
+ unless nm_available?
73
+ puts "audit:symbols: skipped (nm unavailable on this platform)"
74
+ next
75
+ end
58
76
  lib = Dir.glob("lib/libleptris.{dylib,so,dll}").first
59
- unless lib && system("which nm > /dev/null 2>&1")
60
- abort "audit:symbols: vendored library or nm not found — run rake compile"
77
+ unless lib
78
+ abort "audit:symbols: vendored library not found — run rake compile"
61
79
  end
62
80
  exported = `nm -gU #{lib}`
63
81
  .lines.map { |l| l.split[2] }.compact
@@ -82,6 +100,13 @@ namespace :audit do
82
100
  abort "audit:symbols: drift detected"
83
101
  end
84
102
  end
103
+
104
+ # @api private
105
+ def nm_available?
106
+ system("nm", "--version", out: File::NULL, err: File::NULL)
107
+ rescue Errno::ENOENT
108
+ false
109
+ end
85
110
  end
86
111
 
87
112
  require "rubygems/package_task"
@@ -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.8"
4
+ VERSION = "1.9.10"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: leptris
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.8
4
+ version: 1.9.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -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