leptris 1.9.17 → 1.9.19

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: 790fde1b932902a17438b2abed525393ebb61464a61ff35081384409277a42cc
4
- data.tar.gz: 356b2a9a9426c03a25c42577952f3634127162e449e3540816b99a8bf6cd354f
3
+ metadata.gz: 97ca1201d65e8bb43ac419b09c9e208fd49a1cb88275beb14cb2f2ec0e7965e2
4
+ data.tar.gz: df1b06279ae9426f463c724a6c895a135daedb19880f62ba1c8cda377228af3f
5
5
  SHA512:
6
- metadata.gz: 8fdfd7ed098ae1501040d5f82808c57813f5f2f8dec606d6ac966bd916cff635dd510ebf68e235a4a3e9c0da6a5a10cc9765ffe20eb06a476876dc2cf6dbc2fc
7
- data.tar.gz: 26142e64a808758e72332fa8aaef029b7fee19c82c3f634f6f0ec9ba7afe7990261f958173a124f2f89ced5270c253f53256f4b12eafc99235a066e38c5b7f3a
6
+ metadata.gz: 390e31d59b5fe74f08776d719e5cd608a6cee954184a65edd688d25e92ed019be47b39c65369a5553fe1b1425341570778b3f6a7abf5896ca425935cf1e3e2aa
7
+ data.tar.gz: f72f7460afa8f16d0aa77e313d8d047c8ff1cf98180332c34f59c4034352fa737256cf943b1cecf941caee2ae7beddd1e0f844c1e2bb305332594f496b026d77
data/CHANGELOG.md CHANGED
@@ -5,6 +5,45 @@ 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.19] - 2026-08-27
9
+
10
+ Lockstep with libleptris 1.9.3 — unblocks the 1.9.18 release
11
+ (v1.9.2 did not compile on musl, upstream #582).
12
+
13
+ ### Added
14
+
15
+ - **`Document#comments`**: document-level comments — parsed
16
+ `<!-- ... -->` outside the root, prolog then epilog, in document
17
+ order (upstream #578). UTF-8, version-memoized like the PI list;
18
+ the companion reader to `#processing_instructions`.
19
+
20
+ ### Fixed
21
+
22
+ - Rides the engine's v1.9.3 fixes: dataless PIs parse correctly
23
+ (#577 — `<?pi?>` no longer clobbers its closing `?`), epilog
24
+ comments are kept and serialize after the root (#578), and
25
+ attribute values normalize per XML 1.0 §3.3.3 (#576 — whitespace
26
+ collapsing and entity decoding in attribute values).
27
+
28
+ ## [1.9.18] - 2026-08-27
29
+
30
+ Lockstep with libleptris 1.9.2 (covers 1.9.1 — the XSLT engine — and
31
+ 1.9.2, the options-struct ABI freeze; the binding's three-field
32
+ SerializeOptions layout is the frozen shape, so no binding change was
33
+ required for the fix).
34
+
35
+ ### Added
36
+
37
+ - **`Leptris::XML::XSLT` — XSLT 1.0 transforms**: the engine compiles
38
+ a stylesheet ONCE into an immutable instruction forest, then applies
39
+ it to any number of documents. `XSLT.parse(xml)` /
40
+ `XSLT.parse_file(path)` (resolves §2.7 embedded stylesheets);
41
+ `Stylesheet#apply_to(doc)` returns the result as an owning,
42
+ queryable Document; `Stylesheet#serialize(doc)` keeps top-level
43
+ text nodes and result fragments. Bad select expressions are
44
+ rejected at COMPILE time. The custom XPath-function handler seam
45
+ attaches mirror-only until a use case arrives.
46
+
8
47
  ## [1.9.17] - 2026-08-27
9
48
 
10
49
  ### Changed
data/Rakefile CHANGED
@@ -8,7 +8,7 @@ RSpec::Core::RakeTask.new(:spec)
8
8
  # Pin for `rake compile` and the platform-gem builds. Keep in lockstep
9
9
  # with .github/workflows/build.yml (which calls `rake compile`) and the
10
10
  # CHANGELOG when libleptris releases.
11
- LIBLEPTRIS_VERSION = "1.9.0"
11
+ LIBLEPTRIS_VERSION = "1.9.3"
12
12
 
13
13
  CMAKE_FLAGS = %w[
14
14
  -DCMAKE_BUILD_TYPE=Release
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.17"
4
+ VERSION = "1.9.19"
5
5
  end
@@ -311,6 +311,21 @@ class Leptris::XML::Document
311
311
  @freed.state == :freed || @c_ptr.nil?
312
312
  end
313
313
 
314
+ # Document-level comments — parsed <!-- ... --> outside the
315
+ # root element, prolog then epilog, in document order (the
316
+ # companion reader to #processing_instructions; libleptris
317
+ # 1.9.3, upstream #578). Version-memoized like the PI list.
318
+ def comments
319
+ return @comments if @comments_version == @version
320
+ count = Leptris::XML::FFI.leptris_document_comment_count(@c_ptr)
321
+ result = Array.new(count) do |i|
322
+ Leptris::XML::FFI.leptris_document_comment_content(@c_ptr, i)
323
+ end
324
+ @comments = result
325
+ @comments_version = @version
326
+ result
327
+ end
328
+
314
329
  # The thread-global last-failure [line, column] (1-based), or nil
315
330
  # when no error is recorded — the position companion to
316
331
  # Document#last_error; populated by recover parses.
@@ -42,6 +42,7 @@ module Leptris
42
42
  typedef :pointer, :leptris_xpath_result
43
43
  typedef :pointer, :leptris_xpath_ns_set
44
44
  typedef :pointer, :leptris_xpath_compiled
45
+ typedef :pointer, :leptris_xslt
45
46
  typedef :pointer, :leptris_pull_parser
46
47
  typedef :pointer, :leptris_iterparse
47
48
  typedef :pointer, :leptris_xpath_var_set
@@ -124,6 +125,13 @@ module Leptris
124
125
  [:leptris_document, :size_t], :string
125
126
  attach_function :leptris_document_add_pi,
126
127
  [:leptris_document, :string, :string], :pointer
128
+ # Document-level comments (libleptris 1.9.3, #578): parsed
129
+ # <!-- ... --> outside the root, prolog then epilog, in
130
+ # document order. Read-only surface (no add_comment yet).
131
+ attach_function :leptris_document_comment_count,
132
+ [:leptris_document], :size_t
133
+ attach_function :leptris_document_comment_content,
134
+ [:leptris_document, :size_t], :string
127
135
  # Options-struct parse (v1.6.0): supersedes the flags variants;
128
136
  # the flags path remains bound for compatibility.
129
137
  attach_function :leptris_parse_string_ex,
@@ -478,7 +486,11 @@ module Leptris
478
486
  attach_function :leptris_xpath_compiled_eval_vars,
479
487
  [:leptris_xpath_compiled, :leptris_document, :leptris_element,
480
488
  :leptris_xpath_var_set], :leptris_xpath_result
489
+ # Source text of a compiled expression (owned by the handle).
490
+ attach_function :leptris_xpath_compiled_text,
491
+ [:leptris_xpath_compiled], :string
481
492
  attach_function :leptris_xpath_compiled_free,
493
+
482
494
  [:leptris_xpath_compiled], :void
483
495
 
484
496
  attach_function :leptris_sax_parse,
@@ -539,7 +551,23 @@ module Leptris
539
551
  [:leptris_element, :pointer, :size_t, :pointer, :pointer], :size_t
540
552
  attach_function :leptris_document_save_file,
541
553
  [:leptris_document, :string, :pointer], :leptris_status
554
+ # XSLT 1.0 engine (libleptris 1.9.1): compile once, apply many.
555
+ attach_function :leptris_xslt_parse,
556
+ [:string, :size_t], :leptris_xslt
557
+ attach_function :leptris_xslt_parse_file,
558
+ [:string], :leptris_xslt
559
+ attach_function :leptris_xslt_free,
560
+ [:leptris_xslt], :void
561
+ # Result tree is a document (free with document_free); errors
562
+ # surface via document_last_error on NULL.
563
+ attach_function :leptris_xslt_apply,
564
+ [:leptris_xslt, :leptris_document], :leptris_document
565
+ # apply + serialize in one call, keeping top-level text nodes
566
+ # and result fragments the tree API would flatten.
567
+ attach_function :leptris_xslt_apply_string,
568
+ [:leptris_xslt, :leptris_document], :pointer
542
569
  attach_function :leptris_c14n_canonicalize,
570
+
543
571
  [:leptris_document, :int, :int], :pointer
544
572
  attach_function :leptris_c14n_canonicalize_subtree,
545
573
  [:leptris_element, :int, :int], :pointer
@@ -648,6 +676,7 @@ module Leptris
648
676
  leptris_status_string leptris_last_error
649
677
  leptris_document_last_error leptris_document_encoding
650
678
  leptris_document_pi_target leptris_document_pi_data
679
+ leptris_document_comment_content
651
680
  leptris_element_name leptris_element_text leptris_element_prefix
652
681
  leptris_element_namespace
653
682
  leptris_element_attribute leptris_element_attribute_ns
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "ffi"
4
+
5
+ module Leptris::XML::XSLT
6
+ module_function
7
+
8
+ def parse(stylesheet_xml)
9
+ Stylesheet.parse(stylesheet_xml)
10
+ end
11
+
12
+ def parse_file(path)
13
+ Stylesheet.parse_file(path)
14
+ end
15
+
16
+ # A compiled XSLT 1.0 stylesheet (libleptris 1.9.1): the stylesheet
17
+ # parses ONCE into an immutable instruction forest — patterns to
18
+ # XPath ASTs, selects through the compiled-XPath path — then applies
19
+ # to any number of documents with no re-parsing.
20
+ #
21
+ # style = Leptris::XML::XSLT.parse(<<~XSL)
22
+ # <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
23
+ # <xsl:template match="/"><out><xsl:value-of select="count(//item)"/></out></xsl:template>
24
+ # </xsl:stylesheet>
25
+ # XSL
26
+ # style.apply_to(doc) # => result Document (queryable tree)
27
+ # style.serialize(doc) # => String (fragments and top-level
28
+ # # text nodes preserved)
29
+ #
30
+ class Stylesheet
31
+ # GC-managed compiled handle.
32
+ class Handle < ::FFI::AutoPointer
33
+ def self.release(ptr)
34
+ Leptris::XML::FFI.leptris_xslt_free(ptr)
35
+ end
36
+ end
37
+
38
+ # Compile a stylesheet. Raises XPathError on a stylesheet syntax
39
+ # error (detail on the thread-global last error).
40
+ def self.parse(stylesheet_xml)
41
+ raw = Leptris::XML::FFI.leptris_xslt_parse(
42
+ stylesheet_xml.to_s, stylesheet_xml.to_s.bytesize)
43
+ if raw.null?
44
+ raise Leptris::XML::XPathError,
45
+ "stylesheet parse failed: #{Leptris::XML::FFI.leptris_last_error}"
46
+ end
47
+ new(Handle.new(raw))
48
+ end
49
+
50
+ # Compile from a file. Resolves §2.7 embedded stylesheets
51
+ # (xml-stylesheet PI with an href="#id" fragment) when the file's
52
+ # root is not itself a stylesheet.
53
+ def self.parse_file(path)
54
+ raw = Leptris::XML::FFI.leptris_xslt_parse_file(path.to_s)
55
+ if raw.null?
56
+ raise Leptris::XML::XPathError,
57
+ "stylesheet parse failed: #{Leptris::XML::FFI.leptris_last_error}"
58
+ end
59
+ new(Handle.new(raw))
60
+ end
61
+
62
+ def initialize(handle)
63
+ @handle = handle
64
+ end
65
+
66
+ # Apply to +document+ (not modified) and return the result tree
67
+ # as an owning Document — query it with xpath/css like any other.
68
+ def apply_to(document)
69
+ raw = Leptris::XML::FFI.leptris_xslt_apply(@handle, document.c_ptr)
70
+ if raw.null?
71
+ raise Leptris::XML::XPathError,
72
+ "transform failed: #{document.last_error || Leptris::XML::FFI.leptris_last_error}"
73
+ end
74
+ Leptris::XML::Document.wrap(raw)
75
+ end
76
+
77
+ # Apply and serialize in one call — keeps top-level text nodes and
78
+ # result fragments that the tree API would flatten.
79
+ def serialize(document)
80
+ str_ptr = Leptris::XML::FFI.leptris_xslt_apply_string(
81
+ @handle, document.c_ptr)
82
+ Leptris::XML::FFI.read_owned_string(str_ptr)
83
+ end
84
+ end
85
+ end
data/lib/leptris/xml.rb CHANGED
@@ -22,6 +22,7 @@ module Leptris
22
22
  autoload :Serialization, "leptris/xml/serialization"
23
23
  autoload :SAX, "leptris/xml/sax"
24
24
  autoload :XPath, "leptris/xml/xpath"
25
+ autoload :XSLT, "leptris/xml/xslt"
25
26
  autoload :Pull, "leptris/xml/pull"
26
27
  autoload :Iterparse, "leptris/xml/iterparse"
27
28
 
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.17
4
+ version: 1.9.19
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
@@ -103,6 +103,7 @@ files:
103
103
  - lib/leptris/xml/serialization.rb
104
104
  - lib/leptris/xml/text.rb
105
105
  - lib/leptris/xml/xpath.rb
106
+ - lib/leptris/xml/xslt.rb
106
107
  homepage: https://github.com/leptris/leptris-ruby
107
108
  licenses:
108
109
  - MIT