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