leptris 1.9.15-aarch64-linux → 1.9.16-aarch64-linux

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: 8bd4232b17186b481475262c089642cf53fe8772cce8f4ac5b14c3e2908fe2fc
4
- data.tar.gz: a3d9cf9ea0eb60207fd1efddd36a20e2f7f03d5d8ceb9a334b243dc9d1965488
3
+ metadata.gz: f6960184588bed5ebd9fa8fbf64fe97bb8476b433ba43b5176568f20b9dd561b
4
+ data.tar.gz: 739e787fbd3c921bcb2ac4cdf776b3f85bc7ec2fe870b8f94f9366cd3aacc710
5
5
  SHA512:
6
- metadata.gz: '08142860a72a4f30a91e9e13ebb53560e7e3724c22634463f517d1916e3a074a809e2b5fb30915ff819611f05f75fd75eff4332bc7b633eed671743c7c4d1cf2'
7
- data.tar.gz: ba14890554f0df8ea9db1efb1ed3832977a63abfb3d624b447c38c37038f96708724b81184da0bbaa64eebd4644233ee3b2be04d5b7329ce2a45d426e578ff94
6
+ metadata.gz: 2588d661f45aec8859681b381fffd2fb05b4600f2888c826ad86a1c43f8ad86d7a8fc95b8ce4d5ae803772275066e4f43e67f09bf0592d5648d732383081168e
7
+ data.tar.gz: d01eb46bdd19bbdfdf26c6fb278111291f8713439d088f205f7985ba46f31696c344c864f8d95229d4e389c7bc857bdfaae25721cf49d8475c71936c2344b8e1
data/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ 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.16] - 2026-08-27
9
+
10
+ ### Changed
11
+
12
+ - **at_xpath / at_css take the single-node path**: a new
13
+ `wrap_xpath_first_result` seam answers nodeset results via
14
+ get_node(0) + wrap + free — no NodeSet container, no AutoPointer,
15
+ one fewer FFI than xpath().first; scalar results keep full-wrapper
16
+ semantics. Measured on the canonical scraper loop: at_xpath 0.018 s
17
+ -> 0.005 s (3.6x — the per-iteration container churn was GC
18
+ pressure the old path paid twice), at_css ~24%. Equivalence with
19
+ xpath().first is spec-pinned across nodeset/empty/scalar shapes.
20
+ Also drops a vestigial `.send(:from_result)` on a public factory.
21
+
8
22
  ## [1.9.15] - 2026-08-27
9
23
 
10
24
  ### Changed
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leptris
4
- VERSION = "1.9.15"
4
+ VERSION = "1.9.16"
5
5
  end
@@ -24,8 +24,24 @@ module Leptris::XML::Searchable
24
24
  end
25
25
 
26
26
  def at_xpath(*paths)
27
- result = xpath(*paths)
28
- result.is_a?(Leptris::XML::NodeSet) ? result.first : result
27
+ handler, ns, _vars = parse_search_args(paths)
28
+ raise ArgumentError, "custom XPath handlers not supported" if handler
29
+ expr = paths.join(" | ")
30
+
31
+ doc_ptr = is_a?(Leptris::XML::Document) ? c_ptr : document.c_ptr
32
+ context_ptr = is_a?(Leptris::XML::Document) ? nil : c_ptr
33
+
34
+ result_ptr =
35
+ if ns && !ns.empty?
36
+ xpath_eval_with_namespaces(doc_ptr, context_ptr, expr, ns)
37
+ else
38
+ Leptris::XML::FFI.leptris_xpath_eval(doc_ptr, context_ptr, expr)
39
+ end
40
+ if result_ptr.null?
41
+ raise Leptris::XML::XPathError,
42
+ Leptris::XML::FFI.leptris_last_error.to_s
43
+ end
44
+ Leptris::XML::Searchable.wrap_xpath_first_result(document, result_ptr)
29
45
  end
30
46
 
31
47
  def search(*args)
@@ -53,8 +69,13 @@ module Leptris::XML::Searchable
53
69
  end
54
70
 
55
71
  def at_css(*args)
56
- result = css(*args)
57
- result.is_a?(Leptris::XML::NodeSet) ? result.first : result
72
+ handler, ns, _ = parse_search_args(args)
73
+ raise ArgumentError, "namespace bindings not supported in css" if ns && !ns.empty?
74
+ raise ArgumentError, "custom CSS handlers not supported" if handler
75
+ prefix = is_a?(Leptris::XML::Document) ? "//" : ".//"
76
+ expr = args.map { |r| Leptris::XML::CssToXPath.convert(r, prefix: prefix) }
77
+ .join(" | ")
78
+ at_xpath(expr)
58
79
  end
59
80
 
60
81
  protected
@@ -86,6 +107,22 @@ module Leptris::XML::Searchable
86
107
  %r{\A(\./|/|\.\.|\.)}.match?(str)
87
108
  end
88
109
 
110
+ # Single-node seam beside wrap_xpath_result: a nodeset answers
111
+ # via result_get_node(0) + wrap + free — no NodeSet container, no
112
+ # AutoPointer, one fewer FFI than xpath().first; scalars keep the
113
+ # full-wrapper semantics.
114
+ def self.wrap_xpath_first_result(document, result_ptr)
115
+ type = Leptris::XML::FFI.leptris_xpath_result_type(result_ptr)
116
+ if type == Leptris::XML::FFI::XPATH_NODESET
117
+ ptr = Leptris::XML::FFI.leptris_xpath_result_get_node(result_ptr, 0)
118
+ node = ptr.null? ? nil : Leptris::XML::Node.wrap(ptr, document)
119
+ Leptris::XML::FFI.leptris_xpath_result_free(result_ptr)
120
+ node
121
+ else
122
+ wrap_xpath_result(document, result_ptr)
123
+ end
124
+ end
125
+
89
126
  # Shared by Searchable#xpath and Leptris::XML::XPath (compiled
90
127
  # expressions): wraps a raw XPathResult pointer into the
91
128
  # Ruby-typed result and frees the C handle.
@@ -93,7 +130,7 @@ module Leptris::XML::Searchable
93
130
  type = Leptris::XML::FFI.leptris_xpath_result_type(result_ptr)
94
131
  case type
95
132
  when Leptris::XML::FFI::XPATH_NODESET
96
- Leptris::XML::NodeSet.send(:from_result, document, result_ptr)
133
+ Leptris::XML::NodeSet.from_result(document, result_ptr)
97
134
  when Leptris::XML::FFI::XPATH_BOOLEAN
98
135
  v = Leptris::XML::FFI.leptris_xpath_result_boolean(result_ptr) != 0
99
136
  Leptris::XML::FFI.leptris_xpath_result_free(result_ptr)
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.15
4
+ version: 1.9.16
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Ribose Inc.