Module: Dommy::Backend
- Defined in:
- lib/dommy/backend.rb,
lib/dommy/backend/makiri_adapter.rb
Overview
Dommy::Backend — pluggable HTML parser abstraction. Lets Dommy
work with Makiri (Lexbor-based, HTML5-only). Internally, all DOM library
code goes through this facade rather than referencing the parser
directly.
Defaults to Makiri.
Switching backends:
require "dommy"
Dommy::Backend.use(:makiri)
Or set directly:
Dommy::Backend.current = Dommy::Backend::Makiri
All adapters must implement the same interface — see
Backend::Makiri for the canonical reference.
Defined Under Namespace
Modules: Makiri Classes: BackendNotAvailable
Class Attribute Summary collapse
Class Method Summary collapse
- .add_namespace_definition(node, prefix, href) ⇒ Object
-
.adopt(node, target_doc) ⇒ Object
Bring
node(already detached from its old tree) intotarget_doc, returning the backend node now owned bytarget_doc. -
.attribute_nodes(node) ⇒ Object
The element's attribute nodes (each readable via attribute_ns_info).
-
.attribute_ns_info(attr_node) ⇒ Object
Reads a backend attribute node into prefix:, local_name:, qualified_name:, value: (namespace-aware).
- .cdata_class ⇒ Object
-
.clone_document(doc) ⇒ Object
Deep copy of a whole document (DOM cloneNode on the document).
-
.clone_node(node, deep:) ⇒ Object
Deep (or shallow) copy of an element/node, detached and owned by the same document — the backing for DOM cloneNode.
- .comment_class ⇒ Object
-
.create_cdata(content, doc) ⇒ Object
CDATA section node (XML documents).
- .create_comment(content, doc) ⇒ Object
-
.create_document_type(name, public_id, system_id, doc) ⇒ Object
A detached DocumentType node owned by
doc(for DOMImplementation.createDocumentType). - .create_element(name, doc) ⇒ Object
-
.create_element_loose(qualified_name, prefix, local, namespace, doc) ⇒ Object
Create a namespaced element permitting a DOM-valid qualified name that a strict XML backend would reject (an internal invalid char like "f}oo"), preserving case/prefix.
-
.create_processing_instruction(target, data, doc) ⇒ Object
ProcessingInstruction node (
<?target data?>). - .create_text(content, doc) ⇒ Object
- .document_class ⇒ Object
- .document_fragment_class ⇒ Object
-
.document_type_class ⇒ Object
The backend class for a DocumentType node (nil if unsupported), so the wrapper cache can route it to Dommy::DocumentType.
-
.element_class ⇒ Object
Type constants — proxy through to the current backend so
node.is_a?(Backend::Element)resolves dynamically. -
.empty_document ⇒ Object
A fresh, empty HTML-backed document.
-
.empty_document_like(doc) ⇒ Object
An empty backing document matching
doc's kind (HTML stays HTML, XML stays XML) — for a shallow document clone, whose result keeps the source flavor. -
.empty_xml_document ⇒ Object
A fresh, empty XML-backed document — for
new Document()/ createDocument, which the DOM defines as XML documents (case-preserving, real CDATA nodeType, namespaces). - .fragment(html, owner_doc:) ⇒ Object
-
.get_attribute_ns(node, namespace, local_name) ⇒ Object
Namespaced attribute access (DOM *AttributeNS).
- .has_attribute_ns?(node, namespace, local_name) ⇒ Boolean
-
.identity_key(node) ⇒ Object
Stable per-document identity key for a backend node, used to cache DOM wrappers and key per-node side tables.
-
.internal_subset(doc) ⇒ Object
The parsed document's DocumentType node, or nil when it declares none.
-
.moves_nodes_across_documents? ⇒ Boolean
Whether the backend can move a node between documents in place or must adopt a copy first (Lexbor's arenas can't move a node, so inserting a foreign node requires importing it).
-
.namespace_definitions(node) ⇒ Object
The element's in-scope namespace declarations (each responds to
prefix/href). - .namespace_of(node) ⇒ Object
- .node_class ⇒ Object
-
.parse(html) ⇒ Object
Delegate calls so internal code can use
Backend.parse(...). -
.parse_xml(xml) ⇒ Object
Parse XML input into an XML document.
- .processing_instruction_class ⇒ Object
- .remove_attribute_ns(node, namespace, local_name) ⇒ Object
-
.select_all(node, selector, scope_node: nil) ⇒ Object
CSS query that honors Dommy's custom pseudo-classes (
:disabled/:enabled/:checked/:scope). - .select_first(node, selector, scope_node: nil) ⇒ Object
- .set_attribute_ns(node, namespace, prefix, local_name, qualified_name, value) ⇒ Object
-
.set_document_root(doc, node) ⇒ Object
Make
nodethe sole document element ofdoc(used by DOMImplementation.createDocument). -
.template_content_nodes(node) ⇒ Object
The content child nodes of a
<template>element. - .text_class ⇒ Object
- .use(name) ⇒ Object
Class Attribute Details
.current ⇒ Object
27 28 29 |
# File 'lib/dommy/backend.rb', line 27 def current @current ||= detect_default end |
Class Method Details
.add_namespace_definition(node, prefix, href) ⇒ Object
208 209 210 |
# File 'lib/dommy/backend.rb', line 208 def add_namespace_definition(node, prefix, href) current.add_namespace_definition(node, prefix, href) end |
.adopt(node, target_doc) ⇒ Object
Bring node (already detached from its old tree) into target_doc,
returning the backend node now owned by target_doc. Makiri can't move a node
between arenas, so it imports a copy — callers must reseat any wrapper
onto the returned node.
83 84 85 |
# File 'lib/dommy/backend.rb', line 83 def adopt(node, target_doc) current.adopt(node, target_doc) end |
.attribute_nodes(node) ⇒ Object
The element's attribute nodes (each readable via attribute_ns_info). The single choke point so DOM code doesn't touch parser internals.
238 239 240 |
# File 'lib/dommy/backend.rb', line 238 def attribute_nodes(node) current.attribute_nodes(node) end |
.attribute_ns_info(attr_node) ⇒ Object
Reads a backend attribute node into prefix:, local_name:, qualified_name:, value: (namespace-aware).
232 233 234 |
# File 'lib/dommy/backend.rb', line 232 def attribute_ns_info(attr_node) current.attribute_ns_info(attr_node) end |
.cdata_class ⇒ Object
176 177 178 |
# File 'lib/dommy/backend.rb', line 176 def cdata_class current.respond_to?(:cdata_class) ? current.cdata_class : nil end |
.clone_document(doc) ⇒ Object
Deep copy of a whole document (DOM cloneNode on the document).
57 58 59 |
# File 'lib/dommy/backend.rb', line 57 def clone_document(doc) current.clone_document(doc) end |
.clone_node(node, deep:) ⇒ Object
Deep (or shallow) copy of an element/node, detached and owned by the same document — the backing for DOM cloneNode.
52 53 54 |
# File 'lib/dommy/backend.rb', line 52 def clone_node(node, deep:) current.clone_node(node, deep: deep) end |
.comment_class ⇒ Object
256 257 258 |
# File 'lib/dommy/backend.rb', line 256 def comment_class current::Comment end |
.create_cdata(content, doc) ⇒ Object
CDATA section node (XML documents). Backends without CDATA fall back to a text node.
172 173 174 |
# File 'lib/dommy/backend.rb', line 172 def create_cdata(content, doc) current.respond_to?(:create_cdata) ? current.create_cdata(content, doc) : current.create_text(content, doc) end |
.create_comment(content, doc) ⇒ Object
166 167 168 |
# File 'lib/dommy/backend.rb', line 166 def create_comment(content, doc) current.create_comment(content, doc) end |
.create_document_type(name, public_id, system_id, doc) ⇒ Object
A detached DocumentType node owned by doc (for
DOMImplementation.createDocumentType). Returns nil when the backend has no
doctype factory (the caller falls back to a synthetic DocumentType); raises
ArgumentError for a name the factory rejects (the caller then also falls
back, since createDocumentType is permissive).
147 148 149 |
# File 'lib/dommy/backend.rb', line 147 def create_document_type(name, public_id, system_id, doc) current.respond_to?(:create_document_type) ? current.create_document_type(name, public_id, system_id, doc) : nil end |
.create_element(name, doc) ⇒ Object
129 130 131 |
# File 'lib/dommy/backend.rb', line 129 def create_element(name, doc) current.create_element(name, doc) end |
.create_element_loose(qualified_name, prefix, local, namespace, doc) ⇒ Object
Create a namespaced element permitting a DOM-valid qualified name that a strict XML backend would reject (an internal invalid char like "f}oo"), preserving case/prefix. Returns nil when the backend has no loose path (fall back to #create_element); raises ArgumentError for a genuinely invalid name (the caller maps it to InvalidCharacterError).
138 139 140 |
# File 'lib/dommy/backend.rb', line 138 def create_element_loose(qualified_name, prefix, local, namespace, doc) current.create_element_loose(qualified_name, prefix, local, namespace, doc) end |
.create_processing_instruction(target, data, doc) ⇒ Object
ProcessingInstruction node (<?target data?>). Supported by every
backend Dommy ships (both Makiri document families), so — unlike CDATA —
there is no text-node fallback.
183 184 185 |
# File 'lib/dommy/backend.rb', line 183 def create_processing_instruction(target, data, doc) current.create_processing_instruction(target, data, doc) end |
.create_text(content, doc) ⇒ Object
162 163 164 |
# File 'lib/dommy/backend.rb', line 162 def create_text(content, doc) current.create_text(content, doc) end |
.document_class ⇒ Object
248 249 250 |
# File 'lib/dommy/backend.rb', line 248 def document_class current::Document end |
.document_fragment_class ⇒ Object
260 261 262 |
# File 'lib/dommy/backend.rb', line 260 def document_fragment_class current::DocumentFragment end |
.document_type_class ⇒ Object
The backend class for a DocumentType node (nil if unsupported), so the wrapper cache can route it to Dommy::DocumentType.
158 159 160 |
# File 'lib/dommy/backend.rb', line 158 def document_type_class current.respond_to?(:document_type_class) ? current.document_type_class : nil end |
.element_class ⇒ Object
Type constants — proxy through to the current backend so
node.is_a?(Backend::Element) resolves dynamically.
244 245 246 |
# File 'lib/dommy/backend.rb', line 244 def element_class current::Element end |
.empty_document ⇒ Object
A fresh, empty HTML-backed document.
62 63 64 |
# File 'lib/dommy/backend.rb', line 62 def empty_document current.empty_document end |
.empty_document_like(doc) ⇒ Object
An empty backing document matching doc's kind (HTML stays HTML, XML stays
XML) — for a shallow document clone, whose result keeps the source flavor.
75 76 77 |
# File 'lib/dommy/backend.rb', line 75 def empty_document_like(doc) current.empty_document_like(doc) end |
.empty_xml_document ⇒ Object
A fresh, empty XML-backed document — for new Document() / createDocument,
which the DOM defines as XML documents (case-preserving, real CDATA
nodeType, namespaces).
69 70 71 |
# File 'lib/dommy/backend.rb', line 69 def empty_xml_document current.empty_xml_document end |
.fragment(html, owner_doc:) ⇒ Object
118 119 120 |
# File 'lib/dommy/backend.rb', line 118 def fragment(html, owner_doc:) current.fragment(html, owner_doc: owner_doc) end |
.get_attribute_ns(node, namespace, local_name) ⇒ Object
Namespaced attribute access (DOM *AttributeNS). namespace is an href
String or nil.
214 215 216 |
# File 'lib/dommy/backend.rb', line 214 def get_attribute_ns(node, namespace, local_name) current.get_attribute_ns(node, namespace, local_name) end |
.has_attribute_ns?(node, namespace, local_name) ⇒ Boolean
226 227 228 |
# File 'lib/dommy/backend.rb', line 226 def has_attribute_ns?(node, namespace, local_name) current.has_attribute_ns?(node, namespace, local_name) end |
.identity_key(node) ⇒ Object
Stable per-document identity key for a backend node, used to cache DOM wrappers and key per-node side tables. Makiri mints a fresh wrapper per traversal but never frees nodes (arena-owned), so it keys on the stable node pointer.
46 47 48 |
# File 'lib/dommy/backend.rb', line 46 def identity_key(node) current.identity_key(node) end |
.internal_subset(doc) ⇒ Object
The parsed document's DocumentType node, or nil when it declares none.
152 153 154 |
# File 'lib/dommy/backend.rb', line 152 def internal_subset(doc) current.respond_to?(:internal_subset) ? current.internal_subset(doc) : nil end |
.moves_nodes_across_documents? ⇒ Boolean
Whether the backend can move a node between documents in place or must adopt a copy first (Lexbor's arenas can't move a node, so inserting a foreign node requires importing it). Lets callers skip a needless — and on an empty target, root-less and therefore crashing — adoption on backends that don't need it.
91 92 93 |
# File 'lib/dommy/backend.rb', line 91 def moves_nodes_across_documents? current.respond_to?(:moves_nodes_across_documents?) ? current.moves_nodes_across_documents? : true end |
.namespace_definitions(node) ⇒ Object
The element's in-scope namespace declarations (each responds to
prefix/href). Empty on backends without an XML namespace model.
197 198 199 |
# File 'lib/dommy/backend.rb', line 197 def namespace_definitions(node) current.namespace_definitions(node) end |
.namespace_of(node) ⇒ Object
191 192 193 |
# File 'lib/dommy/backend.rb', line 191 def namespace_of(node) current.namespace_of(node) end |
.node_class ⇒ Object
264 265 266 |
# File 'lib/dommy/backend.rb', line 264 def node_class current::Node end |
.parse(html) ⇒ Object
Delegate calls so internal code can use Backend.parse(...).
108 109 110 |
# File 'lib/dommy/backend.rb', line 108 def parse(html) current.parse(html) end |
.parse_xml(xml) ⇒ Object
Parse XML input into an XML document. fall back to the HTML parser.
114 115 116 |
# File 'lib/dommy/backend.rb', line 114 def parse_xml(xml) current.parse_xml(xml) end |
.processing_instruction_class ⇒ Object
187 188 189 |
# File 'lib/dommy/backend.rb', line 187 def processing_instruction_class current.processing_instruction_class end |
.remove_attribute_ns(node, namespace, local_name) ⇒ Object
222 223 224 |
# File 'lib/dommy/backend.rb', line 222 def remove_attribute_ns(node, namespace, local_name) current.remove_attribute_ns(node, namespace, local_name) end |
.select_all(node, selector, scope_node: nil) ⇒ Object
CSS query that honors Dommy's custom pseudo-classes
(:disabled/:enabled/:checked/:scope). Each backend applies its
own mechanism (Lexbor native pseudos plus a
:scope rewrite). scope_node binds :scope to that element.
99 100 101 |
# File 'lib/dommy/backend.rb', line 99 def select_all(node, selector, scope_node: nil) current.select_all(node, selector, scope_node: scope_node) end |
.select_first(node, selector, scope_node: nil) ⇒ Object
103 104 105 |
# File 'lib/dommy/backend.rb', line 103 def select_first(node, selector, scope_node: nil) current.select_first(node, selector, scope_node: scope_node) end |
.set_attribute_ns(node, namespace, prefix, local_name, qualified_name, value) ⇒ Object
218 219 220 |
# File 'lib/dommy/backend.rb', line 218 def set_attribute_ns(node, namespace, prefix, local_name, qualified_name, value) current.set_attribute_ns(node, namespace, prefix, local_name, qualified_name, value) end |
.set_document_root(doc, node) ⇒ Object
Make node the sole document element of doc (used by
DOMImplementation.createDocument). Lexbor-backed documents are seeded with an shell
that must be cleared first.
125 126 127 |
# File 'lib/dommy/backend.rb', line 125 def set_document_root(doc, node) current.set_document_root(doc, node) end |
.template_content_nodes(node) ⇒ Object
The content child nodes of a <template> element. HTML5 parsers model
template contents differently — Lexbor/Makiri in a separate content fragment — so reading them goes
through the backend. Used by the template-content registry's migration.
204 205 206 |
# File 'lib/dommy/backend.rb', line 204 def template_content_nodes(node) current.template_content_nodes(node) end |
.text_class ⇒ Object
252 253 254 |
# File 'lib/dommy/backend.rb', line 252 def text_class current::Text end |
.use(name) ⇒ Object
33 34 35 36 37 38 39 40 41 |
# File 'lib/dommy/backend.rb', line 33 def use(name) @current = case name.to_sym when :makiri require_relative "backend/makiri_adapter" Makiri else raise ArgumentError, "Unknown backend: #{name.inspect}. Use :makiri." end end |