erubis 2.5.0 → 2.6.0

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