tenjin 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +163 -0
- data/MIT-LICENSE +16 -17
- data/README.txt +5 -5
- data/benchmark/Makefile +9 -0
- data/benchmark/bench.rb +3 -2
- data/bin/rbtenjin +6 -3
- data/doc/docstyle.css +25 -4
- data/doc/users-guide.html +2088 -1563
- data/lib/tenjin.rb +784 -158
- data/public_html/_layout.rbhtml +33 -0
- data/public_html/css/style.css +77 -0
- data/public_html/env.rbhtml +15 -0
- data/public_html/favicon.ico +0 -0
- data/public_html/hello.rbhtml +14 -0
- data/public_html/index.rbhtml +39 -0
- data/public_html/rbtenjin.cgi +188 -0
- data/tenjin.gemspec +9 -6
- data/test/data/examples/preprocessing/main.rb +1 -1
- data/test/data/examples/preprocessing/select.rbhtml +1 -1
- data/test/data/faq/{ex11-bench.rb → ex10-bench.rb} +3 -3
- data/test/data/faq/ex10-content.rbhtml +8 -11
- data/test/data/faq/{ex11-layout1.rbhtml → ex10-layout1.rbhtml} +0 -0
- data/test/data/faq/{ex11-layout2.rbhtml → ex10-layout2.rbhtml} +0 -0
- data/test/data/faq/{ex11.rb → ex10.rb} +1 -1
- data/test/data/faq/{ex11.rbhtml → ex10.rbhtml} +0 -0
- data/test/data/faq/{ex11.source → ex10.source} +2 -2
- data/test/data/faq/{ex11_arraybuffer.result → ex10_arraybuffer.result} +1 -1
- data/test/data/faq/{ex5.rbhtml → ex2.rbhtml} +0 -0
- data/test/data/faq/{ex5_template_args.source → ex2_template_args.source} +1 -1
- data/test/data/faq/{ex7-expr-pattern.rb → ex4-expr-pattern.rb} +1 -1
- data/test/data/faq/{ex7-expr-pattern.rbhtml → ex4-expr-pattern.rbhtml} +0 -0
- data/test/data/faq/{ex7_expr_pattern.result → ex4_expr_pattern.result} +1 -1
- data/test/data/faq/{ex6-content.rhtml → ex5-content.rhtml} +0 -0
- data/test/data/faq/{ex6-layout.rhtml → ex5-layout.rhtml} +0 -0
- data/test/data/faq/{ex6.rb → ex5.rb} +2 -2
- data/test/data/faq/{ex6_eruby.result → ex5_eruby.result} +1 -1
- data/test/data/faq/{ex2-content.rbhtml → ex6-content.rbhtml} +0 -0
- data/test/data/faq/{ex2-layout.rbhtml → ex6-layout.rbhtml} +0 -0
- data/test/data/faq/{ex2_removenl.result → ex6_removenl.result} +1 -1
- data/test/data/faq/ex7-m18n.rb +48 -0
- data/test/data/faq/{ex8-m18n.rbhtml → ex7-m18n.rbhtml} +0 -0
- data/test/data/faq/{ex8_m18n.result → ex7_m18n.result} +1 -1
- data/test/data/faq/ex8-baselayout.rbhtml +8 -0
- data/test/data/faq/ex8-content.rbhtml +6 -0
- data/test/data/faq/{ex9-mylayout.rbhtml → ex8-mylayout.rbhtml} +0 -0
- data/test/data/faq/{ex9_changelayout.result → ex8_changelayout.result} +1 -1
- data/test/data/faq/ex9-baselayout.rbhtml +24 -5
- data/test/data/faq/ex9-content.rbhtml +12 -6
- data/test/data/faq/{ex10-customlayout.rbhtml → ex9-customlayout.rbhtml} +1 -1
- data/test/data/faq/{ex10_inherit.result → ex9_inherit.result} +1 -1
- data/test/data/faq/helpers1.rb +17 -0
- data/test/data/faq/helpers1.rbhtml +4 -0
- data/test/data/faq/helpers1.result +11 -0
- data/test/data/faq/helpers2.rb +21 -0
- data/test/data/faq/helpers2.rbhtml +4 -0
- data/test/data/faq/helpers2.result +11 -0
- data/test/data/faq/weekday1.rb +6 -0
- data/test/data/faq/weekday1.rbhtml +9 -0
- data/test/data/faq/weekday1.result +23 -0
- data/test/data/faq/weekday2.rb +8 -0
- data/test/data/faq/weekday2.rbhtml +10 -0
- data/test/data/faq/weekday2.result +24 -0
- data/test/data/faq/weekday3.rb +22 -0
- data/test/data/faq/weekday3.rbhtml +3 -0
- data/test/data/faq/weekday3.result +28 -0
- data/test/data/users_guide/test_010/main.rb +14 -0
- data/test/data/users_guide/test_010/result.output +13 -0
- data/test/data/users_guide/test_010/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_011/main.rb +14 -0
- data/test/data/users_guide/test_011/result.output +2 -0
- data/test/data/users_guide/test_011/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_020/main.rb +14 -0
- data/test/data/users_guide/test_020/result.output +13 -0
- data/test/data/users_guide/test_020/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_021/main.rb +12 -0
- data/test/data/users_guide/test_021/result.output +12 -0
- data/test/data/users_guide/test_021/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_030/main.rb +14 -0
- data/test/data/users_guide/test_030/result.output +23 -0
- data/test/data/users_guide/test_030/views/_layout.rbhtml +10 -0
- data/test/data/users_guide/test_030/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_040/main.rb +14 -0
- data/test/data/users_guide/test_040/result.output +23 -0
- data/test/data/users_guide/test_040/views/_layout.rbhtml +10 -0
- data/test/data/users_guide/test_040/views/page.rbhtml +12 -0
- data/test/data/users_guide/test_050/main.rb +14 -0
- data/test/data/users_guide/test_050/result.output +14 -0
- data/test/data/users_guide/test_050/views/_layout.rbhtml +10 -0
- data/test/data/users_guide/test_050/views/page.rbhtml +13 -0
- data/test/data/users_guide/test_051/main.rb +14 -0
- data/test/data/users_guide/test_051/result.output +12 -0
- data/test/data/users_guide/test_051/views/_layout.rbhtml +11 -0
- data/test/data/users_guide/test_051/views/page.rbhtml +13 -0
- data/test/data/users_guide/test_060/main.rb +14 -0
- data/test/data/users_guide/test_060/result.output +29 -0
- data/test/data/users_guide/test_060/views/_footer.rbhtml +3 -0
- data/test/data/users_guide/test_060/views/_header.rbhtml +3 -0
- data/test/data/users_guide/test_060/views/_layout.rbhtml +13 -0
- data/test/data/users_guide/test_060/views/page.rbhtml +13 -0
- data/test/data/users_guide/test_070/main.rb +14 -0
- data/test/data/users_guide/test_070/result.output +29 -0
- data/test/data/users_guide/test_070/views/_footer.rbhtml +3 -0
- data/test/data/users_guide/test_070/views/_header.rbhtml +3 -0
- data/test/data/users_guide/test_070/views/_layout.rbhtml +13 -0
- data/test/data/users_guide/test_070/views/page.rbhtml +13 -0
- data/test/data/users_guide/test_capturing/main.rb +24 -0
- data/test/data/users_guide/test_capturing/result.output +28 -0
- data/test/data/users_guide/test_capturing/views/_layout.rbhtml +21 -0
- data/test/data/users_guide/test_capturing/views/blog-post.rbhtml +13 -0
- data/test/data/users_guide/test_context/context.rb +5 -0
- data/test/data/users_guide/test_context/context.yaml +4 -0
- data/test/data/users_guide/test_context/example.rbhtml +5 -0
- data/test/data/users_guide/test_context/result1.output +6 -0
- data/test/data/users_guide/test_context/result2.output +6 -0
- data/test/data/users_guide/test_context/result3.output +6 -0
- data/test/data/users_guide/test_context/result4.output +6 -0
- data/test/data/users_guide/test_convert/example.rbhtml +5 -0
- data/test/data/users_guide/test_convert/result1.output +7 -0
- data/test/data/users_guide/test_convert/result2.output +6 -0
- data/test/data/users_guide/test_escape/main.rb +4 -0
- data/test/data/users_guide/test_escape/result.output +5 -0
- data/test/data/users_guide/test_escape/views/page.rbhtml +4 -0
- data/test/data/users_guide/test_execute/example.rbhtml +6 -0
- data/test/data/users_guide/test_execute/result.output +6 -0
- data/test/data/users_guide/test_fragmentcache/cache.d/items/1 +5 -0
- data/test/data/users_guide/test_fragmentcache/main.rb +21 -0
- data/test/data/users_guide/test_fragmentcache/result.output +8 -0
- data/test/data/users_guide/test_fragmentcache/result2.output +6 -0
- data/test/data/users_guide/test_fragmentcache/views/items.rbhtml +10 -0
- data/test/data/users_guide/test_logging/ex-logger.rb +11 -0
- data/test/data/users_guide/test_logging/example.rbhtml +0 -0
- data/test/data/users_guide/test_logging/result1.output +3 -0
- data/test/data/users_guide/test_logging/result2.output +2 -0
- data/test/data/users_guide/test_m17n/m17n.rb +44 -0
- data/test/data/users_guide/test_m17n/m17n.rbhtml +5 -0
- data/test/data/users_guide/test_m17n/result.output +9 -0
- data/test/data/users_guide/test_m17n/result_en.output +4 -0
- data/test/data/users_guide/test_m17n/result_fr.output +4 -0
- data/test/data/users_guide/test_nested/main.rb +8 -0
- data/test/data/users_guide/test_nested/result.output +15 -0
- data/test/data/users_guide/test_nested/views/_blog_layout.rbhtml +5 -0
- data/test/data/users_guide/{layout8_html.rbhtml → test_nested/views/_site_layout.rbhtml} +0 -0
- data/test/data/users_guide/test_nested/views/blog_post.rbhtml +4 -0
- data/test/data/users_guide/test_preprocessing/pp-example1.rb +14 -0
- data/test/data/users_guide/test_preprocessing/result1a.output +11 -0
- data/test/data/users_guide/test_preprocessing/result1b.output +5 -0
- data/test/data/users_guide/test_preprocessing/result1c.output +6 -0
- data/test/data/users_guide/test_preprocessing/result2a.output +10 -0
- data/test/data/users_guide/test_preprocessing/result2b.output +10 -0
- data/test/data/users_guide/test_preprocessing/result3a.output +2 -0
- data/test/data/users_guide/test_preprocessing/result3b.output +2 -0
- data/test/data/users_guide/test_preprocessing/views/pp-example1.rbhtml +4 -0
- data/test/data/users_guide/{example12.rbhtml → test_preprocessing/views/pp-example2.rbhtml} +4 -4
- data/test/data/users_guide/test_preprocessing/views/pp-example3.rbhtml +7 -0
- data/test/data/users_guide/test_retrieve/example.rbhtml +10 -0
- data/test/data/users_guide/test_retrieve/result1.output +11 -0
- data/test/data/users_guide/test_retrieve/result2.output +11 -0
- data/test/data/users_guide/test_retrieve/result3.output +11 -0
- data/test/data/users_guide/test_retrieve/result4.output +8 -0
- data/test/data/users_guide/test_retrieve/result5.output +5 -0
- data/test/data/users_guide/test_safe/result.output +6 -0
- data/test/data/users_guide/test_safe/safe-test.rb +21 -0
- data/test/data/users_guide/test_safehelper/main.rb +16 -0
- data/test/data/users_guide/test_safehelper/result.output +8 -0
- data/test/data/users_guide/{example3.rbhtml → test_syntax_check/example.rbhtml} +0 -0
- data/test/data/users_guide/test_syntax_check/result.output +2 -0
- data/test/data/users_guide/test_trace/layout.rbhtml +7 -0
- data/test/data/users_guide/test_trace/main.rbhtml +5 -0
- data/test/data/users_guide/test_trace/result.output +16 -0
- data/test/data/users_guide/test_trace/trace-example.rb +4 -0
- data/test/oktest.rb +755 -0
- data/test/test_all.rb +24 -14
- data/test/test_engine.rb +628 -63
- data/test/test_engine.yaml +40 -3
- data/test/test_examples.rb +14 -12
- data/test/test_faq.rb +17 -12
- data/test/test_htmlhelper.rb +104 -33
- data/test/test_main.rb +32 -21
- data/test/test_main.yaml +2 -2
- data/test/test_safe.rb +206 -0
- data/test/test_store.rb +220 -0
- data/test/test_tcache.rb +94 -0
- data/test/test_template.rb +65 -23
- data/test/test_template.yaml +7 -7
- data/test/test_users_guide.rb +75 -29
- data/test/testcase-helper.rb +20 -18
- data/test/testunit-assertions.rb +71 -0
- metadata +185 -159
- data/doc-api/classes/Tenjin.html +0 -141
- data/doc-api/classes/Tenjin/ArrayBufferTemplate.html +0 -270
- data/doc-api/classes/Tenjin/BaseContext.html +0 -329
- data/doc-api/classes/Tenjin/Context.html +0 -126
- data/doc-api/classes/Tenjin/ContextHelper.html +0 -461
- data/doc-api/classes/Tenjin/Engine.html +0 -616
- data/doc-api/classes/Tenjin/ErubisTemplate.html +0 -166
- data/doc-api/classes/Tenjin/HtmlHelper.html +0 -359
- data/doc-api/classes/Tenjin/Preprocessor.html +0 -242
- data/doc-api/classes/Tenjin/Template.html +0 -916
- data/doc-api/created.rid +0 -1
- data/doc-api/files/README_txt.html +0 -188
- data/doc-api/files/lib/tenjin_rb.html +0 -136
- data/doc-api/fr_class_index.html +0 -36
- data/doc-api/fr_file_index.html +0 -28
- data/doc-api/fr_method_index.html +0 -91
- data/doc-api/index.html +0 -24
- data/doc-api/rdoc-style.css +0 -208
- data/doc/examples.html +0 -312
- data/doc/faq.html +0 -909
- data/examples/preprocessing/select.rbhtml.cache +0 -17
- data/test/Rookbook.yaml +0 -14
- data/test/assert-text-equal.rb +0 -45
- data/test/data/faq/ex10-baselayout.rbhtml +0 -27
- data/test/data/faq/ex11-content.rbhtml +0 -9
- data/test/data/faq/ex8-m18n.rb +0 -77
- data/test/data/users_guide/content6.rbhtml +0 -3
- data/test/data/users_guide/content7.rbhtml +0 -5
- data/test/data/users_guide/content8.rbhtml +0 -2
- data/test/data/users_guide/contextdata.rb +0 -7
- data/test/data/users_guide/datafile.rb +0 -5
- data/test/data/users_guide/datafile.yaml +0 -10
- data/test/data/users_guide/ex.rbhtml +0 -6
- data/test/data/users_guide/ex.result +0 -7
- data/test/data/users_guide/ex.script +0 -5
- data/test/data/users_guide/ex_script.result +0 -7
- data/test/data/users_guide/ex_source.result +0 -8
- data/test/data/users_guide/example1.rbhtml +0 -12
- data/test/data/users_guide/example1.result +0 -17
- data/test/data/users_guide/example10.rbhtml +0 -4
- data/test/data/users_guide/example10_template_args.result +0 -6
- data/test/data/users_guide/example11.rbhtml +0 -5
- data/test/data/users_guide/example11_template_args_result +0 -2
- data/test/data/users_guide/example12_preprocessed.result +0 -10
- data/test/data/users_guide/example12_preprocessed_source.result +0 -10
- data/test/data/users_guide/example13.rbhtml +0 -6
- data/test/data/users_guide/example13_preprocessed.result +0 -2
- data/test/data/users_guide/example13_preprocessed_source.result +0 -2
- data/test/data/users_guide/example14.rb +0 -32
- data/test/data/users_guide/example14.rbhtml +0 -6
- data/test/data/users_guide/example14_tmplclass.result +0 -15
- data/test/data/users_guide/example15.rb +0 -10
- data/test/data/users_guide/example15_escapefunc.result +0 -14
- data/test/data/users_guide/example16.rbhtml +0 -4
- data/test/data/users_guide/example16a.rb +0 -10
- data/test/data/users_guide/example16a.result +0 -4
- data/test/data/users_guide/example16b.rb +0 -13
- data/test/data/users_guide/example16b.result +0 -4
- data/test/data/users_guide/example16c.rb +0 -12
- data/test/data/users_guide/example16c.result +0 -4
- data/test/data/users_guide/example16d.rb +0 -27
- data/test/data/users_guide/example16d.result +0 -4
- data/test/data/users_guide/example1_S.result +0 -14
- data/test/data/users_guide/example1_SXNC.result +0 -10
- data/test/data/users_guide/example1_source.result +0 -14
- data/test/data/users_guide/example2.rbhtml +0 -3
- data/test/data/users_guide/example2_sb.result2 +0 -9
- data/test/data/users_guide/example3_syntaxcheck.result +0 -2
- data/test/data/users_guide/example4.rbhtml +0 -13
- data/test/data/users_guide/example4_datafile_rb.result +0 -13
- data/test/data/users_guide/example4_yaml.result +0 -13
- data/test/data/users_guide/example5.rbhtml +0 -9
- data/test/data/users_guide/example5_datastr_rb.result +0 -9
- data/test/data/users_guide/example5_datastr_yaml.result +0 -9
- data/test/data/users_guide/example6.rbhtml +0 -19
- data/test/data/users_guide/example6_layout.result +0 -29
- data/test/data/users_guide/example6_nested.result +0 -28
- data/test/data/users_guide/example7_layout2.result +0 -13
- data/test/data/users_guide/example8_layout3.result +0 -8
- data/test/data/users_guide/example9.rbhtml +0 -18
- data/test/data/users_guide/example9_capture.result +0 -26
- data/test/data/users_guide/footer.html +0 -5
- data/test/data/users_guide/footer.rbhtml +0 -4
- data/test/data/users_guide/layout6.rbhtml +0 -17
- data/test/data/users_guide/layout7.rbhtml +0 -9
- data/test/data/users_guide/layout8_xhtml.rbhtml +0 -6
- data/test/data/users_guide/layout9.rbhtml +0 -25
- data/test/data/users_guide/sidemenu.rbhtml +0 -5
- data/test/data/users_guide/user_app.cgi +0 -39
- data/test/data/users_guide/user_app.result +0 -30
- data/test/data/users_guide/user_create.rbhtml +0 -6
- data/test/data/users_guide/user_edit.rbhtml +0 -7
- data/test/data/users_guide/user_form.rbhtml +0 -10
- data/test/data/users_guide/user_layout.rbhtml +0 -16
@@ -0,0 +1,15 @@
|
|
1
|
+
$ ruby main.rb
|
2
|
+
<html> # by _layout.rbhtml
|
3
|
+
<body> # :
|
4
|
+
<h2>Blog Post Test</h2> # by _blog_layout.rbhtml
|
5
|
+
<!-- content --> # :
|
6
|
+
<div class="article"> # by blog_post.rbhtml
|
7
|
+
Foo<br /> # :
|
8
|
+
Bar<br /> # :
|
9
|
+
Baz # :
|
10
|
+
</div> # :
|
11
|
+
# :
|
12
|
+
<!-- /content --> # by _blog_layout.rbhtml
|
13
|
+
# :
|
14
|
+
</body> # by _layout.rbhtml
|
15
|
+
</html> # :
|
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
$VALUE = 'My Great Example'
|
2
|
+
|
3
|
+
## create engine object with preprocessing enabled
|
4
|
+
require 'tenjin'
|
5
|
+
engine = Tenjin::Engine.new(:path=>['views'], :preprocess=>true)
|
6
|
+
|
7
|
+
## print Python script code
|
8
|
+
puts "------ converted script ------"
|
9
|
+
puts engine.get_template('pp-example1.rbhtml').script
|
10
|
+
|
11
|
+
## render html
|
12
|
+
html = engine.render('pp-example1.rbhtml', {})
|
13
|
+
puts "------ rendered html ------"
|
14
|
+
puts html
|
@@ -0,0 +1,11 @@
|
|
1
|
+
$ ruby pp-example1.rb
|
2
|
+
------ converted script ------
|
3
|
+
_buf << %Q`## normal expression
|
4
|
+
value = #{escape(($VALUE).to_s)}
|
5
|
+
## with preprocessing
|
6
|
+
value = My Great Example\n`
|
7
|
+
------ rendered html ------
|
8
|
+
## normal expression
|
9
|
+
value = My Great Example
|
10
|
+
## with preprocessing
|
11
|
+
value = My Great Example
|
@@ -0,0 +1,10 @@
|
|
1
|
+
$ rbtenjin -P views/pp-example2.rbhtml
|
2
|
+
<?rb chk = { params['state'] => ' selected="selected"' } ?>
|
3
|
+
<select name="state">
|
4
|
+
<option value="">-</option>
|
5
|
+
<option value="CA"#{chk['CA']}>California</option>
|
6
|
+
<option value="FL"#{chk['FL']}>Florida</option>
|
7
|
+
<option value="HI"#{chk['HI']}>Hawaii</option>
|
8
|
+
<option value="NY"#{chk['NY']}>New York</option>
|
9
|
+
<option value="TX"#{chk['TX']}>Texas</option>
|
10
|
+
</select>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
$ rbtenjin --preprocess -sb views/pp-example2.rbhtml
|
2
|
+
chk = { params['state'] => ' selected="selected"' }
|
3
|
+
_buf << %Q`<select name="state">
|
4
|
+
<option value="">-</option>
|
5
|
+
<option value="CA"#{chk['CA']}>California</option>
|
6
|
+
<option value="FL"#{chk['FL']}>Florida</option>
|
7
|
+
<option value="HI"#{chk['HI']}>Hawaii</option>
|
8
|
+
<option value="NY"#{chk['NY']}>New York</option>
|
9
|
+
<option value="TX"#{chk['TX']}>Texas</option>
|
10
|
+
</select>\n`
|
@@ -3,10 +3,10 @@
|
|
3
3
|
<?RB "FL" => "Florida", ?>
|
4
4
|
<?RB "TX" => "Texas", ?>
|
5
5
|
<?RB "HI" => "Hawaii", } ?>
|
6
|
-
<?rb chk = {
|
6
|
+
<?rb chk = { params['state'] => ' selected="selected"' } ?>
|
7
7
|
<select name="state">
|
8
8
|
<option value="">-</option>
|
9
|
-
<?RB for code in states.keys.sort ?>
|
10
|
-
<option value="#{{code}}"#{chk[#{{code
|
11
|
-
<?RB end ?>
|
9
|
+
<?RB for code in states.keys.sort ?>
|
10
|
+
<option value="#{{code}}"#{chk['#{{code}}']}>${{states[code]}}</option>
|
11
|
+
<?RB end ?>
|
12
12
|
</select>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'tenjin'
|
2
|
+
include Tenjin::HtmlHelper # defines escape()
|
3
|
+
include Tenjin::SafeHelper # defines safe_escape(), safe_str(), safe_str?()
|
4
|
+
|
5
|
+
## both are same notation
|
6
|
+
input = <<END
|
7
|
+
s1 = ${@s1}
|
8
|
+
s2 = ${@s2}
|
9
|
+
END
|
10
|
+
|
11
|
+
## but passed different data type
|
12
|
+
context = {
|
13
|
+
:s1 => "<b>SOS</b>",
|
14
|
+
:s2 => safe_str("<b>SOS</b>"),
|
15
|
+
}
|
16
|
+
|
17
|
+
## SafeTemplate will escape 's1' but not 's2'
|
18
|
+
template = Tenjin::SafeTemplate.new(:input=>input)
|
19
|
+
print(template.script)
|
20
|
+
print("---------------------\n")
|
21
|
+
print(template.render(context))
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'tenjin'
|
2
|
+
include Tenjin::HtmlHelper
|
3
|
+
include Tenjin::SafeHelper
|
4
|
+
#
|
5
|
+
s = "<AAA>"
|
6
|
+
puts safe_str?(s) #=> false
|
7
|
+
s = safe_escape(s) # same as SafeString.new(escape(s))
|
8
|
+
puts safe_str?(s) #=> true
|
9
|
+
puts s #=> <AAA>
|
10
|
+
puts safe_escape(s) #=> <AAA>
|
11
|
+
#
|
12
|
+
s = "<AAA>"
|
13
|
+
s = safe_str(s) # same as SafeString.new(s)
|
14
|
+
puts safe_str?(s) #=> true
|
15
|
+
puts s #=> <AAA>
|
16
|
+
puts safe_escape(s) #=> <AAA>
|
File without changes
|
@@ -0,0 +1,16 @@
|
|
1
|
+
$ ruby trace-example.rb
|
2
|
+
<!-- ***** begin: layout.rbhtml ***** -->
|
3
|
+
<html>
|
4
|
+
<body>
|
5
|
+
<div class="content">
|
6
|
+
<!-- ***** begin: main.rbhtml ***** -->
|
7
|
+
<ul>
|
8
|
+
<li>A</li>
|
9
|
+
<li>B</li>
|
10
|
+
<li>C</li>
|
11
|
+
</ul>
|
12
|
+
<!-- ***** end: main.rbhtml ***** -->
|
13
|
+
</div>
|
14
|
+
</body>
|
15
|
+
</html>
|
16
|
+
<!-- ***** end: layout.rbhtml ***** -->
|
data/test/oktest.rb
ADDED
@@ -0,0 +1,755 @@
|
|
1
|
+
###
|
2
|
+
### $Release: 0.7.0 $
|
3
|
+
### copyright(c) 2007-2011 kuwata-lab.com all rights reserved
|
4
|
+
### $License: MIT License $
|
5
|
+
###
|
6
|
+
|
7
|
+
module Oktest
|
8
|
+
|
9
|
+
DIFF = ENV['DIFF'] || File.file?('/usr/bin/diff')
|
10
|
+
|
11
|
+
def self.DIFF=(command)
|
12
|
+
remove_const(:DIFF)
|
13
|
+
const_set(:DIFF, command)
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.diff(actual, expected)
|
17
|
+
## actual and expected should be different
|
18
|
+
return nil if actual == expected
|
19
|
+
## both actual and expected should be String
|
20
|
+
return nil unless actual.is_a?(String) && expected.is_a?(String)
|
21
|
+
## either actual or expected should contain "\n"
|
22
|
+
return nil unless actual.index("\n") || expected.index("\n")
|
23
|
+
## diff command
|
24
|
+
command = Oktest::DIFF
|
25
|
+
return nil unless command
|
26
|
+
command = 'diff -u' if command == true
|
27
|
+
## diff
|
28
|
+
require 'tempfile' unless defined?(Tempfile)
|
29
|
+
output = nil
|
30
|
+
#Tempfile.open('actual') do |af| # af.path file is not removed. why?
|
31
|
+
# af.write(actual); af.flush()
|
32
|
+
# Tempfile.open('expected') do |ef|
|
33
|
+
# ef.write(expected); ef.flush()
|
34
|
+
# #output = `#{command} #{ef.path} #{af.path}`
|
35
|
+
# output = IO.popen(cmd="#{command} #{ef.path} #{af.path}") {|io| io.read }
|
36
|
+
# end
|
37
|
+
#end
|
38
|
+
af = ef = nil
|
39
|
+
begin
|
40
|
+
af = Tempfile.open('actual') ; af.write(actual) ; af.flush
|
41
|
+
ef = Tempfile.open('expected') ; ef.write(expected) ; ef.flush
|
42
|
+
#output = `#{command} #{ef.path} #{af.path}`
|
43
|
+
output = IO.popen("#{command} #{ef.path} #{af.path}") {|io| io.read() }
|
44
|
+
ensure
|
45
|
+
af.close if ef
|
46
|
+
ef.close if ef
|
47
|
+
end
|
48
|
+
return output.sub(/\A.*?\n.*?\n/, "--- expected\n+++ actual\n")
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
class AssertionFailed < Exception
|
53
|
+
attr_accessor :diff
|
54
|
+
end
|
55
|
+
|
56
|
+
ASSERTION_FAILED = AssertionFailed
|
57
|
+
|
58
|
+
|
59
|
+
class AssertionObject
|
60
|
+
|
61
|
+
attr_reader :actual, :negative
|
62
|
+
|
63
|
+
def initialize(this, actual, negative=false)
|
64
|
+
@this = this
|
65
|
+
@actual = actual
|
66
|
+
@negative = negative
|
67
|
+
end
|
68
|
+
|
69
|
+
def ==(expected)
|
70
|
+
begin
|
71
|
+
do_assert(@actual == expected, expected, '==', '!=')
|
72
|
+
rescue AssertionFailed => ex
|
73
|
+
ex.diff = Oktest.diff(@actual, expected) if @actual != expected
|
74
|
+
raise ex
|
75
|
+
rescue ASSERTION_FAILED => ex
|
76
|
+
diff = Oktest.diff(@actual, expected) if @actual != expected
|
77
|
+
ex.message << "\n" << diff.chomp() if diff && ! diff.empty?
|
78
|
+
raise ex
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if Object.new.respond_to?(:'!=')
|
83
|
+
eval <<-'END'
|
84
|
+
def !=(expected)
|
85
|
+
do_assert(@actual == expected, expected, '!=', '==')
|
86
|
+
end
|
87
|
+
END
|
88
|
+
end
|
89
|
+
|
90
|
+
def >(expected)
|
91
|
+
do_assert(@actual > expected, expected, '>', '<=')
|
92
|
+
end
|
93
|
+
|
94
|
+
def <(expected)
|
95
|
+
do_assert(@actual < expected, expected, '<', '>=')
|
96
|
+
end
|
97
|
+
|
98
|
+
def >=(expected)
|
99
|
+
do_assert(@actual >= expected, expected, '>=', '<')
|
100
|
+
end
|
101
|
+
|
102
|
+
def <=(expected)
|
103
|
+
do_assert(@actual <= expected, expected, '<=', '>')
|
104
|
+
end
|
105
|
+
|
106
|
+
def ===(expected)
|
107
|
+
do_assert(@actual === expected, expected, '===', '!==')
|
108
|
+
end
|
109
|
+
|
110
|
+
def =~(expected)
|
111
|
+
do_assert(@actual =~ expected, expected, '=~', '!~')
|
112
|
+
end
|
113
|
+
|
114
|
+
def in_delta?(expected, delta)
|
115
|
+
flag = expected - delta <= @actual && @actual <= expected + delta
|
116
|
+
check2(flag) { "(#{(expected - delta).inspect} <= #{@actual.inspect} <= #{(expected + delta).inspect})" }
|
117
|
+
end
|
118
|
+
|
119
|
+
def file?
|
120
|
+
check2(File.file?(@actual)) { "File.file?(#{@actual.inspect})" }
|
121
|
+
end
|
122
|
+
|
123
|
+
def dir?
|
124
|
+
check2(File.directory?(@actual)) { "File.directory?(#{@actual.inspect})" }
|
125
|
+
end
|
126
|
+
|
127
|
+
def exist?
|
128
|
+
check2(File.exist?(@actual)) { "File.exist?(#{@actual.inspect})" }
|
129
|
+
end
|
130
|
+
|
131
|
+
def same?(expected)
|
132
|
+
check2(@actual.equal?(expected)) { "#{@actual.inspect}.equal?(#{expected.inspect})" }
|
133
|
+
end
|
134
|
+
|
135
|
+
def in?(expected)
|
136
|
+
check2(expected.include?(@actual)) { "#{expected.inspect}.include?(#{@actual.inspect})" }
|
137
|
+
end
|
138
|
+
|
139
|
+
def include?(expected)
|
140
|
+
check2(@actual.include?(expected)) { "#{@actual.inspect}.include?(#{expected.inspect})" }
|
141
|
+
end
|
142
|
+
|
143
|
+
def is_a?(expected)
|
144
|
+
check2(@actual.is_a?(expected)) { "#{@actual.inspect}.is_a?(#{expected})" }
|
145
|
+
end
|
146
|
+
alias kind_of? is_a?
|
147
|
+
|
148
|
+
def nil?
|
149
|
+
check2(@actual.nil?) { "#{@actual.inspect}.nil?" }
|
150
|
+
end
|
151
|
+
|
152
|
+
def empty?
|
153
|
+
check2(@actual.empty?) { "#{@actual.inspect}.empty?" }
|
154
|
+
end
|
155
|
+
|
156
|
+
def raise?(exception_class, message=nil)
|
157
|
+
if @negative
|
158
|
+
_should_not_raise(exception_class)
|
159
|
+
ex = nil
|
160
|
+
else
|
161
|
+
ex = _should_raise(exception_class, message)
|
162
|
+
end
|
163
|
+
return ex
|
164
|
+
end
|
165
|
+
|
166
|
+
private
|
167
|
+
|
168
|
+
def _should_raise(exception_class, message)
|
169
|
+
not_raised = false
|
170
|
+
begin
|
171
|
+
@actual.call
|
172
|
+
not_raised = true
|
173
|
+
rescue Exception => ex
|
174
|
+
@actual.instance_variable_set('@exception', ex)
|
175
|
+
def @actual.exception; @exception; end
|
176
|
+
ex.class <= exception_class or
|
177
|
+
raise new_assertion_failed("#{exception_class.name} expected but #{ex.class.name} raised.", 2)
|
178
|
+
if message
|
179
|
+
op = message.is_a?(Regexp) ? '=~' : '=='
|
180
|
+
ex.message.__send__(op, message) or
|
181
|
+
raise new_assertion_failed("#{ex.message.inspect} #{op} #{message.inspect}: failed.", 2)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
raise new_assertion_failed("#{exception_class.name} expected but not raised.", 2) if not_raised
|
185
|
+
return ex
|
186
|
+
end
|
187
|
+
|
188
|
+
def _should_not_raise(exception_class=Exception)
|
189
|
+
begin
|
190
|
+
@actual.call
|
191
|
+
rescue Exception => ex
|
192
|
+
@actual.instance_variable_set('@exception', ex)
|
193
|
+
def @actual.exception; @exception; end
|
194
|
+
if ex.class <= exception_class
|
195
|
+
raise new_assertion_failed("unexpected #{ex.class.name} raised.", 2)
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def do_assert(flag, expected, op, negative_op)
|
201
|
+
flag, msg = check(flag, expected, op, negative_op)
|
202
|
+
return true if flag
|
203
|
+
raise new_assertion_failed(msg)
|
204
|
+
end
|
205
|
+
|
206
|
+
def new_assertion_failed(msg, depth=2)
|
207
|
+
ex = AssertionFailed.new(msg)
|
208
|
+
ex.set_backtrace(caller(depth+1)) # manipulate backtrace
|
209
|
+
return ex
|
210
|
+
end
|
211
|
+
|
212
|
+
def check(flag, expected, op, negative_op)
|
213
|
+
if @negative
|
214
|
+
flag = ! flag
|
215
|
+
op = negative_op
|
216
|
+
end
|
217
|
+
msg = flag ? nil : failed_message(expected, op)
|
218
|
+
return flag, msg
|
219
|
+
end
|
220
|
+
|
221
|
+
def failed_message(expected, op)
|
222
|
+
"#{@actual.inspect} #{op} #{expected.inspect}: failed."
|
223
|
+
end
|
224
|
+
|
225
|
+
def check2(flag)
|
226
|
+
flag = ! flag if @negative
|
227
|
+
return true if flag
|
228
|
+
expr = yield
|
229
|
+
expr = "! #{expr}" if @negative
|
230
|
+
raise new_assertion_failed("#{expr}: failed.")
|
231
|
+
end
|
232
|
+
|
233
|
+
end
|
234
|
+
|
235
|
+
|
236
|
+
module Helper
|
237
|
+
|
238
|
+
module_function
|
239
|
+
|
240
|
+
def ok(actual=nil)
|
241
|
+
actual = yield if block_given? # experimental
|
242
|
+
return Oktest::AssertionObject.new(self, actual, false)
|
243
|
+
end
|
244
|
+
alias ok_ ok
|
245
|
+
|
246
|
+
def not_ok(actual=nil)
|
247
|
+
actual = yield if block_given? # experimental
|
248
|
+
return Oktest::AssertionObject.new(self, actual, true)
|
249
|
+
end
|
250
|
+
alias not_ok_ not_ok
|
251
|
+
|
252
|
+
def capture_io(stdin_str=nil)
|
253
|
+
require 'stringio' unless defined?(StringIO)
|
254
|
+
stdout, stderr = $stdout, $stderr
|
255
|
+
$stdout, $stderr = StringIO.new, StringIO.new
|
256
|
+
stdin, $stdin = $stdin, StringIO.new(stdin_str) if stdin_str
|
257
|
+
begin
|
258
|
+
yield
|
259
|
+
ret = [$stdout.string, $stderr.string]
|
260
|
+
ensure
|
261
|
+
$stdout, $stderr = stdout, stderr
|
262
|
+
$stdin = stdin if stdin_str
|
263
|
+
end
|
264
|
+
return ret
|
265
|
+
end
|
266
|
+
|
267
|
+
def dummy_file(pairs)
|
268
|
+
fnames = []
|
269
|
+
begin
|
270
|
+
pairs.each do |fname, content|
|
271
|
+
fnames << fname
|
272
|
+
File.open(fname, 'wb') {|f| f.write(content) }
|
273
|
+
yield
|
274
|
+
end
|
275
|
+
ensure
|
276
|
+
File.unlink(*fnames)
|
277
|
+
end
|
278
|
+
end
|
279
|
+
|
280
|
+
def dummy_dir(*paths)
|
281
|
+
require 'fileutils' unless defined?(FileUtils)
|
282
|
+
begin
|
283
|
+
paths.each {|path| FileUtils.mkdir_p(path) }
|
284
|
+
yield
|
285
|
+
ensure
|
286
|
+
paths.reverse.each {|path| FileUtils.rm_rf(path) }
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
## marker method to represent pre-condition
|
291
|
+
def pre_cond; yield; end
|
292
|
+
|
293
|
+
## marker method to represent post-condition
|
294
|
+
def post_cond; yield; end
|
295
|
+
|
296
|
+
## marker method to describe target of specification
|
297
|
+
def target(desc); yield; end
|
298
|
+
|
299
|
+
## marker method to describe specification
|
300
|
+
#def spec(desc); yield if block_given?; end
|
301
|
+
def spec(desc)
|
302
|
+
reporter = @_oktest_runner && @_oktest_runner.reporter
|
303
|
+
status = nil
|
304
|
+
begin
|
305
|
+
reporter.enter_spec(self, desc) if reporter
|
306
|
+
if block_given?
|
307
|
+
yield
|
308
|
+
status = :ok
|
309
|
+
else
|
310
|
+
status = :empty
|
311
|
+
end
|
312
|
+
rescue AssertionFailed => ex
|
313
|
+
status = :fail
|
314
|
+
raise ex
|
315
|
+
rescue => ex
|
316
|
+
status = :error
|
317
|
+
raise ex
|
318
|
+
ensure
|
319
|
+
reporter.exit_spec(self, status) if reporter
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
##
|
324
|
+
## intercept method call of object
|
325
|
+
##
|
326
|
+
## stub example.
|
327
|
+
## class Hello
|
328
|
+
## def hello(name); return "Hello #{name}!"; end
|
329
|
+
## end
|
330
|
+
## obj = Hello.new
|
331
|
+
## intr = intercept(obj, :hello)
|
332
|
+
## intr.called #=> false
|
333
|
+
## obj.hello('World') #=> "Hello World!"
|
334
|
+
## intr.called #=> true
|
335
|
+
## intr.args #=> ["World"]
|
336
|
+
## intr.return #=> "Hello World!"
|
337
|
+
##
|
338
|
+
## mock example.
|
339
|
+
## class Hello
|
340
|
+
## def hello(name); return "Hello #{name}!"; end
|
341
|
+
## end
|
342
|
+
## obj = Hello.new
|
343
|
+
## intr = intercept(obj, :hello) do |name|
|
344
|
+
## "Bonjor #{name}!" # or `obj.__intercepted_hello(name)'
|
345
|
+
## end
|
346
|
+
## intr.called #=> false
|
347
|
+
## obj.hello('World') #=> "Bonjor World!"
|
348
|
+
## intr.called #=> true
|
349
|
+
## intr.args #=> ["World"]
|
350
|
+
## intr.return #=> "Bonjor World!"
|
351
|
+
##
|
352
|
+
def intercept(object, method, &block)
|
353
|
+
return Oktest::Util::Interceptor.new(object, method, &block)
|
354
|
+
end
|
355
|
+
|
356
|
+
end
|
357
|
+
|
358
|
+
|
359
|
+
module ClassMethodHelper
|
360
|
+
|
361
|
+
def method_added(name)
|
362
|
+
dict = (@_test_method_names_dict ||= {})
|
363
|
+
name = name.to_s
|
364
|
+
if name =~ /\Atest_?/
|
365
|
+
## if test method name is duplicated, raise error
|
366
|
+
dict[name].nil? or
|
367
|
+
raise NameError.new("#{self.name}##{name}(): already defined (please change test method name).")
|
368
|
+
dict[name] = dict.size()
|
369
|
+
## if ENV['TEST'] is set, remove unmatched method
|
370
|
+
if ENV['TEST']
|
371
|
+
remove_method(name) unless name.sub(/\Atest_?/, '').index(ENV['TEST'])
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def test(desc, &block)
|
377
|
+
@_test_count ||= 0
|
378
|
+
@_test_count += 1
|
379
|
+
method_name = "test_%03d_%s" % [@_test_count, desc.to_s.gsub(/[^\w]/, '_')]
|
380
|
+
define_method(method_name, block)
|
381
|
+
end
|
382
|
+
|
383
|
+
end
|
384
|
+
|
385
|
+
|
386
|
+
module TestCase
|
387
|
+
include Helper
|
388
|
+
|
389
|
+
@_subclasses = []
|
390
|
+
|
391
|
+
def self._subclasses # :nodoc:
|
392
|
+
return @_subclasses
|
393
|
+
end
|
394
|
+
|
395
|
+
def self.included(klass)
|
396
|
+
@_subclasses << klass if klass.is_a?(Class)
|
397
|
+
klass.class_eval do
|
398
|
+
extend Oktest::ClassMethodHelper
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
end
|
403
|
+
|
404
|
+
|
405
|
+
class Reporter
|
406
|
+
|
407
|
+
def before_all(klass)
|
408
|
+
end
|
409
|
+
|
410
|
+
def after_all(klass)
|
411
|
+
end
|
412
|
+
|
413
|
+
def before(obj)
|
414
|
+
end
|
415
|
+
|
416
|
+
def after(obj)
|
417
|
+
end
|
418
|
+
|
419
|
+
def print_ok(obj)
|
420
|
+
end
|
421
|
+
|
422
|
+
def print_failed(obj, ex)
|
423
|
+
end
|
424
|
+
|
425
|
+
def print_error(obj, ex)
|
426
|
+
end
|
427
|
+
|
428
|
+
def enter_spec(obj, desc)
|
429
|
+
end
|
430
|
+
|
431
|
+
def exit_spec(obj, status)
|
432
|
+
end
|
433
|
+
|
434
|
+
end
|
435
|
+
|
436
|
+
|
437
|
+
class BaseReporter < Reporter
|
438
|
+
|
439
|
+
def initialize(out=nil)
|
440
|
+
@out = out || $stdout
|
441
|
+
@_flush = @out.respond_to?(:flush)
|
442
|
+
end
|
443
|
+
|
444
|
+
def before_all(klass)
|
445
|
+
@count_test = 0
|
446
|
+
@count_spec = 0
|
447
|
+
end
|
448
|
+
|
449
|
+
def before(obj)
|
450
|
+
@count_test += 1
|
451
|
+
@spec_status = nil
|
452
|
+
end
|
453
|
+
|
454
|
+
def after(obj)
|
455
|
+
end
|
456
|
+
|
457
|
+
def enter_spec(obj, desc)
|
458
|
+
@count_spec += 1
|
459
|
+
end
|
460
|
+
|
461
|
+
def exit_spec(obj, status)
|
462
|
+
@spec_status = status
|
463
|
+
case status
|
464
|
+
when :ok ; write('.')
|
465
|
+
when :empty ; write('_')
|
466
|
+
when :fail ; write('f')
|
467
|
+
when :error ; write('E')
|
468
|
+
else
|
469
|
+
raise "** internal error: status=#{status.inspect}"
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
private
|
474
|
+
|
475
|
+
def _test_ident(obj)
|
476
|
+
return obj.instance_variable_get('@_test_method')
|
477
|
+
end
|
478
|
+
|
479
|
+
def write(str)
|
480
|
+
@out << str
|
481
|
+
@out.flush if @_flush
|
482
|
+
end
|
483
|
+
|
484
|
+
def print_backtrace(ex, out=@out)
|
485
|
+
ex.backtrace.each do |str|
|
486
|
+
out << " #{str}\n"
|
487
|
+
if str =~ /\A(.*):(\d+):in `(.*?)'/
|
488
|
+
filepath, linenum, method = $1, $2.to_i, $3
|
489
|
+
#break if method =~ /\Atest_?/
|
490
|
+
line = get_line(filepath, linenum)
|
491
|
+
out << " #{line.strip}\n" if line
|
492
|
+
break if method =~ /\Atest_?/
|
493
|
+
end
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
def get_line(filepath, linenum)
|
498
|
+
return nil unless File.file?(filepath)
|
499
|
+
linenum = linenum.to_i
|
500
|
+
line = File.open(filepath) do |f|
|
501
|
+
i = 0
|
502
|
+
f.find { (i += 1) == linenum }
|
503
|
+
end
|
504
|
+
return line
|
505
|
+
end
|
506
|
+
|
507
|
+
end
|
508
|
+
|
509
|
+
|
510
|
+
class SimpleReporter < BaseReporter
|
511
|
+
|
512
|
+
def before_all(klass)
|
513
|
+
super
|
514
|
+
write("### %s: " % klass.name)
|
515
|
+
@buf = ""
|
516
|
+
end
|
517
|
+
|
518
|
+
def after_all(klass)
|
519
|
+
super
|
520
|
+
write(" (#{@count_test} tests, #{@count_spec} specs)\n")
|
521
|
+
@out << @buf.to_s
|
522
|
+
@buf = nil
|
523
|
+
end
|
524
|
+
|
525
|
+
def print_ok(obj)
|
526
|
+
write(".") unless @spec_status
|
527
|
+
end
|
528
|
+
|
529
|
+
def print_failed(obj, ex)
|
530
|
+
write("f") unless @spec_status
|
531
|
+
@buf << "Failed: #{_test_ident(obj)}()\n"
|
532
|
+
@buf << " #{ex.message}\n"
|
533
|
+
print_backtrace(ex, @buf)
|
534
|
+
#assert ex.is_a?(AssertionFailed)
|
535
|
+
@buf << ex.diff if ex.diff
|
536
|
+
end
|
537
|
+
|
538
|
+
def print_error(obj, ex)
|
539
|
+
write("E") unless @spec_status
|
540
|
+
@buf << "ERROR: #{_test_ident(obj)}()\n"
|
541
|
+
@buf << " #{ex.class.name}: #{ex.message}\n"
|
542
|
+
print_backtrace(ex, @buf)
|
543
|
+
end
|
544
|
+
|
545
|
+
end
|
546
|
+
|
547
|
+
|
548
|
+
class VerboseReporter < BaseReporter
|
549
|
+
|
550
|
+
def before_all(klass)
|
551
|
+
super
|
552
|
+
write("### %s\n" % klass.name)
|
553
|
+
end
|
554
|
+
|
555
|
+
def after_all(klass)
|
556
|
+
super
|
557
|
+
write(" (#{@count_test} tests, #{@count_spec} specs)\n")
|
558
|
+
end
|
559
|
+
|
560
|
+
def before(obj)
|
561
|
+
super
|
562
|
+
write("- #{_test_ident(obj)}: ")
|
563
|
+
end
|
564
|
+
|
565
|
+
def print_ok(obj)
|
566
|
+
write(" ok\n")
|
567
|
+
end
|
568
|
+
|
569
|
+
def print_failed(obj, ex)
|
570
|
+
write(" FAILED\n")
|
571
|
+
write(" #{ex.message}\n")
|
572
|
+
print_backtrace(ex, @out)
|
573
|
+
#assert ex.is_a?(AssertionFailed)
|
574
|
+
write(ex.diff) if ex.diff
|
575
|
+
end
|
576
|
+
|
577
|
+
def print_error(obj, ex)
|
578
|
+
write(" ERROR\n")
|
579
|
+
write(" #{ex.class.name}: #{ex.message}\n")
|
580
|
+
print_backtrace(ex, @out)
|
581
|
+
end
|
582
|
+
|
583
|
+
end
|
584
|
+
|
585
|
+
|
586
|
+
REPORTER = SimpleReporter
|
587
|
+
#REPORTER = VerboseReporter
|
588
|
+
|
589
|
+
def self.REPORTER=(reporter_class)
|
590
|
+
remove_const(:REPORTER)
|
591
|
+
const_set(:REPORTER, reporter_class)
|
592
|
+
end
|
593
|
+
|
594
|
+
|
595
|
+
class Runner
|
596
|
+
|
597
|
+
def initialize(reporter=nil)
|
598
|
+
@reporter = reporter || REPORTER.new
|
599
|
+
end
|
600
|
+
attr_accessor :reporter
|
601
|
+
|
602
|
+
def test_method_names_from(klass)
|
603
|
+
test_method_names = klass.instance_methods(true).collect {|sym| sym.to_s }.grep(/\Atest/).sort()
|
604
|
+
dict = klass.instance_variable_get('@_test_method_names_dict')
|
605
|
+
if dict
|
606
|
+
dict = dict.dup() # key: test method name (String), value: index (Integer)
|
607
|
+
i = 0
|
608
|
+
test_method_names.select {|name| ! dict.key?(name) }.reverse.each {|name| dict[name] = (i -= 1) }
|
609
|
+
test_method_names = dict.sort_by {|k, v| v }.collect {|k, v| k }
|
610
|
+
end
|
611
|
+
return test_method_names
|
612
|
+
end
|
613
|
+
|
614
|
+
def warning(msg)
|
615
|
+
warn "WARNING: #{msg}"
|
616
|
+
end
|
617
|
+
|
618
|
+
def run(klass)
|
619
|
+
reporter = @reporter
|
620
|
+
## gather test methods
|
621
|
+
test_method_names = test_method_names_from(klass)
|
622
|
+
## filer by $TEST environment variable
|
623
|
+
pattern = ENV['TEST']
|
624
|
+
test_method_names.delete_if {|x| x.index(pattern).nil? } if pattern
|
625
|
+
## sort by linenumber
|
626
|
+
# nothing
|
627
|
+
## invoke before_all()
|
628
|
+
reporter.before_all(klass)
|
629
|
+
if klass.respond_to?(:before_all)
|
630
|
+
klass.before_all()
|
631
|
+
elsif klass.method_defined?(:before_all)
|
632
|
+
warning "#{klass.name}#before_all() should be class method (but defined as instance method)"
|
633
|
+
end
|
634
|
+
## invoke test methods
|
635
|
+
count = 0
|
636
|
+
flag_before = klass.method_defined?(:before)
|
637
|
+
flag_setup = klass.method_defined?(:setup)
|
638
|
+
flag_after = klass.method_defined?(:after)
|
639
|
+
flag_teardown = klass.method_defined?(:teardown)
|
640
|
+
test_method_names.each do |method_name|
|
641
|
+
## create instance object for each test
|
642
|
+
begin
|
643
|
+
obj = klass.new
|
644
|
+
rescue ArgumentError
|
645
|
+
obj = klass.new(method_name)
|
646
|
+
end
|
647
|
+
obj.instance_variable_set('@_name', method_name.sub(/\Atest_?/, ''))
|
648
|
+
obj.instance_variable_set('@_test_method', method_name)
|
649
|
+
obj.instance_variable_set('@_oktest_runner', self)
|
650
|
+
## invoke before() or setup()
|
651
|
+
reporter.before(obj)
|
652
|
+
flag_before ? obj.before() : flag_setup ? obj.setup() : nil
|
653
|
+
## invoke test method
|
654
|
+
begin
|
655
|
+
obj.__send__(method_name)
|
656
|
+
reporter.print_ok(obj)
|
657
|
+
rescue Oktest::AssertionFailed => ex
|
658
|
+
count += 1
|
659
|
+
reporter.print_failed(obj, ex)
|
660
|
+
rescue Exception => ex
|
661
|
+
count += 1
|
662
|
+
reporter.print_error(obj, ex)
|
663
|
+
ensure
|
664
|
+
## invoke after() or teardown()
|
665
|
+
flag_after ? obj.after() : flag_teardown ? obj.teardown() : nil
|
666
|
+
reporter.after(obj)
|
667
|
+
end
|
668
|
+
end
|
669
|
+
## invoke after_all()
|
670
|
+
if klass.respond_to?(:after_all)
|
671
|
+
klass.after_all()
|
672
|
+
elsif klass.method_defined?(:after_all)
|
673
|
+
warning "#{klass.name}#after_all() should be class method (but defined as instance method)"
|
674
|
+
end
|
675
|
+
reporter.after_all(klass)
|
676
|
+
##
|
677
|
+
return count
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
|
682
|
+
def self.run(*classes)
|
683
|
+
opts = classes.last.is_a?(Hash) ? classes.pop() : {}
|
684
|
+
reporter_class = opts[:verbose] ? VerboseReporter : REPORTER
|
685
|
+
reporter = reporter_class.new(opts[:out])
|
686
|
+
runner = Runner.new(reporter)
|
687
|
+
classes.each {|cls| runner.run(cls) }
|
688
|
+
self.run_at_exit = false
|
689
|
+
end
|
690
|
+
|
691
|
+
def self.run_all(opts={})
|
692
|
+
classes = Oktest::TestCase._subclasses()
|
693
|
+
args = classes + [opts]
|
694
|
+
self.run(*args)
|
695
|
+
end
|
696
|
+
|
697
|
+
@_run_at_exit = true
|
698
|
+
|
699
|
+
def self.run_at_exit?
|
700
|
+
return @_run_at_exit
|
701
|
+
end
|
702
|
+
|
703
|
+
def self.run_at_exit=(flag)
|
704
|
+
@_run_at_exit = flag
|
705
|
+
end
|
706
|
+
|
707
|
+
|
708
|
+
module Util
|
709
|
+
|
710
|
+
|
711
|
+
class Interceptor
|
712
|
+
|
713
|
+
def initialize(object, method, &block)
|
714
|
+
@object, @method, @block = object, method, block
|
715
|
+
@called = false
|
716
|
+
intercept()
|
717
|
+
end
|
718
|
+
|
719
|
+
attr_accessor :object, :method, :block, :called, :args, :return
|
720
|
+
|
721
|
+
private
|
722
|
+
|
723
|
+
def intercept
|
724
|
+
intr = self
|
725
|
+
(class << @object; self; end).class_eval do
|
726
|
+
method = intr.method
|
727
|
+
alias_name = "__intercepted_#{method}"
|
728
|
+
alias_method alias_name, method
|
729
|
+
define_method(method) do |*args|
|
730
|
+
intr.called = true
|
731
|
+
intr.args = args
|
732
|
+
intr.return = intr.block ? intr.block.call(*args) \
|
733
|
+
: __send__(alias_name, *args)
|
734
|
+
intr.return
|
735
|
+
end
|
736
|
+
end
|
737
|
+
return self
|
738
|
+
end
|
739
|
+
|
740
|
+
end
|
741
|
+
|
742
|
+
|
743
|
+
end #Util
|
744
|
+
|
745
|
+
|
746
|
+
end
|
747
|
+
|
748
|
+
|
749
|
+
at_exit do
|
750
|
+
ex = $!
|
751
|
+
if (! ex || ex.is_a?(SystemExit)) && Oktest.run_at_exit? # && ! defined?(Test::Unit)
|
752
|
+
Oktest.run_all()
|
753
|
+
raise ex if ex
|
754
|
+
end
|
755
|
+
end
|