tenderlove-nokogiri 0.0.0.20081001111445

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. data/History.txt +6 -0
  2. data/Manifest.txt +105 -0
  3. data/README.txt +51 -0
  4. data/Rakefile +70 -0
  5. data/ext/nokogiri/extconf.rb +24 -0
  6. data/ext/nokogiri/html_document.c +85 -0
  7. data/ext/nokogiri/html_document.h +10 -0
  8. data/ext/nokogiri/html_sax_parser.c +32 -0
  9. data/ext/nokogiri/html_sax_parser.h +11 -0
  10. data/ext/nokogiri/native.c +35 -0
  11. data/ext/nokogiri/native.h +32 -0
  12. data/ext/nokogiri/xml_cdata.c +36 -0
  13. data/ext/nokogiri/xml_cdata.h +9 -0
  14. data/ext/nokogiri/xml_document.c +159 -0
  15. data/ext/nokogiri/xml_document.h +10 -0
  16. data/ext/nokogiri/xml_node.c +573 -0
  17. data/ext/nokogiri/xml_node.h +13 -0
  18. data/ext/nokogiri/xml_node_set.c +90 -0
  19. data/ext/nokogiri/xml_node_set.h +9 -0
  20. data/ext/nokogiri/xml_reader.c +420 -0
  21. data/ext/nokogiri/xml_reader.h +10 -0
  22. data/ext/nokogiri/xml_sax_parser.c +161 -0
  23. data/ext/nokogiri/xml_sax_parser.h +10 -0
  24. data/ext/nokogiri/xml_text.c +25 -0
  25. data/ext/nokogiri/xml_text.h +9 -0
  26. data/ext/nokogiri/xml_xpath.c +39 -0
  27. data/ext/nokogiri/xml_xpath.h +11 -0
  28. data/ext/nokogiri/xml_xpath_context.c +69 -0
  29. data/ext/nokogiri/xml_xpath_context.h +9 -0
  30. data/ext/nokogiri/xslt_stylesheet.c +83 -0
  31. data/ext/nokogiri/xslt_stylesheet.h +9 -0
  32. data/lib/nokogiri.rb +45 -0
  33. data/lib/nokogiri/css.rb +6 -0
  34. data/lib/nokogiri/css/node.rb +95 -0
  35. data/lib/nokogiri/css/parser.rb +24 -0
  36. data/lib/nokogiri/css/parser.y +198 -0
  37. data/lib/nokogiri/css/tokenizer.rb +9 -0
  38. data/lib/nokogiri/css/tokenizer.rex +63 -0
  39. data/lib/nokogiri/css/xpath_visitor.rb +153 -0
  40. data/lib/nokogiri/decorators.rb +1 -0
  41. data/lib/nokogiri/decorators/hpricot.rb +3 -0
  42. data/lib/nokogiri/decorators/hpricot/node.rb +47 -0
  43. data/lib/nokogiri/decorators/hpricot/node_set.rb +14 -0
  44. data/lib/nokogiri/decorators/hpricot/xpath_visitor.rb +13 -0
  45. data/lib/nokogiri/hpricot.rb +46 -0
  46. data/lib/nokogiri/html.rb +64 -0
  47. data/lib/nokogiri/html/builder.rb +9 -0
  48. data/lib/nokogiri/html/document.rb +9 -0
  49. data/lib/nokogiri/html/sax/parser.rb +21 -0
  50. data/lib/nokogiri/version.rb +3 -0
  51. data/lib/nokogiri/xml.rb +29 -0
  52. data/lib/nokogiri/xml/after_handler.rb +18 -0
  53. data/lib/nokogiri/xml/before_handler.rb +32 -0
  54. data/lib/nokogiri/xml/builder.rb +79 -0
  55. data/lib/nokogiri/xml/document.rb +22 -0
  56. data/lib/nokogiri/xml/node.rb +162 -0
  57. data/lib/nokogiri/xml/node_set.rb +136 -0
  58. data/lib/nokogiri/xml/reader.rb +14 -0
  59. data/lib/nokogiri/xml/sax.rb +9 -0
  60. data/lib/nokogiri/xml/sax/document.rb +59 -0
  61. data/lib/nokogiri/xml/sax/parser.rb +33 -0
  62. data/lib/nokogiri/xml/text.rb +6 -0
  63. data/lib/nokogiri/xml/xpath.rb +6 -0
  64. data/lib/nokogiri/xslt.rb +11 -0
  65. data/lib/nokogiri/xslt/stylesheet.rb +6 -0
  66. data/nokogiri.gemspec +33 -0
  67. data/test/css/test_nthiness.rb +141 -0
  68. data/test/css/test_parser.rb +214 -0
  69. data/test/css/test_tokenizer.rb +162 -0
  70. data/test/files/staff.xml +57 -0
  71. data/test/files/staff.xslt +32 -0
  72. data/test/files/tlm.html +850 -0
  73. data/test/helper.rb +70 -0
  74. data/test/hpricot/files/basic.xhtml +17 -0
  75. data/test/hpricot/files/boingboing.html +2266 -0
  76. data/test/hpricot/files/cy0.html +3653 -0
  77. data/test/hpricot/files/immob.html +400 -0
  78. data/test/hpricot/files/pace_application.html +1320 -0
  79. data/test/hpricot/files/tenderlove.html +16 -0
  80. data/test/hpricot/files/uswebgen.html +220 -0
  81. data/test/hpricot/files/utf8.html +1054 -0
  82. data/test/hpricot/files/week9.html +1723 -0
  83. data/test/hpricot/files/why.xml +19 -0
  84. data/test/hpricot/load_files.rb +7 -0
  85. data/test/hpricot/test_alter.rb +67 -0
  86. data/test/hpricot/test_builder.rb +27 -0
  87. data/test/hpricot/test_parser.rb +412 -0
  88. data/test/hpricot/test_paths.rb +15 -0
  89. data/test/hpricot/test_preserved.rb +72 -0
  90. data/test/hpricot/test_xml.rb +26 -0
  91. data/test/html/sax/test_parser.rb +27 -0
  92. data/test/html/test_builder.rb +78 -0
  93. data/test/html/test_document.rb +22 -0
  94. data/test/test_convert_xpath.rb +173 -0
  95. data/test/test_nokogiri.rb +36 -0
  96. data/test/test_reader.rb +222 -0
  97. data/test/test_xslt_transforms.rb +29 -0
  98. data/test/xml/sax/test_parser.rb +93 -0
  99. data/test/xml/test_builder.rb +16 -0
  100. data/test/xml/test_document.rb +141 -0
  101. data/test/xml/test_node.rb +148 -0
  102. data/test/xml/test_node_set.rb +54 -0
  103. data/test/xml/test_text.rb +13 -0
  104. metadata +191 -0
