erubis 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. data/CHANGES.txt +62 -2
  2. data/README.txt +1 -1
  3. data/benchmark/bench.rb +18 -10
  4. data/bin/erubis +1 -1
  5. data/contrib/erubis +2 -3318
  6. data/contrib/inline-require +1 -1
  7. data/doc-api/classes/ActionView.html +105 -0
  8. data/doc-api/classes/ActionView/TemplateHandlers/Erubis.html +202 -0
  9. data/doc-api/classes/Erubis.html +7 -1
  10. data/doc-api/classes/Erubis/ArrayBufferEnhancer.html +12 -12
  11. data/doc-api/classes/Erubis/ArrayEnhancer.html +12 -12
  12. data/doc-api/classes/Erubis/Basic/Converter.html +34 -30
  13. data/doc-api/classes/Erubis/BiPatternEnhancer.html +12 -12
  14. data/doc-api/classes/Erubis/CGenerator.html +60 -60
  15. data/doc-api/classes/Erubis/Context.html +42 -42
  16. data/doc-api/classes/Erubis/Converter.html +27 -27
  17. data/doc-api/classes/Erubis/DeleteIndentEnhancer.html +6 -6
  18. data/doc-api/classes/Erubis/Engine.html +40 -37
  19. data/doc-api/classes/Erubis/ErboutEnhancer.html +12 -12
  20. data/doc-api/classes/Erubis/EscapeEnhancer.html +6 -6
  21. data/doc-api/classes/Erubis/Evaluator.html +19 -19
  22. data/doc-api/classes/Erubis/Generator.html +60 -60
  23. data/doc-api/classes/Erubis/HeaderFooterEnhancer.html +12 -12
  24. data/doc-api/classes/Erubis/Helpers/RailsFormHelper.html +201 -176
  25. data/doc-api/classes/Erubis/Helpers/RailsHelper.html +58 -58
  26. data/doc-api/classes/Erubis/Helpers/RailsHelper/{PreprocessingEruby.html → TemplateConverter.html} +24 -37
  27. data/doc-api/classes/Erubis/InterpolationEnhancer.html +36 -35
  28. data/doc-api/classes/Erubis/JavaGenerator.html +54 -54
  29. data/doc-api/classes/Erubis/JavascriptGenerator.html +60 -60
  30. data/doc-api/classes/Erubis/Main.html +19 -19
  31. data/doc-api/classes/Erubis/NoCodeEnhancer.html +30 -30
  32. data/doc-api/classes/Erubis/NoTextEnhancer.html +6 -6
  33. data/doc-api/classes/Erubis/OptimizedEruby.html +6 -6
  34. data/doc-api/classes/Erubis/OptimizedGenerator.html +72 -72
  35. data/doc-api/classes/Erubis/OptimizedXmlEruby.html +6 -6
  36. data/doc-api/classes/Erubis/PI/Converter.html +21 -21
  37. data/doc-api/classes/Erubis/PI/Ec.html +6 -6
  38. data/doc-api/classes/Erubis/PI/Ejava.html +6 -6
  39. data/doc-api/classes/Erubis/PI/Ejavascript.html +6 -6
  40. data/doc-api/classes/Erubis/PI/Eperl.html +6 -6
  41. data/doc-api/classes/Erubis/PI/Ephp.html +6 -6
  42. data/doc-api/classes/Erubis/PI/Eruby.html +6 -6
  43. data/doc-api/classes/Erubis/PI/Escheme.html +6 -6
  44. data/doc-api/classes/Erubis/PI/TinyEruby.html +24 -24
  45. data/doc-api/classes/Erubis/PercentLineEnhancer.html +6 -6
  46. data/doc-api/classes/Erubis/PerlGenerator.html +54 -54
  47. data/doc-api/classes/Erubis/PhpGenerator.html +54 -54
  48. data/doc-api/classes/Erubis/PreprocessingEruby.html +183 -0
  49. data/doc-api/classes/Erubis/PreprocessingHelper.html +212 -0
  50. data/doc-api/classes/Erubis/PrintEnabledEnhancer.html +20 -20
  51. data/doc-api/classes/Erubis/PrintOutEnhancer.html +30 -30
  52. data/doc-api/classes/Erubis/RubyEvaluator.html +18 -18
  53. data/doc-api/classes/Erubis/RubyGenerator.html +48 -48
  54. data/doc-api/classes/Erubis/SchemeGenerator.html +60 -60
  55. data/doc-api/classes/Erubis/SimplifyEnhancer.html +7 -7
  56. data/doc-api/classes/Erubis/StdoutEnhancer.html +12 -12
  57. data/doc-api/classes/Erubis/StringBufferEnhancer.html +12 -12
  58. data/doc-api/classes/Erubis/TinyEruby.html +24 -24
  59. data/doc-api/classes/Erubis/XmlHelper.html +30 -30
  60. data/doc-api/created.rid +1 -1
  61. data/doc-api/files/README_txt.html +2 -2
  62. data/doc-api/files/erubis/context_rb.html +1 -1
  63. data/doc-api/files/erubis/converter_rb.html +2 -2
  64. data/doc-api/files/erubis/engine/ec_rb.html +1 -1
  65. data/doc-api/files/erubis/engine/ejava_rb.html +1 -1
  66. data/doc-api/files/erubis/engine/ejavascript_rb.html +1 -1
  67. data/doc-api/files/erubis/engine/enhanced_rb.html +1 -1
  68. data/doc-api/files/erubis/engine/eperl_rb.html +1 -1
  69. data/doc-api/files/erubis/engine/ephp_rb.html +1 -1
  70. data/doc-api/files/erubis/engine/eruby_rb.html +1 -1
  71. data/doc-api/files/erubis/engine/escheme_rb.html +1 -1
  72. data/doc-api/files/erubis/engine/optimized_rb.html +1 -1
  73. data/doc-api/files/erubis/engine_rb.html +2 -2
  74. data/doc-api/files/erubis/enhancer_rb.html +2 -2
  75. data/doc-api/files/erubis/error_rb.html +1 -1
  76. data/doc-api/files/erubis/evaluator_rb.html +1 -1
  77. data/doc-api/files/erubis/generator_rb.html +1 -1
  78. data/doc-api/files/erubis/helper_rb.html +1 -1
  79. data/doc-api/files/erubis/helpers/rails_form_helper_rb.html +2 -2
  80. data/doc-api/files/erubis/helpers/rails_helper_rb.html +3 -3
  81. data/doc-api/files/erubis/local-setting_rb.html +1 -1
  82. data/doc-api/files/erubis/main_rb.html +1 -1
  83. data/doc-api/files/erubis/preprocessing_rb.html +114 -0
  84. data/doc-api/files/erubis/tiny_rb.html +1 -1
  85. data/doc-api/files/erubis_rb.html +1 -1
  86. data/doc-api/fr_class_index.html +5 -1
  87. data/doc-api/fr_file_index.html +1 -0
  88. data/doc-api/fr_method_index.html +223 -213
  89. data/doc/users-guide.html +75 -6
  90. data/lib/erubis.rb +2 -2
  91. data/lib/erubis/context.rb +1 -1
  92. data/lib/erubis/converter.rb +11 -7
  93. data/lib/erubis/engine.rb +9 -6
  94. data/lib/erubis/engine/ec.rb +1 -1
  95. data/lib/erubis/engine/ejava.rb +1 -1
  96. data/lib/erubis/engine/ejavascript.rb +1 -1
  97. data/lib/erubis/engine/enhanced.rb +1 -1
  98. data/lib/erubis/engine/eperl.rb +1 -1
  99. data/lib/erubis/engine/ephp.rb +1 -1
  100. data/lib/erubis/engine/eruby.rb +1 -1
  101. data/lib/erubis/engine/escheme.rb +1 -1
  102. data/lib/erubis/engine/optimized.rb +1 -1
  103. data/lib/erubis/enhancer.rb +4 -3
  104. data/lib/erubis/error.rb +1 -1
  105. data/lib/erubis/evaluator.rb +1 -1
  106. data/lib/erubis/generator.rb +1 -1
  107. data/lib/erubis/helper.rb +1 -1
  108. data/lib/erubis/helpers/rails_form_helper.rb +18 -10
  109. data/lib/erubis/helpers/rails_helper.rb +100 -98
  110. data/lib/erubis/local-setting.rb +1 -1
  111. data/lib/erubis/main.rb +1 -1
  112. data/lib/erubis/preprocessing.rb +59 -0
  113. data/lib/erubis/tiny.rb +1 -1
  114. data/test/assert-text-equal.rb +1 -1
  115. data/test/data/users-guide/stderr.log +3 -0
  116. data/test/data/users-guide/tail_260.result +4 -0
  117. data/test/data/users-guide/tailnewline.rhtml +3 -0
  118. data/test/test-engines.rb +1 -1
  119. data/test/test-enhancers.rb +1 -1
  120. data/test/test-erubis.rb +44 -2
  121. data/test/test-main.rb +2 -2
  122. data/test/test-users-guide.rb +1 -1
  123. data/test/test.rb +1 -1
  124. data/test/testutil.rb +1 -1
  125. metadata +15 -5
  126. data/contrib/action_view_base_rb.patch +0 -23
@@ -1,8 +1,68 @@
1
- # $Rev: 99 $
2
- # $Release: 2.5.0 $
1
+ # $Rev: 107 $
2
+ # $Release: 2.6.0 $
3
3
  # copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
4
4
 
5
5
 
