lib/moxml/node.rb in moxml-0.1.0 vs lib/moxml/node.rb in moxml-0.1.1
- old
+ new
@@ -1,113 +1,133 @@
+# frozen_string_literal: true
+
+require_relative "xml_utils"
+require_relative "node_set"
+
module Moxml
class Node
- attr_reader :native
+ include XmlUtils
- def initialize(native_node = nil)
- @native = native_node || create_native_node
+ attr_reader :native, :context
+
+ def initialize(native, context)
+ @native = native
+ @context = context
end
- def self.wrap(native_node)
- return nil if native_node.nil?
-
- klass = case Moxml.adapter.node_type(native_node)
- when :element then Element
- when :text then Text
- when :cdata then Cdata
- when :comment then Comment
- when :processing_instruction then ProcessingInstruction
- when :document then Document
- when :attribute then Attribute
- when :namespace then Namespace
- else
- raise Error, "Unknown node type: #{native_node.class}"
- end
-
- klass.new(native_node)
+ def document
+ Document.wrap(adapter.document(@native), context)
end
def parent
- wrap_node(adapter.parent(native))
+ Node.wrap(adapter.parent(@native), context)
end
def children
- NodeSet.new(adapter.children(native))
+ NodeSet.new(adapter.children(@native), context)
end
def next_sibling
- wrap_node(adapter.next_sibling(native))
+ Node.wrap(adapter.next_sibling(@native), context)
end
def previous_sibling
- wrap_node(adapter.previous_sibling(native))
+ Node.wrap(adapter.previous_sibling(@native), context)
end
- def remove
- adapter.remove(native)
+ def add_child(node)
+ node = prepare_node(node)
+ adapter.add_child(@native, node.native)
self
end
- def replace(node)
- adapter.replace(native, node.native)
- self
- end
-
def add_previous_sibling(node)
- adapter.add_previous_sibling(native, node.native)
+ node = prepare_node(node)
+ adapter.add_previous_sibling(@native, node.native)
self
end
def add_next_sibling(node)
- adapter.add_next_sibling(native, node.native)
+ node = prepare_node(node)
+ adapter.add_next_sibling(@native, node.native)
self
end
- def text
- adapter.text_content(native)
+ def remove
+ adapter.remove(@native)
+ self
end
- def text=(content)
- adapter.set_text_content(native, content)
+ def replace(node)
+ node = prepare_node(node)
+ adapter.replace(@native, node.native)
self
end
- def inner_html
- adapter.inner_html(native)
+ def to_xml(options = {})
+ adapter.serialize(@native, default_options.merge(options))
end
- def inner_html=(html)
- adapter.set_inner_html(native, html)
+ def xpath(expression, namespaces = {})
+ NodeSet.new(adapter.xpath(@native, expression, namespaces), context)
end
- def outer_html
- adapter.outer_html(native)
+ def at_xpath(expression, namespaces = {})
+ Node.wrap(adapter.at_xpath(@native, expression, namespaces), context)
end
- def path
- adapter.path(native)
+ def ==(other)
+ self.class == other.class && @native == other.native
end
- def line
- adapter.line(native)
- end
+ def self.wrap(node, context)
+ return nil if node.nil?
- def column
- adapter.column(native)
+ klass = case adapter(context).node_type(node)
+ when :element then Element
+ when :text then Text
+ when :cdata then Cdata
+ when :comment then Comment
+ when :processing_instruction then ProcessingInstruction
+ when :document then Document
+ when :declaration then Declaration
+ when :doctype then Doctype
+ else self
+ end
+
+ klass.new(node, context)
end
protected
- def wrap_node(native_node)
- self.class.wrap(native_node)
+ def adapter
+ context.config.adapter
end
+ def self.adapter(context)
+ context.config.adapter
+ end
+
private
- def adapter
- Moxml.adapter
+ def prepare_node(node)
+ case node
+ when String then Text.new(adapter.create_text(node), context)
+ when Node then node
+ else
+ raise ArgumentError, "Invalid node type: #{node.class}"
+ end
end
- def create_native_node
- raise NotImplementedError, "Subclasses must implement create_native_node"
+ def default_options
+ {
+ encoding: context.config.default_encoding,
+ indent: context.config.default_indent,
+ # The short format of empty tags in Oga and Nokogiri isn't configurable
+ # Oga: <empty /> (with a space)
+ # Nokogiri: <empty/> (without a space)
+ # The expanded format is enforced to avoid this conflict
+ expand_empty: true
+ }
end
end
end