Skip to content
This repository
Newer
Older
100644 532 lines (466 sloc) 17.178 kb
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
1 require 'strscan'
2
c23b2a4a » jamis
2005-06-14 Updated vendor copy of html-scanner lib, for bug fixes and optimizations
3 module HTML #:nodoc:
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
4
c23b2a4a » jamis
2005-06-14 Updated vendor copy of html-scanner lib, for bug fixes and optimizations
5 class Conditions < Hash #:nodoc:
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
6 def initialize(hash)
7 super()
8 hash = { :content => hash } unless Hash === hash
9 hash = keys_to_symbols(hash)
10 hash.each do |k,v|
11 case k
12 when :tag, :content then
13 # keys are valid, and require no further processing
14 when :attributes then
15 hash[k] = keys_to_strings(v)
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
16 when :parent, :child, :ancestor, :descendant, :sibling, :before,
17 :after
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
18 hash[k] = Conditions.new(v)
19 when :children
20 hash[k] = v = keys_to_symbols(v)
1ab2ab07 » miloops
2010-09-27 Remove more warnings shadowing outer local variable.
21 v.each do |key,value|
583ddf22 » miloops
2010-09-22 Remove more warnings shadowing outer local variable.
22 case key
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
23 when :count, :greater_than, :less_than
24 # keys are valid, and require no further processing
25 when :only
1ab2ab07 » miloops
2010-09-27 Remove more warnings shadowing outer local variable.
26 v[key] = Conditions.new(value)
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
27 else
1ab2ab07 » miloops
2010-09-27 Remove more warnings shadowing outer local variable.
28 raise "illegal key #{key.inspect} => #{value.inspect}"
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
29 end
30 end
31 else
32 raise "illegal key #{k.inspect} => #{v.inspect}"
33 end
34 end
35 update hash
36 end
37
38 private
39
40 def keys_to_strings(hash)
10a63e2a » miloops
2010-09-22 Refactor methods in html node to avoid injects.
41 Hash[hash.keys.map {|k| [k.to_s, hash[k]]}]
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
42 end
43
44 def keys_to_symbols(hash)
10a63e2a » miloops
2010-09-22 Refactor methods in html node to avoid injects.
45 Hash[hash.keys.map do |k|
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
46 raise "illegal key #{k.inspect}" unless k.respond_to?(:to_sym)
10a63e2a » miloops
2010-09-22 Refactor methods in html node to avoid injects.
47 [k.to_sym, hash[k]]
48 end]
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
49 end
50 end
51
52 # The base class of all nodes, textual and otherwise, in an HTML document.
c23b2a4a » jamis
2005-06-14 Updated vendor copy of html-scanner lib, for bug fixes and optimizations
53 class Node #:nodoc:
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
54 # The array of children of this node. Not all nodes have children.
55 attr_reader :children
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
56
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
57 # The parent node of this node. All nodes have a parent, except for the
58 # root node.
59 attr_reader :parent
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
60
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
61 # The line number of the input where this node was begun
62 attr_reader :line
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
63
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
64 # The byte position in the input where this node was begun
65 attr_reader :position
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
66
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
67 # Create a new node as a child of the given parent.
68 def initialize(parent, line=0, pos=0)
69 @parent = parent
70 @children = []
71 @line, @position = line, pos
72 end
73
74 # Return a textual representation of the node.
75 def to_s
46c14a6b » tchandy
2010-08-29 Use join instead of looping and calling to_s [#5492 state:resolved]
76 @children.join()
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
77 end
78
79 # Return false (subclasses must override this to provide specific matching
80 # behavior.) +conditions+ may be of any type.
81 def match(conditions)
82 false
83 end
84
85 # Search the children of this node for the first node for which #find
86 # returns non +nil+. Returns the result of the #find call that succeeded.
87 def find(conditions)
c23b2a4a » jamis
2005-06-14 Updated vendor copy of html-scanner lib, for bug fixes and optimizations
88 conditions = validate_conditions(conditions)
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
89 @children.each do |child|
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
90 node = child.find(conditions)
91 return node if node
92 end
93 nil
94 end
95
96 # Search for all nodes that match the given conditions, and return them
97 # as an array.
98 def find_all(conditions)
c23b2a4a » jamis
2005-06-14 Updated vendor copy of html-scanner lib, for bug fixes and optimizations
99 conditions = validate_conditions(conditions)
100
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
101 matches = []
102 matches << self if match(conditions)
103 @children.each do |child|
104 matches.concat child.find_all(conditions)
105 end
106 matches
107 end
108
109 # Returns +false+. Subclasses may override this if they define a kind of
110 # tag.
111 def tag?
112 false
113 end
114
115 def validate_conditions(conditions)
116 Conditions === conditions ? conditions : Conditions.new(conditions)
117 end
7f26415d » dhh
2005-09-20 Optimized tag_options to not sort keys, which is no longer necessary …
118
119 def ==(node)
120 return false unless self.class == node.class && children.size == node.children.size
121
122 equivalent = true
123
124 children.size.times do |i|
125 equivalent &&= children[i] == node.children[i]
126 end
127
128 equivalent
129 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
130
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
131 class <<self
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
132 def parse(parent, line, pos, content, strict=true)
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
133 if content !~ /^<\S/
134 Text.new(parent, line, pos, content)
135 else
136 scanner = StringScanner.new(content)
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
137
138 unless scanner.skip(/</)
139 if strict
140 raise "expected <"
141 else
142 return Text.new(parent, line, pos, content)
143 end
144 end
145
f9b19904 » jamis
2005-11-21 Update html-scanner to handle CDATA sections better. Closes #2970. [J…
146 if scanner.skip(/!\[CDATA\[/)
1a182272 » packagethief
2008-10-22 Fix that HTML::Node.parse would blow up on unclosed CDATA sections.
147 unless scanner.skip_until(/\]\]>/)
148 if strict
149 raise "expected ]]> (got #{scanner.rest.inspect} for #{content})"
150 else
151 scanner.skip_until(/\Z/)
152 end
153 end
154
19fbb314 » technoweenie
2007-02-04 Add much-needed html-scanner tests. Fixed CDATA parsing bug. [Rick]
155 return CDATA.new(parent, line, pos, scanner.pre_match.gsub(/<!\[CDATA\[/, ''))
f9b19904 » jamis
2005-11-21 Update html-scanner to handle CDATA sections better. Closes #2970. [J…
156 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
157
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
158 closing = ( scanner.scan(/\//) ? :close : nil )
586a944d » tenderlove
2011-08-16 Tags with invalid names should also be stripped in order to prevent
159 return Text.new(parent, line, pos, content) unless name = scanner.scan(/[^\s!>\/]+/)
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
160 name.downcase!
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
161
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
162 unless closing
163 scanner.skip(/\s*/)
164 attributes = {}
165 while attr = scanner.scan(/[-\w:]+/)
166 value = true
167 if scanner.scan(/\s*=\s*/)
168 if delim = scanner.scan(/['"]/)
169 value = ""
170 while text = scanner.scan(/[^#{delim}\\]+|./)
171 case text
172 when "\\" then
173 value << text
2002e587 » nono
2010-06-26 Strip_tags never ending attribute should not raise a TypeError [#4870
174 break if scanner.eos?
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
175 value << scanner.getch
176 when delim
177 break
178 else value << text
179 end
180 end
181 else
182 value = scanner.scan(/[^\s>\/]+/)
183 end
184 end
185 attributes[attr.downcase] = value
186 scanner.skip(/\s*/)
187 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
188
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
189 closing = ( scanner.scan(/\//) ? :self : nil )
190 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
191
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
192 unless scanner.scan(/\s*>/)
193 if strict
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
194 raise "expected > (got #{scanner.rest.inspect} for #{content}, #{attributes.inspect})"
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
195 else
196 # throw away all text until we find what we're looking for
197 scanner.skip_until(/>/) or scanner.terminate
198 end
199 end
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
200
201 Tag.new(parent, line, pos, name, attributes, closing)
202 end
203 end
204 end
205 end
206
207 # A node that represents text, rather than markup.
c23b2a4a » jamis
2005-06-14 Updated vendor copy of html-scanner lib, for bug fixes and optimizations
208 class Text < Node #:nodoc:
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
209
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
210 attr_reader :content
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
211
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
212 # Creates a new text node as a child of the given parent, with the given
213 # content.
214 def initialize(parent, line, pos, content)
215 super(parent, line, pos)
216 @content = content
217 end
218
219 # Returns the content of this node.
220 def to_s
221 @content
222 end
223
224 # Returns +self+ if this node meets the given conditions. Text nodes support
225 # conditions of the following kinds:
226 #
227 # * if +conditions+ is a string, it must be a substring of the node's
228 # content
229 # * if +conditions+ is a regular expression, it must match the node's
230 # content
231 # * if +conditions+ is a hash, it must contain a <tt>:content</tt> key that
232 # is either a string or a regexp, and which is interpreted as described
233 # above.
234 def find(conditions)
235 match(conditions) && self
236 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
237
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
238 # Returns non-+nil+ if this node meets the given conditions, or +nil+
239 # otherwise. See the discussion of #find for the valid conditions.
240 def match(conditions)
241 case conditions
242 when String
3f0952d9 » jamis
2006-09-10 Fix assert_tag so that :content => "foo" does not match substrings, b…
243 @content == conditions
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
244 when Regexp
245 @content =~ conditions
246 when Hash
247 conditions = validate_conditions(conditions)
248
249 # Text nodes only have :content, :parent, :ancestor
250 unless (conditions.keys - [:content, :parent, :ancestor]).empty?
251 return false
252 end
253
254 match(conditions[:content])
255 else
256 nil
257 end
258 end
7f26415d » dhh
2005-09-20 Optimized tag_options to not sort keys, which is no longer necessary …
259
260 def ==(node)
261 return false unless super
262 content == node.content
263 end
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
264 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
265
f9b19904 » jamis
2005-11-21 Update html-scanner to handle CDATA sections better. Closes #2970. [J…
266 # A CDATA node is simply a text node with a specialized way of displaying
267 # itself.
32b27f99 » dhh
2005-12-08 Remove insignificant classes from docs
268 class CDATA < Text #:nodoc:
f9b19904 » jamis
2005-11-21 Update html-scanner to handle CDATA sections better. Closes #2970. [J…
269 def to_s
3bcadc92 » packagethief
2008-10-22 Fix incorrect closing CDATA delimiter. Add tests for CDATA nodes.
270 "<![CDATA[#{super}]]>"
f9b19904 » jamis
2005-11-21 Update html-scanner to handle CDATA sections better. Closes #2970. [J…
271 end
272 end
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
273
274 # A Tag is any node that represents markup. It may be an opening tag, a
275 # closing tag, or a self-closing tag. It has a name, and may have a hash of
276 # attributes.
c23b2a4a » jamis
2005-06-14 Updated vendor copy of html-scanner lib, for bug fixes and optimizations
277 class Tag < Node #:nodoc:
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
278
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
279 # Either +nil+, <tt>:close</tt>, or <tt>:self</tt>
280 attr_reader :closing
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
281
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
282 # Either +nil+, or a hash of attributes for this node.
283 attr_reader :attributes
284
285 # The name of this tag.
286 attr_reader :name
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
287
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
288 # Create a new node as a child of the given parent, using the given content
289 # to describe the node. It will be parsed and the node name, attributes and
290 # closing status extracted.
291 def initialize(parent, line, pos, name, attributes, closing)
292 super(parent, line, pos)
293 @name = name
294 @attributes = attributes
295 @closing = closing
296 end
297
298 # A convenience for obtaining an attribute of the node. Returns +nil+ if
299 # the node has no attributes.
300 def [](attr)
301 @attributes ? @attributes[attr] : nil
302 end
303
304 # Returns non-+nil+ if this tag can contain child nodes.
bfdb4375 » jamis
2005-09-05 Updated vendor copy of html-scanner to support better xml parsing
305 def childless?(xml = false)
306 return false if xml && @closing.nil?
c23b2a4a » jamis
2005-06-14 Updated vendor copy of html-scanner lib, for bug fixes and optimizations
307 !@closing.nil? ||
308 @name =~ /^(img|br|hr|link|meta|area|base|basefont|
309 col|frame|input|isindex|param)$/ox
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
310 end
311
312 # Returns a textual representation of the node
313 def to_s
314 if @closing == :close
315 "</#{@name}>"
316 else
317 s = "<#{@name}"
b167248b » dhh
2005-05-09 Fixed the HTML scanner used by assert_tag where a infinite loop could…
318 @attributes.each do |k,v|
319 s << " #{k}"
d833645c » technoweenie
2006-12-14 Fix HTML::Node to output double quotes instead of single quotes. Closes
320 s << "=\"#{v}\"" if String === v
b167248b » dhh
2005-05-09 Fixed the HTML scanner used by assert_tag where a infinite loop could…
321 end
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
322 s << " /" if @closing == :self
323 s << ">"
324 @children.each { |child| s << child.to_s }
c23b2a4a » jamis
2005-06-14 Updated vendor copy of html-scanner lib, for bug fixes and optimizations
325 s << "</#{@name}>" if @closing != :self && !@children.empty?
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
326 s
327 end
328 end
329
330 # If either the node or any of its children meet the given conditions, the
331 # matching node is returned. Otherwise, +nil+ is returned. (See the
332 # description of the valid conditions in the +match+ method.)
333 def find(conditions)
334 match(conditions) && self || super
335 end
336
337 # Returns +true+, indicating that this node represents an HTML tag.
338 def tag?
339 true
340 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
341
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
342 # Returns +true+ if the node meets any of the given conditions. The
343 # +conditions+ parameter must be a hash of any of the following keys
344 # (all are optional):
345 #
346 # * <tt>:tag</tt>: the node name must match the corresponding value
347 # * <tt>:attributes</tt>: a hash. The node's values must match the
348 # corresponding values in the hash.
349 # * <tt>:parent</tt>: a hash. The node's parent must match the
350 # corresponding hash.
351 # * <tt>:child</tt>: a hash. At least one of the node's immediate children
352 # must meet the criteria described by the hash.
353 # * <tt>:ancestor</tt>: a hash. At least one of the node's ancestors must
354 # meet the criteria described by the hash.
355 # * <tt>:descendant</tt>: a hash. At least one of the node's descendants
356 # must meet the criteria described by the hash.
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
357 # * <tt>:sibling</tt>: a hash. At least one of the node's siblings must
358 # meet the criteria described by the hash.
359 # * <tt>:after</tt>: a hash. The node must be after any sibling meeting
360 # the criteria described by the hash, and at least one sibling must match.
361 # * <tt>:before</tt>: a hash. The node must be before any sibling meeting
362 # the criteria described by the hash, and at least one sibling must match.
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
363 # * <tt>:children</tt>: a hash, for counting children of a node. Accepts the
364 # keys:
365 # ** <tt>:count</tt>: either a number or a range which must equal (or
366 # include) the number of children that match.
367 # ** <tt>:less_than</tt>: the number of matching children must be less than
368 # this number.
369 # ** <tt>:greater_than</tt>: the number of matching children must be
370 # greater than this number.
371 # ** <tt>:only</tt>: another hash consisting of the keys to use
372 # to match on the children, and only matching children will be
373 # counted.
374 #
375 # Conditions are matched using the following algorithm:
376 #
377 # * if the condition is a string, it must be a substring of the value.
378 # * if the condition is a regexp, it must match the value.
379 # * if the condition is a number, the value must match number.to_s.
380 # * if the condition is +true+, the value must not be +nil+.
381 # * if the condition is +false+ or +nil+, the value must be +nil+.
382 #
383 # Usage:
384 #
385 # # test if the node is a "span" tag
386 # node.match :tag => "span"
387 #
388 # # test if the node's parent is a "div"
389 # node.match :parent => { :tag => "div" }
390 #
391 # # test if any of the node's ancestors are "table" tags
392 # node.match :ancestor => { :tag => "table" }
393 #
394 # # test if any of the node's immediate children are "em" tags
395 # node.match :child => { :tag => "em" }
396 #
397 # # test if any of the node's descendants are "strong" tags
398 # node.match :descendant => { :tag => "strong" }
399 #
400 # # test if the node has between 2 and 4 span tags as immediate children
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
401 # node.match :children => { :count => 2..4, :only => { :tag => "span" } }
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
402 #
403 # # get funky: test to see if the node is a "div", has a "ul" ancestor
404 # # and an "li" parent (with "class" = "enum"), and whether or not it has
405 # # a "span" descendant that contains # text matching /hello world/:
406 # node.match :tag => "div",
407 # :ancestor => { :tag => "ul" },
408 # :parent => { :tag => "li",
409 # :attributes => { :class => "enum" } },
410 # :descendant => { :tag => "span",
411 # :child => /hello world/ }
412 def match(conditions)
413 conditions = validate_conditions(conditions)
930f3365 » jamis
2005-07-04 Updated html-scanner so that assert_tag(:tag => "p", :content => "foo…
414 # check content of child nodes
f783d50c » jamis
2005-11-21 Allow assert_tag(:conditions) to match the empty string when a tag ha…
415 if conditions[:content]
416 if children.empty?
417 return false unless match_condition("", conditions[:content])
418 else
419 return false unless children.find { |child| child.match(conditions[:content]) }
420 end
421 end
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
422
423 # test the name
424 return false unless match_condition(@name, conditions[:tag]) if conditions[:tag]
425
426 # test attributes
427 (conditions[:attributes] || {}).each do |key, value|
428 return false unless match_condition(self[key], value)
429 end
430
431 # test parent
432 return false unless parent.match(conditions[:parent]) if conditions[:parent]
433
434 # test children
435 return false unless children.find { |child| child.match(conditions[:child]) } if conditions[:child]
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
436
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
437 # test ancestors
438 if conditions[:ancestor]
439 return false unless catch :found do
440 p = self
441 throw :found, true if p.match(conditions[:ancestor]) while p = p.parent
442 end
443 end
444
445 # test descendants
446 if conditions[:descendant]
447 return false unless children.find do |child|
448 # test the child
449 child.match(conditions[:descendant]) ||
450 # test the child's descendants
451 child.match(:descendant => conditions[:descendant])
452 end
453 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
454
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
455 # count children
456 if opts = conditions[:children]
e515ba9e » jamis
2005-10-18 Fix the html-scanner to count children correctly, playing nicely with…
457 matches = children.select do |c|
458 (c.kind_of?(HTML::Tag) and (c.closing == :self or ! c.childless?))
459 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
460
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
461 matches = matches.select { |c| c.match(opts[:only]) } if opts[:only]
462 opts.each do |key, value|
463 next if key == :only
464 case key
465 when :count
466 if Integer === value
467 return false if matches.length != value
468 else
469 return false unless value.include?(matches.length)
470 end
471 when :less_than
472 return false unless matches.length < value
473 when :greater_than
474 return false unless matches.length > value
475 else raise "unknown count condition #{key}"
476 end
477 end
478 end
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
479
480 # test siblings
481 if conditions[:sibling] || conditions[:before] || conditions[:after]
482 siblings = parent ? parent.children : []
483 self_index = siblings.index(self)
484
485 if conditions[:sibling]
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
486 return false unless siblings.detect do |s|
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
487 s != self && s.match(conditions[:sibling])
488 end
489 end
490
491 if conditions[:before]
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
492 return false unless siblings[self_index+1..-1].detect do |s|
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
493 s != self && s.match(conditions[:before])
494 end
495 end
496
497 if conditions[:after]
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
498 return false unless siblings[0,self_index].detect do |s|
409bc097 » dhh
2005-05-06 Added functionality to assert_tag, so you can now do tests on the sib…
499 s != self && s.match(conditions[:after])
500 end
501 end
502 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
503
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
504 true
505 end
506
7f26415d » dhh
2005-09-20 Optimized tag_options to not sort keys, which is no longer necessary …
507 def ==(node)
508 return false unless super
509 return false unless closing == node.closing && self.name == node.name
510 attributes == node.attributes
511 end
b451de0d » spastorino
2010-08-14 Deletes trailing whitespaces (over text files only find * -type f -ex…
512
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
513 private
514 # Match the given value to the given condition.
515 def match_condition(value, condition)
516 case condition
517 when String
b7ce9c5a » jamis
2005-11-09 assert_tag uses exact matches for string conditions, instead of parti…
518 value && value == condition
806cf6d7 » dhh
2005-04-17 Added assert_tag and assert_no_tag as a much improved alternative to …
519 when Regexp
520 value && value.match(condition)
521 when Numeric
522 value == condition.to_s
523 when true
524 !value.nil?
525 when false, nil
526 value.nil?
527 else
528 false
529 end
530 end
531 end
532 end
Something went wrong with that request. Please try again.