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.
- data/MIT-LICENSE +20 -0
- data/README.txt +54 -0
- data/benchmark/bench.rb +502 -0
- data/benchmark/bench_context.rb +17 -0
- data/benchmark/bench_context.yaml +141 -0
- data/benchmark/templates/_footer.html +4 -0
- data/benchmark/templates/_header.html +52 -0
- data/benchmark/templates/bench_eruby.rhtml +29 -0
- data/benchmark/templates/bench_tenjin.rbhtml +29 -0
- data/bin/rbtenjin +449 -0
- data/doc-api/classes/Tenjin.html +141 -0
- data/doc-api/classes/Tenjin/ArrayBufferTemplate.html +270 -0
- data/doc-api/classes/Tenjin/BaseContext.html +312 -0
- data/doc-api/classes/Tenjin/Context.html +126 -0
- data/doc-api/classes/Tenjin/ContextHelper.html +433 -0
- data/doc-api/classes/Tenjin/Engine.html +616 -0
- data/doc-api/classes/Tenjin/ErubisTemplate.html +166 -0
- data/doc-api/classes/Tenjin/HtmlHelper.html +359 -0
- data/doc-api/classes/Tenjin/Preprocessor.html +242 -0
- data/doc-api/classes/Tenjin/Template.html +916 -0
- data/doc-api/created.rid +1 -0
- data/doc-api/files/README_txt.html +185 -0
- data/doc-api/files/lib/tenjin_rb.html +136 -0
- data/doc-api/fr_class_index.html +36 -0
- data/doc-api/fr_file_index.html +28 -0
- data/doc-api/fr_method_index.html +89 -0
- data/doc-api/index.html +24 -0
- data/doc-api/rdoc-style.css +208 -0
- data/doc/docstyle.css +188 -0
- data/doc/examples.html +312 -0
- data/doc/faq.html +909 -0
- data/doc/users-guide.html +1691 -0
- data/lib/tenjin.rb +959 -0
- data/setup.rb +1331 -0
- data/tenjin.gemspec +58 -0
- data/test/assert-text-equal.rb +45 -0
- data/test/data/examples/form/create.rbhtml +4 -0
- data/test/data/examples/form/form.rbhtml +14 -0
- data/test/data/examples/form/layout.rbhtml +8 -0
- data/test/data/examples/form/main.rb +9 -0
- data/test/data/examples/form/main.result +21 -0
- data/test/data/examples/form/update.rbhtml +4 -0
- data/test/data/examples/preprocessing/helper.rb +16 -0
- data/test/data/examples/preprocessing/main.rb +11 -0
- data/test/data/examples/preprocessing/main.result +17 -0
- data/test/data/examples/preprocessing/select.rbhtml +15 -0
- data/test/data/examples/preprocessing/select_P.result +18 -0
- data/test/data/examples/table/table.rb +9 -0
- data/test/data/examples/table/table.rbhtml +16 -0
- data/test/data/examples/table/table.result +20 -0
- data/test/data/examples/table/table_s.result +18 -0
- data/test/data/faq/ex1.rbhtml +5 -0
- data/test/data/faq/ex10-baselayout.rbhtml +27 -0
- data/test/data/faq/ex10-content.rbhtml +12 -0
- data/test/data/faq/ex10-customlayout.rbhtml +11 -0
- data/test/data/faq/ex10_inherit.result +25 -0
- data/test/data/faq/ex11-bench.rb +28 -0
- data/test/data/faq/ex11-content.rbhtml +9 -0
- data/test/data/faq/ex11-layout1.rbhtml +5 -0
- data/test/data/faq/ex11-layout2.rbhtml +6 -0
- data/test/data/faq/ex11.rb +5 -0
- data/test/data/faq/ex11.rbhtml +8 -0
- data/test/data/faq/ex11.source +11 -0
- data/test/data/faq/ex11_arraybuffer.result +15 -0
- data/test/data/faq/ex1_chksyntax.result +3 -0
- data/test/data/faq/ex2-content.rbhtml +3 -0
- data/test/data/faq/ex2-layout.rbhtml +11 -0
- data/test/data/faq/ex2_removenl.result +19 -0
- data/test/data/faq/ex3.rb +4 -0
- data/test/data/faq/ex3.rbhtml +1 -0
- data/test/data/faq/ex3_escapefunc1.result +2 -0
- data/test/data/faq/ex3_escapefunc2.result +2 -0
- data/test/data/faq/ex5.rbhtml +7 -0
- data/test/data/faq/ex5_template_args.source +9 -0
- data/test/data/faq/ex6-content.rhtml +6 -0
- data/test/data/faq/ex6-layout.rhtml +6 -0
- data/test/data/faq/ex6.rb +10 -0
- data/test/data/faq/ex6_eruby.result +12 -0
- data/test/data/faq/ex7-expr-pattern.rb +34 -0
- data/test/data/faq/ex7-expr-pattern.rbhtml +3 -0
- data/test/data/faq/ex7_expr_pattern.result +4 -0
- data/test/data/faq/ex8-m18n.rb +77 -0
- data/test/data/faq/ex8-m18n.rbhtml +4 -0
- data/test/data/faq/ex8_m18n.result +10 -0
- data/test/data/faq/ex9-baselayout.rbhtml +8 -0
- data/test/data/faq/ex9-content.rbhtml +6 -0
- data/test/data/faq/ex9-mylayout.rbhtml +5 -0
- data/test/data/faq/ex9_changelayout.result +11 -0
- data/test/data/users_guide/content6.rbhtml +3 -0
- data/test/data/users_guide/content7.rbhtml +5 -0
- data/test/data/users_guide/content8.rbhtml +2 -0
- data/test/data/users_guide/contextdata.rb +7 -0
- data/test/data/users_guide/datafile.rb +5 -0
- data/test/data/users_guide/datafile.yaml +10 -0
- data/test/data/users_guide/ex.rbhtml +6 -0
- data/test/data/users_guide/ex.result +7 -0
- data/test/data/users_guide/ex.script +5 -0
- data/test/data/users_guide/ex_script.result +7 -0
- data/test/data/users_guide/ex_source.result +8 -0
- data/test/data/users_guide/example1.rbhtml +12 -0
- data/test/data/users_guide/example1.result +17 -0
- data/test/data/users_guide/example10.rbhtml +4 -0
- data/test/data/users_guide/example10_template_args.result +6 -0
- data/test/data/users_guide/example11.rbhtml +5 -0
- data/test/data/users_guide/example11_template_args_result +2 -0
- data/test/data/users_guide/example12.rbhtml +12 -0
- data/test/data/users_guide/example12_preprocessed.result +10 -0
- data/test/data/users_guide/example12_preprocessed_source.result +10 -0
- data/test/data/users_guide/example13.rbhtml +6 -0
- data/test/data/users_guide/example13_preprocessed.result +2 -0
- data/test/data/users_guide/example13_preprocessed_source.result +2 -0
- data/test/data/users_guide/example14.rb +32 -0
- data/test/data/users_guide/example14.rbhtml +6 -0
- data/test/data/users_guide/example14_tmplclass.result +15 -0
- data/test/data/users_guide/example15.rb +10 -0
- data/test/data/users_guide/example15_escapefunc.result +14 -0
- data/test/data/users_guide/example16.rbhtml +4 -0
- data/test/data/users_guide/example16a.rb +10 -0
- data/test/data/users_guide/example16a.result +4 -0
- data/test/data/users_guide/example16b.rb +13 -0
- data/test/data/users_guide/example16b.result +4 -0
- data/test/data/users_guide/example16c.rb +12 -0
- data/test/data/users_guide/example16c.result +4 -0
- data/test/data/users_guide/example1_S.result +14 -0
- data/test/data/users_guide/example1_SXNC.result +10 -0
- data/test/data/users_guide/example1_source.result +14 -0
- data/test/data/users_guide/example2.rbhtml +3 -0
- data/test/data/users_guide/example2_sb.result2 +9 -0
- data/test/data/users_guide/example3.rbhtml +5 -0
- data/test/data/users_guide/example3_syntaxcheck.result +2 -0
- data/test/data/users_guide/example4.rbhtml +13 -0
- data/test/data/users_guide/example4_datafile_rb.result +13 -0
- data/test/data/users_guide/example4_yaml.result +13 -0
- data/test/data/users_guide/example5.rbhtml +9 -0
- data/test/data/users_guide/example5_datastr_rb.result +9 -0
- data/test/data/users_guide/example5_datastr_yaml.result +9 -0
- data/test/data/users_guide/example6.rbhtml +19 -0
- data/test/data/users_guide/example6_layout.result +29 -0
- data/test/data/users_guide/example6_nested.result +28 -0
- data/test/data/users_guide/example7_layout2.result +13 -0
- data/test/data/users_guide/example8_layout3.result +8 -0
- data/test/data/users_guide/example9.rbhtml +18 -0
- data/test/data/users_guide/example9_capture.result +26 -0
- data/test/data/users_guide/footer.html +5 -0
- data/test/data/users_guide/footer.rbhtml +4 -0
- data/test/data/users_guide/layout6.rbhtml +17 -0
- data/test/data/users_guide/layout7.rbhtml +9 -0
- data/test/data/users_guide/layout8_html.rbhtml +5 -0
- data/test/data/users_guide/layout8_xhtml.rbhtml +6 -0
- data/test/data/users_guide/layout9.rbhtml +25 -0
- data/test/data/users_guide/sidemenu.rbhtml +5 -0
- data/test/data/users_guide/user_app.cgi +39 -0
- data/test/data/users_guide/user_app.result +30 -0
- data/test/data/users_guide/user_create.rbhtml +6 -0
- data/test/data/users_guide/user_edit.rbhtml +7 -0
- data/test/data/users_guide/user_form.rbhtml +10 -0
- data/test/data/users_guide/user_layout.rbhtml +16 -0
- data/test/test_all.rb +23 -0
- data/test/test_engine.rb +526 -0
- data/test/test_engine.yaml +2039 -0
- data/test/test_examples.rb +81 -0
- data/test/test_faq.rb +60 -0
- data/test/test_htmlhelper.rb +78 -0
- data/test/test_main.rb +564 -0
- data/test/test_main.yaml +174 -0
- data/test/test_template.rb +113 -0
- data/test/test_template.yaml +1244 -0
- data/test/test_users_guide.rb +75 -0
- data/test/testcase-helper.rb +166 -0
- 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,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
|