tenjin 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. data/CHANGES.txt +163 -0
  2. data/MIT-LICENSE +16 -17
  3. data/README.txt +5 -5
  4. data/benchmark/Makefile +9 -0
  5. data/benchmark/bench.rb +3 -2
  6. data/bin/rbtenjin +6 -3
  7. data/doc/docstyle.css +25 -4
  8. data/doc/users-guide.html +2088 -1563
  9. data/lib/tenjin.rb +784 -158
  10. data/public_html/_layout.rbhtml +33 -0
  11. data/public_html/css/style.css +77 -0
  12. data/public_html/env.rbhtml +15 -0
  13. data/public_html/favicon.ico +0 -0
  14. data/public_html/hello.rbhtml +14 -0
  15. data/public_html/index.rbhtml +39 -0
  16. data/public_html/rbtenjin.cgi +188 -0
  17. data/tenjin.gemspec +9 -6
  18. data/test/data/examples/preprocessing/main.rb +1 -1
  19. data/test/data/examples/preprocessing/select.rbhtml +1 -1
  20. data/test/data/faq/{ex11-bench.rb → ex10-bench.rb} +3 -3
  21. data/test/data/faq/ex10-content.rbhtml +8 -11
  22. data/test/data/faq/{ex11-layout1.rbhtml → ex10-layout1.rbhtml} +0 -0
  23. data/test/data/faq/{ex11-layout2.rbhtml → ex10-layout2.rbhtml} +0 -0
  24. data/test/data/faq/{ex11.rb → ex10.rb} +1 -1
  25. data/test/data/faq/{ex11.rbhtml → ex10.rbhtml} +0 -0
  26. data/test/data/faq/{ex11.source → ex10.source} +2 -2
  27. data/test/data/faq/{ex11_arraybuffer.result → ex10_arraybuffer.result} +1 -1
  28. data/test/data/faq/{ex5.rbhtml → ex2.rbhtml} +0 -0
  29. data/test/data/faq/{ex5_template_args.source → ex2_template_args.source} +1 -1
  30. data/test/data/faq/{ex7-expr-pattern.rb → ex4-expr-pattern.rb} +1 -1
  31. data/test/data/faq/{ex7-expr-pattern.rbhtml → ex4-expr-pattern.rbhtml} +0 -0
  32. data/test/data/faq/{ex7_expr_pattern.result → ex4_expr_pattern.result} +1 -1
  33. data/test/data/faq/{ex6-content.rhtml → ex5-content.rhtml} +0 -0
  34. data/test/data/faq/{ex6-layout.rhtml → ex5-layout.rhtml} +0 -0
  35. data/test/data/faq/{ex6.rb → ex5.rb} +2 -2
  36. data/test/data/faq/{ex6_eruby.result → ex5_eruby.result} +1 -1
  37. data/test/data/faq/{ex2-content.rbhtml → ex6-content.rbhtml} +0 -0
  38. data/test/data/faq/{ex2-layout.rbhtml → ex6-layout.rbhtml} +0 -0
  39. data/test/data/faq/{ex2_removenl.result → ex6_removenl.result} +1 -1
  40. data/test/data/faq/ex7-m18n.rb +48 -0
  41. data/test/data/faq/{ex8-m18n.rbhtml → ex7-m18n.rbhtml} +0 -0
  42. data/test/data/faq/{ex8_m18n.result → ex7_m18n.result} +1 -1
  43. data/test/data/faq/ex8-baselayout.rbhtml +8 -0
  44. data/test/data/faq/ex8-content.rbhtml +6 -0
  45. data/test/data/faq/{ex9-mylayout.rbhtml → ex8-mylayout.rbhtml} +0 -0
  46. data/test/data/faq/{ex9_changelayout.result → ex8_changelayout.result} +1 -1
  47. data/test/data/faq/ex9-baselayout.rbhtml +24 -5
  48. data/test/data/faq/ex9-content.rbhtml +12 -6
  49. data/test/data/faq/{ex10-customlayout.rbhtml → ex9-customlayout.rbhtml} +1 -1
  50. data/test/data/faq/{ex10_inherit.result → ex9_inherit.result} +1 -1
  51. data/test/data/faq/helpers1.rb +17 -0
  52. data/test/data/faq/helpers1.rbhtml +4 -0
  53. data/test/data/faq/helpers1.result +11 -0
  54. data/test/data/faq/helpers2.rb +21 -0
  55. data/test/data/faq/helpers2.rbhtml +4 -0
  56. data/test/data/faq/helpers2.result +11 -0
  57. data/test/data/faq/weekday1.rb +6 -0
  58. data/test/data/faq/weekday1.rbhtml +9 -0
  59. data/test/data/faq/weekday1.result +23 -0
  60. data/test/data/faq/weekday2.rb +8 -0
  61. data/test/data/faq/weekday2.rbhtml +10 -0
  62. data/test/data/faq/weekday2.result +24 -0
  63. data/test/data/faq/weekday3.rb +22 -0
  64. data/test/data/faq/weekday3.rbhtml +3 -0
  65. data/test/data/faq/weekday3.result +28 -0
  66. data/test/data/users_guide/test_010/main.rb +14 -0
  67. data/test/data/users_guide/test_010/result.output +13 -0
  68. data/test/data/users_guide/test_010/views/page.rbhtml +11 -0
  69. data/test/data/users_guide/test_011/main.rb +14 -0
  70. data/test/data/users_guide/test_011/result.output +2 -0
  71. data/test/data/users_guide/test_011/views/page.rbhtml +11 -0
  72. data/test/data/users_guide/test_020/main.rb +14 -0
  73. data/test/data/users_guide/test_020/result.output +13 -0
  74. data/test/data/users_guide/test_020/views/page.rbhtml +11 -0
  75. data/test/data/users_guide/test_021/main.rb +12 -0
  76. data/test/data/users_guide/test_021/result.output +12 -0
  77. data/test/data/users_guide/test_021/views/page.rbhtml +11 -0
  78. data/test/data/users_guide/test_030/main.rb +14 -0
  79. data/test/data/users_guide/test_030/result.output +23 -0
  80. data/test/data/users_guide/test_030/views/_layout.rbhtml +10 -0
  81. data/test/data/users_guide/test_030/views/page.rbhtml +11 -0
  82. data/test/data/users_guide/test_040/main.rb +14 -0
  83. data/test/data/users_guide/test_040/result.output +23 -0
  84. data/test/data/users_guide/test_040/views/_layout.rbhtml +10 -0
  85. data/test/data/users_guide/test_040/views/page.rbhtml +12 -0
  86. data/test/data/users_guide/test_050/main.rb +14 -0
  87. data/test/data/users_guide/test_050/result.output +14 -0
  88. data/test/data/users_guide/test_050/views/_layout.rbhtml +10 -0
  89. data/test/data/users_guide/test_050/views/page.rbhtml +13 -0
  90. data/test/data/users_guide/test_051/main.rb +14 -0
  91. data/test/data/users_guide/test_051/result.output +12 -0
  92. data/test/data/users_guide/test_051/views/_layout.rbhtml +11 -0
  93. data/test/data/users_guide/test_051/views/page.rbhtml +13 -0
  94. data/test/data/users_guide/test_060/main.rb +14 -0
  95. data/test/data/users_guide/test_060/result.output +29 -0
  96. data/test/data/users_guide/test_060/views/_footer.rbhtml +3 -0
  97. data/test/data/users_guide/test_060/views/_header.rbhtml +3 -0
  98. data/test/data/users_guide/test_060/views/_layout.rbhtml +13 -0
  99. data/test/data/users_guide/test_060/views/page.rbhtml +13 -0
  100. data/test/data/users_guide/test_070/main.rb +14 -0
  101. data/test/data/users_guide/test_070/result.output +29 -0
  102. data/test/data/users_guide/test_070/views/_footer.rbhtml +3 -0
  103. data/test/data/users_guide/test_070/views/_header.rbhtml +3 -0
  104. data/test/data/users_guide/test_070/views/_layout.rbhtml +13 -0
  105. data/test/data/users_guide/test_070/views/page.rbhtml +13 -0
  106. data/test/data/users_guide/test_capturing/main.rb +24 -0
  107. data/test/data/users_guide/test_capturing/result.output +28 -0
  108. data/test/data/users_guide/test_capturing/views/_layout.rbhtml +21 -0
  109. data/test/data/users_guide/test_capturing/views/blog-post.rbhtml +13 -0
  110. data/test/data/users_guide/test_context/context.rb +5 -0
  111. data/test/data/users_guide/test_context/context.yaml +4 -0
  112. data/test/data/users_guide/test_context/example.rbhtml +5 -0
  113. data/test/data/users_guide/test_context/result1.output +6 -0
  114. data/test/data/users_guide/test_context/result2.output +6 -0
  115. data/test/data/users_guide/test_context/result3.output +6 -0
  116. data/test/data/users_guide/test_context/result4.output +6 -0
  117. data/test/data/users_guide/test_convert/example.rbhtml +5 -0
  118. data/test/data/users_guide/test_convert/result1.output +7 -0
  119. data/test/data/users_guide/test_convert/result2.output +6 -0
  120. data/test/data/users_guide/test_escape/main.rb +4 -0
  121. data/test/data/users_guide/test_escape/result.output +5 -0
  122. data/test/data/users_guide/test_escape/views/page.rbhtml +4 -0
  123. data/test/data/users_guide/test_execute/example.rbhtml +6 -0
  124. data/test/data/users_guide/test_execute/result.output +6 -0
  125. data/test/data/users_guide/test_fragmentcache/cache.d/items/1 +5 -0
  126. data/test/data/users_guide/test_fragmentcache/main.rb +21 -0
  127. data/test/data/users_guide/test_fragmentcache/result.output +8 -0
  128. data/test/data/users_guide/test_fragmentcache/result2.output +6 -0
  129. data/test/data/users_guide/test_fragmentcache/views/items.rbhtml +10 -0
  130. data/test/data/users_guide/test_logging/ex-logger.rb +11 -0
  131. data/test/data/users_guide/test_logging/example.rbhtml +0 -0
  132. data/test/data/users_guide/test_logging/result1.output +3 -0
  133. data/test/data/users_guide/test_logging/result2.output +2 -0
  134. data/test/data/users_guide/test_m17n/m17n.rb +44 -0
  135. data/test/data/users_guide/test_m17n/m17n.rbhtml +5 -0
  136. data/test/data/users_guide/test_m17n/result.output +9 -0
  137. data/test/data/users_guide/test_m17n/result_en.output +4 -0
  138. data/test/data/users_guide/test_m17n/result_fr.output +4 -0
  139. data/test/data/users_guide/test_nested/main.rb +8 -0
  140. data/test/data/users_guide/test_nested/result.output +15 -0
  141. data/test/data/users_guide/test_nested/views/_blog_layout.rbhtml +5 -0
  142. data/test/data/users_guide/{layout8_html.rbhtml → test_nested/views/_site_layout.rbhtml} +0 -0
  143. data/test/data/users_guide/test_nested/views/blog_post.rbhtml +4 -0
  144. data/test/data/users_guide/test_preprocessing/pp-example1.rb +14 -0
  145. data/test/data/users_guide/test_preprocessing/result1a.output +11 -0
  146. data/test/data/users_guide/test_preprocessing/result1b.output +5 -0
  147. data/test/data/users_guide/test_preprocessing/result1c.output +6 -0
  148. data/test/data/users_guide/test_preprocessing/result2a.output +10 -0
  149. data/test/data/users_guide/test_preprocessing/result2b.output +10 -0
  150. data/test/data/users_guide/test_preprocessing/result3a.output +2 -0
  151. data/test/data/users_guide/test_preprocessing/result3b.output +2 -0
  152. data/test/data/users_guide/test_preprocessing/views/pp-example1.rbhtml +4 -0
  153. data/test/data/users_guide/{example12.rbhtml → test_preprocessing/views/pp-example2.rbhtml} +4 -4
  154. data/test/data/users_guide/test_preprocessing/views/pp-example3.rbhtml +7 -0
  155. data/test/data/users_guide/test_retrieve/example.rbhtml +10 -0
  156. data/test/data/users_guide/test_retrieve/result1.output +11 -0
  157. data/test/data/users_guide/test_retrieve/result2.output +11 -0
  158. data/test/data/users_guide/test_retrieve/result3.output +11 -0
  159. data/test/data/users_guide/test_retrieve/result4.output +8 -0
  160. data/test/data/users_guide/test_retrieve/result5.output +5 -0
  161. data/test/data/users_guide/test_safe/result.output +6 -0
  162. data/test/data/users_guide/test_safe/safe-test.rb +21 -0
  163. data/test/data/users_guide/test_safehelper/main.rb +16 -0
  164. data/test/data/users_guide/test_safehelper/result.output +8 -0
  165. data/test/data/users_guide/{example3.rbhtml → test_syntax_check/example.rbhtml} +0 -0
  166. data/test/data/users_guide/test_syntax_check/result.output +2 -0
  167. data/test/data/users_guide/test_trace/layout.rbhtml +7 -0
  168. data/test/data/users_guide/test_trace/main.rbhtml +5 -0
  169. data/test/data/users_guide/test_trace/result.output +16 -0
  170. data/test/data/users_guide/test_trace/trace-example.rb +4 -0
  171. data/test/oktest.rb +755 -0
  172. data/test/test_all.rb +24 -14
  173. data/test/test_engine.rb +628 -63
  174. data/test/test_engine.yaml +40 -3
  175. data/test/test_examples.rb +14 -12
  176. data/test/test_faq.rb +17 -12
  177. data/test/test_htmlhelper.rb +104 -33
  178. data/test/test_main.rb +32 -21
  179. data/test/test_main.yaml +2 -2
  180. data/test/test_safe.rb +206 -0
  181. data/test/test_store.rb +220 -0
  182. data/test/test_tcache.rb +94 -0
  183. data/test/test_template.rb +65 -23
  184. data/test/test_template.yaml +7 -7
  185. data/test/test_users_guide.rb +75 -29
  186. data/test/testcase-helper.rb +20 -18
  187. data/test/testunit-assertions.rb +71 -0
  188. metadata +185 -159
  189. data/doc-api/classes/Tenjin.html +0 -141
  190. data/doc-api/classes/Tenjin/ArrayBufferTemplate.html +0 -270
  191. data/doc-api/classes/Tenjin/BaseContext.html +0 -329
  192. data/doc-api/classes/Tenjin/Context.html +0 -126
  193. data/doc-api/classes/Tenjin/ContextHelper.html +0 -461
  194. data/doc-api/classes/Tenjin/Engine.html +0 -616
  195. data/doc-api/classes/Tenjin/ErubisTemplate.html +0 -166
  196. data/doc-api/classes/Tenjin/HtmlHelper.html +0 -359
  197. data/doc-api/classes/Tenjin/Preprocessor.html +0 -242
  198. data/doc-api/classes/Tenjin/Template.html +0 -916
  199. data/doc-api/created.rid +0 -1
  200. data/doc-api/files/README_txt.html +0 -188
  201. data/doc-api/files/lib/tenjin_rb.html +0 -136
  202. data/doc-api/fr_class_index.html +0 -36
  203. data/doc-api/fr_file_index.html +0 -28
  204. data/doc-api/fr_method_index.html +0 -91
  205. data/doc-api/index.html +0 -24
  206. data/doc-api/rdoc-style.css +0 -208
  207. data/doc/examples.html +0 -312
  208. data/doc/faq.html +0 -909
  209. data/examples/preprocessing/select.rbhtml.cache +0 -17
  210. data/test/Rookbook.yaml +0 -14
  211. data/test/assert-text-equal.rb +0 -45
  212. data/test/data/faq/ex10-baselayout.rbhtml +0 -27
  213. data/test/data/faq/ex11-content.rbhtml +0 -9
  214. data/test/data/faq/ex8-m18n.rb +0 -77
  215. data/test/data/users_guide/content6.rbhtml +0 -3
  216. data/test/data/users_guide/content7.rbhtml +0 -5
  217. data/test/data/users_guide/content8.rbhtml +0 -2
  218. data/test/data/users_guide/contextdata.rb +0 -7
  219. data/test/data/users_guide/datafile.rb +0 -5
  220. data/test/data/users_guide/datafile.yaml +0 -10
  221. data/test/data/users_guide/ex.rbhtml +0 -6
  222. data/test/data/users_guide/ex.result +0 -7
  223. data/test/data/users_guide/ex.script +0 -5
  224. data/test/data/users_guide/ex_script.result +0 -7
  225. data/test/data/users_guide/ex_source.result +0 -8
  226. data/test/data/users_guide/example1.rbhtml +0 -12
  227. data/test/data/users_guide/example1.result +0 -17
  228. data/test/data/users_guide/example10.rbhtml +0 -4
  229. data/test/data/users_guide/example10_template_args.result +0 -6
  230. data/test/data/users_guide/example11.rbhtml +0 -5
  231. data/test/data/users_guide/example11_template_args_result +0 -2
  232. data/test/data/users_guide/example12_preprocessed.result +0 -10
  233. data/test/data/users_guide/example12_preprocessed_source.result +0 -10
  234. data/test/data/users_guide/example13.rbhtml +0 -6
  235. data/test/data/users_guide/example13_preprocessed.result +0 -2
  236. data/test/data/users_guide/example13_preprocessed_source.result +0 -2
  237. data/test/data/users_guide/example14.rb +0 -32
  238. data/test/data/users_guide/example14.rbhtml +0 -6
  239. data/test/data/users_guide/example14_tmplclass.result +0 -15
  240. data/test/data/users_guide/example15.rb +0 -10
  241. data/test/data/users_guide/example15_escapefunc.result +0 -14
  242. data/test/data/users_guide/example16.rbhtml +0 -4
  243. data/test/data/users_guide/example16a.rb +0 -10
  244. data/test/data/users_guide/example16a.result +0 -4
  245. data/test/data/users_guide/example16b.rb +0 -13
  246. data/test/data/users_guide/example16b.result +0 -4
  247. data/test/data/users_guide/example16c.rb +0 -12
  248. data/test/data/users_guide/example16c.result +0 -4
  249. data/test/data/users_guide/example16d.rb +0 -27
  250. data/test/data/users_guide/example16d.result +0 -4
  251. data/test/data/users_guide/example1_S.result +0 -14
  252. data/test/data/users_guide/example1_SXNC.result +0 -10
  253. data/test/data/users_guide/example1_source.result +0 -14
  254. data/test/data/users_guide/example2.rbhtml +0 -3
  255. data/test/data/users_guide/example2_sb.result2 +0 -9
  256. data/test/data/users_guide/example3_syntaxcheck.result +0 -2
  257. data/test/data/users_guide/example4.rbhtml +0 -13
  258. data/test/data/users_guide/example4_datafile_rb.result +0 -13
  259. data/test/data/users_guide/example4_yaml.result +0 -13
  260. data/test/data/users_guide/example5.rbhtml +0 -9
  261. data/test/data/users_guide/example5_datastr_rb.result +0 -9
  262. data/test/data/users_guide/example5_datastr_yaml.result +0 -9
  263. data/test/data/users_guide/example6.rbhtml +0 -19
  264. data/test/data/users_guide/example6_layout.result +0 -29
  265. data/test/data/users_guide/example6_nested.result +0 -28
  266. data/test/data/users_guide/example7_layout2.result +0 -13
  267. data/test/data/users_guide/example8_layout3.result +0 -8
  268. data/test/data/users_guide/example9.rbhtml +0 -18
  269. data/test/data/users_guide/example9_capture.result +0 -26
  270. data/test/data/users_guide/footer.html +0 -5
  271. data/test/data/users_guide/footer.rbhtml +0 -4
  272. data/test/data/users_guide/layout6.rbhtml +0 -17
  273. data/test/data/users_guide/layout7.rbhtml +0 -9
  274. data/test/data/users_guide/layout8_xhtml.rbhtml +0 -6
  275. data/test/data/users_guide/layout9.rbhtml +0 -25
  276. data/test/data/users_guide/sidemenu.rbhtml +0 -5
  277. data/test/data/users_guide/user_app.cgi +0 -39
  278. data/test/data/users_guide/user_app.result +0 -30
  279. data/test/data/users_guide/user_create.rbhtml +0 -6
  280. data/test/data/users_guide/user_edit.rbhtml +0 -7
  281. data/test/data/users_guide/user_form.rbhtml +0 -10
  282. data/test/data/users_guide/user_layout.rbhtml +0 -16
