erbse 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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