Parent

Class Index [+]

Quicksearch

Erubis::Main

main class of command

ex.

  Main.main(ARGV)

Public Class Methods

main(argv=ARGV) click to toggle source
    # File lib/erubis/main.rb, line 39
39:     def self.main(argv=ARGV)
40:       status = 0
41:       begin
42:         Main.new.execute(ARGV)
43:       rescue CommandOptionError => ex
44:         $stderr.puts ex.message
45:         status = 1
46:       end
47:       exit(status)
48:     end
new() click to toggle source
    # File lib/erubis/main.rb, line 50
50:     def initialize
51:       @single_options = "hvxztTSbeBXNUC"
52:       @arg_options    = "pcrfKIlaE" #C
53:       @option_names   = {
54:         'h' => :help,
55:         'v' => :version,
56:         'x' => :source,
57:         'z' => :syntax,
58:         'T' => :unexpand,
59:         't' => :untabify,      # obsolete
60:         'S' => :intern,
61:         'b' => :bodyonly,
62:         'B' => :binding,
63:         'p' => :pattern,
64:         'c' => :context,
65:         #'C' => :class,
66:         'e' => :escape,
67:         'r' => :requires,
68:         'f' => :datafiles,
69:         'K' => :kanji,
70:         'I' => :includes,
71:         'l' => :lang,
72:         'a' => :action,
73:         'E' => :enhancers,
74:         'X' => :notext,
75:         'N' => :linenum,
76:         'U' => :unique,
77:         'C' => :compact,
78:       }
79:       assert unless @single_options.length + @arg_options.length == @option_names.length
80:       (@single_options + @arg_options).each_byte do |ch|
81:         assert unless @option_names.key?(ch.chr)
82:       end
83:     end

Public Instance Methods

execute(argv=ARGV) click to toggle source
     # File lib/erubis/main.rb, line 86
 86:     def execute(argv=ARGV)
 87:       ## parse command-line options
 88:       options, properties = parse_argv(argv, @single_options, @arg_options)
 89:       filenames = argv
 90:       options['h'] = true if properties[:help]
 91:       opts = Object.new
 92:       arr = @option_names.collect {|ch, name| "def #{name}; @#{name}; end\n" }
 93:       opts.instance_eval arr.join
 94:       options.each do |ch, val|
 95:         name = @option_names[ch]
 96:         opts.instance_variable_set("@#{name}", val)
 97:       end
 98: 
 99:       ## help, version, enhancer list
100:       if opts.help || opts.version
101:         puts version()         if opts.version
102:         puts usage()           if opts.help
103:         puts show_properties() if opts.help
104:         puts show_enhancers()  if opts.help
105:         return
106:       end
107: 
108:       ## include path
109:       opts.includes.split(/,/).each do |path|
110:         $: << path
111:       end if opts.includes
112: 
113:       ## require library
114:       opts.requires.split(/,/).each do |library|
115:         require library
116:       end if opts.requires
117: 
118:       ## action
119:       action = opts.action
120:       action ||= 'syntax'  if opts.syntax
121:       action ||= 'convert' if opts.source || opts.notext
122: 
123:       ## lang
124:       lang = opts.lang || 'ruby'
125:       action ||= 'convert' if opts.lang
126: 
127:       ## class name of Eruby
128:       #classname = opts.class
129:       classname = nil
130:       klass = get_classobj(classname, lang, properties[:pi])
131: 
132:       ## kanji code
133:       $KCODE = opts.kanji if opts.kanji
134: 
135:       ## read context values from yaml file
136:       datafiles = opts.datafiles
137:       context = load_datafiles(datafiles, opts)
138: 
139:       ## parse context data
140:       if opts.context
141:         context = parse_context_data(opts.context, opts)
142:       end
143: 
144:       ## properties for engine
145:       properties[:escape]   = true         if opts.escape && !properties.key?(:escape)
146:       properties[:pattern]  = opts.pattern if opts.pattern
147:       #properties[:trim]     = false        if opts.notrim
148:       properties[:preamble] = properties[:postamble] = false if opts.bodyonly
149:       properties[:pi]       = nil          if properties[:pi] == true
150: 
151:       ## create engine and extend enhancers
152:       engine = klass.new(nil, properties)
153:       enhancers = get_enhancers(opts.enhancers)
154:       #enhancers.push(Erubis::EscapeEnhancer) if opts.escape
155:       enhancers.each do |enhancer|
156:         engine.extend(enhancer)
157:         engine.bipattern = properties[:bipattern] if enhancer == Erubis::BiPatternEnhancer
158:       end
159: 
160:       ## no-text
161:       engine.extend(Erubis::NoTextEnhancer) if opts.notext
162: 
163:       ## convert and execute
164:       val = nil
165:       msg = "Syntax OK\n"
166:       if filenames && !filenames.empty?
167:         filenames.each do |filename|
168:           File.file?(filename)  or
169:             raise CommandOptionError.new("#{filename}: file not found.")
170:           engine.filename = filename
171:           engine.convert!(File.read(filename))
172:           val = do_action(action, engine, context, filename, opts)
173:           msg = nil if val
174:         end
175:       else
176:         engine.filename = filename = '(stdin)'
177:         engine.convert!($stdin.read())
178:         val = do_action(action, engine, context, filename, opts)
179:         msg = nil if val
180:       end
181:       print msg if action == 'syntax' && msg
182: 
183:     end

