nokogiri 1.1.1-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of nokogiri might be problematic. Click here for more details.

Files changed (142) hide show
  1. data/History.ja.txt +99 -0
  2. data/History.txt +99 -0
  3. data/Manifest.txt +141 -0
  4. data/README.ja.txt +100 -0
  5. data/README.txt +109 -0
  6. data/Rakefile +354 -0
  7. data/ext/nokogiri/extconf.rb +93 -0
  8. data/ext/nokogiri/html_document.c +86 -0
  9. data/ext/nokogiri/html_document.h +10 -0
  10. data/ext/nokogiri/html_sax_parser.c +36 -0
  11. data/ext/nokogiri/html_sax_parser.h +11 -0
  12. data/ext/nokogiri/native.c +41 -0
  13. data/ext/nokogiri/native.h +50 -0
  14. data/ext/nokogiri/xml_cdata.c +44 -0
  15. data/ext/nokogiri/xml_cdata.h +9 -0
  16. data/ext/nokogiri/xml_comment.c +42 -0
  17. data/ext/nokogiri/xml_comment.h +9 -0
  18. data/ext/nokogiri/xml_document.c +206 -0
  19. data/ext/nokogiri/xml_document.h +10 -0
  20. data/ext/nokogiri/xml_dtd.c +121 -0
  21. data/ext/nokogiri/xml_dtd.h +8 -0
  22. data/ext/nokogiri/xml_io.c +17 -0
  23. data/ext/nokogiri/xml_io.h +9 -0
  24. data/ext/nokogiri/xml_node.c +727 -0
  25. data/ext/nokogiri/xml_node.h +13 -0
  26. data/ext/nokogiri/xml_node_set.c +118 -0
  27. data/ext/nokogiri/xml_node_set.h +9 -0
  28. data/ext/nokogiri/xml_reader.c +465 -0
  29. data/ext/nokogiri/xml_reader.h +10 -0
  30. data/ext/nokogiri/xml_sax_parser.c +201 -0
  31. data/ext/nokogiri/xml_sax_parser.h +10 -0
  32. data/ext/nokogiri/xml_syntax_error.c +199 -0
  33. data/ext/nokogiri/xml_syntax_error.h +11 -0
  34. data/ext/nokogiri/xml_text.c +40 -0
  35. data/ext/nokogiri/xml_text.h +9 -0
  36. data/ext/nokogiri/xml_xpath.c +53 -0
  37. data/ext/nokogiri/xml_xpath.h +11 -0
  38. data/ext/nokogiri/xml_xpath_context.c +214 -0
  39. data/ext/nokogiri/xml_xpath_context.h +9 -0
  40. data/ext/nokogiri/xslt_stylesheet.c +123 -0
  41. data/ext/nokogiri/xslt_stylesheet.h +9 -0
  42. data/lib/action-nokogiri.rb +30 -0
  43. data/lib/nokogiri.rb +72 -0
  44. data/lib/nokogiri/css.rb +25 -0
  45. data/lib/nokogiri/css/generated_parser.rb +721 -0
  46. data/lib/nokogiri/css/generated_tokenizer.rb +159 -0
  47. data/lib/nokogiri/css/node.rb +97 -0
  48. data/lib/nokogiri/css/parser.rb +64 -0
  49. data/lib/nokogiri/css/parser.y +216 -0
  50. data/lib/nokogiri/css/syntax_error.rb +6 -0
  51. data/lib/nokogiri/css/tokenizer.rb +9 -0
  52. data/lib/nokogiri/css/tokenizer.rex +63 -0
  53. data/lib/nokogiri/css/xpath_visitor.rb +168 -0
  54. data/lib/nokogiri/decorators.rb +2 -0
  55. data/lib/nokogiri/decorators/hpricot.rb +3 -0
  56. data/lib/nokogiri/decorators/hpricot/node.rb +56 -0
  57. data/lib/nokogiri/decorators/hpricot/node_set.rb +54 -0
  58. data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +28 -0
  59. data/lib/nokogiri/decorators/slop.rb +31 -0
  60. data/lib/nokogiri/hpricot.rb +51 -0
  61. data/lib/nokogiri/html.rb +105 -0
  62. data/lib/nokogiri/html/builder.rb +9 -0
  63. data/lib/nokogiri/html/document.rb +9 -0
  64. data/lib/nokogiri/html/sax/parser.rb +21 -0
  65. data/lib/nokogiri/version.rb +3 -0
  66. data/lib/nokogiri/xml.rb +83 -0
  67. data/lib/nokogiri/xml/after_handler.rb +18 -0
  68. data/lib/nokogiri/xml/attr.rb +10 -0
  69. data/lib/nokogiri/xml/before_handler.rb +33 -0
  70. data/lib/nokogiri/xml/builder.rb +84 -0
  71. data/lib/nokogiri/xml/cdata.rb +9 -0
  72. data/lib/nokogiri/xml/comment.rb +6 -0
  73. data/lib/nokogiri/xml/document.rb +55 -0
  74. data/lib/nokogiri/xml/dtd.rb +6 -0
  75. data/lib/nokogiri/xml/element.rb +6 -0
  76. data/lib/nokogiri/xml/entity_declaration.rb +9 -0
  77. data/lib/nokogiri/xml/node.rb +333 -0
  78. data/lib/nokogiri/xml/node_set.rb +197 -0
  79. data/lib/nokogiri/xml/notation.rb +6 -0
  80. data/lib/nokogiri/xml/reader.rb +20 -0
  81. data/lib/nokogiri/xml/sax.rb +9 -0
  82. data/lib/nokogiri/xml/sax/document.rb +59 -0
  83. data/lib/nokogiri/xml/sax/parser.rb +37 -0
  84. data/lib/nokogiri/xml/syntax_error.rb +21 -0
  85. data/lib/nokogiri/xml/text.rb +6 -0
  86. data/lib/nokogiri/xml/xpath.rb +10 -0
  87. data/lib/nokogiri/xml/xpath/syntax_error.rb +8 -0
  88. data/lib/nokogiri/xml/xpath_context.rb +14 -0
  89. data/lib/nokogiri/xslt.rb +28 -0
  90. data/lib/nokogiri/xslt/stylesheet.rb +6 -0
  91. data/test/css/test_nthiness.rb +159 -0
  92. data/test/css/test_parser.rb +237 -0
  93. data/test/css/test_tokenizer.rb +162 -0
  94. data/test/css/test_xpath_visitor.rb +64 -0
  95. data/test/files/dont_hurt_em_why.xml +422 -0
  96. data/test/files/exslt.xml +8 -0
  97. data/test/files/exslt.xslt +35 -0
  98. data/test/files/staff.xml +59 -0
  99. data/test/files/staff.xslt +32 -0
  100. data/test/files/tlm.html +850 -0
  101. data/test/helper.rb +78 -0
  102. data/test/hpricot/files/basic.xhtml +17 -0
  103. data/test/hpricot/files/boingboing.html +2266 -0
  104. data/test/hpricot/files/cy0.html +3653 -0
  105. data/test/hpricot/files/immob.html +400 -0
  106. data/test/hpricot/files/pace_application.html +1320 -0
  107. data/test/hpricot/files/tenderlove.html +16 -0
  108. data/test/hpricot/files/uswebgen.html +220 -0
  109. data/test/hpricot/files/utf8.html +1054 -0
  110. data/test/hpricot/files/week9.html +1723 -0
  111. data/test/hpricot/files/why.xml +19 -0
  112. data/test/hpricot/load_files.rb +11 -0
  113. data/test/hpricot/test_alter.rb +67 -0
  114. data/test/hpricot/test_builder.rb +27 -0
  115. data/test/hpricot/test_parser.rb +426 -0
  116. data/test/hpricot/test_paths.rb +15 -0
  117. data/test/hpricot/test_preserved.rb +77 -0
  118. data/test/hpricot/test_xml.rb +30 -0
  119. data/test/html/sax/test_parser.rb +27 -0
  120. data/test/html/test_builder.rb +89 -0
  121. data/test/html/test_document.rb +150 -0
  122. data/test/html/test_node.rb +21 -0
  123. data/test/test_convert_xpath.rb +185 -0
  124. data/test/test_css_cache.rb +57 -0
  125. data/test/test_gc.rb +15 -0
  126. data/test/test_memory_leak.rb +38 -0
  127. data/test/test_nokogiri.rb +97 -0
  128. data/test/test_reader.rb +222 -0
  129. data/test/test_xslt_transforms.rb +93 -0
  130. data/test/xml/sax/test_parser.rb +95 -0
  131. data/test/xml/test_attr.rb +15 -0
  132. data/test/xml/test_builder.rb +16 -0
  133. data/test/xml/test_cdata.rb +18 -0
  134. data/test/xml/test_comment.rb +16 -0
  135. data/test/xml/test_document.rb +195 -0
  136. data/test/xml/test_dtd.rb +43 -0
  137. data/test/xml/test_node.rb +394 -0
  138. data/test/xml/test_node_set.rb +143 -0
  139. data/test/xml/test_text.rb +13 -0
  140. data/test/xml/test_xpath.rb +105 -0
  141. data/vendor/hoe.rb +1020 -0
  142. metadata +233 -0
