assert2 0.3.2 → 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,87 @@
1
+ require 'test/unit'
2
+
3
+
4
+ module Test; module Unit; module Assertions
5
+
6
+ # Assert that a block raises a given Exception type matching
7
+ # a given message
8
+ #
9
+ # * +types+ - single exception class or array of classes
10
+ # * +matcher+ - Regular Expression to match the inner_text of XML nodes
11
+ # * +diagnostic+ - optional string to add to failure message
12
+ # * +block+ - Ruby statements that should raise an exception
13
+ #
14
+ # Examples:
15
+ # %transclude AssertXPathSuite#test_assert_raise_message_detects_assertion_failure
16
+ #
17
+ # %transclude AssertXPathSuite#test_assert_raise_message_raises_message
18
+ #
19
+ # See: {assert_raise - Don't Just Say "No"}[http://www.oreillynet.com/onlamp/blog/2007/07/assert_raise_on_ruby_dont_just.html]
20
+ #
21
+ def assert_raise_message(types, expected_message, message = nil, &block)
22
+ args = [types].flatten + [message]
23
+ exception = _assert_raise(*args, &block)
24
+ exception_message = exception.message.dup
25
+
26
+ if expected_message.kind_of? String
27
+ exception_message.gsub!(/^\s+/, '') # if we cosmetically strip leading spaces from both the matcher and matchee,
28
+ expected_message.gsub!(/^\s+/, '') # then multi-line assert_flunk messages are easier on the eyes!
29
+ expected_message = Regexp.escape(expected_message)
30
+ end
31
+
32
+ assert message do
33
+ exception_message.match(expected_message)
34
+ end
35
+
36
+ return exception.message
37
+ end
38
+
39
+ # TODO rebuild this
40
+ def deny_raise_message(types, matcher, diagnostic = nil, &block) #:nodoc:
41
+ exception = assert_raise_message(types, //, diagnostic, &block)
42
+
43
+ assert_no_match matcher,
44
+ exception.message,
45
+ [ diagnostic,
46
+ "exception #{ exception.class.name
47
+ } with this message should not raise from block:",
48
+ "\t"+reflect_source(&block).split("\n").join("\n\t")
49
+ ].compact.join("\n")
50
+
51
+ return exception.message
52
+ end
53
+
54
+ def assert_flunk(matcher, message = nil, &block)
55
+ assert_raise_message FlunkError, matcher, message, &block
56
+ end
57
+
58
+ # TODO reinstall ruby-1.9.0 and pass all cross-tests!!
59
+
60
+ def _assert_raise(*args)
61
+ # _wrap_assertion do
62
+ if Module === args.last
63
+ message = ""
64
+ else
65
+ message = args.pop
66
+ end
67
+ exceptions, modules = args, [] # _check_exception_class(args)
68
+
69
+ expected = args.size == 1 ? args.first : args
70
+ actual_exception = nil
71
+ full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
72
+ assert_block(full_message) do
73
+ begin
74
+ yield
75
+ rescue Exception => actual_exception
76
+ break
77
+ end
78
+ false
79
+ end
80
+ full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
81
+ assert_block(full_message) {exceptions.include?(actual_exception.class)}
82
+ actual_exception
83
+ # end
84
+ end
85
+
86
+ end; end; end
87
+
File without changes
@@ -0,0 +1,182 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <title><%= @title %></title>
6
+ <meta http-equiv="content-type" content="text/html; charset=us-ascii" />
7
+ <script type="text/javascript" src="javascript/prototype.js"></script>
8
+ <script type="text/javascript" src="javascript/effects.js"></script>
9
+ <script type="text/javascript" src="javascript/accordion.js"></script>
10
+ <link rel="stylesheet" type="text/css" href="css/default.css" />
11
+ <script type="text/javascript">
12
+ //<![CDATA[
13
+
14
+ var bottomAccordion = 42;
15
+
16
+ function raise(id)
17
+ {
18
+ var anchor = $(id + '_');
19
+ if (anchor) {
20
+ bottomAccordion.activate(anchor.parentNode);
21
+ }
22
+ }
23
+
24
+ Event.observe(window, 'load', loadAccordions, false);
25
+ function loadAccordions() {
26
+ bottomAccordion = new accordion('vertical_container');
27
+
28
+ var anchor = window.location.href.match(/#(.+)$/);
29
+ if (anchor) anchor = anchor[1];
30
+ if (anchor = $(anchor + '_')) {
31
+ bottomAccordion.activate(anchor.parentNode);
32
+ }
33
+ else {
34
+ bottomAccordion.activate($$('#vertical_container .accordion_toggle')[0]);
35
+ }
36
+ }
37
+ //]]>
38
+ </script>
39
+
40
+ <style type="text/css">
41
+ /*<![CDATA[*/
42
+ /* Vertical Accordions */
43
+
44
+ pre { border-width: 10px;
45
+ border-color: #e7e7c9;
46
+ border-style: solid;
47
+ }
48
+
49
+ .accordion_toggle {
50
+ display: block;
51
+ height: 30px;
52
+ width: 680px;
53
+ background: url(images/accordion_toggle.png) no-repeat top right;
54
+ padding: 0 10px 0 10px;
55
+ cursor: index;
56
+ font-weight: normal;
57
+ text-decoration: none;
58
+ outline: none;
59
+ font-family: 'Lucida Grande', Verdana, Arial;
60
+ color: #800;
61
+ cursor: pointer;
62
+ margin: 0 0 0 0;
63
+ }
64
+
65
+ .accordion_toggle_active {
66
+ background: url(images/accordion_toggle_active.png) no-repeat top right;
67
+ color: #FDE;
68
+ }
69
+
70
+ .accordion_content {
71
+ background-color: #ffffff;
72
+ color: #444444;
73
+ overflow: hidden;
74
+ }
75
+
76
+ .accordion_content h2 {
77
+ margin: 15px 0 5px 10px;
78
+ color: #0099FF;
79
+ }
80
+
81
+ .accordion_content p {
82
+ padding: 5px 10px 0 10px;
83
+ }
84
+
85
+ /*
86
+ Horizontal Accordion
87
+ */
88
+
89
+ .horizontal_accordion_toggle {
90
+ /* REQUIRED */
91
+ float: left; /* This make sure it stays horizontal */
92
+ /* REQUIRED */
93
+
94
+ display: block;
95
+ height: 100px;
96
+ width: 30px;
97
+ background: url(images/h_accordion_toggle.png) no-repeat top left #a9d06a;
98
+ color: #ffffff;
99
+ text-decoration: none;
100
+ outline: none;
101
+ border-right: 1px solid #cde99f;
102
+ cursor: pointer;
103
+ margin: 0 0 0 0;
104
+ }
105
+
106
+ .horizontal_accordion_toggle_active {
107
+ background: url(images/h_accordion_toggle_active.png) no-repeat top left #e0542f;
108
+ border-right: 1px solid #f68263;
109
+ }
110
+
111
+ .horizontal_accordion_content {
112
+ /* REQUIRED */
113
+ height: 100px; /* We need to define a height for the accordion as it stretches the width */
114
+ float: left; /* This make sure it stays horizontal */
115
+ /* REQUIRED */
116
+
117
+ overflow: hidden;
118
+ background-color: #ffffff;
119
+ color: #444444;
120
+ }
121
+
122
+ .horizontal_accordion_content p {
123
+ width: 450px;
124
+ /*line-height: 125%;*/
125
+ padding: 5px 10px 15px 10px;
126
+ }
127
+
128
+
129
+ /* Container styling*/
130
+ #horizontal_container {
131
+ margin: 20px auto 20px auto;
132
+ width: 680px;
133
+ height: 100px;
134
+ }
135
+
136
+ /*#vertical_nested_container {
137
+ margin: 20px auto 20px auto;
138
+ width: 620px;
139
+ }*/
140
+
141
+ /*]]>*/
142
+ </style>
143
+ </head>
144
+
145
+ <body style="font-family: Times,serif; background-image: url(images/sky_blue.png); background-repeat: repeat-x;">
146
+ <div style='position: absolute; top: 0px; left: 70%;'>
147
+ <a href="http://validator.w3.org/check/referer">
148
+ <img border='0' height="76" width="72" alt='Validates this page at W3C'
149
+ src="http://assert2.rubyforge.org/the_test_button.png"/>
150
+ </a>
151
+ </div>
152
+
153
+ <div id="container">
154
+
155
+ <h1><code><big style='color: #008;'><%= @title %></big></code></h1>
156
+
157
+ <div id="vertical_container">
158
+ <%= @sauce %>
159
+ </div>
160
+
161
+ <div class="page-footer">
162
+ <p>Accordion is &#169; Copyright 2007 <a href="http://www.stickmanlabs.com"><small>stickmanlabs</small></a> - MIT-style license</p>
163
+ </div>
164
+ </div>
165
+ <br />
166
+ <script type="text/javascript">
167
+ //<![CDATA[
168
+ //
169
+ // You can hide the accordions on page load like this, it maintains accessibility
170
+ //
171
+ // Special thanks go out to Will Shaver @ http://primedigit.com/
172
+ //
173
+ var verticalAccordions = $$('.accordion_toggle');
174
+ verticalAccordions.each(function(accordion) {
175
+ $(accordion.next(0)).setStyle({
176
+ height: '0px'
177
+ });
178
+ });
179
+ //]]>
180
+ </script>
181
+ </body>
182
+ </html>
@@ -0,0 +1,413 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ripper'
4
+ require 'stringio'
5
+ require 'cgi'
6
+ require 'erb'
7
+ require 'optparse'
8
+ require 'pathname'
9
+
10
+ # TODO reflect the banner anchor at generation time, to figure out what to hotlink to
11
+
12
+ class Ripdoc < Ripper::Filter
13
+ HomePath = (Pathname.new(__FILE__).dirname + '../..').expand_path
14
+
15
+ STYLES = {
16
+ CHAR: 'color: brown; font-weight: bolder;',
17
+ const: "color: #FF4F00; font-weight: bolder;",
18
+ backref: "color: #f4f; font-weight: bolder;",
19
+ comment: "font-style: italic; color: #446; font-family: Times; font-size: 110%;",
20
+ # TODO use "font: Times italic 110%" to save space
21
+ embdoc: "background-color: #FFe; font-family: Times; font-size: 133%;",
22
+ embdoc_beg: "display: none;",
23
+ embdoc_end: "display: none;",
24
+ embexpr: "background-color: #ccc;",
25
+ embexpr_delimiter: "background-color: #aaa;",
26
+ gvar: "color: #8f5902; font-weight: bolder;",
27
+ ivar: "color: #240;",
28
+ int: "color: #336600; font-weight: bolder;",
29
+ operator: "font-weight: bolder; font-size: 120%;",
30
+ kw: "color: purple;",
31
+ regexp_delimiter: "background-color: #faf;",
32
+ regexp: "background-color: #fcf;",
33
+ string: "background-color: white;", #dfc
34
+ string_delimiter: "background-color: #cfa;",
35
+ symbol: "color: #066;",
36
+ tstring_content: 'background: url(images/tstring.png) right;',
37
+ tstring_internal: 'background: url(images/tstring.png) right;', # TODO merge these two!
38
+ tregexp_content: 'background: url(images/hot_pink.png);'
39
+ }
40
+
41
+ def self.generate(filename, title)
42
+ @sauce = compile_fragment(File.read(filename))
43
+ @title = title
44
+ @string_background = :tstring_content
45
+ erb = ERB.new((HomePath + 'lib/assert2/ripdoc.html.erb').read, nil, '>')
46
+ xhtml = erb.result(binding())
47
+ xhtml.gsub! /\<pre>\s*\<\/pre>/m, ''
48
+ xhtml.gsub! /\<p>\s*\<\/p>/m, ''
49
+ return xhtml
50
+ end
51
+
52
+ def dequote(attributes)
53
+ return attributes.gsub('&quot;', '"')
54
+ end # TODO complex '"? if we can't it might be a good thing...
55
+
56
+ def enline(line)
57
+ line = CGI.escapeHTML(line)
58
+ return line.gsub( /&lt;a(.*?)&gt;/){ "<a #{dequote($1)}>" }.
59
+ gsub('&lt;/a&gt;', '</a>').
60
+ gsub(/&lt;br\s*\/&gt;/, '<br/>').
61
+ gsub( '&lt;code&gt;', '<code style="font-weight: bolder; font-style: normal;">').
62
+ gsub('&lt;/code&gt;', '</code>').
63
+ gsub( '&lt;em&gt;', '<em>').
64
+ gsub('&lt;/em&gt;', '</em>').
65
+ gsub( '&lt;li&gt;', '<li>').
66
+ gsub('&lt;/li&gt;', '</li>').
67
+ gsub( '&lt;ul&gt;', '<ul>').
68
+ gsub('&lt;/ul&gt;', '</ul>').
69
+ gsub('&amp;mdash;', '&mdash;')
70
+ end
71
+
72
+ def deformat(line, f)
73
+ if line =~ /^\s/ # CONSIDER why the line-height broke??
74
+ f << "</p>" if @owed_p
75
+ f << "<pre style='line-height: 75%;'>\n" unless @owed_pre
76
+ @owed_p = false
77
+ @owed_pre = true
78
+ f << enline(line) << "\n"
79
+ return
80
+ end
81
+
82
+ f << '</pre>' if @owed_pre
83
+ @owed_pre = false
84
+ f << '<p>' unless @owed_p
85
+ @owed_p = true
86
+ f << enline(line)
87
+ end
88
+
89
+ def on_embdoc_beg(tok, f)
90
+ return f if @in_no_doc
91
+ @embdocs = []
92
+ f << "</pre>\n" if @owed_pre
93
+ @owed_pre = false
94
+ return f
95
+ # on_kw tok, f, 'embdoc_beg'
96
+ end
97
+
98
+ def is_no_doc?(tok)
99
+ tok.strip =~ /^\#\!nodoc\!/ or tok.strip =~ /^\#\!no_doc\!/
100
+ end
101
+
102
+ def on_embdoc(tok, f)
103
+ return f if @in_no_doc
104
+
105
+ if is_no_doc? tok
106
+ @in_no_doc = true
107
+ else
108
+ @embdocs << tok
109
+ end
110
+
111
+ return f
112
+ end
113
+
114
+ def on_embdoc_end(tok, f)
115
+ return f if @in_no_doc
116
+ return end_panel(f)
117
+ return f
118
+ end
119
+
120
+ def name_toggle(banner)
121
+ banner = banner.gsub(/<.*?>/, '').
122
+ gsub(/&.*?;/, '').
123
+ scan(/[ _[:alnum:]]/).
124
+ map{|x| x == ' ' ? '_' : x }.
125
+ join.
126
+ gsub(/_+/, '_').
127
+ gsub(/_$/, '')
128
+
129
+ return "<a href='#' name='#{banner}' id='#{banner}_'></a>" # CONSIDER this can't use <a ../> because enline() would mangle it...
130
+ # CONSIDER the _ is due to a bug in libxml - it squeaks at a name and id that are the same -
131
+ # despite that's a common idiom!
132
+ end
133
+
134
+ def end_panel(f)
135
+ if banner = @embdocs.shift # accordion_toggle_active
136
+ f << '<h1 class="accordion_toggle">'
137
+ f << name_toggle(banner)
138
+ f << enline(banner)
139
+ f << '</h1>'
140
+ end
141
+
142
+ f << '<div class="accordion_content">'
143
+ f << '<p>'
144
+ @owed_p = true
145
+ prior = false
146
+
147
+ @embdocs.each do |doc|
148
+ if doc.strip == ''
149
+ f << "</p>\n<p>" if @owed_p
150
+ prior = false
151
+ elsif doc.strip =~ /^\#\!link\!(.*)/ #!link!froot!loop
152
+ target, contents = $1.split('!') # TODO permit a ! in the contents
153
+ puts '#!link!anchor!text tags work best with text after the last bang!' unless contents
154
+ contents ||= ''
155
+ f << "<a href='\##{target}' onclick='raise(\"#{target}\")'>"
156
+ f << enline(contents)
157
+ f << '</a>'
158
+ else
159
+ f << ' ' if prior
160
+ deformat(doc, f)
161
+ prior = true
162
+ end
163
+ end
164
+
165
+ f << '</p>' if @owed_p
166
+ f << '<pre>' unless @owed_pre
167
+ @owed_pre = true
168
+ @embdocs = []
169
+ return f
170
+ end
171
+
172
+ # TODO need a tregexp_content to distinguish them!
173
+
174
+ def span(kode)
175
+ if STYLES[kode.to_sym]
176
+ # class="#{kode}"
177
+ return %Q[<span style="#{STYLES[kode.to_sym]}">]
178
+ else
179
+ return '<span>'
180
+ end
181
+ end
182
+
183
+ def spanit(kode, f, tok)
184
+ @spans_owed ||= 0
185
+ @spans_owed += 1
186
+ f << span(kode) << CGI.escapeHTML(tok)
187
+ end
188
+
189
+ def on_kw(tok, f, klass = 'kw')
190
+ return f if @in_no_doc
191
+ f << span(klass) << CGI.escapeHTML(tok)
192
+ f << '</span>'
193
+ end
194
+
195
+ def on_comment(tok, f)
196
+ if tok.strip =~ /^\#\!end_panel\!/
197
+ f << '</pre>' if @owed_pre
198
+ @owed_pre = false
199
+ f << '</div>'
200
+ return f
201
+ end
202
+
203
+ nodoc = is_no_doc?(tok)
204
+
205
+ if !nodoc and !@in_no_doc and tok.strip !~ /^\s*#\!/
206
+ f << span(:comment) << enline(tok.rstrip) << '</span>'
207
+ on_nl nil, f
208
+ end
209
+
210
+ @in_no_doc ||= nodoc
211
+ @in_no_doc = nil if tok.strip =~ /^\#\!doc\!/
212
+ return f
213
+ end
214
+
215
+ def on_CHAR(tok, f)
216
+ return f if @in_no_doc
217
+ on_kw tok, f, 'CHAR'
218
+ return f
219
+ end
220
+
221
+ # TODO linefeeds inside %w() and possibly ''
222
+ # TODO colorize :"" and :"#{}" correctly
223
+
224
+ def on_default(event, tok, f)
225
+ return f if @in_no_doc
226
+
227
+ if @symbol_begun
228
+ @symbol_begun = false
229
+ f << %Q[#{span(:symbol)}#{CGI.escapeHTML(tok)}</span>]
230
+ elsif tok =~ /^[[:punct:]]+$/
231
+ f << %Q[#{span(:operator)}#{CGI.escapeHTML(tok)}</span>]
232
+ else
233
+ on_kw tok, f, event.to_s.sub(/^on_/, '')
234
+ end
235
+
236
+ return f
237
+ end
238
+
239
+ def finish_one_span(f)
240
+ if @spans_owed > 0
241
+ f << '</span>'
242
+ @spans_owed -= 1
243
+ end
244
+ end
245
+
246
+ def on_tstring_beg(tok, f)
247
+ return f if @in_no_doc
248
+ @spans_owed += 1
249
+ f << span(:string)
250
+ @string_background = :tstring_content
251
+ f << %Q[#{span(:string_delimiter)}#{CGI.escapeHTML(tok)}</span>]
252
+ end
253
+
254
+ def on_tstring_content(tok, f, style = 'tstring_content')
255
+ tok.split(/\n/).each_with_index do |sub_tok, index|
256
+ if index == 0
257
+ on_string_stretch(sub_tok, f, style)
258
+ else
259
+ space, sub_tok = sub_tok.scan(/(\s*)(.*)/).first
260
+ f << space
261
+ on_string_stretch(sub_tok, f, style)
262
+ end
263
+ end
264
+ return f
265
+ end
266
+
267
+ def on_string_stretch(tok, f, klass = 'TODO remove me')
268
+ return f if @in_no_doc
269
+ f << span(@string_background.to_s) << CGI.escapeHTML(tok)
270
+ f << '</span>'
271
+ end
272
+
273
+ # TODO fix end-of-delim bug in // and %w() and %{} etc
274
+
275
+ def on_tstring_end(tok, f)
276
+ return f if @in_no_doc
277
+
278
+ if tok.length > 1
279
+ margin, content, tok = tok.scan(/^(\s*)(.*)(.)$/).first
280
+ f << margin if margin
281
+ on_tstring_content content, f, 'tstring_internal' if content # TODO is this used??
282
+ end
283
+
284
+ f << %Q[#{span(:string_delimiter)}#{CGI.escapeHTML(tok.to_s)}</span>]
285
+ finish_one_span(f)
286
+ return f
287
+ end # TODO report to ripper author the bug where on_tstring_end contains the whole string
288
+
289
+ def on_regexp_beg(tok, f)
290
+ return f if @in_no_doc
291
+ @spans_owed += 1
292
+ f << span(:regexp)
293
+ @string_background = :tregexp_content
294
+ f << %Q[#{span(:regexp_delimiter)}#{CGI.escapeHTML(tok)}</span>]
295
+ end
296
+
297
+ def on_regexp_end(tok, f)
298
+ return f if @in_no_doc
299
+ f << %Q[#{span(:regexp_delimiter)}#{CGI.escapeHTML(tok)}</span>]
300
+ finish_one_span(f)
301
+ return f
302
+ end
303
+
304
+ def on_embexpr_beg(tok, f)
305
+ return f if @in_no_doc
306
+ spanit :embexpr, f, tok
307
+ return f
308
+ end # TODO don't interrupt a span or nothing with a nodoc!
309
+
310
+ # TODO single-line mode for nodoc
311
+
312
+ def on_ignored_nl(tok, f)
313
+ return f if @in_no_doc
314
+ on_nl nil, f
315
+ end
316
+
317
+ def on_nl(tok, f)
318
+ return f if @in_no_doc
319
+ f << "\n"
320
+ end
321
+
322
+ def on_lbrace(tok, f)
323
+ return f if @in_no_doc
324
+ spanit '', f, '' # tok CONSIDER wonder who is actually emitting the { ??
325
+ f << tok
326
+ end
327
+
328
+ def on_rbrace(tok, f)
329
+ return f if @in_no_doc
330
+ f << tok
331
+ finish_one_span(f) # TODO these things might wrap lines!
332
+ return f
333
+ end
334
+
335
+ def on_symbeg(tok, f)
336
+ return f if @in_no_doc
337
+ on_default(:on_symbeg, tok, f)
338
+ @symbol_begun = true
339
+ return f
340
+ end
341
+
342
+ # TODO syntax hilite the inner language of regices? how about XPathics?
343
+ # escapes in strings??
344
+
345
+ def on_ivar(tok, f)
346
+ return f if @in_no_doc
347
+ f << %Q[#{span(:ivar)}#{CGI.escapeHTML(tok)}</span>]
348
+ end
349
+
350
+ attr_accessor :embdocs,
351
+ :in_no_doc,
352
+ :owed_pre,
353
+ :spans_owed
354
+
355
+ def parse(buf, f)
356
+ @spans_owed = 0
357
+ @symbol_begun = false
358
+ super(buf)
359
+ end
360
+
361
+ DOCTYPE = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
362
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">' +
363
+ "\n"
364
+
365
+ def Ripdoc.compile(f)
366
+ return DOCTYPE +
367
+ '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" dir="ltr"
368
+ ><head>' +
369
+ '</head><body>' + compile_fragment(f) + '</body></html>'
370
+ end
371
+
372
+ def Ripdoc.compile_fragment(f)
373
+ buf = StringIO.new
374
+ parser = Ripdoc.new(f)
375
+ parser.in_no_doc = false
376
+ parser.owed_pre = true
377
+ parser.parse(buf, f)
378
+ result = buf.string
379
+ parser.spans_owed.times{ result += '</span>' }
380
+
381
+ return '<div id="content"><pre>' + result +
382
+ "#{'</pre>' if parser.owed_pre }</div>"
383
+
384
+ end
385
+
386
+ end
387
+
388
+ #~ :on_ident
389
+ #~ :on_const
390
+ #~ :on_semicolon
391
+ #~ :on_op
392
+ #~ :on_int
393
+ #~ :on_comma
394
+ #~ :on_lparen
395
+ #~ :on_rparen
396
+ #~ :on_backref
397
+ #~ :on_period
398
+ #~ :on_lbracket
399
+ #~ :on_rbracket
400
+ #~ :on_rbrace
401
+ #~ :on_qwords_beg
402
+ #~ :on_words_sep
403
+
404
+ class ERB
405
+ attr_accessor :lineno
406
+
407
+ remove_method :result
408
+ def result(b)
409
+ eval(@src, b, (@filename || '(erb)'), (@lineno || 1))
410
+ end
411
+ end
412
+
413
+ system 'rubyw1.9.0 ../../test/ripdoc_suite.rb' if $0 == __FILE__