Private Instance Methods

_instance_eval(_context, _str) click to toggle source
     # File lib/erubis/main.rb, line 430
430:     def _instance_eval(_context, _str)
431:       _context.instance_eval(_str)
432:     end
check_syntax(filename, src) click to toggle source
     # File lib/erubis/main.rb, line 469
469:     def check_syntax(filename, src)
470:       require 'open3'
471:       #command = (ENV['_'] || 'ruby') + ' -wc'   # ENV['_'] stores command name
472:       bin = ENV['_'] && File.basename(ENV['_']) =~ /^ruby/ ? ENV['_'] : 'ruby'
473:       command = bin + ' -wc'
474:       stdin, stdout, stderr = Open3.popen3(command)
475:       stdin.write(src)
476:       stdin.close
477:       result = stdout.read()
478:       stdout.close()
479:       errmsg = stderr.read()
480:       stderr.close()
481:       return nil unless errmsg && !errmsg.empty?
482:       errmsg =~ /\A-:(\d+): /
483:       linenum, message = $1, $'
484:       return "#{filename}:#{linenum}: #{message}"
485:     end
collect_supported_properties(erubis_klass) click to toggle source
     # File lib/erubis/main.rb, line 253
253:     def collect_supported_properties(erubis_klass)
254:       list = []
255:       erubis_klass.ancestors.each do |klass|
256:         if klass.respond_to?(:supported_properties)
257:           list.concat(klass.supported_properties)
258:         end
259:       end
260:       return list
261:     end
do_action(action, engine, context, filename, opts) click to toggle source
     # File lib/erubis/main.rb, line 187
187:     def do_action(action, engine, context, filename, opts)
188:       case action
189:       when 'convert'
190:         s = manipulate_src(engine.src, opts)
191:       when nil, 'exec', 'execute'
192:         s = opts.binding ? engine.result(context.to_hash) : engine.evaluate(context)
193:       when 'syntax'
194:         s = check_syntax(filename, engine.src)
195:       else
196:         raise "*** internal error"
197:       end
198:       print s if s
199:       return s
200:     end
get_classobj(classname, lang, pi) click to toggle source
     # File lib/erubis/main.rb, line 369
369:     def get_classobj(classname, lang, pi)
370:       classname ||= "E#{lang}"
371:       base_module = pi ? Erubis::PI : Erubis
372:       begin
373:         klass = base_module.const_get(classname)
374:       rescue NameError
375:         klass = nil
376:       end
377:       unless klass
378:         if lang
379:           msg = "-l #{lang}: invalid language name (class #{base_module.name}::#{classname} not found)."
380:         else
381:           msg = "-c #{classname}: invalid class name."
382:         end
383:         raise CommandOptionError.new(msg)
384:       end
385:       return klass
386:     end
get_enhancers(enhancer_names) click to toggle source
     # File lib/erubis/main.rb, line 388
388:     def get_enhancers(enhancer_names)
389:       return [] unless enhancer_names
390:       enhancers = []
391:       shortname = nil
392:       begin
393:         enhancer_names.split(/,/).each do |name|
394:           shortname = name
395:           enhancers << Erubis.const_get("#{shortname}Enhancer")
396:         end
397:       rescue NameError
398:         raise CommandOptionError.new("#{shortname}: no such Enhancer (try '-h' to show all enhancers).")
399:       end
400:       return enhancers
401:     end
intern_hash_keys(obj, done={}) click to toggle source
     # File lib/erubis/main.rb, line 450