@@ -0,0 +1,159 @@
1
+ #
2
+ # DO NOT MODIFY!!!!
3
+ # This file is automatically generated by rex 1.0.1
4
+ # from lexical definition file "lib/nokogiri/css/tokenizer.rex".
5
+ #
6
+
7
+ module Nokogiri
8
+ module CSS
9
+ class GeneratedTokenizer < GeneratedParser
10
+ require 'strscan'
11
+
12
+ class ScanError < StandardError ; end
13
+
14
+ attr_reader :lineno
15
+ attr_reader :filename
16
+
17
+ def scan_setup ; end
18
+
19
+ def action &block
20
+ yield
21
+ end
22
+
23
+ def scan_str( str )
24
+ scan_evaluate str
25
+ do_parse
26
+ end
27
+
28
+ def load_file( filename )
29
+ @filename = filename
30
+ open(filename, "r") do |f|
31
+ scan_evaluate f.read
32
+ end
33
+ end
34
+
35
+ def scan_file( filename )
36
+ load_file filename
37
+ do_parse
38
+ end
39
+
40
+ def next_token
41
+ @rex_tokens.shift
42
+ end
43
+
44
+ def scan_evaluate( str )
45
+ scan_setup
46
+ @rex_tokens = []
47
+ @lineno = 1
48
+ ss = StringScanner.new(str)
49
+ state = nil
50
+ until ss.eos?
51
+ text = ss.peek(1)
52
+ @lineno += 1 if text == "\n"
53
+ case state
54
+ when nil
55
+ case
56
+ when (text = ss.scan(/~=/i))
57
+ @rex_tokens.push action { [:INCLUDES, text] }
58
+
59
+ when (text = ss.scan(/\|=/i))
60
+ @rex_tokens.push action { [:DASHMATCH, text] }
61
+
62
+ when (text = ss.scan(/\^=/i))
63
+ @rex_tokens.push action { [:PREFIXMATCH, text] }
64
+
65
+ when (text = ss.scan(/\$=/i))
66
+ @rex_tokens.push action { [:SUFFIXMATCH, text] }
67
+
68
+ when (text = ss.scan(/\*=/i))
69
+ @rex_tokens.push action { [:SUBSTRINGMATCH, text] }
70
+
71
+ when (text = ss.scan(/!=/i))
72
+ @rex_tokens.push action { [:NOT_EQUAL, text] }
73
+
74
+ when (text = ss.scan(/[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*\(\s*/i))
75
+ @rex_tokens.push action { [:FUNCTION, text] }
76
+
77
+ when (text = ss.scan(/@[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
78
+ @rex_tokens.push action { [:IDENT, text] }
79
+
80
+ when (text = ss.scan(/[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
81
+ @rex_tokens.push action { [:IDENT, text] }
82
+
83
+ when (text = ss.scan(/-?([0-9]+|[0-9]*\.[0-9]+)/i))
84
+ @rex_tokens.push action { [:NUMBER, text] }
85
+
86
+ when (text = ss.scan(/\#([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])+/i))
87
+ @rex_tokens.push action { [:HASH, text] }
88
+
89
+ when (text = ss.scan(/[\s\r\n\f]*\+/i))
90
+ @rex_tokens.push action { [:PLUS, text] }
91
+
92
+ when (text = ss.scan(/[\s\r\n\f]*>/i))
93
+ @rex_tokens.push action { [:GREATER, text] }
94
+
95
+ when (text = ss.scan(/[\s\r\n\f]*,/i))
96
+ @rex_tokens.push action { [:COMMA, text] }
97
+
98
+ when (text = ss.scan(/[\s\r\n\f]*~/i))
99
+ @rex_tokens.push action { [:TILDE, text] }
100
+
101
+ when (text = ss.scan(/\:not\(/i))
102
+ @rex_tokens.push action { [:NOT, text] }
103
+
104
+ when (text = ss.scan(/@[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
105
+ @rex_tokens.push action { [:ATKEYWORD, text] }
106
+
107
+ when (text = ss.scan(/-?([0-9]+|[0-9]*\.[0-9]+)%/i))
108
+ @rex_tokens.push action { [:PERCENTAGE, text] }
109
+
110
+ when (text = ss.scan(/-?([0-9]+|[0-9]*\.[0-9]+)[-]?([_a-z]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])([_a-z0-9-]|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
111
+ @rex_tokens.push action { [:DIMENSION, text] }
112
+
113
+ when (text = ss.scan(/<!--/i))
114
+ @rex_tokens.push action { [:CDO, text] }
115
+
116
+ when (text = ss.scan(/-->/i))
117
+ @rex_tokens.push action { [:CDC, text] }
118
+
119
+ when (text = ss.scan(/[\s\r\n\f]*\/\//i))
120
+ @rex_tokens.push action { [:DOUBLESLASH, text] }
121
+
122
+ when (text = ss.scan(/[\s\r\n\f]*\//i))
123
+ @rex_tokens.push action { [:SLASH, text] }
124
+
125
+ when (text = ss.scan(/U\+[0-9a-f?]{1,6}(-[0-9a-f]{1,6})?/i))
126
+ @rex_tokens.push action {[:UNICODE_RANGE, text] }
127
+
128
+ when (text = ss.scan(/\/\*(.|[\r\n])*?\*\//i))
129
+ ;
130
+
131
+ when (text = ss.scan(/[\s\t\r\n\f]+/i))
132
+ @rex_tokens.push action { [:S, text] }
133
+
134
+ when (text = ss.scan(/[\.*:\[\]=\)]/i))
135
+ @rex_tokens.push action { [text, text] }
136
+
137
+ when (text = ss.scan(/"([^\n\r\f"]|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*"|'([^\n\r\f']|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*'/i))
138
+ @rex_tokens.push action { [:STRING, text] }
139
+
140
+ when (text = ss.scan(/\"([^\n\r\f\"]|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*|([^\n\r\f\']|\\n|\r\n|\r|\f|[^\0-\177]|\\[0-9a-f]{1,6}(\r\n|[\s\n\r\t\f])?|\\[^\n\r\f0-9a-f])*/i))
141
+ @rex_tokens.push action { [:INVALID, text] }
142
+
143
+ when (text = ss.scan(/./i))
144
+ @rex_tokens.push action { [text, text] }
145
+
146
+ else
147
+ text = ss.string[ss.pos .. -1]
148
+ raise ScanError, "can not match: '" + text + "'"
149
+ end # if
150
+
151
+ else
152
+ raise ScanError, "undefined state: '" + state.to_s + "'"
153
+ end # case state
154
+ end # until ss
155
+ end # def scan_evaluate
156
+
157
+ end # class
158
+ end
159
+ end
@@ -0,0 +1,97 @@
1
+ module Nokogiri
2
+ module CSS
3
+ class Node
4
+ attr_accessor :type, :value
5
+ def initialize type, value
6
+ @type = type
7
+ @value = value
8
+ end
9
+
10
+ def accept visitor
11
+ visitor.send(:"visit_#{type.to_s.downcase}", self)
12
+ end
13
+
14
+ def to_xpath prefix = nil, visitor = nil
15
+ prefix ||= '//'
16
+ visitor ||= XPathVisitor.new
17
+ self.preprocess!
18
+ prefix + visitor.accept(self)
19
+ end
20
+
21
+ def preprocess!
22
+ ### Deal with nth-child
23
+ matches = find_by_type(
24
+ [:CONDITIONAL_SELECTOR,
25
+ [:ELEMENT_NAME],
26
+ [:PSEUDO_CLASS,
27
+ [:FUNCTION]
28
+ ]
29
+ ]
30
+ )
31
+ matches.each do |match|
32
+ if match.value[1].value[0].value[0] =~ /^nth-child/
33
+ tag_name = match.value[0].value.first
34
+ match.value[0].value = ['*']
35
+ match.value[1] = Node.new(:COMBINATOR, [
36
+ match.value[1].value[0],
37
+ Node.new(:FUNCTION, ['self(', tag_name])
38
+ ])
39
+ end
40
+ if match.value[1].value[0].value[0] =~ /^nth-last-child/
41
+ tag_name = match.value[0].value.first
42
+ match.value[0].value = ['*']
43
+ match.value[1] = Node.new(:COMBINATOR, [
44
+ match.value[1].value[0],
45
+ Node.new(:FUNCTION, ['self(', tag_name])
46
+ ])
47
+ end
48
+ end
49
+
50
+ ### Deal with first-child, last-child
51
+ matches = find_by_type(
52
+ [:CONDITIONAL_SELECTOR,
53
+ [:ELEMENT_NAME], [:PSEUDO_CLASS]
54
+ ])
55
+ matches.each do |match|
56
+ if ['first-child', 'last-child'].include?(match.value[1].value.first)
57
+ which = match.value[1].value.first.gsub(/-\w*$/, '')
58
+ tag_name = match.value[0].value.first
59
+ match.value[0].value = ['*']
60
+ match.value[1] = Node.new(:COMBINATOR, [
61
+ Node.new(:FUNCTION, ["#{which}("]),
62
+ Node.new(:FUNCTION, ['self(', tag_name])
63
+ ])
64
+ elsif 'only-child' == match.value[1].value.first
65
+ tag_name = match.value[0].value.first
66
+ match.value[0].value = ['*']
67
+ match.value[1] = Node.new(:COMBINATOR, [
68
+ Node.new(:FUNCTION, ["#{match.value[1].value.first}("]),
69
+ Node.new(:FUNCTION, ['self(', tag_name])
70
+ ])
71
+ end
72
+ end
73
+
74
+ self
75
+ end
76
+
77
+ def find_by_type(types)
78
+ matches = []
79
+ matches << self if to_type == types
80
+ @value.each do |v|
81
+ matches += v.find_by_type(types) if v.respond_to?(:find_by_type)
82
+ end
83
+ matches
84
+ end
85
+
86
+ def to_type
87
+ [@type] + @value.map { |n|
88
+ n.to_type if n.respond_to?(:to_type)
89
+ }.compact
90
+ end
91
+
92
+ def to_a
93
+ [@type] + @value.map { |n| n.respond_to?(:to_a) ? n.to_a : [n] }
94
+ end
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,64 @@
1
+ require 'thread'
2
+
3
+ module Nokogiri
4
+ module CSS
5
+ class Parser < GeneratedTokenizer
6
+ @cache_on = true
7
+ @cache = {}
8
+ @mutex = Mutex.new
9
+
10
+ class << self
11
+ attr_accessor :cache_on
12
+ alias :cache_on? :cache_on
13
+ alias :set_cache :cache_on=
14
+
15
+ def parse string
16
+ new.parse(string)
17
+ end
18
+
19
+ def xpath_for string, options={}
20
+ new.xpath_for(string, options)
21
+ end
22
+
23
+ def [] string
24
+ return unless @cache_on
25
+ @mutex.synchronize { @cache[string] }
26
+ end
27
+
28
+ def []= string, value
29
+ return value unless @cache_on
30
+ @mutex.synchronize { @cache[string] = value }
31
+ end
32
+
33
+ def clear_cache
34
+ @mutex.synchronize { @cache = {} }
35
+ end
36
+
37
+ def without_cache &block
38
+ tmp = @cache_on
39
+ @cache_on = false
40
+ block.call
41
+ @cache_on = tmp
42
+ end
43
+ end
44
+ alias :parse :scan_str
45
+
46
+ def xpath_for string, options={}
47
+ v = self.class[string]
48
+ return v if v
49
+
50
+ prefix = options[:prefix] || nil
51
+ visitor = options[:visitor] || nil
52
+ args = [prefix, visitor]
53
+ self.class[string] = parse(string).map { |ast|
54
+ ast.to_xpath(prefix, visitor)
55
+ }
56
+ end
57
+
58
+ def on_error error_token_id, error_value, value_stack
59
+ after = value_stack.compact.last
60
+ raise SyntaxError.new("unexpected '#{error_value}' after '#{after}'")
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,216 @@
1
+ class Nokogiri::CSS::GeneratedParser
2
+
3
+ token FUNCTION INCLUDES DASHMATCH LBRACE HASH PLUS GREATER S STRING IDENT
4
+ token COMMA URI CDO CDC NUMBER PERCENTAGE LENGTH EMS EXS ANGLE TIME FREQ
5
+ token IMPORTANT_SYM IMPORT_SYM MEDIA_SYM PAGE_SYM CHARSET_SYM DIMENSION
6
+ token PREFIXMATCH SUFFIXMATCH SUBSTRINGMATCH TILDE NOT_EQUAL SLASH DOUBLESLASH
7
+ token NOT
8
+
9
+ rule
10
+ selector
11
+ : selector COMMA s_0toN simple_selector_1toN {
12
+ result = [val.first, val.last].flatten
13
+ }
14
+ | simple_selector_1toN { result = val.flatten }
15
+ ;
16
+ combinator
17
+ : PLUS s_0toN { result = :DIRECT_ADJACENT_SELECTOR }
18
+ | GREATER s_0toN { result = :CHILD_SELECTOR }
19
+ | TILDE s_0toN { result = :PRECEDING_SELECTOR }
20
+ | S { result = :DESCENDANT_SELECTOR }
21
+ | DOUBLESLASH s_0toN { result = :DESCENDANT_SELECTOR }
22
+ | SLASH s_0toN { result = :CHILD_SELECTOR }
23
+ ;
24
+ simple_selector
25
+ : element_name hcap_0toN {
26
+ result = if val[1].nil?
27
+ val.first
28
+ else
29
+ Node.new(:CONDITIONAL_SELECTOR, [val.first, val[1]])
30
+ end
31
+ }
32
+ | element_name hcap_1toN negation {
33
+ result = Node.new(:CONDITIONAL_SELECTOR,
34
+ [
35
+ val.first,
36
+ Node.new(:COMBINATOR, [val[1], val.last])
37
+ ]
38
+ )
39
+ }
40
+ | element_name negation {
41
+ result = Node.new(:CONDITIONAL_SELECTOR, val)
42
+ }
43
+ | function
44
+ | function attrib {
45
+ result = Node.new(:CONDITIONAL_SELECTOR, val)
46
+ }
47
+ | hcap_1toN negation {
48
+ result = Node.new(:CONDITIONAL_SELECTOR,
49
+ [
50
+ Node.new(:ELEMENT_NAME, ['*']),
51
+ Node.new(:COMBINATOR, val)
52
+ ]
53
+ )
54
+ }
55
+ | hcap_1toN {
56
+ result = Node.new(:CONDITIONAL_SELECTOR,
57
+ [Node.new(:ELEMENT_NAME, ['*']), val.first]
58
+ )
59
+ }
60
+ ;
61
+ simple_selector_1toN
62
+ : simple_selector combinator simple_selector_1toN {
63
+ result = Node.new(val[1], [val.first, val.last])
64
+ }
65
+ | simple_selector
66
+ ;
67
+ class
68
+ : '.' IDENT { result = Node.new(:CLASS_CONDITION, [val[1]]) }
69
+ ;
70
+ element_name
71
+ : IDENT { result = Node.new(:ELEMENT_NAME, val) }
72
+ | '*' { result = Node.new(:ELEMENT_NAME, val) }
73
+ ;
74
+ attrib
75
+ : '[' s_0toN IDENT s_0toN attrib_val_0or1 ']' {
76
+ result = Node.new(:ATTRIBUTE_CONDITION,
77
+ [Node.new(:ELEMENT_NAME, [val[2]])] + (val[4] || [])
78
+ )
79
+ }
80
+ | '[' s_0toN function s_0toN attrib_val_0or1 ']' {
81
+ result = Node.new(:ATTRIBUTE_CONDITION,
82
+ [val[2]] + (val[4] || [])
83
+ )
84
+ }
85
+ | '[' s_0toN NUMBER s_0toN ']' {
86
+ # Non standard, but hpricot supports it.
87
+ result = Node.new(:PSEUDO_CLASS,
88
+ [Node.new(:FUNCTION, ['nth-child(', val[2]])]
89
+ )
90
+ }
91
+ ;
92
+ function
93
+ : FUNCTION ')' {
94
+ result = Node.new(:FUNCTION, [val.first.strip])
95
+ }
96
+ | FUNCTION expr ')' {
97
+ result = Node.new(:FUNCTION, [val.first.strip, val[1]].flatten)
98
+ }
99
+ | FUNCTION an_plus_b ')' {
100
+ result = Node.new(:FUNCTION, [val.first.strip, val[1]].flatten)
101
+ }
102
+ | NOT expr ')' {
103
+ result = Node.new(:FUNCTION, [val.first.strip, val[1]].flatten)
104
+ }
105
+ ;
106
+ expr
107
+ : NUMBER COMMA s_0toN expr { result = [val.first, val.last] }
108
+ | STRING COMMA s_0toN expr { result = [val.first, val.last] }
109
+ | NUMBER
110
+ | STRING
111
+ ;
112
+ an_plus_b
113
+ : NUMBER IDENT PLUS NUMBER # 5n+3 -5n+3
114
+ {
115
+ if val[1] == 'n'
116
+ result = Node.new(:AN_PLUS_B, val)
117
+ else
118
+ raise Racc::ParseError, "parse error on IDENT '#{val[1]}'"
119
+ end
120
+ }
121
+ | IDENT PLUS NUMBER { # n+3, -n+3
122
+ if val[0] == 'n'
123
+ val.unshift("1")
124
+ result = Node.new(:AN_PLUS_B, val)
125
+ elsif val[0] == '-n'
126
+ val[0] = 'n'
127
+ val.unshift("-1")
128
+ result = Node.new(:AN_PLUS_B, val)
129
+ else
130
+ raise Racc::ParseError, "parse error on IDENT '#{val[1]}'"
131
+ end
132
+ }
133
+ | NUMBER IDENT # 5n, -5n
134
+ {
135
+ if val[1] == 'n'
136
+ val << "+"
137
+ val << "0"
138
+ result = Node.new(:AN_PLUS_B, val)
139
+ else
140
+ raise Racc::ParseError, "parse error on IDENT '#{val[1]}'"
141
+ end
142
+ }
143
+ | IDENT # even, odd
144
+ {
145
+ if val[0] == 'even'
146
+ val = ["2","n","+","0"]
147
+ result = Node.new(:AN_PLUS_B, val)
148
+ elsif val[0] == 'odd'
149
+ val = ["2","n","+","1"]
150
+ result = Node.new(:AN_PLUS_B, val)
151
+ else
152
+ raise Racc::ParseError, "parse error on IDENT '#{val[0]}'"
153
+ end
154
+ }
155
+ ;
156
+ pseudo
157
+ : ':' function {
158
+ result = Node.new(:PSEUDO_CLASS, [val[1]])
159
+ }
160
+ | ':' IDENT { result = Node.new(:PSEUDO_CLASS, [val[1]]) }
161
+ ;
162
+ hcap_0toN
163
+ : hcap_1toN
164
+ |
165
+ ;
166
+ hcap_1toN
167
+ : attribute_id hcap_1toN {
168
+ result = Node.new(:COMBINATOR, val)
169
+ }
170
+ | class hcap_1toN {
171
+ result = Node.new(:COMBINATOR, val)
172
+ }
173
+ | attrib hcap_1toN {
174
+ result = Node.new(:COMBINATOR, val)
175
+ }
176
+ | pseudo hcap_1toN {
177
+ result = Node.new(:COMBINATOR, val)
178
+ }
179
+ | attribute_id
180
+ | class
181
+ | attrib
182
+ | pseudo
183
+ ;
184
+ attribute_id
185
+ : HASH { result = Node.new(:ID, val) }
186
+ ;
187
+ attrib_val_0or1
188
+ : eql_incl_dash s_0toN IDENT s_0toN { result = [val.first, val[2]] }
189
+ | eql_incl_dash s_0toN STRING s_0toN { result = [val.first, val[2]] }
190
+ |
191
+ ;
192
+ eql_incl_dash
193
+ : '='
194
+ | PREFIXMATCH
195
+ | SUFFIXMATCH
196
+ | SUBSTRINGMATCH
197
+ | NOT_EQUAL
198
+ | INCLUDES
199
+ | DASHMATCH
200
+ ;
201
+ negation
202
+ : NOT s_0toN negation_arg s_0toN ')' {
203
+ result = Node.new(:NOT, [val[2]])
204
+ }
205
+ ;
206
+ negation_arg
207
+ : hcap_1toN
208
+ ;
209
+ s_0toN
210
+ : S s_0toN
211
+ |
212
+ ;
213
+ end
214
+
215
+ ---- header
216
+