tenjin 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.txt +54 -0
  3. data/benchmark/bench.rb +502 -0
  4. data/benchmark/bench_context.rb +17 -0
  5. data/benchmark/bench_context.yaml +141 -0
  6. data/benchmark/templates/_footer.html +4 -0
  7. data/benchmark/templates/_header.html +52 -0
  8. data/benchmark/templates/bench_eruby.rhtml +29 -0
  9. data/benchmark/templates/bench_tenjin.rbhtml +29 -0
  10. data/bin/rbtenjin +449 -0
  11. data/doc-api/classes/Tenjin.html +141 -0
  12. data/doc-api/classes/Tenjin/ArrayBufferTemplate.html +270 -0
  13. data/doc-api/classes/Tenjin/BaseContext.html +312 -0
  14. data/doc-api/classes/Tenjin/Context.html +126 -0
  15. data/doc-api/classes/Tenjin/ContextHelper.html +433 -0
  16. data/doc-api/classes/Tenjin/Engine.html +616 -0
  17. data/doc-api/classes/Tenjin/ErubisTemplate.html +166 -0
  18. data/doc-api/classes/Tenjin/HtmlHelper.html +359 -0
  19. data/doc-api/classes/Tenjin/Preprocessor.html +242 -0
  20. data/doc-api/classes/Tenjin/Template.html +916 -0
  21. data/doc-api/created.rid +1 -0
  22. data/doc-api/files/README_txt.html +185 -0
  23. data/doc-api/files/lib/tenjin_rb.html +136 -0
  24. data/doc-api/fr_class_index.html +36 -0
  25. data/doc-api/fr_file_index.html +28 -0
  26. data/doc-api/fr_method_index.html +89 -0
  27. data/doc-api/index.html +24 -0
  28. data/doc-api/rdoc-style.css +208 -0
  29. data/doc/docstyle.css +188 -0
  30. data/doc/examples.html +312 -0
  31. data/doc/faq.html +909 -0
  32. data/doc/users-guide.html +1691 -0
  33. data/lib/tenjin.rb +959 -0
  34. data/setup.rb +1331 -0
  35. data/tenjin.gemspec +58 -0
  36. data/test/assert-text-equal.rb +45 -0
  37. data/test/data/examples/form/create.rbhtml +4 -0
  38. data/test/data/examples/form/form.rbhtml +14 -0
  39. data/test/data/examples/form/layout.rbhtml +8 -0
  40. data/test/data/examples/form/main.rb +9 -0
  41. data/test/data/examples/form/main.result +21 -0
  42. data/test/data/examples/form/update.rbhtml +4 -0
  43. data/test/data/examples/preprocessing/helper.rb +16 -0
  44. data/test/data/examples/preprocessing/main.rb +11 -0
  45. data/test/data/examples/preprocessing/main.result +17 -0
  46. data/test/data/examples/preprocessing/select.rbhtml +15 -0
  47. data/test/data/examples/preprocessing/select_P.result +18 -0
  48. data/test/data/examples/table/table.rb +9 -0
  49. data/test/data/examples/table/table.rbhtml +16 -0
  50. data/test/data/examples/table/table.result +20 -0
  51. data/test/data/examples/table/table_s.result +18 -0
  52. data/test/data/faq/ex1.rbhtml +5 -0
  53. data/test/data/faq/ex10-baselayout.rbhtml +27 -0
  54. data/test/data/faq/ex10-content.rbhtml +12 -0
  55. data/test/data/faq/ex10-customlayout.rbhtml +11 -0
  56. data/test/data/faq/ex10_inherit.result +25 -0
  57. data/test/data/faq/ex11-bench.rb +28 -0
  58. data/test/data/faq/ex11-content.rbhtml +9 -0
  59. data/test/data/faq/ex11-layout1.rbhtml +5 -0
  60. data/test/data/faq/ex11-layout2.rbhtml +6 -0
  61. data/test/data/faq/ex11.rb +5 -0
  62. data/test/data/faq/ex11.rbhtml +8 -0
  63. data/test/data/faq/ex11.source +11 -0
  64. data/test/data/faq/ex11_arraybuffer.result +15 -0
  65. data/test/data/faq/ex1_chksyntax.result +3 -0
  66. data/test/data/faq/ex2-content.rbhtml +3 -0
  67. data/test/data/faq/ex2-layout.rbhtml +11 -0
  68. data/test/data/faq/ex2_removenl.result +19 -0
  69. data/test/data/faq/ex3.rb +4 -0
  70. data/test/data/faq/ex3.rbhtml +1 -0
  71. data/test/data/faq/ex3_escapefunc1.result +2 -0
  72. data/test/data/faq/ex3_escapefunc2.result +2 -0
  73. data/test/data/faq/ex5.rbhtml +7 -0
  74. data/test/data/faq/ex5_template_args.source +9 -0
  75. data/test/data/faq/ex6-content.rhtml +6 -0
  76. data/test/data/faq/ex6-layout.rhtml +6 -0
  77. data/test/data/faq/ex6.rb +10 -0
  78. data/test/data/faq/ex6_eruby.result +12 -0
  79. data/test/data/faq/ex7-expr-pattern.rb +34 -0
  80. data/test/data/faq/ex7-expr-pattern.rbhtml +3 -0
  81. data/test/data/faq/ex7_expr_pattern.result +4 -0
  82. data/test/data/faq/ex8-m18n.rb +77 -0
  83. data/test/data/faq/ex8-m18n.rbhtml +4 -0
  84. data/test/data/faq/ex8_m18n.result +10 -0
  85. data/test/data/faq/ex9-baselayout.rbhtml +8 -0
  86. data/test/data/faq/ex9-content.rbhtml +6 -0
  87. data/test/data/faq/ex9-mylayout.rbhtml +5 -0
  88. data/test/data/faq/ex9_changelayout.result +11 -0
  89. data/test/data/users_guide/content6.rbhtml +3 -0
  90. data/test/data/users_guide/content7.rbhtml +5 -0
  91. data/test/data/users_guide/content8.rbhtml +2 -0
  92. data/test/data/users_guide/contextdata.rb +7 -0
  93. data/test/data/users_guide/datafile.rb +5 -0
  94. data/test/data/users_guide/datafile.yaml +10 -0
  95. data/test/data/users_guide/ex.rbhtml +6 -0
  96. data/test/data/users_guide/ex.result +7 -0
  97. data/test/data/users_guide/ex.script +5 -0
  98. data/test/data/users_guide/ex_script.result +7 -0
  99. data/test/data/users_guide/ex_source.result +8 -0
  100. data/test/data/users_guide/example1.rbhtml +12 -0
  101. data/test/data/users_guide/example1.result +17 -0
  102. data/test/data/users_guide/example10.rbhtml +4 -0
  103. data/test/data/users_guide/example10_template_args.result +6 -0
  104. data/test/data/users_guide/example11.rbhtml +5 -0
  105. data/test/data/users_guide/example11_template_args_result +2 -0
  106. data/test/data/users_guide/example12.rbhtml +12 -0
  107. data/test/data/users_guide/example12_preprocessed.result +10 -0
  108. data/test/data/users_guide/example12_preprocessed_source.result +10 -0
  109. data/test/data/users_guide/example13.rbhtml +6 -0
  110. data/test/data/users_guide/example13_preprocessed.result +2 -0
  111. data/test/data/users_guide/example13_preprocessed_source.result +2 -0
  112. data/test/data/users_guide/example14.rb +32 -0
  113. data/test/data/users_guide/example14.rbhtml +6 -0
  114. data/test/data/users_guide/example14_tmplclass.result +15 -0
  115. data/test/data/users_guide/example15.rb +10 -0
  116. data/test/data/users_guide/example15_escapefunc.result +14 -0
  117. data/test/data/users_guide/example16.rbhtml +4 -0
  118. data/test/data/users_guide/example16a.rb +10 -0
  119. data/test/data/users_guide/example16a.result +4 -0
  120. data/test/data/users_guide/example16b.rb +13 -0
  121. data/test/data/users_guide/example16b.result +4 -0
  122. data/test/data/users_guide/example16c.rb +12 -0
  123. data/test/data/users_guide/example16c.result +4 -0
  124. data/test/data/users_guide/example1_S.result +14 -0
  125. data/test/data/users_guide/example1_SXNC.result +10 -0
  126. data/test/data/users_guide/example1_source.result +14 -0
  127. data/test/data/users_guide/example2.rbhtml +3 -0
  128. data/test/data/users_guide/example2_sb.result2 +9 -0
  129. data/test/data/users_guide/example3.rbhtml +5 -0
  130. data/test/data/users_guide/example3_syntaxcheck.result +2 -0
  131. data/test/data/users_guide/example4.rbhtml +13 -0
  132. data/test/data/users_guide/example4_datafile_rb.result +13 -0
  133. data/test/data/users_guide/example4_yaml.result +13 -0
  134. data/test/data/users_guide/example5.rbhtml +9 -0
  135. data/test/data/users_guide/example5_datastr_rb.result +9 -0
  136. data/test/data/users_guide/example5_datastr_yaml.result +9 -0
  137. data/test/data/users_guide/example6.rbhtml +19 -0
  138. data/test/data/users_guide/example6_layout.result +29 -0
  139. data/test/data/users_guide/example6_nested.result +28 -0
  140. data/test/data/users_guide/example7_layout2.result +13 -0
  141. data/test/data/users_guide/example8_layout3.result +8 -0
  142. data/test/data/users_guide/example9.rbhtml +18 -0
  143. data/test/data/users_guide/example9_capture.result +26 -0
  144. data/test/data/users_guide/footer.html +5 -0
  145. data/test/data/users_guide/footer.rbhtml +4 -0
  146. data/test/data/users_guide/layout6.rbhtml +17 -0
  147. data/test/data/users_guide/layout7.rbhtml +9 -0
  148. data/test/data/users_guide/layout8_html.rbhtml +5 -0
  149. data/test/data/users_guide/layout8_xhtml.rbhtml +6 -0
  150. data/test/data/users_guide/layout9.rbhtml +25 -0
  151. data/test/data/users_guide/sidemenu.rbhtml +5 -0
  152. data/test/data/users_guide/user_app.cgi +39 -0
  153. data/test/data/users_guide/user_app.result +30 -0
  154. data/test/data/users_guide/user_create.rbhtml +6 -0
  155. data/test/data/users_guide/user_edit.rbhtml +7 -0
  156. data/test/data/users_guide/user_form.rbhtml +10 -0
  157. data/test/data/users_guide/user_layout.rbhtml +16 -0
  158. data/test/test_all.rb +23 -0
  159. data/test/test_engine.rb +526 -0
  160. data/test/test_engine.yaml +2039 -0
  161. data/test/test_examples.rb +81 -0
  162. data/test/test_faq.rb +60 -0
  163. data/test/test_htmlhelper.rb +78 -0
  164. data/test/test_main.rb +564 -0
  165. data/test/test_main.yaml +174 -0
  166. data/test/test_template.rb +113 -0
  167. data/test/test_template.yaml +1244 -0
  168. data/test/test_users_guide.rb +75 -0
  169. data/test/testcase-helper.rb +166 -0
  170. metadata +226 -0
