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