@@ -0,0 +1,5 @@
1
+ <div>
2
+ <?RB ## '_()' represents translator method ?>
3
+ <?RB _ = @_ ?>
4
+ <p>${{_['Hello']}} ${@username}!</p>
5
+ </div>
@@ -0,0 +1,9 @@
1
+ $ ruby m17n.rb
2
+ --- lang: en ---
3
+ <div>
4
+ <p>Hello World!</p>
5
+ </div>
6
+ --- lang: fr ---
7
+ <div>
8
+ <p>Bonjour World!</p>
9
+ </div>
@@ -0,0 +1,4 @@
1
+ $ cat m17n.rbhtml.en.cache
2
+ _buf << %Q`<div>
3
+ <p>Hello #{escape((@username).to_s)}!</p>
4
+ </div>\n`
@@ -0,0 +1,4 @@
1
+ $ cat m17n.rbhtml.fr.cache
2
+ _buf << %Q`<div>
3
+ <p>Bonjour #{escape((@username).to_s)}!</p>
4
+ </div>\n`
@@ -0,0 +1,8 @@
1
+ require 'tenjin'
2
+ engine = Tenjin::Engine.new(:path=>['views'])
3
+ context = {
4
+ :title => 'Blog Post Test',
5
+ :post_content => "Foo\nBar\nBaz",
6
+ }
7
+ html = engine.render('blog_post.rbhtml', context)
8
+ print(html)
@@ -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> # :
@@ -0,0 +1,5 @@
1
+ <?rb @_layout = '_site_layout.rbhtml' ?>
2
+ <h2>${@title}</h2>
3
+ <!-- content -->
4
+ #{@_content}
5
+ <!-- /content -->
@@ -0,0 +1,4 @@
1
+ <?rb @_layout = '_blog_layout.rbhtml' ?>
2
+ <div class="article">
3
+ #{text2html(@post_content)}
4
+ </div>
@@ -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,5 @@
1
+ $ rbtenjin -P -c '$VALUE="My Great Example"' views/pp-example1.rbhtml
2
+ ## normal expression
3
+ value = ${$VALUE}
4
+ ## with preprocessing
5
+ value = My Great Example
@@ -0,0 +1,6 @@
1
+ $ rbtenjin -sP -c '$VALUE="My Great Example"' views/pp-example1.rbhtml
2
+ _buf = ''; _buf << %Q`\#\# normal expression
3
+ value = ${$VALUE}
4
+ \#\# with preprocessing
5
+ value = #{escape((_decode_params(($VALUE))).to_s)}\n`
6
+ _buf.to_s
@@ -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`
@@ -0,0 +1,2 @@
1
+ $ rbtenjin -P views/pp-example3.rbhtml
2
+ <a href="/items/show/#{params["id"]}">Show ${params["name"]}</a>
@@ -0,0 +1,2 @@
1
+ $ rbtenjin --preprocess -sb views/pp-example3.rbhtml
2
+ _buf << %Q`<a href="/items/show/#{params["id"]}">Show #{escape((params["name"]).to_s)}</a>\n`
@@ -0,0 +1,4 @@
1
+ ## normal expression
2
+ value = ${$VALUE}
3
+ ## with preprocessing
4
+ value = ${{$VALUE}}
@@ -3,10 +3,10 @@
3
3
  <?RB "FL" => "Florida", ?>
