tenjin 0.6.2 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.txt +163 -0
- data/MIT-LICENSE +16 -17
- data/README.txt +5 -5
- data/benchmark/Makefile +9 -0
- data/benchmark/bench.rb +3 -2
- data/bin/rbtenjin +6 -3
- data/doc/docstyle.css +25 -4
- data/doc/users-guide.html +2088 -1563
- data/lib/tenjin.rb +784 -158
- data/public_html/_layout.rbhtml +33 -0
- data/public_html/css/style.css +77 -0
- data/public_html/env.rbhtml +15 -0
- data/public_html/favicon.ico +0 -0
- data/public_html/hello.rbhtml +14 -0
- data/public_html/index.rbhtml +39 -0
- data/public_html/rbtenjin.cgi +188 -0
- data/tenjin.gemspec +9 -6
- data/test/data/examples/preprocessing/main.rb +1 -1
- data/test/data/examples/preprocessing/select.rbhtml +1 -1
- data/test/data/faq/{ex11-bench.rb → ex10-bench.rb} +3 -3
- data/test/data/faq/ex10-content.rbhtml +8 -11
- data/test/data/faq/{ex11-layout1.rbhtml → ex10-layout1.rbhtml} +0 -0
- data/test/data/faq/{ex11-layout2.rbhtml → ex10-layout2.rbhtml} +0 -0
- data/test/data/faq/{ex11.rb → ex10.rb} +1 -1
- data/test/data/faq/{ex11.rbhtml → ex10.rbhtml} +0 -0
- data/test/data/faq/{ex11.source → ex10.source} +2 -2
- data/test/data/faq/{ex11_arraybuffer.result → ex10_arraybuffer.result} +1 -1
- data/test/data/faq/{ex5.rbhtml → ex2.rbhtml} +0 -0
- data/test/data/faq/{ex5_template_args.source → ex2_template_args.source} +1 -1
- data/test/data/faq/{ex7-expr-pattern.rb → ex4-expr-pattern.rb} +1 -1
- data/test/data/faq/{ex7-expr-pattern.rbhtml → ex4-expr-pattern.rbhtml} +0 -0
- data/test/data/faq/{ex7_expr_pattern.result → ex4_expr_pattern.result} +1 -1
- data/test/data/faq/{ex6-content.rhtml → ex5-content.rhtml} +0 -0
- data/test/data/faq/{ex6-layout.rhtml → ex5-layout.rhtml} +0 -0
- data/test/data/faq/{ex6.rb → ex5.rb} +2 -2
- data/test/data/faq/{ex6_eruby.result → ex5_eruby.result} +1 -1
- data/test/data/faq/{ex2-content.rbhtml → ex6-content.rbhtml} +0 -0
- data/test/data/faq/{ex2-layout.rbhtml → ex6-layout.rbhtml} +0 -0
- data/test/data/faq/{ex2_removenl.result → ex6_removenl.result} +1 -1
- data/test/data/faq/ex7-m18n.rb +48 -0
- data/test/data/faq/{ex8-m18n.rbhtml → ex7-m18n.rbhtml} +0 -0
- data/test/data/faq/{ex8_m18n.result → ex7_m18n.result} +1 -1
- data/test/data/faq/ex8-baselayout.rbhtml +8 -0
- data/test/data/faq/ex8-content.rbhtml +6 -0
- data/test/data/faq/{ex9-mylayout.rbhtml → ex8-mylayout.rbhtml} +0 -0
- data/test/data/faq/{ex9_changelayout.result → ex8_changelayout.result} +1 -1
- data/test/data/faq/ex9-baselayout.rbhtml +24 -5
- data/test/data/faq/ex9-content.rbhtml +12 -6
- data/test/data/faq/{ex10-customlayout.rbhtml → ex9-customlayout.rbhtml} +1 -1
- data/test/data/faq/{ex10_inherit.result → ex9_inherit.result} +1 -1
- data/test/data/faq/helpers1.rb +17 -0
- data/test/data/faq/helpers1.rbhtml +4 -0
- data/test/data/faq/helpers1.result +11 -0
- data/test/data/faq/helpers2.rb +21 -0
- data/test/data/faq/helpers2.rbhtml +4 -0
- data/test/data/faq/helpers2.result +11 -0
- data/test/data/faq/weekday1.rb +6 -0
- data/test/data/faq/weekday1.rbhtml +9 -0
- data/test/data/faq/weekday1.result +23 -0
- data/test/data/faq/weekday2.rb +8 -0
- data/test/data/faq/weekday2.rbhtml +10 -0
- data/test/data/faq/weekday2.result +24 -0
- data/test/data/faq/weekday3.rb +22 -0
- data/test/data/faq/weekday3.rbhtml +3 -0
- data/test/data/faq/weekday3.result +28 -0
- data/test/data/users_guide/test_010/main.rb +14 -0
- data/test/data/users_guide/test_010/result.output +13 -0
- data/test/data/users_guide/test_010/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_011/main.rb +14 -0
- data/test/data/users_guide/test_011/result.output +2 -0
- data/test/data/users_guide/test_011/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_020/main.rb +14 -0
- data/test/data/users_guide/test_020/result.output +13 -0
- data/test/data/users_guide/test_020/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_021/main.rb +12 -0
- data/test/data/users_guide/test_021/result.output +12 -0
- data/test/data/users_guide/test_021/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_030/main.rb +14 -0
- data/test/data/users_guide/test_030/result.output +23 -0
- data/test/data/users_guide/test_030/views/_layout.rbhtml +10 -0
- data/test/data/users_guide/test_030/views/page.rbhtml +11 -0
- data/test/data/users_guide/test_040/main.rb +14 -0
- data/test/data/users_guide/test_040/result.output +23 -0
- data/test/data/users_guide/test_040/views/_layout.rbhtml +10 -0
- data/test/data/users_guide/test_040/views/page.rbhtml +12 -0
- data/test/data/users_guide/test_050/main.rb +14 -0
- data/test/data/users_guide/test_050/result.output +14 -0
- data/test/data/users_guide/test_050/views/_layout.rbhtml +10 -0
- data/test/data/users_guide/test_050/views/page.rbhtml +13 -0
- data/test/data/users_guide/test_051/main.rb +14 -0
- data/test/data/users_guide/test_051/result.output +12 -0
- data/test/data/users_guide/test_051/views/_layout.rbhtml +11 -0
- data/test/data/users_guide/test_051/views/page.rbhtml +13 -0
- data/test/data/users_guide/test_060/main.rb +14 -0
- data/test/data/users_guide/test_060/result.output +29 -0
- data/test/data/users_guide/test_060/views/_footer.rbhtml +3 -0
- data/test/data/users_guide/test_060/views/_header.rbhtml +3 -0
- data/test/data/users_guide/test_060/views/_layout.rbhtml +13 -0
- data/test/data/users_guide/test_060/views/page.rbhtml +13 -0
- data/test/data/users_guide/test_070/main.rb +14 -0
- data/test/data/users_guide/test_070/result.output +29 -0
- data/test/data/users_guide/test_070/views/_footer.rbhtml +3 -0
- data/test/data/users_guide/test_070/views/_header.rbhtml +3 -0
- data/test/data/users_guide/test_070/views/_layout.rbhtml +13 -0
- data/test/data/users_guide/test_070/views/page.rbhtml +13 -0
- data/test/data/users_guide/test_capturing/main.rb +24 -0
- data/test/data/users_guide/test_capturing/result.output +28 -0
- data/test/data/users_guide/test_capturing/views/_layout.rbhtml +21 -0
- data/test/data/users_guide/test_capturing/views/blog-post.rbhtml +13 -0
- data/test/data/users_guide/test_context/context.rb +5 -0
- data/test/data/users_guide/test_context/context.yaml +4 -0
- data/test/data/users_guide/test_context/example.rbhtml +5 -0
- data/test/data/users_guide/test_context/result1.output +6 -0
- data/test/data/users_guide/test_context/result2.output +6 -0
- data/test/data/users_guide/test_context/result3.output +6 -0
- data/test/data/users_guide/test_context/result4.output +6 -0
- data/test/data/users_guide/test_convert/example.rbhtml +5 -0
- data/test/data/users_guide/test_convert/result1.output +7 -0
- data/test/data/users_guide/test_convert/result2.output +6 -0
- data/test/data/users_guide/test_escape/main.rb +4 -0
- data/test/data/users_guide/test_escape/result.output +5 -0
- data/test/data/users_guide/test_escape/views/page.rbhtml +4 -0
- data/test/data/users_guide/test_execute/example.rbhtml +6 -0
- data/test/data/users_guide/test_execute/result.output +6 -0
- data/test/data/users_guide/test_fragmentcache/cache.d/items/1 +5 -0
- data/test/data/users_guide/test_fragmentcache/main.rb +21 -0
- data/test/data/users_guide/test_fragmentcache/result.output +8 -0
- data/test/data/users_guide/test_fragmentcache/result2.output +6 -0
- data/test/data/users_guide/test_fragmentcache/views/items.rbhtml +10 -0
- data/test/data/users_guide/test_logging/ex-logger.rb +11 -0
- data/test/data/users_guide/test_logging/example.rbhtml +0 -0
- data/test/data/users_guide/test_logging/result1.output +3 -0
- data/test/data/users_guide/test_logging/result2.output +2 -0
- data/test/data/users_guide/test_m17n/m17n.rb +44 -0
- data/test/data/users_guide/test_m17n/m17n.rbhtml +5 -0
- data/test/data/users_guide/test_m17n/result.output +9 -0
- data/test/data/users_guide/test_m17n/result_en.output +4 -0
- data/test/data/users_guide/test_m17n/result_fr.output +4 -0
- data/test/data/users_guide/test_nested/main.rb +8 -0
- data/test/data/users_guide/test_nested/result.output +15 -0
- data/test/data/users_guide/test_nested/views/_blog_layout.rbhtml +5 -0
- data/test/data/users_guide/{layout8_html.rbhtml → test_nested/views/_site_layout.rbhtml} +0 -0
- data/test/data/users_guide/test_nested/views/blog_post.rbhtml +4 -0
- data/test/data/users_guide/test_preprocessing/pp-example1.rb +14 -0
- data/test/data/users_guide/test_preprocessing/result1a.output +11 -0
- data/test/data/users_guide/test_preprocessing/result1b.output +5 -0
- data/test/data/users_guide/test_preprocessing/result1c.output +6 -0
- data/test/data/users_guide/test_preprocessing/result2a.output +10 -0
- data/test/data/users_guide/test_preprocessing/result2b.output +10 -0
- data/test/data/users_guide/test_preprocessing/result3a.output +2 -0
- data/test/data/users_guide/test_preprocessing/result3b.output +2 -0
- data/test/data/users_guide/test_preprocessing/views/pp-example1.rbhtml +4 -0
- data/test/data/users_guide/{example12.rbhtml → test_preprocessing/views/pp-example2.rbhtml} +4 -4
- data/test/data/users_guide/test_preprocessing/views/pp-example3.rbhtml +7 -0
- data/test/data/users_guide/test_retrieve/example.rbhtml +10 -0
- data/test/data/users_guide/test_retrieve/result1.output +11 -0
- data/test/data/users_guide/test_retrieve/result2.output +11 -0
- data/test/data/users_guide/test_retrieve/result3.output +11 -0
- data/test/data/users_guide/test_retrieve/result4.output +8 -0
- data/test/data/users_guide/test_retrieve/result5.output +5 -0
- data/test/data/users_guide/test_safe/result.output +6 -0
- data/test/data/users_guide/test_safe/safe-test.rb +21 -0
- data/test/data/users_guide/test_safehelper/main.rb +16 -0
- data/test/data/users_guide/test_safehelper/result.output +8 -0
- data/test/data/users_guide/{example3.rbhtml → test_syntax_check/example.rbhtml} +0 -0
- data/test/data/users_guide/test_syntax_check/result.output +2 -0
- data/test/data/users_guide/test_trace/layout.rbhtml +7 -0
- data/test/data/users_guide/test_trace/main.rbhtml +5 -0
- data/test/data/users_guide/test_trace/result.output +16 -0
- data/test/data/users_guide/test_trace/trace-example.rb +4 -0
- data/test/oktest.rb +755 -0
- data/test/test_all.rb +24 -14
- data/test/test_engine.rb +628 -63
- data/test/test_engine.yaml +40 -3
- data/test/test_examples.rb +14 -12
- data/test/test_faq.rb +17 -12
- data/test/test_htmlhelper.rb +104 -33
- data/test/test_main.rb +32 -21
- data/test/test_main.yaml +2 -2
- data/test/test_safe.rb +206 -0
- data/test/test_store.rb +220 -0
- data/test/test_tcache.rb +94 -0
- data/test/test_template.rb +65 -23
- data/test/test_template.yaml +7 -7
- data/test/test_users_guide.rb +75 -29
- data/test/testcase-helper.rb +20 -18
- data/test/testunit-assertions.rb +71 -0
- metadata +185 -159
- data/doc-api/classes/Tenjin.html +0 -141
- data/doc-api/classes/Tenjin/ArrayBufferTemplate.html +0 -270
- data/doc-api/classes/Tenjin/BaseContext.html +0 -329
- data/doc-api/classes/Tenjin/Context.html +0 -126
- data/doc-api/classes/Tenjin/ContextHelper.html +0 -461
- data/doc-api/classes/Tenjin/Engine.html +0 -616
- data/doc-api/classes/Tenjin/ErubisTemplate.html +0 -166
- data/doc-api/classes/Tenjin/HtmlHelper.html +0 -359
- data/doc-api/classes/Tenjin/Preprocessor.html +0 -242
- data/doc-api/classes/Tenjin/Template.html +0 -916
- data/doc-api/created.rid +0 -1
- data/doc-api/files/README_txt.html +0 -188
- data/doc-api/files/lib/tenjin_rb.html +0 -136
- data/doc-api/fr_class_index.html +0 -36
- data/doc-api/fr_file_index.html +0 -28
- data/doc-api/fr_method_index.html +0 -91
- data/doc-api/index.html +0 -24
- data/doc-api/rdoc-style.css +0 -208
- data/doc/examples.html +0 -312
- data/doc/faq.html +0 -909
- data/examples/preprocessing/select.rbhtml.cache +0 -17
- data/test/Rookbook.yaml +0 -14
- data/test/assert-text-equal.rb +0 -45
- data/test/data/faq/ex10-baselayout.rbhtml +0 -27
- data/test/data/faq/ex11-content.rbhtml +0 -9
- data/test/data/faq/ex8-m18n.rb +0 -77
- data/test/data/users_guide/content6.rbhtml +0 -3
- data/test/data/users_guide/content7.rbhtml +0 -5
- data/test/data/users_guide/content8.rbhtml +0 -2
- data/test/data/users_guide/contextdata.rb +0 -7
- data/test/data/users_guide/datafile.rb +0 -5
- data/test/data/users_guide/datafile.yaml +0 -10
- data/test/data/users_guide/ex.rbhtml +0 -6
- data/test/data/users_guide/ex.result +0 -7
- data/test/data/users_guide/ex.script +0 -5
- data/test/data/users_guide/ex_script.result +0 -7
- data/test/data/users_guide/ex_source.result +0 -8
- data/test/data/users_guide/example1.rbhtml +0 -12
- data/test/data/users_guide/example1.result +0 -17
- data/test/data/users_guide/example10.rbhtml +0 -4
- data/test/data/users_guide/example10_template_args.result +0 -6
- data/test/data/users_guide/example11.rbhtml +0 -5
- data/test/data/users_guide/example11_template_args_result +0 -2
- data/test/data/users_guide/example12_preprocessed.result +0 -10
- data/test/data/users_guide/example12_preprocessed_source.result +0 -10
- data/test/data/users_guide/example13.rbhtml +0 -6
- data/test/data/users_guide/example13_preprocessed.result +0 -2
- data/test/data/users_guide/example13_preprocessed_source.result +0 -2
- data/test/data/users_guide/example14.rb +0 -32
- data/test/data/users_guide/example14.rbhtml +0 -6
- data/test/data/users_guide/example14_tmplclass.result +0 -15
- data/test/data/users_guide/example15.rb +0 -10
- data/test/data/users_guide/example15_escapefunc.result +0 -14
- data/test/data/users_guide/example16.rbhtml +0 -4
- data/test/data/users_guide/example16a.rb +0 -10
- data/test/data/users_guide/example16a.result +0 -4
- data/test/data/users_guide/example16b.rb +0 -13
- data/test/data/users_guide/example16b.result +0 -4
- data/test/data/users_guide/example16c.rb +0 -12
- data/test/data/users_guide/example16c.result +0 -4
- data/test/data/users_guide/example16d.rb +0 -27
- data/test/data/users_guide/example16d.result +0 -4
- data/test/data/users_guide/example1_S.result +0 -14
- data/test/data/users_guide/example1_SXNC.result +0 -10
- data/test/data/users_guide/example1_source.result +0 -14
- data/test/data/users_guide/example2.rbhtml +0 -3
- data/test/data/users_guide/example2_sb.result2 +0 -9
- data/test/data/users_guide/example3_syntaxcheck.result +0 -2
- data/test/data/users_guide/example4.rbhtml +0 -13
- data/test/data/users_guide/example4_datafile_rb.result +0 -13
- data/test/data/users_guide/example4_yaml.result +0 -13
- data/test/data/users_guide/example5.rbhtml +0 -9
- data/test/data/users_guide/example5_datastr_rb.result +0 -9
- data/test/data/users_guide/example5_datastr_yaml.result +0 -9
- data/test/data/users_guide/example6.rbhtml +0 -19
- data/test/data/users_guide/example6_layout.result +0 -29
- data/test/data/users_guide/example6_nested.result +0 -28
- data/test/data/users_guide/example7_layout2.result +0 -13
- data/test/data/users_guide/example8_layout3.result +0 -8
- data/test/data/users_guide/example9.rbhtml +0 -18
- data/test/data/users_guide/example9_capture.result +0 -26
- data/test/data/users_guide/footer.html +0 -5
- data/test/data/users_guide/footer.rbhtml +0 -4
- data/test/data/users_guide/layout6.rbhtml +0 -17
- data/test/data/users_guide/layout7.rbhtml +0 -9
- data/test/data/users_guide/layout8_xhtml.rbhtml +0 -6
- data/test/data/users_guide/layout9.rbhtml +0 -25
- data/test/data/users_guide/sidemenu.rbhtml +0 -5
- data/test/data/users_guide/user_app.cgi +0 -39
- data/test/data/users_guide/user_app.result +0 -30
- data/test/data/users_guide/user_create.rbhtml +0 -6
- data/test/data/users_guide/user_edit.rbhtml +0 -7
- data/test/data/users_guide/user_form.rbhtml +0 -10
- data/test/data/users_guide/user_layout.rbhtml +0 -16
data/CHANGES.txt
CHANGED
@@ -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 '''.
|
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 = <AAA></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 #=> <AAA>
|
105
|
+
puts safe_escape(s) #=> <AAA>
|
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.
|
data/MIT-LICENSE
CHANGED
@@ -1,20 +1,19 @@
|
|
1
|
-
copyright(c) 2007-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
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
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
OF
|
20
|
-
|
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.
|
4
|
-
copyright:: copyright(c) 2007-
|
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.
|
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.
|
41
|
-
$ cd rbtenjin-0.
|
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
|
|
data/benchmark/Makefile
ADDED
data/benchmark/bench.rb
CHANGED
@@ -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.
|
426
|
+
defun = defun_code(template.script)
|
426
427
|
context.instance_eval(defun)
|
427
428
|
ntimes.times do
|
428
429
|
output = context.tmpl_tenjin_view()
|
data/bin/rbtenjin
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
##
|
4
|
-
## copyright(c) 2007-
|
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
|
-
##
|
27
|
-
## $Release: 0.
|
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
|
|
data/doc/docstyle.css
CHANGED
@@ -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
|
+
}
|
data/doc/users-guide.html
CHANGED
@@ -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
|
-
|
10
|
-
<body>
|
10
|
+
</head>
|
11
11
|
|
12
|
+
<body>
|
12
13
|
<blockquote>
|
13
|
-
|
14
|
+
<div class="mainbody">
|
15
|
+
<div align="left">
|
16
|
+
<h1>rbTenjin User's Guide</h1>
|
17
|
+
</div>
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
</div>
|
19
|
+
<div align="left">
|
20
|
+
release: 0.7.0<br>
|
21
|
+
</div>
|
19
22
|
|
20
|
-
<
|
21
|
-
|
22
|
-
<
|
23
|
-
<
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
</
|
82
|
-
|
83
|
-
<
|
84
|
-
|
85
|
-
<
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
<
|
91
|
-
|
92
|
-
<
|
93
|
-
<
|
94
|
-
|
95
|
-
<
|
96
|
-
|
97
|
-
<
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
</
|
102
|
-
|
103
|
-
</
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
<li
|
108
|
-
</
|
109
|
-
|
110
|
-
|
111
|
-
</
|
112
|
-
|
113
|
-
<
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
<
|
119
|
-
|
120
|
-
<
|
121
|
-
|
122
|
-
|
123
|
-
</
|
124
|
-
|
125
|
-
<
|
126
|
-
|
127
|
-
<
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
<a
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
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
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
</
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
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.
|
186
|
-
$
|
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
|
-
|
189
|
-
|
190
|
-
erb
|
191
|
-
erb-
|
192
|
-
|
193
|
-
|
194
|
-
erubis
|
195
|
-
|
196
|
-
|
197
|
-
tenjin
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
</
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
<
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
<
|
211
|
-
<
|
212
|
-
|
213
|
-
<
|
214
|
-
|
215
|
-
</
|
216
|
-
|
217
|
-
<
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
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><?rb ... ?></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>& < > "</code>' is escaped to '<code>&amp; &lt; &gt; &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"><table>
|
258
|
-
<tbody>
|
259
|
-
<strong><?rb i = 0 ?></strong>
|
260
|
-
<strong><?rb for item in ['<foo>', 'bar&bar', '"baz"'] ?></strong>
|
261
|
-
<strong><?rb i += 1 ?></strong>
|
262
|
-
<tr>
|
263
|
-
<td><strong>#{item}</strong></td>
|
264
|
-
<td><strong>${item}</strong></td>
|
265
|
-
</tr>
|
266
|
-
<strong><?rb end ?></strong>
|
267
|
-
<tbody>
|
268
|
-
</table>
|
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><?rb ... ?></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
|
+
<h2><strong>${@title}</strong></h2>
|
276
265
|
<table>
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
<
|
283
|
-
|
284
|
-
|
285
|
-
</tr>
|
286
|
-
<tr>
|
287
|
-
<td><strong>"baz"</strong></td>
|
288
|
-
<td><strong>&quot;baz&quot;</strong></td>
|
289
|
-
</tr>
|
290
|
-
<tbody>
|
266
|
+
<strong><?rb i = 0 ?></strong>
|
267
|
+
<strong><?rb for item in @items ?></strong>
|
268
|
+
<strong><?rb i += 1 ?></strong>
|
269
|
+
<strong><?rb klass = i % 2 == 1 ? 'odd' : 'even' ?></strong>
|
270
|
+
<tr class="<strong>#{klass}</strong>">
|
271
|
+
<td><strong>${item}</strong></td>
|
272
|
+
</tr>
|
273
|
+
<strong><?rb end ?></strong>
|
291
274
|
</table>
|
292
275
|
</pre>
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
<a name="
|
297
|
-
|
298
|
-
<
|
299
|
-
|
300
|
-
|
301
|
-
<
|
302
|
-
|
303
|
-
|
304
|
-
_buf = ''; _buf << %Q`<table>
|
305
|
-
<tbody>\n`
|
306
|
-
<strong>i = 0</strong>
|
307
|
-
<strong>for item in ['<foo>', 'bar&bar', '"baz"']</strong>
|
308
|
-
<strong>i += 1</strong>
|
309
|
-
_buf << %Q` <tr>
|
310
|
-
<td><strong>#{item}</strong></td>
|
311
|
-
<td><strong>#{escape((item).to_s)}</strong></td>
|
312
|
-
</tr>\n`
|
313
|
-
<strong>end</strong>
|
314
|
-
_buf << %Q` <tbody>
|
315
|
-
</table>\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
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
<
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
<
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
<
|
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 => 'Tenjin Example',
|
305
|
+
:items => ['<AAA>', 'B&B', '"CCC"'],
|
306
|
+
}
|
307
|
+
|
308
|
+
## create engine object
|
309
|
+
<strong>engine = Tenjin::Engine.new(:path=>['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
|
+
<h2>Tenjin Example</h2>
|
322
|
+
<table>
|
323
|
+
<tr class="odd">
|
324
|
+
<td>&lt;AAA&gt;</td>
|
325
|
+
</tr>
|
326
|
+
<tr class="even">
|
327
|
+
<td>B&amp;B</td>
|
328
|
+
</tr>
|
329
|
+
<tr class="odd">
|
330
|
+
<td>&quot;CCC&quot;</td>
|
331
|
+
</tr>
|
332
|
+
</table>
|
336
333
|
</pre>
|
337
|
-
|
338
|
-
<div class="
|
339
|
-
|
340
|
-
<
|
341
|
-
<
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
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 < 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=>['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
|
-
|
360
|
-
|
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
|
-
|
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
|
-
|
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 << %Q`<h2>#{escape((@title).to_s)}</h2>
|
380
|
+
<table>\n`
|
381
|
+
i = 0
|
382
|
+
for item in @items
|
383
|
+
i += 1
|
384
|
+
klass = i % 2 == 1 ? 'odd' : 'even'
|
385
|
+
_buf << %Q` <tr class="#{klass}">
|
386
|
+
<td>#{escape((item).to_s)}</td>
|
387
|
+
</tr>\n`
|
388
|
+
end
|
389
|
+
_buf << %Q`</table>\n`
|
369
390
|
_buf.to_s
|
370
391
|
</pre>
|
371
|
-
|
372
|
-
</p>
|
373
|
-
|
374
|
-
<
|
375
|
-
|
376
|
-
<
|
377
|
-
|
378
|
-
</
|
379
|
-
<
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
<
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
</
|
418
|
-
<
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
<
|
425
|
-
|
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=>['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
|
+
<!DOCTYPE>
|
425
|
+
<html>
|
426
|
+
<head>
|
427
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
428
|
+
<title>${@title}</title>
|
429
|
+
</head>
|
430
|
+
<body>
|
431
|
+
<strong>#{@_content}</strong>
|
432
|
+
</body>
|
433
|
+
</html>
|
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 => 'Tenjin Example',
|
445
|
+
:items => ['<AAA>', 'B&B', '"CCC"'],
|
446
|
+
}
|
447
|
+
|
448
|
+
## cleate engine object
|
449
|
+
engine = Tenjin::Engine.new(:path=>['views']<strong>, :layout=>'_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
|
+
<!DOCTYPE>
|
462
|
+
<html>
|
463
|
+
<head>
|
464
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
465
|
+
<title>Tenjin Example</title>
|
466
|
+
</head>
|
467
|
+
<body>
|
468
|
+
<h2>Tenjin Example</h2>
|
469
|
+
<table>
|
470
|
+
<tr class="odd">
|
471
|
+
<td>&lt;AAA&gt;</td>
|
472
|
+
</tr>
|
473
|
+
<tr class="even">
|
474
|
+
<td>B&amp;B</td>
|
475
|
+
</tr>
|
476
|
+
<tr class="odd">
|
477
|
+
<td>&quot;CCC&quot;</td>
|
478
|
+
</tr>
|
479
|
+
</table>
|
480
|
+
|
481
|
+
</body>
|
482
|
+
</html>
|
426
483
|
</pre>
|
427
|
-
|
428
|
-
<
|
429
|
-
|
430
|
-
|
431
|
-
|
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"><p>
|
449
|
-
${@text}
|
450
|
-
#{@num}
|
451
|
-
#{@flag}
|
452
|
-
</p>
|
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
|
+
<!DOCTYPE>
|
506
|
+
<html>
|
507
|
+
<head>
|
508
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
509
|
+
<title><strong>${@page_title}</strong></title>
|
510
|
+
</head>
|
511
|
+
<body>
|
512
|
+
#{@_content}
|
513
|
+
</body>
|
514
|
+
</html>
|
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><?rb @page_title = 'Tenjin: Layout Template Example' ?></strong>
|
522
|
+
<h2>${@title}</h2>
|
523
|
+
<table>
|
524
|
+
<?rb i = 0 ?>
|
454
525
|
<?rb for item in @items ?>
|
455
|
-
<
|
526
|
+
<?rb i += 1 ?>
|
527
|
+
<?rb klass = i % 2 == 1 ? 'odd' : 'even' ?>
|
528
|
+
<tr class="#{klass}">
|
529
|
+
<td>${item}</td>
|
530
|
+
</tr>
|
456
531
|
<?rb end ?>
|
532
|
+
</table>
|
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
|
+
<!DOCTYPE>
|
541
|
+
<html>
|
542
|
+
<head>
|
543
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
544
|
+
<title><strong>Tenjin: Layout Template Example</strong></title>
|
545
|
+
</head>
|
546
|
+
<body>
|
547
|
+
<h2>Tenjin Example</h2>
|
548
|
+
<table>
|
549
|
+
<tr class="odd">
|
550
|
+
<td>&lt;AAA&gt;</td>
|
551
|
+
</tr>
|
552
|
+
<tr class="even">
|
553
|
+
<td>B&amp;B</td>
|
554
|
+
</tr>
|
555
|
+
<tr class="odd">
|
556
|
+
<td>&quot;CCC&quot;</td>
|
557
|
+
</tr>
|
558
|
+
</table>
|
457
559
|
|
458
|
-
<
|
459
|
-
<
|
560
|
+
</body>
|
561
|
+
</html>
|
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><?rb #@ARGS title, items ?></strong>
|
574
|
+
<?rb @page_title = 'Tenjin: Layout Template Example' ?>
|
575
|
+
<h2><strong>${title}</strong></h2>
|
576
|
+
<table>
|
577
|
+
<?rb i = 0 ?>
|
578
|
+
<?rb for item in <strong>items</strong> ?>
|
579
|
+
<?rb i += 1 ?>
|
580
|
+
<?rb klass = i % 2 == 1 ? 'odd' : 'even' ?>
|
581
|
+
<tr class="#{klass}">
|
582
|
+
<td>${item}</td>
|
583
|
+
</tr>
|
460
584
|
<?rb end ?>
|
585
|
+
</table>
|
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 << %Q`<h2>#{escape((<strong>title</strong>).to_s)}</h2>
|
596
|
+
<table>\n`
|
597
|
+
i = 0
|
598
|
+
for item in <strong>items</strong>
|
599
|
+
i += 1
|
600
|
+
klass = i % 2 == 1 ? 'odd' : 'even'
|
601
|
+
_buf << %Q` <tr class="#{klass}">
|
602
|
+
<td>#{escape((item).to_s)}</td>
|
603
|
+
</tr>\n`
|
604
|
+
end
|
605
|
+
_buf << %Q`</table>\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><?rb #@ARGS _content, page_title ?></strong>
|
613
|
+
<!DOCTYPE>
|
614
|
+
<html>
|
615
|
+
<head>
|
616
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
617
|
+
<title>${@page_title}</title>
|
618
|
+
</head>
|
619
|
+
<body>
|
620
|
+
#{@_content}
|
621
|
+
</body>
|
622
|
+
</html>
|
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 << %Q`<!DOCTYPE>
|
632
|
+
<html>
|
633
|
+
<head>
|
634
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
635
|
+
<title>#{escape((@page_title).to_s)}</title>
|
636
|
+
</head>
|
637
|
+
<body>
|
638
|
+
#{@_content}
|
639
|
+
</body>
|
640
|
+
</html>\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
|
+
<?rb #@ARGS _content, page_title ?>
|
661
|
+
<!DOCTYPE>
|
662
|
+
<html>
|
663
|
+
<head>
|
664
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
665
|
+
<title>${@page_title}</title>
|
666
|
+
</head>
|
667
|
+
<body>
|
668
|
+
<strong><?rb import('_header.rbhtml') ?></strong>
|
669
|
+
#{@_content}
|
670
|
+
<strong><?rb import('_footer.rbhtml') ?></strong>
|
671
|
+
</body>
|
672
|
+
</html>
|
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><div class="header"></strong>
|
680
|
+
<strong><h1>${@page_title}</h1></strong>
|
681
|
+
<strong></div></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><address></strong>
|
689
|
+
<strong>copyright(c) 2010 kuwata-lab.com all rights reserved</strong>
|
690
|
+
<strong></address></strong>
|
461
691
|
</pre>
|
462
|
-
|
463
|
-
<
|
464
|
-
|
465
|
-
<
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
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
|
+
<!DOCTYPE>
|
701
|
+
<html>
|
702
|
+
<head>
|
703
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
704
|
+
<title>Tenjin: Layout Template Example</title>
|
705
|
+
</head>
|
706
|
+
<body>
|
707
|
+
<strong><div class="header"></strong>
|
708
|
+
<strong><h1>Tenjin: Layout Template Example</h1></strong>
|
709
|
+
<strong></div></strong>
|
710
|
+
<h2>Tenjin Example</h2>
|
711
|
+
<table>
|
712
|
+
<tr class="odd">
|
713
|
+
<td>&lt;AAA&gt;</td>
|
714
|
+
</tr>
|
715
|
+
<tr class="even">
|
716
|
+
<td>B&amp;B</td>
|
717
|
+
</tr>
|
718
|
+
<tr class="odd">
|
719
|
+
<td>&quot;CCC&quot;</td>
|
720
|
+
</tr>
|
721
|
+
</table>
|
722
|
+
|
723
|
+
<strong><address></strong>
|
724
|
+
<strong>copyright(c) 2010 kuwata-lab.com all rights reserved</strong>
|
725
|
+
<strong></address></strong>
|
726
|
+
</body>
|
727
|
+
</html>
|
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 => 'Tenjin Example',
|
744
|
+
:items => ['<AAA>', 'B&B', '"CCC"'],
|
745
|
+
}
|
746
|
+
|
747
|
+
## cleate engine object
|
748
|
+
engine = Tenjin::Engine.new(:path=>['views'], <strong>:postfix=>'.rbhtml'</strong>, :layout=><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
|
+
<?rb #@ARGS _content, page_title ?>
|
760
|
+
<!DOCTYPE>
|
761
|
+
<html>
|
762
|
+
<head>
|
763
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
764
|
+
<title>${@page_title}</title>
|
765
|
+
</head>
|
766
|
+
<body>
|
767
|
+
<?rb import(<strong>:_header</strong>) ?>
|
768
|
+
#{@_content}
|
769
|
+
<?rb import(<strong>:_footer</strong>) ?>
|
770
|
+
</body>
|
771
|
+
</html>
|
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 < 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=>'views', :postfix=>'.rbhtml', :layout=>:_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
|
-
<p>
|
481
|
-
foo
|
482
|
-
3.14
|
483
|
-
true
|
484
|
-
</p>
|
485
800
|
|
486
|
-
|
487
|
-
|
488
|
-
|
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, &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
|
+
<html><body>
|
828
|
+
<h1><strong><?rb start_capture(:title) do ?></strong>Document Title<strong><?rb end ?></strong></h1>
|
829
|
+
<strong><?rb start_capture(:content) ?></strong>
|
830
|
+
<ul>
|
831
|
+
<?rb for item in list do ?>
|
832
|
+
<li>${item}</li>
|
833
|
+
<?rb end ?>
|
834
|
+
</ul>
|
835
|
+
<strong><?rb stop_capture() ?></strong>
|
836
|
+
</body></html>
|
837
|
+
</pre>
|
838
|
+
|
839
|
+
<div class="program_caption">
|
840
|
+
ex. layout.rbhtml
|
841
|
+
</div>
|
842
|
+
<pre class="program">
|
843
|
+
<?xml version="1.0" ?>
|
844
|
+
<html xml:lang="en">
|
845
|
+
<head>
|
846
|
+
<title>${<strong>@title</strong>}</title>
|
847
|
+
</head>
|
848
|
+
<body>
|
849
|
+
<h1>${<strong>@title</strong>}</h1>
|
850
|
+
<div id="content">
|
851
|
+
<?rb echo(<strong>@content</strong>) ?>
|
852
|
+
</div>
|
853
|
+
</body>
|
854
|
+
</html>
|
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
|
-
|
491
|
-
|
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
|
+
<?py ## layout template example ?>
|
872
|
+
<html>
|
873
|
+
<body>
|
874
|
+
<div id="main">
|
875
|
+
<?rb ## if captured by 'start_capture(:main)', use it. ?>
|
876
|
+
<?rb ## if not captured, use this block. ?>
|
877
|
+
<?rb if not captured_as(:main) ?>
|
878
|
+
<p>content not found</p>
|
879
|
+
<?rb end ?>
|
880
|
+
</div>
|
881
|
+
</body>
|
882
|
+
</html
|
492
883
|
</pre>
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
<
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
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 '&', '<', '>', and '"' into '&amp;', '&lt;', '&gt;', and '&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 '&<>"' 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") #=> ' checked="checked"'
|
958
|
+
checked(value=="0") #=> ''
|
501
959
|
</pre>
|
502
|
-
|
503
|
-
|
504
|
-
Result:</div>
|
505
|
-
<pre class="terminal">$ rbtenjin <strong>-f datafile.rb</strong> example4.rbhtml
|
506
|
-
<p>
|
507
|
-
foo
|
508
|
-
3.14
|
509
|
-
true
|
510
|
-
</p>
|
960
|
+
</dd>
|
961
|
+
</dl>
|
511
962
|
|
512
|
-
|
513
|
-
|
514
|
-
<p>baz</p>
|
963
|
+
<dl class="dl1">
|
964
|
+
<dt class="dt1">selected(value)</dt>
|
515
965
|
|
516
|
-
|
517
|
-
|
966
|
+
<dd class="dd1">
|
967
|
+
Return ' selected="selected" if value is true.
|
968
|
+
<pre class="program">
|
969
|
+
value = "1"
|
970
|
+
selected(value=="1") #=> ' selected="selected"'
|
971
|
+
selected(value=="0") #=> ''
|
518
972
|
</pre>
|
519
|
-
|
973
|
+
</dd>
|
974
|
+
</dl>
|
520
975
|
|
976
|
+
<dl class="dl1">
|
977
|
+
<dt class="dt1">disabled(value)</dt>
|
521
978
|
|
522
|
-
<
|
523
|
-
|
524
|
-
<
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
File 'example5.rbhtml':</div>
|
529
|
-
<pre class="program">text: #{@text}
|
530
|
-
items:
|
531
|
-
<?rb for item in @items ?>
|
532
|
-
- #{item}
|
533
|
-
<?rb end ?>
|
534
|
-
hash:
|
535
|
-
<?rb for key, val in @hash ?>
|
536
|
-
#{key}: #{val}
|
537
|
-
<?rb end ?>
|
979
|
+
<dd class="dd1">
|
980
|
+
Return ' disabled="disabled"' if value is true.
|
981
|
+
<pre class="program">
|
982
|
+
value = "1"
|
983
|
+
disabled(value=="1") #=> ' disabled="disabled"'
|
984
|
+
disabled(value=="0") #=> ''
|
538
985
|
</pre>
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
<
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
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') #=> ' name="val"'
|
996
|
+
tagattr('name', nil) #=> ''
|
997
|
+
urlpath = "/blog/"
|
998
|
+
tagattr('class', urlpath=='/blog/', 'current') #=> ' class="current"'
|
999
|
+
tagattr('class', urlpath=='/', 'current') #=> ''
|
551
1000
|
</pre>
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
<
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
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'); #=> ' name="user" value="guest"'
|
1011
|
+
nv('user', 'guest', '-'); #=> ' name="user" value="guest" id="user-guest"'
|
564
1012
|
</pre>
|
565
|
-
|
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"><html>
|
586
|
-
<body>
|
1013
|
+
</dd>
|
1014
|
+
</dl>
|
587
1015
|
|
588
|
-
|
589
|
-
<
|
590
|
-
</div>
|
1016
|
+
<dl class="dl1">
|
1017
|
+
<dt class="dt1">js_link(label, onclick, tags={}):</dt>
|
591
1018
|
|
592
|
-
|
593
|
-
<
|
594
|
-
|
595
|
-
|
596
|
-
</
|
1019
|
+
<dd class="dd1">
|
1020
|
+
Return '<a href="" onclick="onclick">label</a>' string.
|
1021
|
+
<pre class="program">
|
1022
|
+
js_link('Show', '$().show()')
|
1023
|
+
#=> '<a href="javascript:undefined" onclick="$().show();return false">Show</a>'
|
1024
|
+
js_link('Show', '$().show()', :class=>"link")
|
1025
|
+
#=> '<a href="javascript:undefined" onclick="$().show();return false" class="link">Show</a>'
|
1026
|
+
</pre>
|
1027
|
+
</dd>
|
1028
|
+
</dl>
|
597
1029
|
|
598
|
-
|
599
|
-
<
|
600
|
-
</div>
|
1030
|
+
<dl class="dl1">
|
1031
|
+
<dt class="dt1">nl2br(text)</dt>
|
601
1032
|
|
602
|
-
|
603
|
-
<
|
1033
|
+
<dd class="dd1">
|
1034
|
+
Convert "\n" into "<br />\n".
|
1035
|
+
<pre class="program">
|
1036
|
+
nl2br("foo\nbar\n") #=> "foo<br />\nbar<br />\n"
|
604
1037
|
</pre>
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
<
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
<
|
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 "<br />\n" and " &nbsp;".
|
1046
|
+
<pre class="program">
|
1047
|
+
text2html(" foo\n bar\n") #=> " &nbsp;foo<br />\n &nbsp;bar<br />\n"
|
613
1048
|
</pre>
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
<
|
618
|
-
|
619
|
-
|
620
|
-
|
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}" #=> 'odd'
|
1060
|
+
"#{cycle}" #=> 'even'
|
1061
|
+
"#{cycle}" #=> 'odd'
|
621
1062
|
</pre>
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
<
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
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 = <<END
|
1091
|
+
s1 = <strong>${@s1}</strong>
|
1092
|
+
s2 = <strong>${@s2}</strong>
|
1093
|
+
END
|
1094
|
+
|
1095
|
+
## but passed different data type
|
1096
|
+
context = {
|
1097
|
+
:s1 => "<b>SOS</b>",
|
1098
|
+
:s2 => <strong>safe_str</strong>("<b>SOS</b>"),
|
1099
|
+
}
|
1100
|
+
|
1101
|
+
## SafeTemplate will escape 's1' but not 's2'
|
1102
|
+
template = <strong>Tenjin::SafeTemplate</strong>.new(:input=>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
|
-
<html>
|
638
|
-
<body>
|
639
1107
|
|
640
|
-
|
641
|
-
<strong><ul></strong>
|
642
|
-
<strong><li><a href="/">Top</a></li></strong>
|
643
|
-
<strong><li><a href="/prod">Products</a></li></strong>
|
644
|
-
<strong><li><a href="/support">Support</a></li></strong>
|
645
|
-
<strong></ul></strong>
|
646
|
-
</div>
|
1108
|
+
<p>The follwoing output shows that:</p>
|
647
1109
|
|
648
|
-
|
649
|
-
|
650
|
-
<p>&amp;BAR</p>
|
651
|
-
<p>&quot;BAZ&quot;</p>
|
652
|
-
</div>
|
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
|
-
|
655
|
-
|
656
|
-
<strong><address></strong>
|
657
|
-
<strong> <a href="mailto:webmaster@example.com">webmaster@example.com</a></strong>
|
658
|
-
<strong></address></strong>
|
1113
|
+
<li>Normal string (= <code>"<b>SOS</b>"</code>) is escaped automatically, but the other string which is marked as escaped (= <code>safe_str("<b>SOS</b>")</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
|
-
|
1116
|
+
<div class="terminal_caption">
|
1117
|
+
Output example
|
1118
|
+
</div>
|
1119
|
+
<pre class="terminal">
|
1120
|
+
$ ruby safe-test.rb
|
1121
|
+
_buf << %Q`s1 = #{<strong>safe_escape</strong>((@s1).to_s)}
|
1122
|
+
s2 = #{<strong>safe_escape</strong>((@s2).to_s)}\n`
|
1123
|
+
---------------------
|
1124
|
+
s1 = &lt;b&gt;SOS&lt;/b&gt;
|
1125
|
+
s2 = <strong><b>SOS</b></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 = "<AAA>"
|
1187
|
+
puts safe_str?(s) #=> false
|
1188
|
+
s = safe_escape(s) # same as SafeString.new(escape(s))
|
1189
|
+
puts safe_str?(s) #=> true
|
1190
|
+
puts s #=> &lt;AAA&gt;
|
1191
|
+
puts safe_escape(s) #=> &lt;AAA&gt;
|
1192
|
+
#
|
1193
|
+
s = "<AAA>"
|
1194
|
+
s = safe_str(s) # same as SafeString.new(s)
|
1195
|
+
puts safe_str?(s) #=> true
|
1196
|
+
puts s #=> <AAA>
|
1197
|
+
puts safe_escape(s) #=> <AAA>
|
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
|
+
<html>
|
1210
|
+
<body>
|
1211
|
+
<strong>#{@_content}</strong>
|
662
1212
|
</body>
|
663
|
-
</
|
1213
|
+
</html>
|
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><?rb @_layout = '_site_layout.rbhtml' ?></strong>
|
1221
|
+
<h2>${@title}</h2>
|
1222
|
+
<!-- content -->
|
1223
|
+
<strong>#{@_content}</strong>
|
1224
|
+
<!-- /content -->
|
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><?rb @_layout = '_blog_layout.rbhtml' ?></strong>
|
1232
|
+
<div class="article">
|
1233
|
+
#{text2html(@post_content)}
|
1234
|
+
</div>
|
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=>['views'])
|
1243
|
+
context = {
|
1244
|
+
:title => 'Blog Post Test',
|
1245
|
+
:post_content => "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
|
+
<html> # by _layout.rbhtml
|
1257
|
+
<body> # :
|
1258
|
+
<h2>Blog Post Test</h2> # by _blog_layout.rbhtml
|
1259
|
+
<!-- content --> # :
|
1260
|
+
<div class="article"> # by blog_post.rbhtml
|
1261
|
+
Foo<br /> # :
|
1262
|
+
Bar<br /> # :
|
1263
|
+
Baz # :
|
1264
|
+
</div> # :
|
1265
|
+
# :
|
1266
|
+
<!-- /content --> # by _blog_layout.rbhtml
|
1267
|
+
# :
|
1268
|
+
</body> # by _layout.rbhtml
|
1269
|
+
</html> # :
|
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=>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=>'layout.rbhtml', <strong>:trace=>true</strong>)
|
1285
|
+
output = engine.render('main.rbhtml', {'items'=>['A','B','C']})
|
1286
|
+
puts output
|
664
1287
|
</pre>
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
<
|
670
|
-
|
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"><html>
|
1288
|
+
|
1289
|
+
<p>Will print:</p><a name="test_trace/result.output"></a>
|
1290
|
+
<pre class="terminal">
|
1291
|
+
$ ruby trace-example.rb
|
1292
|
+
<strong><!-- ***** begin: layout.rbhtml ***** --></strong>
|
1293
|
+
<html>
|
689
1294
|
<body>
|
1295
|
+
<div class="content">
|
1296
|
+
<strong><!-- ***** begin: main.rbhtml ***** --></strong>
|
1297
|
+
<ul>
|
1298
|
+
<li>A</li>
|
1299
|
+
<li>B</li>
|
1300
|
+
<li>C</li>
|
1301
|
+
</ul>
|
1302
|
+
<strong><!-- ***** end: main.rbhtml ***** --></strong>
|
1303
|
+
</div>
|
1304
|
+
</body>
|
1305
|
+
</html>
|
1306
|
+
<strong><!-- ***** end: layout.rbhtml ***** --></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
|
-
|
692
|
-
|
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
|
+
<h2>#{@blog_post[:title]}</h2>
|
1327
|
+
<div class="blog-post">
|
1328
|
+
#{text2html(@blog_post[:content])}
|
1329
|
+
</div>
|
1330
|
+
|
1331
|
+
<strong><?rb start_capture('sidebar') do ?></strong>
|
1332
|
+
<h3>Recent Posts</h3>
|
1333
|
+
<ul>
|
1334
|
+
<?rb for post in @recent_posts ?>
|
1335
|
+
<a href="/blog/#{post[:id]}">${post[:title]}</a>
|
1336
|
+
<?rb end ?>
|
1337
|
+
</ul>
|
1338
|
+
<strong><?rb end ?></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
|
+
<html>
|
1346
|
+
<body>
|
1347
|
+
<div id="header-part">
|
1348
|
+
<strong><?rb if ! captured_as(:header) ?></strong>
|
1349
|
+
<h1>My Great Blog</h1>
|
1350
|
+
<strong><?rb end ?></strong>
|
693
1351
|
</div>
|
694
|
-
|
695
1352
|
<div id="main-content">
|
696
|
-
|
1353
|
+
#{@_content}
|
697
1354
|
</div>
|
698
|
-
|
699
|
-
|
700
|
-
|
1355
|
+
<div id="sidebar-part">
|
1356
|
+
<strong><?rb if ! captured_as(:sidebar) ?></strong>
|
1357
|
+
<h3>Links</h3>
|
1358
|
+
<ul>
|
1359
|
+
<a href="http://google.com/">Google</a>
|
1360
|
+
<a href="http://yahoo.com/">Yahoo!</a>
|
1361
|
+
</ul>
|
1362
|
+
<strong><?rb end ?></strong>
|
701
1363
|
</div>
|
702
|
-
|
703
1364
|
</body>
|
704
|
-
</
|
705
|
-
</pre>
|
706
|
-
|
707
|
-
<div class="program_caption">
|
708
|
-
|
709
|
-
|
710
|
-
|
711
|
-
|
1365
|
+
</html>
|
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 = <<END
|
1374
|
+
Tenjin has great features.
|
1375
|
+
- Very Fast
|
1376
|
+
- Full Featured
|
1377
|
+
- Easy to Use
|
1378
|
+
END
|
1379
|
+
context = {
|
1380
|
+
:blog_post => {
|
1381
|
+
:title => 'Tenjin is Great',
|
1382
|
+
:content => post_content,
|
1383
|
+
},
|
1384
|
+
:recent_posts => [
|
1385
|
+
{:id=>1, :title=>'Tenjin is Fast' },
|
1386
|
+
{:id=>2, :title=>'Tenjin is Full-Featured' },
|
1387
|
+
{:id=>3, :title=>'Tenjin is Easy-to-Use' },
|
1388
|
+
]
|
1389
|
+
}
|
1390
|
+
|
1391
|
+
## render template
|
1392
|
+
require 'tenjin'
|
1393
|
+
engine = Tenjin::Engine.new(:path=>['views'], :layout=>'_layout.rbhtml')
|
1394
|
+
html = engine.render('blog-post.rbhtml', context)
|
1395
|
+
puts html
|
712
1396
|
</pre>
|
713
|
-
|
714
|
-
<
|
715
|
-
|
716
|
-
<
|
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
|
<html>
|
718
1406
|
<body>
|
719
|
-
|
720
|
-
|
721
|
-
<ul>
|
722
|
-
<li><a href="/">Top</a></li>
|
723
|
-
<li><a href="/prod">Products</a></li>
|
724
|
-
<li><a href="/support">Support</a></li>
|
725
|
-
</ul>
|
1407
|
+
<div id="header-part">
|
1408
|
+
<h1>My Great Blog</h1>
|
726
1409
|
</div>
|
727
|
-
|
728
1410
|
<div id="main-content">
|
729
|
-
|
730
|
-
|
731
|
-
|
1411
|
+
<h2>Tenjin is Great</h2>
|
1412
|
+
<div class="blog-post">
|
1413
|
+
Tenjin has great features.<br />
|
1414
|
+
- Very Fast<br />
|
1415
|
+
- Full Featured<br />
|
1416
|
+
- Easy to Use<br />
|
732
1417
|
|
733
|
-
|
1418
|
+
</div>
|
734
1419
|
|
735
|
-
<div id="footer">
|
736
|
-
<hr />
|
737
|
-
<address>
|
738
|
-
<a href="mailto:webmaster@example.com">webmaster@example.com</a>
|
739
|
-
</address>
|
740
1420
|
|
741
1421
|
</div>
|
742
|
-
|
1422
|
+
<div id="sidebar-part">
|
1423
|
+
<strong><h3>Recent Posts</h3></strong>
|
1424
|
+
<strong><ul></strong>
|
1425
|
+
<strong><a href="/blog/1">Tenjin is Fast</a></strong>
|
1426
|
+
<strong><a href="/blog/2">Tenjin is Full-Featured</a></strong>
|
1427
|
+
<strong><a href="/blog/3">Tenjin is Easy-to-Use</a></strong>
|
1428
|
+
<strong></ul></strong>
|
1429
|
+
</div>
|
743
1430
|
</body>
|
744
|
-
</
|
745
|
-
</pre>
|
746
|
-
<
|
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
|
-
<h1><strong>${@title}</strong></h1>
|
757
|
-
|
758
|
-
<div id="main-content">
|
759
|
-
#{@_content}
|
760
|
-
<div>
|
1431
|
+
</html>
|
1432
|
+
</pre><br>
|
1433
|
+
<a name="templace-cache" id="templace-cache"></a>
|
761
1434
|
|
762
|
-
|
763
|
-
...
|
764
|
-
</pre>
|
765
|
-
<a name="content7.rbhtml"></a>
|
766
|
-
<div class="program_caption">
|
767
|
-
File 'content7.rbhtml':</div>
|
768
|
-
<pre class="program"><strong><?rb @title = 'Document Title' ?></strong>
|
769
|
-
<strong><?rb @url = '/next/page' ?></strong>
|
770
|
-
<table>
|
771
|
-
...content...
|
772
|
-
</table>
|
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
|
-
<h1><strong>Document Title</strong></h1>
|
780
|
-
|
781
|
-
<div id="main-content">
|
782
|
-
<table>
|
783
|
-
...content...
|
784
|
-
</table>
|
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 < 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=>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
|
<div>
|
1469
|
+
<strong><?rb # fragment cache with key ('items/1') and lifetime (60sec) ?></strong>
|
1470
|
+
<strong><?rb cache_with('items/1', 60) do ?></strong>
|
1471
|
+
<ul>
|
1472
|
+
<?rb for item in @get_items.call() ?>
|
1473
|
+
<li>${item}</li>
|
1474
|
+
<?rb end ?>
|
1475
|
+
</ul>
|
1476
|
+
<strong><?rb end ?></strong>
|
1477
|
+
</div>
|
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
|
-
|
789
|
-
|
790
|
-
</
|
791
|
-
|
792
|
-
|
793
|
-
</
|
794
|
-
|
795
|
-
|
796
|
-
|
797
|
-
|
798
|
-
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
<
|
810
|
-
|
811
|
-
|
812
|
-
<pre class="
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
</
|
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 => get_items}
|
1502
|
+
|
1503
|
+
## render html
|
1504
|
+
engine = Tenjin::Engine.new(:path=>['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
|
+
<div>
|
1515
|
+
<ul>
|
1516
|
+
<li>AAA</li>
|
1517
|
+
<li>BBB</li>
|
1518
|
+
<li>CCC</li>
|
1519
|
+
</ul>
|
1520
|
+
</div>
|
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
|
+
<ul>
|
1527
|
+
<li>AAA</li>
|
1528
|
+
<li>BBB</li>
|
1529
|
+
<li>CCC</li>
|
1530
|
+
</ul>
|
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 => '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
|
-
<?xml version="1.0" encoding="UTF-8"?>
|
824
|
-
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
825
|
-
<body>
|
826
|
-
<h1>Hello World!</h1>
|
827
1556
|
|
828
|
-
|
829
|
-
|
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
|
-
<
|
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"><?rb @title = 'Capture Test' ?>
|
842
|
-
<html>
|
843
|
-
<body>
|
1571
|
+
<h3 class="section2">Preprocessing</h3>
|
844
1572
|
|
845
|
-
<
|
846
|
-
<ul>
|
847
|
-
<?rb for i in [0, 1, 2] ?>
|
848
|
-
<li>i = #{i}</li>
|
849
|
-
<?rb end ?>
|
850
|
-
</ul>
|
851
|
-
<strong><?rb stop_capture() ?></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
|
-
<
|
854
|
-
<div class="footer">copyright&copy; 2007 kuwata-lab.com</div>
|
855
|
-
<strong><?rb stop_capture() ?></strong>
|
1575
|
+
<h4 class="section3">Basics of Preprocessing</h4>
|
856
1576
|
|
857
|
-
|
858
|
-
</html>
|
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"><html lang="en">
|
872
|
-
<head>
|
873
|
-
<title>${@title}</title>
|
874
|
-
</head>
|
875
|
-
<body>
|
1577
|
+
<p>Notation of preprocessing:</p>
|
876
1578
|
|
877
|
-
|
878
|
-
<
|
879
|
-
<h1>${@title}</h1>
|
880
|
-
<strong><?rb end ?></strong>
|
881
|
-
<!-- /HEADER -->
|
1579
|
+
<dl class="dl1">
|
1580
|
+
<dt class="dt1"><code><?RB ... ?></code></dt>
|
882
1581
|
|
883
|
-
|
884
|
-
<strong>#{@content_part}</strong>
|
885
|
-
<!-- /CONTENT -->
|
1582
|
+
<dd class="dd1">Preprocessing statement.</dd>
|
886
1583
|
|
887
|
-
|
888
|
-
<strong><?rb unless captured_as('footer_part') ?></strong>
|
889
|
-
<hr />
|
890
|
-
<address>webmaster@localhost</address>
|
891
|
-
<strong><?rb end ?></strong>
|
892
|
-
<!-- /FOOTER -->
|
1584
|
+
<dt class="dt1"><code>#{{...}}</code></dt>
|
893
1585
|
|
894
|
-
|
895
|
-
</html>
|
896
|
-
</pre>
|
897
|
-
<p>'<code>unless captured_as("name") ... end</code>' is equivarent to the following.
|
898
|
-
</p>
|
899
|
-
<pre class="program"><?rb if @name ?>
|
900
|
-
<?rb _buf << @name ?>
|
901
|
-
<?rb else ?>
|
902
|
-
...
|
903
|
-
<?rb end ?>
|
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
|
-
<html lang="en">
|
912
|
-
<head>
|
913
|
-
<title>Capture Test</title>
|
914
|
-
</head>
|
915
|
-
<body>
|
1586
|
+
<dd class="dd1">Preprocessing expression (without HTML escape)</dd>
|
916
1587
|
|
917
|
-
|
918
|
-
<h1>Capture Test</h1>
|
919
|
-
<!-- /HEADER -->
|
1588
|
+
<dt class="dt1"><code>${{...}}</code></dt>
|
920
1589
|
|
921
|
-
|
922
|
-
|
923
|
-
<strong><li>i = 0</li></strong>
|
924
|
-
<strong><li>i = 1</li></strong>
|
925
|
-
<strong><li>i = 2</li></strong>
|
926
|
-
<strong></ul></strong>
|
1590
|
+
<dd class="dd1">Preprocessing expression (with HTML escape)</dd>
|
1591
|
+
</dl>
|
927
1592
|
|
928
|
-
|
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
|
-
|
931
|
-
|
932
|
-
|
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
|
-
|
935
|
-
|
936
|
-
</
|
937
|
-
<
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
<
|
955
|
-
</
|
956
|
-
|
957
|
-
<pre class="terminal"
|
958
|
-
|
959
|
-
|
960
|
-
_buf << %Q
|
961
|
-
|
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=>['views'], <strong>:preprocess=>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 << %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 << %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
|
-
<
|
965
|
-
|
966
|
-
<
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
<
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
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><?RB ... ?></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><?RB states = { "CA" => "California", ?></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><?RB ... ?></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><?RB states = { "CA" => "California", ?></strong>
|
1006
1675
|
<strong><?RB "NY" => "New York", ?></strong>
|
1007
1676
|
<strong><?RB "FL" => "Florida", ?></strong>
|
1008
1677
|
<strong><?RB "TX" => "Texas", ?></strong>
|
1009
1678
|
<strong><?RB "HI" => "Hawaii", } ?></strong>
|
1010
|
-
<?rb chk = {
|
1679
|
+
<?rb chk = { params['state'] => ' selected="selected"' } ?>
|
1011
1680
|
<select name="state">
|
1012
1681
|
<option value="">-</option>
|
1013
|
-
<strong><?RB for code in states.keys.sort ?></strong>
|
1014
|
-
<option value="<strong>#{{code}}</strong>"#{chk[<strong>#{{code
|
1015
|
-
<strong><?RB end ?></strong>
|
1682
|
+
<strong><?RB for code in states.keys.sort ?></strong>
|
1683
|
+
<option value="<strong>#{{code}}</strong>"#{chk['<strong>#{{code}}</strong>']}><strong>${{states[code]}}</strong></option>
|
1684
|
+
<strong><?RB end ?></strong>
|
1016
1685
|
</select>
|
1017
1686
|
</pre>
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
<
|
1022
|
-
|
1023
|
-
|
1024
|
-
<pre class="terminal"
|
1025
|
-
|
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
|
+
<?rb chk = { params['state'] => ' selected="selected"' } ?>
|
1026
1696
|
<select name="state">
|
1027
1697
|
<option value="">-</option>
|
1028
|
-
<option value="CA"#{chk[
|
1029
|
-
<option value="FL"#{chk[
|
1030
|
-
<option value="HI"#{chk[
|
1031
|
-
<option value="NY"#{chk[
|
1032
|
-
<option value="TX"#{chk[
|
1698
|
+
<option value="CA"#{chk['CA']}>California</option>
|
1699
|
+
<option value="FL"#{chk['FL']}>Florida</option>
|
1700
|
+
<option value="HI"#{chk['HI']}>Hawaii</option>
|
1701
|
+
<option value="NY"#{chk['NY']}>New York</option>
|
1702
|
+
<option value="TX"#{chk['TX']}>Texas</option>
|
1033
1703
|
</select>
|
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 <a></a> 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><?RB</strong>
|
1716
|
+
## ex. link_to('Show', '/show/1') => <a href="/show/1">Show</a>
|
1717
|
+
def link_to(label, url)
|
1718
|
+
return "<a href=\"#{url}\">#{label}</a>"
|
1719
|
+
end
|
1720
|
+
<strong>?></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
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
<
|
1039
|
-
|
1040
|
-
|
1041
|
-
<
|
1042
|
-
|
1043
|
-
|
1044
|
-
chk = { @params['state'] => ' selected="selected"' }
|
1045
|
-
_buf << %Q`<select name="state">
|
1046
|
-
<option value="">-</option>
|
1047
|
-
<option value="CA"#{chk["CA"]}>California</option>
|
1048
|
-
<option value="FL"#{chk["FL"]}>Florida</option>
|
1049
|
-
<option value="HI"#{chk["HI"]}>Hawaii</option>
|
1050
|
-
<option value="NY"#{chk["NY"]}>New York</option>
|
1051
|
-
<option value="TX"#{chk["TX"]}>Texas</option>
|
1052
|
-
</select>\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><a></a></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"><?RB require 'cgi' ?>
|
1067
|
-
<?RB ## ex. link_to('Show', '/show/1') => <a href="/show/1">Show</a> ?>
|
1068
|
-
<?RB def link_to(label, url) ?>
|
1069
|
-
<?RB return "<a href=\"#{CGI.unescape(url)}\">#{label}</a>" ?>
|
1070
|
-
<?RB end ?>
|
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
|
-
<a href="/items/show/<strong>#{@params["id"]}"</strong>>Show <strong>${@params["name"]}</strong></a>
|
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 << %Q`<a href="/items/show/<strong>#{@params["id"]}</strong>">Show <strong>#{escape((@params["name"]).to_s)}</strong></a>\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 << %Q`#{escape((hash[").to_s)}"]}</code>` and not '<code>_buf << %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 << %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=>'rbTenjin Example', :items=>['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=>'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"><h1>#{@title}</h1>
|
1242
|
-
<ul>
|
1243
|
-
<?rb for item in @items ?>
|
1244
|
-
<li>${item}</li>
|
1245
|
-
<?rb end ?>
|
1246
|
-
</ul>
|
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
|
+
<a href="/items/show/<strong>#{</strong>params["id"]<strong>}</strong>">Show <strong>${</strong>params["name"]<strong>}</strong></a>
|
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
|
-
|
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=>"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
|
+
<div>
|
1763
|
+
<?RB ## '_()' represents translator method ?>
|
1764
|
+
<?RB _ = @_ ?>
|
1765
|
+
<p><strong>${{_['Hello']}}</strong> ${@username}!</p>
|
1766
|
+
</div>
|
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
|
-
|
1257
|
-
##
|
1258
|
-
|
1259
|
-
|
1260
|
-
|
1261
|
-
|
1262
|
-
|
1263
|
-
|
1264
|
-
|
1265
|
-
##
|
1266
|
-
|
1267
|
-
|
1268
|
-
|
1269
|
-
##
|
1270
|
-
|
1271
|
-
|
1272
|
-
|
1273
|
-
|
1274
|
-
|
1275
|
-
|
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] = ['<AAA>','B&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 << %Q`<h1>#{@title}</h1>
|
1290
|
-
<ul>\n`
|
1291
|
-
for item in @items
|
1292
|
-
_buf << %Q` <li>#{escape((item).to_s)}</li>\n`
|
1775
|
+
|
1776
|
+
##
|
1777
|
+
## message catalog to translate message
|
1778
|
+
##
|
1779
|
+
MESSAGE_CATALOG = {
|
1780
|
+
'en' => { 'Hello'=>"Hello", 'Good bye'=>"Good bye" },
|
1781
|
+
'fr' => { 'Hello'=>"Bonjour", 'Good bye'=>"Au revoir" },
|
1782
|
+
}
|
1783
|
+
|
1784
|
+
##
|
1785
|
+
## create translation function and return it.
|
1786
|
+
## ex.
|
1787
|
+
## _ = create_m17n_obj('fr')
|
1788
|
+
## print _['Hello'] #=> '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
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
</
|
1303
|
-
|
1304
|
-
|
1305
|
-
|
1306
|
-
|
1307
|
-
|
1308
|
-
|
1309
|
-
|
1310
|
-
|
1311
|
-
|
1312
|
-
|
1313
|
-
|
1314
|
-
|
1315
|
-
|
1316
|
-
|
1317
|
-
<
|
1318
|
-
|
1319
|
-
|
1320
|
-
|
1321
|
-
|
1322
|
-
|
1323
|
-
|
1324
|
-
|
1325
|
-
|
1326
|
-
|
1327
|
-
|
1328
|
-
|
1329
|
-
|
1330
|
-
|
1331
|
-
|
1332
|
-
|
1333
|
-
<
|
1334
|
-
|
1335
|
-
|
1336
|
-
</
|
1337
|
-
|
1338
|
-
|
1339
|
-
|
1340
|
-
<
|
1341
|
-
|
1342
|
-
|
1343
|
-
|
1344
|
-
|
1345
|
-
|
1346
|
-
</
|
1347
|
-
|
1348
|
-
|
1349
|
-
|
1350
|
-
<
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
</
|
1362
|
-
|
1363
|
-
<
|
1364
|
-
|
1365
|
-
<
|
1366
|
-
|
1367
|
-
</
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
</
|
1378
|
-
|
1379
|
-
|
1380
|
-
<
|
1381
|
-
<
|
1382
|
-
|
1383
|
-
<
|
1796
|
+
|
1797
|
+
##
|
1798
|
+
## test program
|
1799
|
+
##
|
1800
|
+
if __FILE__ == $0
|
1801
|
+
## render html for English
|
1802
|
+
engine_en = Tenjin::Engine.new(:preprocess=>true, <strong>:lang=>'en'</strong>)
|
1803
|
+
context = { :username => '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=>true, <strong>:lang=>'fr'</strong>)
|
1811
|
+
context = { :username => '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
|
+
<div>
|
1826
|
+
<p><strong>Hello</strong> World!</p>
|
1827
|
+
</div>
|
1828
|
+
--- lang: fr ---
|
1829
|
+
<div>
|
1830
|
+
<p><strong>Bonjour</strong> World!</p>
|
1831
|
+
</div>
|
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 << %Q`<div>
|
1848
|
+
<p><strong>Hello</strong> #{escape((@username).to_s)}!</p>
|
1849
|
+
</div>\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 << %Q`<div>
|
1858
|
+
<p><strong>Bonjour</strong> #{escape((@username).to_s)}!</p>
|
1859
|
+
</div>\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=>['views'], <strong>:escapefunc=>'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
|
<p>
|
1385
|
-
|
1386
|
-
|
1387
|
-
Gender:
|
1388
|
-
<?rb gender = @params['gender'] ?>
|
1389
|
-
<?rb chk = { true=>' checked="checked"', false=>'' } ?>
|
1390
|
-
<input type="radio" name="gender" value="m" #{chk[gender=='m']} />Male
|
1391
|
-
<input type="radio" name="gender" value="f" #{chk[gender=='f']} />Female
|
1906
|
+
escaped: ${@value}
|
1907
|
+
not escaped: #{@value}
|
1392
1908
|
</p>
|
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 << %Q`<p>
|
1917
|
+
escaped: #{<strong>ERB::Util.h</strong>((@value).to_s)}
|
1918
|
+
not escaped: #{@value}
|
1919
|
+
</p>\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
|
+
<ul>
|
1950
|
+
<?rb for item in items ?>
|
1951
|
+
<li>${item}</li>
|
1952
|
+
<?rb <strong>ende</strong> ?>
|
1953
|
+
</ul>
|
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"><?rb #@ARGS ?>
|
1398
|
-
<form action="user_app.cgi" method="post">
|
1399
|
-
<input type="hidden" name="action" value="create" />
|
1400
|
-
<strong><?rb import :form ?></strong>
|
1401
|
-
<input type="submit" value="Create" />
|
1402
|
-
</form>
|
1403
|
-
</pre>
|
1404
|
-
<a name="user_edit.rbhtml"></a>
|
1405
|
-
<div class="program_caption">
|
1406
|
-
File 'user_edit.rbhtml':</div>
|
1407
|
-
<pre class="program"><?rb #@ARGS params ?>
|
1408
|
-
<form action="user_app.cgi" method="post">
|
1409
|
-
<input type="hidden" name="action" value="edit" />
|
1410
|
-
<input type="hidden" name="id" value="${params['id']}" />
|
1411
|
-
<strong><?rb import :form ?></strong>
|
1412
|
-
<input type="submit" value="Edit" />
|
1413
|
-
</form>
|
1414
|
-
</pre>
|
1415
|
-
<a name="user_layout.rbhtml"></a>
|
1416
|
-
<div class="program_caption">
|
1417
|
-
File 'user_layout.rbhtml':</div>
|
1418
|
-
<pre class="program"><?rb #@ARGS _content, title ?>
|
1419
|
-
<html>
|
1420
|
-
<body>
|
1421
1963
|
|
1422
|
-
|
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
|
-
|
1425
|
-
<
|
1426
|
-
</div>
|
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
|
-
|
1429
|
-
<strong><?rb import 'footer.html' ?></strong>
|
1430
|
-
</div>
|
1969
|
+
<h3 class="section2">Convert Template into Ruby Script</h3>
|
1431
1970
|
|
1432
|
-
|
1433
|
-
|
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
|
+
<ul>
|
1978
|
+
<?rb for item in @items ?>
|
1979
|
+
<li>${item}</li>
|
1980
|
+
<?rb end ?>
|
1981
|
+
</ul>
|
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 << %Q`<ul>\n`
|
1990
|
+
for item in @items
|
1991
|
+
_buf << %Q` <li>#{escape((item).to_s)}</li>\n`
|
1992
|
+
end
|
1993
|
+
_buf << %Q`</ul>\n`
|
1994
|
+
_buf.to_s
|
1434
1995
|
</pre>
|
1435
|
-
|
1436
|
-
<
|
1437
|
-
|
1438
|
-
<
|
1439
|
-
|
1440
|
-
|
1441
|
-
|
1442
|
-
|
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 << %Q`<ul>\n`
|
2005
|
+
for item in @items
|
2006
|
+
_buf << %Q` <li>#{escape((item).to_s)}</li>\n`
|
2007
|
+
end
|
2008
|
+
_buf << %Q`</ul>\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
|
+
<table>
|
2025
|
+
<?rb i = 0 ?>
|
2026
|
+
<?rb for item in @items ?>
|
2027
|
+
<?rb i += 1 ?>
|
2028
|
+
<tr>
|
2029
|
+
<td>#{i}</td>
|
2030
|
+
<td>${item}</td>
|
2031
|
+
</tr>
|
2032
|
+
<?rb end ?>
|
2033
|
+
</table>
|
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
|
-
|
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
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
params = {}
|
1467
|
-
else
|
1468
|
-
title = 'Edit User'
|
1469
|
-
params = {:name=>'Margalette',
|
1470
|
-
:email=>'meg@example.com',
|
1471
|
-
:gender=>'f',
|
1472
|
-
:id=>123 }
|
1473
|
-
end
|
1474
|
-
<strong>context = { :title=>title, :params=>params }</strong>
|
1475
|
-
<strong># or context = Tenjin::Context.new(:title=>title, :params=>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=>'user_', :postfix=>'.rbhtml', :layout=>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
|
-
<html>
|
1492
|
-
<body>
|
1493
2054
|
|
1494
|
-
|
2055
|
+
<p>Option '-X' (or '-a statements') retrieves only statements.</p><a name="test_retrieve/result2.output"></a>
|
1495
2056
|
|
1496
|
-
|
1497
|
-
|
1498
|
-
|
1499
|
-
<
|
1500
|
-
|
1501
|
-
<strong> Email: <input type="text" name="email" value="" /><br /></strong>
|
1502
|
-
<strong> Gender:</strong>
|
1503
|
-
<strong> <input type="radio" name="gender" value="m" />Male</strong>
|
1504
|
-
<strong> <input type="radio" name="gender" value="f" />Female</strong>
|
1505
|
-
<strong></p></strong>
|
1506
|
-
<strong> <input type="submit" value="Create" /></strong>
|
1507
|
-
<strong></form></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
|
-
|
2063
|
+
i = 0
|
2064
|
+
for item in @items
|
2065
|
+
i += 1
|
1510
2066
|
|
1511
|
-
<div id="footer">
|
1512
|
-
<strong><hr /></strong>
|
1513
|
-
<strong><address></strong>
|
1514
|
-
<strong> <a href="mailto:webmaster@example.com">webmaster@example.com</a></strong>
|
1515
|
-
<strong></address></strong>
|
1516
|
-
</div>
|
1517
2067
|
|
1518
|
-
|
1519
|
-
|
2068
|
+
|
2069
|
+
|
2070
|
+
end
|
2071
|
+
|
1520
2072
|
</pre>
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
<
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
<pre class="program">require 'tenjin'
|
1540
|
-
filename = 'example14.rbhtml'
|
1541
|
-
template = Tenjin::Template.new(filename, <strong>:escapefunc=>'CGI.escapeHTML'</strong>)
|
1542
|
-
print template.script, "\n"
|
1543
|
-
|
1544
|
-
require 'cgi'
|
1545
|
-
title = 'rbTenjin Example'
|
1546
|
-
items = ['<foo>', '&bar', '"baz"']
|
1547
|
-
output = template.render(:title=>title, :items=>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 << %Q`<h1>#{@title}</h1>
|
1555
|
-
<ul>\n`
|
1556
|
-
for item in @items
|
1557
|
-
_buf << %Q` <li>#{<strong>CGI.escapeHTML</strong>((item).to_s)}</li>\n`
|
1558
|
-
end
|
1559
|
-
_buf << %Q`</ul>\n`
|
1560
2092
|
|
1561
|
-
|
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
|
+
<?rb @items = ['<AAA>', 'B&B', '"CCC"'] ?>
|
1562
2132
|
<ul>
|
1563
|
-
|
1564
|
-
|
1565
|
-
|
2133
|
+
<?rb for item in @items ?>
|
2134
|
+
<li>${item}</li>
|
2135
|
+
<?rb end ?>
|
1566
2136
|
</ul>
|
1567
|
-
</pre>
|
1568
|
-
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
<
|
1573
|
-
|
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"><?rb #@ARGS label, url ?>
|
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
|
<ul>
|
1582
|
-
<li>
|
2145
|
+
<li>&lt;AAA&gt;</li>
|
2146
|
+
<li>B&amp;B</li>
|
2147
|
+
<li>&quot;CCC&quot;</li>
|
1583
2148
|
</ul>
|
1584
|
-
</pre>
|
1585
|
-
<
|
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
|
-
|
1593
|
-
return "<a href=\"#{escape_xml(url)}\">#{escape_xml(label)}</a>"
|
1594
|
-
end
|
2152
|
+
<h3 class="section2">Context Data</h3>
|
1595
2153
|
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1600
|
-
</
|
1601
|
-
<
|
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
|
<ul>
|
1606
|
-
<
|
2161
|
+
<?rb for item in @items ?>
|
2162
|
+
<li>${item}</li>
|
2163
|
+
<?rb end ?>
|
1607
2164
|
</ul>
|
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 "<a href=\"#{escape_xml(url)}\">#{escape_xml(label)}</a>"
|
1620
|
-
end
|
1621
|
-
<strong>end</strong>
|
2165
|
+
</pre><a name="test_context/result1.output"></a>
|
1622
2166
|
|
1623
|
-
|
1624
|
-
|
1625
|
-
|
1626
|
-
|
1627
|
-
</
|
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
|
<ul>
|
1633
|
-
<li>
|
2173
|
+
<li>A</li>
|
2174
|
+
<li>B</li>
|
2175
|
+
<li>C</li>
|
1634
2176
|
</ul>
|
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 < Tenjin::Context</strong>
|
1644
|
-
def link_to(label, url)
|
1645
|
-
return "<a href=\"#{escape_xml(url)}\">#{escape_xml(label)}</a>"
|
1646
|
-
end
|
1647
|
-
<strong>end</strong>
|
1648
2178
|
|
1649
|
-
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1657
|
-
<
|
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
|
<ul>
|
1659
|
-
<li>
|
2189
|
+
<li>A</li>
|
2190
|
+
<li>B</li>
|
2191
|
+
<li>C</li>
|
1660
2192
|
</ul>
|
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 "<a href=\"#{escape(url)}\">#{escape(label)}</a>"
|
1675
|
-
end
|
1676
2194
|
|
1677
|
-
|
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
|
-
|
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
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
<
|
1697
|
-
|
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
|
<ul>
|
1700
|
-
<li>
|
2214
|
+
<li>AAA</li>
|
2215
|
+
<li>123</li>
|
2216
|
+
<li>true</li>
|
1701
2217
|
</ul>
|
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
|
+
<ul>
|
2236
|
+
<li>AAA</li>
|
2237
|
+
<li>123</li>
|
2238
|
+
<li>true</li>
|
2239
|
+
</ul>
|
2240
|
+
</pre><br>
|
2241
|
+
<br>
|
2242
|
+
<a name="shooting" id="shooting"></a>
|
1705
2243
|
|
1706
|
-
<
|
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
|
-
<
|
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
|
-
|
2255
|
+
<p>(not documented yet)</p><br>
|
2256
|
+
</div>
|
1731
2257
|
</blockquote>
|
1732
|
-
|
1733
|
-
</body>
|
2258
|
+
</body>
|
1734
2259
|
</html>
|