erubis 2.3.1 → 2.4.0

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