lib/wunderbar/node.rb in wunderbar-0.23.2 vs lib/wunderbar/node.rb in wunderbar-0.24.0

- old
+ new

@@ -144,10 +144,102 @@ end def preserve_spaces? false end + + def root + if parent + parent.root + else + self + end + end + + def search(css) + css = Node.parse_css_selector(css) if String === css + + matches = [] + if children + children.each { |child| matches += child.search(css) if Node === child } + end + + pattern = css.first + + if pattern[:id] + return matches unless attrs and attrs[:id] == pattern[:id] + end + + if pattern[:class] + names = attrs ? attrs[:class].to_s.split(' ') : [] + return matches unless pattern[:class].all? {|name| names.include? name} + end + + if pattern[:name] + return matches unless name == pattern[:name] + end + + if pattern[:attr] + return matches unless attrs and pattern[:attr].all? do |k1, v1| + attrs.any? {|k2, v2| k1.to_s == k2.to_s and v1.to_s == v2.to_s} + end + end + + if css.length == 1 + matches << self + else + matches += search(css[1..-1]) + end + end + + def at(css) + search(css).first + end + + # parse a subset of css_selectors + def self.parse_css_selector(css) + if css.include? ' ' + css.split(/\s+/).map {|token| parse_css_selector(token).first} + else + result = {} + while css != '' + if css =~/^([-\w]+)/ + result[:name] = $1 + css=css[$1.length..-1] + elsif css =~/^#([-\w]+)/ + raise ArgumentError("duplicate id") if result[:id] + result[:id] = $1 + css=css[$1.length+1..-1] + elsif css =~/^\.([-\w]+)/ + result[:class] ||= [] + raise ArgumentError("duplicate class") if result[:class].include? $1 + result[:class] << $1 + css=css[$1.length+1..-1] + elsif css =~/^\[([-\w]+)=([-\w]+)\]/ + result[:attr] ||= {} + raise ArgumentError("duplicate attribute") if result[:attr][$1] + result[:attr][$1] = $2 + css=css[$1.length+$2.length+3..-1] + elsif css =~/^\[([-\w]+)='([^']+)'\]/ + result[:attr] ||= {} + raise ArgumentError("duplicate attribute") if result[:attr][$1] + result[:attr][$1] = $2 + css=css[$1.length+$2.length+5..-1] + elsif css =~/^\[([-\w]+)="([^"]+)"\]/ + result[:attr] ||= {} + raise ArgumentError("duplicate attribute") if result[:attr][$1] + result[:attr][$1] = $2 + css=css[$1.length+$2.length+5..-1] + elsif css =~/^\*/ + css=css[1..-1] + else + raise ArgumentError("syntax error: #{css.inspect}") + end + end + [result] + end + end end class CommentNode < Node def initialize(text) @text = text @@ -158,10 +250,12 @@ result end end class DocTypeNode < Node + attr_accessor :declare + def initialize(*args) @declare = args.shift @name = args.shift end @@ -264,7 +358,6 @@ end module CompactNode; end module SpacedNode; end - end