Module: Leptris::XML::Searchable
- Included in:
- Document, DocumentFragment, Node, NodeSet
- Defined in:
- lib/leptris/xml/searchable.rb
Class Method Summary collapse
-
.wrap_xpath_first_result(document, result_ptr) ⇒ Object
Single-node seam beside wrap_xpath_result: a nodeset answers via result_get_node(0) + wrap + free — no NodeSet container, no AutoPointer, one fewer FFI than xpath().first; scalars keep the full-wrapper semantics.
-
.wrap_xpath_result(document, result_ptr) ⇒ Object
Shared by Searchable#xpath and Leptris::XML::XPath (compiled expressions): wraps a raw XPathResult pointer into the Ruby-typed result and frees the C handle.
Instance Method Summary collapse
-
#at(*args) ⇒ Object
(also: #%)
Single-node seam (round XIV): dispatch on syntax like #search, then call the at_* fast paths directly — no NodeSet container, no result handle, one fewer dispatch than search().first.
- #at_css(*args) ⇒ Object
- #at_xpath(*paths) ⇒ Object
- #css(*args) ⇒ Object
- #search(*args) ⇒ Object (also: #/)
- #xpath(*paths) ⇒ Object
Class Method Details
.wrap_xpath_first_result(document, result_ptr) ⇒ Object
Single-node seam beside wrap_xpath_result: a nodeset answers via result_get_node(0) + wrap + free — no NodeSet container, no AutoPointer, one fewer FFI than xpath().first; scalars keep the full-wrapper semantics.
121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/leptris/xml/searchable.rb', line 121 def self.wrap_xpath_first_result(document, result_ptr) type = Leptris::XML::FFI.leptris_xpath_result_type(result_ptr) if type == Leptris::XML::FFI::XPATH_NODESET ptr = Leptris::XML::FFI.leptris_xpath_result_get_node(result_ptr, 0) node = ptr.null? ? nil : Leptris::XML::Node.wrap(ptr, document) Leptris::XML::FFI.leptris_xpath_result_free(result_ptr) node else wrap_xpath_result(document, result_ptr) end end |
.wrap_xpath_result(document, result_ptr) ⇒ Object
Shared by Searchable#xpath and Leptris::XML::XPath (compiled expressions): wraps a raw XPathResult pointer into the Ruby-typed result and frees the C handle.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/leptris/xml/searchable.rb', line 136 def self.wrap_xpath_result(document, result_ptr) type = Leptris::XML::FFI.leptris_xpath_result_type(result_ptr) case type when Leptris::XML::FFI::XPATH_NODESET Leptris::XML::NodeSet.from_result(document, result_ptr) when Leptris::XML::FFI::XPATH_BOOLEAN v = Leptris::XML::FFI.leptris_xpath_result_boolean(result_ptr) != 0 Leptris::XML::FFI.leptris_xpath_result_free(result_ptr) v when Leptris::XML::FFI::XPATH_NUMBER v = Leptris::XML::FFI.leptris_xpath_result_number(result_ptr) Leptris::XML::FFI.leptris_xpath_result_free(result_ptr) v when Leptris::XML::FFI::XPATH_STRING str_ptr = Leptris::XML::FFI.leptris_xpath_result_string(result_ptr) v = Leptris::XML::FFI.read_owned_string(str_ptr) Leptris::XML::FFI.leptris_xpath_result_free(result_ptr) v else Leptris::XML::FFI.leptris_xpath_result_free(result_ptr) raise Leptris::XML::XPathError, "unknown xpath result type #{type}" end end |
Instance Method Details
#at(*args) ⇒ Object Also known as: %
Single-node seam (round XIV): dispatch on syntax like #search, then call the at_* fast paths directly — no NodeSet container, no result handle, one fewer dispatch than search().first.
56 57 58 59 60 61 62 63 |
# File 'lib/leptris/xml/searchable.rb', line 56 def at(*args) paths = args.first.is_a?(Array) ? args.first : [args.first] if paths.map(&:to_s).all? { |p| looks_like_xpath?(p) } at_xpath(*paths) else at_css(*args) end end |
#at_css(*args) ⇒ Object
78 79 80 81 82 83 84 85 86 |
# File 'lib/leptris/xml/searchable.rb', line 78 def at_css(*args) handler, ns, _ = parse_search_args(args) raise ArgumentError, "namespace bindings not supported in css" if ns && !ns.empty? raise ArgumentError, "custom CSS handlers not supported" if handler prefix = is_a?(Leptris::XML::Document) ? "//" : ".//" expr = args.map { |r| Leptris::XML::CssToXPath.convert(r, prefix: prefix) } .join(" | ") at_xpath(expr) end |
#at_xpath(*paths) ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
# File 'lib/leptris/xml/searchable.rb', line 26 def at_xpath(*paths) handler, ns, _vars = parse_search_args(paths) raise ArgumentError, "custom XPath handlers not supported" if handler expr = paths.join(" | ") doc_ptr = is_a?(Leptris::XML::Document) ? c_ptr : document.c_ptr context_ptr = is_a?(Leptris::XML::Document) ? nil : c_ptr result_ptr = if ns && !ns.empty? xpath_eval_with_namespaces(doc_ptr, context_ptr, expr, ns) else Leptris::XML::FFI.leptris_xpath_eval(doc_ptr, context_ptr, expr) end if result_ptr.null? raise Leptris::XML::XPathError, Leptris::XML::FFI.leptris_last_error.to_s end Leptris::XML::Searchable.wrap_xpath_first_result(document, result_ptr) end |
#css(*args) ⇒ Object
66 67 68 69 70 71 72 73 74 75 76 |
# File 'lib/leptris/xml/searchable.rb', line 66 def css(*args) handler, ns, _ = parse_search_args(args) raise ArgumentError, "namespace bindings not supported in css" if ns && !ns.empty? raise ArgumentError, "custom CSS handlers not supported" if handler # Nokogiri semantics: css is receiver-relative — absolute "//" # from a Document, descendant ".//" from elements and fragments. prefix = is_a?(Leptris::XML::Document) ? "//" : ".//" expr = args.map { |r| Leptris::XML::CssToXPath.convert(r, prefix: prefix) } .join(" | ") xpath(expr) end |
#search(*args) ⇒ Object Also known as: /
47 48 49 50 |
# File 'lib/leptris/xml/searchable.rb', line 47 def search(*args) paths = args.first.is_a?(Array) ? args.first : [args.first] paths.map(&:to_s).all? { |p| looks_like_xpath?(p) } ? xpath(*paths) : css(*paths) end |
#xpath(*paths) ⇒ Object
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/leptris/xml/searchable.rb', line 4 def xpath(*paths) handler, ns, _vars = parse_search_args(paths) raise ArgumentError, "custom XPath handlers not supported" if handler expr = paths.join(" | ") doc_ptr = is_a?(Leptris::XML::Document) ? c_ptr : document.c_ptr context_ptr = is_a?(Leptris::XML::Document) ? nil : c_ptr result_ptr = if ns && !ns.empty? xpath_eval_with_namespaces(doc_ptr, context_ptr, expr, ns) else Leptris::XML::FFI.leptris_xpath_eval(doc_ptr, context_ptr, expr) end if result_ptr.null? raise Leptris::XML::XPathError, Leptris::XML::FFI.leptris_last_error.to_s end Leptris::XML::Searchable.wrap_xpath_result(document, result_ptr) end |