class StringDoc::Node

String-based XML node.

@api private

Constants

FORM_INPUTS
REGEX_TAGS
SELF_CLOSING
VALUELESS

Attributes

attributes[R]
children[R]

@api private

node[R]

@api private

parent[RW]

@api private

significance[R]

@api private

tag_close[R]

@api private

tag_open_end[R]

@api private

tag_open_start[R]

@api private

transforms[R]

@api private

Public Class Methods

form_input?(tag) click to toggle source

Returns true if tag is a form input.

# File lib/string_doc/node.rb, line 24
def form_input?(tag)
  FORM_INPUTS.include?(tag)
end
new(tag_open_start = "", attributes = Attributes.new, tag_open_end = "", children = StringDoc.empty, tag_close = "", parent: nil, significance: [], labels: {}) click to toggle source
# File lib/string_doc/node.rb, line 48
def initialize(tag_open_start = "", attributes = Attributes.new, tag_open_end = "", children = StringDoc.empty, tag_close = "", parent: nil, significance: [], labels: {})
  @tag_open_start, @attributes, @tag_open_end, @children, @tag_close = tag_open_start, attributes, tag_open_end, children, tag_close
  @parent, @labels, @significance = parent, labels, significance
  @transforms = { high: [], default: [], low: [] }
  @pipeline = nil
  @finalized_labels = {}
end
self_closing?(tag) click to toggle source

Returns true if tag is self-closing.

# File lib/string_doc/node.rb, line 18
def self_closing?(tag)
  SELF_CLOSING.include?(tag)
end
without_value?(tag) click to toggle source

Returns true if tag does not contain a value.

# File lib/string_doc/node.rb, line 30
def without_value?(tag)
  VALUELESS.include?(tag)
end

Public Instance Methods

==(other) click to toggle source
# File lib/string_doc/node.rb, line 314
def ==(other)
  other.is_a?(Node) &&
    @tag_open_start == other.tag_open_start &&
    @attributes == other.attributes &&
    @tag_open_end == other.tag_open_end &&
    @children == other.children &&
    @tag_close == other.tag_close
end
after(node) click to toggle source

Inserts node after self.

# File lib/string_doc/node.rb, line 220
def after(node)
  @parent.insert_after(node, self)
end
append(node) click to toggle source

Appends node as a child.

# File lib/string_doc/node.rb, line 232
def append(node)
  children.append(node)
end
append_html(html) click to toggle source

Appends html as a child.

# File lib/string_doc/node.rb, line 238
def append_html(html)
  children.append_html(html)
end
before(node) click to toggle source

Inserts node before self.

# File lib/string_doc/node.rb, line 226
def before(node)
  @parent.insert_before(node, self)
end
clear() click to toggle source

Removes all children.

# File lib/string_doc/node.rb, line 214
def clear
  children.clear
end
close(tag, child) click to toggle source

Close self with tag and a child.

@api private

# File lib/string_doc/node.rb, line 121
def close(tag, child)
  tap do
    @children = StringDoc.from_nodes(child)
    @tag_open_end = tag ? ">" : ""
    @tag_close = (tag && !self.class.self_closing?(tag)) ? "</#{tag}>" : ""
  end
end
delete_label(name) click to toggle source

Delete the label with name.

# File lib/string_doc/node.rb, line 277
def delete_label(name)
  @labels.delete(name.to_sym)
end
each(descend: false) { |self| ... } click to toggle source
# File lib/string_doc/node.rb, line 323
def each(descend: false)
  return enum_for(:each, descend: descend) unless block_given?
  yield self
end
each_significant_node(type, descend: false, &block) click to toggle source
# File lib/string_doc/node.rb, line 328
def each_significant_node(type, descend: false, &block)
  return enum_for(:each_significant_node, type, descend: descend) unless block_given?

  if @children.is_a?(StringDoc)
    @children.each_significant_node(type, descend: descend, &block)
  end
end
each_significant_node_with_name(type, name, descend: false, &block) click to toggle source
# File lib/string_doc/node.rb, line 344
def each_significant_node_with_name(type, name, descend: false, &block)
  return enum_for(:each_significant_node_with_name, type, name, descend: descend) unless block_given?

  if @children.is_a?(StringDoc)
    @children.each_significant_node_with_name(type, name, descend: descend, &block)
  end
