erbse 0.0.1

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 (162) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.txt +828 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.md +51 -0
  5. data/benchmark/Makefile +6 -0
  6. data/benchmark/bench.rb +313 -0
  7. data/benchmark/bench_context.yaml +141 -0
  8. data/benchmark/templates/_footer.html +4 -0
  9. data/benchmark/templates/_header.html +52 -0
  10. data/benchmark/templates/bench_erb.rhtml +29 -0
  11. data/benchmark/templates/bench_erubis.rhtml +29 -0
  12. data/benchmark/templates/bench_eruby.rhtml +29 -0
  13. data/bin/erubis +10 -0
  14. data/erbse.gemspec +24 -0
  15. data/lib/erbse.rb +52 -0
  16. data/lib/erbse/context.rb +83 -0
  17. data/lib/erbse/converter.rb +357 -0
  18. data/lib/erbse/engine.rb +114 -0
  19. data/lib/erbse/engine/ec.rb +117 -0
  20. data/lib/erbse/engine/ecpp.rb +113 -0
  21. data/lib/erbse/engine/ejava.rb +110 -0
  22. data/lib/erbse/engine/ejavascript.rb +119 -0
  23. data/lib/erbse/engine/enhanced.rb +126 -0
  24. data/lib/erbse/engine/eperl.rb +95 -0
  25. data/lib/erbse/engine/ephp.rb +99 -0
  26. data/lib/erbse/engine/eruby.rb +119 -0
  27. data/lib/erbse/engine/escheme.rb +114 -0
  28. data/lib/erbse/engine/optimized.rb +127 -0
  29. data/lib/erbse/enhancer.rb +723 -0
  30. data/lib/erbse/error.rb +23 -0
  31. data/lib/erbse/evaluator.rb +88 -0
  32. data/lib/erbse/generator.rb +85 -0
  33. data/lib/erbse/helper.rb +47 -0
  34. data/lib/erbse/helpers/rails_form_helper.rb +197 -0
  35. data/lib/erbse/helpers/rails_helper.rb +353 -0
  36. data/lib/erbse/main.rb +516 -0
  37. data/lib/erbse/preprocessing.rb +58 -0
  38. data/lib/erbse/tiny.rb +144 -0
  39. data/lib/erbse/util.rb +22 -0
  40. data/lib/erbse/version.rb +3 -0
  41. data/test/assert-text-equal.rb +44 -0
  42. data/test/data/users-guide/Example.ejava +55 -0
  43. data/test/data/users-guide/array_example.result +9 -0
  44. data/test/data/users-guide/arraybuffer_example.result +9 -0
  45. data/test/data/users-guide/bipattern-example.rhtml +4 -0
  46. data/test/data/users-guide/bipattern_example.result +6 -0
  47. data/test/data/users-guide/bufvar-example.rb +10 -0
  48. data/test/data/users-guide/bufvar-example.result +17 -0
  49. data/test/data/users-guide/context.rb +6 -0
  50. data/test/data/users-guide/context.yaml +8 -0
  51. data/test/data/users-guide/def_method.rb +14 -0
  52. data/test/data/users-guide/def_method.result +3 -0
  53. data/test/data/users-guide/escape_example.result +9 -0
  54. data/test/data/users-guide/example.ec +27 -0
  55. data/test/data/users-guide/example.ecpp +30 -0
  56. data/test/data/users-guide/example.ejs +20 -0
  57. data/test/data/users-guide/example.eperl +18 -0
  58. data/test/data/users-guide/example.ephp +18 -0
  59. data/test/data/users-guide/example.eruby +6 -0
  60. data/test/data/users-guide/example.escheme +28 -0
  61. data/test/data/users-guide/example1.eruby +6 -0
  62. data/test/data/users-guide/example1.rb +17 -0
  63. data/test/data/users-guide/example1.result +16 -0
  64. data/test/data/users-guide/example10.rb +4 -0
  65. data/test/data/users-guide/example10.result +17 -0
  66. data/test/data/users-guide/example10.xhtml +14 -0
  67. data/test/data/users-guide/example10_x.result +17 -0
  68. data/test/data/users-guide/example11.php +20 -0
  69. data/test/data/users-guide/example11.result +23 -0
  70. data/test/data/users-guide/example11.rhtml +21 -0
  71. data/test/data/users-guide/example11_C.result +10 -0
  72. data/test/data/users-guide/example11_N.result +16 -0
  73. data/test/data/users-guide/example11_U.result +16 -0
  74. data/test/data/users-guide/example11_php.result +15 -0
  75. data/test/data/users-guide/example1_x.result +9 -0
  76. data/test/data/users-guide/example2.eruby +7 -0
  77. data/test/data/users-guide/example2.rb +10 -0
  78. data/test/data/users-guide/example2.result +27 -0
  79. data/test/data/users-guide/example2_trim.result +10 -0
  80. data/test/data/users-guide/example2_x.result +10 -0
  81. data/test/data/users-guide/example3.eruby +6 -0
  82. data/test/data/users-guide/example3.rb +10 -0
  83. data/test/data/users-guide/example31.result +22 -0
  84. data/test/data/users-guide/example32.result +4 -0
  85. data/test/data/users-guide/example3_e.result +8 -0
  86. data/test/data/users-guide/example4.eruby +3 -0
  87. data/test/data/users-guide/example4.rb +11 -0
  88. data/test/data/users-guide/example4.result +10 -0
  89. data/test/data/users-guide/example4_x.result +5 -0
  90. data/test/data/users-guide/example5.eruby +6 -0
  91. data/test/data/users-guide/example5.rb +16 -0
  92. data/test/data/users-guide/example5.result +7 -0
  93. data/test/data/users-guide/example6.rb +12 -0
  94. data/test/data/users-guide/example6.result +7 -0
  95. data/test/data/users-guide/example7.eruby +8 -0
  96. data/test/data/users-guide/example71.result +13 -0
  97. data/test/data/users-guide/example72.result +13 -0
  98. data/test/data/users-guide/example8.eruby +6 -0
  99. data/test/data/users-guide/example8_ruby.result +7 -0
  100. data/test/data/users-guide/example8_yaml.result +7 -0
  101. data/test/data/users-guide/example9.eruby +3 -0
  102. data/test/data/users-guide/example9.rb +8 -0
  103. data/test/data/users-guide/example9.result +9 -0
  104. data/test/data/users-guide/example91.result +5 -0
  105. data/test/data/users-guide/example92.result +4 -0
  106. data/test/data/users-guide/example_c.result +32 -0
  107. data/test/data/users-guide/example_java.result +56 -0
  108. data/test/data/users-guide/example_js.result +22 -0
  109. data/test/data/users-guide/example_perl.result +20 -0
  110. data/test/data/users-guide/example_php.result +19 -0
  111. data/test/data/users-guide/example_scheme.result +30 -0
  112. data/test/data/users-guide/example_scheme_display.result +29 -0
  113. data/test/data/users-guide/fasteruby-example.rb +8 -0
  114. data/test/data/users-guide/fasteruby-example.result +18 -0
  115. data/test/data/users-guide/fasteruby.rb +11 -0
  116. data/test/data/users-guide/fasteruby.result +38 -0
  117. data/test/data/users-guide/fasteruby.rhtml +15 -0
  118. data/test/data/users-guide/headerfooter-example.eruby +9 -0
  119. data/test/data/users-guide/headerfooter-example2.rb +8 -0
  120. data/test/data/users-guide/headerfooter-example2.rhtml +10 -0
  121. data/test/data/users-guide/headerfooter_example.result +11 -0
  122. data/test/data/users-guide/headerfooter_example2.result +13 -0
  123. data/test/data/users-guide/interpolation_example.result +9 -0
  124. data/test/data/users-guide/main_program1.rb +8 -0
  125. data/test/data/users-guide/main_program1.result +6 -0
  126. data/test/data/users-guide/main_program2.rb +8 -0
  127. data/test/data/users-guide/main_program2.result +6 -0
  128. data/test/data/users-guide/nocode-example.eruby +14 -0
  129. data/test/data/users-guide/nocode-php.result +20 -0
  130. data/test/data/users-guide/nocode_example.result +15 -0
  131. data/test/data/users-guide/normal-eruby-test.eruby +9 -0
  132. data/test/data/users-guide/normal_eruby_test.result +11 -0
  133. data/test/data/users-guide/notext-example.eruby +14 -0
  134. data/test/data/users-guide/notext-example.php +19 -0
  135. data/test/data/users-guide/notext-php.result +20 -0
  136. data/test/data/users-guide/notext_example.result +16 -0
  137. data/test/data/users-guide/percentline-example.rhtml +6 -0
  138. data/test/data/users-guide/percentline_example.result +9 -0
  139. data/test/data/users-guide/prefixedline-example.rb +9 -0
  140. data/test/data/users-guide/prefixedline-example.rhtml +6 -0
  141. data/test/data/users-guide/prefixedline_example.result +9 -0
  142. data/test/data/users-guide/printenable_example.result +4 -0
  143. data/test/data/users-guide/printenabled-example.eruby +3 -0
  144. data/test/data/users-guide/printenabled-example.rb +8 -0
  145. data/test/data/users-guide/printstatement_example.result +8 -0
  146. data/test/data/users-guide/simplify_example.result +9 -0
  147. data/test/data/users-guide/stderr.log +3 -0
  148. data/test/data/users-guide/stdout_exmple.result +9 -0
  149. data/test/data/users-guide/stringbuffer_example.result +9 -0
  150. data/test/data/users-guide/tail_260.result +4 -0
  151. data/test/data/users-guide/tailnewline.rhtml +3 -0
  152. data/test/data/users-guide/template1.rhtml +4 -0
  153. data/test/data/users-guide/template2.rhtml +4 -0
  154. data/test/test-engines.rb +425 -0
  155. data/test/test-enhancers.rb +646 -0
  156. data/test/test-erubis.rb +887 -0
  157. data/test/test-index-cgi.rb +191 -0
  158. data/test/test-main.rb +752 -0
  159. data/test/test-users-guide.rb +73 -0
  160. data/test/test.rb +45 -0
  161. data/test/testutil.rb +111 -0
  162. metadata +233 -0
