glue 0.41.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. data/History.txt +6 -0
  2. data/Manifest.txt +6 -0
  3. data/README.txt +130 -0
  4. data/Rakefile +16 -0
  5. data/lib/glue.rb +49 -72
  6. data/test/test_glue.rb +218 -0
  7. metadata +84 -100
  8. data/doc/AUTHORS +0 -13
  9. data/doc/CHANGELOG.1 +0 -354
  10. data/doc/LICENSE +0 -32
  11. data/doc/RELEASES +0 -207
  12. data/lib/glue/attribute.rb +0 -113
  13. data/lib/glue/attributeutils.rb +0 -117
  14. data/lib/glue/autoreload.rb +0 -60
  15. data/lib/glue/builder.rb +0 -57
  16. data/lib/glue/builder/xml.rb +0 -103
  17. data/lib/glue/cache.rb +0 -22
  18. data/lib/glue/cache/drb.rb +0 -51
  19. data/lib/glue/cache/file.rb +0 -78
  20. data/lib/glue/cache/memcached.rb +0 -68
  21. data/lib/glue/cache/memory.rb +0 -79
  22. data/lib/glue/cache/og.rb +0 -61
  23. data/lib/glue/configuration.rb +0 -305
  24. data/lib/glue/fixture.rb +0 -154
  25. data/lib/glue/html.rb +0 -12
  26. data/lib/glue/localization.rb +0 -129
  27. data/lib/glue/logger.rb +0 -208
  28. data/lib/glue/mail.rb +0 -160
  29. data/lib/glue/mailer.rb +0 -55
  30. data/lib/glue/mailer/incoming.rb +0 -41
  31. data/lib/glue/mailer/outgoing.rb +0 -119
  32. data/lib/glue/settings.rb +0 -3
  33. data/lib/glue/uri.rb +0 -190
  34. data/lib/glue/validation.rb +0 -447
  35. data/lib/html/document.rb +0 -63
  36. data/lib/html/node.rb +0 -480
  37. data/lib/html/tokenizer.rb +0 -103
  38. data/lib/html/version.rb +0 -11
  39. data/test/fixture/article.csv +0 -3
  40. data/test/fixture/article.yml +0 -13
  41. data/test/fixture/user.yml +0 -12
  42. data/test/glue/builder/tc_xml.rb +0 -57
  43. data/test/glue/tc_aspects.rb +0 -99
  44. data/test/glue/tc_attribute.rb +0 -112
  45. data/test/glue/tc_attribute_mixins.rb +0 -86
  46. data/test/glue/tc_builder.rb +0 -30
  47. data/test/glue/tc_configuration.rb +0 -135
  48. data/test/glue/tc_fixture.rb +0 -98
  49. data/test/glue/tc_localization.rb +0 -49
  50. data/test/glue/tc_logger.rb +0 -43
  51. data/test/glue/tc_mail.rb +0 -99
  52. data/test/glue/tc_stores.rb +0 -16
  53. data/test/glue/tc_uri.rb +0 -97
  54. data/test/glue/tc_validation.rb +0 -217
  55. data/test/public/dummy_mailer/registration.xhtml +0 -5