@@ -0,0 +1,17 @@
1
+ require 'yaml'
2
+
3
+ class StockInfo
4
+ def initialize(values={})
5
+ @name = values['name']
6
+ @name2 = values['name2']
7
+ @url = values['url']
8
+ @symbol = values['symbol']
9
+ @price = values['price']
10
+ @change = values['change']
11
+ @ratio = values['ratio']
12
+ end
13
+ attr_accessor :name, :name2, :url, :symbol, :price, :change, :ratio
14
+ end
15
+
16
+ ydoc = YAML.load_file('bench_context.yaml')
17
+ @list = ydoc['list'].collect { |values| StockInfo.new(values) }
@@ -0,0 +1,141 @@
1
+ list:
2
+ - name: Adobe Systems
3
+ name2: Adobe Systems Inc.
4
+ url: http://www.adobe.com
5
+ symbol: ADBE
6
+ price: 39.26
7
+ change: 0.13
8
+ ratio: 0.33
9
+ - name: Advanced Micro Devices
10
+ name2: Advanced Micro Devices Inc.
11
+ url: http://www.amd.com
12
+ symbol: AMD
13
+ price: 16.22
14
+ change: 0.17
15
+ ratio: 1.06
16
+ - name: Amazon.com
17
+ name2: Amazon.com Inc
18
+ url: http://www.amazon.com
19
+ symbol: AMZN
20
+ price: 36.85
21
+ change: -0.23
22
+ ratio: -0.62
23
+ - name: Apple
24
+ name2: Apple Inc.
25
+ url: http://www.apple.com
26
+ symbol: AAPL
27
+ price: 85.38
28
+ change: -0.87
29
+ ratio: -1.01
30
+ - name: BEA Systems
31
+ name2: BEA Systems Inc.
32
+ url: http://www.bea.com
33
+ symbol: BEAS
34
+ price: 12.46
35
+ change: 0.09
36
+ ratio: 0.73
37
+ - name: CA
38
+ name2: CA, Inc.
39
+ url: http://www.ca.com
40
+ symbol: CA
41
+ price: 24.66
42
+ change: 0.38
43
+ ratio: 1.57
44
+ - name: Cisco Systems
45
+ name2: Cisco Systems Inc.
46
+ url: http://www.cisco.com
47
+ symbol: CSCO
48
+ price: 26.35
49
+ change: 0.13
50
+ ratio: 0.5
51
+ - name: Dell
52
+ name2: Dell Corp.
53
+ url: http://www.dell.com/
54
+ symbol: DELL
55
+ price: 23.73
56
+ change: -0.42
57
+ ratio: -1.74
58
+ - name: eBay
59
+ name2: eBay Inc.
60
+ url: http://www.ebay.com
61
+ symbol: EBAY
62
+ price: 31.65
63
+ change: -0.8
64
+ ratio: -2.47
65
+ - name: Google
66
+ name2: Google Inc.
67
+ url: http://www.google.com
68
+ symbol: GOOG
69
+ price: 495.84
70
+ change: 7.75
71
+ ratio: 1.59
72
+ - name: Hewlett-Packard
73
+ name2: Hewlett-Packard Co.
74
+ url: http://www.hp.com
75
+ symbol: HPQ
76
+ price: 41.69
77
+ change: -0.02
78
+ ratio: -0.05
79
+ - name: IBM
80
+ name2: International Business Machines Corp.
81
+ url: http://www.ibm.com
82
+ symbol: IBM
83
+ price: 97.45
84
+ change: -0.06
85
+ ratio: -0.06
86
+ - name: Intel
87
+ name2: Intel Corp.
88
+ url: http://www.intel.com
89
+ symbol: INTC
90
+ price: 20.53
91
+ change: -0.07
92
+ ratio: -0.34
93
+ - name: Juniper Networks
94
+ name2: Juniper Networks, Inc
95
+ url: http://www.juniper.net/
96
+ symbol: JNPR
97
+ price: 18.96
98
+ change: 0.5
99
+ ratio: 2.71
100
+ - name: Microsoft
101
+ name2: Microsoft Corp
102
+ url: http://www.microsoft.com
103
+ symbol: MSFT
104
+ price: 30.6
105
+ change: 0.15
106
+ ratio: 0.49
107
+ - name: Oracle
108
+ name2: Oracle Corp.
109
+ url: http://www.oracle.com
110
+ symbol: ORCL
111
+ price: 17.15
112
+ change: 0.17
113
+ ratio: 1.0
114
+ - name: SAP
115
+ name2: SAP AG
116
+ url: http://www.sap.com
117
+ symbol: SAP
118
+ price: 46.2
119
+ change: -0.16
120
+ ratio: -0.35
121
+ - name: Seagate Technology
122
+ name2: Seagate Technology
123
+ url: http://www.seagate.com/
124
+ symbol: STX
125
+ price: 27.35
126
+ change: -0.36
127
+ ratio: -1.3
128
+ - name: Sun Microsystems
129
+ name2: Sun Microsystems Inc.
130
+ url: http://www.sun.com
131
+ symbol: SUNW
132
+ price: 6.33
133
+ change: -0.01
134
+ ratio: -0.16
135
+ - name: Yahoo
136
+ name2: Yahoo! Inc.
137
+ url: http://www.yahoo.com
138
+ symbol: YHOO
139
+ price: 28.04
140
+ change: -0.17
141
+ ratio: -0.6
@@ -0,0 +1,4 @@
1
+ </table>
2
+
3
+ </body>
4
+ </html>
@@ -0,0 +1,52 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
5
+ <head>
6
+ <title>Stock Prices</title>
7
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
8
+ <meta http-equiv="Content-Style-Type" content="text/css" />
9
+ <meta http-equiv="Content-Script-Type" content="text/javascript" />
10
+ <link rel="shortcut icon" href="/images/favicon.ico" />
11
+ <link rel="stylesheet" type="text/css" href="/css/style.css" media="all" />
12
+ <script type="text/javascript" src="/js/util.js"></script>
13
+ <style type="text/css">
14
+ /*<![CDATA[*/
15
+
16
+ body {
17
+ color: #333333;
18
+ line-height: 150%;
19
+ }
20
+
21
+ thead {
22
+ font-weight: bold;
23
+ background-color: #CCCCCC;
24
+ }
25
+
26
+ .odd {
27
+ background-color: #FFCCCC;
28
+ }
29
+
30
+ .even {
31
+ background-color: #CCCCFF;
32
+ }
33
+
34
+ .minus {
35
+ color: #FF0000;
36
+ }
37
+
38
+ /*]]>*/
39
+ </style>
40
+
41
+ </head>
42
+
43
+ <body>
44
+
45
+ <h1>Stock Prices</h1>
46
+
47
+ <table>
48
+ <thead>
49
+ <tr>
50
+ <th>#</th><th>symbol</th><th>name</th><th>price</th><th>change</th><th>ratio</th>
51
+ </tr>
52
+ </thead>
@@ -0,0 +1,29 @@
1
+ <tbody>
2
+ <%
3
+ n = 0
4
+ for item in list
5
+ n += 1
6
+ %>
7
+ <tr class="<%= n % 2 == 0 ? 'even' : 'odd' %>">
8
+ <td style="text-align: center"><%= n %></td>
9
+ <td>
10
+ <a href="/stocks/<%= item['symbol'] %>"><%= item['symbol'] %></a>
11
+ </td>
12
+ <td>
13
+ <a href="<%= item['url'] %>"><%= item['name'] %></a>
14
+ </td>
15
+ <td>
16
+ <strong><%= item['price'] %></strong>
17
+ </td>
18
+ <% if item['change'] < 0.0 %>
19
+ <td class="minus"><%= item['change'] %></td>
20
+ <td class="minus"><%= item['ratio'] %></td>
21
+ <% else %>
22
+ <td><%= item['change'] %></td>
23
+ <td><%= item['ratio'] %></td>
24
+ <% end %>
25
+ </tr>
26
+ <%
27
+ end
28
+ %>
29
+ </tbody>
@@ -0,0 +1,29 @@
1
+ <tbody>
2
+ <?rb
3
+ n = 0
4
+ for item in @list
5
+ n += 1
6
+ ?>
7
+ <tr class="#{n % 2 == 0 ? 'even' : 'odd'}">
8
+ <td style="text-align: center">#{n}</td>
9
+ <td>
10
+ <a href="/stocks/#{item['symbol']}">#{item['symbol']}</a>
11
+ </td>
12
+ <td>
13
+ <a href="#{item['url']}">#{item['name']}</a>
14
+ </td>
15
+ <td>
16
+ <strong>#{item['price']}</strong>
17
+ </td>
18
+ <?rb if item['change'] < 0.0 ?>
19
+ <td class="minus">#{item['change']}</td>
20
+ <td class="minus">#{item['ratio']}</td>
21
+ <?rb else ?>
22
+ <td>#{item['change']}</td>
23
+ <td>#{item['ratio']}</td>
24
+ <?rb end ?>
25
+ </tr>
26
+ <?rb
27
+ end
28
+ ?>
29
+ </tbody>
data/bin/rbtenjin ADDED
@@ -0,0 +1,449 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ ##
4
+ ## copyright(c) 2007 kuwata-lab all rights reserved.
5
+ ##
6
+ ## Permission is hereby granted, free of charge, to any person obtaining
7
+ ## a copy of this software and associated documentation files (the
8
+ ## "Software"), to deal in the Software without restriction, including
9
+ ## without limitation the rights to use, copy, modify, merge, publish,
10
+ ## distribute, sublicense, and/or sell copies of the Software, and to
11
+ ## permit persons to whom the Software is furnished to do so, subject to
12
+ ## the following conditions:
13
+ ##
14
+ ## The above copyright notice and this permission notice shall be
15
+ ## included in all copies or substantial portions of the Software.
16
+ ##
17
+ ## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ ## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ ## MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ ## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ ## LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ ## OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ ## WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ ##
25
+
26
+ ## $Rev: 59 $
27
+ ## $Release: 0.6.0 $
28
+
29
+ require 'tenjin'
30
+
31
+ module Tenjin
32
+
33
+
34
+ module NoTextModule
35
+
36
+ def initialize(*args)
37
+ @noexpr = args[-1].is_a?(Hash) ? args[-1].delete(:noexpr) : nil
38
+ super
39
+ end
40
+
41
+ def start_text_part()
42
+ nil
43
+ end
44
+
45
+ def stop_text_part()
46
+ nil
47
+ end
48
+
49
+ def add_text(text, encode_newline=false)
50
+ return unless text && !text.empty?
51
+ n = text.count("\n")
52
+ n -= 1 if encode_newline && text[-1] == ?\n
53
+ @script << (@newline * n)
54
+ end
55
+
56
+ ## add expression code
57
+ def add_expr(code, flag_escape=nil)
58
+ return if !code || code.empty?
59
+ if @noexpr
60
+ @script << (@newline * code.count("\n"))
61
+ elsif flag_escape
62
+ #@script << "_buf << %Q`\#{#{@escapefunc}((#{code}).to_s)}`"
63
+ @script << "#{@escapefunc}((#{code}).to_s); "
64
+ else
65
+ #@script << "_buf << %Q`\#{#{code}}`"
66
+ @script << "#{code}; "
67
+ end
68
+ end
69
+
70
+ end
71
+
72
+
73
+ class NoTextTemplate < Template
74
+ include NoTextModule
75
+ end
76
+
77
+
78
+ class CommandOptionError < StandardError
79
+ end
80
+
81
+
82
+ class Main
83
+
84
+
85
+ def self.main()
86
+ begin
87
+ output = self.new().execute()
88
+ print output if output
89
+ exit(0)
90
+ rescue CommandOptionError => ex
91
+ $stderr.puts ex.message
92
+ exit(1)
93
+ end
94
+ end
95
+
96
+
97
+ def initialize(argv=nil)
98
+ @command = File.basename($0)
99
+ @argv = argv || ARGV
100
+ end
101
+
102
+
103
+ def execute()
104
+ command = @command
105
+
106
+ ## parse options
107
+ noargopts = 'hvsSNXCUbxzqwTPdD'
108
+ argopts = 'fckra'
109
+ argopts2 = ''
110
+ command = File.basename($0)
111
+ options, properties, filenames = parse_argv(@argv, noargopts, argopts, argopts2)
112
+ debug = options[:D]
113
+ debug and $stderr.puts "*** debug: options=#{options.inspect}"
114
+ debug and $stderr.puts "*** debug: properties=#{properties.inspect}"
115
+ debug and $stderr.puts "*** debug: filenames=#{filenames.inspect}"
116
+
117
+ ## help, version
118
+ return usage() if options[:h] || properties[:help]
119
+ return version()+"\n" if options[:v] || properties[:version]
120
+
121
+ ## check options
122
+ datafile = options[:f]
123
+ if datafile && !test(?f, datafile)
124
+ raise _error("-f %s: file not found." % datafile)
125
+ end
126
+
127
+ ## action
128
+ action = options[:a]
129
+ actions = %w[render convert retrieve statements syntax dump preprocess]
130
+ if action
131
+ unless actions.include?(action)
132
+ raise _error("-a #{action}: unknown action.")
133
+ end
134
+ action = action.intern
135
+ else
136
+ action = options[:s] && :convert ||
137
+ options[:X] && :statements ||
138
+ options[:S] && :retrieve ||
139
+ options[:z] && :syntax ||
140
+ options[:P] && :preprocess ||
141
+ true && :render
142
+ end
143
+
144
+ ## ruby global options
145
+ $KCODE = options[:k] if options[:k]
146
+ $VERBOSE = 2 if options[:w]
147
+
148
+ ## lib
149
+ if options[:r]
150
+ begin
151
+ for lib in options[:r].split(/,/)
152
+ require lib
153
+ end
154
+ rescue LoadError => ex
155
+ raise _error("-r %s: library not found." % lib)
156
+ end
157
+ end
158
+
159
+ ## context data file
160
+ context = Tenjin::Context.new
161
+ if options[:f]
162
+ datafile = options[:f]
163
+ content = File.read(datafile)
164
+ if datafile =~ /\.ya?ml\z/
165
+ content = _expandtabs(content) unless options[:T]
166
+ hash = load_yaml(content, datafile)
167
+ context.update(hash)
168
+ elsif datafile =~ /\.rb\z/
169
+ load_rubycode_as_contextdata(content, context, datafile)
170
+ else
171
+ raise _error("-f %s: unknown file type ('*.yaml' or '*.rb' expected)." % datafile)
172
+ end
173
+ end
174
+
175
+ ## context data
176
+ if options[:c]
177
+ if options[:c][0] == ?{
178
+ yamlstr = options[:c]
179
+ hash = load_yaml(yamlstr, '-c')
180
+ context.update(hash)
181
+ else
182
+ ruby_code = options[:c]
183
+ load_rubycode_as_contextdata(ruby_code, context, '-c')
184
+ end
185
+ end
186
+
187
+ ## set initalizer option for Tenjin::Template.new()
188
+ if options[:b]
189
+ properties[:preamble] = properties[:postamble] = nil
190
+ elsif action == :convert || action == :retrieve || action == :statements
191
+ properties[:preamble] = true unless properties.key?(:preamble)
192
+ properties[:postamble] = true unless properties.key?(:postamble)
193
+ end
194
+
195
+ ## set initalizer option for Tenjin::Engine.new()
196
+ properties[:cache] = false unless properties.key?(:cache)
197
+ properties[:path] = properties[:path].split(/,/) if properties[:path]
198
+ if properties.key?(:templateclass)
199
+ classname = properties[:templateclass]
200
+ klass = _to_class(classname)
201
+ properties[:templateclass] = klass
202
+ elsif action == :preprocess || options[:P]
203
+ properties[:templateclass] = Tenjin::Preprocessor
204
+ properties[:preprocess] = false
205
+ elsif action == :retrieve
206
+ properties[:templateclass] = Tenjin::NoTextTemplate
207
+ elsif action == :statements
208
+ properties[:templateclass] = Tenjin::NoTextTemplate
209
+ properties[:noexpr] = true
210
+ end
211
+
212
+ ## create Engine instance
213
+ engine = Tenjin::Engine.new(properties)
214
+
215
+ ## execute
216
+ filenames = [nil] if filenames.empty?
217
+ output_buf = ''
218
+ for template_name in filenames
219
+ if template_name.nil?
220
+ input = $stdin.read()
221
+ template_class = properties.fetch(:templateclass, Tenjin::Template)
222
+ template = template_class.new(properties)
223
+ engine.register_template(template_name, template)
224
+ end
225
+ case action
226
+ when :convert, :retrieve, :statements
227
+ template = engine.get_template(template_name)
228
+ output = template.script
229
+ when :syntax
230
+ template = engine.get_template(template_name)
231
+ output = check_syntax(template.script, template.filename, options[:q], options[:w])
232
+ when :render, :preprocess
233
+ output = engine.render(template_name, context)
234
+ else
235
+ assert unreachable
236
+ end
237
+ output_buf << manipulate_output(output, options)
238
+ end
239
+ return output_buf
240
+ end
241
+
242
+
243
+ def check_syntax(script, filename, quiet, warning)
244
+ command = warning ? "ruby -wc" : "ruby -c"
245
+ require 'open3'
246
+ stdin, stdout, stderr = *Open3.popen3(command)
247
+ stdin.write(script) ; stdin.close()
248
+ result = stdout.read() ; stdout.close()
249
+ errmsg = stderr.read() ; stderr.close()
250
+ if errmsg && !errmsg.empty?
251
+ errmsg.gsub!(/^-(:\d+: )/, "#{filename}\\1")
252
+ return errmsg
253
+ else
254
+ return quiet ? '' : "#{filename}: #{result}"
255
+ end
256
+ end
257
+
258
+
259
+ def manipulate_output(output, options)
260
+ flag_linenum = options[:N] # add line numbers
261
+ flag_compact = options[:C] # remove empty lines
262
+ flag_unique = options[:U] # compress empty lines to a line
263
+ if flag_linenum
264
+ n = 0
265
+ output.gsub!(/^/) { n += 1; "%5d: " % n }
266
+ output.gsub!(/^ *\d+:\s+?\n/, '') if flag_compact
267
+ output.gsub!(/(^ *\d+:\s+?\n)+/, "\n") if flag_unique
268
+ else
269
+ output.gsub!(/^\s*?\n/, '') if flag_compact
270
+ output.gsub!(/(^\s*?\n)+/, "\n") if flag_unique
271
+ end
272
+ return output
273
+ end
274
+
275
+
276
+ def load_yaml(yamlstr, filename)
277
+ require 'yaml'
278
+ hash = YAML.load(yamlstr)
279
+ unless hash.is_a?(Hash)
280
+ raise _error("%s: not a mapping (hash)." % filename)
281
+ end
282
+ return hash
283
+ end
284
+
285
+
286
+ def load_rubycode_as_contextdata(_rubycode, _context, _filename)
287
+ _context.instance_eval(_rubycode, _filename)
288
+ end
289
+
290
+
291
+ def usage(command=nil)
292
+ command ||= @command
293
+ s = <<"END"
294
+ Usage: #{command} [..options..] [file1 [file2...]]
295
+ -h, --help : help
296
+ -v, --version : version
297
+ -a action : action
298
+ -a render : render template (default)
299
+ -a convert : convert template into script
300
+ -a retrieve : retrieve statements and expressons
301
+ -a statements : retrieve only statements
302
+ -a syntax : syntax check
303
+ -a preprocess : show preprocessed template
304
+ -s : alias of '-a convert'
305
+ -S : alias of '-a retrieve'
306
+ -z : alias of '-a syntax'
307
+ -X : alias of '-a statements'
308
+ # -d : alias of '-a dump'
309
+ -P : alias of '-a preprocess'
310
+ -N : add line number
311
+ -C : compact: remove empty lines
312
+ -U : uniq: compress empty lines into a line
313
+ -b : remove "_buf='';" and "_buf.to_s"
314
+ -q : quet mode (for '-a syntax')
315
+ # -w : use strict package
316
+ -c string : context data string (yaml or ruby)
317
+ -f file : context data file (*.yaml or *.rb)
318
+ -T : unexpand tab chars in datafile
319
+ -r lib1,lib2,.. : require libraries
320
+ -k code : kanji code for $KCODE
321
+ # --encoding=encoding : encoding name, with converting into unicode
322
+ --escapefunc=name : 'escape' function name
323
+ # --tostrfunc=name : 'to_str' function name
324
+ --preamble=text : preamble which is insreted into ruby script
325
+ --postamble=text : postamble which is insreted into ruby script
326
+ # --smarttrim : trim "\\n{expr}\\n" into "\\n{expr}".
327
+ --prefix=str : prefix string for template shortname
328
+ --postfix=str : postfix string for template shortname
329
+ --layout=filename : layout template name
330
+ --path=dir1,dir2,.. : template lookup path
331
+ --preprocess : activate preprocessing
332
+ --templateclass=name: template class (default: Tenjin::Template)
333
+ Examples:
334
+ ex1. render template
335
+ $ #{command} file.rbhtml
336
+ ex2. convert template into ruby script
337
+ $ #{command} -a convert file.rbhtml
338
+ $ #{command} -a retrieve -UN file.rbhtml # for debug
339
+ ex3. render with context data file (*.yaml or *.rb)
340
+ $ #{command} -f datafile.yaml file.rbhtml
341
+ ex4. render with context data string
342
+ $ #{command} -c '{title: tenjin example, items: [1, 2, 3]}' file.rbhtml # yaml
343
+ $ #{command} -c '@title="tenjin example"; @items=[1,2,3]' file.rbhtml # ruby
344
+ ex5. syntax check
345
+ $ #{command} -wa syntax *.rbhtml # or '-wz'
346
+ END
347
+ return s.gsub(/^\#.*\n/, '')
348
+ end
349
+
350
+
351
+ def version()
352
+ return RELEASE
353
+ end
354
+
355
+
356
+ def parse_argv(argv, noargopts, argopts, argopts2='')
357
+ options = {}
358
+ properties = {}
359
+ while argv[0] && argv[0][0] == ?-
360
+ optstr = argv.shift
361
+ if optstr == '-'
362
+ break
363
+ elsif optstr =~ /\A--([-\w]+)(=.*)?/
364
+ name = $1
365
+ value = $2 && !$2.empty? ? _to_value($2[1..-1]) : true
366
+ properties[name.intern] = value
367
+ else
368
+ optstr = optstr[1..-1]
369
+ while !optstr.empty?
370
+ ch = optstr[0].chr
371
+ optstr = optstr[1..-1]
372
+ if noargopts.include?(ch)
373
+ options[ch.intern] = true
374
+ elsif argopts.include?(ch)
375
+ if !optstr.empty?
376
+ options[ch.intern] = optstr
377
+ optstr = ''
378
+ elsif !argv.empty?
379
+ options[ch.intern] = argv.shift
380
+ else
381
+ raise _error("-#{ch}: argument required.")
382
+ end
383
+ elsif argopts2.include?(ch)
384
+ options[ch.intern] = !optstr.empty? ? optstr : true
385
+ optstr = ''
386
+ else
387
+ raise _error("-#{ch}: unknown option.")
388
+ end
389
+ end
390
+ end
391
+ end
392
+ filenames = argv
393
+ return options, properties, filenames
394
+ end
395
+
396
+
397
+ def _to_value(s)
398
+ case s
399
+ when 'true', 'yes' ; return true
400
+ when 'false', 'no' ; return false
401
+ when 'null', 'nil' ; return nil
402
+ when /\A\d+\z/ ; return s.to_i
403
+ when /\A\d+\.\d+\z/ ; return s.to_f
404
+ when /\A:[-\w]+\z/ ; return s[1..-1].intern
405
+ else ; return s
406
+ end
407
+ end
408
+
409
+
410
+ def _to_class(classname)
411
+ klass = Object
412
+ begin
413
+ classname.split(/::/).each { |m| klass = klass.const_get(m) }
414
+ rescue NameError => ex
415
+ raise _error("%s: class not found." % classname)
416
+ end
417
+ return klass
418
+ end
419
+
420
+
421
+ def _error(message)
422
+ return CommandOptionError.new(message)
423
+ end
424
+
425
+
426
+ def _expandtabs(input, width=8)
427
+ arr = input.split(/\t/)
428
+ last = arr.pop
429
+ buf = ''
430
+ arr.each do |s|
431
+ column = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
432
+ n = width - (column % width)
433
+ buf << s << (' ' * n)
434
+ end
435
+ buf << last
436
+ return buf
437
+ end
438
+
439
+
440
+ end
441
+
442
+
443
+ end
444
+
445
+
446
+ #if __FILE__ == $0
447
+ unless defined?(DONT_INVOKE)
448
+ Tenjin::Main.main()
449
+ end