Class: Hexp::CssSelector::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/hexp/css_selector/parser.rb

Overview

A parser of CSS selectors

This is a wrapper around the SASS parser. This way we are isolated from changes in SASS. It also makes things easier should we decide to switch to a different parsing library or roll our own parser. We only use a fraction of the functionality of SASS so this might be worth it, although at this point I want to avoid reinventing that wheel.

The classes that make up the parse tree largely mimic the ones from SASS, like CommaSequence, SimpleSequence, Class, Id, etc. By having them in our own namespace however we can easily add Hexp-specific functionality to them.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(selector) ⇒ Parser

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initialize the parser with the selector to parse

Parameters:

  • selector (String)


21
22
23
# File 'lib/hexp/css_selector/parser.rb', line 21

def initialize(selector)
  @selector = selector.freeze
end

Class Method Details

.call(selector) ⇒ Hexp::CssSelector::CommaSequence

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parse a CSS selector in one go

Parameters:

  • selector (String)

Returns:



44
45
46
# File 'lib/hexp/css_selector/parser.rb', line 44

def self.call(selector)
  new(selector).parse
end

Instance Method Details

#parseHexp::CssSelector::CommaSequence

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Parse the selector



30
31
32
33
34
35
36
# File 'lib/hexp/css_selector/parser.rb', line 30

def parse
  CommaSequence.new(
    ::Nokogiri::CSS.parse(@selector).map do |node|
      node.accept(self)
    end
  )
end

#visit_attribute_condition(node) ⇒ Object

href^=“http://”


90
91
92
93
94
# File 'lib/hexp/css_selector/parser.rb', line 90

def visit_attribute_condition(node)
  element, operator, value = node.value
  name = element.value.first
  Attribute.new(name.sub(/^@/, ''), operator, value)
end

#visit_child_selector(node) ⇒ Object

ul > li



85
86
87
# File 'lib/hexp/css_selector/parser.rb', line 85

def visit_child_selector(node)
  raise "not implemented"
end

#visit_class_condition(node) ⇒ Object



76
77
78
# File 'lib/hexp/css_selector/parser.rb', line 76

def visit_class_condition(node)
  Class.new(node.value.first)
end

#visit_conditional_selector(node) ⇒ Object



54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/hexp/css_selector/parser.rb', line 54

def visit_conditional_selector(node)
  head, tail = node.value
  children = [head]
  while tail.type == :COMBINATOR
    head, tail = tail.value
    children << head
  end
  children << tail

  SimpleSequence.new(
    children.map {|child| child.accept(self) }
  )
end

#visit_descendant_selector(node) ⇒ Object



48
49
50
51
52
# File 'lib/hexp/css_selector/parser.rb', line 48

def visit_descendant_selector(node)
  Sequence.new(
    node.value.map {|child| child.accept(self) }
  )
end

#visit_element_name(node) ⇒ Object



68
69
70
71
72
73
74
# File 'lib/hexp/css_selector/parser.rb', line 68

def visit_element_name(node)
  if node.value == ["*"]
    Universal.new
  else
    Element.new(node.value.first)
  end
end

#visit_id(node) ⇒ Object



80
81
82
# File 'lib/hexp/css_selector/parser.rb', line 80

def visit_id(node)
  Id.new(node.value.first.sub(/^#/, ''))
end

#visit_pseudo_selector(node) ⇒ Object

li:first / li:nth-child(3n)



97
98
99
# File 'lib/hexp/css_selector/parser.rb', line 97

def visit_pseudo_selector(node)
  raise "not implemented"
end