@@ -0,0 +1,516 @@
1
+ ###
2
+ ### $Release: 2.7.0 $
3
+ ### copyright(c) 2006-2011 kuwata-lab.com all rights reserved.
4
+ ###
5
+
6
+ require 'yaml'
7
+ require 'erubis'
8
+ require 'erubis/tiny'
9
+ require 'erubis/engine/enhanced'
10
+ require 'erubis/engine/optimized'
11
+ require 'erubis/engine/eruby'
12
+ require 'erubis/engine/ephp'
13
+ require 'erubis/engine/ec'
14
+ require 'erubis/engine/ecpp'
15
+ require 'erubis/engine/ejava'
16
+ require 'erubis/engine/escheme'
17
+ require 'erubis/engine/eperl'
18
+ require 'erubis/engine/ejavascript'
19
+
20
+
21
+ module Erubis
22
+
23
+
24
+ Ejs = Ejavascript
25
+ EscapedEjs = EscapedEjavascript
26
+
27
+
28
+ class CommandOptionError < ErubisError
29
+ end
30
+
31
+
32
+ ##
33
+ ## main class of command
34
+ ##
35
+ ## ex.
36
+ ## Main.main(ARGV)
37
+ ##
38
+ class Main
39
+
40
+ def self.main(argv=ARGV)
41
+ status = 0
42
+ begin
43
+ Main.new.execute(ARGV)
44
+ rescue CommandOptionError => ex
45
+ $stderr.puts ex.message
46
+ status = 1
47
+ end
48
+ exit(status)
49
+ end
50
+
51
+ def initialize
52
+ @single_options = "hvxztTSbeBXNUC"
53
+ @arg_options = "pcrfKIlaE" #C
54
+ @option_names = {
55
+ 'h' => :help,
56
+ 'v' => :version,
57
+ 'x' => :source,
58
+ 'z' => :syntax,
59
+ 'T' => :unexpand,
60
+ 't' => :untabify, # obsolete
61
+ 'S' => :intern,
62
+ 'b' => :bodyonly,
63
+ 'B' => :binding,
64
+ 'p' => :pattern,
65
+ 'c' => :context,
66
+ #'C' => :class,
67
+ 'e' => :escape,
68
+ 'r' => :requires,
69
+ 'f' => :datafiles,
70
+ 'K' => :kanji,
71
+ 'I' => :includes,
72
+ 'l' => :lang,
73
+ 'a' => :action,
74
+ 'E' => :enhancers,
75
+ 'X' => :notext,
76
+ 'N' => :linenum,
77
+ 'U' => :unique,
78
+ 'C' => :compact,
79
+ }
80
+ assert unless @single_options.length + @arg_options.length == @option_names.length
81
+ (@single_options + @arg_options).each_byte do |ch|
82
+ assert unless @option_names.key?(ch.chr)
83
+ end
84
+ end
85
+
86
+
87
+ def execute(argv=ARGV)
88
+ ## parse command-line options
89
+ options, properties = parse_argv(argv, @single_options, @arg_options)
90
+ filenames = argv
91
+ options['h'] = true if properties[:help]
92
+ opts = Object.new
93
+ arr = @option_names.collect {|ch, name| "def #{name}; @#{name}; end\n" }
94
+ opts.instance_eval arr.join
95
+ options.each do |ch, val|
96
+ name = @option_names[ch]
97
+ opts.instance_variable_set("@#{name}", val)
98
+ end
99
+
100
+ ## help, version, enhancer list
101
+ if opts.help || opts.version
102
+ puts version() if opts.version
103
+ puts usage() if opts.help
104
+ puts show_properties() if opts.help
105
+ puts show_enhancers() if opts.help
106
+ return
107
+ end
108
+
109
+ ## include path
110
+ opts.includes.split(/,/).each do |path|
111
+ $: << path
112
+ end if opts.includes
113
+
114
+ ## require library
115
+ opts.requires.split(/,/).each do |library|
116
+ require library
117
+ end if opts.requires
118
+
119
+ ## action
120
+ action = opts.action
121
+ action ||= 'syntax' if opts.syntax
122
+ action ||= 'convert' if opts.source || opts.notext
123
+
124
+ ## lang
125
+ lang = opts.lang || 'ruby'
126
+ action ||= 'convert' if opts.lang
127
+
128
+ ## class name of Eruby
129
+ #classname = opts.class
130
+ classname = nil
131
+ klass = get_classobj(classname, lang, properties[:pi])
132
+
133
+ ## kanji code
134
+ $KCODE = opts.kanji if opts.kanji
135
+
136
+ ## read context values from yaml file
137
+ datafiles = opts.datafiles
138
+ context = load_datafiles(datafiles, opts)
139
+
140
+ ## parse context data
141
+ if opts.context
142
+ context = parse_context_data(opts.context, opts)
143
+ end
144
+
145
+ ## properties for engine
146
+ properties[:escape] = true if opts.escape && !properties.key?(:escape)
147
+ properties[:pattern] = opts.pattern if opts.pattern
148
+ #properties[:trim] = false if opts.notrim
149
+ properties[:preamble] = properties[:postamble] = false if opts.bodyonly
150
+ properties[:pi] = nil if properties[:pi] == true
151
+
152
+ ## create engine and extend enhancers
153
+ engine = klass.new(nil, properties)
154
+ enhancers = get_enhancers(opts.enhancers)
155
+ #enhancers.push(Erubis::EscapeEnhancer) if opts.escape
156
+ enhancers.each do |enhancer|
157
+ engine.extend(enhancer)
158
+ engine.bipattern = properties[:bipattern] if enhancer == Erubis::BiPatternEnhancer
159
+ end
160
+
161
+ ## no-text
162
+ engine.extend(Erubis::NoTextEnhancer) if opts.notext
163
+
164
+ ## convert and execute
165
+ val = nil
166
+ msg = "Syntax OK\n"
167
+ if filenames && !filenames.empty?
168
+ filenames.each do |filename|
169
+ File.file?(filename) or
170
+ raise CommandOptionError.new("#{filename}: file not found.")
171
+ engine.filename = filename
172
+ engine.convert!(File.read(filename))
173
+ val = do_action(action, engine, context, filename, opts)
174
+ msg = nil if val
175
+ end
176
+ else
177
+ engine.filename = filename = '(stdin)'
178
+ engine.convert!($stdin.read())
179
+ val = do_action(action, engine, context, filename, opts)
180
+ msg = nil if val
181
+ end
182
+ print msg if action == 'syntax' && msg
183
+
184
+ end
185
+
186
+ private
187
+
188
+ def do_action(action, engine, context, filename, opts)
189
+ case action
190
+ when 'convert'
191
+ s = manipulate_src(engine.src, opts)
192
+ when nil, 'exec', 'execute'
193
+ s = opts.binding ? engine.result(context.to_hash) : engine.evaluate(context)
194
+ when 'syntax'
195
+ s = check_syntax(filename, engine.src)
196
+ else
197
+ raise "*** internal error"
198
+ end
199
+ print s if s
200
+ return s
201
+ end
202
+
203
+ def manipulate_src(source, opts)
204
+ flag_linenum = opts.linenum
205
+ flag_unique = opts.unique
206
+ flag_compact = opts.compact
207
+ if flag_linenum
208
+ n = 0
209
+ source.gsub!(/^/) { n += 1; "%5d: " % n }
210
+ source.gsub!(/^ *\d+:\s+?\n/, '') if flag_compact
211
+ source.gsub!(/(^ *\d+:\s+?\n)+/, "\n") if flag_unique
212
+ else
213
+ source.gsub!(/^\s*?\n/, '') if flag_compact
214
+ source.gsub!(/(^\s*?\n)+/, "\n") if flag_unique
215
+ end
216
+ return source
217
+ end
218
+
219
+ def usage(command=nil)
220
+ command ||= File.basename($0)
221
+ buf = []
222
+ buf << "erubis - embedded program converter for multi-language"
223
+ buf << "Usage: #{command} [..options..] [file ...]"
224
+ buf << " -h, --help : help"
225
+ buf << " -v : version"
226
+ buf << " -x : show converted code"
227
+ buf << " -X : show converted code, only ruby code and no text part"
228
+ buf << " -N : numbering: add line numbers (for '-x/-X')"
229
+ buf << " -U : unique: compress empty lines to a line (for '-x/-X')"
230
+ buf << " -C : compact: remove empty lines (for '-x/-X')"
231
+ buf << " -b : body only: no preamble nor postamble (for '-x/-X')"
232
+ buf << " -z : syntax checking"
233
+ buf << " -e : escape (equal to '--E Escape')"
234
+ buf << " -p pattern : embedded pattern (default '<% %>')"
235
+ buf << " -l lang : convert but no execute (ruby/php/c/cpp/java/scheme/perl/js)"
236
+ buf << " -E e1,e2,... : enhancer names (Escape, PercentLine, BiPattern, ...)"
237
+ buf << " -I path : library include path"
238
+ buf << " -K kanji : kanji code (euc/sjis/utf8) (default none)"
239
+ buf << " -c context : context data string (yaml inline style or ruby code)"
240
+ buf << " -f datafile : context data file ('*.yaml', '*.yml', or '*.rb')"
241
+ #buf << " -t : expand tab characters in YAML file"
242
+ buf << " -T : don't expand tab characters in YAML file"
243
+ buf << " -S : convert mapping key from string to symbol in YAML file"
244
+ buf << " -B : invoke 'result(binding)' instead of 'evaluate(context)'"
245
+ buf << " --pi=name : parse '<?name ... ?>' instead of '<% ... %>'"
246
+ #'
247
+ # -T : don't trim spaces around '<% %>'
248
+ # -c class : class name (XmlEruby/PercentLineEruby/...) (default Eruby)
249
+ # -r library : require library
250
+ # -a : action (convert/execute)
251
+ return buf.join("\n")
252
+ end
253
+
254
+ def collect_supported_properties(erubis_klass)
255
+ list = []
256
+ erubis_klass.ancestors.each do |klass|
257
+ if klass.respond_to?(:supported_properties)
258
+ list.concat(klass.supported_properties)
259
+ end
260
+ end
261
+ return list
262
+ end
263
+
264
+ def show_properties
265
+ s = "supported properties:\n"
266
+ basic_props = collect_supported_properties(Erubis::Basic::Engine)
267
+ pi_props = collect_supported_properties(Erubis::PI::Engine)
268
+ list = []
269
+ common_props = basic_props & pi_props
270
+ list << ['(common)', common_props]
271
+ list << ['(basic)', basic_props - common_props]
272
+ list << ['(pi)', pi_props - common_props]
273
+ %w[ruby php c cpp java scheme perl javascript].each do |lang|
274
+ klass = Erubis.const_get("E#{lang}")
275
+ list << [lang, collect_supported_properties(klass) - basic_props]
276
+ end
277
+ list.each do |lang, props|
278
+ s << " * #{lang}\n"
279
+ props.each do |name, default_val, desc|
280
+ s << (" --%-23s : %s\n" % ["#{name}=#{default_val.inspect}", desc])
281
+ end
282
+ end
283
+ s << "\n"
284
+ return s
285
+ end
286
+
287
+ def show_enhancers
288
+ dict = {}
289
+ ObjectSpace.each_object(Module) do |mod|
290
+ dict[$1] = mod if mod.name =~ /\AErubis::(.*)Enhancer\z/
291
+ end
292
+ s = "enhancers:\n"
293
+ dict.sort_by {|name, mod| name }.each do |name, mod|
294
+ s << (" %-13s : %s\n" % [name, mod.desc])
295
+ end
296
+ return s
297
+ end
298
+
299
+ def version
300
+ return Erubis::VERSION
301
+ end
302
+
303
+ def parse_argv(argv, arg_none='', arg_required='', arg_optional='')
304
+ options = {}
305
+ context = {}
306
+ while argv[0] && argv[0][0] == ?-
307
+ optstr = argv.shift
308
+ optstr = optstr[1, optstr.length-1]
309
+ #
310
+ if optstr[0] == ?- # context
311
+ optstr =~ /\A\-([-\w]+)(?:=(.*))?/ or
312
+ raise CommandOptionError.new("-#{optstr}: invalid context value.")
313
+ name, value = $1, $2
314
+ name = name.gsub(/-/, '_').intern
315
+ #value = value.nil? ? true : YAML.load(value) # error, why?
316
+ value = value.nil? ? true : YAML.load("---\n#{value}\n")
317
+ context[name] = value
318
+ #
319
+ else # options
320
+ while optstr && !optstr.empty?
321
+ optchar = optstr[0].chr
322
+ optstr = optstr[1..-1]
323
+ if arg_none.include?(optchar)
324
+ options[optchar] = true
325
+ elsif arg_required.include?(optchar)
326
+ arg = optstr.empty? ? argv.shift : optstr or
327
+ raise CommandOptionError.new("-#{optchar}: #{@option_names[optchar]} required.")
328
+ options[optchar] = arg
329
+ optstr = nil
330
+ elsif arg_optional.include?(optchar)
331
+ arg = optstr.empty? ? true : optstr
332
+ options[optchar] = arg
333
+ optstr = nil
334
+ else
335
+ raise CommandOptionError.new("-#{optchar}: unknown option.")
336
+ end
337
+ end
338
+ end
339
+ #
340
+ end # end of while
341
+
342
+ return options, context
343
+ end
344
+
345
+
346
+ def untabify(str, width=8)
347
+ list = str.split(/\t/)
348
+ last = list.pop
349
+ sb = ''
350
+ list.each do |s|
351
+ column = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
352
+ n = width - (column % width)
353
+ sb << s << (' ' * n)
354
+ end
355
+ sb << last
356
+ return sb
357
+ end
358
+ #--
359
+ #def untabify(str, width=8)
360
+ # sb = ''
361
+ # str.scan(/(.*?)\t/m) do |s, |
362
+ # len = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
363
+ # sb << s << (" " * (width - len % width))
364
+ # end
365
+ # return $' ? (sb << $') : str
366
+ #end
367
+ #++
368
+
369
+
370
+ def get_classobj(classname, lang, pi)
371
+ classname ||= "E#{lang}"
372
+ base_module = pi ? Erubis::PI : Erubis
373
+ begin
374
+ klass = base_module.const_get(classname)
375
+ rescue NameError
376
+ klass = nil
377
+ end
378
+ unless klass
379
+ if lang
380
+ msg = "-l #{lang}: invalid language name (class #{base_module.name}::#{classname} not found)."
381
+ else
382
+ msg = "-c #{classname}: invalid class name."
383
+ end
384
+ raise CommandOptionError.new(msg)
385
+ end
386
+ return klass
387
+ end
388
+
389
+ def get_enhancers(enhancer_names)
390
+ return [] unless enhancer_names
391
+ enhancers = []
392
+ shortname = nil
393
+ begin
394
+ enhancer_names.split(/,/).each do |name|
395
+ shortname = name
396
+ enhancers << Erubis.const_get("#{shortname}Enhancer")
397
+ end
398
+ rescue NameError
399
+ raise CommandOptionError.new("#{shortname}: no such Enhancer (try '-h' to show all enhancers).")
400
+ end
401
+ return enhancers
402
+ end
403
+
404
+ def load_datafiles(filenames, opts)
405
+ context = Erubis::Context.new
406
+ return context unless filenames
407
+ filenames.split(/,/).each do |filename|
408
+ filename.strip!
409
+ test(?f, filename) or raise CommandOptionError.new("#{filename}: file not found.")
410
+ if filename =~ /\.ya?ml$/
411
+ if opts.unexpand
412
+ ydoc = YAML.load_file(filename)
413
+ else
414
+ ydoc = YAML.load(untabify(File.read(filename)))
415
+ end
416
+ ydoc.is_a?(Hash) or raise CommandOptionError.new("#{filename}: root object is not a mapping.")
417
+ intern_hash_keys(ydoc) if opts.intern
418
+ context.update(ydoc)
419
+ elsif filename =~ /\.rb$/
420
+ str = File.read(filename)
421
+ context2 = Erubis::Context.new
422
+ _instance_eval(context2, str)
423
+ context.update(context2)
424
+ else
425
+ CommandOptionError.new("#{filename}: '*.yaml', '*.yml', or '*.rb' required.")
426
+ end
427
+ end
428
+ return context
429
+ end
430
+
431
+ def _instance_eval(_context, _str)
432
+ _context.instance_eval(_str)
433
+ end
434
+
435
+ def parse_context_data(context_str, opts)
436
+ if context_str[0] == ?{
437
+ require 'yaml'
438
+ ydoc = YAML.load(context_str)
439
+ unless ydoc.is_a?(Hash)
440
+ raise CommandOptionError.new("-c: root object is not a mapping.")
441
+ end
442
+ intern_hash_keys(ydoc) if opts.intern
443
+ return ydoc
444
+ else
445
+ context = Erubis::Context.new
446
+ context.instance_eval(context_str, '-c')
447
+ return context
448
+ end
449
+ end
450
+
451
+ def intern_hash_keys(obj, done={})
452
+ return if done.key?(obj.__id__)
453
+ case obj
454
+ when Hash
455
+ done[obj.__id__] = obj
456
+ obj.keys.each do |key|
457
+ obj[key.intern] = obj.delete(key) if key.is_a?(String)
458
+ end
459
+ obj.values.each do |val|
460
+ intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
461
+ end
462
+ when Array
463
+ done[obj.__id__] = obj
464
+ obj.each do |val|
465
+ intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
466
+ end
467
+ end
468
+ end
469
+
470
+ def check_syntax(filename, src)
471
+ require 'open3'
472
+ #command = (ENV['_'] || 'ruby') + ' -wc' # ENV['_'] stores command name
473
+ bin = ENV['_'] && File.basename(ENV['_']) =~ /^ruby/ ? ENV['_'] : 'ruby'
474
+ command = bin + ' -wc'
475
+ stdin, stdout, stderr = Open3.popen3(command)
476
+ stdin.write(src)
477
+ stdin.close
478
+ result = stdout.read()
479
+ stdout.close()
480
+ errmsg = stderr.read()
481
+ stderr.close()
482
+ return nil unless errmsg && !errmsg.empty?
483
+ errmsg =~ /\A-:(\d+): /
484
+ linenum, message = $1, $'
485
+ return "#{filename}:#{linenum}: #{message}"
486
+ end
487
+
488
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == "rbx"
489
+ def check_syntax(filename, src)
490
+ require 'compiler'
491
+ verbose = $VERBOSE
492
+ msg = nil
493
+ begin
494
+ $VERBOSE = true
495
+ Rubinius::Compiler.compile_string(src, filename)
496
+ rescue SyntaxError => ex
497
+ ex_linenum = ex.line
498
+ linenum = 0
499
+ srcline = src.each_line do |line|
500
+ linenum += 1
501
+ break line if linenum == ex_linenum
502
+ end
503
+ msg = "#{ex.message}\n"
504
+ msg << srcline
505
+ msg << "\n" unless srcline =~ /\n\z/
506
+ msg << (" " * (ex.column-1)) << "^\n"
507
+ ensure
508
+ $VERBOSE = verbose
509
+ end
510
+ return msg
511
+ end
512
+ end
513
+
514
+ end
515
+
516
+ end