450:     def intern_hash_keys(obj, done={})
451:       return if done.key?(obj.__id__)
452:       case obj
453:       when Hash
454:         done[obj.__id__] = obj
455:         obj.keys.each do |key|
456:           obj[key.intern] = obj.delete(key) if key.is_a?(String)
457:         end
458:         obj.values.each do |val|
459:           intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
460:         end
461:       when Array
462:         done[obj.__id__] = obj
463:         obj.each do |val|
464:           intern_hash_keys(val, done) if val.is_a?(Hash) || val.is_a?(Array)
465:         end
466:       end
467:     end
load_datafiles(filenames, opts) click to toggle source
     # File lib/erubis/main.rb, line 403
403:     def load_datafiles(filenames, opts)
404:       context = Erubis::Context.new
405:       return context unless filenames
406:       filenames.split(/,/).each do |filename|
407:         filename.strip!
408:         test(ff, filename) or raise CommandOptionError.new("#{filename}: file not found.")
409:         if filename =~ /\.ya?ml$/
410:           if opts.unexpand
411:             ydoc = YAML.load_file(filename)
412:           else
413:             ydoc = YAML.load(untabify(File.read(filename)))
414:           end
415:           ydoc.is_a?(Hash) or raise CommandOptionError.new("#{filename}: root object is not a mapping.")
416:           intern_hash_keys(ydoc) if opts.intern
417:           context.update(ydoc)
418:         elsif filename =~ /\.rb$/
419:           str = File.read(filename)
420:           context2 = Erubis::Context.new
421:           _instance_eval(context2, str)
422:           context.update(context2)
423:         else
424:           CommandOptionError.new("#{filename}: '*.yaml', '*.yml', or '*.rb' required.")
425:         end
426:       end
427:       return context
428:     end
manipulate_src(source, opts) click to toggle source
     # File lib/erubis/main.rb, line 202
202:     def manipulate_src(source, opts)
203:       flag_linenum   = opts.linenum
204:       flag_unique    = opts.unique
205:       flag_compact   = opts.compact
206:       if flag_linenum
207:         n = 0
208:         source.gsub!(/^/) { n += 1; "%5d:  " % n }
209:         source.gsub!(/^ *\d+:\s+?\n/, '')      if flag_compact
210:         source.gsub!(/(^ *\d+:\s+?\n)+/, "\n") if flag_unique
211:       else
212:         source.gsub!(/^\s*?\n/, '')      if flag_compact
213:         source.gsub!(/(^\s*?\n)+/, "\n") if flag_unique
214:       end
215:       return source
216:     end
parse_argv(argv, arg_none='', arg_required='', arg_optional='') click to toggle source
     # File lib/erubis/main.rb, line 302
302:     def parse_argv(argv, arg_none='', arg_required='', arg_optional='')
303:       options = {}
304:       context = {}
305:       while argv[0] && argv[0][0] == --
306:         optstr = argv.shift
307:         optstr = optstr[1, optstr.length-1]
308:         #
309:         if optstr[0] == --    # context
310:           optstr =~ /\A\-([-\w]+)(?:=(.*))?/  or
311:             raise CommandOptionError.new("-#{optstr}: invalid context value.")
312:           name, value = $1, $2
313:           name  = name.gsub(/-/, '_').intern
314:           #value = value.nil? ? true : YAML.load(value)   # error, why?
315:           value = value.nil? ? true : YAML.load("---\n#{value}\n")
316:           context[name] = value
317:           #
318:         else                  # options
319:           while optstr && !optstr.empty?
320:             optchar = optstr[0].chr
321:             optstr = optstr[1..1]
322:             if arg_none.include?(optchar)
323:               options[optchar] = true
324:             elsif arg_required.include?(optchar)
325:               arg = optstr.empty? ? argv.shift : optstr  or
326:                 raise CommandOptionError.new("-#{optchar}: #{@option_names[optchar]} required.")
327:               options[optchar] = arg
328:               optstr = nil
329:             elsif arg_optional.include?(optchar)
330:               arg = optstr.empty? ? true : optstr
331:               options[optchar] = arg
332:               optstr = nil
333:             else
334:               raise CommandOptionError.new("-#{optchar}: unknown option.")
335:             end
336:           end
337:         end
338:         #
339:       end  # end of while
340: 
341:       return options, context
342:     end
parse_context_data(context_str, opts) click to toggle source
     # File lib/erubis/main.rb, line 434