6
+ - release: 2.6.0
7
+ date:
8
+ enhancements:
9
+
10
+ - |
11
+ Improved support of Ruby on Rails 2.0.2.
12
+ New class ActionView::TemplateHandlers::Erubis is defined and
13
+ registered as default handler of *.html.erb and *.rhtml.
14
+
15
+ - |
16
+ '<%% %>' and '<%%= %>' are converted into '<% %>' and '<%= %>' respectively.
17
+ This is for compatibility with ERB.
18
+
19
+ ex1.rhtml:
20
+ <ul>
21
+ <%% for item in @list %>
22
+ <li><%%= item %></li>
23
+ <%% end %>
24
+ </ul>
25
+
26
+ result:
27
+ $ erubis ex1.rhtml
28
+ <ul>
29
+ <% for item in @list %>
30
+ <li><%= item %></li>
31
+ <% end %>
32
+ </ul>
33
+
34
+ - |
35
+ '<%= -%>' removes tail spaces and newlines.
36
+ This is for compatibiliy with ERB when trim mode is '-'.
37
+ '<%= =%>' also removes tail spaces and newlines, and this is
38
+ Erubis-original enhancement (cooler than '<%= -%>', isn't it?).
39
+
40
+ ex2.rhtml:
41
+ <div>
42
+ <%= @var -%> # or <%= @var =%>
43
+ </div>
44
+
45
+ result (version 2.6.0):
46
+ $ erubis -c '{var: "AAA\n"}' ex2.rhtml
47
+ <div>
48
+ AAA
49
+ </div>
50
+
51
+ result (version 2.5.0):
52
+ $ erubis -c '{var: "AAA\n"}' ex2.rhtml
53
+ <div>
54
+ AAA
55
+
56
+ </div>
57
+
58
+ - |
59
+ Erubis::Eruby.load_file() now allows you to change cache filename.
60
+
61
+ ex.
62
+ eruby = Erubis::Eruby.load_file("ex3.rhtml",
63
+ :cachename=>'ex3.rhtml.cache')
64
+
65
+
6
66
  - release: 2.5.0
7
67
  date: 2008-01-30
8
68
  enhancements:
data/README.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  = README
2
2
 
3
- release:: 2.5.0
3
+ release:: 2.6.0
4
4
  copyright:: copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
5
5
 
6
6
 
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  ###
4
- ### $Rev: 77 $
5
- ### $Release: 2.5.0 $
4
+ ### $Rev: 101 $
5
+ ### $Release: 2.6.0 $
6
6
  ### copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
7
7
  ###
8
8
 
@@ -93,7 +93,8 @@ class BenchmarkApplication
93
93
 
94
94
  def execute_eruby(filename, context)
95
95
  return unless ERuby
96
- eval context2code(context)
96
+ #eval context2code(context)
97
+ list = context['list']
97
98
  @ntimes.times do
98
99
  ERuby.import(filename)
99
100
  end
@@ -101,7 +102,8 @@ class BenchmarkApplication
101
102
  end
102
103
 
103
104
  def execute_erb(filename, context)
104
- eval context2code(context)
105
+ #eval context2code(context)
106
+ list = context['list']
105
107
  output = nil
106
108
  @ntimes.times do
107
109
  eruby = ERB.new(File.read(filename))
@@ -112,7 +114,8 @@ class BenchmarkApplication
112
114
  end
113
115
 
114
116
  def execute_erb_cached(filename, context)
115
- eval context2code(context)
117
+ #eval context2code(context)
118
+ list = context['list']
116
119
  output = nil
117
120
  cachefile = filename + '.cache'
118
121
  File.unlink(cachefile) if test(?f, cachefile)
@@ -135,7 +138,8 @@ class BenchmarkApplication
135
138
  for klass in %w[Eruby FastEruby TinyEruby ArrayBufferEruby PrintOutEruby StdoutEruby] do
136
139
  s = <<-END
137
140
  def execute_erubis_#{klass.downcase}(filename, context)
138
- eval context2code(context)
141
+ #eval context2code(context)
142
+ list = context['list']
139
143
  output = nil
140
144
  @ntimes.times do
141
145
  eruby = Erubis::#{klass}.new(File.read(filename))
@@ -152,7 +156,8 @@ class BenchmarkApplication
152
156
  for klass in %w[Eruby FastEruby] do
153
157
  s = <<-END
154
158
  def execute_erubis_#{klass.downcase}_cached(filename, context)
155
- eval context2code(context)
159
+ #eval context2code(context)
160
+ list = context['list']
156
161
  cachefile = filename + '.cache'
157
162
  File.unlink(cachefile) if test(?f, cachefile)
158
163
  output = nil
@@ -173,7 +178,8 @@ class BenchmarkApplication
173
178
 
174
179
  def convert_eruby(filename, context)
175
180
  return unless ERuby
176
- eval context2code(context)
181
+ #eval context2code(context)
182
+ list = context['list']
177
183
  output = nil
178
184
  @ntimes.times do
179
185
  output = ERuby::Compiler.new.compile_string(File.read(filename))
@@ -182,7 +188,8 @@ class BenchmarkApplication
182
188
  end
183
189
 
184
190
  def convert_erb(filename, context)
185
- eval context2code(context)
191
+ #eval context2code(context)
192
+ list = context['list']
186
193
  output = nil
187
194
  @ntimes.times do
188
195
  eruby = ERB.new(File.read(filename))
@@ -194,7 +201,8 @@ class BenchmarkApplication
194
201
  for klass in %w[Eruby FastEruby TinyEruby]
195
202
  s = <<-END
196
203
  def convert_erubis_#{klass.downcase}(filename, context)
197
- eval context2code(context)
204
+ #eval context2code(context)
205
+ list = context['list']
198
206
  output = nil
199
207
  @ntimes.times do
200
208
  eruby = Erubis::#{klass}.new(File.read(filename))
data/bin/erubis CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ###
4
4
  ### $Rev: 77 $
5
- ### $Release: 2.5.0 $
5
+ ### $Release: 2.6.0 $
6
6
  ### copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
7
7
  ###
8
8
 
@@ -2,3326 +2,10 @@
2
2
 
3
3
  ###
4
4
  ### $Rev: 77 $
5
- ### $Release: 2.5.0 $
5
+ ### $Release: 2.6.0 $
6
6
  ### copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
7
7
  ###
8
8
 
9
- #--begin of require 'erubis/main'
10
- ###
11
- ### $Rev: 91 $
12
- ### $Release: 2.5.0 $
13
- ### copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
14
- ###
15
-
16
- require 'yaml'
17
- #--begin of require 'erubis'
18
- ##
19
- ## $Rev: 99 $
20
- ## $Release: 2.5.0 $
21
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
22
- ##
23
-
24
- ##
25
- ## an implementation of eRuby
26
- ##
27
- ## ex.
28
- ## input = <<'END'
29
- ## <ul>
30
- ## <% for item in @list %>
31
- ## <li><%= item %>
32
- ## <%== item %></li>
33
- ## <% end %>
34
- ## </ul>
35
- ## END
36
- ## list = ['<aaa>', 'b&b', '"ccc"']
37
- ## eruby = Erubis::Eruby.new(input)
38
- ## puts "--- code ---"
39
- ## puts eruby.src
40
- ## puts "--- result ---"
41
- ## context = Erubis::Context.new() # or new(:list=>list)
42
- ## context[:list] = list
43
- ## puts eruby.evaluate(context)
44
- ##
45
- ## result:
46
- ## --- source ---
47
- ## _buf = ''; _buf << '<ul>
48
- ## '; for item in @list
49
- ## _buf << ' <li>'; _buf << ( item ).to_s; _buf << '
50
- ## '; _buf << ' '; _buf << Erubis::XmlHelper.escape_xml( item ); _buf << '</li>
51
- ## '; end
52
- ## _buf << '</ul>
53
- ## ';
54
- ## _buf.to_s
55
- ## --- result ---
56
- ## <ul>
57
- ## <li><aaa>
58
- ## &lt;aaa&gt;</li>
59
- ## <li>b&b
60
- ## b&amp;b</li>
61
- ## <li>"ccc"
62
- ## &quot;ccc&quot;</li>
63
- ## </ul>
64
- ##
65
-
66
-
67
- module Erubis
68
- VERSION = ('$Release: 2.5.0 $' =~ /([.\d]+)/) && $1
69
- end
70
-
71
- #--begin of require 'erubis/engine'
72
- ##
73
- ## $Rev: 77 $
74
- ## $Release: 2.5.0 $
75
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
76
- ##
77
-
78
-
79
- #--begin of require 'erubis/generator'
80
- ##
81
- ## $Rev: 77 $
82
- ## $Release: 2.5.0 $
83
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
84
- ##
85
-
86
- #--begin of require 'abstract'
87
- ##
88
- ## $Rev: 1 $
89
- ## $Release: 0.1.0 $
90
- ## copyright(c) 2006 kuwata-lab.com all rights reserved.
91
- ##
92
- ##
93
- ## helper to define abstract method in Ruby.
94
- ##
95
- ##
96
- ## example1. (shorter notation)
97
- ##
98
- ## require 'abstract'
99
- ## class Foo
100
- ## abstract_method 'arg1, arg2=""', :method1, :method2, :method3
101
- ## end
102
- ##
103
- ##
104
- ## example2. (RDoc friendly notation)
105
- ##
106
- ## require 'abstract'
107
- ## class Bar
108
- ## # ... method1 description ...
109
- ## def method1(arg1, arg2="")
110
- ## not_implemented
111
- ## end
112
- ##
113
- ## # ... method2 description ...
114
- ## def method2(arg1, arg2="")
115
- ## not_implemented
116
- ## end
117
- ## end
118
- ##
119
-
120
-
121
- ##
122
- class Module
123
-
124
- ##
125
- ## define abstract methods
126
- ##
127
- def abstract_method args_str, *method_names
128
- method_names.each do |name|
129
- module_eval <<-END
130
- def #{name}(#{args_str})
131
- mesg = "class \#{self.class.name} must implement abstract method `#{self.name}##{name}()'."
132
- #mesg = "\#{self.class.name}##{name}() is not implemented."
133
- err = NotImplementedError.new mesg
134
- err.set_backtrace caller()
135
- raise err
136
- end
137
- END
138
- end
139
- end
140
-
141
- end
142
-
143
-
144
- ##
145
- module Kernel
146
-
147
- ##
148
- ## raise NotImplementedError
149
- ##
150
- def not_implemented #:doc:
151
- backtrace = caller()
152
- method_name = (backtrace.shift =~ /`(\w+)'$/) && $1
153
- mesg = "class #{self.class.name} must implement abstract method '#{method_name}()'."
154
- #mesg = "#{self.class.name}##{method_name}() is not implemented."
155
- err = NotImplementedError.new mesg
156
- err.set_backtrace backtrace
157
- raise err
158
- end
159
- private :not_implemented
160
-
161
- end
162
- #--end of require 'abstract'
163
-
164
- module Erubis
165
-
166
-
167
- ##
168
- ## code generator, called by Converter module
169
- ##
170
- module Generator
171
-
172
- def self.supported_properties() # :nodoc:
173
- return [
174
- [:escapefunc, nil, "escape function name"],
175
- ]
176
- end
177
-
178
- attr_accessor :escapefunc
179
-
180
- def init_generator(properties={})
181
- @escapefunc = properties[:escapefunc]
182
- end
183
-
184
-
185
- ## (abstract) escape text string
186
- ##
187
- ## ex.
188
- ## def escape_text(text)
189
- ## return text.dump
190
- ## # or return "'" + text.gsub(/['\\]/, '\\\\\&') + "'"
191
- ## end
192
- def escape_text(text)
193
- not_implemented
194
- end
195
-
196
- ## return escaped expression code (ex. 'h(...)' or 'htmlspecialchars(...)')
197
- def escaped_expr(code)
198
- code.strip!
199
- return "#{@escapefunc}(#{code})"
200
- end
201
-
202
- ## (abstract) add @preamble to src
203
- def add_preamble(src)
204
- not_implemented
205
- end
206
-
207
- ## (abstract) add text string to src
208
- def add_text(src, text)
209
- not_implemented
210
- end
211
-
212
- ## (abstract) add statement code to src
213
- def add_stmt(src, code)
214
- not_implemented
215
- end
216
-
217
- ## (abstract) add expression literal code to src. this is called by add_expr().
218
- def add_expr_literal(src, code)
219
- not_implemented
220
- end
221
-
222
- ## (abstract) add escaped expression code to src. this is called by add_expr().
223
- def add_expr_escaped(src, code)
224
- not_implemented
225
- end
226
-
227
- ## (abstract) add expression code to src for debug. this is called by add_expr().
228
- def add_expr_debug(src, code)
229
- not_implemented
230
- end
231
-
232
- ## (abstract) add @postamble to src
233
- def add_postamble(src)
234
- not_implemented
235
- end
236
-
237
-
238
- end
239
-
240
-
241
- end
242
- #--end of require 'erubis/generator'
243
- #--begin of require 'erubis/converter'
244
- ##
245
- ## $Rev: 89 $
246
- ## $Release: 2.5.0 $
247
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
248
- ##
249
-
250
- #--already included require 'abstract'
251
-
252
- module Erubis
253
-
254
-
255
- ##
256
- ## convert
257
- ##
258
- module Converter
259
-
260
- attr_accessor :preamble, :postamble, :escape
261
-
262
- def self.supported_properties # :nodoc:
263
- return [
264
- [:preamble, nil, "preamble (no preamble when false)"],
265
- [:postamble, nil, "postamble (no postamble when false)"],
266
- [:escape, nil, "escape expression or not in default"],
267
- ]
268
- end
269
-
270
- def init_converter(properties={})
271
- @preamble = properties[:preamble]
272
- @postamble = properties[:postamble]
273
- @escape = properties[:escape]
274
- end
275
-
276
- ## convert input string into target language
277
- def convert(input)
278
- codebuf = "" # or []
279
- @preamble.nil? ? add_preamble(codebuf) : (@preamble && (codebuf << @preamble))
280
- convert_input(codebuf, input)
281
- @postamble.nil? ? add_postamble(codebuf) : (@postamble && (codebuf << @postamble))
282
- @_proc = nil # clear cached proc object
283
- return codebuf # or codebuf.join()
284
- end
285
-
286
- protected
287
-
288
- ##
289
- ## detect spaces at beginning of line
290
- ##
291
- def detect_spaces_at_bol(text, is_bol)
292
- lspace = nil
293
- if text.empty?
294
- lspace = "" if is_bol
295
- elsif text[-1] == ?\n
296
- lspace = ""
297
- else
298
- rindex = text.rindex(?\n)
299
- if rindex
300
- s = text[rindex+1..-1]
301
- if s =~ /\A[ \t]*\z/
302
- lspace = s
303
- #text = text[0..rindex]
304
- text[rindex+1..-1] = ''
305
- end
306
- else
307
- if is_bol && text =~ /\A[ \t]*\z/
308
- #lspace = text
309
- #text = nil
310
- lspace = text.dup
311
- text[0..-1] = ''
312
- end
313
- end
314
- end
315
- return lspace
316
- end
317
-
318
- ##
319
- ## (abstract) convert input to code
320
- ##
321
- def convert_input(codebuf, input)
322
- not_implemented
323
- end
324
-
325
- end
326
-
327
-
328
- module Basic
329
- end
330
-
331
-
332
- ##
333
- ## basic converter which supports '<% ... %>' notation.
334
- ##
335
- module Basic::Converter
336
- include Erubis::Converter
337
-
338
- def self.supported_properties # :nodoc:
339
- return [
340
- [:pattern, '<% %>', "embed pattern"],
341
- [:trim, true, "trim spaces around <% ... %>"],
342
- ]
343
- end
344
-
345
- attr_accessor :pattern, :trim
346
-
347
- def init_converter(properties={})
348
- super(properties)
349
- @pattern = properties[:pattern]
350
- @trim = properties[:trim] != false
351
- end
352
-
353
- protected
354
-
355
- ## return regexp of pattern to parse eRuby script
356
- def pattern_regexp(pattern)
357
- prefix, postfix = pattern.split() # '<% %>' => '<%', '%>'
358
- #return /(.*?)(^[ \t]*)?#{prefix}(=+|\#)?(.*?)-?#{postfix}([ \t]*\r?\n)?/m
359
- #return /(^[ \t]*)?#{prefix}(=+|\#)?(.*?)-?#{postfix}([ \t]*\r?\n)?/m
360
- return /#{prefix}(=+|-|\#)?(.*?)-?#{postfix}([ \t]*\r?\n)?/m
361
- end
362
- module_function :pattern_regexp
363
-
364
- #DEFAULT_REGEXP = /(.*?)(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
365
- #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
366
- #DEFAULT_REGEXP = /<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
367
- DEFAULT_REGEXP = pattern_regexp('<% %>')
368
-
369
- public
370
-
371
- def convert_input(src, input)
372
- pat = @pattern
373
- regexp = pat.nil? || pat == '<% %>' ? DEFAULT_REGEXP : pattern_regexp(pat)
374
- pos = 0
375
- is_bol = true # is beginning of line
376
- input.scan(regexp) do |indicator, code, rspace|
377
- match = Regexp.last_match()
378
- len = match.begin(0) - pos
379
- text = input[pos, len]
380
- pos = match.end(0)
381
- ch = indicator ? indicator[0] : nil
382
- lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
383
- is_bol = rspace ? true : false
384
- add_text(src, text) if text && !text.empty?
385
- ## * when '<%= %>', do nothing
386
- ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
387
- if ch == ?= # <%= %>
388
- add_text(src, lspace) if lspace
389
- add_expr(src, code, indicator)
390
- add_text(src, rspace) if rspace
391
- elsif ch == ?\# # <%# %>
392
- n = code.count("\n") + (rspace ? 1 : 0)
393
- if @trim && lspace && rspace
394
- add_stmt(src, "\n" * n)
395
- else
396
- add_text(src, lspace) if lspace
397
- add_stmt(src, "\n" * n)
398
- add_text(src, rspace) if rspace
399
- end
400
- else # <% %>
401
- if @trim && lspace && rspace
402
- add_stmt(src, "#{lspace}#{code}#{rspace}")
403
- else
404
- add_text(src, lspace) if lspace
405
- add_stmt(src, code)
406
- add_text(src, rspace) if rspace
407
- end
408
- end
409
- end
410
- rest = $' || input # add input when no matched
411
- add_text(src, rest)
412
- end
413
-
414
- ## add expression code to src
415
- def add_expr(src, code, indicator)
416
- case indicator
417
- when '='
418
- @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
419
- when '=='
420
- @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
421
- when '==='
422
- add_expr_debug(src, code)
423
- end
424
- end
425
-
426
- end
427
-
428
-
429
- module PI
430
- end
431
-
432
- ##
433
- ## Processing Instructions (PI) converter for XML.
434
- ## this class converts '<?rb ... ?>' and '${...}' notation.
435
- ##
436
- module PI::Converter
437
- include Erubis::Converter
438
-
439
- def self.desc # :nodoc:
440
- "use processing instructions (PI) instead of '<% %>'"
441
- end
442
-
443
- def self.supported_properties # :nodoc:
444
- return [
445
- [:trim, true, "trim spaces around <% ... %>"],
446
- [:pi, 'rb', "PI (Processing Instrunctions) name"],
447
- [:embchar, '@', "char for embedded expression pattern('@{...}@')"],
448
- [:pattern, '<% %>', "embed pattern"],
449
- ]
450
- end
451
-
452
- attr_accessor :pi, :prefix
453
-
454
- def init_converter(properties={})
455
- super(properties)
456
- @trim = properties.fetch(:trim, true)
457
- @pi = properties[:pi] if properties[:pi]
458
- @embchar = properties[:embchar] || '@'
459
- @pattern = properties[:pattern]
460
- @pattern = '<% %>' if @pattern.nil? #|| @pattern == true
461
- end
462
-
463
- def convert(input)
464
- code = super(input)
465
- return @header || @footer ? "#{@header}#{code}#{@footer}" : code
466
- end
467
-
468
- protected
469
-
470
- def convert_input(codebuf, input)
471
- unless @regexp
472
- @pi ||= 'e'
473
- ch = Regexp.escape(@embchar)
474
- if @pattern
475
- left, right = @pattern.split(' ')
476
- @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/m
477
- else
478
- @regexp = /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?|#{ch}(!*)?\{(.*?)\}#{ch}/m
479
- end
480
- end
481
- #
482
- is_bol = true
483
- pos = 0
484
- input.scan(@regexp) do |pi_arg, stmt, rspace,
485
- indicator1, expr1, indicator2, expr2|
486
- match = Regexp.last_match
487
- len = match.begin(0) - pos
488
- text = input[pos, len]
489
- pos = match.end(0)
490
- lspace = stmt ? detect_spaces_at_bol(text, is_bol) : nil
491
- is_bol = stmt && rspace ? true : false
492
- add_text(codebuf, text) # unless text.empty?
493
- #
494
- if stmt
495
- if @trim && lspace && rspace
496
- add_pi_stmt(codebuf, "#{lspace}#{stmt}#{rspace}", pi_arg)
497
- else
498
- add_text(codebuf, lspace) if lspace
499
- add_pi_stmt(codebuf, stmt, pi_arg)
500
- add_text(codebuf, rspace) if rspace
501
- end
502
- else
503
- add_pi_expr(codebuf, expr1 || expr2, indicator1 || indicator2)
504
- end
505
- end
506
- rest = $' || input
507
- add_text(codebuf, rest)
508
- end
509
-
510
- #--
511
- #def convert_input(codebuf, input)
512
- # parse_stmts(codebuf, input)
513
- # #parse_stmts2(codebuf, input)
514
- #end
515
- #
516
- #def parse_stmts(codebuf, input)
517
- # #regexp = pattern_regexp(@pattern)
518
- # @pi ||= 'e'
519
- # @stmt_pattern ||= /<\?#{@pi}(?:-(\w+))?(\s.*?)\?>([ \t]*\r?\n)?/m
520
- # is_bol = true
521
- # pos = 0
522
- # input.scan(@stmt_pattern) do |pi_arg, code, rspace|
523
- # match = Regexp.last_match
524
- # len = match.begin(0) - pos
525
- # text = input[pos, len]
526
- # pos = match.end(0)
527
- # lspace = detect_spaces_at_bol(text, is_bol)
528
- # is_bol = rspace ? true : false
529
- # parse_exprs(codebuf, text) # unless text.empty?
530
- # if @trim && lspace && rspace
531
- # add_pi_stmt(codebuf, "#{lspace}#{code}#{rspace}", pi_arg)
532
- # else
533
- # add_text(codebuf, lspace)
534
- # add_pi_stmt(codebuf, code, pi_arg)
535
- # add_text(codebuf, rspace)
536
- # end
537
- # end
538
- # rest = $' || input
539
- # parse_exprs(codebuf, rest)
540
- #end
541
- #
542
- #def parse_exprs(codebuf, input)
543
- # unless @expr_pattern
544
- # ch = Regexp.escape(@embchar)
545
- # if @pattern
546
- # left, right = @pattern.split(' ')
547
- # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}|#{left}(=+)(.*?)#{right}/
548
- # else
549
- # @expr_pattern = /#{ch}(!*)?\{(.*?)\}#{ch}/
550
- # end
551
- # end
552
- # pos = 0
553
- # input.scan(@expr_pattern) do |indicator1, code1, indicator2, code2|
554
- # indicator = indicator1 || indicator2
555
- # code = code1 || code2
556
- # match = Regexp.last_match
557
- # len = match.begin(0) - pos
558
- # text = input[pos, len]
559
- # pos = match.end(0)
560
- # add_text(codebuf, text) # unless text.empty?
561
- # add_pi_expr(codebuf, code, indicator)
562
- # end
563
- # rest = $' || input
564
- # add_text(codebuf, rest)
565
- #end
566
- #++
567
-
568
- def add_pi_stmt(codebuf, code, pi_arg) # :nodoc:
569
- case pi_arg
570
- when nil ; add_stmt(codebuf, code)
571
- when 'header' ; @header = code
572
- when 'footer' ; @footer = code
573
- when 'comment'; add_stmt(codebuf, "\n" * code.count("\n"))
574
- when 'value' ; add_expr_literal(codebuf, code)
575
- else ; add_stmt(codebuf, code)
576
- end
577
- end
578
-
579
- def add_pi_expr(codebuf, code, indicator) # :nodoc:
580
- case indicator
581
- when nil, '', '==' # @{...}@ or <%== ... %>
582
- @escape == false ? add_expr_literal(codebuf, code) : add_expr_escaped(codebuf, code)
583
- when '!', '=' # @!{...}@ or <%= ... %>
584
- @escape == false ? add_expr_escaped(codebuf, code) : add_expr_literal(codebuf, code)
585
- when '!!', '===' # @!!{...}@ or <%=== ... %>
586
- add_expr_debug(codebuf, code)
587
- else
588
- # ignore
589
- end
590
- end
591
-
592
- end
593
-
594
-
595
- end
596
- #--end of require 'erubis/converter'
597
- #--begin of require 'erubis/evaluator'
598
- ##
599
- ## $Rev: 94 $
600
- ## $Release: 2.5.0 $
601
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
602
- ##
603
-
604
- #--begin of require 'erubis/error'
605
- ##
606
- ## $Rev: 77 $
607
- ## $Release: 2.5.0 $
608
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
609
- ##
610
-
611
- module Erubis
612
-
613
-
614
- ##
615
- ## base error class
616
- ##
617
- class ErubisError < StandardError
618
- end
619
-
620
-
621
- ##
622
- ## raised when method or function is not supported
623
- ##
624
- class NotSupportedError < ErubisError
625
- end
626
-
627
-
628
- end
629
- #--end of require 'erubis/error'
630
- #--begin of require 'erubis/context'
631
- ##
632
- ## $Rev: 77 $
633
- ## $Release: 2.5.0 $
634
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
635
- ##
636
-
637
-
638
- module Erubis
639
-
640
-
641
- ##
642
- ## context object for Engine#evaluate
643
- ##
644
- ## ex.
645
- ## template = <<'END'
646
- ## Hello <%= @user %>!
647
- ## <% for item in @list %>
648
- ## - <%= item %>
649
- ## <% end %>
650
- ## END
651
- ##
652
- ## context = Erubis::Context.new(:user=>'World', :list=>['a','b','c'])
653
- ## # or
654
- ## # context = Erubis::Context.new
655
- ## # context[:user] = 'World'
656
- ## # context[:list] = ['a', 'b', 'c']
657
- ##
658
- ## eruby = Erubis::Eruby.new(template)
659
- ## print eruby.evaluate(context)
660
- ##
661
- class Context
662
- include Enumerable
663
-
664
- def initialize(hash=nil)
665
- hash.each do |name, value|
666
- self[name] = value
667
- end if hash
668
- end
669
-
670
- def [](key)
671
- return instance_variable_get("@#{key}")
672
- end
673
-
674
- def []=(key, value)
675
- return instance_variable_set("@#{key}", value)
676
- end
677
-
678
- def keys
679
- return instance_variables.collect { |name| name[1..-1] }
680
- end
681
-
682
- def each
683
- instance_variables.each do |name|
684
- key = name[1..-1]
685
- value = instance_variable_get(name)
686
- yield(key, value)
687
- end
688
- end
689
-
690
- def to_hash
691
- hash = {}
692
- self.keys.each { |key| hash[key] = self[key] }
693
- return hash
694
- end
695
-
696
- def update(context_or_hash)
697
- arg = context_or_hash
698
- if arg.is_a?(Hash)
699
- arg.each do |key, val|
700
- self[key] = val
701
- end
702
- else
703
- arg.instance_variables.each do |varname|
704
- key = varname[1..-1]
705
- val = arg.instance_variable_get(varname)
706
- self[key] = val
707
- end
708
- end
709
- end
710
-
711
- end
712
-
713
-
714
- end
715
- #--end of require 'erubis/context'
716
-
717
-
718
- module Erubis
719
-
720
- EMPTY_BINDING = binding()
721
-
722
-
723
- ##
724
- ## evaluate code
725
- ##
726
- module Evaluator
727
-
728
- def self.supported_properties # :nodoc:
729
- return []
730
- end
731
-
732
- attr_accessor :src, :filename
733
-
734
- def init_evaluator(properties)
735
- @filename = properties[:filename]
736
- end
737
-
738
- def result(*args)
739
- raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
740
- end
741
-
742
- def evaluate(*args)
743
- raise NotSupportedError.new("evaluation of code except Ruby is not supported.")
744
- end
745
-
746
- end
747
-
748
-
749
- ##
750
- ## evaluator for Ruby
751
- ##
752
- module RubyEvaluator
753
- include Evaluator
754
-
755
- def self.supported_properties # :nodoc:
756
- list = Evaluator.supported_properties
757
- return list
758
- end
759
-
760
- ## eval(@src) with binding object
761
- def result(_binding_or_hash=TOPLEVEL_BINDING)
762
- _arg = _binding_or_hash
763
- if _arg.is_a?(Hash)
764
- ## load _context data as local variables by eval
765
- #eval _arg.keys.inject("") { |s, k| s << "#{k.to_s} = _arg[#{k.inspect}];" }
766
- eval _arg.collect{|k,v| "#{k} = _arg[#{k.inspect}]; "}.join
767
- _arg = binding()
768
- end
769
- return eval(@src, _arg, (@filename || '(erubis)'))
770
- end
771
-
772
- ## invoke context.instance_eval(@src)
773
- def evaluate(context=Context.new)
774
- context = Context.new(context) if context.is_a?(Hash)
775
- #return context.instance_eval(@src, @filename || '(erubis)')
776
- @_proc ||= eval("proc { #{@src} }", Erubis::EMPTY_BINDING, @filename || '(erubis)')
777
- return context.instance_eval(&@_proc)
778
- end
779
-
780
- ## if object is an Class or Module then define instance method to it,
781
- ## else define singleton method to it.
782
- def def_method(object, method_name, filename=nil)
783
- m = object.is_a?(Module) ? :module_eval : :instance_eval
784
- object.__send__(m, "def #{method_name}; #{@src}; end", filename || @filename || '(erubis)')
785
- end
786
-
787
-
788
- end
789
-
790
-
791
- end
792
- #--end of require 'erubis/evaluator'
793
- #--already included require 'erubis/context'
794
-
795
-
796
- module Erubis
797
-
798
-
799
- ##
800
- ## (abstract) abstract engine class.
801
- ## subclass must include evaluator and converter module.
802
- ##
803
- class Engine
804
- #include Evaluator
805
- #include Converter
806
- #include Generator
807
-
808
- def initialize(input=nil, properties={})
809
- #@input = input
810
- init_generator(properties)
811
- init_converter(properties)
812
- init_evaluator(properties)
813
- @src = convert(input) if input
814
- end
815
-
816
-
817
- ##
818
- ## convert input string and set it to @src
819
- ##
820
- def convert!(input)
821
- @src = convert(input)
822
- end
823
-
824
-
825
- ##
826
- ## load file, write cache file, and return engine object.
827
- ## this method create cache file (filename + '.cache') automatically.
828
- ##
829
- def self.load_file(filename, properties={})
830
- cachename = filename + '.cache'
831
- properties[:filename] = filename
832
- if test(?f, cachename) && File.mtime(filename) <= File.mtime(cachename)
833
- engine = self.new(nil, properties)
834
- engine.src = File.read(cachename)
835
- else
836
- input = File.open(filename, 'rb') { |f| f.read }
837
- engine = self.new(input, properties)
838
- File.open(cachename, 'w') do |f|
839
- f.flock(File::LOCK_EX)
840
- f.write(engine.src)
841
- end
842
- end
843
- engine.src.untaint # ok?
844
- return engine
845
- end
846
-
847
-
848
- ##
849
- ## helper method to convert and evaluate input text with context object.
850
- ## context may be Binding, Hash, or Object.
851
- ##
852
- def process(input, context=nil, filename=nil)
853
- code = convert(input)
854
- filename ||= '(erubis)'
855
- if context.is_a?(Binding)
856
- return eval(code, context, filename)
857
- else
858
- context = Context.new(context) if context.is_a?(Hash)
859
- return context.instance_eval(code, filename)
860
- end
861
- end
862
-
863
-
864
- ##
865
- ## helper method evaluate Proc object with contect object.
866
- ## context may be Binding, Hash, or Object.
867
- ##
868
- def process_proc(proc_obj, context=nil, filename=nil)
869
- if context.is_a?(Binding)
870
- filename ||= '(erubis)'
871
- return eval(proc_obj, context, filename)
872
- else
873
- context = Context.new(context) if context.is_a?(Hash)
874
- return context.instance_eval(&proc_obj)
875
- end
876
- end
877
-
878
-
879
- end # end of class Engine
880
-
881
-
882
- ##
883
- ## (abstract) base engine class for Eruby, Eperl, Ejava, and so on.
884
- ## subclass must include generator.
885
- ##
886
- class Basic::Engine < Engine
887
- include Evaluator
888
- include Basic::Converter
889
- include Generator
890
- end
891
-
892
-
893
- class PI::Engine < Engine
894
- include Evaluator
895
- include PI::Converter
896
- include Generator
897
- end
898
-
899
-
900
- end
901
- #--end of require 'erubis/engine'
902
- #require 'erubis/generator'
903
- #require 'erubis/converter'
904
- #require 'erubis/evaluator'
905
- #require 'erubis/error'
906
- #require 'erubis/context'
907
- #--begin of require 'erubis/helper'
908
- ##
909
- ## $Rev: 89 $
910
- ## $Release: 2.5.0 $
911
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
912
- ##
913
-
914
-
915
- module Erubis
916
-
917
- ##
918
- ## helper for xml
919
- ##
920
- module XmlHelper
921
-
922
- module_function
923
-
924
- ESCAPE_TABLE = {
925
- '&' => '&amp;',
926
- '<' => '&lt;',
927
- '>' => '&gt;',
928
- '"' => '&quot;',
929
- "'" => '&#039;',
930
- }
931
-
932
- def escape_xml(value)
933
- value.to_s.gsub(/[&<>"]/) { |s| ESCAPE_TABLE[s] } # or /[&<>"']/
934
- #value.to_s.gsub(/[&<>"]/) { ESCAPE_TABLE[$&] }
935
- end
936
-
937
- def escape_xml2(value)
938
- return value.to_s.gsub(/\&/,'&amp;').gsub(/</,'&lt;').gsub(/>/,'&gt;').gsub(/"/,'&quot;')
939
- end
940
-
941
- alias h escape_xml
942
- alias html_escape escape_xml
943
-
944
- def url_encode(str)
945
- return str.gsub(/[^-_.a-zA-Z0-9]+/) { |s|
946
- s.unpack('C*').collect { |i| "%%%02X" % i }.join
947
- }
948
- end
949
-
950
- alias u url_encode
951
-
952
- end
953
-
954
-
955
- end
956
- #--end of require 'erubis/helper'
957
- #--begin of require 'erubis/enhancer'
958
- ##
959
- ## $Rev: 93 $
960
- ## $Release: 2.5.0 $
961
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
962
- ##
963
-
964
-
965
- module Erubis
966
-
967
-
968
- ##
969
- ## switch '<%= ... %>' to escaped and '<%== ... %>' to unescaped
970
- ##
971
- ## ex.
972
- ## class XmlEruby < Eruby
973
- ## include EscapeEnhancer
974
- ## end
975
- ##
976
- ## this is language-indenedent.
977
- ##
978
- module EscapeEnhancer
979
-
980
- def self.desc # :nodoc:
981
- "switch '<%= %>' to escaped and '<%== %>' to unescaped"
982
- end
983
-
984
- #--
985
- #def self.included(klass)
986
- # klass.class_eval <<-END
987
- # alias _add_expr_literal add_expr_literal
988
- # alias _add_expr_escaped add_expr_escaped
989
- # alias add_expr_literal _add_expr_escaped
990
- # alias add_expr_escaped _add_expr_literal
991
- # END
992
- #end
993
- #++
994
-
995
- def add_expr(src, code, indicator)
996
- case indicator
997
- when '='
998
- @escape ? add_expr_literal(src, code) : add_expr_escaped(src, code)
999
- when '=='
1000
- @escape ? add_expr_escaped(src, code) : add_expr_literal(src, code)
1001
- when '==='
1002
- add_expr_debug(src, code)
1003
- end
1004
- end
1005
-
1006
- end
1007
-
1008
-
1009
- #--
1010
- ## (obsolete)
1011
- #module FastEnhancer
1012
- #end
1013
- #++
1014
-
1015
-
1016
- ##
1017
- ## use $stdout instead of string
1018
- ##
1019
- ## this is only for Eruby.
1020
- ##
1021
- module StdoutEnhancer
1022
-
1023
- def self.desc # :nodoc:
1024
- "use $stdout instead of array buffer or string buffer"
1025
- end
1026
-
1027
- def add_preamble(src)
1028
- src << "_buf = $stdout;"
1029
- end
1030
-
1031
- def add_postamble(src)
1032
- src << "\n''\n"
1033
- end
1034
-
1035
- end
1036
-
1037
-
1038
- ##
1039
- ## use print statement instead of '_buf << ...'
1040
- ##
1041
- ## this is only for Eruby.
1042
- ##
1043
- module PrintOutEnhancer
1044
-
1045
- def self.desc # :nodoc:
1046
- "use print statement instead of '_buf << ...'"
1047
- end
1048
-
1049
- def add_preamble(src)
1050
- end
1051
-
1052
- def add_text(src, text)
1053
- src << " print '" << escape_text(text) << "';" unless text.empty?
1054
- end
1055
-
1056
- def add_expr_literal(src, code)
1057
- src << ' print((' << code << ').to_s);'
1058
- end
1059
-
1060
- def add_expr_escaped(src, code)
1061
- src << ' print ' << escaped_expr(code) << ';'
1062
- end
1063
-
1064
- def add_postamble(src)
1065
- src << "\n" unless src[-1] == ?\n
1066
- end
1067
-
1068
- end
1069
-
1070
-
1071
- ##
1072
- ## enable print function
1073
- ##
1074
- ## Notice: use Eruby#evaluate() and don't use Eruby#result()
1075
- ## to be enable print function.
1076
- ##
1077
- ## this is only for Eruby.
1078
- ##
1079
- module PrintEnabledEnhancer
1080
-
1081
- def self.desc # :nodoc:
1082
- "enable to use print function in '<% %>'"
1083
- end
1084
-
1085
- def add_preamble(src)
1086
- src << "@_buf = "
1087
- super
1088
- end
1089
-
1090
- def print(*args)
1091
- args.each do |arg|
1092
- @_buf << arg.to_s
1093
- end
1094
- end
1095
-
1096
- def evaluate(context=nil)
1097
- _src = @src
1098
- if context.is_a?(Hash)
1099
- context.each do |key, val| instance_variable_set("@#{key}", val) end
1100
- elsif context
1101
- context.instance_variables.each do |name|
1102
- instance_variable_set(name, context.instance_variable_get(name))
1103
- end
1104
- end
1105
- return instance_eval(_src, (@filename || '(erubis)'))
1106
- end
1107
-
1108
- end
1109
-
1110
-
1111
- ##
1112
- ## return array instead of string
1113
- ##
1114
- ## this is only for Eruby.
1115
- ##
1116
- module ArrayEnhancer
1117
-
1118
- def self.desc # :nodoc:
1119
- "return array instead of string"
1120
- end
1121
-
1122
- def add_preamble(src)
1123
- src << "_buf = [];"
1124
- end
1125
-
1126
- def add_postamble(src)
1127
- src << "\n" unless src[-1] == ?\n
1128
- src << "_buf\n"
1129
- end
1130
-
1131
- end
1132
-
1133
-
1134
- ##
1135
- ## use an Array object as buffer (included in Eruby by default)
1136
- ##
1137
- ## this is only for Eruby.
1138
- ##
1139
- module ArrayBufferEnhancer
1140
-
1141
- def self.desc # :nodoc:
1142
- "use an Array object for buffering (included in Eruby class)"
1143
- end
1144
-
1145
- def add_preamble(src)
1146
- src << "_buf = [];"
1147
- end
1148
-
1149
- def add_postamble(src)
1150
- src << "\n" unless src[-1] == ?\n
1151
- src << "_buf.join\n"
1152
- end
1153
-
1154
- end
1155
-
1156
-
1157
- ##
1158
- ## use String class for buffering
1159
- ##
1160
- ## this is only for Eruby.
1161
- ##
1162
- module StringBufferEnhancer
1163
-
1164
- def self.desc # :nodoc:
1165
- "use a String object for buffering"
1166
- end
1167
-
1168
- def add_preamble(src)
1169
- src << "_buf = '';"
1170
- end
1171
-
1172
- def add_postamble(src)
1173
- src << "\n" unless src[-1] == ?\n
1174
- src << "_buf.to_s\n"
1175
- end
1176
-
1177
- end
1178
-
1179
-
1180
- ##
1181
- ## use StringIO class for buffering
1182
- ##
1183
- ## this is only for Eruby.
1184
- ##
1185
- module StringIOEnhancer # :nodoc:
1186
-
1187
- def self.desc # :nodoc:
1188
- "use a StringIO object for buffering"
1189
- end
1190
-
1191
- def add_preamble(src)
1192
- src << "_buf = StringIO.new;"
1193
- end
1194
-
1195
- def add_postamble(src)
1196
- src << "\n" unless src[-1] == ?\n
1197
- src << "_buf.string\n"
1198
- end
1199
-
1200
- end
1201
-
1202
-
1203
- ##
1204
- ## set buffer variable name to '_erbout' as well as '_buf'
1205
- ##
1206
- ## this is only for Eruby.
1207
- ##
1208
- module ErboutEnhancer
1209
-
1210
- def self.desc # :nodoc:
1211
- "set '_erbout = _buf = \"\";' to be compatible with ERB."
1212
- end
1213
-
1214
- def add_preamble(src)
1215
- src << "_erbout = _buf = '';"
1216
- end
1217
-
1218
- def add_postamble(src)
1219
- src << "\n" unless src[-1] == ?\n
1220
- src << "_buf.to_s\n"
1221
- end
1222
-
1223
- end
1224
-
1225
-
1226
- ##
1227
- ## remove text and leave code, especially useful when debugging.
1228
- ##
1229
- ## ex.
1230
- ## $ erubis -s -E NoText file.eruby | more
1231
- ##
1232
- ## this is language independent.
1233
- ##
1234
- module NoTextEnhancer
1235
-
1236
- def self.desc # :nodoc:
1237
- "remove text and leave code (useful when debugging)"
1238
- end
1239
-
1240
- def add_text(src, text)
1241
- src << ("\n" * text.count("\n"))
1242
- if text[-1] != ?\n
1243
- text =~ /^(.*?)\z/
1244
- src << (' ' * $1.length)
1245
- end
1246
- end
1247
-
1248
- end
1249
-
1250
-
1251
- ##
1252
- ## remove code and leave text, especially useful when validating HTML tags.
1253
- ##
1254
- ## ex.
1255
- ## $ erubis -s -E NoCode file.eruby | tidy -errors
1256
- ##
1257
- ## this is language independent.
1258
- ##
1259
- module NoCodeEnhancer
1260
-
1261
- def self.desc # :nodoc:
1262
- "remove code and leave text (useful when validating HTML)"
1263
- end
1264
-
1265
- def add_preamble(src)
1266
- end
1267
-
1268
- def add_postamble(src)
1269
- end
1270
-
1271
- def add_text(src, text)
1272
- src << text
1273
- end
1274
-
1275
- def add_expr(src, code, indicator)
1276
- src << "\n" * code.count("\n")
1277
- end
1278
-
1279
- def add_stmt(src, code)
1280
- src << "\n" * code.count("\n")
1281
- end
1282
-
1283
- end
1284
-
1285
-
1286
- ##
1287
- ## get convert faster, but spaces around '<%...%>' are not trimmed.
1288
- ##
1289
- ## this is language-independent.
1290
- ##
1291
- module SimplifyEnhancer
1292
-
1293
- def self.desc # :nodoc:
1294
- "get convert faster but leave spaces around '<% %>'"
1295
- end
1296
-
1297
- #DEFAULT_REGEXP = /(^[ \t]*)?<%(=+|\#)?(.*?)-?%>([ \t]*\r?\n)?/m
1298
- SIMPLE_REGEXP = /<%(=+|\#)?(.*?)-?%>/m
1299
-
1300
- def convert(input)
1301
- src = ""
1302
- add_preamble(src)
1303
- #regexp = pattern_regexp(@pattern)
1304
- pos = 0
1305
- input.scan(SIMPLE_REGEXP) do |indicator, code|
1306
- match = Regexp.last_match
1307
- index = match.begin(0)
1308
- text = input[pos, index - pos]
1309
- pos = match.end(0)
1310
- add_text(src, text)
1311
- if !indicator # <% %>
1312
- add_stmt(src, code)
1313
- elsif indicator[0] == ?\# # <%# %>
1314
- n = code.count("\n")
1315
- add_stmt(src, "\n" * n)
1316
- else # <%= %>
1317
- add_expr(src, code, indicator)
1318
- end
1319
- end
1320
- rest = $' || input
1321
- add_text(src, rest)
1322
- add_postamble(src)
1323
- return src
1324
- end
1325
-
1326
- end
1327
-
1328
-
1329
- ##
1330
- ## enable to use other embedded expression pattern (default is '\[= =\]').
1331
- ##
1332
- ## notice! this is an experimental. spec may change in the future.
1333
- ##
1334
- ## ex.
1335
- ## input = <<END
1336
- ## <% for item in list %>
1337
- ## <%= item %> : <%== item %>
1338
- ## [= item =] : [== item =]
1339
- ## <% end %>
1340
- ## END
1341
- ##
1342
- ## class BiPatternEruby
1343
- ## include BiPatternEnhancer
1344
- ## end
1345
- ## eruby = BiPatternEruby.new(input, :bipattern=>'\[= =\]')
1346
- ## list = ['<a>', 'b&b', '"c"']
1347
- ## print eruby.result(binding())
1348
- ##
1349
- ## ## output
1350
- ## <a> : &lt;a&gt;
1351
- ## <a> : &lt;a&gt;
1352
- ## b&b : b&amp;b
1353
- ## b&b : b&amp;b
1354
- ## "c" : &quot;c&quot;
1355
- ## "c" : &quot;c&quot;
1356
- ##
1357
- ## this is language independent.
1358
- ##
1359
- module BiPatternEnhancer
1360
-
1361
- def self.desc # :nodoc:
1362
- "another embedded expression pattern (default '\[= =\]')."
1363
- end
1364
-
1365
- def initialize(input, properties={})
1366
- self.bipattern = properties[:bipattern] # or '\$\{ \}'
1367
- super
1368
- end
1369
-
1370
- ## when pat is nil then '\[= =\]' is used
1371
- def bipattern=(pat) # :nodoc:
1372
- @bipattern = pat || '\[= =\]'
1373
- pre, post = @bipattern.split()
1374
- @bipattern_regexp = /(.*?)#{pre}(=*)(.*?)#{post}/m
1375
- end
1376
-
1377
- def add_text(src, text)
1378
- return unless text
1379
- text.scan(@bipattern_regexp) do |txt, indicator, code|
1380
- super(src, txt)
1381
- add_expr(src, code, '=' + indicator)
1382
- end
1383
- rest = $' || text
1384
- super(src, rest)
1385
- end
1386
-
1387
- end
1388
-
1389
-
1390
- ##
1391
- ## regards lines starting with '%' as program code
1392
- ##
1393
- ## this is for compatibility to eruby and ERB.
1394
- ##
1395
- ## this is language-independent.
1396
- ##
1397
- module PercentLineEnhancer
1398
-
1399
- def self.desc # :nodoc:
1400
- "regard lines starting with '%' as program code"
1401
- end
1402
-
1403
- def add_text(src, text)
1404
- pos = 0
1405
- text2 = ''
1406
- text.scan(/^\%(.*?\r?\n)/) do
1407
- line = $1
1408
- match = Regexp.last_match
1409
- len = match.begin(0) - pos
1410
- str = text[pos, len]
1411
- pos = match.end(0)
1412
- if text2.empty?
1413
- text2 = str
1414
- else
1415
- text2 << str
1416
- end
1417
- if line[0] == ?%
1418
- text2 << line
1419
- else
1420
- super(src, text2)
1421
- text2 = ''
1422
- add_stmt(src, line)
1423
- end
1424
- end
1425
- rest = pos == 0 ? text : $' # or $' || text
1426
- unless text2.empty?
1427
- text2 << rest if rest
1428
- rest = text2
1429
- end
1430
- super(src, rest)
1431
- end
1432
-
1433
- end
1434
-
1435
-
1436
- ##
1437
- ## [experimental] allow header and footer in eRuby script
1438
- ##
1439
- ## ex.
1440
- ## ====================
1441
- ## ## without header and footer
1442
- ## $ cat ex1.eruby
1443
- ## <% def list_items(list) %>
1444
- ## <% for item in list %>
1445
- ## <li><%= item %></li>
1446
- ## <% end %>
1447
- ## <% end %>
1448
- ##
1449
- ## $ erubis -s ex1.eruby
1450
- ## _buf = []; def list_items(list)
1451
- ## ; for item in list
1452
- ## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
1453
- ## '; end
1454
- ## ; end
1455
- ## ;
1456
- ## _buf.join
1457
- ##
1458
- ## ## with header and footer
1459
- ## $ cat ex2.eruby
1460
- ## <!--#header:
1461
- ## def list_items(list)
1462
- ## #-->
1463
- ## <% for item in list %>
1464
- ## <li><%= item %></li>
1465
- ## <% end %>
1466
- ## <!--#footer:
1467
- ## end
1468
- ## #-->
1469
- ##
1470
- ## $ erubis -s -c HeaderFooterEruby ex4.eruby
1471
- ##
1472
- ## def list_items(list)
1473
- ## _buf = []; _buf << '
1474
- ## '; for item in list
1475
- ## ; _buf << '<li>'; _buf << ( item ).to_s; _buf << '</li>
1476
- ## '; end
1477
- ## ; _buf << '
1478
- ## ';
1479
- ## _buf.join
1480
- ## end
1481
- ##
1482
- ## ====================
1483
- ##
1484
- ## this is language-independent.
1485
- ##
1486
- module HeaderFooterEnhancer
1487
-
1488
- def self.desc # :nodoc:
1489
- "allow header/footer in document (ex. '<!--#header: #-->')"
1490
- end
1491
-
1492
- HEADER_FOOTER_PATTERN = /(.*?)(^[ \t]*)?<!--\#(\w+):(.*?)\#-->([ \t]*\r?\n)?/m
1493
-
1494
- def add_text(src, text)
1495
- text.scan(HEADER_FOOTER_PATTERN) do |txt, lspace, word, content, rspace|
1496
- flag_trim = @trim && lspace && rspace
1497
- super(src, txt)
1498
- content = "#{lspace}#{content}#{rspace}" if flag_trim
1499
- super(src, lspace) if !flag_trim && lspace
1500
- instance_variable_set("@#{word}", content)
1501
- super(src, rspace) if !flag_trim && rspace
1502
- end
1503
- rest = $' || text
1504
- super(src, rest)
1505
- end
1506
-
1507
- attr_accessor :header, :footer
1508
-
1509
- def convert(input)
1510
- source = super
1511
- return @src = "#{@header}#{source}#{@footer}"
1512
- end
1513
-
1514
- end
1515
-
1516
-
1517
- ##
1518
- ## delete indentation of HTML.
1519
- ##
1520
- ## this is language-independent.
1521
- ##
1522
- module DeleteIndentEnhancer
1523
-
1524
- def self.desc # :nodoc:
1525
- "delete indentation of HTML."
1526
- end
1527
-
1528
- def convert_input(src, input)
1529
- input = input.gsub(/^[ \t]+</, '<')
1530
- super(src, input)
1531
- end
1532
-
1533
- end
1534
-
1535
-
1536
- ##
1537
- ## convert "<h1><%=title%></h1>" into "_buf << %Q`<h1>#{title}</h1>`"
1538
- ##
1539
- ## this is only for Eruby.
1540
- ##
1541
- module InterpolationEnhancer
1542
-
1543
- def self.desc # :nodoc:
1544
- "convert '<p><%=text%></p>' into '_buf << %Q`<p>\#{text}</p>`'"
1545
- end
1546
-
1547
- def convert_input(src, input)
1548
- pat = @pattern
1549
- regexp = pat.nil? || pat == '<% %>' ? Basic::Converter::DEFAULT_REGEXP : pattern_regexp(pat)
1550
- pos = 0
1551
- is_bol = true # is beginning of line
1552
- str = ''
1553
- input.scan(regexp) do |indicator, code, rspace|
1554
- match = Regexp.last_match()
1555
- len = match.begin(0) - pos
1556
- text = input[pos, len]
1557
- pos = match.end(0)
1558
- ch = indicator ? indicator[0] : nil
1559
- lspace = ch == ?= ? nil : detect_spaces_at_bol(text, is_bol)
1560
- is_bol = rspace ? true : false
1561
- _add_text_to_str(str, text)
1562
- ## * when '<%= %>', do nothing
1563
- ## * when '<% %>' or '<%# %>', delete spaces iff only spaces are around '<% %>'
1564
- if ch == ?= # <%= %>
1565
- str << lspace if lspace
1566
- add_expr(str, code, indicator)
1567
- str << rspace if rspace
1568
- elsif ch == ?\# # <%# %>
1569
- n = code.count("\n") + (rspace ? 1 : 0)
1570
- if @trim && lspace && rspace
1571
- add_text(src, str)
1572
- str = ''
1573
- add_stmt(src, "\n" * n)
1574
- else
1575
- str << lspace if lspace
1576
- add_text(src, str)
1577
- str = ''
1578
- add_stmt(src, "\n" * n)
1579
- str << rspace if rspace
1580
- end
1581
- else # <% %>
1582
- if @trim && lspace && rspace
1583
- add_text(src, str)
1584
- str = ''
1585
- add_stmt(src, "#{lspace}#{code}#{rspace}")
1586
- else
1587
- str << lspace if lspace
1588
- add_text(src, str)
1589
- str = ''
1590
- add_stmt(src, code)
1591
- str << rspace if rspace
1592
- end
1593
- end
1594
- end
1595
- rest = $' || input # add input when no matched
1596
- _add_text_to_str(str, rest)
1597
- add_text(src, str)
1598
- end
1599
-
1600
- def add_text(src, text)
1601
- return if !text || text.empty?
1602
- #src << " _buf << %Q`" << text << "`;"
1603
- if text[-1] == ?\n
1604
- text[-1] = "\\n"
1605
- src << " _buf << %Q`" << text << "`\n"
1606
- else
1607
- src << " _buf << %Q`" << text << "`;"
1608
- end
1609
- end
1610
-
1611
- def _add_text_to_str(str, text)
1612
- return if !text || text.empty?
1613
- text.gsub!(/['\#\\]/, '\\\\\&')
1614
- str << text
1615
- end
1616
-
1617
- def add_expr_escaped(str, code)
1618
- str << "\#{#{escaped_expr(code)}}"
1619
- end
1620
-
1621
- def add_expr_literal(str, code)
1622
- str << "\#{#{code}}"
1623
- end
1624
-
1625
- end
1626
-
1627
-
1628
- end
1629
- #--end of require 'erubis/enhancer'
1630
- #require 'erubis/tiny'
1631
- #--begin of require 'erubis/engine/eruby'
1632
- ##
1633
- ## $Rev: 77 $
1634
- ## $Release: 2.5.0 $
1635
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
1636
- ##
1637
-
1638
- #--already included require 'erubis/engine'
1639
- #--already included require 'erubis/enhancer'
1640
-
1641
-
1642
- module Erubis
1643
-
1644
-
1645
- ##
1646
- ## code generator for Ruby
1647
- ##
1648
- module RubyGenerator
1649
- include Generator
1650
- #include ArrayBufferEnhancer
1651
- include StringBufferEnhancer
1652
-
1653
- def init_generator(properties={})
1654
- super
1655
- @escapefunc ||= "Erubis::XmlHelper.escape_xml"
1656
- end
1657
-
1658
- def self.supported_properties() # :nodoc:
1659
- return []
1660
- end
1661
-
1662
- def escape_text(text)
1663
- text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\'
1664
- end
1665
-
1666
- def escaped_expr(code)
1667
- return "#{@escapefunc}(#{code})"
1668
- end
1669
-
1670
- #--
1671
- #def add_preamble(src)
1672
- # src << "_buf = [];"
1673
- #end
1674
- #++
1675
-
1676
- def add_text(src, text)
1677
- src << " _buf << '" << escape_text(text) << "';" unless text.empty?
1678
- end
1679
-
1680
- def add_stmt(src, code)
1681
- #src << code << ';'
1682
- src << code
1683
- src << ';' unless code[-1] == ?\n
1684
- end
1685
-
1686
- def add_expr_literal(src, code)
1687
- src << ' _buf << (' << code << ').to_s;'
1688
- end
1689
-
1690
- def add_expr_escaped(src, code)
1691
- src << ' _buf << ' << escaped_expr(code) << ';'
1692
- end
1693
-
1694
- def add_expr_debug(src, code)
1695
- code.strip!
1696
- s = (code.dump =~ /\A"(.*)"\z/) && $1
1697
- src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
1698
- end
1699
-
1700
- #--
1701
- #def add_postamble(src)
1702
- # src << "\n_buf.join\n"
1703
- #end
1704
- #++
1705
-
1706
- end
1707
-
1708
-
1709
- ##
1710
- ## engine for Ruby
1711
- ##
1712
- class Eruby < Basic::Engine
1713
- include RubyEvaluator
1714
- include RubyGenerator
1715
- end
1716
-
1717
-
1718
- ##
1719
- ## fast engine for Ruby
1720
- ##
1721
- class FastEruby < Eruby
1722
- include InterpolationEnhancer
1723
- end
1724
-
1725
-
1726
- ##
1727
- ## swtich '<%= %>' to escaped and '<%== %>' to not escaped
1728
- ##
1729
- class EscapedEruby < Eruby
1730
- include EscapeEnhancer
1731
- end
1732
-
1733
-
1734
- ##
1735
- ## sanitize expression (<%= ... %>) by default
1736
- ##
1737
- ## this is equivalent to EscapedEruby and is prepared only for compatibility.
1738
- ##
1739
- class XmlEruby < Eruby
1740
- include EscapeEnhancer
1741
- end
1742
-
1743
-
1744
- class PI::Eruby < PI::Engine
1745
- include RubyEvaluator
1746
- include RubyGenerator
1747
-
1748
- def init_converter(properties={})
1749
- @pi = 'rb'
1750
- super(properties)
1751
- end
1752
-
1753
- end
1754
-
1755
-
1756
- end
1757
- #--end of require 'erubis/engine/eruby'
1758
- #require 'erubis/engine/enhanced' # enhanced eruby engines
1759
- #require 'erubis/engine/optimized' # generates optimized ruby code
1760
- #require 'erubis/engine/ephp'
1761
- #require 'erubis/engine/ec'
1762
- #require 'erubis/engine/ejava'
1763
- #require 'erubis/engine/escheme'
1764
- #require 'erubis/engine/eperl'
1765
- #require 'erubis/engine/ejavascript'
1766
-
1767
- #--begin of require 'erubis/local-setting'
1768
- ##
1769
- ## $Rev: 77 $
1770
- ## $Release: 2.5.0 $
1771
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
1772
- ##
1773
-
1774
- ##
1775
- ## you can add site-local settings here.
1776
- ## this files is required by erubis.rb
1777
- ##
1778
- #--end of require 'erubis/local-setting'
1779
- #--end of require 'erubis'
1780
- #--begin of require 'erubis/tiny'
1781
- ##
1782
- ## $Rev: 77 $
1783
- ## $Release: 2.5.0 $
1784
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
1785
- ##
1786
-
1787
- module Erubis
1788
-
1789
- ##
1790
- ## tiny and the simplest implementation of eRuby
1791
- ##
1792
- ## ex.
1793
- ## eruby = TinyEruby.new(File.read('example.rhtml'))
1794
- ## print eruby.src # print ruby code
1795
- ## print eruby.result(binding()) # eval ruby code with Binding object
1796
- ## print eruby.evalute(context) # eval ruby code with context object
1797
- ##
1798
- class TinyEruby
1799
-
1800
- def initialize(input=nil)
1801
- @src = convert(input) if input
1802
- end
1803
- attr_reader :src
1804
-
1805
- EMBEDDED_PATTERN = /<%(=+|\#)?(.*?)-?%>/m
1806
-
1807
- def convert(input)
1808
- src = "_buf = '';" # preamble
1809
- pos = 0
1810
- input.scan(EMBEDDED_PATTERN) do |indicator, code|
1811
- match = Regexp.last_match
1812
- len = match.begin(0) - pos
1813
- text = input[pos, len]
1814
- pos = match.end(0)
1815
- #src << " _buf << '" << escape_text(text) << "';"
1816
- text.gsub!(/['\\]/, '\\\\\&')
1817
- src << " _buf << '" << text << "';" unless text.empty?
1818
- if !indicator # <% %>
1819
- src << code << ";"
1820
- elsif indicator == '#' # <%# %>
1821
- src << ("\n" * code.count("\n"))
1822
- else # <%= %>
1823
- src << " _buf << (" << code << ").to_s;"
1824
- end
1825
- end
1826
- rest = $' || input
1827
- #src << " _buf << '" << escape_text(rest) << "';"
1828
- rest.gsub!(/['\\]/, '\\\\\&')
1829
- src << " _buf << '" << rest << "';" unless rest.empty?
1830
- src << "\n_buf.to_s\n" # postamble
1831
- return src
1832
- end
1833
-
1834
- #def escape_text(text)
1835
- # return text.gsub!(/['\\]/, '\\\\\&') || text
1836
- #end
1837
-
1838
- def result(_binding=TOPLEVEL_BINDING)
1839
- eval @src, _binding
1840
- end
1841
-
1842
- def evaluate(_context=Object.new)
1843
- if _context.is_a?(Hash)
1844
- _obj = Object.new
1845
- _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
1846
- _context = _obj
1847
- end
1848
- _context.instance_eval @src
1849
- end
1850
-
1851
- end
1852
-
1853
-
1854
-
1855
- module PI
1856
- end
1857
-
1858
- class PI::TinyEruby
1859
-
1860
- def initialize(input=nil, options={})
1861
- @escape = options[:escape] || 'Erubis::XmlHelper.escape_xml'
1862
- @src = convert(input) if input
1863
- end
1864
-
1865
- attr_reader :src
1866
-
1867
- EMBEDDED_PATTERN = /(^[ \t]*)?<\?rb(\s.*?)\?>([ \t]*\r?\n)?|@(!+)?\{(.*?)\}@/m
1868
-
1869
- def convert(input)
1870
- src = "_buf = '';" # preamble
1871
- pos = 0
1872
- input.scan(EMBEDDED_PATTERN) do |lspace, stmt, rspace, indicator, expr|
1873
- match = Regexp.last_match
1874
- len = match.begin(0) - pos
1875
- text = input[pos, len]
1876
- pos = match.end(0)
1877
- #src << " _buf << '" << escape_text(text) << "';"
1878
- text.gsub!(/['\\]/, '\\\\\&')
1879
- src << " _buf << '" << text << "';" unless text.empty?
1880
- if stmt # <?rb ... ?>
1881
- if lspace && rspace
1882
- src << "#{lspace}#{stmt}#{rspace}"
1883
- else
1884
- src << " _buf << '" << lspace << "';" if lspace
1885
- src << stmt << ";"
1886
- src << " _buf << '" << rspace << "';" if rspace
1887
- end
1888
- else # ${...}, $!{...}
1889
- if !indicator
1890
- src << " _buf << " << @escape << "(" << expr << ");"
1891
- elsif indicator == '!'
1892
- src << " _buf << (" << expr << ").to_s;"
1893
- end
1894
- end
1895
- end
1896
- rest = $' || input
1897
- #src << " _buf << '" << escape_text(rest) << "';"
1898
- rest.gsub!(/['\\]/, '\\\\\&')
1899
- src << " _buf << '" << rest << "';" unless rest.empty?
1900
- src << "\n_buf.to_s\n" # postamble
1901
- return src
1902
- end
1903
-
1904
- #def escape_text(text)
1905
- # return text.gsub!(/['\\]/, '\\\\\&') || text
1906
- #end
1907
-
1908
- def result(_binding=TOPLEVEL_BINDING)
1909
- eval @src, _binding
1910
- end
1911
-
1912
- def evaluate(_context=Object.new)
1913
- if _context.is_a?(Hash)
1914
- _obj = Object.new
1915
- _context.each do |k, v| _obj.instance_variable_set("@#{k}", v) end
1916
- _context = _obj
1917
- end
1918
- _context.instance_eval @src
1919
- end
1920
-
1921
- end
1922
-
1923
-
1924
- end
1925
- #--end of require 'erubis/tiny'
1926
- #--begin of require 'erubis/engine/enhanced'
1927
- ##
1928
- ## $Rev: 77 $
1929
- ## $Release: 2.5.0 $
1930
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
1931
- ##
1932
-
1933
- #--already included require 'erubis/enhancer'
1934
- #--already included require 'erubis/engine/eruby'
1935
-
1936
-
1937
- module Erubis
1938
-
1939
-
1940
- #--
1941
- ## moved to engine/ruby.rb
1942
- #class EscapedEruby < Eruby
1943
- # include EscapeEnhancer
1944
- #end
1945
- #++
1946
-
1947
-
1948
- #--
1949
- ### (obsolete)
1950
- #class FastEruby < Eruby
1951
- # include FastEnhancer
1952
- #end
1953
- #++
1954
-
1955
-
1956
- class StdoutEruby < Eruby
1957
- include StdoutEnhancer
1958
- end
1959
-
1960
-
1961
- class PrintOutEruby < Eruby
1962
- include PrintOutEnhancer
1963
- end
1964
-
1965
-
1966
- class PrintEnabledEruby < Eruby
1967
- include PrintEnabledEnhancer
1968
- end
1969
-
1970
-
1971
- class ArrayEruby < Eruby
1972
- include ArrayEnhancer
1973
- end
1974
-
1975
-
1976
- class ArrayBufferEruby < Eruby
1977
- include ArrayBufferEnhancer
1978
- end
1979
-
1980
-
1981
- class StringBufferEruby < Eruby
1982
- include StringBufferEnhancer
1983
- end
1984
-
1985
-
1986
- class StringIOEruby < Eruby
1987
- include StringIOEnhancer
1988
- end
1989
-
1990
-
1991
- class ErboutEruby < Eruby
1992
- include ErboutEnhancer
1993
- end
1994
-
1995
-
1996
- class NoTextEruby < Eruby
1997
- include NoTextEnhancer
1998
- end
1999
-
2000
-
2001
- class NoCodeEruby < Eruby
2002
- include NoCodeEnhancer
2003
- end
2004
-
2005
-
2006
- class SimplifiedEruby < Eruby
2007
- include SimplifyEnhancer
2008
- end
2009
-
2010
-
2011
- class StdoutSimplifiedEruby < Eruby
2012
- include StdoutEnhancer
2013
- include SimplifyEnhancer
2014
- end
2015
-
2016
-
2017
- class PrintOutSimplifiedEruby < Eruby
2018
- include PrintOutEnhancer
2019
- include SimplifyEnhancer
2020
- end
2021
-
2022
-
2023
- class BiPatternEruby < Eruby
2024
- include BiPatternEnhancer
2025
- end
2026
-
2027
-
2028
- class PercentLineEruby < Eruby
2029
- include PercentLineEnhancer
2030
- end
2031
-
2032
-
2033
- class HeaderFooterEruby < Eruby
2034
- include HeaderFooterEnhancer
2035
- end
2036
-
2037
-
2038
- class DeleteIndentEruby < Eruby
2039
- include DeleteIndentEnhancer
2040
- end
2041
-
2042
-
2043
- class InterpolationEruby < Eruby
2044
- include InterpolationEnhancer
2045
- end
2046
-
2047
-
2048
- end
2049
- #--end of require 'erubis/engine/enhanced'
2050
- #--begin of require 'erubis/engine/optimized'
2051
- ##
2052
- ## $Rev: 77 $
2053
- ## $Release: 2.5.0 $
2054
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
2055
- ##
2056
-
2057
-
2058
- #--already included require 'erubis/engine/eruby'
2059
-
2060
-
2061
- module Erubis
2062
-
2063
-
2064
- module OptimizedGenerator
2065
- include Generator
2066
-
2067
- def self.supported_properties() # :nodoc:
2068
- return []
2069
- end
2070
-
2071
- def init_generator(properties={})
2072
- super
2073
- @escapefunc ||= "Erubis::XmlHelper.escape_xml"
2074
- @initialized = false
2075
- @prev_is_expr = false
2076
- end
2077
-
2078
- protected
2079
-
2080
- def escape_text(text)
2081
- text.gsub(/['\\]/, '\\\\\&') # "'" => "\\'", '\\' => '\\\\'
2082
- end
2083
-
2084
- def escaped_expr(code)
2085
- @escapefunc ||= 'Erubis::XmlHelper.escape_xml'
2086
- return "#{@escapefunc}(#{code})"
2087
- end
2088
-
2089
- def switch_to_expr(src)
2090
- return if @prev_is_expr
2091
- @prev_is_expr = true
2092
- src << ' _buf'
2093
- end
2094
-
2095
- def switch_to_stmt(src)
2096
- return unless @prev_is_expr
2097
- @prev_is_expr = false
2098
- src << ';'
2099
- end
2100
-
2101
- def add_preamble(src)
2102
- #@initialized = false
2103
- #@prev_is_expr = false
2104
- end
2105
-
2106
- def add_text(src, text)
2107
- return if text.empty?
2108
- if @initialized
2109
- switch_to_expr(src)
2110
- src << " << '" << escape_text(text) << "'"
2111
- else
2112
- src << "_buf = '" << escape_text(text) << "';"
2113
- @initialized = true
2114
- end
2115
- end
2116
-
2117
- def add_stmt(src, code)
2118
- switch_to_stmt(src) if @initialized
2119
- #super
2120
- src << code
2121
- src << ';' unless code[-1] == ?\n
2122
- end
2123
-
2124
- def add_expr_literal(src, code)
2125
- unless @initialized; src << "_buf = ''"; @initialized = true; end
2126
- switch_to_expr(src)
2127
- src << " << (" << code << ").to_s"
2128
- end
2129
-
2130
- def add_expr_escaped(src, code)
2131
- unless @initialized; src << "_buf = ''"; @initialized = true; end
2132
- switch_to_expr(src)
2133
- src << " << " << escaped_expr(code)
2134
- end
2135
-
2136
- def add_expr_debug(src, code)
2137
- code.strip!
2138
- s = (code.dump =~ /\A"(.*)"\z/) && $1
2139
- src << ' $stderr.puts("*** debug: ' << s << '=#{(' << code << ').inspect}");'
2140
- end
2141
-
2142
- def add_postamble(src)
2143
- #super if @initialized
2144
- src << "\n_buf\n" if @initialized
2145
- end
2146
-
2147
- end # end of class OptimizedEruby
2148
-
2149
-
2150
- ##
2151
- ## Eruby class which generates optimized ruby code
2152
- ##
2153
- class OptimizedEruby < Basic::Engine # Eruby
2154
- include RubyEvaluator
2155
- include OptimizedGenerator
2156
-
2157
- def init_converter(properties={})
2158
- @pi = 'rb'
2159
- super(properties)
2160
- end
2161
-
2162
- end
2163
-
2164
-
2165
- ##
2166
- ## XmlEruby class which generates optimized ruby code
2167
- ##
2168
- class OptimizedXmlEruby < OptimizedEruby
2169
- include EscapeEnhancer
2170
-
2171
- def add_expr_debug(src, code)
2172
- switch_to_stmt(src) if indicator == '===' && !@initialized
2173
- super
2174
- end
2175
-
2176
- end # end of class OptimizedXmlEruby
2177
-
2178
- end
2179
- #--end of require 'erubis/engine/optimized'
2180
- #--already included require 'erubis/engine/eruby'
2181
- #--begin of require 'erubis/engine/ephp'
2182
- ##
2183
- ## $Rev: 77 $
2184
- ## $Release: 2.5.0 $
2185
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
2186
- ##
2187
-
2188
- #--already included require 'erubis/engine'
2189
- #--already included require 'erubis/enhancer'
2190
-
2191
-
2192
- module Erubis
2193
-
2194
-
2195
- module PhpGenerator
2196
- include Generator
2197
-
2198
- def self.supported_properties() # :nodoc:
2199
- return []
2200
- end
2201
-
2202
- def init_generator(properties={})
2203
- super
2204
- @escapefunc ||= 'htmlspecialchars'
2205
- end
2206
-
2207
- def add_preamble(src)
2208
- # empty
2209
- end
2210
-
2211
- def escape_text(text)
2212
- return text.gsub!(/<\?xml\b/, '<<?php ?>?xml') || text
2213
- end
2214
-
2215
- def add_text(src, text)
2216
- src << escape_text(text)
2217
- end
2218
-
2219
- def add_expr_literal(src, code)
2220
- code.strip!
2221
- src << "<?php echo #{code}; ?>"
2222
- end
2223
-
2224
- def add_expr_escaped(src, code)
2225
- add_expr_literal(src, escaped_expr(code))
2226
- end
2227
-
2228
- def add_expr_debug(src, code)
2229
- code.strip!
2230
- s = code.gsub(/\'/, "\\'")
2231
- src << "<?php error_log('*** debug: #{s}='.(#{code}), 0); ?>"
2232
- end
2233
-
2234
- def add_stmt(src, code)
2235
- src << "<?php"
2236
- src << " " if code[0] != ?\ #
2237
- if code[-1] == ?\n
2238
- code.chomp!
2239
- src << code << "?>\n"
2240
- else
2241
- src << code << "?>"
2242
- end
2243
- end
2244
-
2245
- def add_postamble(src)
2246
- # empty
2247
- end
2248
-
2249
- end
2250
-
2251
-
2252
- ##
2253
- ## engine for PHP
2254
- ##
2255
- class Ephp < Basic::Engine
2256
- include PhpGenerator
2257
- end
2258
-
2259
-
2260
- class EscapedEphp < Ephp
2261
- include EscapeEnhancer
2262
- end
2263
-
2264
-
2265
- #class XmlEphp < Ephp
2266
- # include EscapeEnhancer
2267
- #end
2268
-
2269
-
2270
- class PI::Ephp < PI::Engine
2271
- include PhpGenerator
2272
-
2273
- def init_converter(properties={})
2274
- @pi = 'php'
2275
- super(properties)
2276
- end
2277
-
2278
- end
2279
-
2280
-
2281
- end
2282
- #--end of require 'erubis/engine/ephp'
2283
- #--begin of require 'erubis/engine/ec'
2284
- ##
2285
- ## $Rev: 77 $
2286
- ## $Release: 2.5.0 $
2287
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
2288
- ##
2289
-
2290
- #--already included require 'erubis/engine'
2291
- #--already included require 'erubis/enhancer'
2292
-
2293
-
2294
- module Erubis
2295
-
2296
-
2297
- module CGenerator
2298
- include Generator
2299
-
2300
- def self.supported_properties() # :nodoc:
2301
- return [
2302
- [:indent, '', "indent spaces (ex. ' ')"],
2303
- [:out, 'stdout', "output file pointer name"],
2304
- ]
2305
- end
2306
-
2307
- def init_generator(properties={})
2308
- super
2309
- @escapefunc ||= "escape"
2310
- @indent = properties[:indent] || ''
2311
- @out = properties[:out] || 'stdout'
2312
- end
2313
-
2314
- def add_preamble(src)
2315
- src << "#line 1 \"#{self.filename}\"\n" if self.filename
2316
- end
2317
-
2318
- def escape_text(text)
2319
- @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
2320
- text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] }
2321
- return text
2322
- end
2323
-
2324
- def escaped_expr(code)
2325
- return "#{@escapefunc}(#{code.strip}, #{@out})"
2326
- end
2327
-
2328
- def add_text(src, text)
2329
- return if text.empty?
2330
- src << (src.empty? || src[-1] == ?\n ? @indent : ' ')
2331
- src << "fputs("
2332
- i = 0
2333
- text.each_line do |line|
2334
- src << "\n" << @indent << ' ' if i > 0
2335
- i += 1
2336
- src << '"' << escape_text(line) << '"'
2337
- end
2338
- src << ", #{@out});" #<< (text[-1] == ?\n ? "\n" : "")
2339
- src << "\n" if text[-1] == ?\n
2340
- end
2341
-
2342
- def add_stmt(src, code)
2343
- src << code
2344
- end
2345
-
2346
- def add_expr_literal(src, code)
2347
- src << @indent if src.empty? || src[-1] == ?\n
2348
- src << " fprintf(#{@out}, " << code.strip << ');'
2349
- end
2350
-
2351
- def add_expr_escaped(src, code)
2352
- src << @indent if src.empty? || src[-1] == ?\n
2353
- src << ' ' << escaped_expr(code) << ';'
2354
- end
2355
-
2356
- def add_expr_debug(src, code)
2357
- code.strip!
2358
- s = nil
2359
- if code =~ /\A\".*?\"\s*,\s*(.*)/
2360
- s = $1.gsub(/[%"]/, '\\\1') + '='
2361
- end
2362
- src << @indent if src.empty? || src[-1] == ?\n
2363
- src << " fprintf(stderr, \"*** debug: #{s}\" #{code});"
2364
- end
2365
-
2366
- def add_postamble(src)
2367
- # empty
2368
- end
2369
-
2370
- end
2371
-
2372
-
2373
- ##
2374
- ## engine for C
2375
- ##
2376
- class Ec < Basic::Engine
2377
- include CGenerator
2378
- end
2379
-
2380
-
2381
- class EscapedEc < Ec
2382
- include EscapeEnhancer
2383
- end
2384
-
2385
-
2386
- #class XmlEc < Ec
2387
- # include EscapeEnhancer
2388
- #end
2389
-
2390
- class PI::Ec < PI::Engine
2391
- include CGenerator
2392
-
2393
- def init_converter(properties={})
2394
- @pi = 'c'
2395
- super(properties)
2396
- end
2397
-
2398
- end
2399
-
2400
-
2401
- end
2402
- #--end of require 'erubis/engine/ec'
2403
- #--begin of require 'erubis/engine/ejava'
2404
- ##
2405
- ## $Rev: 77 $
2406
- ## $Release: 2.5.0 $
2407
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
2408
- ##
2409
-
2410
- #--already included require 'erubis/engine'
2411
- #--already included require 'erubis/enhancer'
2412
-
2413
-
2414
- module Erubis
2415
-
2416
-
2417
- module JavaGenerator
2418
- include Generator
2419
-
2420
- def self.supported_properties() # :nodoc:
2421
- return [
2422
- [:indent, '', "indent spaces (ex. ' ')"],
2423
- [:buf, '_buf', "output buffer name"],
2424
- [:bufclass, 'StringBuffer', "output buffer class (ex. 'StringBuilder')"],
2425
- ]
2426
- end
2427
-
2428
- def init_generator(properties={})
2429
- super
2430
- @escapefunc ||= 'escape'
2431
- @indent = properties[:indent] || ''
2432
- @buf = properties[:buf] || '_buf'
2433
- @bufclass = properties[:bufclass] || 'StringBuffer'
2434
- end
2435
-
2436
- def add_preamble(src)
2437
- src << "#{@indent}#{@bufclass} #{@buf} = new #{@bufclass}();"
2438
- end
2439
-
2440
- def escape_text(text)
2441
- @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
2442
- return text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] } || text
2443
- end
2444
-
2445
- def add_text(src, text)
2446
- return if text.empty?
2447
- src << (src.empty? || src[-1] == ?\n ? @indent : ' ')
2448
- src << @buf << ".append("
2449
- i = 0
2450
- text.each_line do |line|
2451
- src << "\n" << @indent << ' + ' if i > 0
2452
- i += 1
2453
- src << '"' << escape_text(line) << '"'
2454
- end
2455
- src << ");" << (text[-1] == ?\n ? "\n" : "")
2456
- end
2457
-
2458
- def add_stmt(src, code)
2459
- src << code
2460
- end
2461
-
2462
- def add_expr_literal(src, code)
2463
- src << @indent if src.empty? || src[-1] == ?\n
2464
- code.strip!
2465
- src << " #{@buf}.append(#{code});"
2466
- end
2467
-
2468
- def add_expr_escaped(src, code)
2469
- add_expr_literal(src, escaped_expr(code))
2470
- end
2471
-
2472
- def add_expr_debug(src, code)
2473
- code.strip!
2474
- src << @indent if src.empty? || src[-1] == ?\n
2475
- src << " System.err.println(\"*** debug: #{code}=\"+(#{code}));"
2476
- end
2477
-
2478
- def add_postamble(src)
2479
- src << "\n" if src[-1] == ?;
2480
- src << @indent << "return " << @buf << ".toString();\n"
2481
- #src << @indent << "System.out.print(" << @buf << ".toString());\n"
2482
- end
2483
-
2484
- end
2485
-
2486
-
2487
- ##
2488
- ## engine for Java
2489
- ##
2490
- class Ejava < Basic::Engine
2491
- include JavaGenerator
2492
- end
2493
-
2494
-
2495
- class EscapedEjava < Ejava
2496
- include EscapeEnhancer
2497
- end
2498
-
2499
-
2500
- #class XmlEjava < Ejava
2501
- # include EscapeEnhancer
2502
- #end
2503
-
2504
- class PI::Ejava < PI::Engine
2505
- include JavaGenerator
2506
-
2507
- def init_converter(properties={})
2508
- @pi = 'java'
2509
- super(properties)
2510
- end
2511
-
2512
- end
2513
-
2514
- end
2515
- #--end of require 'erubis/engine/ejava'
2516
- #--begin of require 'erubis/engine/escheme'
2517
- ##
2518
- ## $Rev: 77 $
2519
- ## $Release: 2.5.0 $
2520
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
2521
- ##
2522
-
2523
- #--already included require 'erubis/engine'
2524
- #--already included require 'erubis/enhancer'
2525
-
2526
-
2527
- module Erubis
2528
-
2529
-
2530
- module SchemeGenerator
2531
- include Generator
2532
-
2533
- def self.supported_properties() # :nodoc:
2534
- return [
2535
- [:func, '_add', "function name (ex. 'display')"],
2536
- ]
2537
- end
2538
-
2539
- def init_generator(properties={})
2540
- super
2541
- @escapefunc ||= 'escape'
2542
- @func = properties[:func] || '_add' # or 'display'
2543
- end
2544
-
2545
- def add_preamble(src)
2546
- return unless @func == '_add'
2547
- src << "(let ((_buf '())) " + \
2548
- "(define (_add x) (set! _buf (cons x _buf))) "
2549
- #src << "(let* ((_buf '())" + \
2550
- # " (_add (lambda (x) (set! _buf (cons x _buf))))) "
2551
- end
2552
-
2553
- def escape_text(text)
2554
- @table_ ||= { '"'=>'\\"', '\\'=>'\\\\' }
2555
- text.gsub!(/["\\]/) { |m| @table_[m] }
2556
- return text
2557
- end
2558
-
2559
- def escaped_expr(code)
2560
- code.strip!
2561
- return "(#{@escapefunc} #{code})"
2562
- end
2563
-
2564
- def add_text(src, text)
2565
- return if text.empty?
2566
- t = escape_text(text)
2567
- if t[-1] == ?\n
2568
- t[-1, 1] = ''
2569
- src << "(#{@func} \"" << t << "\\n\")\n"
2570
- else
2571
- src << "(#{@func} \"" << t << '")'
2572
- end
2573
- end
2574
-
2575
- def add_stmt(src, code)
2576
- src << code
2577
- end
2578
-
2579
- def add_expr_literal(src, code)
2580
- code.strip!
2581
- src << "(#{@func} #{code})"
2582
- end
2583
-
2584
- def add_expr_escaped(src, code)
2585
- add_expr_literal(src, escaped_expr(code))
2586
- end
2587
-
2588
- def add_expr_debug(src, code)
2589
- s = (code.strip! || code).gsub(/\"/, '\\"')
2590
- src << "(display \"*** debug: #{s}=\")(display #{code.strip})(display \"\\n\")"
2591
- end
2592
-
2593
- def add_postamble(src)
2594
- return unless @func == '_add'
2595
- src << "\n" unless src[-1] == ?\n
2596
- src << " (reverse _buf))\n"
2597
- end
2598
-
2599
- end
2600
-
2601
-
2602
- ##
2603
- ## engine for Scheme
2604
- ##
2605
- class Escheme < Basic::Engine
2606
- include SchemeGenerator
2607
- end
2608
-
2609
-
2610
- class EscapedEscheme < Escheme
2611
- include EscapeEnhancer
2612
- end
2613
-
2614
-
2615
- #class XmlEscheme < Escheme
2616
- # include EscapeEnhancer
2617
- #end
2618
-
2619
-
2620
- class PI::Escheme < PI::Engine
2621
- include SchemeGenerator
2622
-
2623
- def init_converter(properties={})
2624
- @pi = 'scheme'
2625
- super(properties)
2626
- end
2627
-
2628
- end
2629
-
2630
-
2631
- end
2632
- #--end of require 'erubis/engine/escheme'
2633
- #--begin of require 'erubis/engine/eperl'
2634
- ##
2635
- ## $Rev: 77 $
2636
- ## $Release: 2.5.0 $
2637
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
2638
- ##
2639
-
2640
- #--already included require 'erubis/engine'
2641
- #--already included require 'erubis/enhancer'
2642
-
2643
-
2644
- module Erubis
2645
-
2646
-
2647
- module PerlGenerator
2648
- include Generator
2649
-
2650
- def self.supported_properties() # :nodoc:
2651
- return [
2652
- [:func, 'print', "function name"],
2653
- ]
2654
- end
2655
-
2656
- def init_generator(properties={})
2657
- super
2658
- @escapefunc ||= 'encode_entities'
2659
- @func = properties[:func] || 'print'
2660
- end
2661
-
2662
- def add_preamble(src)
2663
- src << "use HTML::Entities; ";
2664
- end
2665
-
2666
- def escape_text(text)
2667
- return text.gsub!(/['\\]/, '\\\\\&') || text
2668
- end
2669
-
2670
- def add_text(src, text)
2671
- src << @func << "('" << escape_text(text) << "'); " unless text.empty?
2672
- end
2673
-
2674
- def add_expr_literal(src, code)
2675
- code.strip!
2676
- src << @func << "(" << code << "); "
2677
- end
2678
-
2679
- def add_expr_escaped(src, code)
2680
- add_expr_literal(src, escaped_expr(code))
2681
- end
2682
-
2683
- def add_expr_debug(src, code)
2684
- code.strip!
2685
- s = code.gsub(/\'/, "\\'")
2686
- src << @func << "('*** debug: #{code}=', #{code}, \"\\n\");"
2687
- end
2688
-
2689
- def add_stmt(src, code)
2690
- src << code
2691
- end
2692
-
2693
- def add_postamble(src)
2694
- src << "\n" unless src[-1] == ?\n
2695
- end
2696
-
2697
- end
2698
-
2699
-
2700
- ##
2701
- ## engine for Perl
2702
- ##
2703
- class Eperl < Basic::Engine
2704
- include PerlGenerator
2705
- end
2706
-
2707
-
2708
- class EscapedEperl < Eperl
2709
- include EscapeEnhancer
2710
- end
2711
-
2712
-
2713
- #class XmlEperl < Eperl
2714
- # include EscapeEnhancer
2715
- #end
2716
-
2717
-
2718
- class PI::Eperl < PI::Engine
2719
- include PerlGenerator
2720
-
2721
- def init_converter(properties={})
2722
- @pi = 'perl'
2723
- super(properties)
2724
- end
2725
-
2726
- end
2727
-
2728
-
2729
- end
2730
- #--end of require 'erubis/engine/eperl'
2731
- #--begin of require 'erubis/engine/ejavascript'
2732
- ##
2733
- ## $Rev: 95 $
2734
- ## $Release: 2.5.0 $
2735
- ## copyright(c) 2006-2008 kuwata-lab.com all rights reserved.
2736
- ##
2737
-
2738
- #--already included require 'erubis/engine'
2739
- #--already included require 'erubis/enhancer'
2740
-
2741
-
2742
- module Erubis
2743
-
2744
-
2745
- module JavascriptGenerator
2746
- include Generator
2747
-
2748
- def self.supported_properties() # :nodoc:
2749
- list = []
2750
- #list << [:indent, '', "indent spaces (ex. ' ')"]
2751
- #list << [:buf, '_buf', "output buffer name"]
2752
- list << [:docwrite, true, "use 'document.write()' when true"]
2753
- return list
2754
- end
2755
-
2756
- def init_generator(properties={})
2757
- super
2758
- @escapefunc ||= 'escape'
2759
- @indent = properties[:indent] || ''
2760
- @buf = properties[:out] || '_buf'
2761
- @docwrite = properties[:docwrite] != false # '!= false' will be removed in the next release
2762
- end
2763
-
2764
- def add_preamble(src)
2765
- src << "#{@indent}var #{@buf} = [];"
2766
- end
2767
-
2768
- def escape_text(text)
2769
- @@table_ ||= { "\r"=>"\\r", "\n"=>"\\n\\\n", "\t"=>"\\t", '"'=>'\\"', "\\"=>"\\\\" }
2770
- return text.gsub!(/[\r\n\t"\\]/) { |m| @@table_[m] } || text
2771
- end
2772
-
2773
- def add_indent(src, indent)
2774
- src << (src.empty? || src[-1] == ?\n ? indent : ' ')
2775
- end
2776
-
2777
- def add_text(src, text)
2778
- return if text.empty?
2779
- add_indent(src, @indent)
2780
- src << @buf << '.push("'
2781
- s = escape_text(text)
2782
- if s[-1] == ?\n
2783
- s[-2, 2] = ''
2784
- src << s << "\");\n"
2785
- else
2786
- src << s << "\");"
2787
- end
2788
- end
2789
-
2790
- def add_stmt(src, code)
2791
- src << code
2792
- end
2793
-
2794
- def add_expr_literal(src, code)
2795
- add_indent(src, @indent)
2796
- code.strip!
2797
- src << "#{@buf}.push(#{code});"
2798
- end
2799
-
2800
- def add_expr_escaped(src, code)
2801
- add_expr_literal(src, escaped_expr(code))
2802
- end
2803
-
2804
- def add_expr_debug(src, code)
2805
- add_indent(src, @indent)
2806
- code.strip!
2807
- src << "alert(\"*** debug: #{code}=\"+(#{code}));"
2808
- end
2809
-
2810
- def add_postamble(src)
2811
- src << "\n" if src[-1] == ?;
2812
- if @docwrite
2813
- src << @indent << 'document.write(' << @buf << ".join(\"\"));\n"
2814
- else
2815
- src << @indent << @buf << ".join(\"\");\n"
2816
- end
2817
- end
2818
-
2819
- end
2820
-
2821
-
2822
- ##
2823
- ## engine for JavaScript
2824
- ##
2825
- class Ejavascript < Basic::Engine
2826
- include JavascriptGenerator
2827
- end
2828
-
2829
-
2830
- class EscapedEjavascript < Ejavascript
2831
- include EscapeEnhancer
2832
- end
2833
-
2834
-
2835
- #class XmlEjavascript < Ejavascript
2836
- # include EscapeEnhancer
2837
- #end
2838
-
2839
-
2840
- class PI::Ejavascript < PI::Engine
2841
- include JavascriptGenerator
2842
-
2843
- def init_converter(properties={})
2844
- @pi = 'js'
2845
- super(properties)
2846
- end
2847
-
2848
- end
2849
-
2850
-
2851
- end
2852
- #--end of require 'erubis/engine/ejavascript'
2853
-
2854
-
2855
- module Erubis
2856
-
2857
-
2858
- Ejs = Ejavascript
2859
- EscapedEjs = EscapedEjavascript
2860
-
2861
-
2862
- class CommandOptionError < ErubisError
2863
- end
2864
-
2865
-
2866
- ##
2867
- ## main class of command
2868
- ##
2869
- ## ex.
2870
- ## Main.main(ARGV)
2871
- ##
2872
- class Main
2873
-
2874
- def self.main(argv=ARGV)
2875
- status = 0
2876
- begin
2877
- Main.new.execute(ARGV)
2878
- rescue CommandOptionError => ex
2879
- $stderr.puts ex.message
2880
- status = 1
2881
- end
2882
- exit(status)
2883
- end
2884
-
2885
- def initialize
2886
- @single_options = "hvxztTSbeBXNUC"
2887
- @arg_options = "pcrfKIlaE" #C
2888
- @option_names = {
2889
- ?h => :help,
2890
- ?v => :version,
2891
- ?x => :source,
2892
- ?z => :syntax,
2893
- ?T => :unexpand,
2894
- ?t => :untabify, # obsolete
2895
- ?S => :intern,
2896
- ?b => :bodyonly,
2897
- ?B => :binding,
2898
- ?p => :pattern,
2899
- ?c => :context,
2900
- #?C => :class,
2901
- ?e => :escape,
2902
- ?r => :requires,
2903
- ?f => :datafiles,
2904
- ?K => :kanji,
2905
- ?I => :includes,
2906
- ?l => :lang,
2907
- ?a => :action,
2908
- ?E => :enhancers,
2909
- ?X => :notext,
2910
- ?N => :linenum,
2911
- ?U => :unique,
2912
- ?C => :compact,
2913
- }
2914
- assert unless @single_options.length + @arg_options.length == @option_names.length
2915
- (@single_options + @arg_options).each_byte do |ch|
2916
- assert unless @option_names.key?(ch)
2917
- end
2918
- end
2919
-
2920
-
2921
- def execute(argv=ARGV)
2922
- ## parse command-line options
2923
- options, properties = parse_argv(argv, @single_options, @arg_options)
2924
- filenames = argv
2925
- options[?h] = true if properties[:help]
2926
- opts = Object.new
2927
- arr = @option_names.collect { |ch, name| "def #{name}; @#{name}; end\n" }
2928
- opts.instance_eval arr.join
2929
- options.each do |ch, val|
2930
- name = @option_names[ch]
2931
- opts.instance_variable_set("@#{name}", val)
2932
- end
2933
-
2934
- ## help, version, enhancer list
2935
- if opts.help || opts.version
2936
- puts version() if opts.version
2937
- puts usage() if opts.help
2938
- puts show_properties() if opts.help
2939
- puts show_enhancers() if opts.help
2940
- return
2941
- end
2942
-
2943
- ## include path
2944
- opts.includes.split(/,/).each do |path|
2945
- $: << path
2946
- end if opts.includes
2947
-
2948
- ## require library
2949
- opts.requires.split(/,/).each do |library|
2950
- require library
2951
- end if opts.requires
2952
-
2953
- ## action
2954
- action = opts.action
2955
- action ||= 'syntax' if opts.syntax
2956
- action ||= 'convert' if opts.source || opts.notext
2957
-
2958
- ## lang
2959
- lang = opts.lang || 'ruby'
2960
- action ||= 'convert' if opts.lang
2961
-
2962
- ## class name of Eruby
2963
- #classname = opts.class
2964
- classname = nil
2965
- klass = get_classobj(classname, lang, properties[:pi])
2966
-
2967
- ## kanji code
2968
- $KCODE = opts.kanji if opts.kanji
2969
-
2970
- ## read context values from yaml file
2971
- datafiles = opts.datafiles
2972
- context = load_datafiles(datafiles, opts)
2973
-
2974
- ## parse context data
2975
- if opts.context
2976
- context = parse_context_data(opts.context, opts)
2977
- end
2978
-
2979
- ## properties for engine
2980
- properties[:escape] = true if opts.escape && !properties.key?(:escape)
2981
- properties[:pattern] = opts.pattern if opts.pattern
2982
- #properties[:trim] = false if opts.notrim
2983
- properties[:preamble] = properties[:postamble] = false if opts.bodyonly
2984
- properties[:pi] = nil if properties[:pi] == true
2985
-
2986
- ## create engine and extend enhancers
2987
- engine = klass.new(nil, properties)
2988
- enhancers = get_enhancers(opts.enhancers)
2989
- #enhancers.push(Erubis::EscapeEnhancer) if opts.escape
2990
- enhancers.each do |enhancer|
2991
- engine.extend(enhancer)
2992
- engine.bipattern = properties[:bipattern] if enhancer == Erubis::BiPatternEnhancer
2993
- end
2994
-
2995
- ## no-text
2996
- engine.extend(Erubis::NoTextEnhancer) if opts.notext
2997
-
2998
- ## convert and execute
2999
- val = nil
3000
- msg = "Syntax OK\n"
3001
- if filenames && !filenames.empty?
3002
- filenames.each do |filename|
3003
- test(?f, filename) or raise CommandOptionError.new("#{filename}: file not found.")
3004
- engine.filename = filename
3005
- engine.convert!(File.read(filename))
3006
- val = do_action(action, engine, context, filename, opts)
3007
- msg = nil if val
3008
- end
3009
- else
3010
- engine.filename = filename = '(stdin)'
3011
- engine.convert!($stdin.read())
3012
- val = do_action(action, engine, context, filename, opts)
3013
- msg = nil if val
3014
- end
3015
- print msg if action == 'syntax' && msg
3016
-
3017
- end
3018
-
3019
- private
3020
-
3021
- def do_action(action, engine, context, filename, opts)
3022
- case action
3023
- when 'convert'
3024
- s = manipulate_src(engine.src, opts)
3025
- when nil, 'exec', 'execute'
3026
- s = opts.binding ? engine.result(context.to_hash) : engine.evaluate(context)
3027
- when 'syntax'
3028
- s = check_syntax(filename, engine.src)
3029
- else
3030
- raise "*** internal error"
3031
- end
3032
- print s if s
3033
- return s
3034
- end
3035
-
3036
- def manipulate_src(source, opts)
3037
- flag_linenum = opts.linenum
3038
- flag_unique = opts.unique
3039
- flag_compact = opts.compact
3040
- if flag_linenum
3041
- n = 0
3042
- source.gsub!(/^/) { n += 1; "%5d: " % n }
3043
- source.gsub!(/^ *\d+:\s+?\n/, '') if flag_compact
3044
- source.gsub!(/(^ *\d+:\s+?\n)+/, "\n") if flag_unique
3045
- else
3046
- source.gsub!(/^\s*?\n/, '') if flag_compact
3047
- source.gsub!(/(^\s*?\n)+/, "\n") if flag_unique
3048
- end
3049
- return source
3050
- end
3051
-
3052
- def usage(command=nil)
3053
- command ||= File.basename($0)
3054
- buf = []
3055
- buf << "erubis - embedded program converter for multi-language"
3056
- buf << "Usage: #{command} [..options..] [file ...]"
3057
- buf << " -h, --help : help"
3058
- buf << " -v : version"
3059
- buf << " -x : show converted code"
3060
- buf << " -X : show converted code, only ruby code and no text part"
3061
- buf << " -N : numbering: add line numbers (for '-x/-X')"
3062
- buf << " -U : unique: compress empty lines to a line (for '-x/-X')"
3063
- buf << " -C : compact: remove empty lines (for '-x/-X')"
3064
- buf << " -b : body only: no preamble nor postamble (for '-x/-X')"
3065
- buf << " -z : syntax checking"
3066
- buf << " -e : escape (equal to '--E Escape')"
3067
- buf << " -p pattern : embedded pattern (default '<% %>')"
3068
- buf << " -l lang : convert but no execute (ruby/php/c/java/scheme/perl/js)"
3069
- buf << " -E e1,e2,... : enhancer names (Escape, PercentLine, BiPattern, ...)"
3070
- buf << " -I path : library include path"
3071
- buf << " -K kanji : kanji code (euc/sjis/utf8) (default none)"
3072
- buf << " -c context : context data string (yaml inline style or ruby code)"
3073
- buf << " -f datafile : context data file ('*.yaml', '*.yml', or '*.rb')"
3074
- #buf << " -t : expand tab characters in YAML file"
3075
- buf << " -T : don't expand tab characters in YAML file"
3076
- buf << " -S : convert mapping key from string to symbol in YAML file"
3077
- buf << " -B : invoke 'result(binding)' instead of 'evaluate(context)'"
3078
- buf << " --pi=name : parse '<?name ... ?>' instead of '<% ... %>'"
3079
- #'
3080
- # -T : don't trim spaces around '<% %>'
3081
- # -c class : class name (XmlEruby/PercentLineEruby/...) (default Eruby)
3082
- # -r library : require library
3083
- # -a : action (convert/execute)
3084
- return buf.join("\n")
3085
- end
3086
-
3087
- def collect_supported_properties(erubis_klass)
3088
- list = []
3089
- erubis_klass.ancestors.each do |klass|
3090
- if klass.respond_to?(:supported_properties)
3091
- list.concat(klass.supported_properties)
3092
- end
3093
- end
3094
- return list
3095
- end
3096
-
3097
- def show_properties
3098
- s = "supported properties:\n"
3099
- basic_props = collect_supported_properties(Erubis::Basic::Engine)
3100
- pi_props = collect_supported_properties(Erubis::PI::Engine)
3101
- list = []
3102
- common_props = basic_props & pi_props
3103
- list << ['(common)', common_props]
3104
- list << ['(basic)', basic_props - common_props]
3105
- list << ['(pi)', pi_props - common_props]
3106
- %w[ruby php c java scheme perl javascript].each do |lang|
3107
- klass = Erubis.const_get("E#{lang}")
3108
- list << [lang, collect_supported_properties(klass) - basic_props]
3109
- end
3110
- list.each do |lang, props|
3111
- s << " * #{lang}\n"
3112
- props.each do |name, default_val, desc|
3113
- s << (" --%-23s : %s\n" % ["#{name}=#{default_val.inspect}", desc])
3114
- end
3115
- end
3116
- s << "\n"
3117
- return s
3118
- end
3119
-
3120
- def show_enhancers
3121
- s = "enhancers:\n"
3122
- list = []
3123
- ObjectSpace.each_object(Module) do |m| list << m end
3124
- list.sort_by { |m| m.name }.each do |m|
3125
- next unless m.name =~ /\AErubis::(.*)Enhancer\z/
3126
- name = $1
3127
- desc = m.desc
3128
- s << (" %-13s : %s\n" % [name, desc])
3129
- end
3130
- return s
3131
- end
3132
-
3133
- def version
3134
- return Erubis::VERSION
3135
- end
3136
-
3137
- def parse_argv(argv, arg_none='', arg_required='', arg_optional='')
3138
- options = {}
3139
- context = {}
3140
- while argv[0] && argv[0][0] == ?-
3141
- optstr = argv.shift
3142
- optstr = optstr[1, optstr.length-1]
3143
- #
3144
- if optstr[0] == ?- # context
3145
- unless optstr =~ /\A\-([-\w]+)(?:=(.*))?/
3146
- raise CommandOptionError.new("-#{optstr}: invalid context value.")
3147
- end
3148
- name = $1; value = $2
3149
- name = name.gsub(/-/, '_').intern
3150
- #value = value.nil? ? true : YAML.load(value) # error, why?
3151
- value = value.nil? ? true : YAML.load("---\n#{value}\n")
3152
- context[name] = value
3153
- #
3154
- else # options
3155
- while optstr && !optstr.empty?
3156
- optchar = optstr[0]
3157
- optstr[0,1] = ""
3158
- if arg_none.include?(optchar)
3159
- options[optchar] = true
3160
- elsif arg_required.include?(optchar)
3161
- arg = optstr.empty? ? argv.shift : optstr
3162
- unless arg
3163
- mesg = "-#{optchar.chr}: #{@option_args[optchar]} required."
3164
- raise CommandOptionError.new(mesg)
3165
- end
3166
- options[optchar] = arg
3167
- optstr = nil
3168
- elsif arg_optional.include?(optchar)
3169
- arg = optstr.empty? ? true : optstr
3170
- options[optchar] = arg
3171
- optstr = nil
3172
- else
3173
- raise CommandOptionError.new("-#{optchar.chr}: unknown option.")
3174
- end
3175
- end
3176
- end
3177
- #
3178
- end # end of while
3179
-
3180
- return options, context
3181
- end
3182
-
3183
-
3184
- def untabify(str, width=8)
3185
- list = str.split(/\t/)
3186
- last = list.pop
3187
- sb = ''
3188
- list.each do |s|
3189
- column = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
3190
- n = width - (column % width)
3191
- sb << s << (' ' * n)
3192
- end
3193
- sb << last
3194
- return sb
3195
- end
3196
- #--
3197
- #def untabify(str, width=8)
3198
- # sb = ''
3199
- # str.scan(/(.*?)\t/m) do |s, |
3200
- # len = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
3201
- # sb << s << (" " * (width - len % width))
3202
- # end
3203
- # return $' ? (sb << $') : str
3204
- #end
3205
- #++
3206
-
3207
-
3208
- def get_classobj(classname, lang, pi)
3209
- classname ||= "E#{lang}"
3210
- base_module = pi ? Erubis::PI : Erubis
3211
- begin
3212
- klass = base_module.const_get(classname)
3213
- rescue NameError
3214
- klass = nil
3215
- end
3216
- unless klass
3217
- if lang
3218
- msg = "-l #{lang}: invalid language name (class #{base_module.name}::#{classname} not found)."
3219
- else
3220
- msg = "-c #{classname}: invalid class name."
3221
- end
3222
- raise CommandOptionError.new(msg)
3223
- end
3224
- return klass
3225
- end
3226
-
3227
- def get_enhancers(enhancer_names)
3228
- return [] unless enhancer_names
3229
- enhancers = []
3230
- shortname = nil
3231
- begin
3232
- enhancer_names.split(/,/).each do |shortname|
3233
- enhancers << Erubis.const_get("#{shortname}Enhancer")
3234
- end
3235
- rescue NameError
3236
- raise CommandOptionError.new("#{shortname}: no such Enhancer (try '-E' to show all enhancers).")
3237
- end
3238
- return enhancers
3239
- end
3240
-
3241
- def load_datafiles(filenames, opts)
3242
- context = Erubis::Context.new
3243
- return context unless filenames
3244
- filenames.split(/,/).each do |filename|
3245
- filename.strip!
3246
- test(?f, filename) or raise CommandOptionError.new("#{filename}: file not found.")
3247
- if filename =~ /\.ya?ml$/
3248
- if opts.unexpand
3249
- ydoc = YAML.load_file(filename)
3250
- else
3251
- ydoc = YAML.load(untabify(File.read(filename)))
3252
- end
3253
- ydoc.is_a?(Hash) or raise CommandOptionError.new("#{filename}: root object is not a mapping.")
3254
- intern_hash_keys(ydoc) if opts.intern
3255
- context.update(ydoc)
3256
- elsif filename =~ /\.rb$/
3257
- str = File.read(filename)
3258
- context2 = Erubis::Context.new
3259
- _instance_eval(context2, str)
3260
- context.update(context2)
3261
- else
3262
- CommandOptionError.new("#{filename}: '*.yaml', '*.yml', or '*.rb' required.")
3263
- end
3264
- end
3265
- return context
3266
- end
3267
-
3268
- def _instance_eval(_context, _str)
3269
- _context.instance_eval(_str)
3270
- end
3271
-
3272
- def parse_context_data(context_str, opts)
3273
- if context_str[0] == ?{
3274
- require 'yaml'
3275
- ydoc = YAML.load(context_str)
3276
- unless ydoc.is_a?(Hash)
3277
- raise CommandOptionError.new("-c: root object is not a mapping.")
3278
- end
3279
- intern_hash_keys(ydoc) if opts.intern
3280
- return ydoc
3281
- else
3282
- context = Erubis::Context.new
3283
- context.instance_eval(context_str, '-c')
3284
- return context
3285
- end
3286
- end
3287
-
3288
- def intern_hash_keys(obj, done={})
3289
- return if done.key?(obj.__id__)
3290
- case obj
3291
- when Hash
3292
- done[obj.__id__] = obj
3293
- obj.keys.each do |key|
3294
- obj[key.intern] = obj.delete(key) if key.is_a?(String)
3295
- end
3296
- obj.values.each do |val|
3297
- intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
3298
- end
3299
- when Array
3300
- done[obj.__id__] = obj
3301
- obj.each do |val|
3302
- intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
3303
- end
3304
- end
3305
- end
3306
-
3307
- def check_syntax(filename, src)
3308
- require 'open3'
3309
- stdin, stdout, stderr = Open3.popen3('ruby -wc')
3310
- stdin.write(src)
3311
- stdin.close
3312
- result = stdout.read()
3313
- stdout.close()
3314
- errmsg = stderr.read()
3315
- stderr.close()
3316
- return nil unless errmsg && !errmsg.empty?
3317
- errmsg =~ /\A-:(\d+): /
3318
- linenum, message = $1, $'
3319
- return "#{filename}:#{linenum}: #{message}"
3320
- end
3321
-
3322
- end
3323
-
3324
- end
3325
- #--end of require 'erubis/main'
9
+ require 'erubis/main'
3326
10
 
3327
11
  Erubis::Main.main(ARGV)