4
4
  <?RB "TX" => "Texas", ?>
5
5
  <?RB "HI" => "Hawaii", } ?>
6
- <?rb chk = { @params['state'] => ' selected="selected"' } ?>
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.inspect}}]}>${{states[code]}}</option>
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,7 @@
1
+ <?RB
2
+ ## ex. link_to('Show', '/show/1') => <a href="/show/1">Show</a>
3
+ def link_to(label, url)
4
+ return "<a href=\"#{url}\">#{label}</a>"
5
+ end
6
+ ?>
7
+ #{{link_to('Show '+_P('params["name"]'), '/items/show/'+_p('params["id"]'))}}
@@ -0,0 +1,10 @@
1
+ <table>
2
+ <?rb i = 0 ?>
3
+ <?rb for item in @items ?>
4
+ <?rb i += 1 ?>
5
+ <tr>
6
+ <td>#{i}</td>
7
+ <td>${item}</td>
8
+ </tr>
9
+ <?rb end ?>
10
+ </table>
@@ -0,0 +1,11 @@
1
+ $ rbtenjin -Sb example.rbhtml
2
+
3
+ i = 0
4
+ for item in @items
5
+ i += 1
6
+
7
+
8
+ escape((item).to_s);
9
+
10
+ end
11
+
@@ -0,0 +1,11 @@
1
+ $ rbtenjin -Xb example.rbhtml
2
+
3
+ i = 0
4
+ for item in @items
5
+ i += 1
6
+
7
+
8
+
9
+
10
+ end
11
+
@@ -0,0 +1,11 @@
1
+ $ rbtenjin -NXb example.rbhtml
2
+ 1:
3
+ 2: i = 0
4
+ 3: for item in @items
5
+ 4: i += 1
6
+ 5:
7
+ 6:
8
+ 7:
9
+ 8:
10
+ 9: end
11
+ 10:
@@ -0,0 +1,8 @@
1
+ $ rbtenjin -UNXb example.rbhtml
2
+
3
+ 2: i = 0
4
+ 3: for item in @items
5
+ 4: i += 1
6
+
7
+ 9: end
8
+
@@ -0,0 +1,5 @@
1
+ $ rbtenjin -CNXb example.rbhtml
2
+ 2: i = 0
3
+ 3: for item in @items
4
+ 4: i += 1
5
+ 9: end
@@ -0,0 +1,6 @@
1
+ $ ruby safe-test.rb
2
+ _buf << %Q`s1 = #{safe_escape((@s1).to_s)}
3
+ s2 = #{safe_escape((@s2).to_s)}\n`
4
+ ---------------------
5
+ s1 = &lt;b&gt;SOS&lt;/b&gt;
6
+ s2 = <b>SOS</b>
@@ -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 #=> &lt;AAA&gt;
10
+ puts safe_escape(s) #=> &lt;AAA&gt;
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>
@@ -0,0 +1,8 @@
1
+ $ ruby main.rb
2
+ false
3
+ true
4
+ &lt;AAA&gt;
5
+ &lt;AAA&gt;
6
+ true
7
+ <AAA>
8
+ <AAA>
@@ -0,0 +1,2 @@
1
+ $ rbtenjin -wz example.rbhtml
2
+ example.rbhtml:5: syntax error, unexpected $end, expecting kEND
@@ -0,0 +1,7 @@
1
+ <html>
2
+ <body>
3
+ <div class="content">
4
+ <?rb echo(@_content) ?>
5
+ </div>
6
+ </body>
7
+ </html>
@@ -0,0 +1,5 @@
1
+ <ul>
2
+ <?rb for item in @items ?>
3
+ <li>${item}</li>
4
+ <?rb end ?>
5
+ </ul>
@@ -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 ***** -->
@@ -0,0 +1,4 @@
1
+ require 'tenjin'
2
+ engine = Tenjin::Engine.new(:layout=>'layout.rbhtml', :trace=>true)
3
+ output = engine.render('main.rbhtml', {'items'=>['A','B','C']})
4
+ puts output
@@ -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