tenjin 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|