def initialize(selector, *values) raise ArgumentError, "CSS expression cannot be empty" if selector.empty? @source = "" values = values[0] if values.size == 1 && values[0].is_a?(Array) statement = selector.strip.dup simple_selector(statement, values).each { |name, value| instance_variable_set("@#{name}", value) } @alternates = [] @depends = nil if statement.sub!(/^\s*,\s*/, "") second = Selector.new(statement, values) @alternates << second if alternates = second.instance_variable_get(:@alternates) second.instance_variable_set(:@alternates, []) @alternates.concat alternates end @source << " , " << second.to_s elsif statement.sub!(/^\s*\+\s*/, "") second = next_selector(statement, values) @depends = lambda do |element, first| if element = next_element(element) second.match(element, first) end end @source << " + " << second.to_s elsif statement.sub!(/^\s*~\s*/, "") second = next_selector(statement, values) @depends = lambda do |element, first| matches = [] while element = next_element(element) if subset = second.match(element, first) if first && !subset.empty? matches << subset.first break else matches.concat subset end end end matches.empty? ? nil : matches end @source << " ~ " << second.to_s elsif statement.sub!(/^\s*>\s*/, "") second = next_selector(statement, values) @depends = lambda do |element, first| matches = [] element.children.each do |child| if child.tag? && subset = second.match(child, first) if first && !subset.empty? matches << subset.first break else matches.concat subset end end end matches.empty? ? nil : matches end @source << " > " << second.to_s elsif statement =~ /^\s+\S+/ && statement != selector second = next_selector(statement, values) @depends = lambda do |element, first| matches = [] stack = element.children.reverse while node = stack.pop next unless node.tag? if subset = second.match(node, first) if first && !subset.empty? matches << subset.first break else matches.concat subset end elsif children = node.children stack.concat children.reverse end end matches.empty? ? nil : matches end @source << " " << second.to_s else unless statement.empty? || statement.strip.empty? raise ArgumentError, "Invalid selector: #{statement}" end end end