434:     def parse_context_data(context_str, opts)
435:       if context_str[0] == {{
436:         require 'yaml'
437:         ydoc = YAML.load(context_str)
438:         unless ydoc.is_a?(Hash)
439:           raise CommandOptionError.new("-c: root object is not a mapping.")
440:         end
441:         intern_hash_keys(ydoc) if opts.intern
442:         return ydoc
443:       else
444:         context = Erubis::Context.new
445:         context.instance_eval(context_str, '-c')
446:         return context
447:       end
448:     end
show_enhancers() click to toggle source
     # File lib/erubis/main.rb, line 286
286:     def show_enhancers
287:       dict = {}
288:       ObjectSpace.each_object(Module) do |mod|
289:         dict[$1] = mod if mod.name =~ /\AErubis::(.*)Enhancer\z/
290:       end
291:       s = "enhancers:\n"
292:       dict.sort_by {|name, mod| name }.each do |name, mod|
293:         s << ("  %-13s : %s\n" % [name, mod.desc])
294:       end
295:       return s
296:     end
show_properties() click to toggle source
     # File lib/erubis/main.rb, line 263
263:     def show_properties
264:       s = "supported properties:\n"
265:       basic_props = collect_supported_properties(Erubis::Basic::Engine)
266:       pi_props    = collect_supported_properties(Erubis::PI::Engine)
267:       list = []
268:       common_props = basic_props & pi_props
269:       list << ['(common)', common_props]
270:       list << ['(basic)',  basic_props - common_props]
271:       list << ['(pi)',     pi_props    - common_props]
272:       ]ruby php c java scheme perl javascript].each do |lang|
273:         klass = Erubis.const_get("E#{lang}")
274:         list << [lang, collect_supported_properties(klass) - basic_props]
275:       end
276:       list.each do |lang, props|
277:         s << "  * #{lang}\n"
278:         props.each do |name, default_val, desc|
279:           s << ("     --%-23s : %s\n" % ["#{name}=#{default_val.inspect}", desc])
280:         end
281:       end
282:       s << "\n"
283:       return s
284:     end
untabify(str, width=8) click to toggle source
     # File lib/erubis/main.rb, line 345
345:     def untabify(str, width=8)
346:       list = str.split(/\t/)
347:       last = list.pop
348:       sb = ''
349:       list.each do |s|
350:         column = (n = s.rindex(\n\)) ? s.length - n - 1 : s.length
351:         n = width - (column % width)
352:         sb << s << (' ' * n)
353:       end
354:       sb << last
355:       return sb
356:     end
usage(command=nil) click to toggle source
     # File lib/erubis/main.rb, line 218
218:     def usage(command=nil)
219:       command ||= File.basename($0)
220:       buf = []
221:       buf << "erubis - embedded program converter for multi-language"
222:       buf << "Usage: #{command} [..options..] [file ...]"
223:       buf << "  -h, --help    : help"
224:       buf << "  -v            : version"
225:       buf << "  -x            : show converted code"
226:       buf << "  -X            : show converted code, only ruby code and no text part"
227:       buf << "  -N            : numbering: add line numbers            (for '-x/-X')"
228:       buf << "  -U            : unique: compress empty lines to a line (for '-x/-X')"
229:       buf << "  -C            : compact: remove empty lines            (for '-x/-X')"
230:       buf << "  -b            : body only: no preamble nor postamble   (for '-x/-X')"
231:       buf << "  -z            : syntax checking"
232:       buf << "  -e            : escape (equal to '--E Escape')"
233:       buf << "  -p pattern    : embedded pattern (default '<% %>')"
234:       buf << "  -l lang       : convert but no execute (ruby/php/c/java/scheme/perl/js)"
235:       buf << "  -E e1,e2,...  : enhancer names (Escape, PercentLine, BiPattern, ...)"
236:       buf << "  -I path       : library include path"
237:       buf << "  -K kanji      : kanji code (euc/sjis/utf8) (default none)"
238:       buf << "  -c context    : context data string (yaml inline style or ruby code)"
239:       buf << "  -f datafile   : context data file ('*.yaml', '*.yml', or '*.rb')"
240:       #buf << "  -t            : expand tab characters in YAML file"
241:       buf << "  -T            : don't expand tab characters in YAML file"
242:       buf << "  -S            : convert mapping key from string to symbol in YAML file"
243:       buf << "  -B            : invoke 'result(binding)' instead of 'evaluate(context)'"
244:       buf << "  --pi=name     : parse '<?name ... ?>' instead of '<% ... %>'"
245:       #'
246:       #  -T            : don't trim spaces around '<% %>'
247:       #  -c class      : class name (XmlEruby/PercentLineEruby/...) (default Eruby)
248:       #  -r library    : require library
249:       #  -a            : action (convert/execute)
250:       return buf.join("\n")
251:     end
version() click to toggle source
     # File lib/erubis/main.rb, line 298
298:     def version
299:       return Erubis::VERSION
300:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.