end
each_significant_node_without_descending_into_type(type, descend: false, &block) click to toggle source
# File lib/string_doc/node.rb, line 336
def each_significant_node_without_descending_into_type(type, descend: false, &block)
  return enum_for(:each_significant_node_without_descending_into_type, type, descend: descend) unless block_given?

  if @children.is_a?(StringDoc)
    @children.each_significant_node_without_descending_into_type(type, descend: descend, &block)
  end
end
empty?() click to toggle source

@api private

# File lib/string_doc/node.rb, line 114
def empty?
  to_s.strip.empty?
end
finalize_labels(keep: []) click to toggle source
# File lib/string_doc/node.rb, line 93
def finalize_labels(keep: [])
  @finalized_labels = @labels
  @labels = keep.each_with_object({}) { |key, hash|
    hash[key] = @finalized_labels.delete(key).deep_dup
  }

  if children.is_a?(StringDoc)
    children.finalize_labels(keep: keep)
  end
end
find_first_significant_node(type, descend: false) click to toggle source
# File lib/string_doc/node.rb, line 352
def find_first_significant_node(type, descend: false)
  if @children.is_a?(StringDoc)
    @children.find_first_significant_node(type, descend: descend)
  else
    nil
  end
end
find_significant_nodes(type, descend: false) click to toggle source
# File lib/string_doc/node.rb, line 360
def find_significant_nodes(type, descend: false)
  if @children.is_a?(StringDoc)
    @children.find_significant_nodes(type, descend: descend)
  else
    []
  end
end
find_significant_nodes_with_name(type, name, descend: false) click to toggle source
# File lib/string_doc/node.rb, line 368
def find_significant_nodes_with_name(type, name, descend: false)
  if @children.is_a?(StringDoc)
    @children.find_significant_nodes_with_name(type, name, descend: descend)
  else
    []
  end
end
freeze(*) click to toggle source
Calls superclass method
# File lib/string_doc/node.rb, line 108
def freeze(*)
  pipeline
  super
end
html() click to toggle source

Returns the html contained within self.

# File lib/string_doc/node.rb, line 190
def html
  children.to_s
end
html=(html) click to toggle source

Replaces self's inner html, without making it available for further manipulation.

# File lib/string_doc/node.rb, line 196
def html=(html)
  @children = html.to_s
end
initialize_copy(_) click to toggle source

@api private

Calls superclass method
# File lib/string_doc/node.rb, line 57
def initialize_copy(_)
  super

  @labels = @labels.deep_dup
  @finalized_labels = @finalized_labels.deep_dup
  @attributes = @attributes.dup
  @children = @children.dup
  @significance = @significance.dup

  @transforms = @transforms.each_with_object({}) { |(key, value), hash|
    hash[key] = value.dup
  }

  @pipeline = nil
end
label(name) click to toggle source

Returns the value for label with name.

# File lib/string_doc/node.rb, line 250
def label(name)
  name = name.to_sym
  if @labels.key?(name)
    @labels[name.to_sym]
  else
    @finalized_labels[name.to_sym]
  end
end
labeled?(name) click to toggle source

Returns true if label exists with name.

# File lib/string_doc/node.rb, line 261
def labeled?(name)
  @labels.key?(name.to_sym) || @finalized_labels.key?(name.to_sym)
end
labels() click to toggle source
# File lib/string_doc/node.rb, line 104
def labels
  @labels.merge(@finalized_labels)
end
next_transform() click to toggle source
# File lib/string_doc/node.rb, line 129
def next_transform
  pipeline.shift
end
prepend(node) click to toggle source

Prepends node as a child.

# File lib/string_doc/node.rb, line 244
def prepend(node)
  children.prepend(node)
end
remove(label = true, descend = true) click to toggle source

Removes the node.

# File lib/string_doc/node.rb, line 166
def remove(label = true, descend = true)
  if label
    set_label(:removed, true)
  end

  @parent.remove_node(self)

  if descend && children.is_a?(StringDoc)
    children.each do |child|
      child.remove(label, descend)
    end
  end
end
removed?() click to toggle source
# File lib/string_doc/node.rb, line 271
def removed?
  labeled?(:removed)
