leptris 1.2.0 → 1.2.1
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 +4 -4
- data/CHANGELOG.md +16 -0
- data/lib/leptris/version.rb +1 -1
- data/lib/leptris/xml/document.rb +2 -1
- data/lib/leptris/xml/ffi.rb +26 -2
- data/lib/leptris/xml/searchable.rb +23 -2
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e9d9e951ee8e7b15451e02933c6e5e80d6cb78fa970ff4411153ec1358c50ab1
|
|
4
|
+
data.tar.gz: 5aab53987963478c27bb0d9bfe96e804672dcc6b7da1842cc3422f9e0b91c235
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7de27428d6e469b405889481a78bdbe1680d28e4b8c4bd2041ccfb49dd3b9a620359f5d66a4bc4f4573e16c332916348cf4313bedbb1c5d1876cf08cb64b243e
|
|
7
|
+
data.tar.gz: c71f63da347773adfd341782dd10326ff5993c673080e63554013eed453137014f76f2b4a0474b9fa452c5009f573d4d65f01213822016e296735a0a1eea30e3
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,22 @@ All notable changes to Leptris will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.2.1] - 2026-08-23
|
|
9
|
+
|
|
10
|
+
Completes the libleptris 1.2.0 public surface in the binding.
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Namespace-bound XPath**: `doc.xpath("//p:title", "p" => "urn:p")`
|
|
15
|
+
(Nokogiri parity) — expression prefixes now resolve to caller-supplied
|
|
16
|
+
URIs regardless of the prefixes the document declared, via
|
|
17
|
+
`leptris_xpath_ns_set_new/_add/_free` + `leptris_xpath_eval_ns`. The
|
|
18
|
+
binding set is built per call and freed under `ensure`. Previously
|
|
19
|
+
the trailing namespace hash was silently ignored.
|
|
20
|
+
- `leptris_error_message` / `leptris_last_error` bound; the status seam
|
|
21
|
+
and parse errors now append the library's last-error detail when
|
|
22
|
+
present (best-effort: it is a library-global string).
|
|
23
|
+
|
|
8
24
|
## [1.2.0] - 2026-08-23
|
|
9
25
|
|
|
10
26
|
Lockstep with libleptris 1.2.0.
|
data/lib/leptris/version.rb
CHANGED
data/lib/leptris/xml/document.rb
CHANGED
|
@@ -50,7 +50,8 @@ class Leptris::XML::Document
|
|
|
50
50
|
if raw.null?
|
|
51
51
|
status = status_ptr.read_int
|
|
52
52
|
raise Leptris::XML::ParseError,
|
|
53
|
-
"leptris_parse_string failed (status=#{status})"
|
|
53
|
+
"leptris_parse_string failed (status=#{status}): " +
|
|
54
|
+
Leptris::XML::FFI.status_message(status)
|
|
54
55
|
end
|
|
55
56
|
wrap(raw)
|
|
56
57
|
end
|
data/lib/leptris/xml/ffi.rb
CHANGED
|
@@ -23,6 +23,7 @@ module Leptris
|
|
|
23
23
|
typedef :pointer, :leptris_attribute
|
|
24
24
|
typedef :pointer, :leptris_doctype
|
|
25
25
|
typedef :pointer, :leptris_xpath_result
|
|
26
|
+
typedef :pointer, :leptris_xpath_ns_set
|
|
26
27
|
typedef :pointer, :leptris_xpath_var_set
|
|
27
28
|
typedef :pointer, :leptris_sax_parser
|
|
28
29
|
typedef :int, :leptris_status
|
|
@@ -365,6 +366,18 @@ module Leptris
|
|
|
365
366
|
attach_function :leptris_xpath_variable_set_string,
|
|
366
367
|
[:leptris_xpath_var_set, :string, :string], :leptris_status
|
|
367
368
|
|
|
369
|
+
# Namespace-bound XPath (v1.2.0): expression prefixes resolve to
|
|
370
|
+
# caller-supplied URIs regardless of the document's declarations.
|
|
371
|
+
attach_function :leptris_xpath_ns_set_new,
|
|
372
|
+
[], :leptris_xpath_ns_set
|
|
373
|
+
attach_function :leptris_xpath_ns_set_free,
|
|
374
|
+
[:leptris_xpath_ns_set], :void
|
|
375
|
+
attach_function :leptris_xpath_ns_set_add,
|
|
376
|
+
[:leptris_xpath_ns_set, :string, :string], :leptris_status
|
|
377
|
+
attach_function :leptris_xpath_eval_ns,
|
|
378
|
+
[:leptris_document, :leptris_element, :string, :leptris_xpath_ns_set],
|
|
379
|
+
:leptris_xpath_result
|
|
380
|
+
|
|
368
381
|
attach_function :leptris_sax_parse,
|
|
369
382
|
[:string, :size_t, :pointer, :pointer], :int
|
|
370
383
|
attach_function :leptris_sax_parser_create,
|
|
@@ -419,6 +432,8 @@ module Leptris
|
|
|
419
432
|
attach_function :leptris_document_set_allocators,
|
|
420
433
|
[:leptris_document, :pointer, :pointer], :leptris_status
|
|
421
434
|
attach_function :leptris_status_string, [:leptris_status], :string
|
|
435
|
+
attach_function :leptris_error_message, [:leptris_status], :string
|
|
436
|
+
attach_function :leptris_last_error, [], :string
|
|
422
437
|
|
|
423
438
|
LEPTRIS_OK = 0
|
|
424
439
|
LEPTRIS_ERROR_MEMORY = -1
|
|
@@ -467,13 +482,22 @@ module Leptris
|
|
|
467
482
|
ptr.read_string.tap { leptris_free_string(ptr) }
|
|
468
483
|
end
|
|
469
484
|
|
|
470
|
-
# Single status seam: turns a C status code into a Ruby error
|
|
485
|
+
# Single status seam: turns a C status code into a Ruby error,
|
|
486
|
+
# appending the library's last-error detail when present. The
|
|
487
|
+
# detail is a library-global string, so it can only be treated
|
|
488
|
+
# as best-effort context.
|
|
471
489
|
def self.check_status(status)
|
|
472
490
|
unless status == LEPTRIS_OK
|
|
473
|
-
raise Leptris::XML::Error,
|
|
491
|
+
raise Leptris::XML::Error, status_message(status)
|
|
474
492
|
end
|
|
475
493
|
status
|
|
476
494
|
end
|
|
495
|
+
|
|
496
|
+
def self.status_message(status)
|
|
497
|
+
base = leptris_status_string(status).to_s
|
|
498
|
+
detail = leptris_last_error.to_s
|
|
499
|
+
detail.empty? ? base : "#{base} (#{detail})"
|
|
500
|
+
end
|
|
477
501
|
end
|
|
478
502
|
end
|
|
479
503
|
end
|
|
@@ -2,14 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
module Leptris::XML::Searchable
|
|
4
4
|
def xpath(*paths)
|
|
5
|
-
handler,
|
|
5
|
+
handler, ns, _vars = parse_search_args(paths)
|
|
6
6
|
raise ArgumentError, "custom XPath handlers not supported" if handler
|
|
7
7
|
expr = paths.join(" | ")
|
|
8
8
|
|
|
9
9
|
doc_ptr = is_a?(Leptris::XML::Document) ? c_ptr : document.c_ptr
|
|
10
10
|
context_ptr = is_a?(Leptris::XML::Document) ? nil : c_ptr
|
|
11
11
|
|
|
12
|
-
result_ptr =
|
|
12
|
+
result_ptr =
|
|
13
|
+
if ns && !ns.empty?
|
|
14
|
+
xpath_eval_with_namespaces(doc_ptr, context_ptr, expr, ns)
|
|
15
|
+
else
|
|
16
|
+
Leptris::XML::FFI.leptris_xpath_eval(doc_ptr, context_ptr, expr)
|
|
17
|
+
end
|
|
13
18
|
if result_ptr.null?
|
|
14
19
|
raise Leptris::XML::XPathError,
|
|
15
20
|
Leptris::XML::FFI.leptris_status_string(Leptris::XML::FFI::LEPTRIS_ERROR_XPATH)
|
|
@@ -50,6 +55,22 @@ module Leptris::XML::Searchable
|
|
|
50
55
|
|
|
51
56
|
protected
|
|
52
57
|
|
|
58
|
+
# Builds a caller-owned namespace binding set, evaluates via
|
|
59
|
+
# leptris_xpath_eval_ns, and frees the set regardless of outcome.
|
|
60
|
+
def xpath_eval_with_namespaces(doc_ptr, context_ptr, expr, ns)
|
|
61
|
+
set = Leptris::XML::FFI.leptris_xpath_ns_set_new
|
|
62
|
+
begin
|
|
63
|
+
ns.each do |prefix, uri|
|
|
64
|
+
Leptris::XML::FFI.check_status(
|
|
65
|
+
Leptris::XML::FFI.leptris_xpath_ns_set_add(
|
|
66
|
+
set, prefix.to_s, uri.to_s))
|
|
67
|
+
end
|
|
68
|
+
Leptris::XML::FFI.leptris_xpath_eval_ns(doc_ptr, context_ptr, expr, set)
|
|
69
|
+
ensure
|
|
70
|
+
Leptris::XML::FFI.leptris_xpath_ns_set_free(set)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
53
74
|
def parse_search_args(args)
|
|
54
75
|
handler = args.find { |a| !a.is_a?(String) && !a.is_a?(Hash) && !a.is_a?(Symbol) }
|
|
55
76
|
args = args - [handler] if handler
|