erubis 2.6.2 → 2.6.3

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