# File actionpack/lib/action_controller/vendor/html-scanner/html/selector.rb, line 239def initialize(selector,*values)raiseArgumentError,"CSS expression cannot be empty"ifselector.empty?@source=""values=values[0]ifvalues.size==1&&values[0].is_a?(Array)# We need a copy to determine if we failed to parse, and also# preserve the original pass by-ref statement.statement=selector.strip.dup# Create a simple selector, along with negation.simple_selector(statement,values).each{|name,value|instance_variable_set("@#{name}",value)}@alternates=[]@depends=nil# Alternative selector.ifstatement.sub!(/^\s*,\s*/,"")second=Selector.new(statement,values)@alternates<<second# If there are alternate selectors, we group them in the top selector.ifalternates=second.instance_variable_get(:@alternates)second.instance_variable_set(:@alternates,[])@alternates.concatalternatesend@source<<" , "<<second.to_s# Sibling selector: create a dependency into second selector that will# match element immediately following this one.elsifstatement.sub!(/^\s*\+\s*/,"")second=next_selector(statement,values)@depends=lambdado|element,first|ifelement=next_element(element)second.match(element,first)endend@source<<" + "<<second.to_s# Adjacent selector: create a dependency into second selector that will# match all elements following this one.elsifstatement.sub!(/^\s*~\s*/,"")second=next_selector(statement,values)@depends=lambdado|element,first|matches=[]whileelement=next_element(element)ifsubset=second.match(element,first)iffirst&&!subset.empty?matches<<subset.firstbreakelsematches.concatsubsetendendendmatches.empty??nil:matchesend@source<<" ~ "<<second.to_s# Child selector: create a dependency into second selector that will# match a child element of this one.elsifstatement.sub!(/^\s*>\s*/,"")second=next_selector(statement,values)@depends=lambdado|element,first|matches=[]element.children.eachdo|child|ifchild.tag?&&subset=second.match(child,first)iffirst&&!subset.empty?matches<<subset.firstbreakelsematches.concatsubsetendendendmatches.empty??nil:matchesend@source<<" > "<<second.to_s# Descendant selector: create a dependency into second selector that# will match all descendant elements of this one. Note,elsifstatement=~/^\s+\S+/&&statement!=selectorsecond=next_selector(statement,values)@depends=lambdado|element,first|matches=[]stack=element.children.reversewhilenode=stack.popnextunlessnode.tag?ifsubset=second.match(node,first)iffirst&&!subset.empty?matches<<subset.firstbreakelsematches.concatsubsetendelsifchildren=node.childrenstack.concatchildren.reverseendendmatches.empty??nil:matchesend@source<<""<<second.to_selse# The last selector is where we check that we parsed# all the parts.unlessstatement.empty?||statement.strip.empty?raiseArgumentError,"Invalid selector: #{statement}"endendend