nokogiri-maglev- 1.5.0.1

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 (225) hide show
  1. data/.autotest +26 -0
  2. data/.gemtest +0 -0
  3. data/CHANGELOG.ja.rdoc +544 -0
  4. data/CHANGELOG.rdoc +532 -0
  5. data/Manifest.txt +283 -0
  6. data/README.ja.rdoc +106 -0
  7. data/README.rdoc +174 -0
  8. data/Rakefile +171 -0
  9. data/bin/nokogiri +53 -0
  10. data/ext/nokogiri/depend +358 -0
  11. data/ext/nokogiri/extconf.rb +124 -0
  12. data/ext/nokogiri/html_document.c +154 -0
  13. data/ext/nokogiri/html_document.h +10 -0
  14. data/ext/nokogiri/html_element_description.c +276 -0
  15. data/ext/nokogiri/html_element_description.h +10 -0
  16. data/ext/nokogiri/html_entity_lookup.c +32 -0
  17. data/ext/nokogiri/html_entity_lookup.h +8 -0
  18. data/ext/nokogiri/html_sax_parser_context.c +94 -0
  19. data/ext/nokogiri/html_sax_parser_context.h +11 -0
  20. data/ext/nokogiri/nokogiri.c +115 -0
  21. data/ext/nokogiri/nokogiri.h +160 -0
  22. data/ext/nokogiri/st.c +576 -0
  23. data/ext/nokogiri/xml_attr.c +94 -0
  24. data/ext/nokogiri/xml_attr.h +9 -0
  25. data/ext/nokogiri/xml_attribute_decl.c +70 -0
  26. data/ext/nokogiri/xml_attribute_decl.h +9 -0
  27. data/ext/nokogiri/xml_cdata.c +56 -0
  28. data/ext/nokogiri/xml_cdata.h +9 -0
  29. data/ext/nokogiri/xml_comment.c +54 -0
  30. data/ext/nokogiri/xml_comment.h +9 -0
  31. data/ext/nokogiri/xml_document.c +478 -0
  32. data/ext/nokogiri/xml_document.h +23 -0
  33. data/ext/nokogiri/xml_document_fragment.c +48 -0
  34. data/ext/nokogiri/xml_document_fragment.h +10 -0
  35. data/ext/nokogiri/xml_dtd.c +202 -0
  36. data/ext/nokogiri/xml_dtd.h +10 -0
  37. data/ext/nokogiri/xml_element_content.c +123 -0
  38. data/ext/nokogiri/xml_element_content.h +10 -0
  39. data/ext/nokogiri/xml_element_decl.c +69 -0
  40. data/ext/nokogiri/xml_element_decl.h +9 -0
  41. data/ext/nokogiri/xml_encoding_handler.c +79 -0
  42. data/ext/nokogiri/xml_encoding_handler.h +8 -0
  43. data/ext/nokogiri/xml_entity_decl.c +110 -0
  44. data/ext/nokogiri/xml_entity_decl.h +10 -0
  45. data/ext/nokogiri/xml_entity_reference.c +52 -0
  46. data/ext/nokogiri/xml_entity_reference.h +9 -0
  47. data/ext/nokogiri/xml_io.c +56 -0
  48. data/ext/nokogiri/xml_io.h +11 -0
  49. data/ext/nokogiri/xml_libxml2_hacks.c +112 -0
  50. data/ext/nokogiri/xml_libxml2_hacks.h +12 -0
  51. data/ext/nokogiri/xml_namespace.c +84 -0
  52. data/ext/nokogiri/xml_namespace.h +13 -0
  53. data/ext/nokogiri/xml_node.c +1397 -0
  54. data/ext/nokogiri/xml_node.h +13 -0
  55. data/ext/nokogiri/xml_node_set.c +418 -0
  56. data/ext/nokogiri/xml_node_set.h +9 -0
  57. data/ext/nokogiri/xml_processing_instruction.c +56 -0
  58. data/ext/nokogiri/xml_processing_instruction.h +9 -0
  59. data/ext/nokogiri/xml_reader.c +684 -0
  60. data/ext/nokogiri/xml_reader.h +10 -0
  61. data/ext/nokogiri/xml_relax_ng.c +162 -0
  62. data/ext/nokogiri/xml_relax_ng.h +9 -0
  63. data/ext/nokogiri/xml_sax_parser.c +293 -0
  64. data/ext/nokogiri/xml_sax_parser.h +39 -0
  65. data/ext/nokogiri/xml_sax_parser_context.c +199 -0
  66. data/ext/nokogiri/xml_sax_parser_context.h +10 -0
  67. data/ext/nokogiri/xml_sax_push_parser.c +115 -0
  68. data/ext/nokogiri/xml_sax_push_parser.h +9 -0
  69. data/ext/nokogiri/xml_schema.c +205 -0
  70. data/ext/nokogiri/xml_schema.h +9 -0
  71. data/ext/nokogiri/xml_syntax_error.c +58 -0
  72. data/ext/nokogiri/xml_syntax_error.h +13 -0
  73. data/ext/nokogiri/xml_text.c +50 -0
  74. data/ext/nokogiri/xml_text.h +9 -0
  75. data/ext/nokogiri/xml_xpath_context.c +315 -0
  76. data/ext/nokogiri/xml_xpath_context.h +9 -0
  77. data/ext/nokogiri/xslt_stylesheet.c +265 -0
  78. data/ext/nokogiri/xslt_stylesheet.h +9 -0
  79. data/lib/nokogiri.rb +127 -0
  80. data/lib/nokogiri/css.rb +27 -0
  81. data/lib/nokogiri/css/node.rb +99 -0
  82. data/lib/nokogiri/css/parser.rb +677 -0
  83. data/lib/nokogiri/css/parser.y +237 -0
  84. data/lib/nokogiri/css/parser_extras.rb +91 -0
  85. data/lib/nokogiri/css/syntax_error.rb +7 -0
  86. data/lib/nokogiri/css/tokenizer.rb +152 -0
  87. data/lib/nokogiri/css/tokenizer.rex +55 -0
  88. data/lib/nokogiri/css/xpath_visitor.rb +171 -0
  89. data/lib/nokogiri/decorators/slop.rb +35 -0
  90. data/lib/nokogiri/html.rb +36 -0
  91. data/lib/nokogiri/html/builder.rb +35 -0
  92. data/lib/nokogiri/html/document.rb +213 -0
  93. data/lib/nokogiri/html/document_fragment.rb +41 -0
  94. data/lib/nokogiri/html/element_description.rb +23 -0
  95. data/lib/nokogiri/html/element_description_defaults.rb +671 -0
  96. data/lib/nokogiri/html/entity_lookup.rb +13 -0
  97. data/lib/nokogiri/html/sax/parser.rb +52 -0
  98. data/lib/nokogiri/html/sax/parser_context.rb +16 -0
  99. data/lib/nokogiri/syntax_error.rb +4 -0
  100. data/lib/nokogiri/version.rb +88 -0
  101. data/lib/nokogiri/xml.rb +67 -0
  102. data/lib/nokogiri/xml/attr.rb +14 -0
  103. data/lib/nokogiri/xml/attribute_decl.rb +18 -0
  104. data/lib/nokogiri/xml/builder.rb +426 -0
  105. data/lib/nokogiri/xml/cdata.rb +11 -0
  106. data/lib/nokogiri/xml/character_data.rb +7 -0
  107. data/lib/nokogiri/xml/document.rb +234 -0
  108. data/lib/nokogiri/xml/document_fragment.rb +98 -0
  109. data/lib/nokogiri/xml/dtd.rb +22 -0
  110. data/lib/nokogiri/xml/element_content.rb +36 -0
  111. data/lib/nokogiri/xml/element_decl.rb +13 -0
  112. data/lib/nokogiri/xml/entity_decl.rb +19 -0
  113. data/lib/nokogiri/xml/namespace.rb +13 -0
  114. data/lib/nokogiri/xml/node.rb +915 -0
  115. data/lib/nokogiri/xml/node/save_options.rb +61 -0
  116. data/lib/nokogiri/xml/node_set.rb +357 -0
  117. data/lib/nokogiri/xml/notation.rb +6 -0
  118. data/lib/nokogiri/xml/parse_options.rb +93 -0
  119. data/lib/nokogiri/xml/pp.rb +2 -0
  120. data/lib/nokogiri/xml/pp/character_data.rb +18 -0
  121. data/lib/nokogiri/xml/pp/node.rb +56 -0
  122. data/lib/nokogiri/xml/processing_instruction.rb +8 -0
  123. data/lib/nokogiri/xml/reader.rb +112 -0
  124. data/lib/nokogiri/xml/relax_ng.rb +32 -0
  125. data/lib/nokogiri/xml/sax.rb +4 -0
  126. data/lib/nokogiri/xml/sax/document.rb +164 -0
  127. data/lib/nokogiri/xml/sax/parser.rb +115 -0
  128. data/lib/nokogiri/xml/sax/parser_context.rb +16 -0
  129. data/lib/nokogiri/xml/sax/push_parser.rb +60 -0
  130. data/lib/nokogiri/xml/schema.rb +63 -0
  131. data/lib/nokogiri/xml/syntax_error.rb +47 -0
  132. data/lib/nokogiri/xml/text.rb +9 -0
  133. data/lib/nokogiri/xml/xpath.rb +10 -0
  134. data/lib/nokogiri/xml/xpath/syntax_error.rb +11 -0
  135. data/lib/nokogiri/xml/xpath_context.rb +16 -0
  136. data/lib/nokogiri/xslt.rb +52 -0
  137. data/lib/nokogiri/xslt/stylesheet.rb +25 -0
  138. data/lib/xsd/xmlparser/nokogiri.rb +90 -0
  139. data/nokogiri_help_responses.md +40 -0
  140. data/tasks/cross_compile.rb +152 -0
  141. data/tasks/nokogiri.org.rb +18 -0
  142. data/tasks/test.rb +94 -0
  143. data/test/css/test_nthiness.rb +159 -0
  144. data/test/css/test_parser.rb +303 -0
  145. data/test/css/test_tokenizer.rb +198 -0
  146. data/test/css/test_xpath_visitor.rb +85 -0
  147. data/test/decorators/test_slop.rb +16 -0
  148. data/test/files/2ch.html +108 -0
  149. data/test/files/address_book.rlx +12 -0
  150. data/test/files/address_book.xml +10 -0
  151. data/test/files/bar/bar.xsd +4 -0
  152. data/test/files/dont_hurt_em_why.xml +422 -0
  153. data/test/files/encoding.html +82 -0
  154. data/test/files/encoding.xhtml +84 -0
  155. data/test/files/exslt.xml +8 -0
  156. data/test/files/exslt.xslt +35 -0
  157. data/test/files/foo/foo.xsd +4 -0
  158. data/test/files/metacharset.html +10 -0
  159. data/test/files/noencoding.html +47 -0
  160. data/test/files/po.xml +32 -0
  161. data/test/files/po.xsd +66 -0
  162. data/test/files/shift_jis.html +10 -0
  163. data/test/files/shift_jis.xml +5 -0
  164. data/test/files/snuggles.xml +3 -0
  165. data/test/files/staff.dtd +10 -0
  166. data/test/files/staff.xml +59 -0
  167. data/test/files/staff.xslt +32 -0
  168. data/test/files/tlm.html +850 -0
  169. data/test/files/valid_bar.xml +2 -0
  170. data/test/helper.rb +173 -0
  171. data/test/html/sax/test_parser.rb +139 -0
  172. data/test/html/sax/test_parser_context.rb +48 -0
  173. data/test/html/test_builder.rb +165 -0
  174. data/test/html/test_document.rb +472 -0
  175. data/test/html/test_document_encoding.rb +138 -0
  176. data/test/html/test_document_fragment.rb +255 -0
  177. data/test/html/test_element_description.rb +101 -0
  178. data/test/html/test_named_characters.rb +14 -0
  179. data/test/html/test_node.rb +193 -0
  180. data/test/html/test_node_encoding.rb +27 -0
  181. data/test/test_convert_xpath.rb +135 -0
  182. data/test/test_css_cache.rb +45 -0
  183. data/test/test_encoding_handler.rb +46 -0
  184. data/test/test_memory_leak.rb +72 -0
  185. data/test/test_nokogiri.rb +133 -0
  186. data/test/test_reader.rb +425 -0
  187. data/test/test_soap4r_sax.rb +52 -0
  188. data/test/test_xslt_transforms.rb +193 -0
  189. data/test/xml/node/test_save_options.rb +28 -0
  190. data/test/xml/node/test_subclass.rb +44 -0
  191. data/test/xml/sax/test_parser.rb +338 -0
  192. data/test/xml/sax/test_parser_context.rb +113 -0
  193. data/test/xml/sax/test_push_parser.rb +156 -0
  194. data/test/xml/test_attr.rb +65 -0
  195. data/test/xml/test_attribute_decl.rb +86 -0
  196. data/test/xml/test_builder.rb +227 -0
  197. data/test/xml/test_cdata.rb +50 -0
  198. data/test/xml/test_comment.rb +29 -0
  199. data/test/xml/test_document.rb +697 -0
  200. data/test/xml/test_document_encoding.rb +26 -0
  201. data/test/xml/test_document_fragment.rb +192 -0
  202. data/test/xml/test_dtd.rb +107 -0
  203. data/test/xml/test_dtd_encoding.rb +33 -0
  204. data/test/xml/test_element_content.rb +56 -0
  205. data/test/xml/test_element_decl.rb +73 -0
  206. data/test/xml/test_entity_decl.rb +122 -0
  207. data/test/xml/test_entity_reference.rb +21 -0
  208. data/test/xml/test_namespace.rb +70 -0
  209. data/test/xml/test_node.rb +917 -0
  210. data/test/xml/test_node_attributes.rb +34 -0
  211. data/test/xml/test_node_encoding.rb +107 -0
  212. data/test/xml/test_node_reparenting.rb +334 -0
  213. data/test/xml/test_node_set.rb +742 -0
  214. data/test/xml/test_parse_options.rb +52 -0
  215. data/test/xml/test_processing_instruction.rb +30 -0
  216. data/test/xml/test_reader_encoding.rb +126 -0
  217. data/test/xml/test_relax_ng.rb +60 -0
  218. data/test/xml/test_schema.rb +94 -0
  219. data/test/xml/test_syntax_error.rb +12 -0
  220. data/test/xml/test_text.rb +47 -0
  221. data/test/xml/test_unparented_node.rb +381 -0
  222. data/test/xml/test_xpath.rb +237 -0
  223. data/test/xslt/test_custom_functions.rb +94 -0
  224. data/test/xslt/test_exception_handling.rb +37 -0
  225. metadata +548 -0