@@ -0,0 +1,9 @@
1
+ require 'nokogiri/xml/sax/document'
2
+ require 'nokogiri/xml/sax/parser'
3
+
4
+ module Nokogiri
5
+ module XML
6
+ module SAX
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,59 @@
1
+ module Nokogiri
2
+ module XML
3
+ module SAX
4
+ class Document
5
+ ###
6
+ # Called when document starts parsing
7
+ def start_document
8
+ end
9
+
10
+ ###
11
+ # Called when document ends parsing
12
+ def end_document
13
+ end
14
+
15
+ ###
16
+ # Called at the beginning of an element
17
+ # +name+ is the name of the tag with +attrs+ as attributes
18
+ def start_element name, attrs = []
19
+ end
20
+
21
+ ###
22
+ # Called at the end of an element
23
+ # +name+ is the tag name
24
+ def end_element name
25
+ end
26
+
27
+ ###
28
+ # Characters read between a tag
29
+ # +string+ contains the character data
30
+ def characters string
31
+ end
32
+
33
+ ###
34
+ # Called when comments are encountered
35
+ # +string+ contains the comment data
36
+ def comment string
37
+ end
38
+
39
+ ###
40
+ # Called on document warnings
41
+ # +string+ contains the warning
42
+ def warning string
43
+ end
44
+
45
+ ###
46
+ # Called on document errors
47
+ # +string+ contains the error
48
+ def error string
49
+ end
50
+
51
+ ###
52
+ # Called when cdata blocks are found
53
+ # +string+ contains the cdata content
54
+ def cdata_block string
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,33 @@
1
+ module Nokogiri
2
+ module XML
3
+ module SAX
4
+ class Parser
5
+ attr_accessor :document
6
+ def initialize(doc = XML::SAX::Document.new)
7
+ @document = doc
8
+ end
9
+
10
+ ###
11
+ # Parse given +thing+ which may be a string containing xml, or an
12
+ # IO object.
13
+ def parse thing
14
+ parse_memory(thing.is_a?(IO) ? thing.read : thing)
15
+ end
16
+
17
+ ###
18
+ # Parse given +io+
19
+ def parse_io io
20
+ parse_memory io.read
21
+ end
22
+
23
+ ###
24
+ # Parse a file with +filename+
25
+ def parse_file filename
26
+ raise Errno::ENOENT unless File.exists?(filename)
27
+ raise Errno::EISDIR if File.directory?(filename)
28
+ native_parse_file filename
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,6 @@
1
+ module Nokogiri
2
+ module XML
3
+ class Text < Node
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module Nokogiri
2
+ module XML
3
+ class XPath
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,11 @@
1
+ require 'nokogiri/xslt/stylesheet'
2
+
3
+ module Nokogiri
4
+ module XSLT
5
+ class << self
6
+ def parse(string)
7
+ Stylesheet.parse_stylesheet_doc(XML.parse(string))
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ module Nokogiri
2
+ module XSLT
3
+ class Stylesheet
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,33 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{nokogiri}
3
+ s.version = "0.0.0.20081001111445"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Aaron Patterson"]
7
+ s.date = %q{2008-10-01}
8
+ s.description = %q{FIX (describe your package)}
9
+ s.email = ["aaronp@rubyforge.org"]
10
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
11
+ s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "ext/nokogiri/extconf.rb", "ext/nokogiri/html_document.c", "ext/nokogiri/html_document.h", "ext/nokogiri/html_sax_parser.c", "ext/nokogiri/html_sax_parser.h", "ext/nokogiri/native.c", "ext/nokogiri/native.h", "ext/nokogiri/xml_cdata.c", "ext/nokogiri/xml_cdata.h", "ext/nokogiri/xml_document.c", "ext/nokogiri/xml_document.h", "ext/nokogiri/xml_node.c", "ext/nokogiri/xml_node.h", "ext/nokogiri/xml_node_set.c", "ext/nokogiri/xml_node_set.h", "ext/nokogiri/xml_reader.c", "ext/nokogiri/xml_reader.h", "ext/nokogiri/xml_sax_parser.c", "ext/nokogiri/xml_sax_parser.h", "ext/nokogiri/xml_text.c", "ext/nokogiri/xml_text.h", "ext/nokogiri/xml_xpath.c", "ext/nokogiri/xml_xpath.h", "ext/nokogiri/xml_xpath_context.c", "ext/nokogiri/xml_xpath_context.h", "ext/nokogiri/xslt_stylesheet.c", "ext/nokogiri/xslt_stylesheet.h", "lib/nokogiri.rb", "lib/nokogiri/css.rb", "lib/nokogiri/css/generated_parser.rb", "lib/nokogiri/css/generated_tokenizer.rb", "lib/nokogiri/css/node.rb", "lib/nokogiri/css/parser.rb", "lib/nokogiri/css/parser.y", "lib/nokogiri/css/tokenizer.rb", "lib/nokogiri/css/tokenizer.rex", "lib/nokogiri/css/xpath_visitor.rb", "lib/nokogiri/decorators.rb", "lib/nokogiri/decorators/hpricot.rb", "lib/nokogiri/decorators/hpricot/node.rb", "lib/nokogiri/decorators/hpricot/node_set.rb", "lib/nokogiri/decorators/hpricot/xpath_visitor.rb", "lib/nokogiri/hpricot.rb", "lib/nokogiri/html.rb", "lib/nokogiri/html/builder.rb", "lib/nokogiri/html/document.rb", "lib/nokogiri/html/sax/parser.rb", "lib/nokogiri/version.rb", "lib/nokogiri/xml.rb", "lib/nokogiri/xml/after_handler.rb", "lib/nokogiri/xml/before_handler.rb", "lib/nokogiri/xml/builder.rb", "lib/nokogiri/xml/document.rb", "lib/nokogiri/xml/node.rb", "lib/nokogiri/xml/node_set.rb", "lib/nokogiri/xml/reader.rb", "lib/nokogiri/xml/sax.rb", "lib/nokogiri/xml/sax/document.rb", "lib/nokogiri/xml/sax/parser.rb", "lib/nokogiri/xml/text.rb", "lib/nokogiri/xml/xpath.rb", "lib/nokogiri/xslt.rb", "lib/nokogiri/xslt/stylesheet.rb", "nokogiri.gemspec", "test/css/test_nthiness.rb", "test/css/test_parser.rb", "test/css/test_tokenizer.rb", "test/files/staff.xml", "test/files/staff.xslt", "test/files/tlm.html", "test/helper.rb", "test/hpricot/files/basic.xhtml", "test/hpricot/files/boingboing.html", "test/hpricot/files/cy0.html", "test/hpricot/files/immob.html", "test/hpricot/files/pace_application.html", "test/hpricot/files/tenderlove.html", "test/hpricot/files/uswebgen.html", "test/hpricot/files/utf8.html", "test/hpricot/files/week9.html", "test/hpricot/files/why.xml", "test/hpricot/load_files.rb", "test/hpricot/test_alter.rb", "test/hpricot/test_builder.rb", "test/hpricot/test_parser.rb", "test/hpricot/test_paths.rb", "test/hpricot/test_preserved.rb", "test/hpricot/test_xml.rb", "test/html/sax/test_parser.rb", "test/html/test_builder.rb", "test/html/test_document.rb", "test/test_convert_xpath.rb", "test/test_nokogiri.rb", "test/test_reader.rb", "test/test_xslt_transforms.rb", "test/xml/sax/test_parser.rb", "test/xml/test_builder.rb", "test/xml/test_document.rb", "test/xml/test_node.rb", "test/xml/test_node_set.rb", "test/xml/test_text.rb"]
12
+ s.has_rdoc = true
13
+ s.homepage = %q{http://github.com/tenderlove/nokogiri/tree/master}
14
+ s.rdoc_options = ["--main", "README.txt"]
15
+ s.require_paths = ["lib", "ext"]
16
+ s.rubyforge_project = %q{nokogiri}
17
+ s.rubygems_version = %q{1.2.0}
18
+ s.summary = %q{FIX (describe your package)}
19
+ s.test_files = ["test/css/test_nthiness.rb", "test/css/test_parser.rb", "test/css/test_tokenizer.rb", "test/hpricot/test_alter.rb", "test/hpricot/test_builder.rb", "test/hpricot/test_parser.rb", "test/hpricot/test_paths.rb", "test/hpricot/test_preserved.rb", "test/hpricot/test_xml.rb", "test/html/sax/test_parser.rb", "test/html/test_builder.rb", "test/html/test_document.rb", "test/test_convert_xpath.rb", "test/test_nokogiri.rb", "test/test_reader.rb", "test/test_xslt_transforms.rb", "test/xml/sax/test_parser.rb", "test/xml/test_builder.rb", "test/xml/test_document.rb", "test/xml/test_node.rb", "test/xml/test_node_set.rb", "test/xml/test_text.rb"]
20
+
21
+ if s.respond_to? :specification_version then
22
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
23
+ s.specification_version = 2
24
+
25
+ if current_version >= 3 then
26
+ s.add_development_dependency(%q<hoe>, [">= 1.7.0"])
27
+ else
28
+ s.add_dependency(%q<hoe>, [">= 1.7.0"])
29
+ end
30
+ else
31
+ s.add_dependency(%q<hoe>, [">= 1.7.0"])
32
+ end
33
+ end
@@ -0,0 +1,141 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', "helper"))
2
+
3
+ module Nokogiri
4
+ module CSS
5
+ class TestNthiness < Nokogiri::TestCase
6
+ def setup
7
+ doc = <<EOF
8
+ <html>
9
+ <table>
10
+ <tr><td>row1 </td></tr>
11
+ <tr><td>row2 </td></tr>
12
+ <tr><td>row3 </td></tr>
13
+ <tr><td>row4 </td></tr>
14
+ <tr><td>row5 </td></tr>
15
+ <tr><td>row6 </td></tr>
16
+ <tr><td>row7 </td></tr>
17
+ <tr><td>row8 </td></tr>
18
+ <tr><td>row9 </td></tr>
19
+ <tr><td>row10 </td></tr>
20
+ <tr><td>row11 </td></tr>
21
+ <tr><td>row12 </td></tr>
22
+ <tr><td>row13 </td></tr>
23
+ <tr><td>row14 </td></tr>
24
+ </table>
25
+ <div>
26
+ <b>bold1 </b>
27
+ <i>italic1 </i>
28
+ <b>bold2 </b>
29
+ <i>italic2 </i>
30
+ <p>para1 </p>
31
+ <b>bold3 </b>
32
+ </div>
33
+ <div>
34
+ <p>para2 </p>
35
+ <p>para3 </p>
36
+ </div>
37
+ <div>
38
+ <p>para4 </p>
39
+ </div>
40
+ <p class='empty'></p>
41
+ <p class='not-empty'><b></b></p>
42
+ </html>
43
+ EOF
44
+ @parser = Nokogiri.Hpricot doc
45
+ @xpath = Nokogiri doc
46
+ @cssparser = Nokogiri::CSS::Parser.new
47
+ end
48
+
49
+
50
+ def test_even
51
+ assert_result_rows [2,4,6,8,10,12,14], @parser.search("table/tr:nth(even)")
52
+ end
53
+
54
+ def test_odd
55
+ assert_result_rows [1,3,5,7,9,11,13], @parser.search("table/tr:nth(odd)")
56
+ end
57
+
58
+ def test_2n
59
+ assert_equal @parser.search("table/tr:nth(even)").inner_text, @parser.search("table/tr:nth(2n)").inner_text
60
+ end
61
+
62
+ def test_2np1
63
+ assert_equal @parser.search("table/tr:nth(odd)").inner_text, @parser.search("table/tr:nth(2n+1)").inner_text
64
+ end
65
+
66
+ def test_4np3
67
+ assert_result_rows [3,7,11], @parser.search("table/tr:nth(4n+3)")
68
+ end
69
+
70
+ def test_3np4
71
+ assert_result_rows [4,7,10,13], @parser.search("table/tr:nth(3n+4)")
72
+ end
73
+
74
+ def test_mnp3
75
+ assert_result_rows [1,2,3], @parser.search("table/tr:nth(-n+3)")
76
+ end
77
+
78
+ def test_np3
79
+ assert_result_rows [3,4,5,6,7,8,9,10,11,12,13,14], @parser.search("table/tr:nth(n+3)")
80
+ end
81
+
82
+ def test_first
83
+ assert_result_rows [1], @parser.search("table/tr:first")
84
+ assert_result_rows [1], @parser.search("table/tr:first()")
85
+ end
86
+
87
+ def test_last
88
+ assert_result_rows [14], @parser.search("table/tr:last")
89
+ assert_result_rows [14], @parser.search("table/tr:last()")
90
+ end
91
+
92
+ def test_first_child
93
+ assert_result_rows [1], @parser.search("div/b:first-child"), "bold"
94
+ assert_result_rows [1], @parser.search("table/tr:first-child")
95
+ end
96
+
97
+ def test_last_child
98
+ assert_result_rows [3], @parser.search("div/b:last-child"), "bold"
99
+ assert_result_rows [14], @parser.search("table/tr:last-child")
100
+ end
101
+
102
+ def test_first_of_type
103
+ assert_result_rows [1], @parser.search("table/tr:first-of-type")
104
+ assert_result_rows [1], @parser.search("div/b:first-of-type"), "bold"
105
+ end
106
+
107
+ def test_last_of_type
108
+ assert_result_rows [14], @parser.search("table/tr:last-of-type")
109
+ assert_result_rows [3], @parser.search("div/b:last-of-type"), "bold"
110
+ end
111
+
112
+ def test_only_of_type
113
+ assert_result_rows [1,4], @parser.search("div/p:only-of-type"), "para"
114
+ end
115
+
116
+ def test_only_child
117
+ assert_result_rows [4], @parser.search("div/p:only-child"), "para"
118
+ end
119
+
120
+ def test_empty
121
+ result = @parser.search("p:empty")
122
+ assert_equal 1, result.size, "unexpected number of rows returned: '#{result.inner_text}'"
123
+ assert_equal 'empty', result.first['class']
124
+ end
125
+
126
+ def test_parent
127
+ result = @parser.search("p:parent")
128
+ assert_equal 5, result.size
129
+ 0.upto(3) do |j|
130
+ assert_equal "para#{j+1} ", result[j].inner_text
131
+ end
132
+ assert_equal "not-empty", result[4]['class']
133
+ end
134
+
135
+ def assert_result_rows intarray, result, word="row"
136
+ assert_equal intarray.size, result.size, "unexpected number of rows returned: '#{result.inner_text}'"
137
+ assert_equal intarray.map{|j| "#{word}#{j}"}.join(' '), result.inner_text.strip, result.inner_text
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,214 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', "helper"))
2
+
3
+ module Nokogiri
4
+ module CSS
5
+ class TestParser < Nokogiri::TestCase
6
+ def setup
7
+ @parser = Nokogiri::CSS::Parser.new
8
+ end
9
+
10
+ def test_find_by_type
11
+ ast = @parser.parse("a:nth-child(2)").first
12
+ matches = ast.find_by_type(
13
+ [:CONDITIONAL_SELECTOR,
14
+ [:ELEMENT_NAME],
15
+ [:PSEUDO_CLASS,
16
+ [:FUNCTION]
17
+ ]
18
+ ]
19
+ )
20
+ assert_equal(1, matches.length)
21
+ assert_equal(ast, matches.first)
22
+ end
23
+
24
+ def test_to_type
25
+ ast = @parser.parse("a:nth-child(2)").first
26
+ assert_equal(
27
+ [:CONDITIONAL_SELECTOR,
28
+ [:ELEMENT_NAME],
29
+ [:PSEUDO_CLASS,
30
+ [:FUNCTION]
31
+ ]
32
+ ], ast.to_type
33
+ )
34
+ end
35
+
36
+ def test_to_a
37
+ asts = @parser.parse("a:nth-child(2)")
38
+ assert_equal(
39
+ [:CONDITIONAL_SELECTOR,
40
+ [:ELEMENT_NAME, ["a"]],
41
+ [:PSEUDO_CLASS,
42
+ [:FUNCTION, ["nth-child("], ["2"]]
43
+ ]
44
+ ], asts.first.to_a
45
+ )
46
+ end
47
+
48
+ def test_function_with_arguments
49
+ assert_xpath "//*[position() = 2 and self::a]",
50
+ @parser.parse("a[2]")
51
+ assert_xpath "//*[position() = 2 and self::a]",
52
+ @parser.parse("a:nth-child(2)")
53
+ end
54
+
55
+ def test_attributes_with_at
56
+ ## This is non standard CSS
57
+ assert_xpath "//a[@id = 'Boing']",
58
+ @parser.parse("a[@id='Boing']")
59
+ end
60
+
61
+ def test_not_equal
62
+ ## This is non standard CSS
63
+ assert_xpath "//a[child::text() != 'Boing']",
64
+ @parser.parse("a[text()!='Boing']")
65
+ end
66
+
67
+ def test_function
68
+ ## This is non standard CSS
69
+ assert_xpath "//a[child::text()]",
70
+ @parser.parse("a[text()]")
71
+
72
+ ## This is non standard CSS
73
+ assert_xpath "//child::text()",
74
+ @parser.parse("text()")
75
+
76
+ ## This is non standard CSS
77
+ assert_xpath "//a[contains(child::text(), 'Boing')]",
78
+ @parser.parse("a[text()*='Boing']")
79
+
80
+ ## This is non standard CSS
81
+ assert_xpath "//script//comment()",
82
+ @parser.parse("script comment()")
83
+ end
84
+
85
+ def test_nonstandard_nth_selectors
86
+ ## These are non standard CSS
87
+ assert_xpath '//a[position() = 99]', @parser.parse('a:eq(99)')
88
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first') # no parens
89
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last') # no parens
90
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth(99)')
91
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first()')
92
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last()')
93
+ assert_xpath '//a[node()]', @parser.parse('a:parent')
94
+ end
95
+
96
+ def test_standard_nth_selectors
97
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth-of-type(99)')
98
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type()')
99
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type()')
100
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type') # no parens
101
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type') # no parens
102
+ assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
103
+ assert_xpath '//a[position() = last() - 99]', @parser.parse('a:nth-last-of-type(99)')
104
+ end
105
+
106
+ def test_nth_child_selectors
107
+ assert_xpath '//*[position() = 1 and self::a]', @parser.parse('a:first-child')
108
+ assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:last-child')
109
+ assert_xpath '//*[position() = 99 and self::a]', @parser.parse('a:nth-child(99)')
110
+ assert_xpath '//*[position() = last() - 99 and self::a]', @parser.parse('a:nth-last-child(99)')
111
+ end
112
+
113
+ def test_miscellaneous_selectors
114
+ assert_xpath '//*[last() = 1 and self::a]',
115
+ @parser.parse('a:only-child')
116
+ assert_xpath '//a[last() = 1]', @parser.parse('a:only-of-type')
117
+ assert_xpath '//a[not(node())]', @parser.parse('a:empty')
118
+ end
119
+
120
+ def test_nth_a_n_plus_b
121
+ assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(2n)')
122
+ assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(2n+1)')
123
+ assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(even)')
124
+ assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(odd)')
125
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 4) = 0)]', @parser.parse('a:nth-of-type(4n+3)')
126
+ assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-1n+3)')
127
+ assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-n+3)')
128
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(1n+3)')
129
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(n+3)')
130
+ end
131
+
132
+ def test_preceding_selector
133
+ assert_xpath "//F[preceding-sibling::E]",
134
+ @parser.parse("E ~ F")
135
+ end
136
+
137
+ def test_attribute
138
+ assert_xpath "//h1[child::a = 'Tender Lovemaking']",
139
+ @parser.parse("h1[a='Tender Lovemaking']")
140
+ end
141
+
142
+ def test_id
143
+ assert_xpath "//*[@id = 'foo']", @parser.parse('#foo')
144
+ end
145
+
146
+ def test_pseudo_class_no_ident
147
+ assert_xpath "//*[1 = 1]", @parser.parse(':link')
148
+ end
149
+
150
+ def test_pseudo_class
151
+ assert_xpath "//a[1 = 1]", @parser.parse('a:link')
152
+ assert_xpath "//a[1 = 1]", @parser.parse('a:visited')
153
+ assert_xpath "//a[1 = 1]", @parser.parse('a:hover')
154
+ assert_xpath "//a[1 = 1]", @parser.parse('a:active')
155
+ assert_xpath "//a[1 = 1 and contains(@class, 'foo')]",
156
+ @parser.parse('a:active.foo')
157
+ end
158
+
159
+ def test_star
160
+ assert_xpath "//*", @parser.parse('*')
161
+ assert_xpath "//*[contains(@class, 'pastoral')]",
162
+ @parser.parse('*.pastoral')
163
+ end
164
+
165
+ def test_class
166
+ assert_xpath "//*[contains(@class, 'a') and contains(@class, 'b')]",
167
+ @parser.parse('.a.b')
168
+ assert_xpath "//*[contains(@class, 'awesome')]",
169
+ @parser.parse('.awesome')
170
+ assert_xpath "//foo[contains(@class, 'awesome')]",
171
+ @parser.parse('foo.awesome')
172
+ assert_xpath "//foo//*[contains(@class, 'awesome')]",
173
+ @parser.parse('foo .awesome')
174
+ end
175
+
176
+ def test_ident
177
+ assert_xpath '//x', @parser.parse('x')
178
+ end
179
+
180
+ def test_parse_space
181
+ assert_xpath '//x//y', @parser.parse('x y')
182
+ end
183
+
184
+ def test_parse_descendant
185
+ assert_xpath '//x/y', @parser.parse('x > y')
186
+ end
187
+
188
+ def test_parse_slash
189
+ ## This is non standard CSS
190
+ assert_xpath '//x/y', @parser.parse('x/y')
191
+ end
192
+
193
+ def test_parse_doubleslash
194
+ ## This is non standard CSS
195
+ assert_xpath '//x//y', @parser.parse('x//y')
196
+ end
197
+
198
+ def test_multi_path
199
+ assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y, y > z')
200
+ assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y,y > z')
201
+ ###
202
+ # TODO: should we make this work?
203
+ # assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y | y > z')
204
+ end
205
+
206
+ def assert_xpath expecteds, asts
207
+ expecteds = [expecteds].flatten
208
+ expecteds.zip(asts).each do |expected, actual|
209
+ assert_equal expected, actual.to_xpath
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end