Reliably remove nodes from owned sets.

The combination of iterating over an array and removing values from it results
in not all elements being removed. For example:

    numbers = [10, 20, 30]

    numbers.each do |num|
      numbers.delete(num)
    end

    numbers # => [20]

As a result of this the NodeSet#remove method uses two iterations:

1. One iteration to retrieve all NodeSet instances to remove nodes from.
2. One iteration to actually remove the nodes.

For the second iteration we iterate over the node sets and then over the nodes.
This ensures that we always remove all nodes instead of leaving some behind.
This commit is contained in:
Yorick Peterse 2014-07-01 09:57:43 +02:00
parent 5073056831
commit 30845e3d65
2 changed files with 20 additions and 2 deletions

View File

@ -166,9 +166,21 @@ module Oga
# This method is intended to remove nodes from an XML document/node.
#
def remove
sets = []
# First we gather all the sets to remove nodse from, then we remove the
# actual nodes. This is done as you can not reliably remove elements
# from an Array while iterating on that same Array.
@nodes.each do |node|
node.node_set.delete(node)
node.node_set = nil
if node.node_set
sets << node.node_set
node.node_set = nil
end
end
sets.each do |set|
@nodes.each { |node| set.delete(node) }
end
end

View File

@ -213,6 +213,12 @@ describe Oga::XML::NodeSet do
@n1.node_set.nil?.should == true
@n2.node_set.nil?.should == true
end
example 'remove all nodes from the owned set' do
@doc_set.remove
@doc_set.empty?.should == true
end
end
context '#delete' do