@@ -0,0 +1,152 @@
1
+ require 'rake/extensioncompiler'
2
+ HOST = Rake::ExtensionCompiler.mingw_host
3
+
4
+ require 'mini_portile'
5
+ $recipes = {}
6
+ $recipes[:zlib] = MiniPortile.new "zlib", "1.2.5"
7
+ $recipes[:libiconv] = MiniPortile.new "libiconv", "1.13.1"
8
+ $recipes[:libxml2] = MiniPortile.new "libxml2", "2.7.7"
9
+ $recipes[:libxslt] = MiniPortile.new "libxslt", "1.1.26"
10
+ $recipes.each { |_, recipe| recipe.host = HOST }
11
+
12
+ file "lib/nokogiri/nokogiri.rb" do
13
+ File.open("lib/nokogiri/nokogiri.rb", 'wb') do |f|
14
+ f.write %Q{require "nokogiri/\#{RUBY_VERSION.sub(/\\.\\d+$/, '')}/nokogiri"\n}
15
+ end
16
+ end
17
+
18
+ namespace :cross do
19
+ task :zlib do
20
+ recipe = $recipes[:zlib]
21
+ recipe.files = ["http://zlib.net/#{recipe.name}-#{recipe.version}.tar.gz"]
22
+ class << recipe
23
+ def configure
24
+ Dir.chdir work_path do
25
+ mk = File.read 'win32/Makefile.gcc'
26
+ File.open 'win32/Makefile.gcc', 'wb' do |f|
27
+ f.puts "BINARY_PATH = #{CROSS_DIR}/bin"
28
+ f.puts "LIBRARY_PATH = #{CROSS_DIR}/lib"
29
+ f.puts "INCLUDE_PATH = #{CROSS_DIR}/include"
30
+ f.puts mk.sub(/^PREFIX\s*=\s*$/, "PREFIX = #{HOST}-")
31
+ end
32
+ end
33
+ end
34
+
35
+ def configured?
36
+ Dir.chdir work_path do
37
+ !! (File.read('win32/Makefile.gcc') =~ /^BINARY_PATH/)
38
+ end
39
+ end
40
+
41
+ def compile
42
+ execute "compile", "make -f win32/Makefile.gcc"
43
+ end
44
+
45
+ def install
46
+ execute "install", "make -f win32/Makefile.gcc install"
47
+ end
48
+ end
49
+
50
+ checkpoint = "#{CROSS_DIR}/#{recipe.name}-#{recipe.version}.installed"
51
+ unless File.exist?(checkpoint)
52
+ recipe.cook
53
+ touch checkpoint
54
+ end
55
+ recipe.activate
56
+ end
57
+
58
+ task :libiconv do
59
+ recipe = $recipes[:libiconv]
60
+ recipe.files = ["http://ftp.gnu.org/pub/gnu/libiconv/#{recipe.name}-#{recipe.version}.tar.gz"]
61
+ recipe.configure_options = [
62
+ "--host=#{HOST}",
63
+ "--enable-static",
64
+ "--disable-shared",
65
+ "CPPFLAGS='-mno-cygwin -Wall'",
66
+ "CFLAGS='-mno-cygwin -O2 -g'",
67
+ "CXXFLAGS='-mno-cygwin -O2 -g'",
68
+ "LDFLAGS=-mno-cygwin"
69
+ ]
70
+
71
+ checkpoint = "#{CROSS_DIR}/#{recipe.name}-#{recipe.version}.installed"
72
+ unless File.exist?(checkpoint)
73
+ recipe.cook
74
+ touch checkpoint
75
+ end
76
+ recipe.activate
77
+ end
78
+
79
+ task :libxml2 => ["cross:zlib", "cross:libiconv"] do
80
+ recipe = $recipes[:libxml2]
81
+ recipe.files = ["ftp://ftp.xmlsoft.org/libxml2/#{recipe.name}-#{recipe.version}.tar.gz"]
82
+ recipe.configure_options = [
83
+ "--host=#{HOST}",
84
+ "--enable-static",
85
+ "--disable-shared",
86
+ "--with-zlib=#{CROSS_DIR}",
87
+ "--with-iconv=#{$recipes[:libiconv].path}",
88
+ "--without-python",
89
+ "--without-readline",
90
+ "CFLAGS='-DIN_LIBXML'"
91
+ ]
92
+ class << recipe
93
+ def download
94
+ Dir.chdir archives_path do
95
+ @files.each do |url|
96
+ sh "wget #{url} || curl -O #{url}"
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ checkpoint = "#{CROSS_DIR}/#{recipe.name}-#{recipe.version}.installed"
103
+ unless File.exist?(checkpoint)
104
+ recipe.cook
105
+ touch checkpoint
106
+ end
107
+ recipe.activate
108
+ end
109
+
110
+ task :libxslt => ['cross:libxml2'] do
111
+ recipe = $recipes[:libxslt]
112
+ recipe.files = ["ftp://ftp.xmlsoft.org/libxml2/#{recipe.name}-#{recipe.version}.tar.gz"]
113
+ recipe.configure_options = [
114
+ "--host=#{HOST}",
115
+ "--enable-static",
116
+ "--disable-shared",
117
+ "--with-libxml-prefix=#{$recipes[:libxml2].path}",
118
+ "--without-python",
119
+ "--without-crypto",
120
+ "CFLAGS='-DIN_LIBXML'"
121
+ ]
122
+ class << recipe
123
+ def download
124
+ Dir.chdir archives_path do
125
+ @files.each do |url|
126
+ sh "wget #{url} || curl -O #{url}"
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ checkpoint = "#{CROSS_DIR}/#{recipe.name}-#{recipe.version}.installed"
133
+ unless File.exist?(checkpoint)
134
+ recipe.cook
135
+ touch checkpoint
136
+ end
137
+ recipe.activate
138
+ end
139
+
140
+ task :file_list do
141
+ HOE.spec.files += Dir["lib/nokogiri/nokogiri.rb"]
142
+ HOE.spec.files += Dir["lib/nokogiri/1.{8,9}/nokogiri.so"]
143
+ end
144
+ end
145
+
146
+ HOE.clean_globs += [
147
+ "#{CROSS_DIR}/*.installed",
148
+ "#{CROSS_DIR}/#{HOST}",
149
+ "tmp/#{HOST}",
150
+ ]
151
+
152
+ task :cross => ["cross:libxslt", "lib/nokogiri/nokogiri.rb", "cross:file_list"]
@@ -0,0 +1,18 @@
1
+ namespace :docs do
2
+ desc "generate HTML docs for nokogiri.org"
3
+ task :website do
4
+ title = "#{HOE.name}-#{HOE.version} Documentation"
5
+
6
+ options = []
7
+ options << "--main=#{HOE.readme_file}"
8
+ options << '--format=activerecord'
9
+ options << '--threads=1'
10
+ options << "--title=#{title.inspect}"
11
+
12
+ options += HOE.spec.require_paths
13
+ options += HOE.spec.extra_rdoc_files
14
+ require 'rdoc/rdoc'
15
+ ENV['RAILS_ROOT'] ||= File.expand_path(File.join('..', 'nokogiri_ws'))
16
+ RDoc::RDoc.new.document options
17
+ end
18
+ end
data/tasks/test.rb ADDED
@@ -0,0 +1,94 @@
1
+ namespace :test do
2
+ desc "run test suite with aggressive GC"
3
+ task :gc => :build do
4
+ ENV['NOKOGIRI_GC'] = "true"
5
+ Rake::Task["test"].invoke
6
+ end
7
+
8
+ desc "find call-seq in the rdoc"
9
+ task :rdoc_call_seq => 'docs' do
10
+ Dir['doc/**/*.html'].each { |docfile|
11
+ next if docfile =~ /\.src/
12
+ puts "FAIL: #{docfile}" if File.read(docfile) =~ /call-seq/
13
+ }
14
+ end
15
+
16
+ desc "find all undocumented things"
17
+ task :rdoc => 'docs' do
18
+ base = File.expand_path(File.join(File.dirname(__FILE__), '..', 'doc'))
19
+ require 'test/unit'
20
+ test = Class.new(Test::Unit::TestCase)
21
+ Dir["#{base}/**/*.html"].each { |docfile|
22
+ test.class_eval(<<-eotest)
23
+ def test_#{docfile.sub("#{base}/", '').gsub(/[\/\.-]/, '_')}
24
+ assert_no_match(
25
+ /Not documented/,
26
+ File.read('#{docfile}'),
27
+ '#{docfile} has undocumented things'
28
+ )
29
+ end
30
+ eotest
31
+ }
32
+ end
33
+
34
+ desc "Test against multiple versions of libxml2 (MULTIXML2_DIR=directory)"
35
+ task :multixml2 do
36
+ MULTI_XML = File.join(ENV['HOME'], '.multixml2')
37
+ unless File.exists?(MULTI_XML)
38
+ %w{ versions install build }.each { |x|
39
+ FileUtils.mkdir_p(File.join(MULTI_XML, x))
40
+ }
41
+ Dir.chdir File.join(MULTI_XML, 'versions') do
42
+ require 'net/ftp'
43
+ ftp = Net::FTP.new('xmlsoft.org')
44
+ ftp.login('anonymous', 'anonymous')
45
+ ftp.chdir('libxml2')
46
+ ftp.list('libxml2-2.*.tar.gz').each do |x|
47
+ file = x[/[^\s]*$/]
48
+ puts "Downloading #{file}"
49
+ ftp.getbinaryfile(file)
50
+ end
51
+ end
52
+ end
53
+
54
+ # Build any libxml2 versions in $HOME/.multixml2/versions that
55
+ # haven't been built yet
56
+ Dir[File.join(MULTI_XML, 'versions','*.tar.gz')].each do |f|
57
+ filename = File.basename(f, '.tar.gz')
58
+
59
+ install_dir = File.join(MULTI_XML, 'install', filename)
60
+ next if File.exists?(install_dir)
61
+
62
+ Dir.chdir File.join(MULTI_XML, 'versions') do
63
+ system "tar zxvf #{f} -C #{File.join(MULTI_XML, 'build')}"
64
+ end
65
+
66
+ Dir.chdir File.join(MULTI_XML, 'build', filename) do
67
+ system "./configure --without-http --prefix=#{install_dir}"
68
+ system "make && make install"
69
+ end
70
+ end
71
+
72
+ test_results = {}
73
+ libxslt = Dir[File.join(MULTI_XML, 'install', 'libxslt*')].first
74
+
75
+ directories = ENV['MULTIXML2_DIR'] ? [ENV['MULTIXML2_DIR']] : Dir[File.join(MULTI_XML, 'install', '*')]
76
+ directories.sort.reverse_each do |xml2_version|
77
+ next unless xml2_version =~ /libxml2/
78
+ extopts = "--with-xml2-include=#{xml2_version}/include/libxml2 --with-xml2-lib=#{xml2_version}/lib --with-xslt-dir=#{libxslt} --with-iconv-dir=/usr"
79
+ cmd = "#{$0} clean test EXTOPTS='#{extopts}' LD_LIBRARY_PATH='#{xml2_version}/lib'"
80
+
81
+ version = File.basename(xml2_version)
82
+ result = system(cmd)
83
+ test_results[version] = {
84
+ :result => result,
85
+ :cmd => cmd
86
+ }
87
+ end
88
+ test_results.sort_by { |k,v| k }.each do |k,v|
89
+ passed = v[:result]
90
+ puts "#{k}: #{passed ? 'PASS' : 'FAIL'}"
91
+ puts "repro: #{v[:cmd]}" unless passed
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,159 @@
1
+ require "helper"
2
+
3
+ module Nokogiri
4
+ module CSS
5
+ class TestNthiness < Nokogiri::TestCase
6
+ def setup
7
+ super
8
+ doc = <<EOF
9
+ <html>
10
+ <table>
11
+ <tr><td>row1 </td></tr>
12
+ <tr><td>row2 </td></tr>
13
+ <tr><td>row3 </td></tr>
14
+ <tr><td>row4 </td></tr>
15
+ <tr><td>row5 </td></tr>
16
+ <tr><td>row6 </td></tr>
17
+ <tr><td>row7 </td></tr>
18
+ <tr><td>row8 </td></tr>
19
+ <tr><td>row9 </td></tr>
20
+ <tr><td>row10 </td></tr>
21
+ <tr><td>row11 </td></tr>
22
+ <tr><td>row12 </td></tr>
23
+ <tr><td>row13 </td></tr>
24
+ <tr><td>row14 </td></tr>
25
+ </table>
26
+ <div>
27
+ <b>bold1 </b>
28
+ <i>italic1 </i>
29
+ <b>bold2 </b>
30
+ <i>italic2 </i>
31
+ <p>para1 </p>
32
+ <b>bold3 </b>
33
+ </div>
34
+ <div>
35
+ <p>para2 </p>
36
+ <p>para3 </p>
37
+ </div>
38
+ <div>
39
+ <p>para4 </p>
40
+ </div>
41
+ <p class='empty'></p>
42
+ <p class='not-empty'><b></b></p>
43
+ </html>
44
+ EOF
45
+ @parser = Nokogiri.HTML doc
46
+ end
47
+
48
+
49
+ def test_even
50
+ assert_result_rows [2,4,6,8,10,12,14], @parser.search("table/tr:nth(even)")
51
+ end
52
+
53
+ def test_odd
54
+ assert_result_rows [1,3,5,7,9,11,13], @parser.search("table/tr:nth(odd)")
55
+ end
56
+
57
+ def test_2n
58
+ assert_equal @parser.search("table/tr:nth(even)").inner_text, @parser.search("table/tr:nth(2n)").inner_text
59
+ end
60
+
61
+ def test_2np1
62
+ assert_equal @parser.search("table/tr:nth(odd)").inner_text, @parser.search("table/tr:nth(2n+1)").inner_text
63
+ end
64
+
65
+ def test_4np3
66
+ assert_result_rows [3,7,11], @parser.search("table/tr:nth(4n+3)")
67
+ end
68
+
69
+ def test_3np4
70
+ assert_result_rows [4,7,10,13], @parser.search("table/tr:nth(3n+4)")
71
+ end
72
+
73
+ def test_mnp3
74
+ assert_result_rows [1,2,3], @parser.search("table/tr:nth(-n+3)")
75
+ end
76
+
77
+ def test_np3
78
+ assert_result_rows [3,4,5,6,7,8,9,10,11,12,13,14], @parser.search("table/tr:nth(n+3)")
79
+ end
80
+
81
+ def test_first
82
+ assert_result_rows [1], @parser.search("table/tr:first")
83
+ assert_result_rows [1], @parser.search("table/tr:first()")
84
+ end
85
+
86
+ def test_last
87
+ assert_result_rows [14], @parser.search("table/tr:last")
88
+ assert_result_rows [14], @parser.search("table/tr:last()")
89
+ end
90
+
91
+ def test_first_child
92
+ assert_result_rows [1], @parser.search("div/b:first-child"), "bold"
93
+ assert_result_rows [1], @parser.search("table/tr:first-child")
94
+ end
95
+
96
+ def test_last_child
97
+ assert_result_rows [3], @parser.search("div/b:last-child"), "bold"
98
+ assert_result_rows [14], @parser.search("table/tr:last-child")
99
+ end
100
+
101
+ def test_first_of_type
102
+ assert_result_rows [1], @parser.search("table/tr:first-of-type")
103
+ assert_result_rows [1], @parser.search("div/b:first-of-type"), "bold"
104
+ end
105
+
106
+ def test_last_of_type
107
+ assert_result_rows [14], @parser.search("table/tr:last-of-type")
108
+ assert_result_rows [3], @parser.search("div/b:last-of-type"), "bold"
109
+ end
110
+
111
+ def test_only_of_type
112
+ assert_result_rows [1,4], @parser.search("div/p:only-of-type"), "para"
113
+ end
114
+
115
+ def test_only_child
116
+ assert_result_rows [4], @parser.search("div/p:only-child"), "para"
117
+ end
118
+
119
+ def test_empty
120
+ result = @parser.search("p:empty")
121
+ assert_equal 1, result.size, "unexpected number of rows returned: '#{result.inner_text}'"
122
+ assert_equal 'empty', result.first['class']
123
+ end
124
+
125
+ def test_parent
126
+ result = @parser.search("p:parent")
127
+ assert_equal 5, result.size
128
+ 0.upto(3) do |j|
129
+ assert_equal "para#{j+1} ", result[j].inner_text
130
+ end
131
+ assert_equal "not-empty", result[4]['class']
132
+ end
133
+
134
+ def test_siblings
135
+ doc = <<-EOF
136
+ <html><body><div>
137
+ <p id="1">p1 </p>
138
+ <p id="2">p2 </p>
139
+ <p id="3">p3 </p>
140
+ <p id="4">p4 </p>
141
+ <p id="5">p5 </p>
142
+ EOF
143
+ parser = Nokogiri.HTML doc
144
+ assert_equal 2, parser.search("#3 ~ p").size
145
+ assert_equal "p4 p5 ", parser.search("#3 ~ p").inner_text
146
+ assert_equal 0, parser.search("#5 ~ p").size
147
+
148
+ assert_equal 1, parser.search("#3 + p").size
149
+ assert_equal "p4 ", parser.search("#3 + p").inner_text
150
+ assert_equal 0, parser.search("#5 + p").size
151
+ end
152
+
153
+ def assert_result_rows intarray, result, word="row"
154
+ assert_equal intarray.size, result.size, "unexpected number of rows returned: '#{result.inner_text}'"
155
+ assert_equal intarray.map{|j| "#{word}#{j}"}.join(' '), result.inner_text.strip, result.inner_text
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,303 @@
1
+ require "helper"
2
+
3
+ module Nokogiri
4
+ module CSS
5
+ class TestParser < Nokogiri::TestCase
6
+ def setup
7
+ super
8
+ @parser = Nokogiri::CSS::Parser.new
9
+ end
10
+
11
+ def test_extra_single_quote
12
+ assert_raises(CSS::SyntaxError) { @parser.parse("'") }
13
+ end
14
+
15
+ def test_syntax_error_raised
16
+ assert_raises(CSS::SyntaxError) { @parser.parse("a[x=]") }
17
+ end
18
+
19
+ def test_function_and_pseudo
20
+ assert_xpath '//child::text()[position() = 99]', @parser.parse('text():nth-of-type(99)')
21
+ end
22
+
23
+ def test_find_by_type
24
+ ast = @parser.parse("a:nth-child(2)").first
25
+ matches = ast.find_by_type(
26
+ [:CONDITIONAL_SELECTOR,
27
+ [:ELEMENT_NAME],
28
+ [:PSEUDO_CLASS,
29
+ [:FUNCTION]
30
+ ]
31
+ ]
32
+ )
33
+ assert_equal(1, matches.length)
34
+ assert_equal(ast, matches.first)
35
+ end
36
+
37
+ def test_to_type
38
+ ast = @parser.parse("a:nth-child(2)").first
39
+ assert_equal(
40
+ [:CONDITIONAL_SELECTOR,
41
+ [:ELEMENT_NAME],
42
+ [:PSEUDO_CLASS,
43
+ [:FUNCTION]
44
+ ]
45
+ ], ast.to_type
46
+ )
47
+ end
48
+
49
+ def test_to_a
50
+ asts = @parser.parse("a:nth-child(2)")
51
+ assert_equal(
52
+ [:CONDITIONAL_SELECTOR,
53
+ [:ELEMENT_NAME, ["a"]],
54
+ [:PSEUDO_CLASS,
55
+ [:FUNCTION, ["nth-child("], ["2"]]
56
+ ]
57
+ ], asts.first.to_a
58
+ )
59
+ end
60
+
61
+ def test_has
62
+ assert_xpath "//a[b]", @parser.parse("a:has(b)")
63
+ assert_xpath "//a[b/c]", @parser.parse("a:has(b > c)")
64
+ end
65
+
66
+ def test_dashmatch
67
+ assert_xpath "//a[@class = 'bar' or starts-with(@class, concat('bar', '-'))]",
68
+ @parser.parse("a[@class|='bar']")
69
+ assert_xpath "//a[@class = 'bar' or starts-with(@class, concat('bar', '-'))]",
70
+ @parser.parse("a[@class |= 'bar']")
71
+ end
72
+
73
+ def test_includes
74
+ assert_xpath "//a[contains(concat(\" \", @class, \" \"),concat(\" \", 'bar', \" \"))]",
75
+ @parser.parse("a[@class~='bar']")
76
+ assert_xpath "//a[contains(concat(\" \", @class, \" \"),concat(\" \", 'bar', \" \"))]",
77
+ @parser.parse("a[@class ~= 'bar']")
78
+ end
79
+
80
+ def test_function_with_arguments
81
+ assert_xpath "//*[position() = 2 and self::a]",
82
+ @parser.parse("a[2]")
83
+ assert_xpath "//*[position() = 2 and self::a]",
84
+ @parser.parse("a:nth-child(2)")
85
+ end
86
+
87
+ def test_carrot
88
+ assert_xpath "//a[starts-with(@id, 'Boing')]",
89
+ @parser.parse("a[id^='Boing']")
90
+ assert_xpath "//a[starts-with(@id, 'Boing')]",
91
+ @parser.parse("a[id ^= 'Boing']")
92
+ end
93
+
94
+ def test_suffix_match
95
+ assert_xpath "//a[substring(@id, string-length(@id) - string-length('Boing') + 1, string-length('Boing')) = 'Boing']",
96
+ @parser.parse("a[id$='Boing']")
97
+ assert_xpath "//a[substring(@id, string-length(@id) - string-length('Boing') + 1, string-length('Boing')) = 'Boing']",
98
+ @parser.parse("a[id $= 'Boing']")
99
+ end
100
+
101
+ def test_attributes_with_at
102
+ ## This is non standard CSS
103
+ assert_xpath "//a[@id = 'Boing']",
104
+ @parser.parse("a[@id='Boing']")
105
+ assert_xpath "//a[@id = 'Boing']",
106
+ @parser.parse("a[@id = 'Boing']")
107
+ end
108
+
109
+ def test_attributes_with_at_and_stuff
110
+ ## This is non standard CSS
111
+ assert_xpath "//a[@id = 'Boing']//div",
112
+ @parser.parse("a[@id='Boing'] div")
113
+ end
114
+
115
+ def test_not_equal
116
+ ## This is non standard CSS
117
+ assert_xpath "//a[child::text() != 'Boing']",
118
+ @parser.parse("a[text()!='Boing']")
119
+ assert_xpath "//a[child::text() != 'Boing']",
120
+ @parser.parse("a[text() != 'Boing']")
121
+ end
122
+
123
+ def test_function
124
+ ## This is non standard CSS
125
+ assert_xpath "//a[child::text()]",
126
+ @parser.parse("a[text()]")
127
+
128
+ ## This is non standard CSS
129
+ assert_xpath "//child::text()",
130
+ @parser.parse("text()")
131
+
132
+ ## This is non standard CSS
133
+ assert_xpath "//a[contains(child::text(), 'Boing')]",
134
+ @parser.parse("a[text()*='Boing']")
135
+ assert_xpath "//a[contains(child::text(), 'Boing')]",
136
+ @parser.parse("a[text() *= 'Boing']")
137
+
138
+ ## This is non standard CSS
139
+ assert_xpath "//script//comment()",
140
+ @parser.parse("script comment()")
141
+ end
142
+
143
+ def test_nonstandard_nth_selectors
144
+ ## These are non standard CSS
145
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first()')
146
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first') # no parens
147
+ assert_xpath '//a[position() = 99]', @parser.parse('a:eq(99)')
148
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth(99)')
149
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last()')
150
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last') # no parens
151
+ assert_xpath '//a[node()]', @parser.parse('a:parent')
152
+ end
153
+
154
+ def test_standard_nth_selectors
155
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type()')
156
+ assert_xpath '//a[position() = 1]', @parser.parse('a:first-of-type') # no parens
157
+ assert_xpath '//a[position() = 99]', @parser.parse('a:nth-of-type(99)')
158
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type()')
159
+ assert_xpath '//a[position() = last()]', @parser.parse('a:last-of-type') # no parens
160
+ assert_xpath '//a[position() = last()]', @parser.parse('a:nth-last-of-type(1)')
161
+ assert_xpath '//a[position() = last() - 98]', @parser.parse('a:nth-last-of-type(99)')
162
+ end
163
+
164
+ def test_nth_child_selectors
165
+ assert_xpath '//*[position() = 1 and self::a]', @parser.parse('a:first-child')
166
+ assert_xpath '//*[position() = 99 and self::a]', @parser.parse('a:nth-child(99)')
167
+ assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:last-child')
168
+ assert_xpath '//*[position() = last() and self::a]', @parser.parse('a:nth-last-child(1)')
169
+ assert_xpath '//*[position() = last() - 98 and self::a]', @parser.parse('a:nth-last-child(99)')
170
+ end
171
+
172
+ def test_miscellaneous_selectors
173
+ assert_xpath '//*[last() = 1 and self::a]',
174
+ @parser.parse('a:only-child')
175
+ assert_xpath '//a[last() = 1]', @parser.parse('a:only-of-type')
176
+ assert_xpath '//a[not(node())]', @parser.parse('a:empty')
177
+ end
178
+
179
+ def test_nth_a_n_plus_b
180
+ assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(2n)')
181
+ assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(2n+1)')
182
+ assert_xpath '//a[(position() mod 2) = 0]', @parser.parse('a:nth-of-type(even)')
183
+ assert_xpath '//a[(position() >= 1) and (((position()-1) mod 2) = 0)]', @parser.parse('a:nth-of-type(odd)')
184
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 4) = 0)]', @parser.parse('a:nth-of-type(4n+3)')
185
+ assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-1n+3)')
186
+ assert_xpath '//a[(position() <= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(-n+3)')
187
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(1n+3)')
188
+ assert_xpath '//a[(position() >= 3) and (((position()-3) mod 1) = 0)]', @parser.parse('a:nth-of-type(n+3)')
189
+
190
+ assert_xpath '//a[((last()-position()+1) mod 2) = 0]', @parser.parse('a:nth-last-of-type(2n)')
191
+ assert_xpath '//a[((last()-position()+1) >= 1) and ((((last()-position()+1)-1) mod 2) = 0)]', @parser.parse('a:nth-last-of-type(2n+1)')
192
+ assert_xpath '//a[((last()-position()+1) mod 2) = 0]', @parser.parse('a:nth-last-of-type(even)')
193
+ assert_xpath '//a[((last()-position()+1) >= 1) and ((((last()-position()+1)-1) mod 2) = 0)]', @parser.parse('a:nth-last-of-type(odd)')
194
+ assert_xpath '//a[((last()-position()+1) >= 3) and ((((last()-position()+1)-3) mod 4) = 0)]', @parser.parse('a:nth-last-of-type(4n+3)')
195
+ assert_xpath '//a[((last()-position()+1) <= 3) and ((((last()-position()+1)-3) mod 1) = 0)]', @parser.parse('a:nth-last-of-type(-1n+3)')
196
+ assert_xpath '//a[((last()-position()+1) <= 3) and ((((last()-position()+1)-3) mod 1) = 0)]', @parser.parse('a:nth-last-of-type(-n+3)')
197
+ assert_xpath '//a[((last()-position()+1) >= 3) and ((((last()-position()+1)-3) mod 1) = 0)]', @parser.parse('a:nth-last-of-type(1n+3)')
198
+ assert_xpath '//a[((last()-position()+1) >= 3) and ((((last()-position()+1)-3) mod 1) = 0)]', @parser.parse('a:nth-last-of-type(n+3)')
199
+ end
200
+
201
+ def test_preceding_selector
202
+ assert_xpath "//E/following-sibling::F",
203
+ @parser.parse("E ~ F")
204
+
205
+ assert_xpath "//E/following-sibling::F//G",
206
+ @parser.parse("E ~ F G")
207
+ end
208
+
209
+ def test_direct_preceding_selector
210
+ assert_xpath "//E/following-sibling::*[1]/self::F",
211
+ @parser.parse("E + F")
212
+
213
+ assert_xpath "//E/following-sibling::*[1]/self::F//G",
214
+ @parser.parse("E + F G")
215
+ end
216
+
217
+ def test_attribute
218
+ assert_xpath "//h1[@a = 'Tender Lovemaking']",
219
+ @parser.parse("h1[a='Tender Lovemaking']")
220
+ end
221
+
222
+ def test_id
223
+ assert_xpath "//*[@id = 'foo']", @parser.parse('#foo')
224
+ end
225
+
226
+ def test_pseudo_class_no_ident
227
+ assert_xpath "//*[link(.)]", @parser.parse(':link')
228
+ end
229
+
230
+ def test_pseudo_class
231
+ assert_xpath "//a[link(.)]", @parser.parse('a:link')
232
+ assert_xpath "//a[visited(.)]", @parser.parse('a:visited')
233
+ assert_xpath "//a[hover(.)]", @parser.parse('a:hover')
234
+ assert_xpath "//a[active(.)]", @parser.parse('a:active')
235
+ assert_xpath "//a[active(.) and contains(concat(' ', @class, ' '), ' foo ')]",
236
+ @parser.parse('a:active.foo')
237
+ end
238
+
239
+ def test_star
240
+ assert_xpath "//*", @parser.parse('*')
241
+ assert_xpath "//*[contains(concat(' ', @class, ' '), ' pastoral ')]",
242
+ @parser.parse('*.pastoral')
243
+ end
244
+
245
+ def test_class
246
+ assert_xpath "//*[contains(concat(' ', @class, ' '), ' a ') and contains(concat(' ', @class, ' '), ' b ')]",
247
+ @parser.parse('.a.b')
248
+ assert_xpath "//*[contains(concat(' ', @class, ' '), ' awesome ')]",
249
+ @parser.parse('.awesome')
250
+ assert_xpath "//foo[contains(concat(' ', @class, ' '), ' awesome ')]",
251
+ @parser.parse('foo.awesome')
252
+ assert_xpath "//foo//*[contains(concat(' ', @class, ' '), ' awesome ')]",
253
+ @parser.parse('foo .awesome')
254
+ end
255
+
256
+ def test_not_so_simple_not
257
+ assert_xpath "//*[@id = 'p' and not(contains(concat(' ', @class, ' '), ' a '))]",
258
+ @parser.parse('#p:not(.a)')
259
+ assert_xpath "//p[contains(concat(' ', @class, ' '), ' a ') and not(contains(concat(' ', @class, ' '), ' b '))]",
260
+ @parser.parse('p.a:not(.b)')
261
+ assert_xpath "//p[@a = 'foo' and not(contains(concat(' ', @class, ' '), ' b '))]",
262
+ @parser.parse("p[a='foo']:not(.b)")
263
+ end
264
+
265
+ def test_ident
266
+ assert_xpath '//x', @parser.parse('x')
267
+ end
268
+
269
+ def test_parse_space
270
+ assert_xpath '//x//y', @parser.parse('x y')
271
+ end
272
+
273
+ def test_parse_descendant
274
+ assert_xpath '//x/y', @parser.parse('x > y')
275
+ end
276
+
277
+ def test_parse_slash
278
+ ## This is non standard CSS
279
+ assert_xpath '//x/y', @parser.parse('x/y')
280
+ end
281
+
282
+ def test_parse_doubleslash
283
+ ## This is non standard CSS
284
+ assert_xpath '//x//y', @parser.parse('x//y')
285
+ end
286
+
287
+ def test_multi_path
288
+ assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y, y > z')
289
+ assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y,y > z')
290
+ ###
291
+ # TODO: should we make this work?
292
+ # assert_xpath ['//x/y', '//y/z'], @parser.parse('x > y | y > z')
293
+ end
294
+
295
+ def assert_xpath expecteds, asts
296
+ expecteds = [expecteds].flatten
297
+ expecteds.zip(asts).each do |expected, actual|
298
+ assert_equal expected, actual.to_xpath
299
+ end
300
+ end
301
+ end
302
+ end
303
+ end