end
render(output = String.new, context: nil) click to toggle source
# File lib/string_doc/node.rb, line 281
def render(output = String.new, context: nil)
  if transforms_itself?
    __transform(output, context: context)
  else
    output << tag_open_start

    attributes.each_string do |attribute_string|
      output << attribute_string
    end

    output << tag_open_end

    case children
    when StringDoc
      children.render(output, context: context)
    else
      output << children.to_s
    end

    output << tag_close
  end

  output
end
Also aliased as: to_html, to_xml
replace(replacement) click to toggle source

Replaces the current node.

# File lib/string_doc/node.rb, line 160
def replace(replacement)
  @parent.replace_node(self, replacement)
end
replace_children(children) click to toggle source

Replaces self's children.

# File lib/string_doc/node.rb, line 202
def replace_children(children)
  @children.replace(children)
end
set_label(name, value) click to toggle source

Sets the label with name and value.

# File lib/string_doc/node.rb, line 267
def set_label(name, value)
  @labels[name.to_sym] = value
end
significance?(*types) click to toggle source
# File lib/string_doc/node.rb, line 154
def significance?(*types)
  (@significance & types).any?
end
significant?(type = nil) click to toggle source
# File lib/string_doc/node.rb, line 146
def significant?(type = nil)
  if type
    @significance.include?(type.to_sym)
  else
    @significance.any?
  end
end
soft_copy() click to toggle source

@api private

# File lib/string_doc/node.rb, line 74
def soft_copy
  instance = self.class.allocate

  instance.instance_variable_set(:@tag_open_start, @tag_open_start)
  instance.instance_variable_set(:@tag_open_end, @tag_open_end)
  instance.instance_variable_set(:@tag_close, @tag_close)
  instance.instance_variable_set(:@parent, @parent)
  instance.instance_variable_set(:@significance, @significance)
  instance.instance_variable_set(:@transforms, @transforms)
  instance.instance_variable_set(:@finalized_labels, @finalized_labels)

  instance.instance_variable_set(:@attributes, @attributes.dup)
  instance.instance_variable_set(:@children, @children.is_a?(StringDoc) ? @children.soft_copy : @children.dup)
  instance.instance_variable_set(:@labels, @labels.deep_dup)
  instance.instance_variable_set(:@pipeline, @pipeline.dup)

  instance
end
tagname() click to toggle source

Returns the node's tagname.

# File lib/string_doc/node.rb, line 208
def tagname
  @tag_open_start.gsub(/[^a-zA-Z0-9]/, "")
end
text() click to toggle source

Returns the text of this node and all children, joined together.

# File lib/string_doc/node.rb, line 184
def text
  html.gsub(REGEX_TAGS, "")
end
to_html(output = String.new, context: nil)
Alias for: render
to_s() click to toggle source

Returns the node as an xml string, without transforming.

# File lib/string_doc/node.rb, line 310
def to_s
  string_nodes.flatten.map(&:to_s).join
end
to_xml(output = String.new, context: nil)
Alias for: render
transform(priority: :default, &block) click to toggle source
# File lib/string_doc/node.rb, line 133
def transform(priority: :default, &block)
  @transforms[priority] << block
  @pipeline = nil
end
transforms?() click to toggle source
# File lib/string_doc/node.rb, line 138
def transforms?
  transforms_itself? || @children.transforms?
end
transforms_itself?() click to toggle source
# File lib/string_doc/node.rb, line 142
def transforms_itself?
  pipeline.any?
end

Private Instance Methods

__transform(string, context:) click to toggle source
# File lib/string_doc/node.rb, line 382
def __transform(string, context:)
  node = if frozen?
    soft_copy
  else
    self
  end

  current = node
  while transform = node.next_transform
    return_value = transform.call(node, context, string)

    case return_value
    when NilClass
      return
    when StringDoc
      return_value.render(string, context: context); return
    when Node, MetaNode
      if return_value.removed?
        return
      else
        current = return_value
      end
    else
      string << return_value.to_s; return
    end
  end

  current.render(string, context: context)
end
pipeline() click to toggle source
# File lib/string_doc/node.rb, line 378
def pipeline
  @pipeline ||= @transforms.values.flatten
end
string_nodes() click to toggle source
# File lib/string_doc/node.rb, line 412
def string_nodes
  [@tag_open_start, @attributes, @tag_open_end, @children, @tag_close]
end