lib/string_doc/meta_node.rb in pakyow-presenter-1.0.0.rc3 vs lib/string_doc/meta_node.rb in pakyow-presenter-1.0.0.rc4
- old
+ new
@@ -9,66 +9,93 @@
class MetaNode
# @api private
attr_reader :doc, :transforms, :internal_nodes
def initialize(nodes)
- nodes.first.parent.replace_node(nodes.first, self)
-
- nodes[1..-1].each do |node|
- # Remove the node, but don't make it appear to have been removed for transforms.
+ # Reparent nodes that belong to the same parent.
+ #
+ nodes.group_by { |node| node.parent }.each_pair do |parent, children|
+ # If the children already belong to a meta node doc, don't reparent them again.
#
- node.remove; node.delete_label(:removed)
+ unless children.first.labeled?(:__meta_node)
+ parent.replace_node(children.first, self)
+ end
+
+ children[1..-1].each do |node|
+ # Remove the node, but don't make it appear to have been removed for transforms.
+ #
+ node.remove(false, false)
+ end
end
nodes.each do |node|
node.set_label(:__meta_node, true)
end
@doc = StringDoc.from_nodes(nodes)
@transforms = { high: [], default: [], low: [] }
- @internal_nodes = nodes.select { |node|
- !node.is_a?(MetaNode) && node.labeled?(:__meta_node)
- }
+ @internal_nodes = nodes.dup
@pipeline = nil
end
# @api private
def initialize_copy(_)
super
- @doc = @doc.dup
+ nodes, internal_nodes = [], []
+ @doc.nodes.each do |current_node|
+ duped_node = current_node.dup
+ nodes << duped_node
+ if @internal_nodes.any? { |current_internal_node| current_internal_node.equal?(current_node) }
+ internal_nodes << duped_node
+ end
+ end
+
+ @doc = StringDoc.from_nodes(nodes)
+
@transforms = @transforms.each_with_object({}) { |(key, value), hash|
hash[key] = value.dup
}
- @internal_nodes = nodes.select { |node|
- !node.is_a?(MetaNode) && node.labeled?(:__meta_node)
- }
+ @internal_nodes = internal_nodes
@pipeline = nil
end
# @api private
def soft_copy
instance = self.class.allocate
- new_doc = @doc.soft_copy
- instance.instance_variable_set(:@doc, new_doc)
+ nodes, internal_nodes = [], []
+ @doc.nodes.each do |current_node|
+ duped_node = current_node.soft_copy
+ nodes << duped_node
+
+ if @internal_nodes.any? { |current_internal_node| current_internal_node.equal?(current_node) }
+ internal_nodes << duped_node
+ end
+ end
+
+ instance.instance_variable_set(:@doc, StringDoc.from_nodes(nodes))
instance.instance_variable_set(:@transforms, @transforms)
- instance.instance_variable_set(:@internal_nodes, new_doc.nodes.select { |node|
- !node.is_a?(MetaNode) && node.labeled?(:__meta_node)
- })
+ instance.instance_variable_set(:@internal_nodes, internal_nodes)
instance.instance_variable_set(:@pipeline, @pipeline.dup)
instance
end
+ def finalize_labels(keep: [])
+ nodes.each do |node|
+ node.finalize_labels(keep: keep)
+ end
+ end
+
def freeze(*)
pipeline
super
end
@@ -126,14 +153,20 @@
def replace(replacement)
internal_nodes.each do |each_node|
each_node.replace(replacement)
end
+
+ @internal_nodes = StringDoc.nodes_from_doc_or_string(replacement)
end
- def remove
- internal_nodes.each(&:remove)
+ def remove(label = true, descend = true)
+ internal_nodes.each do |node|
+ node.remove(label, descend)
+ end
+
+ @internal_nodes = []
end
def text
internal_nodes[0].text
end
@@ -215,12 +248,27 @@
each_node.delete_label(name)
end
end
def each(descend: false, &block)
- internal_nodes.each do |node|
- node.each(descend: descend, &block)
+ return enum_for(:each, descend: descend) unless block_given?
+
+ yield self
+
+ nodes.each do |node|
+ # Yield each node that isn't an internal node (e.g. added before/after).
+ #
+ unless @internal_nodes.any? { |internal_node| internal_node.equal?(node) }
+ case node
+ when MetaNode
+ node.each do |each_meta_node|
+ yield each_meta_node
+ end
+ else
+ yield node
+ end
+ end
end
end
def each_significant_node(type, descend: false, &block)
return enum_for(:each_significant_node, type, descend: descend) unless block_given?
@@ -266,20 +314,26 @@
internal_nodes.each_with_object([]) { |node, collected|
collected.concat(node.find_significant_nodes_with_name(type, name, descend: descend))
}
end
+ def removed?
+ internal_nodes.all?(&:removed?)
+ end
+
# Converts the node to an xml string.
#
def render(output = String.new, context: nil)
if transforms_itself?
__transform(output, context: context)
else
nodes.each do |each_node|
each_node.render(output, context: context)
end
end
+
+ output
end
alias :to_html :render
alias :to_xml :render
# Returns the node as an xml string, without transforming.
@@ -311,19 +365,19 @@
when NilClass
return
when StringDoc
return_value.render(string, context: context); return
when Node, MetaNode
- current = return_value
+ if return_value.removed?
+ return
+ else
+ current = return_value
+ end
else
string << return_value.to_s; return
end
end
- # Don't render if the node was removed during the transform.
- #
- if !current.is_a?(Node) || !current.labeled?(:removed)
- current.render(string, context: context)
- end
+ current.render(string, context: context)
end
end
end