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
@@ -2,6 +2,169 @@
2
2
  = CHANGES
3
3
 
4
4
 
5
+ == Release 0.7.0
6
+
7
+ * [enhance] Support Ruby 1.9.
8
+
9
+ * [enhance] Add 'HtmlHelper#escape_html()' which escapes '\'' into '''.
10
+
11
+ * [change] Change 'HtmlHelper#escape()' to be alias of '#escape_html()', not '#escape_xml()'
12
+
13
+ * [change] '${}' is changed to escape "'" into '&#039'.
14
+
15
+ * [enhance] Fragment cache support
16
+
17
+ ## fragment cache with key ('items/1') and lifetime (60sec)
18
+ <?rb cache_with('items/1', 60) do ?>
19
+ <ul>
20
+ <?rb for item in @get_items.call() ?>
21
+ <li>${item}</li>
22
+ <?rb end ?>
23
+ </ul>
24
+ <?rb end ?>
25
+
26
+ ## use file-base cache store
27
+ Dir.mkdir('cache.d') unless File.exist?('cache.d')
28
+ kv_store = Tenjin::FileBaseStore.new('cache.d')
29
+ Tenjin::Engine.data_cache = kv_store
30
+
31
+ See: http://www.kuwata-lab.com/tenjin/rbtenjin-users-guide.html#fragment-cache
32
+
33
+ * [enhance] (EXPERIMENTAL) Add 'SafeTemplate' and 'SafeEngine' classes which escapes HTML characters automatically.
34
+ * SafeTemplate and SafeEngine escapes context data except SafeString object.
35
+ * Using these classes, only '${...}' is available. '#{...}' is inhibited.
36
+
37
+ ##
38
+ include Tenjin::HtmlHelper
39
+ include Tenjin::SafeHelper
40
+ context = {
41
+ :text1=>"<AAA>", # will be escaped
42
+ :text2=>safe_str("<AAA>"), # not escaped because marked as 'already escaped'
43
+ }
44
+ engine = Template::SafeEngine.new()
45
+ html = engine.render('example.rbhtml', context)
46
+ ## example.rbhtml:
47
+ #<p>text1 = ${@text1}<p>
48
+ #<p>text2 = ${@text2}<p>
49
+ ## Output:
50
+ #<p>text1 = &lt;AAA&gt;</p>
51
+ #<p>text2 = <AAA></p>
52
+
53
+ See: http://www.kuwata-lab.com/tenjin/rbtenjin-users-guide.html#auto-escaping
54
+
55
+ * [enhance] Add new option ':lang' to 'Template.new()'
56
+ which will be helpful to create M17N page.
57
+ This feature should be used with preprocessing.
58
+
59
+ ## creates 'example.rbhtml.en.cache' file
60
+ lang = "en"
61
+ engine = Tenjin::Engine.new(:preprocess=>true, :lang=>lang)
62
+ engine.render("example.rbhtml", {})
63
+
64
+ ## creates 'example.rbhtml.fr.cache' file
65
+ lang = "fr"
66
+ engine = Tenjin::Engine.new(:preprocess=>true, :lang=>lang)
67
+ engine.render("example.rbhtml", {})
68
+
69
+ See: http://www.kuwata-lab.com/tenjin/rbtenjin-users-guide.html#m17n
70
+
71
+ * [enhance] 'Template' class now supports ':trace' option which prints template filename as HTML comment when importing other template file.
72
+
73
+ ## print '<!-- **** begin: partial.rhtml **** -->'
74
+ ## and '<!-- **** end: partial.rhtml **** -->'
75
+ ## when importing other template.
76
+ engine = Tenjin::Engine.new(:trace=>true)
77
+
78
+ See: http://www.kuwata-lab.com/tenjin/rbtenjin-users-guide.html#trace
79
+
80
+ * [enhance] 'Tenjin::Template' class now accepts ':input' option which represents template file content.
81
+
82
+ input = <<END
83
+ <p>Hello ${@name}!
84
+ END
85
+ t = Tenjin::Template.new(:input=>input)
86
+ puts t.render({:name=>"Guest"})
87
+
88
+ * [enhance] Support logger.
89
+
90
+ require 'logger'
91
+ Tenjin.logger = Logger.new($stderr)
92
+
93
+ See: http://www.kuwata-lab.com/tenjin/rbtenjin-users-guide.html#logging
94
+
95
+ * [enhance] Add new module 'Tenjin::SafeHelper' which includes 'safe_str()', 'safe_escape()', and 'safe_str?()'.
96
+
97
+ include Tenjin::HtmlHelper
98
+ include Tenjin::SafeHelper
99
+ #
100
+ s = "<AAA>"
101
+ puts safe_str?(s) #=> false
102
+ s = safe_escape(s) # same as SafeString.new(escape(s))
103
+ puts safe_str?(s) #=> true
104
+ puts s #=> &lt;AAA&gt;
105
+ puts safe_escape(s) #=> &lt;AAA&gt;
106
+ #
107
+ s = "<AAA>"
108
+ s = safe_str(s) # same as SafeString.new(s)
109
+ puts safe_str?(s) #=> true
110
+ puts s #=> <AAA>
111
+ puts safe_escape(s) #=> <AAA>
112
+
113
+ See: http://www.kuwata-lab.com/tenjin/rbtenjin-users-guide.html#auto-escaping
114
+
115
+ * [change] Html tag helpers (such as 'checked()') now returns 'SafeString' object to support both 'Tenjin::Template' and 'Tenjin::SafeTemplate'.
116
+
117
+ * [change] Html tag helpers (such as 'checked()') are moved from 'Tenjin::HtmlHelper' into new module 'Tenjin::HtmlTagHelper'.
118
+
119
+ * [enhance] Add 'new_cycle()' helper which returns values cyclic.
120
+
121
+ ## template
122
+ <?rb cycle = new_cycle('odd', 'even') ?>
123
+ <?rb 5.times do ?>
124
+ class="${cycle}"
125
+ <?rb end ?>
126
+ ## output
127
+ class="odd"
128
+ class="even"
129
+ class="odd"
130
+ class="even"
131
+ class="odd"
132
+
133
+ * [enhance] Add new html tag 'js_link()'.
134
+
135
+ js_link('Show', '$().show()')
136
+ #=> '<a href="javascript:undefined" onclick="$().show();return false">Show</a>
137
+
138
+ * [enhance] Add new html tag 'nv()' which generates 'name' and 'value' attributes.
139
+
140
+ nv('gender', 'F') #=> ' name="gender" value="F"
141
+ nv('gender', 'F', '-') #=> ' name="gender" value="F" id="gender-F"
142
+
143
+ * [enhance] Add 'public_html/rbtenjin.cgi' which is a sample script to use tenjin in CGI script.
144
+
145
+ See: http://www.kuwata-lab.com/tenjin/rbtenjin-users-guide.html#cgi-script
146
+
147
+ * [bugfix] import() now works well with preprocessing enabled.
148
+
149
+ * [change][internal] change test scripts to use 'oktset.rb' instead of test::unit.
150
+
151
+ * [change][internal] add 'FileFinder' class
152
+
153
+ * [change][internal] rewrite 'Engine' class to use 'FileFinder' class
154
+
155
+ * [change][internal] change 'TemplateCache#load()' to make 'timestamp' arg as optional
156
+
157
+ * [change][internal] change a lot of methods of 'Engine' class to be private
158
+
159
+ * [change][internal] rename 'Engine.datastore()' to 'Engine.data_store()'
160
+
161
+ * [change][internal] eliminate timestamp checking of template files
162
+
163
+ * [change][internal] Changed to use File.rename() instead of File.open() + File#flock()
164
+ when creating template cache file.
165
+
166
+
167
+
5
168
  == Release 0.6.2 (2008-02-24)
6
169
 
7
170
  * Rubinius supported.
@@ -1,20 +1,19 @@
1
- copyright(c) 2007-2008 kuwata-lab.com all rights reserved.
1
+ copyright(c) 2007-2011 kuwata-lab.com all rights reserved
2
2
 
3
- Permission is hereby granted, free of charge, to any person obtaining
4
- a copy of this software and associated documentation files (the
5
- "Software"), to deal in the Software without restriction, including
6
- without limitation the rights to use, copy, modify, merge, publish,
7
- distribute, sublicense, and/or sell copies of the Software, and to
8
- permit persons to whom the Software is furnished to do so, subject to
9
- the following conditions:
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
10
9
 
11
- The above copyright notice and this permission notice shall be
12
- included in all copies or substantial portions of the Software.
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
13
12
 
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
- NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
- LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
- OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.txt CHANGED
@@ -1,7 +1,7 @@
1
1
  = README
2
2
 
3
- release:: 0.6.2
4
- copyright:: copyright(c) 2007-2008 kuwata-lab.com all rights reserved.
3
+ release:: 0.7.0
4
+ copyright:: copyright(c) 2007-2011 kuwata-lab.com all rights reserved
5
5
 
6
6
 
7
7
  == About
@@ -34,11 +34,11 @@ See doc/*.html for details.
34
34
 
35
35
  $ sudo gem install tenjin
36
36
 
37
- * Else download rbtenjin-0.6.2.tar.bz2 and just copy 'lib/tenjin.rb' and
37
+ * Else download rbtenjin-0.7.0.tar.bz2 and just copy 'lib/tenjin.rb' and
38
38
  'bin/rbtenjin' into proper directory.
39
39
 
40
- $ tar xjf rbtenjin-0.6.2.tar.bz2
41
- $ cd rbtenjin-0.6.2/
40
+ $ tar xjf rbtenjin-0.7.0.tar.bz2
41
+ $ cd rbtenjin-0.7.0/
42
42
  $ sudo copy lib/tenjin.rb /usr/local/lib/ruby/1.8/site_ruby/1.8/
43
43
  $ sudo copy bin/rbtenjin /usr/local/bin/
44
44
 
@@ -0,0 +1,9 @@
1
+ ntimes = 1000
2
+
3
+ all:
4
+ ruby bench.rb -n $(ntimes)
5
+
6
+ clean:
7
+ rm -rf *.cache bench_*.rhtml bench_*.rbhtml* *.result
8
+
9
+
@@ -375,7 +375,8 @@ Benchmark.bm(20) do |job|
375
375
  when 'tenjin'
376
376
  job.report(target) do
377
377
  ntimes.times do
378
- engine = Tenjin::Engine.new(:cache=>true)
378
+ #engine = Tenjin::Engine.new(:cache=>true)
379
+ engine = Tenjin::Engine.new(:cache=>Tenjin::FileBaseTemplateCache.new)
379
380
  output = engine.render(tmpl_tenjin, context)
380
381
  print output
381
382
  end
@@ -422,7 +423,7 @@ Benchmark.bm(20) do |job|
422
423
  when 'tenjin-defun-reuse'
423
424
  job.report(target) do
424
425
  template = Tenjin::Template.new(tmpl_tenjin)
425
- defun = defun_code(template.rbcode)
426
+ defun = defun_code(template.script)
426
427
  context.instance_eval(defun)
427
428
  ntimes.times do
428
429
  output = context.tmpl_tenjin_view()
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  ##
4
- ## copyright(c) 2007-2008 kuwata-lab.com all rights reserved.
4
+ ## copyright(c) 2007-2011 kuwata-lab.com all rights reserved
5
5
  ##
6
6
  ## Permission is hereby granted, free of charge, to any person obtaining
7
7
  ## a copy of this software and associated documentation files (the
@@ -23,8 +23,11 @@
23
23
  ## WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
24
  ##
25
25
 
26
- ## $Rev: 70 $
27
- ## $Release: 0.6.2 $
26
+ ##
27
+ ## $Release: 0.7.0 $
28
+ ## copyright(c) 2007-2011 kuwata-lab.com all rights reserved
29
+ ## $License: MIT License $
30
+ ##
28
31
 
29
32
  require 'tenjin'
30
33
 
@@ -27,7 +27,7 @@ pre {
27
27
  white-space:pre;
28
28
  }
29
29
 
30
- .program {
30
+ pre.program {
31
31
  border-style:solid;
32
32
  border-width:1px;
33
33
  border-color:#6699FF;
@@ -38,7 +38,7 @@ pre {
38
38
  word-break:break-all;
39
39
  }
40
40
 
41
- .terminal {
41
+ pre.terminal {
42
42
  border-style:solid;
43
43
  border-width:1;
44
44
  border-color:#999999;
@@ -49,7 +49,7 @@ pre {
49
49
  word-break:break-all;
50
50
  }
51
51
 
52
- .output {
52
+ pre.output {
53
53
  border-style:solid;
54
54
  border-width:1px;
55
55
  border-color:#CCCCCC;
@@ -61,6 +61,12 @@ pre {
61
61
  }
62
62
 
63
63
 
64
+ pre strong {
65
+ color: #990000;
66
+ font-weight: bold;
67
+ }
68
+
69
+
64
70
  .program_caption {
65
71
  margin-top: 20px;
66
72
  }
@@ -168,7 +174,7 @@ h3, .subsection {
168
174
  font-size:small;
169
175
  }
170
176
 
171
- .note {
177
+ div.note, div.tips {
172
178
  background-color:#FFFFDD;
173
179
  border-style:solid;
174
180
  border-width:0px 1px 0px 1px;
@@ -176,9 +182,14 @@ h3, .subsection {
176
182
  color:#333300;
177
183
  /* font-size:small; */
178
184
  line-height:120%;
185
+ margin-top: 10px;
179
186
  padding: 5px 20px 5px 20px;
180
187
  }
181
188
 
189
+ div.note span.caption, div.tips span.caption {
190
+ color: #C60;
191
+ }
192
+
182
193
  .figure {
183
194
  /*
184
195
  border-width:1px;
@@ -186,3 +197,13 @@ h3, .subsection {
186
197
  white-space:pre;
187
198
  */
188
199
  }
200
+
201
+ strong {
202
+ color: #630;
203
+ font-weight; bold;
204
+ }
205
+
206
+
207
+ em {
208
+ font-style: italic;
209
+ }
@@ -1,1734 +1,2259 @@
1
1
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
2
+
2
3
  <html>
3
4
  <head>
4
- <meta http-equiv="Content-Type" content="text/html">
5
+ <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
5
6
  <title>rbTenjin User's Guide</title>
6
7
  <meta name="generator" content="kwaser">
7
8
  <meta http-equiv="Content-Style-Type" content="text/css">
8
9
  <link rel="stylesheet" href="docstyle.css" type="text/css">
9
- </head>
10
- <body>
10
+ </head>
11
11
 
12
+ <body>
12
13
  <blockquote>
13
- <div class="mainbody">
14
+ <div class="mainbody">
15
+ <div align="left">
16
+ <h1>rbTenjin User's Guide</h1>
17
+ </div>
14
18
 
15
- <div align="left"><h1>rbTenjin User's Guide</h1></div>
16
- <div align="left">
17
- last update: $Date: 2008-02-24 11:43:28 +0900 (Sun, 24 Feb 2008) $<br>
18
- </div>
19
+ <div align="left">
20
+ release: 0.7.0<br>
21
+ </div>
19
22
 
20
- <p>Release: 0.6.2
21
- </p>
22
- <p>Table of Contents:
23
- <ul>
24
- <li><a href="#intro">Introduction</a>
25
- <ul>
26
- <li><a href="#overview">Overview</a>
27
- </li>
28
- <li><a href="#features">Features</a>
29
- </li>
30
- <li><a href="#benchmark">Benchmark</a>
31
- </li>
32
- </ul>
33
- </li>
34
- <li><a href="#installation">Installation</a>
35
- </li>
36
- <li><a href="#desguide">Designer's Guide</a>
37
- <ul>
38
- <li><a href="#des-notation">Notation</a>
39
- </li>
40
- <li><a href="#des-convert">Convert into Ruby Code</a>
41
- </li>
42
- <li><a href="#des-syntaxchk">Syntax Checking</a>
43
- </li>
44
- <li><a href="#des-contextdata">Context Data File</a>
45
- </li>
46
- <li><a href="#des-cmlinecontext">Command-line Context Data</a>
47
- </li>
48
- <li><a href="#des-nested-template">Nested Template</a>
49
- </li>
50
- <li><a href="#des-layout">Layout Template</a>
51
- </li>
52
- <li><a href="#des-capturing">Capturing</a>
53
- </li>
54
- <li><a href="#des-args">Template Arguments</a>
55
- </li>
56
- <li><a href="#des-preprocess">Preprocessing</a>
57
- </li>
58
- <li><a href="#des-otheropts">Other Options</a>
59
- </li>
60
- </ul>
61
- </li>
62
- <li><a href="#devguide">Developer's Guide</a>
63
- <ul>
64
- <li><a href="#dev-example">An Example</a>
65
- </li>
66
- <li><a href="#dev-classes">Classes and Functions in rbTenjin</a>
67
- </li>
68
- <li><a href="#dev-templateclass">Class Tenjin::Template</a>
69
- </li>
70
- <li><a href="#dev-engineclass">Class Tenjin::Engine</a>
71
- </li>
72
- <li><a href="#dev-initopts">Template Initialize Options</a>
73
- </li>
74
- <li><a href="#dev-helpers">Add Your Helper Functions</a>
75
- </li>
76
- <li><a href="#dev-othertopics">Other Topics</a>
77
- </li>
78
- </ul>
79
- </li>
80
- </ul>
81
- </p>
82
- <a name="intro"></a>
83
- <h2 class="section1">Introduction</h2>
84
- <a name="overview"></a>
85
- <h3 class="section2">Overview</h3>
86
- <p>rbTenjin is a very fast and lightweight template engine based on embedded Ruby.
87
- You can embed Ruby statements and expressions into your text file.
88
- rbTenjin converts it into Ruby script and evaluate it.
89
- </p>
90
- <p>The following is an example of rbTenjin.
91
- </p>
92
- <a name="ex.rbhtml"></a>
93
- <div class="program_caption">
94
- File 'ex.rbhtml':</div>
95
- <pre class="program">Hello <strong>#{@name}</strong>!
96
- &lt;ul&gt;
97
- <strong>&lt;?rb for item in @items ?&gt;</strong>
98
- &lt;li&gt;<strong>${item}</strong>&lt;/li&gt;
99
- <strong>&lt;?rb end ?&gt;</strong>
100
- &lt;/ul&gt;
101
- </pre>
102
- <p>Here is the notation:
103
- </p>
104
- <ul type="disc">
105
- <li><code>&lt;?rb ... ?&gt;</code> represents embedded Ruby statements.
106
- </li>
107
- <li><code>#{...}</code> represents embedded Ruby expression.
108
- </li>
109
- <li><code>${...}</code> represents embedded escaped (sanitized) Ruby expression.
110
- </li>
111
- </ul>
112
- <a name="ex_source.result"></a>
113
- <div class="terminal_caption">
114
- Result of covertion into Ruby script:</div>
115
- <pre class="terminal">$ rbtenjin -s ex.rbhtml
116
- _buf = ''; _buf &lt;&lt; %Q`Hello <strong>#{@name}</strong>!
117
- &lt;ul&gt;\n`
118
- <strong>for item in @items</strong>
119
- _buf &lt;&lt; %Q` &lt;li&gt;<strong>#{escape((item).to_s)}</strong>&lt;/li&gt;\n`
120
- <strong>end</strong>
121
- _buf &lt;&lt; %Q`&lt;/ul&gt;\n`
122
- _buf.to_s
123
- </pre>
124
- <a name="ex.result"></a>
125
- <div class="terminal_caption">
126
- Output of execution with context data:</div>
127
- <pre class="terminal">$ rbtenjin -c "@name='World'; @items=['&lt;AAA&gt;','B&amp;B','\"CCC\"']" ex.rbhtml
128
- Hello World!
129
- &lt;ul&gt;
130
- &lt;li&gt;&amp;lt;AAA&amp;gt;&lt;/li&gt;
131
- &lt;li&gt;B&amp;amp;B&lt;/li&gt;
132
- &lt;li&gt;&amp;quot;CCC&amp;quot;&lt;/li&gt;
133
- &lt;/ul&gt;
134
- </pre>
135
- <a name="ex.script"></a>
136
- <div class="program_caption">
137
- Example of Ruby script</div>
138
- <pre class="program">require 'tenjin'
139
- engine = Tenjin::Engine.new()
140
- context = { :name=&gt;'World', :items=&gt;['&lt;AAA&gt;', 'B&amp;B', '"CCC"'] }
141
- output = engine.render('ex.rbhtml', context)
142
- print output
23
+ <div class="toc"><span class="caption">Table of Contents:</span>
24
+
25
+ <ul>
26
+ <li>
27
+ <a href="#overview">Overview</a>
28
+
29
+ <ul>
30
+ <li><a href="#features">Features</a></li>
31
+
32
+ <li><a href="#install">Install</a></li>
33
+
34
+ <li><a href="#benchmark">Benchmark</a></li>
35
+ </ul>
36
+ </li>
37
+
38
+ <li>
39
+ <a href="#basic-examples">Basic Examples</a>
40
+
41
+ <ul>
42
+ <li><a href="#template-syntax">Template Syntax</a></li>
43
+
44
+ <li><a href="#render-template">Render Template</a></li>
45
+
46
+ <li><a href="#source-code">Show Converted Source Code</a></li>
47
+
48
+ <li><a href="#layout-template">Layout Template</a></li>
49
+
50
+ <li><a href="#context-variables">Context Variables</a></li>
51
+
52
+ <li><a href="#template-arguments">Template Arguments</a></li>
53
+
54
+ <li><a href="#partial-template">Include Partial Template</a></li>
55
+
56
+ <li><a href="#template-short-name">Template Short Name</a></li>
57
+
58
+ <li>
59
+ <a href="#helper-functions">Helper Function</a>
60
+
61
+ <ul>
62
+ <li><a href="#Tenjin::ContextHelper">Tenjin::ContextHelper</a></li>
63
+
64
+ <li><a href="#Tenjin::HtmlHelper">Tenjin::HtmlHelper</a></li>
65
+
66
+ <li><a href="#Tenjin::SafeHelper">Tenjin::SafeHelper</a></li>
67
+
68
+ <li><a href="#Tenjin::HtmlTagHelper">Tenjin::HtmlTagHelper</a></li>
69
+ </ul>
70
+ </li>
71
+ </ul>
72
+ </li>
73
+
74
+ <li>
75
+ <a href="#advanced-features">Advanced Features</a>
76
+
77
+ <ul>
78
+ <li><a href="#safe-template">Safe Template</a></li>
79
+
80
+ <li><a href="#nested-layout-template">Nested Layout Template</a></li>
81
+
82
+ <li><a href="#trace">Trace Templates</a></li>
83
+
84
+ <li><a href="#capturing">Capturing</a></li>
85
+
86
+ <li><a href="#templace-cache">Template Cache</a></li>
87
+
88
+ <li><a href="#fragment-cache">Fragment Cache</a></li>
89
+
90
+ <li><a href="#logging">Logging</a></li>
91
+
92
+ <li>
93
+ <a href="#preprocessing">Preprocessing</a>
94
+
95
+ <ul>
96
+ <li><a href="#preprocessing-basics">Basics of Preprocessing</a></li>
97
+
98
+ <li><a href="#preprocessing-loop-expantion">Loop Expantion</a></li>
99
+
100
+ <li><a href="#preprocessing-parameters">Parameters</a></li>
101
+ </ul>
102
+ </li>
103
+
104
+ <li><a href="#m17n">M17N Page</a></li>
105
+
106
+ <li><a href="#cgi-script">Make Tenjin as PHP-like Tool</a></li>
107
+ </ul>
108
+ </li>
109
+
110
+ <li>
111
+ <a href="#tips">Tips</a>
112
+
113
+ <ul>
114
+ <li><a href="#function-names">Specify Function Names of escape() and to_str()</a></li>
115
+
116
+ <li><a href="#tips-template-inheritance">Template Inheritance</a></li>
117
+ </ul>
118
+ </li>
119
+
120
+ <li>
121
+ <a href="#command"><code>rbtenjin</code> Command</a>
122
+
123
+ <ul>
124
+ <li><a href="#command-syntax-check">Syntax Check</a></li>
125
+
126
+ <li><a href="#command-convert-script">Convert Template into Ruby Script</a></li>
127
+
128
+ <li><a href="#command-retrieve">Retrieve Embedded Code</a></li>
129
+
130
+ <li><a href="#command-execute-template">Execute Template File</a></li>
131
+
132
+ <li><a href="#command-context-data">Context Data</a></li>
133
+ </ul>
134
+ </li>
135
+
136
+ <li><a href="#shooting">Trouble shooting</a></li>
137
+
138
+ <li><a href="#customize">Customization Examples</a></li>
139
+ </ul>
140
+
141
+ </div><a name="overview" id="overview"></a>
142
+
143
+ <h2 class="section1">Overview</h2>
144
+
145
+ <p>Tenjin is a very fast and full-featured template engine implemented in pure Ruby.</p><a name="features" id="features"></a>
146
+
147
+ <h3 class="section2">Features</h3>
148
+
149
+ <ul type="disc">
150
+ <li>
151
+ <a href="#benchmark">Very fast</a>
152
+
153
+ <ul type="circle">
154
+ <li>Same as fast as Erubis</li>
155
+
156
+ <li><a href="#safe-template">Safe Template</a></li>
157
+ </ul>
158
+ </li>
159
+
160
+ <li>Full featured
161
+
162
+ <ul type="circle">
163
+ <li><a href="#layout-template">Layout template</a></li>
164
+
165
+ <li><a href="#partial-template">Partial template</a></li>
166
+
167
+ <li><a href="#fragment-cache">Fragment cache</a></li>
168
+
169
+ <li><a href="#capturing">Capturing</a></li>
170
+
171
+ <li><a href="#preprocessing">Preprocessing</a></li>
172
+
173
+ <li><a href="#m17n">M17N Support</a></li>
174
+ </ul>
175
+ </li>
176
+
177
+ <li>Easy to learn
178
+
179
+ <ul type="circle">
180
+ <li>Because you can embed any ruby statements or expression in your template files</li>
181
+
182
+ <li>You don't have to study template-specific language</li>
183
+ </ul>
184
+ </li>
185
+
186
+ <li>Compact
187
+
188
+ <ul type="circle">
189
+ <li>Less than 2000 lines of code</li>
190
+ </ul>
191
+ </li>
192
+ </ul><br>
193
+ <a name="install" id="install"></a>
194
+
195
+ <h3 class="section2">Install</h3>
196
+ <pre class="terminal">
197
+ $ gem install tenjin
143
198
  </pre>
144
- <br>
145
-
146
-
147
- <a name="features"></a>
148
- <h3 class="section2">Features</h3>
149
- <p>rbTenjin has the following features:
150
- </p>
151
- <ul type="disc">
152
- <li>rbTenjin runs very fast. It works about three times as fast as ERB.
153
- </li>
154
- <li>rbTenjin doesn't break HTML design because it uses XML Processing
155
- Instructions (PI) as embedded notation for Ruby statements.
156
- </li>
157
- <li>rbTenjin is secure because it supports escaping expression value by default.
158
- </li>
159
- <li>rbTenjin is small and lightweight. It is very easy to include rbTenjin
160
- into your application.
161
- </li>
162
- <li>rbTenjin supports auto caching of converted Ruby code.
163
- </li>
164
- <li>rbTenjin supports partial template and layout template.
165
- These are very useful especially for web application.
166
- </li>
167
- <li>rbTenjin supports partial capturing of template.
168
- </li>
169
- <li>rbTenjin can load YAML file as context data. Using rbTenjin, it is able to
170
- separate template file and data file.
171
- </li>
172
- </ul>
173
- <br>
174
-
175
-
176
- <a name="benchmark"></a>
177
- <h3 class="section2">Benchmark</h3>
178
- <p>Benchmark script is contained in rbTenjin archive.
179
- The following is an example of benchmark.
180
- </p>
181
- <div class="terminal_caption">
182
- MacOS X 10.4 Tiger, Intel CoreDuo 1.83GHz, Memory 2GB</div>
183
- <pre class="terminal">$ cd rbtenjin-X.X.X/benchmark
199
+
200
+ <p>or</p>
201
+ <pre class="terminal">
202
+ $ tar xzf rbtenjin-X.X.X.tar.gz
203
+ $ cd rbtenjin-X.X.X/
204
+ $ mkdir -p $HOME/bin
205
+ $ mkdir -p $HOME/lib/ruby
206
+ $ cp bin/rbtenjin $HOME/bin
207
+ $ cp lib/tenjin.rb $HOME/lib/ruby
208
+ $ export PATH=$HOME/bin:$PATH
209
+ $ export RUBYLIB=$HOME/lib/ruby
210
+ </pre><br>
211
+ <a name="benchmark" id="benchmark"></a>
212
+
213
+ <h3 class="section2">Benchmark</h3>
214
+
215
+ <div class="terminal_caption">
216
+ MacOS X 10.6 Snow Leopard, Intel CoreDuo2 2GHz, Memory 2GB
217
+ </div>
218
+ <pre class="terminal">
184
219
  $ ruby -v
185
- ruby 1.8.6 (2007-03-13 patchlevel 0) [i686-darwin8.9.1]
186
- $ ruby bench.rb -n 10000
220
+ ruby 1.8.7 (2011-02-18 patchlevel 334) [i686-darwin10.7.0]
221
+ $ cd benchmark
222
+ $ ruby bench.rb -n 1000
187
223
  user system total real
188
- eruby 12.02000 0.27000 12.29000 ( 12.34855)
189
- eruby-cache 11.09000 0.43000 11.53000 ( 11.58262)
190
- erb 36.32000 0.41000 36.73000 ( 36.89404)
191
- erb-cache 11.13000 0.45000 11.57000 ( 11.62259)
192
- erb-reuse 10.78000 0.03000 10.81000 ( 10.85908)
193
- erb-defmethod 5.82000 0.02000 5.84000 ( 5.86168)
194
- erubis 10.31000 0.32000 10.64000 ( 10.68644)
195
- erubis-cache 7.02000 0.43000 7.45000 ( 7.50923)
196
- erubis-reuse 4.43000 0.01000 4.44000 ( 4.45338)
197
- tenjin 6.87000 0.47000 7.34000 ( 7.37263)
198
- tenjin-nocache 8.73000 0.36000 9.10000 ( 9.14337)
199
- tenjin-reuse 4.45000 0.07000 4.52000 ( 4.53931)
200
- </pre>
201
- <p>This shows that rbTenjin is much faster than any other eRuby implementations.
202
- </p>
203
- <br>
204
-
205
-
206
- <br>
207
-
208
-
209
- <a name="installation"></a>
210
- <h2 class="section1">Installation</h2>
211
- <p>rbTenjin requires Ruby 1.8 or later.
212
- </p>
213
- <ul type="disc">
214
- <li>If you have installed RubyGems, just type '<code>gem install rbtenjin</code>'.
215
- </li>
216
- <li>Or if you have administrator privilegde, install with setup.rb.
217
- <pre class="terminal">$ tar xjf rbtenjin_X.X.X.tar.bz
218
- $ cd rbtenjin_X.X.X/
219
- $ ruby setup.rb --help | more
220
- $ ruby setup.rb config
221
- $ ruby setup.rb setup
222
- $ sudo ruby setup.rb install
223
- </pre>
224
- </li>
225
- <li>Or copy 'lib/tenjin.rb' and 'bin/rbtenjin' to proper directories.
226
- <pre class="terminal">$ tar xjf rbtenjin_X.X.X.tar.bz
227
- $ cd rbtenjin_X.X.X/
228
- $ cp lib/tenjin.rb $HOME/lib/ruby/
229
- $ cp bin/rbtenjin $HOME/bin/
230
- </pre>
231
- </li>
232
- </ul>
233
- <br>
234
-
235
-
236
- <a name="desguide"></a>
237
- <h2 class="section1">Designer's Guide</h2>
238
- <p>This section shows how to use rbTenjin for designer.
239
- </p>
240
- <p>If you want to know how to use rbTenjin in your program, see <a href="#devguide">Developer's Guide</a> section.
241
- </p>
242
- <a name="des-notation"></a>
243
- <h3 class="section2">Notation</h3>
244
- <p>The following is the notation of rbTenjin.
245
- </p>
246
- <ul type="disc">
247
- <li>'<code>&lt;?rb ... ?&gt;</code>' represents embedded Ruby statement.
248
- </li>
249
- <li>'<code>#{...}</code>' represents embedded Ruby expression.
250
- </li>
251
- <li>'<code>${...}</code>' represents embedded Ruby expression which is to be escaped (for example, '<code>&amp; &lt; &gt; "</code>' is escaped to '<code>&amp;amp; &amp;lt; &amp;gt; &amp;quot;</code>').
252
- </li>
253
- </ul>
254
- <a name="example1.rbhtml"></a>
255
- <div class="program_caption">
256
- File 'example1.rbhtml':</div>
257
- <pre class="program">&lt;table&gt;
258
- &lt;tbody&gt;
259
- <strong>&lt;?rb i = 0 ?&gt;</strong>
260
- <strong>&lt;?rb for item in ['&lt;foo&gt;', 'bar&amp;bar', '"baz"'] ?&gt;</strong>
261
- <strong>&lt;?rb i += 1 ?&gt;</strong>
262
- &lt;tr&gt;
263
- &lt;td&gt;<strong>#{item}</strong>&lt;/td&gt;
264
- &lt;td&gt;<strong>${item}</strong>&lt;/td&gt;
265
- &lt;/tr&gt;
266
- <strong>&lt;?rb end ?&gt;</strong>
267
- &lt;tbody&gt;
268
- &lt;/table&gt;
269
- </pre>
270
- <p>The following is the result of executing 'example1.rbhtml'.
271
- </p>
272
- <a name="example1.result"></a>
273
- <div class="terminal_caption">
274
- Result:</div>
275
- <pre class="terminal">$ rbtenjin example1.rbhtml
224
+ erb 1.510000 0.030000 1.540000 ( 1.555130)
225
+ erb-cache 0.570000 0.030000 0.600000 ( 0.606775)
226
+ erb-reuse 0.550000 0.000000 0.550000 ( 0.548511)
227
+ erb-defmethod 0.380000 0.000000 0.380000 ( 0.398116)
228
+ erubis 0.950000 0.030000 0.980000 ( 0.979889)
229
+ erubis-cache 0.580000 0.030000 0.610000 ( 0.614893)
230
+ erubis-reuse 0.390000 0.000000 0.390000 ( 0.432674)
231
+ tenjin 0.560000 0.040000 0.600000 ( 0.606353)
232
+ tenjin-nocache 0.850000 0.040000 0.890000 ( 0.890926)
233
+ tenjin-reuse 0.370000 0.010000 0.380000 ( 0.393109)
234
+ </pre><br>
235
+ <br>
236
+ <a name="basic-examples" id="basic-examples"></a>
237
+
238
+ <h2 class="section1">Basic Examples</h2>
239
+
240
+ <p>This section describes basics of Tenjin.</p><a name="template-syntax" id="template-syntax"></a>
241
+
242
+ <h3 class="section2">Template Syntax</h3>
243
+
244
+ <p>Notation:</p>
245
+
246
+ <dl class="dl1">
247
+ <dt class="dt1"><code>&lt;?rb ... ?&gt;</code></dt>
248
+
249
+ <dd class="dd1">Ruby statements</dd>
250
+
251
+ <dt class="dt1"><code>${...}</code></dt>
252
+
253
+ <dd class="dd1">Ruby expression (with HTML escape)</dd>
254
+
255
+ <dt class="dt1"><code>#{...}</code></dt>
256
+
257
+ <dd class="dd1">Ruby expression (without HTML escape)</dd>
258
+ </dl><a name="test_010/views/page.rbhtml"></a>
259
+
260
+ <div class="program_caption">
261
+ views/page.rbhtml: html template
262
+ </div>
263
+ <pre class="program">
264
+ &lt;h2&gt;<strong>${@title}</strong>&lt;/h2&gt;
276
265
  &lt;table&gt;
277
- &lt;tbody&gt;
278
- &lt;tr&gt;
279
- &lt;td&gt;<strong>&lt;foo&gt;</strong>&lt;/td&gt;
280
- &lt;td&gt;<strong>&amp;lt;foo&amp;gt;</strong>&lt;/td&gt;
281
- &lt;/tr&gt;
282
- &lt;tr&gt;
283
- &lt;td&gt;<strong>bar&amp;bar</strong>&lt;/td&gt;
284
- &lt;td&gt;<strong>bar&amp;amp;bar</strong>&lt;/td&gt;
285
- &lt;/tr&gt;
286
- &lt;tr&gt;
287
- &lt;td&gt;<strong>"baz"</strong>&lt;/td&gt;
288
- &lt;td&gt;<strong>&amp;quot;baz&amp;quot;</strong>&lt;/td&gt;
289
- &lt;/tr&gt;
290
- &lt;tbody&gt;
266
+ <strong>&lt;?rb i = 0 ?&gt;</strong>
267
+ <strong>&lt;?rb for item in @items ?&gt;</strong>
268
+ <strong>&lt;?rb i += 1 ?&gt;</strong>
269
+ <strong>&lt;?rb klass = i % 2 == 1 ? 'odd' : 'even' ?&gt;</strong>
270
+ &lt;tr class="<strong>#{klass}</strong>"&gt;
271
+ &lt;td&gt;<strong>${item}</strong>&lt;/td&gt;
272
+ &lt;/tr&gt;
273
+ <strong>&lt;?rb end ?&gt;</strong>
291
274
  &lt;/table&gt;
292
275
  </pre>
293
- <br>
294
-
295
-
296
- <a name="des-convert"></a>
297
- <h3 class="section2">Convert into Ruby Code</h3>
298
- <p>Command-line option '-s' converts embedded files into Ruby code.
299
- </p>
300
- <a name="example1_source.result"></a>
301
- <div class="terminal_caption">
302
- Result:</div>
303
- <pre class="terminal">$ rbtenjin <strong>-s</strong> example1.rbhtml
304
- _buf = ''; _buf &lt;&lt; %Q`&lt;table&gt;
305
- &lt;tbody&gt;\n`
306
- <strong>i = 0</strong>
307
- <strong>for item in ['&lt;foo&gt;', 'bar&amp;bar', '"baz"']</strong>
308
- <strong>i += 1</strong>
309
- _buf &lt;&lt; %Q` &lt;tr&gt;
310
- &lt;td&gt;<strong>#{item}</strong>&lt;/td&gt;
311
- &lt;td&gt;<strong>#{escape((item).to_s)}</strong>&lt;/td&gt;
312
- &lt;/tr&gt;\n`
313
- <strong>end</strong>
314
- _buf &lt;&lt; %Q` &lt;tbody&gt;
315
- &lt;/table&gt;\n`
316
- _buf.to_s
276
+
277
+ <div class="tips"><span class="caption">TIPS:</span>
278
+
279
+ <p>You can check template syntax by 'rbtenjin -z'.</p><a name="test_011/result.output"></a>
280
+
281
+ <div class="terminal_caption">
282
+ Syntax check of template files
283
+ </div>
284
+ <pre class="terminal">
285
+ $ rbtenjin <strong>-z</strong> views/*.rbhtml
286
+ views/page.rbhtml: Syntax OK
317
287
  </pre>
318
- <ul type="disc">
319
- <li>Variable <code>@_buf</code> is a String.
320
- </li>
321
- <li>Function <code>escape()</code> (= <code>Tenjin::Context.escape()</code>) escapes <code>'&amp; &lt; &gt; "'</code> into <code>'&amp;amp; &amp;lt; &amp;gt; &amp;quot;'</code>.
322
- Command-line option <code>--escapefunc=func</code> makes rbtenjin to use <code>func()</code> instead of <code>escape()</code>.
323
- </li>
324
- <li>Newline character ("\n" or "\r\n") is automatically detected by rbTenjin.
325
- </li>
326
- </ul>
327
- <p>'<code>_buf = '';</code>' is called as preamble and '<code>_buf.to_s</code>' is called as postamble.
328
- Command-line option '<code>-b</code>' removes preamble and postamble.
329
- </p>
330
- <a name="example2.rbhtml"></a>
331
- <div class="program_caption">
332
- File 'example2.rbhtml'</div>
333
- <pre class="program">&lt;?rb for i in [1, 2, 3] ?&gt;
334
- &lt;p&gt;#{item}&lt;/p&gt;
335
- &lt;?rb end ?&gt;
288
+
289
+ </div><br>
290
+ <a name="render-template" id="render-template"></a>
291
+
292
+ <h3 class="section2">Render Template</h3>
293
+
294
+ <p>This is an example code to render template file.</p><a name="test_010/main.rb"></a>
295
+
296
+ <div class="program_caption">
297
+ main.rb: main program
298
+ </div>
299
+ <pre class="program">
300
+ <strong>require 'tenjin'</strong>
301
+
302
+ ## context data
303
+ context = {
304
+ :title =&gt; 'Tenjin Example',
305
+ :items =&gt; ['&lt;AAA&gt;', 'B&amp;B', '"CCC"'],
306
+ }
307
+
308
+ ## create engine object
309
+ <strong>engine = Tenjin::Engine.new(:path=&gt;['views'])</strong>
310
+
311
+ ## render template with context data
312
+ html = <strong>engine.render('page.rbhtml', context)</strong>
313
+ print html
314
+ </pre><a name="test_010/result.output"></a>
315
+
316
+ <div class="terminal_caption">
317
+ result
318
+ </div>
319
+ <pre class="terminal">
320
+ $ ruby main.rb
321
+ &lt;h2&gt;Tenjin Example&lt;/h2&gt;
322
+ &lt;table&gt;
323
+ &lt;tr class="odd"&gt;
324
+ &lt;td&gt;&amp;lt;AAA&amp;gt;&lt;/td&gt;
325
+ &lt;/tr&gt;
326
+ &lt;tr class="even"&gt;
327
+ &lt;td&gt;B&amp;amp;B&lt;/td&gt;
328
+ &lt;/tr&gt;
329
+ &lt;tr class="odd"&gt;
330
+ &lt;td&gt;&amp;quot;CCC&amp;quot;&lt;/td&gt;
331
+ &lt;/tr&gt;
332
+ &lt;/table&gt;
336
333
  </pre>
337
- <a name="example2_sb.result2"></a>
338
- <div class="terminal_caption">
339
- Result:</div>
340
- <pre class="terminal">$ rbtenjin -s example2.rbhtml
341
- <strong>_buf = '';</strong> for i in [1, 2, 3]
342
- _buf &lt;&lt; %Q`&lt;p&gt;#{item}&lt;/p&gt;\n`
343
- end
344
- <strong>_buf.to_s</strong>
345
- $ rbtenjin -s<strong>b</strong> example2.rbhtml
346
- for i in [1, 2, 3]
347
- _buf &lt;&lt; %Q`&lt;p&gt;#{item}&lt;/p&gt;\n`
334
+
335
+ <div class="tips"><span class="caption">TIPS:</span>
336
+
337
+ <p>Hash context data is converted into Tenjin::Context object. It is possible to use your own class as context data object instead of Tenjin::Context.</p>
338
+ <pre class="program">
339
+ require 'tenjin'
340
+ class FooController &lt; Controller
341
+ include Tenjin::ContextHelper
342
+ include Tenjin::HtmlHelper
343
+ #include Tenjin::SafeHelper # optional
344
+ #include Tenjin::HtmlTagHelper # optional
345
+ @@engine = Tenjin::Engine.new(:path=&gt;['views'])
346
+
347
+ def index
348
+ @items = ['AAA', 'BBB', 'CCC']
349
+ html = @@engine.render('foo/index.rbhtml', <strong>self</strong>)
350
+ return html
351
+ end
348
352
  end
349
353
  </pre>
350
- <p>Command-line option '-S' also show converted Ruby code but it doesn't print text part.
351
- This is useful to check Ruby code for debugging.
352
- </p>
353
- <a name="example1_S.result"></a>
354
- <div class="terminal_caption">
355
- Result:</div>
356
- <pre class="terminal">$ rbtenjin <strong>-S</strong> example1.rbhtml
357
- _buf = '';
358
354
 
359
- i = 0
360
- for item in ['&lt;foo&gt;', 'bar&amp;bar', '"baz"']
361
- i += 1
355
+ </div><br>
356
+ <a name="source-code" id="source-code"></a>
362
357
 
358
+ <h3 class="section2">Show Converted Source Code</h3>
363
359
 
364
- escape((item).to_s);
360
+ <p>rbTenjin converts template files into Ruby script and executes it. Compiled Ruby script is saved into cache file automatically.</p>
365
361
 
366
- end
362
+ <div class="terminal_caption">
363
+ Show cached file
364
+ </div>
365
+ <pre class="terminal">
366
+ $ ls views/page.rbhtml*
367
+ views/page.rbhtml views/page.rbhtml.cache
368
+ $ file views/page.rbhtml.cache
369
+ views/page.rbhtml.cache: text
370
+ </pre>
367
371
 
372
+ <p>You can get converted script by '<code>rbtenjin -s</code>'.</p><a name="test_020/result.output"></a>
368
373
 
374
+ <div class="terminal_caption">
375
+ Show Ruby code
376
+ </div>
377
+ <pre class="terminal">
378
+ $ rbtenjin <strong>-s</strong> views/page.rbhtml
379
+ _buf = ''; _buf &lt;&lt; %Q`&lt;h2&gt;#{escape((@title).to_s)}&lt;/h2&gt;
380
+ &lt;table&gt;\n`
381
+ i = 0
382
+ for item in @items
383
+ i += 1
384
+ klass = i % 2 == 1 ? 'odd' : 'even'
385
+ _buf &lt;&lt; %Q` &lt;tr class="#{klass}"&gt;
386
+ &lt;td&gt;#{escape((item).to_s)}&lt;/td&gt;
387
+ &lt;/tr&gt;\n`
388
+ end
389
+ _buf &lt;&lt; %Q`&lt;/table&gt;\n`
369
390
  _buf.to_s
370
391
  </pre>
371
- <p>In addition, the following command-line options are available.
372
- </p>
373
- <dl class="dl3" compact>
374
- <dt class="dt3"><b>
375
- -N </b></dt>
376
- <dd class="dd3">
377
- Add line number.
378
- </dd>
379
- <dt class="dt3"><b>
380
- -X </b></dt>
381
- <dd class="dd3">
382
- Delete expressions.
383
- </dd>
384
- <dt class="dt3"><b>
385
- -C </b></dt>
386
- <dd class="dd3">
387
- Remove empty lines (compact-mode).
388
- </dd>
389
- <dt class="dt3"><b>
390
- -U </b></dt>
391
- <dd class="dd3">
392
- Compress empty lines to a line (uniq-mode).
393
- </dd>
394
- </dl>
395
- <a name="example1_SXNC.result"></a>
396
- <div class="terminal_caption">
397
- Result:</div>
398
- <pre class="terminal">$ rbtenjin <strong>-SUNX</strong> example1.rbhtml
399
- 1: _buf = '';
400
-
401
- 3: i = 0
402
- 4: for item in ['&lt;foo&gt;', 'bar&amp;bar', '"baz"']
403
- 5: i += 1
404
-
405
- 10: end
406
-
407
- 13: _buf.to_s
408
- </pre>
409
- <br>
410
-
411
-
412
- <a name="des-syntaxchk"></a>
413
- <h3 class="section2">Syntax Checking</h3>
414
- <p>Command-line option '<code>-z</code>' checks syntax error in embedded Ruby code
415
- and command-line option '<code>-w</code>' sets warning level to 2.
416
- It is recommended to use '-w' when you specify '-z'.
417
- </p>
418
- <a name="example3.rbhtml"></a>
419
- <div class="program_caption">
420
- File example3.rbhtml:</div>
421
- <pre class="program">&lt;ul&gt;
422
- &lt;?rb for item in items ?&gt;
423
- &lt;li&gt;${item}&lt;/li&gt;
424
- &lt;?rb <strong>ende</strong> ?&gt;
425
- &lt;/ul&gt;
392
+
393
+ <p>If you specify '<code>-sb</code>' instead of '<code>-s</code>', neither preamble (= '<code>@_buf = _buf = "";</code>') nor postamble (= '<code>_buf.to_s</code>') are printed. See <a href="#command-retrieve">Retrieve Embedded Code</a> section for more information.</p>
394
+
395
+ <p>Or:</p><a name="test_021/main.rb"></a>
396
+
397
+ <div class="program_caption">
398
+ How to convert template file into Ruby script
399
+ </div>
400
+ <pre class="program">
401
+ require 'tenjin'
402
+ template = Tenjin::Template.new('views/page.rbhtml')
403
+ puts template.script
404
+
405
+ ### or:
406
+ #template = Tenjin::Template.new
407
+ #filename = 'views/page.rbhtml'
408
+ #print(template.convert(File.read(filename), filename))
409
+
410
+ ### or:
411
+ #engine = Tenjin::Engine.new(:path=&gt;['views'])
412
+ #print(engine.get_template('page.rbhtml').script)
413
+ </pre><br>
414
+ <a name="layout-template" id="layout-template"></a>
415
+
416
+ <h3 class="section2">Layout Template</h3>
417
+
418
+ <p>Layout template will help you to use common HTML design for all pages.</p><a name="test_030/views/_layout.rbhtml"></a>
419
+
420
+ <div class="program_caption">
421
+ views/_layout.rbhtml
422
+ </div>
423
+ <pre class="program">
424
+ &lt;!DOCTYPE&gt;
425
+ &lt;html&gt;
426
+ &lt;head&gt;
427
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
428
+ &lt;title&gt;${@title}&lt;/title&gt;
429
+ &lt;/head&gt;
430
+ &lt;body&gt;
431
+ <strong>#{@_content}</strong>
432
+ &lt;/body&gt;
433
+ &lt;/html&gt;
434
+ </pre><a name="test_030/main.rb"></a>
435
+
436
+ <div class="program_caption">
437
+ main.rb
438
+ </div>
439
+ <pre class="program">
440
+ require 'tenjin'
441
+
442
+ ## context data
443
+ context = {
444
+ :title =&gt; 'Tenjin Example',
445
+ :items =&gt; ['&lt;AAA&gt;', 'B&amp;B', '"CCC"'],
446
+ }
447
+
448
+ ## cleate engine object
449
+ engine = Tenjin::Engine.new(:path=&gt;['views']<strong>, :layout=&gt;'_layout.rbhtml'</strong>)
450
+
451
+ ## render template with context data
452
+ html = engine.render('page.rbhtml', context)
453
+ print html
454
+ </pre><a name="test_030/result.output"></a>
455
+
456
+ <div class="terminal_caption">
457
+ Result
458
+ </div>
459
+ <pre class="terminal">
460
+ $ ruby main.rb
461
+ &lt;!DOCTYPE&gt;
462
+ &lt;html&gt;
463
+ &lt;head&gt;
464
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
465
+ &lt;title&gt;Tenjin Example&lt;/title&gt;
466
+ &lt;/head&gt;
467
+ &lt;body&gt;
468
+ &lt;h2&gt;Tenjin Example&lt;/h2&gt;
469
+ &lt;table&gt;
470
+ &lt;tr class="odd"&gt;
471
+ &lt;td&gt;&amp;lt;AAA&amp;gt;&lt;/td&gt;
472
+ &lt;/tr&gt;
473
+ &lt;tr class="even"&gt;
474
+ &lt;td&gt;B&amp;amp;B&lt;/td&gt;
475
+ &lt;/tr&gt;
476
+ &lt;tr class="odd"&gt;
477
+ &lt;td&gt;&amp;quot;CCC&amp;quot;&lt;/td&gt;
478
+ &lt;/tr&gt;
479
+ &lt;/table&gt;
480
+
481
+ &lt;/body&gt;
482
+ &lt;/html&gt;
426
483
  </pre>
427
- <a name="example3_syntaxcheck.result"></a>
428
- <div class="terminal_caption">
429
- Result:</div>
430
- <pre class="terminal">$ rbtenjin <strong>-wz</strong> example3.rbhtml
431
- example3.rbhtml:5: syntax error, unexpected $end, expecting kEND
484
+
485
+ <p>You can specify other layout template file with <code>render()</code> method.</p>
486
+ <pre class="program">
487
+ ## use other layout template file
488
+ engine.render('page.rbhtml', context, <strong>'_other_layout.jshtml'</strong>)
489
+
490
+ ## don't use layout template file
491
+ engine.render('page.pyhtml', context, <strong>false</strong>)
432
492
  </pre>
433
- <p>Command-line option '-wz' is more convenient than '<code>rbtenjin -s file | ruby -wc</code>'
434
- because the former can take several filenames.
435
- </p>
436
- <p>Command-line option '-q' (quiet-mode) prints nothing if it has no errors.
437
- </p>
438
- <br>
439
-
440
-
441
- <a name="des-contextdata"></a>
442
- <h3 class="section2">Context Data File</h3>
443
- <p>rbTenjin allows you to specify context data by YAML file or Ruby script.
444
- </p>
445
- <a name="example4.rbhtml"></a>
446
- <div class="program_caption">
447
- File 'example4.rbhtml':</div>
448
- <pre class="program">&lt;p&gt;
449
- ${@text}
450
- #{@num}
451
- #{@flag}
452
- &lt;/p&gt;
453
493
 
494
+ <p>Tenjin supports nested layout template. See <a href="#nested-layout-template">Nested Layout Template</a> section for details.</p><br>
495
+ <a name="context-variables" id="context-variables"></a>
496
+
497
+ <h3 class="section2">Context Variables</h3>
498
+
499
+ <p>In Tenjin, Instance variables are shared between template files. If you set instance variables in a template, it is available in layout template.</p><a name="test_040/views/_layout.rbhtml"></a>
500
+
501
+ <div class="program_caption">
502
+ views/_layout.rbhtml
503
+ </div>
504
+ <pre class="program">
505
+ &lt;!DOCTYPE&gt;
506
+ &lt;html&gt;
507
+ &lt;head&gt;
508
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
509
+ &lt;title&gt;<strong>${@page_title}</strong>&lt;/title&gt;
510
+ &lt;/head&gt;
511
+ &lt;body&gt;
512
+ #{@_content}
513
+ &lt;/body&gt;
514
+ &lt;/html&gt;
515
+ </pre><a name="test_040/views/page.rbhtml"></a>
516
+
517
+ <div class="program_caption">
518
+ views/page.rbhtml: pass page title date from template to layout template
519
+ </div>
520
+ <pre class="program">
521
+ <strong>&lt;?rb @page_title = 'Tenjin: Layout Template Example' ?&gt;</strong>
522
+ &lt;h2&gt;${@title}&lt;/h2&gt;
523
+ &lt;table&gt;
524
+ &lt;?rb i = 0 ?&gt;
454
525
  &lt;?rb for item in @items ?&gt;
455
- &lt;p&gt;${item}&lt;/p&gt;
526
+ &lt;?rb i += 1 ?&gt;
527
+ &lt;?rb klass = i % 2 == 1 ? 'odd' : 'even' ?&gt;
528
+ &lt;tr class="#{klass}"&gt;
529
+ &lt;td&gt;${item}&lt;/td&gt;
530
+ &lt;/tr&gt;
456
531
  &lt;?rb end ?&gt;
532
+ &lt;/table&gt;
533
+ </pre><a name="test_040/result.output"></a>
534
+
535
+ <div class="terminal_caption">
536
+ Result
537
+ </div>
538
+ <pre class="terminal">
539
+ $ ruby main.rb
540
+ &lt;!DOCTYPE&gt;
541
+ &lt;html&gt;
542
+ &lt;head&gt;
543
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
544
+ &lt;title&gt;<strong>Tenjin: Layout Template Example</strong>&lt;/title&gt;
545
+ &lt;/head&gt;
546
+ &lt;body&gt;
547
+ &lt;h2&gt;Tenjin Example&lt;/h2&gt;
548
+ &lt;table&gt;
549
+ &lt;tr class="odd"&gt;
550
+ &lt;td&gt;&amp;lt;AAA&amp;gt;&lt;/td&gt;
551
+ &lt;/tr&gt;
552
+ &lt;tr class="even"&gt;
553
+ &lt;td&gt;B&amp;amp;B&lt;/td&gt;
554
+ &lt;/tr&gt;
555
+ &lt;tr class="odd"&gt;
556
+ &lt;td&gt;&amp;quot;CCC&amp;quot;&lt;/td&gt;
557
+ &lt;/tr&gt;
558
+ &lt;/table&gt;
457
559
 
458
- &lt;?rb for key, value in @hash ?&gt;
459
- &lt;p&gt;#{key} = ${value}&lt;/p&gt;
560
+ &lt;/body&gt;
561
+ &lt;/html&gt;
562
+ </pre><br>
563
+ <a name="template-arguments" id="template-arguments"></a>
564
+
565
+ <h3 class="section2">Template Arguments</h3>
566
+
567
+ <p>For readability, it is recommended to declare context variables in your template files.</p><a name="test_050/views/page.rbhtml"></a>
568
+
569
+ <div class="program_caption">
570
+ views/page.rbhtml
571
+ </div>
572
+ <pre class="program">
573
+ <strong>&lt;?rb #@ARGS title, items ?&gt;</strong>
574
+ &lt;?rb @page_title = 'Tenjin: Layout Template Example' ?&gt;
575
+ &lt;h2&gt;<strong>${title}</strong>&lt;/h2&gt;
576
+ &lt;table&gt;
577
+ &lt;?rb i = 0 ?&gt;
578
+ &lt;?rb for item in <strong>items</strong> ?&gt;
579
+ &lt;?rb i += 1 ?&gt;
580
+ &lt;?rb klass = i % 2 == 1 ? 'odd' : 'even' ?&gt;
581
+ &lt;tr class="#{klass}"&gt;
582
+ &lt;td&gt;${item}&lt;/td&gt;
583
+ &lt;/tr&gt;
460
584
  &lt;?rb end ?&gt;
585
+ &lt;/table&gt;
586
+ </pre><a name="test_050/result.output"></a>
587
+
588
+ <div class="terminal_caption">
589
+ Converted Ruby script
590
+ </div>
591
+ <pre class="terminal">
592
+ $ rbtenjin -sb views/page.rbhtml
593
+ <strong> title = @title; items = @items;</strong>
594
+ @page_title = 'Tenjin: Layout Template Example'
595
+ _buf &lt;&lt; %Q`&lt;h2&gt;#{escape((<strong>title</strong>).to_s)}&lt;/h2&gt;
596
+ &lt;table&gt;\n`
597
+ i = 0
598
+ for item in <strong>items</strong>
599
+ i += 1
600
+ klass = i % 2 == 1 ? 'odd' : 'even'
601
+ _buf &lt;&lt; %Q` &lt;tr class="#{klass}"&gt;
602
+ &lt;td&gt;#{escape((item).to_s)}&lt;/td&gt;
603
+ &lt;/tr&gt;\n`
604
+ end
605
+ _buf &lt;&lt; %Q`&lt;/table&gt;\n`
606
+ </pre><a name="test_051/views/_layout.rbhtml"></a>
607
+
608
+ <div class="program_caption">
609
+ views/_layout.rbhtml
610
+ </div>
611
+ <pre class="program">
612
+ <strong>&lt;?rb #@ARGS _content, page_title ?&gt;</strong>
613
+ &lt;!DOCTYPE&gt;
614
+ &lt;html&gt;
615
+ &lt;head&gt;
616
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
617
+ &lt;title&gt;${@page_title}&lt;/title&gt;
618
+ &lt;/head&gt;
619
+ &lt;body&gt;
620
+ #{@_content}
621
+ &lt;/body&gt;
622
+ &lt;/html&gt;
623
+ </pre><a name="test_051/result.output"></a>
624
+
625
+ <div class="terminal_caption">
626
+ Converted Ruby script
627
+ </div>
628
+ <pre class="terminal">
629
+ $ rbtenjin -sb views/_layout.rbhtml
630
+ <strong> _content = @_content; page_title = @page_title;</strong>
631
+ _buf &lt;&lt; %Q`&lt;!DOCTYPE&gt;
632
+ &lt;html&gt;
633
+ &lt;head&gt;
634
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
635
+ &lt;title&gt;#{escape((@page_title).to_s)}&lt;/title&gt;
636
+ &lt;/head&gt;
637
+ &lt;body&gt;
638
+ #{@_content}
639
+ &lt;/body&gt;
640
+ &lt;/html&gt;\n`
641
+ </pre><br>
642
+ <a name="partial-template" id="partial-template"></a>
643
+
644
+ <h3 class="section2">Include Partial Template</h3>
645
+
646
+ <p>You can include other template files by <code>import()</code> helper method.</p>
647
+
648
+ <dl class="dl1">
649
+ <dt class="dt1">import(<em>template-name</em>)</dt>
650
+
651
+ <dd class="dd1">Import other template. <em>template-name</em> can be file name or template short name.</dd>
652
+ </dl>
653
+
654
+ <p>In the following example, layout template includes header and footer templates into it.</p><a name="test_060/views/_layout.rbhtml"></a>
655
+
656
+ <div class="program_caption">
657
+ views/_layout.rbhtml
658
+ </div>
659
+ <pre class="program">
660
+ &lt;?rb #@ARGS _content, page_title ?&gt;
661
+ &lt;!DOCTYPE&gt;
662
+ &lt;html&gt;
663
+ &lt;head&gt;
664
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
665
+ &lt;title&gt;${@page_title}&lt;/title&gt;
666
+ &lt;/head&gt;
667
+ &lt;body&gt;
668
+ <strong>&lt;?rb import('_header.rbhtml') ?&gt;</strong>
669
+ #{@_content}
670
+ <strong>&lt;?rb import('_footer.rbhtml') ?&gt;</strong>
671
+ &lt;/body&gt;
672
+ &lt;/html&gt;
673
+ </pre><a name="test_060/views/_header.rbhtml"></a>
674
+
675
+ <div class="program_caption">
676
+ views/_header.rbhtml
677
+ </div>
678
+ <pre class="program">
679
+ <strong>&lt;div class="header"&gt;</strong>
680
+ <strong>&lt;h1&gt;${@page_title}&lt;/h1&gt;</strong>
681
+ <strong>&lt;/div&gt;</strong>
682
+ </pre><a name="test_060/views/_footer.rbhtml"></a>
683
+
684
+ <div class="program_caption">
685
+ views/_footer.rbhtml
686
+ </div>
687
+ <pre class="program">
688
+ <strong>&lt;address&gt;</strong>
689
+ <strong>copyright(c) 2010 kuwata-lab.com all rights reserved</strong>
690
+ <strong>&lt;/address&gt;</strong>
461
691
  </pre>
462
- <a name="datafile.yaml"></a>
463
- <div class="program_caption">
464
- File 'datafile.yaml':</div>
465
- <pre class="program">text: foo
466
- num: 3.14
467
- flag: yes
468
- items:
469
- - foo
470
- - bar
471
- - baz
472
- hash:
473
- x: 1
474
- y: 2
692
+
693
+ <p>Output result shows that header and footer templates are included as you expect.</p><a name="test_060/result.output"></a>
694
+
695
+ <div class="terminal_caption">
696
+ Result
697
+ </div>
698
+ <pre class="terminal">
699
+ $ ruby main.rb
700
+ &lt;!DOCTYPE&gt;
701
+ &lt;html&gt;
702
+ &lt;head&gt;
703
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
704
+ &lt;title&gt;Tenjin: Layout Template Example&lt;/title&gt;
705
+ &lt;/head&gt;
706
+ &lt;body&gt;
707
+ <strong>&lt;div class="header"&gt;</strong>
708
+ <strong>&lt;h1&gt;Tenjin: Layout Template Example&lt;/h1&gt;</strong>
709
+ <strong>&lt;/div&gt;</strong>
710
+ &lt;h2&gt;Tenjin Example&lt;/h2&gt;
711
+ &lt;table&gt;
712
+ &lt;tr class="odd"&gt;
713
+ &lt;td&gt;&amp;lt;AAA&amp;gt;&lt;/td&gt;
714
+ &lt;/tr&gt;
715
+ &lt;tr class="even"&gt;
716
+ &lt;td&gt;B&amp;amp;B&lt;/td&gt;
717
+ &lt;/tr&gt;
718
+ &lt;tr class="odd"&gt;
719
+ &lt;td&gt;&amp;quot;CCC&amp;quot;&lt;/td&gt;
720
+ &lt;/tr&gt;
721
+ &lt;/table&gt;
722
+
723
+ <strong>&lt;address&gt;</strong>
724
+ <strong>copyright(c) 2010 kuwata-lab.com all rights reserved</strong>
725
+ <strong>&lt;/address&gt;</strong>
726
+ &lt;/body&gt;
727
+ &lt;/html&gt;
728
+ </pre><br>
729
+ <a name="template-short-name" id="template-short-name"></a>
730
+
731
+ <h3 class="section2">Template Short Name</h3>
732
+
733
+ <p>If you set template postfix, you can specify template by short name such as '<code>:page</code>' instead of '<code>page.rbhtml</code>'. Notice that template short name should be Symbol.</p><a name="test_070/main.rb"></a>
734
+
735
+ <div class="program_caption">
736
+ main.rb
737
+ </div>
738
+ <pre class="program">
739
+ require 'tenjin'
740
+
741
+ ## context data
742
+ context = {
743
+ :title =&gt; 'Tenjin Example',
744
+ :items =&gt; ['&lt;AAA&gt;', 'B&amp;B', '"CCC"'],
745
+ }
746
+
747
+ ## cleate engine object
748
+ engine = Tenjin::Engine.new(:path=&gt;['views'], <strong>:postfix=&gt;'.rbhtml'</strong>, :layout=&gt;<strong>:_layout</strong>)
749
+
750
+ ## render template with context data
751
+ html = engine.render(<strong>:page</strong>, context)
752
+ puts html
753
+ </pre><a name="test_070/views/_layout.rbhtml"></a>
754
+
755
+ <div class="program_caption">
756
+ views/_layout.rbhtml
757
+ </div>
758
+ <pre class="program">
759
+ &lt;?rb #@ARGS _content, page_title ?&gt;
760
+ &lt;!DOCTYPE&gt;
761
+ &lt;html&gt;
762
+ &lt;head&gt;
763
+ &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /&gt;
764
+ &lt;title&gt;${@page_title}&lt;/title&gt;
765
+ &lt;/head&gt;
766
+ &lt;body&gt;
767
+ &lt;?rb import(<strong>:_header</strong>) ?&gt;
768
+ #{@_content}
769
+ &lt;?rb import(<strong>:_footer</strong>) ?&gt;
770
+ &lt;/body&gt;
771
+ &lt;/html&gt;
772
+ </pre><br>
773
+ <a name="helper-functions" id="helper-functions"></a>
774
+
775
+ <h3 class="section2">Helper Function</h3>
776
+
777
+ <p>Tenjin provides some helper methods.</p>
778
+
779
+ <div class="tips"><span class="caption">TIPS:</span>
780
+
781
+ <p>These are defined in helper modules. If you want use them in your class, just include them.</p>
782
+ <pre class="program">
783
+ class FooController &lt; Controller
784
+ <strong>include Tenjin::ContextHelper</strong>
785
+ <strong>include Tenjin::HtmlHelper</strong>
786
+ <strong>include Tenjin::HtmlTagHelper</strong>
787
+ <strong>include Tenjin::SafeHelper</strong>
788
+
789
+ @@engine = Tenjin::Engine.new(:path=&gt;'views', :postfix=&gt;'.rbhtml', :layout=&gt;:_layout)
790
+
791
+ def index()
792
+ @title = "Tenjin Example"
793
+ @items = ["AAA", "BBB", "CCC"]
794
+ html = @@engine.render(:index, <strong>self</strong>)
795
+ return html
796
+ end
797
+
798
+ end
475
799
  </pre>
476
- <a name="example4_yaml.result"></a>
477
- <div class="terminal_caption">
478
- Result:</div>
479
- <pre class="terminal">$ rbtenjin <strong>-f datafile.yaml</strong> example4.rbhtml
480
- &lt;p&gt;
481
- foo
482
- 3.14
483
- true
484
- &lt;/p&gt;
485
800
 
486
- &lt;p&gt;foo&lt;/p&gt;
487
- &lt;p&gt;bar&lt;/p&gt;
488
- &lt;p&gt;baz&lt;/p&gt;
801
+ </div><a name="Tenjin::ContextHelper" id="Tenjin::ContextHelper"></a>
802
+
803
+ <h4 class="section3">Tenjin::ContextHelper</h4>
804
+
805
+ <dl class="dl1">
806
+ <dt class="dt1">import(template_name, _append_to_buf=true)</dt>
807
+
808
+ <dd class="dd1">Include other template. 'template_name' can be filename or short name. See <a href="#partial-template">Include Partial Template</a> section for details.</dd>
809
+ </dl>
810
+
811
+ <dl class="dl1">
812
+ <dt class="dt1">echo(value)</dt>
813
+
814
+ <dd class="dd1">Add value into _buf. This is equivarent to '#{value}'.</dd>
815
+ </dl>
816
+
817
+ <dl class="dl1">
818
+ <dt class="dt1">start_capture(name=nil, &amp;block)</dt>
819
+
820
+ <dd class="dd1">
821
+ start capturing. returns captured string if block given, else return nil. if block is not given, calling stop_capture() is required. See <a href="#capturing">Capturing</a> section for details.
822
+
823
+ <div class="program_caption">
824
+ ex. list.rbhtml
825
+ </div>
826
+ <pre class="program">
827
+ &lt;html&gt;&lt;body&gt;
828
+ &lt;h1&gt;<strong>&lt;?rb start_capture(:title) do ?&gt;</strong>Document Title<strong>&lt;?rb end ?&gt;</strong>&lt;/h1&gt;
829
+ <strong>&lt;?rb start_capture(:content) ?&gt;</strong>
830
+ &lt;ul&gt;
831
+ &lt;?rb for item in list do ?&gt;
832
+ &lt;li&gt;${item}&lt;/li&gt;
833
+ &lt;?rb end ?&gt;
834
+ &lt;/ul&gt;
835
+ <strong>&lt;?rb stop_capture() ?&gt;</strong>
836
+ &lt;/body&gt;&lt;/html&gt;
837
+ </pre>
838
+
839
+ <div class="program_caption">
840
+ ex. layout.rbhtml
841
+ </div>
842
+ <pre class="program">
843
+ &lt;?xml version="1.0" ?&gt;
844
+ &lt;html xml:lang="en"&gt;
845
+ &lt;head&gt;
846
+ &lt;title&gt;${<strong>@title</strong>}&lt;/title&gt;
847
+ &lt;/head&gt;
848
+ &lt;body&gt;
849
+ &lt;h1&gt;${<strong>@title</strong>}&lt;/h1&gt;
850
+ &lt;div id="content"&gt;
851
+ &lt;?rb echo(<strong>@content</strong>) ?&gt;
852
+ &lt;/div&gt;
853
+ &lt;/body&gt;
854
+ &lt;/html&gt;
855
+ </pre>
856
+ </dd>
857
+ </dl>
858
+
859
+ <dl class="dl1">
860
+ <dt class="dt1">stop_capture(store_to_context=true)</dt>
861
+
862
+ <dd class="dd1">Stop capturing. Returns captured string. Necessary only when start_capture() doesn't take a block.</dd>
863
+ </dl>
864
+
865
+ <dl class="dl1">
866
+ <dt class="dt1">captured_as(name)</dt>
489
867
 
490
- &lt;p&gt;x = 1&lt;/p&gt;
491
- &lt;p&gt;y = 2&lt;/p&gt;
868
+ <dd class="dd1">
869
+ If captured string is found then add it to _buf and return true, else return false. This is a helper method for layout template. See <a href="#capturing">Capturing</a> section for details.
870
+ <pre class="program">
871
+ &lt;?py ## layout template example ?&gt;
872
+ &lt;html&gt;
873
+ &lt;body&gt;
874
+ &lt;div id="main"&gt;
875
+ &lt;?rb ## if captured by 'start_capture(:main)', use it. ?&gt;
876
+ &lt;?rb ## if not captured, use this block. ?&gt;
877
+ &lt;?rb if not captured_as(:main) ?&gt;
878
+ &lt;p&gt;content not found&lt;/p&gt;
879
+ &lt;?rb end ?&gt;
880
+ &lt;/div&gt;
881
+ &lt;/body&gt;
882
+ &lt;/html
492
883
  </pre>
493
- <a name="datafile.rb"></a>
494
- <div class="program_caption">
495
- File 'datafile.rb':</div>
496
- <pre class="program">@text = "foo"
497
- @num = 3.14
498
- @flag = true
499
- @items = ["foo", "bar", "baz"]
500
- @hash = {:x=&gt;1, :y=&gt;2}
884
+ </dd>
885
+ </dl>
886
+
887
+ <dl class="dl1">
888
+ <dt class="dt1">_p(str)</dt>
889
+
890
+ <dd class="dd1">See <a href="#preprocessing">Preprocessing</a> section.</dd>
891
+ </dl>
892
+
893
+ <dl class="dl1">
894
+ <dt class="dt1">_P(str)</dt>
895
+
896
+ <dd class="dd1">See <a href="#preprocessing">Preprocessing</a> section.</dd>
897
+ </dl>
898
+
899
+ <dl class="dl1">
900
+ <dt class="dt1">cache_with(key, lifetime=nil)</dt>
901
+
902
+ <dd class="dd1">Cache html fragment. See <a href="#fragment-cache">Fragment Cache</a> section for details.</dd>
903
+ </dl><br>
904
+ <a name="Tenjin::HtmlHelper" id="Tenjin::HtmlHelper"></a>
905
+
906
+ <h4 class="section3">Tenjin::HtmlHelper</h4>
907
+
908
+ <dl class="dl1">
909
+ <dt class="dt1">escape_html(str)</dt>
910
+
911
+ <dd class="dd1">Alias to escape_html().</dd>
912
+ </dl>
913
+
914
+ <dl class="dl1">
915
+ <dt class="dt1">escape_xml(str)</dt>
916
+
917
+ <dd class="dd1">Escape '&amp;', '&lt;', '&gt;', and '"' into '&amp;amp;', '&amp;lt;', '&amp;gt;', and '&amp;quot;' respectively.</dd>
918
+ </dl>
919
+
920
+ <dl class="dl1">
921
+ <dt class="dt1">escape_html(str)</dt>
922
+
923
+ <dd class="dd1">Similar to escape_xml(), but much faster when str contains a lot of '&amp;&lt;&gt;"' characters.</dd>
924
+ </dl><br>
925
+ <a name="Tenjin::SafeHelper" id="Tenjin::SafeHelper"></a>
926
+
927
+ <h4 class="section3">Tenjin::SafeHelper</h4>
928
+
929
+ <dl class="dl1">
930
+ <dt class="dt1">safe_str(str)</dt>
931
+
932
+ <dd class="dd1">Return SafeString object. See <a href="#safe-template">Safe Template</a> section for details.</dd>
933
+ </dl>
934
+
935
+ <dl class="dl1">
936
+ <dt class="dt1">safe_str?(str)</dt>
937
+
938
+ <dd class="dd1">Return true if s is SafeString object. See <a href="#safe-template">Safe Template</a> section for details.</dd>
939
+ </dl>
940
+
941
+ <dl class="dl1">
942
+ <dt class="dt1">safe_escape(str)</dt>
943
+
944
+ <dd class="dd1">Escape str only if val str not SafeString object, and return SafeString object. See <a href="#safe-template">Safe Template</a> section for details.</dd>
945
+ </dl><br>
946
+ <a name="Tenjin::HtmlTagHelper" id="Tenjin::HtmlTagHelper"></a>
947
+
948
+ <h4 class="section3">Tenjin::HtmlTagHelper</h4>
949
+
950
+ <dl class="dl1">
951
+ <dt class="dt1">checked(value)</dt>
952
+
953
+ <dd class="dd1">
954
+ Return ' checked="checked" if value is true.
955
+ <pre class="program">
956
+ value = "1"
957
+ checked(value=="1") #=&gt; ' checked="checked"'
958
+ checked(value=="0") #=&gt; ''
501
959
  </pre>
502
- <a name="example4_datafile_rb.result"></a>
503
- <div class="terminal_caption">
504
- Result:</div>
505
- <pre class="terminal">$ rbtenjin <strong>-f datafile.rb</strong> example4.rbhtml
506
- &lt;p&gt;
507
- foo
508
- 3.14
509
- true
510
- &lt;/p&gt;
960
+ </dd>
961
+ </dl>
511
962
 
512
- &lt;p&gt;foo&lt;/p&gt;
513
- &lt;p&gt;bar&lt;/p&gt;
514
- &lt;p&gt;baz&lt;/p&gt;
963
+ <dl class="dl1">
964
+ <dt class="dt1">selected(value)</dt>
515
965
 
516
- &lt;p&gt;x = 1&lt;/p&gt;
517
- &lt;p&gt;y = 2&lt;/p&gt;
966
+ <dd class="dd1">
967
+ Return ' selected="selected" if value is true.
968
+ <pre class="program">
969
+ value = "1"
970
+ selected(value=="1") #=&gt; ' selected="selected"'
971
+ selected(value=="0") #=&gt; ''
518
972
  </pre>
519
- <br>
973
+ </dd>
974
+ </dl>
520
975
 
976
+ <dl class="dl1">
977
+ <dt class="dt1">disabled(value)</dt>
521
978
 
522
- <a name="des-cmlinecontext"></a>
523
- <h3 class="section2">Command-line Context Data</h3>
524
- <p>Command-line option '<code>-c</code>' specifies context data in YAML format or Ruby code.
525
- </p>
526
- <a name="example5.rbhtml"></a>
527
- <div class="program_caption">
528
- File 'example5.rbhtml':</div>
529
- <pre class="program">text: #{@text}
530
- items:
531
- &lt;?rb for item in @items ?&gt;
532
- - #{item}
533
- &lt;?rb end ?&gt;
534
- hash:
535
- &lt;?rb for key, val in @hash ?&gt;
536
- #{key}: #{val}
537
- &lt;?rb end ?&gt;
979
+ <dd class="dd1">
980
+ Return ' disabled="disabled"' if value is true.
981
+ <pre class="program">
982
+ value = "1"
983
+ disabled(value=="1") #=&gt; ' disabled="disabled"'
984
+ disabled(value=="0") #=&gt; ''
538
985
  </pre>
539
- <a name="example5_datastr_rb.result"></a>
540
- <div class="terminal_caption">
541
- Result of context data in ruby code:</div>
542
- <pre class="terminal">$ rbtenjin <strong>-c '@text="foo"; @items=%w[a b c]; @hash={"x"=&gt;1,"y"=&gt;2}'</strong> example5.rbhtml
543
- text: foo
544
- items:
545
- - a
546
- - b
547
- - c
548
- hash:
549
- x: 1
550
- y: 2
986
+ </dd>
987
+ </dl>
988
+
989
+ <dl class="dl1">
990
+ <dt class="dt1">tagattr(name, expr, value=nil, escape=true)</dt>
991
+
992
+ <dd class="dd1">
993
+ (experimental) Return ' name="value"' if expr is not false nor nil. If value is nil or false then expr is used as value.
994
+ <pre class="program">
995
+ tagattr('name', 'val') #=&gt; ' name="val"'
996
+ tagattr('name', nil) #=&gt; ''
997
+ urlpath = "/blog/"
998
+ tagattr('class', urlpath=='/blog/', 'current') #=&gt; ' class="current"'
999
+ tagattr('class', urlpath=='/', 'current') #=&gt; ''
551
1000
  </pre>
552
- <a name="example5_datastr_yaml.result"></a>
553
- <div class="terminal_caption">
554
- Result of context data in yaml format:</div>
555
- <pre class="terminal">$ rbtenjin <strong>-c '{text: foo, items: [a, b, c], hash: {x: 1, y: 2} }'</strong> example5.rbhtml
556
- text: foo
557
- items:
558
- - a
559
- - b
560
- - c
561
- hash:
562
- x: 1
563
- y: 2
1001
+ </dd>
1002
+ </dl>
1003
+
1004
+ <dl class="dl1">
1005
+ <dt class="dt1">nv(name, value, separator=nil):</dt>
1006
+
1007
+ <dd class="dd1">
1008
+ Return 'name="name" value="value"' string. If separator is specfied, id attribute is added.
1009
+ <pre class="program">
1010
+ nv('user', 'guest'); #=&gt; ' name="user" value="guest"'
1011
+ nv('user', 'guest', '-'); #=&gt; ' name="user" value="guest" id="user-guest"'
564
1012
  </pre>
565
- <br>
566
-
567
-
568
- <a name="des-nested-template"></a>
569
- <h3 class="section2">Nested Template</h3>
570
- <p>Template can include other templates.
571
- Included templates can also include other templates.
572
- </p>
573
- <p>The following function is available to include other templates.
574
- </p>
575
- <dl class="dl3">
576
- <dt class="dt3"><b>
577
- import(template_name) </b></dt>
578
- <dd class="dd3">
579
- Include other template.
580
- </dd>
581
- </dl>
582
- <a name="example6.rbhtml"></a>
583
- <div class="program_caption">
584
- File 'example6.rbhtml':</div>
585
- <pre class="program">&lt;html&gt;
586
- &lt;body&gt;
1013
+ </dd>
1014
+ </dl>
587
1015
 
588
- &lt;div id="sidemenu"&gt;
589
- <strong>&lt;?rb import 'sidemenu.rbhtml' ?&gt;</strong>
590
- &lt;/div&gt;
1016
+ <dl class="dl1">
1017
+ <dt class="dt1">js_link(label, onclick, tags={}):</dt>
591
1018
 
592
- &lt;div id="main-content"&gt;
593
- &lt;?rb for item in @items ?&gt;
594
- &lt;p&gt;${item}&lt;/p&gt;
595
- &lt;?rb end ?&gt;
596
- &lt;/div&gt;
1019
+ <dd class="dd1">
1020
+ Return '&lt;a href="" onclick="onclick"&gt;label&lt;/a&gt;' string.
1021
+ <pre class="program">
1022
+ js_link('Show', '$().show()')
1023
+ #=&gt; '&lt;a href="javascript:undefined" onclick="$().show();return false"&gt;Show&lt;/a&gt;'
1024
+ js_link('Show', '$().show()', :class=&gt;"link")
1025
+ #=&gt; '&lt;a href="javascript:undefined" onclick="$().show();return false" class="link"&gt;Show&lt;/a&gt;'
1026
+ </pre>
1027
+ </dd>
1028
+ </dl>
597
1029
 
598
- &lt;div id="footer"&gt;
599
- <strong>#{import 'footer.rbhtml', false}</strong>
600
- &lt;/div&gt;
1030
+ <dl class="dl1">
1031
+ <dt class="dt1">nl2br(text)</dt>
601
1032
 
602
- &lt;/body&gt;
603
- &lt;/table&gt;
1033
+ <dd class="dd1">
1034
+ Convert "\n" into "&lt;br /&gt;\n".
1035
+ <pre class="program">
1036
+ nl2br("foo\nbar\n") #=&gt; "foo&lt;br /&gt;\nbar&lt;br /&gt;\n"
604
1037
  </pre>
605
- <a name="sidemenu.rbhtml"></a>
606
- <div class="program_caption">
607
- File 'sidemenu.rbhtml':</div>
608
- <pre class="program">&lt;ul&gt;
609
- &lt;?rb for item in @menu ?&gt;
610
- &lt;li&gt;&lt;a href="${item['url']}"&gt;${item['name']}&lt;/a&gt;&lt;/li&gt;
611
- &lt;?rb end ?&gt;
612
- &lt;/ul&gt;
1038
+ </dd>
1039
+ </dl>
1040
+
1041
+ <dl class="dl1">
1042
+ <dt class="dt1">text2html(text)</dt>
1043
+
1044
+ <dd class="dd1">
1045
+ Convert "\n" and " " into "&lt;br /&gt;\n" and " &amp;nbsp;".
1046
+ <pre class="program">
1047
+ text2html(" foo\n bar\n") #=&gt; " &amp;nbsp;foo&lt;br /&gt;\n &amp;nbsp;bar&lt;br /&gt;\n"
613
1048
  </pre>
614
- <a name="footer.rbhtml"></a>
615
- <div class="program_caption">
616
- File 'footer.rbhtml':</div>
617
- <pre class="program">&lt;hr /&gt;
618
- &lt;address&gt;
619
- &lt;a href="mailto:${@webmaster_email}"&gt;${@webmaster_email}&lt;/a&gt;
620
- &lt;/address&gt;
1049
+ </dd>
1050
+ </dl>
1051
+
1052
+ <dl class="dl1">
1053
+ <dt class="dt1">new_cycle(*values)</dt>
1054
+
1055
+ <dd class="dd1">
1056
+ Return Cycle object.
1057
+ <pre class="program">
1058
+ cycle = new_cycle('odd', 'even')
1059
+ "#{cycle}" #=&gt; 'odd'
1060
+ "#{cycle}" #=&gt; 'even'
1061
+ "#{cycle}" #=&gt; 'odd'
621
1062
  </pre>
622
- <a name="contextdata.rb"></a>
623
- <div class="program_caption">
624
- File 'contextdata.rb':</div>
625
- <pre class="program">@items = [ '&lt;FOO&gt;', '&amp;BAR', '"BAZ"' ]
626
- @webmaster_email = 'webmaster@example.com'
627
- @menu = [
628
- {'name'=&gt; 'Top', 'url'=&gt; '/' },
629
- {'name'=&gt; 'Products', 'url'=&gt; '/prod' },
630
- {'name'=&gt; 'Support', 'url'=&gt; '/support' },
631
- ]
1063
+ </dd>
1064
+ </dl><br>
1065
+ <br>
1066
+ <br>
1067
+ <a name="advanced-features" id="advanced-features"></a>
1068
+
1069
+ <h2 class="section1">Advanced Features</h2><a name="safe-template" id="safe-template"></a>
1070
+
1071
+ <h3 class="section2">Safe Template</h3>
1072
+
1073
+ <p><span style="color:#FF0000">(EXPERIMENTAL)</span></p>
1074
+
1075
+ <p>Tenjin provides <code>SafeTemplate</code> and <code>SafeEngine</code> class which enforces HTML escape. These are similar to Django's feature or Jinja2's autoescape feature.</p>
1076
+
1077
+ <p>The point of these classes is that <strong>you can control whether escape html or not by data type, not by embedded notation</strong>.</p>
1078
+
1079
+ <p>See the following example.</p><a name="test_safe/safe-test.rb"></a>
1080
+
1081
+ <div class="program_caption">
1082
+ safe-test.rb
1083
+ </div>
1084
+ <pre class="program">
1085
+ require 'tenjin'
1086
+ <strong>include Tenjin::HtmlHelper</strong> # defines escape()
1087
+ <strong>include Tenjin::SafeHelper</strong> # defines safe_escape(), safe_str(), safe_str?()
1088
+
1089
+ ## both are same notation
1090
+ input = &lt;&lt;END
1091
+ s1 = <strong>${@s1}</strong>
1092
+ s2 = <strong>${@s2}</strong>
1093
+ END
1094
+
1095
+ ## but passed different data type
1096
+ context = {
1097
+ :s1 =&gt; "&lt;b&gt;SOS&lt;/b&gt;",
1098
+ :s2 =&gt; <strong>safe_str</strong>("&lt;b&gt;SOS&lt;/b&gt;"),
1099
+ }
1100
+
1101
+ ## SafeTemplate will escape 's1' but not 's2'
1102
+ template = <strong>Tenjin::SafeTemplate</strong>.new(:input=&gt;input)
1103
+ print(template.script)
1104
+ print("---------------------\n")
1105
+ print(template.render(context))
632
1106
  </pre>
633
- <a name="example6_nested.result"></a>
634
- <div class="terminal_caption">
635
- Result:</div>
636
- <pre class="terminal">$ rbtenjin -f contextdata.rb example6.rbhtml
637
- &lt;html&gt;
638
- &lt;body&gt;
639
1107
 
640
- &lt;div id="sidemenu"&gt;
641
- <strong>&lt;ul&gt;</strong>
642
- <strong>&lt;li&gt;&lt;a href="/"&gt;Top&lt;/a&gt;&lt;/li&gt;</strong>
643
- <strong>&lt;li&gt;&lt;a href="/prod"&gt;Products&lt;/a&gt;&lt;/li&gt;</strong>
644
- <strong>&lt;li&gt;&lt;a href="/support"&gt;Support&lt;/a&gt;&lt;/li&gt;</strong>
645
- <strong>&lt;/ul&gt;</strong>
646
- &lt;/div&gt;
1108
+ <p>The follwoing output shows that:</p>
647
1109
 
648
- &lt;div id="main-content"&gt;
649
- &lt;p&gt;&amp;lt;FOO&amp;gt;&lt;/p&gt;
650
- &lt;p&gt;&amp;amp;BAR&lt;/p&gt;
651
- &lt;p&gt;&amp;quot;BAZ&amp;quot;&lt;/p&gt;
652
- &lt;/div&gt;
1110
+ <ul type="disc">
1111
+ <li><code>SafeTemplate</code> and <code>SafeEngine</code> classes uses <code>safe_escape()</code> instead of <code>escape()</code> to escape value.</li>
653
1112
 
654
- &lt;div id="footer"&gt;
655
- <strong>&lt;hr /&gt;</strong>
656
- <strong>&lt;address&gt;</strong>
657
- <strong> &lt;a href="mailto:webmaster@example.com"&gt;webmaster@example.com&lt;/a&gt;</strong>
658
- <strong>&lt;/address&gt;</strong>
1113
+ <li>Normal string (= <code>"&lt;b&gt;SOS&lt;/b&gt;"</code>) is escaped automatically, but the other string which is marked as escaped (= <code>safe_str("&lt;b&gt;SOS&lt;/b&gt;")</code>) is not escaped. This means that you can controll escape by data type, not embedded notation.</li>
1114
+ </ul><a name="test_safe/result.output"></a>
659
1115
 
660
- &lt;/div&gt;
1116
+ <div class="terminal_caption">
1117
+ Output example
1118
+ </div>
1119
+ <pre class="terminal">
1120
+ $ ruby safe-test.rb
1121
+ _buf &lt;&lt; %Q`s1 = #{<strong>safe_escape</strong>((@s1).to_s)}
1122
+ s2 = #{<strong>safe_escape</strong>((@s2).to_s)}\n`
1123
+ ---------------------
1124
+ s1 = &amp;lt;b&amp;gt;SOS&amp;lt;/b&amp;gt;
1125
+ s2 = <strong>&lt;b&gt;SOS&lt;/b&gt;</strong>
1126
+ </pre>
1127
+
1128
+ <p>In addition, <code>SafeTemplate</code>/<code>SafeEngine</code> classes inhibits <code>#{...}</code> because some people mistake it with <code>${...}</code> and it can be XSS security hole in the result. Use <code>${...}</code> in each case.</p>
1129
+ <pre class="program">
1130
+ #{@value} # Not available with SafeTemplate/SafeEngine!
1131
+ ${@value} # Use this in each case.
1132
+ </pre>
1133
+
1134
+ <div class="tips"><span class="caption">TIPS:</span>
1135
+
1136
+ <p>Implementation of SafeTemplate and SafeEngine is very small. In other words, it is easy to implement your own SafeTemplate/SafeEngine class. See source code of Tenjin for details.</p>
1137
+
1138
+ </div>
1139
+
1140
+ <p>There are three helper methods defined in Tenjin::SafeHelper.</p>
1141
+
1142
+ <dl class="dl1">
1143
+ <dt class="dt1">safe_escape(str)</dt>
1144
+
1145
+ <dd class="dd1">
1146
+ <ul type="circle">
1147
+ <li>If str is normal String, escape it and return SafeString object.</li>
1148
+
1149
+ <li>If str is SafeString object, just return it.</li>
1150
+ </ul>
1151
+ </dd>
1152
+ </dl>
1153
+
1154
+ <dl class="dl1">
1155
+ <dt class="dt1">safe_str(str)</dt>
661
1156
 
1157
+ <dd class="dd1">
1158
+ <ul type="circle">
1159
+ <li>If str is normal String, return SafeString object WITHOUT escaping.</li>
1160
+
1161
+ <li>If str is SafeString object, just return it.</li>
1162
+ </ul>
1163
+ </dd>
1164
+ </dl>
1165
+
1166
+ <dl class="dl1">
1167
+ <dt class="dt1">safe_str?(str)</dt>
1168
+
1169
+ <dd class="dd1">
1170
+ <ul type="circle">
1171
+ <li>If str is normla String, return false.</li>
1172
+
1173
+ <li>If str is SafeString object, return true.</li>
1174
+ </ul>
1175
+ </dd>
1176
+ </dl><a name="test_safehelper/main.rb"></a>
1177
+
1178
+ <div class="program_caption">
1179
+ Example of safe helpers
1180
+ </div>
1181
+ <pre class="program">
1182
+ require 'tenjin'
1183
+ include Tenjin::HtmlHelper
1184
+ include Tenjin::SafeHelper
1185
+ #
1186
+ s = "&lt;AAA&gt;"
1187
+ puts safe_str?(s) #=&gt; false
1188
+ s = safe_escape(s) # same as SafeString.new(escape(s))
1189
+ puts safe_str?(s) #=&gt; true
1190
+ puts s #=&gt; &amp;lt;AAA&amp;gt;
1191
+ puts safe_escape(s) #=&gt; &amp;lt;AAA&amp;gt;
1192
+ #
1193
+ s = "&lt;AAA&gt;"
1194
+ s = safe_str(s) # same as SafeString.new(s)
1195
+ puts safe_str?(s) #=&gt; true
1196
+ puts s #=&gt; &lt;AAA&gt;
1197
+ puts safe_escape(s) #=&gt; &lt;AAA&gt;
1198
+ </pre><br>
1199
+ <a name="nested-layout-template" id="nested-layout-template"></a>
1200
+
1201
+ <h3 class="section2">Nested Layout Template</h3>
1202
+
1203
+ <p>It is able to nest several layout template files.</p><a name="test_nested/views/_site_layout.rbhtml"></a>
1204
+
1205
+ <div class="program_caption">
1206
+ views/_site_layout.rbhtml
1207
+ </div>
1208
+ <pre class="program">
1209
+ &lt;html&gt;
1210
+ &lt;body&gt;
1211
+ <strong>#{@_content}</strong>
662
1212
  &lt;/body&gt;
663
- &lt;/table&gt;
1213
+ &lt;/html&gt;
1214
+ </pre><a name="test_nested/views/_blog_layout.rbhtml"></a>
1215
+
1216
+ <div class="program_caption">
1217
+ views/_blog_layout.rbhtml
1218
+ </div>
1219
+ <pre class="program">
1220
+ <strong>&lt;?rb @_layout = '_site_layout.rbhtml' ?&gt;</strong>
1221
+ &lt;h2&gt;${@title}&lt;/h2&gt;
1222
+ &lt;!-- content --&gt;
1223
+ <strong>#{@_content}</strong>
1224
+ &lt;!-- /content --&gt;
1225
+ </pre><a name="test_nested/views/blog_post.rbhtml"></a>
1226
+
1227
+ <div class="program_caption">
1228
+ views/blog_post.rbhtml
1229
+ </div>
1230
+ <pre class="program">
1231
+ <strong>&lt;?rb @_layout = '_blog_layout.rbhtml' ?&gt;</strong>
1232
+ &lt;div class="article"&gt;
1233
+ #{text2html(@post_content)}
1234
+ &lt;/div&gt;
1235
+ </pre><a name="test_nested/main.rb"></a>
1236
+
1237
+ <div class="program_caption">
1238
+ main.rb
1239
+ </div>
1240
+ <pre class="program">
1241
+ require 'tenjin'
1242
+ engine = Tenjin::Engine.new(:path=&gt;['views'])
1243
+ context = {
1244
+ :title =&gt; 'Blog Post Test',
1245
+ :post_content =&gt; "Foo\nBar\nBaz",
1246
+ }
1247
+ html = engine.render('blog_post.rbhtml', context)
1248
+ print(html)
1249
+ </pre><a name="test_nested/result.output"></a>
1250
+
1251
+ <div class="terminal_caption">
1252
+ Result
1253
+ </div>
1254
+ <pre class="terminal">
1255
+ $ ruby main.rb
1256
+ &lt;html&gt; # by _layout.rbhtml
1257
+ &lt;body&gt; # :
1258
+ &lt;h2&gt;Blog Post Test&lt;/h2&gt; # by _blog_layout.rbhtml
1259
+ &lt;!-- content --&gt; # :
1260
+ &lt;div class="article"&gt; # by blog_post.rbhtml
1261
+ Foo&lt;br /&gt; # :
1262
+ Bar&lt;br /&gt; # :
1263
+ Baz # :
1264
+ &lt;/div&gt; # :
1265
+ # :
1266
+ &lt;!-- /content --&gt; # by _blog_layout.rbhtml
1267
+ # :
1268
+ &lt;/body&gt; # by _layout.rbhtml
1269
+ &lt;/html&gt; # :
1270
+ </pre><br>
1271
+ <a name="trace" id="trace"></a>
1272
+
1273
+ <h3 class="section2">Trace Templates</h3>
1274
+
1275
+ <p>If you pass '<code>:trace=&gt;true</code>' to Tenjin::Template class or Tenjin::Engine class, Template class will print template file name at the beginning and end of output.</p>
1276
+
1277
+ <p>For example:</p><a name="test_trace/trace-example.rb"></a>
1278
+
1279
+ <div class="program_caption">
1280
+ trace-example.rb
1281
+ </div>
1282
+ <pre class="program">
1283
+ require 'tenjin'
1284
+ engine = Tenjin::Engine.new(:layout=&gt;'layout.rbhtml', <strong>:trace=&gt;true</strong>)
1285
+ output = engine.render('main.rbhtml', {'items'=&gt;['A','B','C']})
1286
+ puts output
664
1287
  </pre>
665
- <p>Function '<code>import()</code>' can take template filename
666
- (ex. 'user_main.rbhtml') or template short name (ex. :main).
667
- Template short name is a Symbol.
668
- </p>
669
- <p>To make template short name available, command-line option '<code>--prefix</code>' and
670
- '<code>--postfix</code>' are required.
671
- For example, '<code>include("user_main.rbhtml")</code>' can be described as '<code>include(:main)</code>'
672
- when '<code>--prefix="user_"</code>' and '<code>--postfix=".rbhtml"</code>' are specified in command-line.
673
- </p>
674
- <br>
675
-
676
-
677
- <a name="des-layout"></a>
678
- <h3 class="section2">Layout Template</h3>
679
- <p>Command-line option '<code>--layout=templatename</code>' specifies layout template name.
680
- </p>
681
- <p>For example, 'exmample6.rbhtml' template in the previous section can be divided
682
- into layout file 'layout6.rbhtml' and content file 'content6.rbhtml'.
683
- Variable '<code>@_content</code>' in layout template represents the result of content file.
684
- </p>
685
- <a name="layout6.rbhtml"></a>
686
- <div class="program_caption">
687
- File 'layout6.rbhtml':</div>
688
- <pre class="program">&lt;html&gt;
1288
+
1289
+ <p>Will print:</p><a name="test_trace/result.output"></a>
1290
+ <pre class="terminal">
1291
+ $ ruby trace-example.rb
1292
+ <strong>&lt;!-- ***** begin: layout.rbhtml ***** --&gt;</strong>
1293
+ &lt;html&gt;
689
1294
  &lt;body&gt;
1295
+ &lt;div class="content"&gt;
1296
+ <strong>&lt;!-- ***** begin: main.rbhtml ***** --&gt;</strong>
1297
+ &lt;ul&gt;
1298
+ &lt;li&gt;A&lt;/li&gt;
1299
+ &lt;li&gt;B&lt;/li&gt;
1300
+ &lt;li&gt;C&lt;/li&gt;
1301
+ &lt;/ul&gt;
1302
+ <strong>&lt;!-- ***** end: main.rbhtml ***** --&gt;</strong>
1303
+ &lt;/div&gt;
1304
+ &lt;/body&gt;
1305
+ &lt;/html&gt;
1306
+ <strong>&lt;!-- ***** end: layout.rbhtml ***** --&gt;</strong>
1307
+ </pre>
1308
+
1309
+ <p>This feature is very useful when debugging to detect template file name from HTML output.</p>
690
1310
 
691
- &lt;div id="sidemenu"&gt;
692
- &lt;?rb import 'sidemenu.rbhtml' ?&gt;
1311
+ <p>If you like it, you can make it always enabled.</p>
1312
+ <pre class="program">
1313
+ ## trace is always enabled
1314
+ Tenjin::Engine.TRACE = true
1315
+ </pre><br>
1316
+ <a name="capturing" id="capturing"></a>
1317
+
1318
+ <h3 class="section2">Capturing</h3>
1319
+
1320
+ <p>It is able to capture parital of output. You can use this feature as an alternative of Django's template-inheritance.</p><a name="test_capturing/views/blog-post.rbhtml"></a>
1321
+
1322
+ <div class="program_caption">
1323
+ views/blog-post.rbhtml : one partial capture ('sidebar')
1324
+ </div>
1325
+ <pre class="program">
1326
+ &lt;h2&gt;#{@blog_post[:title]}&lt;/h2&gt;
1327
+ &lt;div class="blog-post"&gt;
1328
+ #{text2html(@blog_post[:content])}
1329
+ &lt;/div&gt;
1330
+
1331
+ <strong>&lt;?rb start_capture('sidebar') do ?&gt;</strong>
1332
+ &lt;h3&gt;Recent Posts&lt;/h3&gt;
1333
+ &lt;ul&gt;
1334
+ &lt;?rb for post in @recent_posts ?&gt;
1335
+ &lt;a href="/blog/#{post[:id]}"&gt;${post[:title]}&lt;/a&gt;
1336
+ &lt;?rb end ?&gt;
1337
+ &lt;/ul&gt;
1338
+ <strong>&lt;?rb end ?&gt;</strong>
1339
+ </pre><a name="test_capturing/views/_layout.rbhtml"></a>
1340
+
1341
+ <div class="program_caption">
1342
+ views/_layout.rbhtml : two placeholders ('header' and 'sidebar')
1343
+ </div>
1344
+ <pre class="program">
1345
+ &lt;html&gt;
1346
+ &lt;body&gt;
1347
+ &lt;div id="header-part"&gt;
1348
+ <strong>&lt;?rb if ! captured_as(:header) ?&gt;</strong>
1349
+ &lt;h1&gt;My Great Blog&lt;/h1&gt;
1350
+ <strong>&lt;?rb end ?&gt;</strong>
693
1351
  &lt;/div&gt;
694
-
695
1352
  &lt;div id="main-content"&gt;
696
- <strong>#{@_content}</strong>
1353
+ #{@_content}
697
1354
  &lt;/div&gt;
698
-
699
- &lt;div id="footer"&gt;
700
- #{import 'footer.rbhtml', false}
1355
+ &lt;div id="sidebar-part"&gt;
1356
+ <strong>&lt;?rb if ! captured_as(:sidebar) ?&gt;</strong>
1357
+ &lt;h3&gt;Links&lt;/h3&gt;
1358
+ &lt;ul&gt;
1359
+ &lt;a href="http://google.com/"&gt;Google&lt;/a&gt;
1360
+ &lt;a href="http://yahoo.com/"&gt;Yahoo!&lt;/a&gt;
1361
+ &lt;/ul&gt;
1362
+ <strong>&lt;?rb end ?&gt;</strong>
701
1363
  &lt;/div&gt;
702
-
703
1364
  &lt;/body&gt;
704
- &lt;/table&gt;
705
- </pre>
706
- <a name="content6.rbhtml"></a>
707
- <div class="program_caption">
708
- File 'content6.rbhtml':</div>
709
- <pre class="program">&lt;?rb for item in @items ?&gt;
710
- &lt;p&gt;${item}&lt;/p&gt;
711
- &lt;?rb end ?&gt;
1365
+ &lt;/html&gt;
1366
+ </pre><a name="test_capturing/main.rb"></a>
1367
+
1368
+ <div class="program_caption">
1369
+ main.rb
1370
+ </div>
1371
+ <pre class="program">
1372
+ ## context data
1373
+ post_content = &lt;&lt;END
1374
+ Tenjin has great features.
1375
+ - Very Fast
1376
+ - Full Featured
1377
+ - Easy to Use
1378
+ END
1379
+ context = {
1380
+ :blog_post =&gt; {
1381
+ :title =&gt; 'Tenjin is Great',
1382
+ :content =&gt; post_content,
1383
+ },
1384
+ :recent_posts =&gt; [
1385
+ {:id=&gt;1, :title=&gt;'Tenjin is Fast' },
1386
+ {:id=&gt;2, :title=&gt;'Tenjin is Full-Featured' },
1387
+ {:id=&gt;3, :title=&gt;'Tenjin is Easy-to-Use' },
1388
+ ]
1389
+ }
1390
+
1391
+ ## render template
1392
+ require 'tenjin'
1393
+ engine = Tenjin::Engine.new(:path=&gt;['views'], :layout=&gt;'_layout.rbhtml')
1394
+ html = engine.render('blog-post.rbhtml', context)
1395
+ puts html
712
1396
  </pre>
713
- <a name="example6_layout.result"></a>
714
- <div class="terminal_caption">
715
- Result:</div>
716
- <pre class="terminal">$ rbtenjin -f contextdata.rb <strong>--layout=layout6.rbhtml</strong> content6.rbhtml
1397
+
1398
+ <p>The result shows that captured string (with name 'sidebar') overwrites layout template content.</p><a name="test_capturing/result.output"></a>
1399
+
1400
+ <div class="program_caption">
1401
+ Result : only 'sidebar' placeholder is overwritten by capturing.
1402
+ </div>
1403
+ <pre class="program">
1404
+ $ ruby main.rb
717
1405
  &lt;html&gt;
718
1406
  &lt;body&gt;
719
-
720
- &lt;div id="sidemenu"&gt;
721
- &lt;ul&gt;
722
- &lt;li&gt;&lt;a href="/"&gt;Top&lt;/a&gt;&lt;/li&gt;
723
- &lt;li&gt;&lt;a href="/prod"&gt;Products&lt;/a&gt;&lt;/li&gt;
724
- &lt;li&gt;&lt;a href="/support"&gt;Support&lt;/a&gt;&lt;/li&gt;
725
- &lt;/ul&gt;
1407
+ &lt;div id="header-part"&gt;
1408
+ &lt;h1&gt;My Great Blog&lt;/h1&gt;
726
1409
  &lt;/div&gt;
727
-
728
1410
  &lt;div id="main-content"&gt;
729
- <strong> &lt;p&gt;&amp;lt;FOO&amp;gt;&lt;/p&gt;</strong>
730
- <strong> &lt;p&gt;&amp;amp;BAR&lt;/p&gt;</strong>
731
- <strong> &lt;p&gt;&amp;quot;BAZ&amp;quot;&lt;/p&gt;</strong>
1411
+ &lt;h2&gt;Tenjin is Great&lt;/h2&gt;
1412
+ &lt;div class="blog-post"&gt;
1413
+ Tenjin has great features.&lt;br /&gt;
1414
+ - Very Fast&lt;br /&gt;
1415
+ - Full Featured&lt;br /&gt;
1416
+ - Easy to Use&lt;br /&gt;
732
1417
 
733
- &lt;/div&gt;
1418
+ &lt;/div&gt;
734
1419
 
735
- &lt;div id="footer"&gt;
736
- &lt;hr /&gt;
737
- &lt;address&gt;
738
- &lt;a href="mailto:webmaster@example.com"&gt;webmaster@example.com&lt;/a&gt;
739
- &lt;/address&gt;
740
1420
 
741
1421
  &lt;/div&gt;
742
-
1422
+ &lt;div id="sidebar-part"&gt;
1423
+ <strong>&lt;h3&gt;Recent Posts&lt;/h3&gt;</strong>
1424
+ <strong>&lt;ul&gt;</strong>
1425
+ <strong>&lt;a href="/blog/1"&gt;Tenjin is Fast&lt;/a&gt;</strong>
1426
+ <strong>&lt;a href="/blog/2"&gt;Tenjin is Full-Featured&lt;/a&gt;</strong>
1427
+ <strong>&lt;a href="/blog/3"&gt;Tenjin is Easy-to-Use&lt;/a&gt;</strong>
1428
+ <strong>&lt;/ul&gt;</strong>
1429
+ &lt;/div&gt;
743
1430
  &lt;/body&gt;
744
- &lt;/table&gt;
745
- </pre>
746
- <p>Target template and layout template don't share local variables.
747
- It means that local variables set in a template are not available in layout template.
748
- </p>
749
- <p>If you want variables set in a temlate to be available in layout template,
750
- use instance variables instead of local variables.
751
- </p>
752
- <a name="layout7.rbhtml"></a>
753
- <div class="program_caption">
754
- File 'layout7.rbhtml':</div>
755
- <pre class="program">...
756
- &lt;h1&gt;<strong>${@title}</strong>&lt;/h1&gt;
757
-
758
- &lt;div id="main-content"&gt;
759
- #{@_content}
760
- &lt;div&gt;
1431
+ &lt;/html&gt;
1432
+ </pre><br>
1433
+ <a name="templace-cache" id="templace-cache"></a>
761
1434
 
762
- &lt;a href="<strong>${@url}</strong>"&gt;Next page&lt;/a&gt;
763
- ...
764
- </pre>
765
- <a name="content7.rbhtml"></a>
766
- <div class="program_caption">
767
- File 'content7.rbhtml':</div>
768
- <pre class="program"><strong>&lt;?rb @title = 'Document Title' ?&gt;</strong>
769
- <strong>&lt;?rb @url = '/next/page' ?&gt;</strong>
770
- &lt;table&gt;
771
- ...content...
772
- &lt;/table&gt;
773
- </pre>
774
- <a name="example7_layout2.result"></a>
775
- <div class="terminal_caption">
776
- Result:</div>
777
- <pre class="terminal">$ rbtenjin --layout=layout7.rbhtml content7.rbhtml
778
- ...
779
- &lt;h1&gt;<strong>Document Title</strong>&lt;/h1&gt;
780
-
781
- &lt;div id="main-content"&gt;
782
- &lt;table&gt;
783
- ...content...
784
- &lt;/table&gt;
1435
+ <h3 class="section2">Template Cache</h3>
785
1436
 
1437
+ <p>Tenjin converts template file into Ruby script and save it as cache file. By default, it is saved as template-filename + '.cache' in bytecode format. You can change this behaviour by setting <code>Tenjin::Engine.template_cache</code> or passing cache object to <code>Tenjin::Engine.new()</code>.</p>
1438
+
1439
+ <div class="program_caption">
1440
+ example to change template caching
1441
+ </div>
1442
+ <pre class="program">
1443
+ ## assume that you implimented MemcachedTemplateCache package
1444
+ class MemcachedTemplaceCache &lt; Tenjin::TemplateCache
1445
+ def save(cachepath, template) ... end
1446
+ def load(cachepath, timestamp=nil) ... end
1447
+ end
1448
+ end
1449
+
1450
+ ## change to store template cache into memcached
1451
+ <strong>Tenjin::Engine.template_cache = MemcachedTemplateCache.new();</strong>
1452
+ my $engine = Tenjin::Engine.new();
1453
+
1454
+ ## or
1455
+ my $engine = Tenjin::Engine.new(<strong>:cache=&gt;MemcachedTemplateCache.new()</strong>);
1456
+
1457
+ </pre><br>
1458
+ <a name="fragment-cache" id="fragment-cache"></a>
1459
+
1460
+ <h3 class="section2">Fragment Cache</h3>
1461
+
1462
+ <p>You can cache a certain part of HTML to improve performance. This is called as Fragment Cache.</p><a name="test_fragmentcache/views/items.rbhtml"></a>
1463
+
1464
+ <div class="program_caption">
1465
+ views/items.rbhtml
1466
+ </div>
1467
+ <pre class="program">
786
1468
  &lt;div&gt;
1469
+ <strong>&lt;?rb # fragment cache with key ('items/1') and lifetime (60sec) ?&gt;</strong>
1470
+ <strong>&lt;?rb cache_with('items/1', 60) do ?&gt;</strong>
1471
+ &lt;ul&gt;
1472
+ &lt;?rb for item in @get_items.call() ?&gt;
1473
+ &lt;li&gt;${item}&lt;/li&gt;
1474
+ &lt;?rb end ?&gt;
1475
+ &lt;/ul&gt;
1476
+ <strong>&lt;?rb end ?&gt;</strong>
1477
+ &lt;/div&gt;
1478
+ </pre>
1479
+
1480
+ <p>Tenjin stores fragments caches into memory by default. If you want to change or customize cache store, see the following example.</p><a name="test_fragmentcache/main.rb"></a>
1481
+
1482
+ <div class="program_caption">
1483
+ main.rb
1484
+ </div>
1485
+ <pre class="program">
1486
+ require 'tenjin'
787
1487
 
788
- &lt;a href="<strong>/next/page</strong>"&gt;Next page&lt;/a&gt;
789
- ...
790
- </pre>
791
- <p>Using '@_layout' variable, it is able to specify layout template name in each template file.
792
- If you assigned false to '@_layout' variable, no layout template is used.
793
- </p>
794
- <a name="content8.rbhtml"></a>
795
- <div class="program_caption">
796
- File 'content8.rbhtml':</div>
797
- <pre class="program"><strong>&lt;?rb @_layout = :layout8_xhtml ?&gt;</strong>
798
- &lt;h1&gt;Hello World!&lt;/h1&gt;
799
- </pre>
800
- <a name="layout8_html.rbhtml"></a>
801
- <div class="program_caption">
802
- File 'layout8_html.rbhtml':</div>
803
- <pre class="program">&lt;html&gt;
804
- &lt;body&gt;
805
- #{@_content}
806
- &lt;/body&gt;
807
- &lt;/html&gt;
808
- </pre>
809
- <a name="layout8_xhtml.rbhtml"></a>
810
- <div class="program_caption">
811
- File 'layout8_xhtml.rbhtml':</div>
812
- <pre class="program">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
813
- &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
814
- &lt;body&gt;
815
- #{@_content}
816
- &lt;/body&gt;
817
- &lt;/html&gt;
1488
+ ## create key-value store object
1489
+ Dir.mkdir('cache.d') unless File.exist?('cache.d')
1490
+ <strong>kv_store = Tenjin::FileBaseStore.new('cache.d') # file based</strong>
1491
+
1492
+ ## set key-value store into tenjin.helpers.fagment_cache object
1493
+ <strong>Tenjin::Engine.data_cache = kv_store</strong>
1494
+
1495
+ ## context data
1496
+ ## (it is strongly recommended to create Proc object
1497
+ ## to provide pull-style context data)
1498
+ get_items = proc { # called only when cache is expired
1499
+ ['AAA', 'BBB', 'CCC']
1500
+ }
1501
+ context = {:get_items =&gt; get_items}
1502
+
1503
+ ## render html
1504
+ engine = Tenjin::Engine.new(:path=&gt;['views'])
1505
+ html = engine.render('items.rbhtml', context)
1506
+ puts html
1507
+ </pre><a name="test_fragmentcache/result.output"></a>
1508
+
1509
+ <div class="terminal_caption">
1510
+ Result
1511
+ </div>
1512
+ <pre class="terminal">
1513
+ $ ruby main.rb
1514
+ &lt;div&gt;
1515
+ &lt;ul&gt;
1516
+ &lt;li&gt;AAA&lt;/li&gt;
1517
+ &lt;li&gt;BBB&lt;/li&gt;
1518
+ &lt;li&gt;CCC&lt;/li&gt;
1519
+ &lt;/ul&gt;
1520
+ &lt;/div&gt;
1521
+ </pre>
1522
+
1523
+ <p>You'll find that HTML fragment is cached into cache directory. This cache data will be expired at 60 seconds after.</p><a name="test_fragmentcache/result2.output"></a>
1524
+ <pre class="terminal">
1525
+ $ cat cache.d/items/1
1526
+ &lt;ul&gt;
1527
+ &lt;li&gt;AAA&lt;/li&gt;
1528
+ &lt;li&gt;BBB&lt;/li&gt;
1529
+ &lt;li&gt;CCC&lt;/li&gt;
1530
+ &lt;/ul&gt;
1531
+ </pre><br>
1532
+ <a name="logging" id="logging"></a>
1533
+
1534
+ <h3 class="section2">Logging</h3>
1535
+
1536
+ <p>If you set logging object to <code>Tenjin.logger</code>, rbTenjin will report loading template files.</p>
1537
+
1538
+ <p>For example:</p><a name="test_logging/ex-logger.rb"></a>
1539
+
1540
+ <div class="program_caption">
1541
+ ex-logger.rb
1542
+ </div>
1543
+ <pre class="program">
1544
+ require 'tenjin'
1545
+
1546
+ ## set logger object
1547
+ <strong>require 'logger'</strong>
1548
+ <strong>Tenjin.logger = Logger.new($stdout)</strong>
1549
+ Tenjin.logger.datetime_format = ""
1550
+
1551
+ engine = Tenjin::Engine.new()
1552
+ context = {:name =&gt; 'World'}
1553
+ html = engine.render('example.rbhtml', context)
1554
+ #print html
818
1555
  </pre>
819
- <a name="example8_layout3.result"></a>
820
- <div class="terminal_caption">
821
- Result: ':layout8_html' is specified in command-line option but ':layout8_xhtml' is used</div>
822
- <pre class="terminal">$ rbtenjin --postfix='.rbhtml' <strong>--layout=':layout8_html'</strong> content8.rbhtml
823
- &lt;?xml version="1.0" encoding="UTF-8"?&gt;
824
- &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"&gt;
825
- &lt;body&gt;
826
- &lt;h1&gt;Hello World!&lt;/h1&gt;
827
1556
 
828
- &lt;/body&gt;
829
- &lt;/html&gt;
1557
+ <p>If you run it first time, Tenjin will report that template object is stored into cache file.</p><a name="test_logging/result1.output"></a>
1558
+ <pre class="terminal">
1559
+ $ ruby ex-logger.rb
1560
+ D, [#3700] DEBUG -- : [tenjin.rb:1022] cache not found (cachefile="example.rbhtml.cache").
1561
+ D, [#3700] DEBUG -- : [tenjin.rb:1005] cache saved (cachefile="example.rbhtml.cache").
830
1562
  </pre>
831
- <br>
832
1563
 
1564
+ <p>And if you run it again, Tenjin will report that template object is loaded from cache file.</p><a name="test_logging/result2.output"></a>
1565
+ <pre class="terminal">
1566
+ $ ruby ex-logger.rb
1567
+ D, [#3730] DEBUG -- : [tenjin.rb:1028] cache found (cachefile="example.rbhtml.cache").
1568
+ </pre><br>
1569
+ <a name="preprocessing" id="preprocessing"></a>
833
1570
 
834
- <a name="des-capturing"></a>
835
- <h3 class="section2">Capturing</h3>
836
- <p>It is able to capture any part of template.
837
- </p>
838
- <a name="example9.rbhtml"></a>
839
- <div class="program_caption">
840
- File 'example9.rbhtml':</div>
841
- <pre class="program">&lt;?rb @title = 'Capture Test' ?&gt;
842
- &lt;html&gt;
843
- &lt;body&gt;
1571
+ <h3 class="section2">Preprocessing</h3>
844
1572
 
845
- <strong>&lt;?rb start_capture(:content_part) ?&gt;</strong>
846
- &lt;ul&gt;
847
- &lt;?rb for i in [0, 1, 2] ?&gt;
848
- &lt;li&gt;i = #{i}&lt;/li&gt;
849
- &lt;?rb end ?&gt;
850
- &lt;/ul&gt;
851
- <strong>&lt;?rb stop_capture() ?&gt;</strong>
1573
+ <p>Tenjin supports preprocessing of template. Preprocessing executes some logics when templates are loaded and that logics are not executed when rendering. Preprocessing makes your application much faster.</p><a name="preprocessing-basics" id="preprocessing-basics"></a>
852
1574
 
853
- <strong>&lt;?rb start_capture('footer_part') ?&gt;</strong>
854
- &lt;div class="footer"&gt;copyright&amp;copy; 2007 kuwata-lab.com&lt;/div&gt;
855
- <strong>&lt;?rb stop_capture() ?&gt;</strong>
1575
+ <h4 class="section3">Basics of Preprocessing</h4>
856
1576
 
857
- &lt;/body&gt;
858
- &lt;/html&gt;
859
- </pre>
860
- <p>Captured strings are accessable as local variables.
861
- For example, you can get captured string as a variable '<code>content_part</code>' in the above example.
862
- </p>
863
- <p>A template can contain several capturing.
864
- It is not able to nest capturing.
865
- </p>
866
- <p>In layout file, it is able to use strings captured in templates.
867
- </p>
868
- <a name="layout9.rbhtml"></a>
869
- <div class="program_caption">
870
- File 'layout9.rbhtml':</div>
871
- <pre class="program">&lt;html lang="en"&gt;
872
- &lt;head&gt;
873
- &lt;title&gt;${@title}&lt;/title&gt;
874
- &lt;/head&gt;
875
- &lt;body&gt;
1577
+ <p>Notation of preprocessing:</p>
876
1578
 
877
- &lt;!-- HEADER --&gt;
878
- <strong>&lt;?rb unless captured_as('header_part') ?&gt;</strong>
879
- &lt;h1&gt;${@title}&lt;/h1&gt;
880
- <strong>&lt;?rb end ?&gt;</strong>
881
- &lt;!-- /HEADER --&gt;
1579
+ <dl class="dl1">
1580
+ <dt class="dt1"><code>&lt;?RB ... ?&gt;</code></dt>
882
1581
 
883
- &lt;!-- CONTENT --&gt;
884
- <strong>#{@content_part}</strong>
885
- &lt;!-- /CONTENT --&gt;
1582
+ <dd class="dd1">Preprocessing statement.</dd>
886
1583
 
887
- &lt;!-- FOOTER --&gt;
888
- <strong>&lt;?rb unless captured_as('footer_part') ?&gt;</strong>
889
- &lt;hr /&gt;
890
- &lt;address&gt;webmaster@localhost&lt;/address&gt;
891
- <strong>&lt;?rb end ?&gt;</strong>
892
- &lt;!-- /FOOTER --&gt;
1584
+ <dt class="dt1"><code>#{{...}}</code></dt>
893
1585
 
894
- &lt;/body&gt;
895
- &lt;/html&gt;
896
- </pre>
897
- <p>'<code>unless captured_as("name") ... end</code>' is equivarent to the following.
898
- </p>
899
- <pre class="program">&lt;?rb if @name ?&gt;
900
- &lt;?rb _buf &lt;&lt; @name ?&gt;
901
- &lt;?rb else ?&gt;
902
- ...
903
- &lt;?rb end ?&gt;
904
- </pre>
905
- <p>The following result shows that content part and footer part are overrided by capturing in content template but header part is not.
906
- </p>
907
- <a name="example9_capture.result"></a>
908
- <div class="terminal_caption">
909
- Result:</div>
910
- <pre class="terminal">$ rbtenjin --layout=layout9.rbhtml example9.rbhtml
911
- &lt;html lang="en"&gt;
912
- &lt;head&gt;
913
- &lt;title&gt;Capture Test&lt;/title&gt;
914
- &lt;/head&gt;
915
- &lt;body&gt;
1586
+ <dd class="dd1">Preprocessing expression (without HTML escape)</dd>
916
1587
 
917
- &lt;!-- HEADER --&gt;
918
- &lt;h1&gt;Capture Test&lt;/h1&gt;
919
- &lt;!-- /HEADER --&gt;
1588
+ <dt class="dt1"><code>${{...}}</code></dt>
920
1589
 
921
- &lt;!-- CONTENT --&gt;
922
- <strong>&lt;ul&gt;</strong>
923
- <strong>&lt;li&gt;i = 0&lt;/li&gt;</strong>
924
- <strong>&lt;li&gt;i = 1&lt;/li&gt;</strong>
925
- <strong>&lt;li&gt;i = 2&lt;/li&gt;</strong>
926
- <strong>&lt;/ul&gt;</strong>
1590
+ <dd class="dd1">Preprocessing expression (with HTML escape)</dd>
1591
+ </dl>
927
1592
 
928
- &lt;!-- /CONTENT --&gt;
1593
+ <p>The following shows difference between <code>${...}</code> and <code>${{...}}</code>.</p><a name="test_preprocessing/views/pp-example1.rbhtml"></a>
929
1594
 
930
- &lt;!-- FOOTER --&gt;
931
- <strong>&lt;div class="footer"&gt;copyright&amp;copy; 2007 kuwata-lab.com&lt;/div&gt;</strong>
932
- &lt;!-- /FOOTER --&gt;
1595
+ <div class="program_caption">
1596
+ views/pp-example1.rbhtml
1597
+ </div>
1598
+ <pre class="program">
1599
+ ## normal expression
1600
+ value = <strong>${$VALUE}</strong>
1601
+ ## with preprocessing
1602
+ value = <strong>${{$VALUE}}</strong>
1603
+ </pre><a name="test_preprocessing/pp-example1.rb"></a>
933
1604
 
934
- &lt;/body&gt;
935
- &lt;/html&gt;
936
- </pre>
937
- <br>
938
-
939
-
940
- <a name="des-args"></a>
941
- <h3 class="section2">Template Arguments</h3>
942
- <p>It is able to specify template arguments in template files.
943
- Template arguments are variables which are passed by main program via context object.
944
- In the following example, '<code>title</code>' and '<code>name</code>' are template arguments.
945
- </p>
946
- <a name="example10.rbhtml"></a>
947
- <div class="program_caption">
948
- File 'example10.rbhtml':</div>
949
- <pre class="program">&lt;?xml version="1.0"?&gt;
950
- <strong>&lt;?rb #@ARGS title, name ?&gt;</strong>
951
- &lt;h1&gt;${title}&lt;/h1&gt;
952
- &lt;p&gt;Hello ${name}!&lt;/p&gt;
953
- </pre>
954
- <p>Template arguments line is converted into assignment statements of local variables.
955
- </p>
956
- <a name="example10_template_args.result"></a>
957
- <pre class="terminal">$ rbtenjin -s example10.rbhtml
958
- _buf = ''; _buf &lt;&lt; %Q`&lt;?xml version="1.0"?&gt;\n`
959
- <strong> title = @title; name = @name;</strong>
960
- _buf &lt;&lt; %Q`&lt;h1&gt;#{escape((title).to_s)}&lt;/h1&gt;
961
- &lt;p&gt;Hello #{escape((name).to_s)}!&lt;/p&gt;\n`
1605
+ <div class="program_caption">
1606
+ pp-example1.rb
1607
+ </div>
1608
+ <pre class="program">
1609
+ $VALUE = 'My Great Example'
1610
+
1611
+ ## create engine object with preprocessing enabled
1612
+ require 'tenjin'
1613
+ engine = Tenjin::Engine.new(:path=&gt;['views'], <strong>:preprocess=&gt;true</strong>)
1614
+
1615
+ ## print Python script code
1616
+ puts "------ converted script ------"
1617
+ puts engine.get_template('pp-example1.rbhtml').script
1618
+
1619
+ ## render html
1620
+ html = engine.render('pp-example1.rbhtml', {})
1621
+ puts "------ rendered html ------"
1622
+ puts html
1623
+ </pre><a name="test_preprocessing/result1a.output"></a>
1624
+
1625
+ <div class="terminal_caption">
1626
+ Result: notice that <code>${{...}}</code> is evaluated at template converting stage.
1627
+ </div>
1628
+ <pre class="terminal">
1629
+ $ ruby pp-example1.rb
1630
+ ------ converted script ------
1631
+ _buf &lt;&lt; %Q`## normal expression
1632
+ value = <strong>#{escape(($VALUE).to_s)}</strong>
1633
+ ## with preprocessing
1634
+ value = <strong>My Great Example</strong>\n`
1635
+ ------ rendered html ------
1636
+ ## normal expression
1637
+ value = My Great Example
1638
+ ## with preprocessing
1639
+ value = My Great Example
1640
+ </pre>
1641
+
1642
+ <p>You can confirm preprocessed template by '<code>rbtenjin -P</code>' command.</p><a name="test_preprocessing/result1b.output"></a>
1643
+
1644
+ <div class="terminal_caption">
1645
+ Preprocessed template
1646
+ </div>
1647
+ <pre class="terminal">
1648
+ $ rbtenjin <strong>-P</strong> -c '$VALUE="My Great Example"' views/pp-example1.rbhtml
1649
+ ## normal expression
1650
+ value = ${$VALUE}
1651
+ ## with preprocessing
1652
+ value = My Great Example
1653
+ </pre>
1654
+
1655
+ <p>If you want to see preprocessing script (not preprocessed script), use '<code>rbtenjin -sP</code>' command.</p><a name="test_preprocessing/result1c.output"></a>
1656
+ <pre class="terminal">
1657
+ $ rbtenjin <strong>-sP</strong> -c '$VALUE="My Great Example"' views/pp-example1.rbhtml
1658
+ _buf = ''; _buf &lt;&lt; %Q`\#\# normal expression
1659
+ value = ${$VALUE}
1660
+ \#\# with preprocessing
1661
+ value = #{escape((_decode_params(($VALUE))).to_s)}\n`
962
1662
  _buf.to_s
963
- </pre>
964
- <p>If template arguments are specified, other variables passed by context object are not set.
965
- </p>
966
- <a name="example11.rbhtml"></a>
967
- <div class="program_caption">
968
- File 'example11.rbhtml':</div>
969
- <pre class="program">&lt;p&gt;
970
- <strong>&lt;?rb #@ARGS x ?&gt;</strong>
971
- x = #{x}
972
- y = #{y} # NameError
973
- &lt;/p&gt;
974
- </pre>
975
- <a name="example11_template_args_result"></a>
976
- <div class="terminal_caption">
977
- Result:</div>
978
- <pre class="terminal">$ rbtenjin <strong>-c '@x=10;@y=20'</strong> example11.rbhtml
979
- example12.rbhtml:4:in `_render': undefined local variable or method `y' (NameError)
980
- </pre>
981
- <br>
982
-
983
-
984
- <a name="des-preprocess"></a>
985
- <h3 class="section2">Preprocessing</h3>
986
- <p>rbTenjin supports preprocessing of template.
987
- Preprocessing executes some logics when templates are loaded and that logics are not executed when rendering.
988
- Preprocessing makes your application much faster.
989
- </p>
990
- <p>Notation of preprocessing is the following.
991
- </p>
992
- <ul type="disc">
993
- <li><code>&lt;?RB ... ?&gt;</code> represents preprocessing statement.
994
- </li>
995
- <li><code>#{{...}}</code> represents preprocessing expression (without HTML escape).
996
- </li>
997
- <li><code>${{...}}</code> represents preprocessing expression (with HTML escape).
998
- </li>
999
- </ul>
1000
- <p>For example, assume the following template.
1001
- </p>
1002
- <a name="example12.rbhtml"></a>
1003
- <div class="program_caption">
1004
- File 'example12.rbhtml':</div>
1005
- <pre class="program"><strong>&lt;?RB states = { "CA" =&gt; "California", ?&gt;</strong>
1663
+ </pre><br>
1664
+ <a name="preprocessing-loop-expantion" id="preprocessing-loop-expantion"></a>
1665
+
1666
+ <h4 class="section3">Loop Expantion</h4>
1667
+
1668
+ <p>It is possible to evaluate some logics by '<code>&lt;?RB ... ?&gt;</code>' when convert template into Ruby script code. For example, you can expand loop in advance to improve performance.</p><a name="test_preprocessing/views/pp-example2.rbhtml"></a>
1669
+
1670
+ <div class="program_caption">
1671
+ views/pp-example2.rbhtml
1672
+ </div>
1673
+ <pre class="program">
1674
+ <strong>&lt;?RB states = { "CA" =&gt; "California", ?&gt;</strong>
1006
1675
  <strong>&lt;?RB "NY" =&gt; "New York", ?&gt;</strong>
1007
1676
  <strong>&lt;?RB "FL" =&gt; "Florida", ?&gt;</strong>
1008
1677
  <strong>&lt;?RB "TX" =&gt; "Texas", ?&gt;</strong>
1009
1678
  <strong>&lt;?RB "HI" =&gt; "Hawaii", } ?&gt;</strong>
1010
- &lt;?rb chk = { @params['state'] =&gt; ' selected="selected"' } ?&gt;
1679
+ &lt;?rb chk = { params['state'] =&gt; ' selected="selected"' } ?&gt;
1011
1680
  &lt;select name="state"&gt;
1012
1681
  &lt;option value=""&gt;-&lt;/option&gt;
1013
- <strong>&lt;?RB for code in states.keys.sort ?&gt;</strong>
1014
- &lt;option value="<strong>#{{code}}</strong>"#{chk[<strong>#{{code.inspect}}</strong>]}&gt;<strong>${{states[code]}}</strong>&lt;/option&gt;
1015
- <strong>&lt;?RB end ?&gt;</strong>
1682
+ <strong>&lt;?RB for code in states.keys.sort ?&gt;</strong>
1683
+ &lt;option value="<strong>#{{code}}</strong>"#{chk['<strong>#{{code}}</strong>']}&gt;<strong>${{states[code]}}</strong>&lt;/option&gt;
1684
+ <strong>&lt;?RB end ?&gt;</strong>
1016
1685
  &lt;/select&gt;
1017
1686
  </pre>
1018
- <p>If preprocessing is activated, the above will be converted into the following when template is loaded.
1019
- (Command-line option <code>-P</code> shows the result of preprocessing.)
1020
- </p>
1021
- <a name="example12_preprocessed.result"></a>
1022
- <div class="terminal_caption">
1023
- Result of preprocessing:</div>
1024
- <pre class="terminal">$ rbtenjin <strong>-P</strong> example12.rbhtml
1025
- &lt;?rb chk = { @params['state'] =&gt; ' selected="selected"' } ?&gt;
1687
+
1688
+ <p>Preprocessed script code shows that loop is expanded in advance. It means that loop is not executed when rendering template.</p><a name="test_preprocessing/result2a.output"></a>
1689
+
1690
+ <div class="terminal_caption">
1691
+ Preprocessed template
1692
+ </div>
1693
+ <pre class="terminal">
1694
+ $ rbtenjin -P views/pp-example2.rbhtml
1695
+ &lt;?rb chk = { params['state'] =&gt; ' selected="selected"' } ?&gt;
1026
1696
  &lt;select name="state"&gt;
1027
1697
  &lt;option value=""&gt;-&lt;/option&gt;
1028
- &lt;option value="CA"#{chk["CA"]}&gt;California&lt;/option&gt;
1029
- &lt;option value="FL"#{chk["FL"]}&gt;Florida&lt;/option&gt;
1030
- &lt;option value="HI"#{chk["HI"]}&gt;Hawaii&lt;/option&gt;
1031
- &lt;option value="NY"#{chk["NY"]}&gt;New York&lt;/option&gt;
1032
- &lt;option value="TX"#{chk["TX"]}&gt;Texas&lt;/option&gt;
1698
+ &lt;option value="CA"#{chk['CA']}&gt;California&lt;/option&gt;
1699
+ &lt;option value="FL"#{chk['FL']}&gt;Florida&lt;/option&gt;
1700
+ &lt;option value="HI"#{chk['HI']}&gt;Hawaii&lt;/option&gt;
1701
+ &lt;option value="NY"#{chk['NY']}&gt;New York&lt;/option&gt;
1702
+ &lt;option value="TX"#{chk['TX']}&gt;Texas&lt;/option&gt;
1033
1703
  &lt;/select&gt;
1704
+ </pre><br>
1705
+ <a name="preprocessing-parameters" id="preprocessing-parameters"></a>
1706
+
1707
+ <h4 class="section3">Parameters</h4>
1708
+
1709
+ <p>Assume that link_to() is a helper method which takes label and url and generate &lt;a&gt;&lt;/a&gt; tag. In this case, label and url can be parameterized by <code>_p("...")</code> and <code>_P("...")</code>. The former is converted into #{...} and the latter converted into ${...} by preprocessor.</p><a name="test_preprocessing/views/pp-example3.rbhtml"></a>
1710
+
1711
+ <div class="program_caption">
1712
+ views/pp-example3.rbhtml
1713
+ </div>
1714
+ <pre class="program">
1715
+ <strong>&lt;?RB</strong>
1716
+ ## ex. link_to('Show', '/show/1') =&gt; &lt;a href="/show/1"&gt;Show&lt;/a&gt;
1717
+ def link_to(label, url)
1718
+ return "&lt;a href=\"#{url}\"&gt;#{label}&lt;/a&gt;"
1719
+ end
1720
+ <strong>?&gt;</strong>
1721
+ <strong>#{{</strong>link_to('Show '+<strong>_P(</strong>'params["name"]'<strong>)</strong>, '/items/show/'+<strong>_p(</strong>'params["id"]'<strong>)</strong>)<strong>}}</strong>
1034
1722
  </pre>
1035
- <p>This means that for-loop is executed only once when template is loaded and is not executed when rendering.
1036
- In the result, rendering speed becomes to be much faster.
1037
- </p>
1038
- <p>And the Ruby code is here. This shows that there is no for-loop.
1039
- </p>
1040
- <a name="example12_preprocessed_source.result"></a>
1041
- <div class="terminal_caption">
1042
- Translated script code:</div>
1043
- <pre class="terminal">$ rbtenjin <strong>--preprocess</strong> -sb example12.rbhtml
1044
- chk = { @params['state'] =&gt; ' selected="selected"' }
1045
- _buf &lt;&lt; %Q`&lt;select name="state"&gt;
1046
- &lt;option value=""&gt;-&lt;/option&gt;
1047
- &lt;option value="CA"#{chk["CA"]}&gt;California&lt;/option&gt;
1048
- &lt;option value="FL"#{chk["FL"]}&gt;Florida&lt;/option&gt;
1049
- &lt;option value="HI"#{chk["HI"]}&gt;Hawaii&lt;/option&gt;
1050
- &lt;option value="NY"#{chk["NY"]}&gt;New York&lt;/option&gt;
1051
- &lt;option value="TX"#{chk["TX"]}&gt;Texas&lt;/option&gt;
1052
- &lt;/select&gt;\n`
1053
- </pre>
1054
- <p>If you have errors on preprocessing, you should check source script by <code>-Ps</code> option<sup>(<a href="#fnref:1" name="fnlink:1">*1</a>)</sup>.
1055
- </p>
1056
- <p>The following is an another example.
1057
- Assume that <code>link_to()</code> is a helper method which takes label and url and generate
1058
- <code>&lt;a&gt;&lt;/a&gt;</code> tag.
1059
- In this case, label and url can be parameterized by <code>_p("...")</code> and <code>_P("...")</code>.
1060
- The former is converted into <code>#{...}</code> and the latter converted into <code>${...}</code>
1061
- by preprocessor.
1062
- </p>
1063
- <a name="example13.rbhtml"></a>
1064
- <div class="program_caption">
1065
- File 'example13.rbhtml':</div>
1066
- <pre class="program">&lt;?RB require 'cgi' ?&gt;
1067
- &lt;?RB ## ex. link_to('Show', '/show/1') =&gt; &lt;a href="/show/1"&gt;Show&lt;/a&gt; ?&gt;
1068
- &lt;?RB def link_to(label, url) ?&gt;
1069
- &lt;?RB return "&lt;a href=\"#{CGI.unescape(url)}\"&gt;#{label}&lt;/a&gt;" ?&gt;
1070
- &lt;?RB end ?&gt;
1071
- #{{link_to 'Show '+<strong>_P('@params["name"]')</strong>, '/items/show/'+<strong>_p('@params["id"]')</strong>}}
1072
- </pre>
1073
- <a name="example13_preprocessed.result"></a>
1074
- <div class="terminal_caption">
1075
- Preprocessed template:</div>
1076
- <pre class="terminal">$ rbtenjin <strong>-P</strong> example13.rbhtml
1077
- &lt;a href="/items/show/<strong>#{@params["id"]}"</strong>&gt;Show <strong>${@params["name"]}</strong>&lt;/a&gt;
1078
- </pre>
1079
- <a name="example13_preprocessed_source.result"></a>
1080
- <div class="terminal_caption">
1081
- Translated script code:</div>
1082
- <pre class="terminal">$ rbtenjin <strong>--preprocess</strong> -sb example13.rbhtml
1083
- _buf &lt;&lt; %Q`&lt;a href="/items/show/<strong>#{@params["id"]}</strong>"&gt;Show <strong>#{escape((@params["name"]).to_s)}</strong>&lt;/a&gt;\n`
1084
- </pre>
1085
- <p>There are many web-application framework and they provides helper functions.
1086
- These helper functions are divided into two groups.
1087
- </p>
1088
- <ul type="disc">
1089
- <li><code>link_to()</code> or <code>_()</code> (function for M17N) return the same result
1090
- when the same arguments are passed.
1091
- These functions can be expanded by preprocessor.
1092
- </li>
1093
- <li>Some functions return the different result even if the same arguments are passed.
1094
- These functions can't be expaned by preprocessor.
1095
- </li>
1096
- </ul>
1097
- <p>Preprocessor has the power to make your application much faster,
1098
- but it may make the debugging difficult.
1099
- You should use it carefully.
1100
- </p>
1101
- <div class="footnote">
1102
- <dl compact>
1103
- <dt>(<a name="fnref:1" href="#fnlink:1">*1</a>)</dt>
1104
- <dd>Command-line option '-Ps' is available but '-PS' is not availabe. This is a current restriction of rbtenjin. </dd>
1105
- </dl>
1106
- </div>
1107
- <br>
1108
-
1109
-
1110
- <a name="des-otheropts"></a>
1111
- <h3 class="section2">Other Options</h3>
1112
- <ul type="disc">
1113
- <li>Command-line option '<code>--escapefunc=func1</code>' changes <code>escape()</code> function name to <code>func1</code>.
1114
- For example, '<code>--escapefunc=h</code>' changes escape function from <code>escape()</code> to <code>h()</code>.
1115
- </li>
1116
- <li>It is not able to contain '<code>}</code>' character in '<code>${...}</code>'.
1117
- For example, '<code>${hash["}"]}</code>' will be converted into '<code>_buf &lt;&lt; %Q`#{escape((hash[").to_s)}"]}</code>` and not '<code>_buf &lt;&lt; %Q`#{escape((hash["}"]).to_s)}`</code>'.
1118
- There is no such restriction about '<code>#{...}</code>'.
1119
- </li>
1120
- <li>It is not able to contain '<code>\</code>' and '<code>`</code>' characters in '<code>#{...}</code>'
1121
- because these characters are escaped.
1122
- For example, '<code>#{hash["\n"]}</code>' will be converted into '<code>_buf &lt;&lt; %Q`hash["\n"]`</code>'.
1123
- There is no such restriction about '<code>${...}</code>'.
1124
- </li>
1125
- <li>Command-line option '<code>--path=dir1,dir2,...</code>' sepcifies template directory path.
1126
- </li>
1127
- </ul>
1128
- <br>
1129
-
1130
-
1131
- <br>
1132
-
1133
-
1134
- <a name="devguide"></a>
1135
- <h2 class="section1">Developer's Guide</h2>
1136
- <p>This section shows how to use rbTenjin in your Ruby script.
1137
- </p>
1138
- <p>If you want to know the notation or features of rbTenjin, see <a href="#desguide">Designer's Guide</a> section.
1139
- </p>
1140
- <a name="dev-example"></a>
1141
- <h3 class="section2">An Example</h3>
1142
- <p>The following is an example to use rbTenjin in Ruby.
1143
- </p>
1144
- <div class="program_caption">
1145
- Example:</div>
1146
- <pre class="program">require 'tenjin'
1147
- engine = Tenjin::Engine.new()
1148
- context = { :title=&gt;'rbTenjin Example', :items=&gt;['AAA', 'BBB', 'CCC'] }
1149
- filename = 'file.rbhtml'
1150
- output = engine.render(filename, context)
1151
- print output
1152
- </pre>
1153
- <p>If you want to define helper functions for template, see <a href="#dev-helpers">Add Your Helper Functions</a> section.
1154
- </p>
1155
- <br>
1156
-
1157
-
1158
- <a name="dev-classes"></a>
1159
- <h3 class="section2">Classes and Functions in rbTenjin</h3>
1160
- <p>rbTenjin has the follwoing classes.
1161
- </p>
1162
- <dl class="dl3">
1163
- <dt class="dt3"><b>
1164
- Tenjin::Template </b></dt>
1165
- <dd class="dd3">
1166
- This class represents a template file.
1167
- An object of Tenjin::Template correspond to a template file.
1168
- </dd>
1169
- </dl>
1170
- <dl class="dl3">
1171
- <dt class="dt3"><b>
1172
- Tenjin::Engine </b></dt>
1173
- <dd class="dd3">
1174
- This class represents some template objects.
1175
- It can handle nested template and layout template.
1176
- Using Tenjin::Engine class, you can use rbTenjin as a template engine for web application.
1177
- </dd>
1178
- </dl>
1179
- <dl class="dl3">
1180
- <dt class="dt3"><b>
1181
- Tenjin::Context </b></dt>
1182
- <dd class="dd3">
1183
- This class represents context data.
1184
- </dd>
1185
- </dl>
1186
- <p>rbTenjin has the following utility functions.
1187
- These are defined at Tenjin::HtmlHelper module and Tenjin::Context class includes it.
1188
- </p>
1189
- <br>
1190
-
1191
-
1192
- <a name="dev-templateclass"></a>
1193
- <h3 class="section2">Class Tenjin::Template</h3>
1194
- <p>Tenjin::Template class represents a template file.
1195
- An object of Tenjin::Template corresponds to a template file.
1196
- It doesn't support nested template nor layout template (use Tenjin::Engine class instead).
1197
- </p>
1198
- <p>This class has the following methods and attributes.
1199
- </p>
1200
- <dl class="dl3">
1201
- <dt class="dt3"><b>
1202
- Tenjin::Template.new(filename=nil, :escapefunc=&gt;'escape') </b></dt>
1203
- <dd class="dd3">
1204
- Create template object. If filename is given, read and convert it to Ruby code.
1205
- </dd>
1206
- </dl>
1207
- <dl class="dl3">
1208
- <dt class="dt3"><b>
1209
- Tenjin::Template#convert(input, filename=None) </b></dt>
1210
- <dd class="dd3">
1211
- Convert input text into Ruby code and return it.
1212
- </dd>
1213
- </dl>
1214
- <dl class="dl3">
1215
- <dt class="dt3"><b>
1216
- Tenjin::Template#convert_file(filename) </b></dt>
1217
- <dd class="dd3">
1218
- Convert file into Ruby code and return it.
1219
- This is equivarent to <code>Tenjin::Template#convert(File.read(filename), filename)</code>
1220
- </dd>
1221
- </dl>
1222
- <dl class="dl3">
1223
- <dt class="dt3"><b>
1224
- Tenjin::Template#render(context=nil) </b></dt>
1225
- <dd class="dd3">
1226
- Compile Ruby code, evaluate it with context data, and return the result of evaluation.
1227
- </dd>
1228
- </dl>
1229
- <dl class="dl3">
1230
- <dt class="dt3"><b>
1231
- Tenjin::Template#script </b></dt>
1232
- <dd class="dd3">
1233
- Converted Ruby code
1234
- </dd>
1235
- </dl>
1236
- <p>The followings are examples to use Tenjin::Template in Ruby script.
1237
- </p>
1238
- <a name="example14.rbhtml"></a>
1239
- <div class="program_caption">
1240
- File 'example14.rbhtml':</div>
1241
- <pre class="program">&lt;h1&gt;#{@title}&lt;/h1&gt;
1242
- &lt;ul&gt;
1243
- &lt;?rb for item in @items ?&gt;
1244
- &lt;li&gt;${item}&lt;/li&gt;
1245
- &lt;?rb end ?&gt;
1246
- &lt;/ul&gt;
1723
+
1724
+ <p>The following shows that <code>_P('...')</code> and <code>_p('...')</code> are converted into <code>${...}</code> and <code>#{...}</code> respectively.</p><a name="test_preprocessing/result3a.output"></a>
1725
+
1726
+ <div class="terminal_caption">
1727
+ Preprocessed template:
1728
+ </div>
1729
+ <pre class="terminal">
1730
+ $ rbtenjin -P views/pp-example3.rbhtml
1731
+ &lt;a href="/items/show/<strong>#{</strong>params["id"]<strong>}</strong>"&gt;Show <strong>${</strong>params["name"]<strong>}</strong>&lt;/a&gt;
1247
1732
  </pre>
1248
- <a name="example14.rb"></a>
1249
- <div class="program_caption">
1250
- File 'example14.rb':</div>
1251
- <pre class="program">## template file
1252
- filename = 'example14.rbhtml'
1253
1733
 
1254
- ## convert into ruby code
1734
+ <p>There are many web-application framework and they provides helper functions. These helper functions are divided into two groups. link_to() or _() (function for M17N) return the same result when the same arguments are passed. These functions can be expanded by preprocessor. Some functions return the different result even if the same arguments are passed. These functions can't be expaned by preprocessor.</p>
1735
+
1736
+ <p>Preprocessor has the power to make view-layer much faster, but it may make the debugging difficult. You should use it carefully.</p><br>
1737
+ <br>
1738
+ <a name="m17n" id="m17n"></a>
1739
+
1740
+ <h3 class="section2">M17N Page</h3>
1741
+
1742
+ <p>If you have M17N site, you can make your site faster by Tenjin.</p>
1743
+
1744
+ <p>In M17N-ed site, message translation function (such as <code>_('message-key')</code>) is called many times. Therefore if you can eliminate calling that function, your site can be faster. And Tenjin can do it by preprocessing.</p>
1745
+
1746
+ <p>The points are:</p>
1747
+
1748
+ <ul type="disc">
1749
+ <li>Change cache filename according to language. For example, create cache file 'file.rbhtml.en.cache', 'file.rbhtml.fr.cache', 'file.rbhtml.it.cache', and so on from a template file 'file.rbhtml'. This is done by Tenjin automatically if you pass '<code>:lang=&gt;"en"</code>' or '<code>lang="fr"</code>' option to Engine class.</li>
1750
+
1751
+ <li>Create Engine object for each language and pass <code>:lang</code> option respectively.</li>
1752
+
1753
+ <li>Enable preprocessing to create different cache content for each language.</li>
1754
+ </ul>
1755
+
1756
+ <p>The following is an example to generate M17N pages from a template file.</p><a name="test_m17n/m17n.rbhtml"></a>
1757
+
1758
+ <div class="program_caption">
1759
+ m17n.rbhtml:
1760
+ </div>
1761
+ <pre class="program">
1762
+ &lt;div&gt;
1763
+ &lt;?RB ## '_()' represents translator method ?&gt;
1764
+ &lt;?RB _ = @_ ?&gt;
1765
+ &lt;p&gt;<strong>${{_['Hello']}}</strong> ${@username}!&lt;/p&gt;
1766
+ &lt;/div&gt;
1767
+ </pre><a name="test_m17n/m17n.rb"></a>
1768
+
1769
+ <div class="program_caption">
1770
+ m17n.rb:
1771
+ </div>
1772
+ <pre class="program">
1773
+ # -*- coding: utf-8 -*-
1255
1774
  require 'tenjin'
1256
- template = <strong>Tenjin::Template.new(filename)</strong>
1257
- ## or
1258
- # template = Tenjin::Template.new()
1259
- # script = <strong>template.convert_file(filename)</strong>
1260
- ## or
1261
- # template = Tenjin::Template.new()
1262
- # input = File.read(filename)
1263
- # script = <strong>template.convert(input, filename)</strong> # filename is optional
1264
-
1265
- ## show converted ruby code
1266
- puts "---- ruby code ----"
1267
- puts <strong>template.script</strong>
1268
-
1269
- ## evaluate ruby code
1270
- hash = {:title=&gt;'rbTenjin Example', :items=&gt;['&lt;AAA&gt;','B&amp;B','"CCC"']}
1271
- output = <strong>template.render(hash)</strong>
1272
- puts "---- output ----"
1273
- puts output
1274
- ## or
1275
- #hash = {:title=&gt;'rbTenjin Example', :items=&gt;['&lt;AAA&gt;','B&amp;B','"CCC"']}
1276
- #context = <strong>Tenjin::Context.new(hash)</strong>
1277
- #output = <strong>template.render(context)</strong>
1278
- ## or
1279
- # context = Tenjin::Context.new
1280
- # context[:title] = 'rbTenjin Example'
1281
- # context[:items] = ['&lt;AAA&gt;','B&amp;B','"CCC"']
1282
- # output = template.render(context)
1283
- </pre>
1284
- <a name="example14_tmplclass.result"></a>
1285
- <div class="terminal_caption">
1286
- Result:</div>
1287
- <pre class="terminal">$ ruby example14.rb
1288
- ---- ruby code ----
1289
- _buf &lt;&lt; %Q`&lt;h1&gt;#{@title}&lt;/h1&gt;
1290
- &lt;ul&gt;\n`
1291
- for item in @items
1292
- _buf &lt;&lt; %Q` &lt;li&gt;#{escape((item).to_s)}&lt;/li&gt;\n`
1775
+
1776
+ ##
1777
+ ## message catalog to translate message
1778
+ ##
1779
+ MESSAGE_CATALOG = {
1780
+ 'en' =&gt; { 'Hello'=&gt;"Hello", 'Good bye'=&gt;"Good bye" },
1781
+ 'fr' =&gt; { 'Hello'=&gt;"Bonjour", 'Good bye'=&gt;"Au revoir" },
1782
+ }
1783
+
1784
+ ##
1785
+ ## create translation function and return it.
1786
+ ## ex.
1787
+ ## _ = create_m17n_obj('fr')
1788
+ ## print _['Hello'] #=&gt; 'Bonjour'
1789
+ ##
1790
+ def create_m17n_obj(lang)
1791
+ hash = MESSAGE_CATALOG[lang] or
1792
+ raise Error.new("#{lang}: unknown lang.")
1793
+ _ = proc {|message_key| hash[message_key] }
1794
+ return _
1293
1795
  end
1294
- _buf &lt;&lt; %Q`&lt;/ul&gt;\n`
1295
- ---- output ----
1296
- &lt;h1&gt;rbTenjin Example&lt;/h1&gt;
1297
- &lt;ul&gt;
1298
- &lt;li&gt;&amp;lt;AAA&amp;gt;&lt;/li&gt;
1299
- &lt;li&gt;B&amp;amp;B&lt;/li&gt;
1300
- &lt;li&gt;&amp;quot;CCC&amp;quot;&lt;/li&gt;
1301
- &lt;/ul&gt;
1302
- </pre>
1303
- <br>
1304
-
1305
-
1306
- <a name="dev-engineclass"></a>
1307
- <h3 class="section2">Class Tenjin::Engine</h3>
1308
- <p>Tenjin::Engine class contains some template objects.
1309
- It can handle nested template and layout template.
1310
- Using Tenjin::Engine class, you can use rbTenjin as a template engine for web application.
1311
- </p>
1312
- <p>This class has the following methods.
1313
- </p>
1314
- <dl class="dl3">
1315
- <dt class="dt3"><b>
1316
- Tenjin::Engine.new(:prefix=&gt;'', :postfix=&gt;'', :layout=&gt;nil, :path=nil, :cache=&gt;true, :preprocess=&gt;false, :templateclass=&gt;Tenjin::Template) </b></dt>
1317
- <dd class="dd3">
1318
- Create Engine object.
1319
- <code>:path</code> represents template search path and it should be an Array of directory name.
1320
- Other arguments are passed to Tenjin::Template.new() internally.
1321
- </dd>
1322
- </dl>
1323
- <dl class="dl3">
1324
- <dt class="dt3"><b>
1325
- Tenjin::Engine#render(template_name, context=nil, layout=nil) </b></dt>
1326
- <dd class="dd3">
1327
- Convert template into Ruby code, evaluate it with context data, and return the result of it.
1328
- If <code>layout</code> is true or nil then layout template name specified by constructor option is
1329
- used as layout template, else if false then layout template is not used,
1330
- else if string then it is regarded as layout template name.
1331
- </dd>
1332
- </dl>
1333
- <p>Argument <code>template_name</code> in render() methods is filename or short name of template.
1334
- Template short name is a Symbol.
1335
- For example, '<code>render(:list, context)</code>' is equivarent to '<code>render("user_list.rbhtml", context)</code>' if prefix option is '<code>user_</code>' and postfix option is '<code>.rbhtml</code>'.
1336
- </p>
1337
- <p>In template file, the followings are available.
1338
- </p>
1339
- <dl class="dl3">
1340
- <dt class="dt3"><b>
1341
- @_content </b></dt>
1342
- <dd class="dd3">
1343
- This variable represents the result of evaluation of other template.
1344
- This is available only in layout template file.
1345
- </dd>
1346
- </dl>
1347
- <dl class="dl3">
1348
- <dt class="dt3"><b>
1349
- import(template_name) </b></dt>
1350
- <dd class="dd3">
1351
- Include and evaluate other template.
1352
- This method is an instance method of Tenjin::Context class.
1353
- </dd>
1354
- </dl>
1355
- <dl class="dl3">
1356
- <dt class="dt3"><b>
1357
- start_capture(name) </b></dt>
1358
- <dd class="dd3">
1359
- Start capturing. Result will be stored into <code>@<em>name</em></code>.
1360
- </dd>
1361
- </dl>
1362
- <dl class="dl3">
1363
- <dt class="dt3"><b>
1364
- stop_capture() </b></dt>
1365
- <dd class="dd3">
1366
- Stop capturing.
1367
- </dd>
1368
- </dl>
1369
- <dl class="dl3">
1370
- <dt class="dt3"><b>
1371
- captured_as(varname) </b></dt>
1372
- <dd class="dd3">
1373
- If captured string as <em>varname</em> is exist then append it into
1374
- <code>@_buf</code> and return true, else return false.
1375
- This is a helper function for layout template.
1376
- </dd>
1377
- </dl>
1378
- <p>The followings are example of Tenjin::Engine class.
1379
- </p>
1380
- <a name="user_form.rbhtml"></a>
1381
- <div class="program_caption">
1382
- File 'user_form.rbhtml':</div>
1383
- <pre class="program">&lt;?rb #@ARGS params ?&gt;
1796
+
1797
+ ##
1798
+ ## test program
1799
+ ##
1800
+ if __FILE__ == $0
1801
+ ## render html for English
1802
+ engine_en = Tenjin::Engine.new(:preprocess=&gt;true, <strong>:lang=&gt;'en'</strong>)
1803
+ context = { :username =&gt; 'World' }
1804
+ <strong>context[:_] = create_m17n_obj('en')</strong>
1805
+ html = engine_en.render('m17n.rbhtml', context)
1806
+ puts "--- lang: en ---"
1807
+ puts html
1808
+
1809
+ ## render html for French
1810
+ engine_fr = Tenjin::Engine.new(:preprocess=&gt;true, <strong>:lang=&gt;'fr'</strong>)
1811
+ context = { :username =&gt; 'World' }
1812
+ <strong>context[:_] = create_m17n_obj('fr')</strong>
1813
+ html = engine_fr.render('m17n.rbhtml', context)
1814
+ puts "--- lang: fr ---"
1815
+ puts html
1816
+ end
1817
+ </pre><a name="test_m17n/result.output"></a>
1818
+
1819
+ <div class="terminal_caption">
1820
+ Result:
1821
+ </div>
1822
+ <pre class="terminal">
1823
+ $ ruby m17n.rb
1824
+ --- lang: en ---
1825
+ &lt;div&gt;
1826
+ &lt;p&gt;<strong>Hello</strong> World!&lt;/p&gt;
1827
+ &lt;/div&gt;
1828
+ --- lang: fr ---
1829
+ &lt;div&gt;
1830
+ &lt;p&gt;<strong>Bonjour</strong> World!&lt;/p&gt;
1831
+ &lt;/div&gt;
1832
+ </pre>
1833
+
1834
+ <p>After that, you can find two cache files are created.</p>
1835
+ <pre class="terminal">
1836
+ $ ls m17n.rbhtml*
1837
+ m17n.rbhtml m17n.rbhtml.<strong>en</strong>.cache m17n.rbhtml.<strong>fr</strong>.cache
1838
+ </pre>
1839
+
1840
+ <p>And each cache files have different content.</p><a name="test_m17n/result_en.output"></a>
1841
+
1842
+ <div class="terminal_caption">
1843
+ <code>_('Hello')</code> is translated into "Hello" in Engilish cache file
1844
+ </div>
1845
+ <pre class="terminal">
1846
+ $ cat m17n.rbhtml.en.cache
1847
+ _buf &lt;&lt; %Q`&lt;div&gt;
1848
+ &lt;p&gt;<strong>Hello</strong> #{escape((@username).to_s)}!&lt;/p&gt;
1849
+ &lt;/div&gt;\n`
1850
+ </pre><a name="test_m17n/result_fr.output"></a>
1851
+
1852
+ <div class="terminal_caption">
1853
+ <code>_('Hello')</code> is translated into "Bonjour" in French cache file
1854
+ </div>
1855
+ <pre class="terminal">
1856
+ $ cat m17n.rbhtml.fr.cache
1857
+ _buf &lt;&lt; %Q`&lt;div&gt;
1858
+ &lt;p&gt;<strong>Bonjour</strong> #{escape((@username).to_s)}!&lt;/p&gt;
1859
+ &lt;/div&gt;\n`
1860
+ </pre><br>
1861
+ <a name="cgi-script" id="cgi-script"></a>
1862
+
1863
+ <h3 class="section2">Make Tenjin as PHP-like Tool</h3>
1864
+
1865
+ <p>Tenjin provides 'rbtenjin.cgi' CGI script which makes Tenjin as PHP-like tool.</p>
1866
+
1867
+ <div class="terminal_caption">
1868
+ Setup
1869
+ </div>
1870
+ <pre class="terminal">
1871
+ $ htdocs=/usr/local/apache2/htdocs # or $HOME/public_html
1872
+ $ tar xzf rbtenjin-X.X.X.tar.gz
1873
+ $ cd rbtenjin-X.X.X/
1874
+ $ cp lib/tenjin.rb $htdocs
1875
+ $ cp public_html/rbtenjin.cgi $htdocs
1876
+ $ cp public_html/.htaccess $htdocs
1877
+ $ cd public_html/*.rbhtml $htdocs
1878
+ $ chmod a+x $htdocs/rbtenjin.cgi
1879
+ </pre>
1880
+
1881
+ <p>After that, access to http://localhost/ (or http://localhost/~yourname/) and you'll see example page.</p><br>
1882
+ <br>
1883
+ <a name="tips" id="tips"></a>
1884
+
1885
+ <h2 class="section1">Tips</h2><a name="function-names" id="function-names"></a>
1886
+
1887
+ <h3 class="section2">Specify Function Names of escape() and to_str()</h3>
1888
+
1889
+ <p>It is able to specify function names of html escape.</p><a name="test_escape/main.rb"></a>
1890
+
1891
+ <div class="program_caption">
1892
+ main.rb
1893
+ </div>
1894
+ <pre class="program">
1895
+ require 'tenjin'
1896
+ require 'erb'
1897
+ engine = Tenjin::Engine.new(:path=&gt;['views'], <strong>:escapefunc=&gt;'ERB::Util.h'</strong>)
1898
+ puts engine.get_template('page.rbhtml').script
1899
+ </pre><a name="test_escape/views/page.rbhtml"></a>
1900
+
1901
+ <div class="program_caption">
1902
+ views/page.rbhtml
1903
+ </div>
1904
+ <pre class="program">
1384
1905
  &lt;p&gt;
1385
- Name: &lt;input type="text" name="name" value="${params['name']}" /&gt;&lt;br /&gt;
1386
- Email: &lt;input type="text" name="email" value="${params['email']}" /&gt;&lt;br /&gt;
1387
- Gender:
1388
- &lt;?rb gender = @params['gender'] ?&gt;
1389
- &lt;?rb chk = { true=&gt;' checked="checked"', false=&gt;'' } ?&gt;
1390
- &lt;input type="radio" name="gender" value="m" #{chk[gender=='m']} /&gt;Male
1391
- &lt;input type="radio" name="gender" value="f" #{chk[gender=='f']} /&gt;Female
1906
+ escaped: ${@value}
1907
+ not escaped: #{@value}
1392
1908
  &lt;/p&gt;
1909
+ </pre><a name="test_escape/result.output"></a>
1910
+
1911
+ <div class="program_caption">
1912
+ Result
1913
+ </div>
1914
+ <pre class="program">
1915
+ $ ruby main.rb
1916
+ _buf &lt;&lt; %Q`&lt;p&gt;
1917
+ escaped: #{<strong>ERB::Util.h</strong>((@value).to_s)}
1918
+ not escaped: #{@value}
1919
+ &lt;/p&gt;\n`
1920
+ </pre><br>
1921
+ <a name="tips-template-inheritance" id="tips-template-inheritance"></a>
1922
+
1923
+ <h3 class="section2">Template Inheritance</h3>
1924
+
1925
+ <p>Tenjin doesn't support Template Inheritance which Django template engine does. But you can emulate it by capturing<sup>(<a href="#fnref:1" name="fnlink:1" id="fnlink:1">*1</a>)</sup>. See <a href="#capturing">this section</a> for details.</p>
1926
+
1927
+ <div class="footnote">
1928
+ <dl compact>
1929
+ <dt>(<a name="fnref:1" href="#fnlink:1" id="fnref:1">*1</a>)</dt>
1930
+
1931
+ <dd>Notice that capturing is useful but not so powerful than template inheritance.</dd>
1932
+ </dl>
1933
+ </div><br>
1934
+ <br>
1935
+ <a name="command" id="command"></a>
1936
+
1937
+ <h2 class="section1"><code>rbtenjin</code> Command</h2>
1938
+
1939
+ <p>See '<code>rbtenjin -h</code>' for details.</p><a name="command-syntax-check" id="command-syntax-check"></a>
1940
+
1941
+ <h3 class="section2">Syntax Check</h3>
1942
+
1943
+ <p>Command-line option '<code>-z</code>' checks syntax of template files. In addition '<code>-w</code>' option sets warning level to 2. It is recommended to use '-w' when you specify '-z' option.</p><a name="test_syntax_check/example.rbhtml"></a>
1944
+
1945
+ <div class="program_caption">
1946
+ example.rbhtml
1947
+ </div>
1948
+ <pre class="program">
1949
+ &lt;ul&gt;
1950
+ &lt;?rb for item in items ?&gt;
1951
+ &lt;li&gt;${item}&lt;/li&gt;
1952
+ &lt;?rb <strong>ende</strong> ?&gt;
1953
+ &lt;/ul&gt;
1954
+ </pre><a name="test_syntax_check/result.output"></a>
1955
+
1956
+ <div class="terminal_caption">
1957
+ Result:
1958
+ </div>
1959
+ <pre class="terminal">
1960
+ $ rbtenjin <strong>-wz</strong> example.rbhtml
1961
+ example.rbhtml:5: syntax error, unexpected $end, expecting kEND
1393
1962
  </pre>
1394
- <a name="user_create.rbhtml"></a>
1395
- <div class="program_caption">
1396
- File 'user_create.rbhtml':</div>
1397
- <pre class="program">&lt;?rb #@ARGS ?&gt;
1398
- &lt;form action="user_app.cgi" method="post"&gt;
1399
- &lt;input type="hidden" name="action" value="create" /&gt;
1400
- <strong>&lt;?rb import :form ?&gt;</strong>
1401
- &lt;input type="submit" value="Create" /&gt;
1402
- &lt;/form&gt;
1403
- </pre>
1404
- <a name="user_edit.rbhtml"></a>
1405
- <div class="program_caption">
1406
- File 'user_edit.rbhtml':</div>
1407
- <pre class="program">&lt;?rb #@ARGS params ?&gt;
1408
- &lt;form action="user_app.cgi" method="post"&gt;
1409
- &lt;input type="hidden" name="action" value="edit" /&gt;
1410
- &lt;input type="hidden" name="id" value="${params['id']}" /&gt;
1411
- <strong>&lt;?rb import :form ?&gt;</strong>
1412
- &lt;input type="submit" value="Edit" /&gt;
1413
- &lt;/form&gt;
1414
- </pre>
1415
- <a name="user_layout.rbhtml"></a>
1416
- <div class="program_caption">
1417
- File 'user_layout.rbhtml':</div>
1418
- <pre class="program">&lt;?rb #@ARGS _content, title ?&gt;
1419
- &lt;html&gt;
1420
- &lt;body&gt;
1421
1963
 
1422
- &lt;h1&gt;${title}&lt;/h1&gt;
1964
+ <p>Command-line option '-wz' is more convenient than '<code>rbtenjin -s file | ruby -wc</code>' because the former can take several filenames.</p>
1423
1965
 
1424
- &lt;div id="main-content"&gt;
1425
- <strong>#{_content}</strong>
1426
- &lt;/div&gt;
1966
+ <p>Command-line option '-q' (quiet-mode) prints nothing if there are no syntax errors.</p><br>
1967
+ <a name="command-convert-script" id="command-convert-script"></a>
1427
1968
 
1428
- &lt;div id="footer"&gt;
1429
- <strong>&lt;?rb import 'footer.html' ?&gt;</strong>
1430
- &lt;/div&gt;
1969
+ <h3 class="section2">Convert Template into Ruby Script</h3>
1431
1970
 
1432
- &lt;/body&gt;
1433
- &lt;/html&gt;
1971
+ <p>Command-line option '-s' converts template file into Ruby script code.</p><a name="test_convert/example.rbhtml"></a>
1972
+
1973
+ <div class="program_caption">
1974
+ example.rbhtml
1975
+ </div>
1976
+ <pre class="program">
1977
+ &lt;ul&gt;
1978
+ &lt;?rb for item in @items ?&gt;
1979
+ &lt;li&gt;${item}&lt;/li&gt;
1980
+ &lt;?rb end ?&gt;
1981
+ &lt;/ul&gt;
1982
+ </pre><a name="test_convert/result1.output"></a>
1983
+
1984
+ <div class="terminal_caption">
1985
+ Result (-s)
1986
+ </div>
1987
+ <pre class="terminal">
1988
+ $ rbtenjin <strong>-s</strong> example.rbhtml
1989
+ _buf = ''; _buf &lt;&lt; %Q`&lt;ul&gt;\n`
1990
+ for item in @items
1991
+ _buf &lt;&lt; %Q` &lt;li&gt;#{escape((item).to_s)}&lt;/li&gt;\n`
1992
+ end
1993
+ _buf &lt;&lt; %Q`&lt;/ul&gt;\n`
1994
+ _buf.to_s
1434
1995
  </pre>
1435
- <a name="footer.html"></a>
1436
- <div class="program_caption">
1437
- File 'footer.html':</div>
1438
- <pre class="program">&lt;?rb #@ARGS ?&gt;
1439
- &lt;hr /&gt;
1440
- &lt;address&gt;
1441
- &lt;a href="mailto:webmaster@example.com"&gt;webmaster@example.com&lt;/a&gt;
1442
- &lt;/address&gt;
1996
+
1997
+ <p>Option '-b' removes preamble ('<code>_buf = ''</code>') and postamble ('<code>_buf.to_s)</code>').</p><a name="test_convert/result2.output"></a>
1998
+
1999
+ <div class="terminal_caption">
2000
+ Result (-sb)
2001
+ </div>
2002
+ <pre class="terminal">
2003
+ $ rbtenjin -s<strong>b</strong> example.rbhtml
2004
+ _buf &lt;&lt; %Q`&lt;ul&gt;\n`
2005
+ for item in @items
2006
+ _buf &lt;&lt; %Q` &lt;li&gt;#{escape((item).to_s)}&lt;/li&gt;\n`
2007
+ end
2008
+ _buf &lt;&lt; %Q`&lt;/ul&gt;\n`
2009
+ </pre><br>
2010
+ <a name="command-retrieve" id="command-retrieve"></a>
2011
+
2012
+ <h3 class="section2">Retrieve Embedded Code</h3>
2013
+
2014
+ <p>Tenjin allows you to retrieve embedded code from template files in order to help template debugging.</p>
2015
+
2016
+ <p>It is hard to debug large template files because HTML and embedded code are mixed in a file. Retrieving embedded code from template files will help you to debug large template files.</p>
2017
+
2018
+ <p>Assume the following template file.</p><a name="test_retrieve/example.rbhtml"></a>
2019
+
2020
+ <div class="program_caption">
2021
+ example.rbhtml
2022
+ </div>
2023
+ <pre class="program">
2024
+ &lt;table&gt;
2025
+ &lt;?rb i = 0 ?&gt;
2026
+ &lt;?rb for item in @items ?&gt;
2027
+ &lt;?rb i += 1 ?&gt;
2028
+ &lt;tr&gt;
2029
+ &lt;td&gt;#{i}&lt;/td&gt;
2030
+ &lt;td&gt;${item}&lt;/td&gt;
2031
+ &lt;/tr&gt;
2032
+ &lt;?rb end ?&gt;
2033
+ &lt;/table&gt;
1443
2034
  </pre>
1444
- <a name="user_app.cgi"></a>
1445
- <div class="program_caption">
1446
- File 'user_app.cgi':</div>
1447
- <pre class="program">#!/usr/bin/env ruby
1448
2035
 
1449
- require 'cgi'
1450
- <strong>require 'tenjin'</strong>
2036
+ <p>Option '-S' (or '-a retrieve') retrieves embedded codes.</p><a name="test_retrieve/result1.output"></a>
1451
2037
 
1452
- ## set action ('create' or 'edit')
1453
- action = nil
1454
- cgi = nil
1455
- if ENV['REQUEST_METHOD']
1456
- cgi = CGI.new
1457
- action = cgi['action']
1458
- elsif ARGV[0]
1459
- action = ARGV[0]
1460
- end
1461
- action = 'create' unless ['create', 'edit'].include?(action)
1462
-
1463
- ## set context data
1464
- if action == 'create'
1465
- title = 'Create User'
1466
- params = {}
1467
- else
1468
- title = 'Edit User'
1469
- params = {:name=&gt;'Margalette',
1470
- :email=&gt;'meg@example.com',
1471
- :gender=&gt;'f',
1472
- :id=&gt;123 }
1473
- end
1474
- <strong>context = { :title=&gt;title, :params=&gt;params }</strong>
1475
- <strong># or context = Tenjin::Context.new(:title=&gt;title, :params=&gt;params)</strong>
2038
+ <div class="terminal_caption">
2039
+ Result (-Sb)
2040
+ </div>
2041
+ <pre class="terminal">
2042
+ $ rbtenjin -<strong>S</strong>b example.rbhtml
2043
+
2044
+ i = 0
2045
+ for item in @items
2046
+ i += 1
2047
+
2048
+
2049
+ escape((item).to_s);
2050
+
2051
+ end
1476
2052
 
1477
- ## create engine object
1478
- layout = :layout # or 'user_layout.rbhtml'
1479
- <strong>engine = Tenjin::Engine.new(:prefix=&gt;'user_', :postfix=&gt;'.rbhtml', :layout=&gt;layout)</strong>
1480
-
1481
- ## evaluate template
1482
- template_name = action.intern # :create or :edit
1483
- <strong>output = engine.render(template_name, context)</strong>
1484
- print cgi.header() if cgi
1485
- print output
1486
2053
  </pre>
1487
- <a name="user_app.result"></a>
1488
- <div class="terminal_caption">
1489
- Result:</div>
1490
- <pre class="terminal">$ ruby user_app.cgi create
1491
- &lt;html&gt;
1492
- &lt;body&gt;
1493
2054
 
1494
- &lt;h1&gt;Create User&lt;/h1&gt;
2055
+ <p>Option '-X' (or '-a statements') retrieves only statements.</p><a name="test_retrieve/result2.output"></a>
1495
2056
 
1496
- &lt;div id="main-content"&gt;
1497
- <strong>&lt;form action="user_app.cgi" method="post"&gt;</strong>
1498
- <strong> &lt;input type="hidden" name="action" value="create" /&gt;</strong>
1499
- <strong>&lt;p&gt;</strong>
1500
- <strong> Name: &lt;input type="text" name="name" value="" /&gt;&lt;br /&gt;</strong>
1501
- <strong> Email: &lt;input type="text" name="email" value="" /&gt;&lt;br /&gt;</strong>
1502
- <strong> Gender:</strong>
1503
- <strong> &lt;input type="radio" name="gender" value="m" /&gt;Male</strong>
1504
- <strong> &lt;input type="radio" name="gender" value="f" /&gt;Female</strong>
1505
- <strong>&lt;/p&gt;</strong>
1506
- <strong> &lt;input type="submit" value="Create" /&gt;</strong>
1507
- <strong>&lt;/form&gt;</strong>
2057
+ <div class="terminal_caption">
2058
+ Result (-Xb)
2059
+ </div>
2060
+ <pre class="terminal">
2061
+ $ rbtenjin -<strong>X</strong>b example.rbhtml
1508
2062
 
1509
- &lt;/div&gt;
2063
+ i = 0
2064
+ for item in @items
2065
+ i += 1
1510
2066
 
1511
- &lt;div id="footer"&gt;
1512
- <strong>&lt;hr /&gt;</strong>
1513
- <strong>&lt;address&gt;</strong>
1514
- <strong> &lt;a href="mailto:webmaster@example.com"&gt;webmaster@example.com&lt;/a&gt;</strong>
1515
- <strong>&lt;/address&gt;</strong>
1516
- &lt;/div&gt;
1517
2067
 
1518
- &lt;/body&gt;
1519
- &lt;/html&gt;
2068
+
2069
+
2070
+ end
2071
+
1520
2072
  </pre>
1521
- <br>
1522
-
1523
-
1524
- <a name="dev-initopts"></a>
1525
- <h3 class="section2">Template Initialize Options</h3>
1526
- <p>Tenjin::Template() can take the follwoing options.
1527
- </p>
1528
- <ul type="disc">
1529
- <li>'<code>escapefunc</code>' (string) specifies function name to escape string.
1530
- Default is '<code>escape</code>' (= <code>Tenjin::Context#escape</code>).
1531
- </li>
1532
- </ul>
1533
- <p>Constructor of Tenjin::Engine can also take the same options as above.
1534
- These options given to constructor of Tenjin::Engine are passed to constructor of Tenjin::Template internally.
1535
- </p>
1536
- <a name="example15.rb"></a>
1537
- <div class="program_caption">
1538
- File 'example15.rb':</div>
1539
- <pre class="program">require 'tenjin'
1540
- filename = 'example14.rbhtml'
1541
- template = Tenjin::Template.new(filename, <strong>:escapefunc=&gt;'CGI.escapeHTML'</strong>)
1542
- print template.script, "\n"
1543
-
1544
- require 'cgi'
1545
- title = 'rbTenjin Example'
1546
- items = ['&lt;foo&gt;', '&amp;bar', '"baz"']
1547
- output = template.render(:title=&gt;title, :items=&gt;items)
1548
- print output
2073
+
2074
+ <p>Option '-N' adds line numbers.</p><a name="test_retrieve/result3.output"></a>
2075
+
2076
+ <div class="terminal_caption">
2077
+ Result (-NXb)
2078
+ </div>
2079
+ <pre class="terminal">
2080
+ $ rbtenjin -<strong>N</strong>Xb example.rbhtml
2081
+ 1:
2082
+ 2: i = 0
2083
+ 3: for item in @items
2084
+ 4: i += 1
2085
+ 5:
2086
+ 6:
2087
+ 7:
2088
+ 8:
2089
+ 9: end
2090
+ 10:
1549
2091
  </pre>
1550
- <a name="example15_escapefunc.result"></a>
1551
- <div class="terminal_caption">
1552
- Result:</div>
1553
- <pre class="terminal">$ ruby example15.rb
1554
- _buf &lt;&lt; %Q`&lt;h1&gt;#{@title}&lt;/h1&gt;
1555
- &lt;ul&gt;\n`
1556
- for item in @items
1557
- _buf &lt;&lt; %Q` &lt;li&gt;#{<strong>CGI.escapeHTML</strong>((item).to_s)}&lt;/li&gt;\n`
1558
- end
1559
- _buf &lt;&lt; %Q`&lt;/ul&gt;\n`
1560
2092
 
1561
- &lt;h1&gt;rbTenjin Example&lt;/h1&gt;
2093
+ <p>Option '-U' (unique) compress empty lines.</p><a name="test_retrieve/result4.output"></a>
2094
+
2095
+ <div class="terminal_caption">
2096
+ Result (-UNXb)
2097
+ </div>
2098
+ <pre class="terminal">
2099
+ $ rbtenjin -<strong>U</strong>NXb example.rbhtml
2100
+
2101
+ 2: i = 0
2102
+ 3: for item in @items
2103
+ 4: i += 1
2104
+
2105
+ 9: end
2106
+
2107
+ </pre>
2108
+
2109
+ <p>Option '-C' (compact) removes empty lines.</p><a name="test_retrieve/result5.output"></a>
2110
+
2111
+ <div class="terminal_caption">
2112
+ Result (-CNXb)
2113
+ </div>
2114
+ <pre class="terminal">
2115
+ $ rbtenjin -<strong>C</strong>NXb example.rbhtml
2116
+ 2: i = 0
2117
+ 3: for item in @items
2118
+ 4: i += 1
2119
+ 9: end
2120
+ </pre><br>
2121
+ <a name="command-execute-template" id="command-execute-template"></a>
2122
+
2123
+ <h3 class="section2">Execute Template File</h3>
2124
+
2125
+ <p>You can execute template file in command-line.</p><a name="test_execute/example.rbhtml"></a>
2126
+
2127
+ <div class="program_caption">
2128
+ example.rbhtml
2129
+ </div>
2130
+ <pre class="program">
2131
+ &lt;?rb @items = ['&lt;AAA&gt;', 'B&amp;B', '"CCC"'] ?&gt;
1562
2132
  &lt;ul&gt;
1563
- &lt;li&gt;&amp;lt;foo&amp;gt;&lt;/li&gt;
1564
- &lt;li&gt;&amp;amp;bar&lt;/li&gt;
1565
- &lt;li&gt;&amp;quot;baz&amp;quot;&lt;/li&gt;
2133
+ &lt;?rb for item in @items ?&gt;
2134
+ &lt;li&gt;${item}&lt;/li&gt;
2135
+ &lt;?rb end ?&gt;
1566
2136
  &lt;/ul&gt;
1567
- </pre>
1568
- <br>
1569
-
1570
-
1571
- <a name="dev-helpers"></a>
1572
- <h3 class="section2">Add Your Helper Functions</h3>
1573
- <p>There are several ways to use helper functions.
1574
- </p>
1575
- <p>Assume the following template.
1576
- </p>
1577
- <a name="example16.rbhtml"></a>
1578
- <div class="program_caption">
1579
- File 'example16.rbhtml':</div>
1580
- <pre class="program">&lt;?rb #@ARGS label, url ?&gt;
2137
+ </pre><a name="test_execute/result.output"></a>
2138
+
2139
+ <div class="terminal_caption">
2140
+ Result
2141
+ </div>
2142
+ <pre class="terminal">
2143
+ $ rbtenjin example.rbhtml
1581
2144
  &lt;ul&gt;
1582
- &lt;li&gt;#{<strong>link_to(label, url)</strong>}&lt;/li&gt;
2145
+ &lt;li&gt;&amp;lt;AAA&amp;gt;&lt;/li&gt;
2146
+ &lt;li&gt;B&amp;amp;B&lt;/li&gt;
2147
+ &lt;li&gt;&amp;quot;CCC&amp;quot;&lt;/li&gt;
1583
2148
  &lt;/ul&gt;
1584
- </pre>
1585
- <p>(A) Define helper functions as global function.
1586
- </p>
1587
- <a name="example16a.rb"></a>
1588
- <div class="program_caption">
1589
- File 'example16a.rb':</div>
1590
- <pre class="program">require 'tenjin'
2149
+ </pre><br>
2150
+ <a name="command-context-data" id="command-context-data"></a>
1591
2151
 
1592
- def link_to(label, url)
1593
- return "&lt;a href=\"#{escape_xml(url)}\"&gt;#{escape_xml(label)}&lt;/a&gt;"
1594
- end
2152
+ <h3 class="section2">Context Data</h3>
1595
2153
 
1596
- engine = Tenjin::Engine.new()
1597
- context = { :label=&gt;'Top', :url=&gt;'/' }
1598
- output = engine.render('example16.rbhtml', context)
1599
- print output
1600
- </pre>
1601
- <a name="example16a.result"></a>
1602
- <div class="terminal_caption">
1603
- Result:</div>
1604
- <pre class="terminal">$ ruby example16a.rb
2154
+ <p>You can specify context data with command-line option '<code>-c</code>'.</p><a name="test_context/example.rbhtml"></a>
2155
+
2156
+ <div class="program_caption">
2157
+ example.rbhtml
2158
+ </div>
2159
+ <pre class="program">
1605
2160
  &lt;ul&gt;
1606
- &lt;li&gt;&lt;a href="/"&gt;Top&lt;/a&gt;&lt;/li&gt;
2161
+ &lt;?rb for item in @items ?&gt;
2162
+ &lt;li&gt;${item}&lt;/li&gt;
2163
+ &lt;?rb end ?&gt;
1607
2164
  &lt;/ul&gt;
1608
- </pre>
1609
- <p>(B) Define helper functions as module function of Tenjin::ContextHelper module.
1610
- </p>
1611
- <a name="example16b.rb"></a>
1612
- <div class="program_caption">
1613
- File 'example16b.rb':</div>
1614
- <pre class="program">require 'tenjin'
1615
-
1616
- <strong>module Tenjin::ContextHelper</strong>
1617
- module_function
1618
- def link_to(label, url)
1619
- return "&lt;a href=\"#{escape_xml(url)}\"&gt;#{escape_xml(label)}&lt;/a&gt;"
1620
- end
1621
- <strong>end</strong>
2165
+ </pre><a name="test_context/result1.output"></a>
1622
2166
 
1623
- engine = Tenjin::Engine.new()
1624
- context = { :label=&gt;'Top', :url=&gt;'/' }
1625
- output = engine.render('example16.rbhtml', context)
1626
- print output
1627
- </pre>
1628
- <a name="example16b.result"></a>
1629
- <div class="terminal_caption">
1630
- Result:</div>
1631
- <pre class="terminal">$ ruby example16b.rb
2167
+ <div class="terminal_caption">
2168
+ Result
2169
+ </div>
2170
+ <pre class="terminal">
2171
+ $ rbtenjin <strong>-c '@items=["A","B","C"]'</strong> example.rbhtml
1632
2172
  &lt;ul&gt;
1633
- &lt;li&gt;&lt;a href="/"&gt;Top&lt;/a&gt;&lt;/li&gt;
2173
+ &lt;li&gt;A&lt;/li&gt;
2174
+ &lt;li&gt;B&lt;/li&gt;
2175
+ &lt;li&gt;C&lt;/li&gt;
1634
2176
  &lt;/ul&gt;
1635
2177
  </pre>
1636
- <p>(C) Define subclass of Tenjin::Context and define helper functions as instance method.
1637
- </p>
1638
- <a name="example16c.rb"></a>
1639
- <div class="program_caption">
1640
- File 'example16c.rb':</div>
1641
- <pre class="program">require 'tenjin'
1642
-
1643
- <strong>class MyContext &lt; Tenjin::Context</strong>
1644
- def link_to(label, url)
1645
- return "&lt;a href=\"#{escape_xml(url)}\"&gt;#{escape_xml(label)}&lt;/a&gt;"
1646
- end
1647
- <strong>end</strong>
1648
2178
 
1649
- engine = Tenjin::Engine.new()
1650
- <strong>context = MyContext.new(:label=&gt;'Top', :url=&gt;'/')</strong>
1651
- output = engine.render('example16.rbhtml', context)
1652
- print output
1653
- </pre>
1654
- <a name="example16c.result"></a>
1655
- <div class="terminal_caption">
1656
- Result:</div>
1657
- <pre class="terminal">$ ruby example16c.rb
2179
+ <p>If you want to specify several values, separate them by ';' such as '-c "@x=10;@y=20"'.</p>
2180
+
2181
+ <p>If you installed yaml library, you can specify context data in YAML format. Tenjin regards context data string as YAML format if it starts with '{'.</p><a name="test_context/result2.output"></a>
2182
+
2183
+ <div class="terminal_caption">
2184
+ Result
2185
+ </div>
2186
+ <pre class="terminal">
2187
+ $ rbtenjin <strong>-c '{items: [A, B, C]}'</strong> example.rbhtml
1658
2188
  &lt;ul&gt;
1659
- &lt;li&gt;&lt;a href="/"&gt;Top&lt;/a&gt;&lt;/li&gt;
2189
+ &lt;li&gt;A&lt;/li&gt;
2190
+ &lt;li&gt;B&lt;/li&gt;
2191
+ &lt;li&gt;C&lt;/li&gt;
1660
2192
  &lt;/ul&gt;
1661
2193
  </pre>
1662
- <p>(D) Define helper functions in current class, set context data as instance variables, and pass self as context object
1663
- </p>
1664
- <a name="example16d.rb"></a>
1665
- <div class="program_caption">
1666
- File 'example16d.rb':</div>
1667
- <pre class="program">require 'tenjin'
1668
-
1669
- class MyClass
1670
- <strong>include Tenjin::ContextHelper</strong>
1671
- <strong>#include Tenjin::HtmlHelper</strong> # optional
1672
-
1673
- def link_to(label, url) # define helper functions in current class
1674
- return "&lt;a href=\"#{escape(url)}\"&gt;#{escape(label)}&lt;/a&gt;"
1675
- end
1676
2194
 
1677
- def render_template(template_name)
1678
- engine = Tenjin::Engine.new()
1679
- output = engine.render(template_name, <strong>self</strong>) # pass self as context object
1680
- return output
1681
- end
1682
-
1683
- def main
1684
- ## set context data as instance variables
1685
- <strong>@label = 'Top'</strong>
1686
- <strong>@url = '/'</strong>
1687
- output = render_template('example16.rbhtml')
1688
- print output
1689
- end
2195
+ <p>In addition, Tenjin supports context data file in Ruby format or YAML format.</p><a name="test_context/context.rb"></a>
1690
2196
 
1691
- end
2197
+ <div class="program_caption">
2198
+ context.rb
2199
+ </div>
2200
+ <pre class="program">
2201
+ @items = [
2202
+ "AAA",
2203
+ 123,
2204
+ true,
2205
+ ]
2206
+ </pre><a name="test_context/result3.output"></a>
1692
2207
 
1693
- MyClass.new.main()
1694
- </pre>
1695
- <a name="example16d.result"></a>
1696
- <div class="terminal_caption">
1697
- Result:</div>
1698
- <pre class="terminal">$ ruby example16d.rb
2208
+ <div class="terminal_caption">
2209
+ Result
2210
+ </div>
2211
+ <pre class="terminal">
2212
+ $ rbtenjin <strong>-f context.rb</strong> example.rbhtml
1699
2213
  &lt;ul&gt;
1700
- &lt;li&gt;&lt;a href="/"&gt;Top&lt;/a&gt;&lt;/li&gt;
2214
+ &lt;li&gt;AAA&lt;/li&gt;
2215
+ &lt;li&gt;123&lt;/li&gt;
2216
+ &lt;li&gt;true&lt;/li&gt;
1701
2217
  &lt;/ul&gt;
1702
- </pre>
1703
- <br>
2218
+ </pre><a name="test_context/context.yaml"></a>
1704
2219
 
2220
+ <div class="program_caption">
2221
+ context.yaml
2222
+ </div>
2223
+ <pre class="program">
2224
+ items:
2225
+ - AAA
2226
+ - 123
2227
+ - true
2228
+ </pre><a name="test_context/result4.output"></a>
2229
+
2230
+ <div class="terminal_caption">
2231
+ Result
2232
+ </div>
2233
+ <pre class="terminal">
2234
+ $ rbtenjin <strong>-f context.yaml</strong> example.rbhtml
2235
+ &lt;ul&gt;
2236
+ &lt;li&gt;AAA&lt;/li&gt;
2237
+ &lt;li&gt;123&lt;/li&gt;
2238
+ &lt;li&gt;true&lt;/li&gt;
2239
+ &lt;/ul&gt;
2240
+ </pre><br>
2241
+ <br>
2242
+ <a name="shooting" id="shooting"></a>
1705
2243
 
1706
- <a name="dev-othertopics"></a>
1707
- <h3 class="section2">Other Topics</h3>
1708
- <ul type="disc">
1709
- <li>Tenjin::Template detects newline character ("\n" or "\r\n") automatically.
1710
- If input file contains "\r\n", rbTenjin generates output which contains "\r\n".
1711
- </li>
1712
- </ul>
1713
- <ul type="disc">
1714
- <li>Tenjin::Template#render() can be called many times.
1715
- If you create a Tenjin::Template object, you can call render() method many times.
1716
- </li>
1717
- </ul>
1718
- <ul type="disc">
1719
- <li>Tenjin::Template#convert() also can be called many times.
1720
- If you create a Tenjin::Template object, you can call convert() (and also render()) method many times.
1721
- </li>
1722
- </ul>
1723
- <br>
2244
+ <h2 class="section1">Trouble shooting</h2>
1724
2245
 
2246
+ <p>(not documented yet)</p><br>
2247
+ <a name="customize" id="customize"></a>
1725
2248
 
1726
- <br>
2249
+ <h2 class="section1">Customization Examples</h2>
1727
2250
 
2251
+ <p>This section shows how to customize rbTenjin.</p>
1728
2252
 
2253
+ <p><strong>Notice that these customization may be changed in the future release.</strong></p>
1729
2254
 
1730
- </div>
2255
+ <p>(not documented yet)</p><br>
2256
+ </div>
1731
2257
  </blockquote>
1732
-
1733
- </body>
2258
+ </body>
1734
2259
  </html>