在地图迭代期间从NodeSet中删除?

时间:2014-01-24 18:56:20

标签: ruby nokogiri

在迭代期间从NodeSet中删除节点是否安全?我从一堆标签中拉出一些链接但是如果链接无效则想要从集合中删除标签。

def get_links(nodeset)
  links = nodeset.map do |node|
    begin
      URI.join(node.document.url, node.get_attribute('href'))
    rescue URI::InvalidURIError
      nodeset.delete(node) # Is this safe?
      nil
    end
  end
  links.compact
end

1 个答案:

答案 0 :(得分:1)

在您的示例代码中,我认为您并没有很好地分离您的行为。不要操纵nodeset内的map数组;并不是因为不能这样做,而是不应以保持清晰和易于维护。将地图“分开”与删除不良网址分开。

至少我会做更多的事情:

def get_valid_links(nodeset)
  doc_url = nodeset.first.document.url
  links = nodeset.map { |node|
    begin
      URI.join(doc_url, node['href'])
    rescue URI::InvalidURIError
      nil
    end
  end
  links.compact
end

nodeset = get_valid_links(nodeset)

这样做不会改变nodeset,除非您明确说明,通过分配从get_links返回的压缩/映射值。这使得该方法的目的非常明确,并且没有副作用。

我认为这是“POLS”(“最小惊喜原则”)会起作用的案例之一。在方法中隐藏nodeset的副作用可以对于那些试图维护代码或在库中使用它的人来说,这是非常令人惊讶的,并且很难解决。

根据经验,我建议您非常小心地将href属性的内容放到URL的末尾,并期望它是好的或有用的。请记住,href可能是一个JavaScript链接,这会产生一个丑陋的网址。