data/lib/html/document.rb DELETED
@@ -1,63 +0,0 @@
1
- require 'html/tokenizer'
2
- require 'html/node'
3
-
4
- module HTML#:nodoc:
5
-
6
- # A top-level HTMl document. You give it a body of text, and it will parse that
7
- # text into a tree of nodes.
8
- class Document #:nodoc:
9
-
10
- # The root of the parsed document.
11
- attr_reader :root
12
-
13
- # Create a new Document from the given text.
14
- def initialize(text)
15
- tokenizer = Tokenizer.new(text)
16
- @root = Node.new(nil)
17
- node_stack = [ @root ]
18
- while token = tokenizer.next
19
- node = Node.parse(node_stack.last, tokenizer.line, tokenizer.position, token)
20
-
21
- node_stack.last.children << node unless node.tag? && node.closing == :close
22
- if node.tag? && !node.childless?
23
- if node_stack.length > 1 && node.closing == :close
24
- if node_stack.last.name == node.name
25
- node_stack.pop
26
- else
27
- open_start = node_stack.last.position - 20
28
- open_start = 0 if open_start < 0
29
- close_start = node.position - 20
30
- close_start = 0 if close_start < 0
31
- warn <<EOF.strip
32
- ignoring attempt to close #{node_stack.last.name} with #{node.name}
33
- opened at byte #{node_stack.last.position}, line #{node_stack.last.line}
34
- closed at byte #{node.position}, line #{node.line}
35
- attributes at open: #{node_stack.last.attributes.inspect}
36
- text around open: #{text[open_start,40].inspect}
37
- text around close: #{text[close_start,40].inspect}
38
- EOF
39
- end
40
- elsif node.closing != :close
41
- node_stack.push node
42
- end
43
- end
44
- end
45
- end
46
-
47
- # Search the tree for (and return) the first node that matches the given
48
- # conditions. The conditions are interpreted differently for different node
49
- # types, see HTML::Text#find and HTML::Tag#find.
50
- def find(conditions)
51
- @root.find(conditions)
52
- end
53
-
54
- # Search the tree for (and return) all nodes that match the given
55
- # conditions. The conditions are interpreted differently for different node
56
- # types, see HTML::Text#find and HTML::Tag#find.
57
- def find_all(conditions)
58
- @root.find_all(conditions)
59
- end
60
-
61
- end
62
-
63
- end
data/lib/html/node.rb DELETED
@@ -1,480 +0,0 @@
1
- require 'strscan'
2
-
3
- module HTML#:nodoc:
4
-
5
- class Conditions < Hash#:nodoc:
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)
16
- when :parent, :child, :ancestor, :descendant, :sibling, :before,
17
- :after
18
- hash[k] = Conditions.new(v)
19
- when :children
20
- hash[k] = v = keys_to_symbols(v)
21
- v.each do |k,v2|
22
- case k
23
- when :count, :greater_than, :less_than
24
- # keys are valid, and require no further processing
25
- when :only
26
- v[k] = Conditions.new(v2)
27
- else
28
- raise "illegal key #{k.inspect} => #{v2.inspect}"
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)
41
- hash.keys.inject({}) do |h,k|
42
- h[k.to_s] = hash[k]
43
- h
44
- end
45
- end
46
-
47
- def keys_to_symbols(hash)
48
- hash.keys.inject({}) do |h,k|
49
- raise "illegal key #{k.inspect}" unless k.respond_to?(:to_sym)
50
- h[k.to_sym] = hash[k]
51
- h
52
- end
53
- end
54
- end
55
-
56
- # The base class of all nodes, textual and otherwise, in an HTML document.
57
- class Node#:nodoc:
58
- # The array of children of this node. Not all nodes have children.
59
- attr_reader :children
60
-
61
- # The parent node of this node. All nodes have a parent, except for the
62
- # root node.
63
- attr_reader :parent
64
-
65
- # The line number of the input where this node was begun
66
- attr_reader :line
67
-
68
- # The byte position in the input where this node was begun
69
- attr_reader :position
70
-
71
- # Create a new node as a child of the given parent.
72
- def initialize(parent, line=0, pos=0)
73
- @parent = parent
74
- @children = []
75
- @line, @position = line, pos
76
- end
77
-
78
- # Return a textual representation of the node.
79
- def to_s
80
- s = ""
81
- @children.each { |child| s << child.to_s }
82
- s
83
- end
84
-
85
- # Return false (subclasses must override this to provide specific matching
86
- # behavior.) +conditions+ may be of any type.
87
- def match(conditions)
88
- false
89
- end
90
-
91
- # Search the children of this node for the first node for which #find
92
- # returns non +nil+. Returns the result of the #find call that succeeded.
93
- def find(conditions)
94
- @children.each do |child|
95
- node = child.find(conditions)
96
- return node if node
97
- end
98
- nil
99
- end
100
-
101
- # Search for all nodes that match the given conditions, and return them
102
- # as an array.
103
- def find_all(conditions)
104
- matches = []
105
- matches << self if match(conditions)
106
- @children.each do |child|
107
- matches.concat child.find_all(conditions)
108
- end
109
- matches
110
- end
111
-
112
- # Returns +false+. Subclasses may override this if they define a kind of
113
- # tag.
114
- def tag?
115
- false
116
- end
117
-
118
- def validate_conditions(conditions)
119
- Conditions === conditions ? conditions : Conditions.new(conditions)
120
- end
121
-
122
- class <<self
123
- def parse(parent, line, pos, content, strict=true)
124
- if content !~ /^<\S/
125
- Text.new(parent, line, pos, content)
126
- else
127
- scanner = StringScanner.new(content)
128
-
129
- unless scanner.skip(/</)
130
- if strict
131
- raise "expected <"
132
- else
133
- return Text.new(parent, line, pos, content)
134
- end
135
- end
136
-
137
- closing = ( scanner.scan(/\//) ? :close : nil )
138
- return Text.new(parent, line, pos, content) unless name = scanner.scan(/[\w:]+/)
139
- name.downcase!
140
-
141
- unless closing
142
- scanner.skip(/\s*/)
143
- attributes = {}
144
- while attr = scanner.scan(/[-\w:]+/)
145
- value = true
146
- if scanner.scan(/\s*=\s*/)
147
- if delim = scanner.scan(/['"]/)
148
- value = ""
149
- while text = scanner.scan(/[^#{delim}\\]+|./)
150
- case text
151
- when "\\" then
152
- value << text
153
- value << scanner.getch
154
- when delim
155
- break
156
- else value << text
157
- end
158
- end
159
- else
160
- value = scanner.scan(/[^\s>\/]+/)
161
- end
162
- end
163
- attributes[attr.downcase] = value
164
- scanner.skip(/\s*/)
165
- end
166
-
167
- closing = ( scanner.scan(/\//) ? :self : nil )
168
- end
169
-
170
- unless scanner.scan(/\s*>/)
171
- if strict
172
- raise "expected > (got #{scanner.rest.inspect} for #{content}, #{attributes.inspect})"
173
- else
174
- # throw away all text until we find what we're looking for
175
- scanner.skip_until(/>/) or scanner.terminate
176
- end
177
- end
178
-
179
- Tag.new(parent, line, pos, name, attributes, closing)
180
- end
181
- end
182
- end
183
- end
184
-
185
- # A node that represents text, rather than markup.
186
- class Text < Node#:nodoc:
187
-
188
- attr_reader :content
189
-
190
- # Creates a new text node as a child of the given parent, with the given
191
- # content.
192
- def initialize(parent, line, pos, content)
193
- super(parent, line, pos)
194
- @content = content
195
- end
196
-
197
- # Returns the content of this node.
198
- def to_s
199
- @content
200
- end
201
-
202
- # Returns +self+ if this node meets the given conditions. Text nodes support
203
- # conditions of the following kinds:
204
- #
205
- # * if +conditions+ is a string, it must be a substring of the node's
206
- # content
207
- # * if +conditions+ is a regular expression, it must match the node's
208
- # content
209
- # * if +conditions+ is a hash, it must contain a <tt>:content</tt> key that
210
- # is either a string or a regexp, and which is interpreted as described
211
- # above.
212
- def find(conditions)
213
- match(conditions) && self
214
- end
215
-
216
- # Returns non-+nil+ if this node meets the given conditions, or +nil+
217
- # otherwise. See the discussion of #find for the valid conditions.
218
- def match(conditions)
219
- case conditions
220
- when String
221
- @content.index(conditions)
222
- when Regexp
223
- @content =~ conditions
224
- when Hash
225
- conditions = validate_conditions(conditions)
226
-
227
- # Text nodes only have :content, :parent, :ancestor
228
- unless (conditions.keys - [:content, :parent, :ancestor]).empty?
229
- return false
230
- end
231
-
232
- match(conditions[:content])
233
- else
234
- nil
235
- end
236
- end
237
- end
238
-
239
- # A Tag is any node that represents markup. It may be an opening tag, a
240
- # closing tag, or a self-closing tag. It has a name, and may have a hash of
241
- # attributes.
242
- class Tag < Node#:nodoc:
243
-
244
- # Either +nil+, <tt>:close</tt>, or <tt>:self</tt>
245
- attr_reader :closing
246
-
247
- # Either +nil+, or a hash of attributes for this node.
248
- attr_reader :attributes
249
-
250
- # The name of this tag.
251
- attr_reader :name
252
-
253
- # Create a new node as a child of the given parent, using the given content
254
- # to describe the node. It will be parsed and the node name, attributes and
255
- # closing status extracted.
256
- def initialize(parent, line, pos, name, attributes, closing)
257
- super(parent, line, pos)
258
- @name = name
259
- @attributes = attributes
260
- @closing = closing
261
- end
262
-
263
- # A convenience for obtaining an attribute of the node. Returns +nil+ if
264
- # the node has no attributes.
265
- def [](attr)
266
- @attributes ? @attributes[attr] : nil
267
- end
268
-
269
- # Returns non-+nil+ if this tag can contain child nodes.
270
- def childless?
271
- @name =~ /^(img|br|hr|link|meta|area|base|basefont|col|frame|input|isindex|param)$/o
272
- end
273
-
274
- # Returns a textual representation of the node
275
- def to_s
276
- if @closing == :close
277
- "</#{@name}>"
278
- else
279
- s = "<#{@name}"
280
- @attributes.each do |k,v|
281
- s << " #{k}"
282
- s << "='#{v.gsub(/'/,"\\\\'")}'" if String === v
283
- end
284
- s << " /" if @closing == :self
285
- s << ">"
286
- @children.each { |child| s << child.to_s }
287
- s
288
- end
289
- end
290
-
291
- # If either the node or any of its children meet the given conditions, the
292
- # matching node is returned. Otherwise, +nil+ is returned. (See the
293
- # description of the valid conditions in the +match+ method.)
294
- def find(conditions)
295
- match(conditions) && self || super
296
- end
297
-
298
- # Returns +true+, indicating that this node represents an HTML tag.
299
- def tag?
300
- true
301
- end
302
-
303
- # Returns +true+ if the node meets any of the given conditions. The
304
- # +conditions+ parameter must be a hash of any of the following keys
305
- # (all are optional):
306
- #
307
- # * <tt>:tag</tt>: the node name must match the corresponding value
308
- # * <tt>:attributes</tt>: a hash. The node's values must match the
309
- # corresponding values in the hash.
310
- # * <tt>:parent</tt>: a hash. The node's parent must match the
311
- # corresponding hash.
312
- # * <tt>:child</tt>: a hash. At least one of the node's immediate children
313
- # must meet the criteria described by the hash.
314
- # * <tt>:ancestor</tt>: a hash. At least one of the node's ancestors must
315
- # meet the criteria described by the hash.
316
- # * <tt>:descendant</tt>: a hash. At least one of the node's descendants
317
- # must meet the criteria described by the hash.
318
- # * <tt>:sibling</tt>: a hash. At least one of the node's siblings must
319
- # meet the criteria described by the hash.
320
- # * <tt>:after</tt>: a hash. The node must be after any sibling meeting
321
- # the criteria described by the hash, and at least one sibling must match.
322
- # * <tt>:before</tt>: a hash. The node must be before any sibling meeting
323
- # the criteria described by the hash, and at least one sibling must match.
324
- # * <tt>:children</tt>: a hash, for counting children of a node. Accepts the
325
- # keys:
326
- # ** <tt>:count</tt>: either a number or a range which must equal (or
327
- # include) the number of children that match.
328
- # ** <tt>:less_than</tt>: the number of matching children must be less than
329
- # this number.
330
- # ** <tt>:greater_than</tt>: the number of matching children must be
331
- # greater than this number.
332
- # ** <tt>:only</tt>: another hash consisting of the keys to use
333
- # to match on the children, and only matching children will be
334
- # counted.
335
- #
336
- # Conditions are matched using the following algorithm:
337
- #
338
- # * if the condition is a string, it must be a substring of the value.
339
- # * if the condition is a regexp, it must match the value.
340
- # * if the condition is a number, the value must match number.to_s.
341
- # * if the condition is +true+, the value must not be +nil+.
342
- # * if the condition is +false+ or +nil+, the value must be +nil+.
343
- #
344
- # Usage:
345
- #
346
- # # test if the node is a "span" tag
347
- # node.match :tag => "span"
348
- #
349
- # # test if the node's parent is a "div"
350
- # node.match :parent => { :tag => "div" }
351
- #
352
- # # test if any of the node's ancestors are "table" tags
353
- # node.match :ancestor => { :tag => "table" }
354
- #
355
- # # test if any of the node's immediate children are "em" tags
356
- # node.match :child => { :tag => "em" }
357
- #
358
- # # test if any of the node's descendants are "strong" tags
359
- # node.match :descendant => { :tag => "strong" }
360
- #
361
- # # test if the node has between 2 and 4 span tags as immediate children
362
- # node.match :children => { :count => 2..4, :only => { :tag => "span" } }
363
- #
364
- # # get funky: test to see if the node is a "div", has a "ul" ancestor
365
- # # and an "li" parent (with "class" = "enum"), and whether or not it has
366
- # # a "span" descendant that contains # text matching /hello world/:
367
- # node.match :tag => "div",
368
- # :ancestor => { :tag => "ul" },
369
- # :parent => { :tag => "li",
370
- # :attributes => { :class => "enum" } },
371
- # :descendant => { :tag => "span",
372
- # :child => /hello world/ }
373
- def match(conditions)
374
- conditions = validate_conditions(conditions)
375
-
376
- # only Text nodes have content
377
- return false if conditions[:content]
378
-
379
- # test the name
380
- return false unless match_condition(@name, conditions[:tag]) if conditions[:tag]
381
-
382
- # test attributes
383
- (conditions[:attributes] || {}).each do |key, value|
384
- return false unless match_condition(self[key], value)
385
- end
386
-
387
- # test parent
388
- return false unless parent.match(conditions[:parent]) if conditions[:parent]
389
-
390
- # test children
391
- return false unless children.find { |child| child.match(conditions[:child]) } if conditions[:child]
392
-
393
- # test ancestors
394
- if conditions[:ancestor]
395
- return false unless catch :found do
396
- p = self
397
- throw :found, true if p.match(conditions[:ancestor]) while p = p.parent
398
- end
399
- end
400
-
401
- # test descendants
402
- if conditions[:descendant]
403
- return false unless children.find do |child|
404
- # test the child
405
- child.match(conditions[:descendant]) ||
406
- # test the child's descendants
407
- child.match(:descendant => conditions[:descendant])
408
- end
409
- end
410
-
411
- # count children
412
- if opts = conditions[:children]
413
- matches = children
414
- matches = matches.select { |c| c.match(opts[:only]) } if opts[:only]
415
- opts.each do |key, value|
416
- next if key == :only
417
- case key
418
- when :count
419
- if Integer === value
420
- return false if matches.length != value
421
- else
422
- return false unless value.include?(matches.length)
423
- end
424
- when :less_than
425
- return false unless matches.length < value
426
- when :greater_than
427
- return false unless matches.length > value
428
- else raise "unknown count condition #{key}"
429
- end
430
- end
431
- end
432
-
433
- # test siblings
434
- if conditions[:sibling] || conditions[:before] || conditions[:after]
435
- siblings = parent ? parent.children : []
436
- self_index = siblings.index(self)
437
-
438
- if conditions[:sibling]
439
- return false unless siblings.detect do |s|
440
- s != self && s.match(conditions[:sibling])
441
- end
442
- end
443
-
444
- if conditions[:before]
445
- return false unless siblings[self_index+1..-1].detect do |s|
446
- s != self && s.match(conditions[:before])
447
- end
448
- end
449
-
450
- if conditions[:after]
451
- return false unless siblings[0,self_index].detect do |s|
452
- s != self && s.match(conditions[:after])
453
- end
454
- end
455
- end
456
-
457
- true
458
- end
459
-
460
- private
461
-
462
- # Match the given value to the given condition.
463
- def match_condition(value, condition)
464
- case condition
465
- when String
466
- value && value.index(condition)
467
- when Regexp
468
- value && value.match(condition)
469
- when Numeric
470
- value == condition.to_s
471
- when true
472
- !value.nil?
473
- when false, nil
474
- value.nil?
475
- else
476
- false
477
- end
478
- end
479
- end
480
- end