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