summaryrefslogtreecommitdiff
path: root/scripts/context/ruby/base/switch.rb
diff options
context:
space:
mode:
authorMarius <mariausol@gmail.com>2010-07-04 15:32:09 +0300
committerMarius <mariausol@gmail.com>2010-07-04 15:32:09 +0300
commit85b7bc695629926641c7cb752fd478adfdf374f3 (patch)
tree80293f5aaa7b95a500a78392c39688d8ee7a32fc /scripts/context/ruby/base/switch.rb
downloadcontext-85b7bc695629926641c7cb752fd478adfdf374f3.tar.gz
stable 2010-05-24 13:10
Diffstat (limited to 'scripts/context/ruby/base/switch.rb')
-rw-r--r--scripts/context/ruby/base/switch.rb635
1 files changed, 635 insertions, 0 deletions
diff --git a/scripts/context/ruby/base/switch.rb b/scripts/context/ruby/base/switch.rb
new file mode 100644
index 000000000..19eced424
--- /dev/null
+++ b/scripts/context/ruby/base/switch.rb
@@ -0,0 +1,635 @@
+# module : base/switch
+# copyright : PRAGMA Advanced Document Engineering
+# version : 2002-2005
+# author : Hans Hagen
+#
+# project : ConTeXt / eXaMpLe
+# concept : Hans Hagen
+# info : j.hagen@xs4all.nl
+# www : www.pragma-ade.com
+
+# we cannot use getoptlong because we want to be more
+# tolerant; also we want to be case insensitive (2002).
+
+# we could make each option a class itself, but this is
+# simpler; also we can put more in the array
+
+# beware: regexps/o in methods are optimized globally
+
+require "rbconfig"
+
+$mswindows = Config::CONFIG['host_os'] =~ /mswin/
+$separator = File::PATH_SEPARATOR
+
+class String
+
+ def has_suffix?(suffix)
+ self =~ /\.#{suffix}$/i
+ end
+
+end
+
+# may move to another module
+
+class File
+
+ @@update_eps = 1
+
+ def File.needsupdate(oldname,newname)
+ begin
+ oldtime = File.stat(oldname).mtime.to_i
+ newtime = File.stat(newname).mtime.to_i
+ if newtime >= oldtime then
+ return false
+ elsif oldtime-newtime < @@update_eps then
+ return false
+ else
+ return true
+ end
+ rescue
+ return true
+ end
+ end
+
+ def File.syncmtimes(oldname,newname)
+ return
+ begin
+ if $mswindows then
+ # does not work (yet) / gives future timestamp
+ # t = File.mtime(oldname) # i'm not sure if the time is frozen, so we do it here
+ # File.utime(0,t,oldname,newname)
+ else
+ t = File.mtime(oldname) # i'm not sure if the time is frozen, so we do it here
+ File.utime(0,t,oldname,newname)
+ end
+ rescue
+ end
+ end
+
+ def File.timestamp(name)
+ begin
+ "#{File.stat(name).mtime}"
+ rescue
+ return 'unknown'
+ end
+ end
+
+end
+
+# main thing
+
+module CommandBase
+
+ # this module can be used as a mixin in a command handler
+
+ $stdout.sync = true
+
+ def initialize(commandline,logger,banner)
+ @commandline, @logger, @banner = commandline, logger, banner
+ @forcenewline, @versiondone, @error = false, false, false
+ version if @commandline.option('version')
+ end
+
+ def reportlines(*str)
+ @logger.reportlines(str)
+ end
+
+ # only works in 1.8
+ #
+ # def report(*str)
+ # @logger.report(str)
+ # end
+ #
+ # def version # just a bit of playing with defs
+ # report(@banner.join(' - '))
+ # def report(*str)
+ # @logger.report
+ # @logger.report(str)
+ # def report(*str)
+ # @logger.report(str)
+ # end
+ # end
+ # def version
+ # end
+ # end
+
+ def report(*str)
+ initlogger ; @logger.report(str)
+ end
+
+ def seterror
+ @error = true
+ end
+
+ def error?
+ return @error
+ end
+
+ def exit
+ if @error then Kernel.exit(1) else Kernel.exit(0) end
+ end
+
+ def execute(str=nil)
+ send(str || action || 'main')
+ exit
+ end
+
+ def debug(*str)
+ initlogger ; @logger.debug(str)
+ end
+
+ def error(*str)
+ initlogger ; @logger.error(str)
+ end
+
+ def initlogger
+ if @forcenewline then
+ @logger.report
+ @forcenewline = false
+ end
+ end
+
+ def logger
+ @logger
+ end
+
+ def version # just a bit of playing with defs
+ unless @versiondone then
+ report(@banner.join(' - '))
+ @forcenewline = true
+ @versiondone = true
+ end
+ end
+
+ def help
+ version # is nilled when already given
+ @commandline.helpkeys.each do |k|
+ if @commandline.help?(k) then
+ kstr = ('--'+k).ljust(@commandline.helplength+2)
+ message = @commandline.helptext(k)
+ message = '' if message == CommandLine::NOHELP
+ message = message.split(/\s*\n\s*/)
+ loop do
+ report("#{kstr} #{message.shift}")
+ kstr = ' '*kstr.length
+ break if message.length == 0
+ end
+ end
+ end
+ end
+
+ def option(key)
+ @commandline.option(key)
+ end
+ def oneof(*key)
+ @commandline.oneof(*key)
+ end
+
+ def globfiles(pattern='*',suffix=nil)
+ @commandline.setarguments([pattern].flatten)
+ if files = findfiles(suffix) then
+ @commandline.setarguments(files)
+ else
+ @commandline.setarguments
+ end
+ end
+
+ private
+
+ def findfiles(suffix=nil)
+
+ if @commandline.arguments.length>1 then
+ return @commandline.arguments
+ else
+ pattern = @commandline.argument('first')
+ pattern = '*' if pattern.empty?
+ if suffix && ! pattern.match(/\..+$/o) then
+ suffix = '.' + suffix
+ pattern += suffix unless pattern =~ /#{suffix}$/
+ end
+ # not {} safe
+ pattern = '**/' + pattern if @commandline.option('recurse')
+ files = Dir[pattern]
+ if files && files.length>0 then
+ return files
+ else
+ pattern = @commandline.argument('first')
+ if FileTest.file?(pattern) then
+ return [pattern]
+ else
+ report("no files match pattern #{pattern}")
+ return nil
+ end
+ end
+ end
+
+ end
+
+ def globbed(pattern,recurse=false)
+
+ files = Array.new
+ pattern.split(' ').each do |p|
+ if recurse then
+ if p =~ /^(.*)(\/.*?)$/i then
+ p = $1 + '/**' + $2
+ else
+ p = '**/' + p
+ end
+ p.gsub!(/[\\\/]+/, '/')
+ end
+ files.push(Dir.glob(p))
+ end
+ files.flatten.sort do |a,b|
+ pathcompare(a,b)
+ end
+ end
+
+ def pathcompare(a,b)
+
+ aa, bb = a.split('/'), b.split('/')
+ if aa.length == bb.length then
+ aa.each_index do |i|
+ if aa[i]<bb[i] then
+ return -1
+ elsif aa[i]>bb[i] then
+ return +1
+ end
+ end
+ return 0
+ else
+ return aa.length <=> bb.length
+ end
+
+ end
+
+end
+
+class CommandLine
+
+ VALUE, FLAG = 1, 2
+ NOHELP = 'no arguments'
+
+ def initialize(prefix='-')
+
+ @registered = Array.new
+ @options = Hash.new
+ @unchecked = Hash.new
+ @arguments = Array.new
+ @original = ARGV.join(' ')
+ @helptext = Hash.new
+ @mandated = Hash.new
+ @provided = Hash.new
+ @prefix = prefix
+ @actions = Array.new
+
+ # The quotes in --switch="some value" get lost in ARGV, so we need to do some trickery here.
+
+ @original = ''
+ ARGV.each do |a|
+ aa = a.strip.gsub(/^([#{@prefix}]+\w+\=)([^\"].*?\s+.*[^\"])$/) do
+ $1 + "\"" + $2 + "\""
+ end
+ @original += if @original.empty? then '' else ' ' end + aa
+ end
+
+ end
+
+ def setarguments(args=[])
+ @arguments = if args then args else [] end
+ end
+
+ def register(option,shortcut,kind,default=false,action=false,helptext='')
+ if kind == FLAG then
+ @options[option] = default
+ elsif not default then
+ @options[option] = ''
+ else
+ @options[option] = default
+ end
+ @registered.push([option,shortcut,kind])
+ @mandated[option] = false
+ # @provided[option] = false
+ @helptext[option] = helptext
+ @actions.push(option) if action
+ end
+
+ def registerflag(option,default=false,helptext='')
+ if default.class == String then
+ register(option,'',FLAG,false,false,default)
+ else
+ register(option,'',FLAG,false,false,helptext)
+ end
+ end
+
+ def registervalue(option,default='',helptext='')
+ register(option,'',VALUE,default,false,helptext)
+ end
+
+ def registeraction(option,helptext='')
+ register(option,'',FLAG,false,true,helptext)
+ end
+
+ def registermandate(*option)
+ [*option].each do |o|
+ [o].each do |oo|
+ @mandated[oo] = true
+ end
+ end
+ end
+
+ def actions
+ a = @actions.delete_if do |t|
+ ! option(t)
+ end
+ if a && a.length>0 then
+ return a
+ else
+ return nil
+ end
+ end
+
+ def action
+ @actions.each do |t|
+ return t if option(t)
+ end
+ return nil
+ end
+
+ def forgotten
+ @mandated.keys.sort - @provided.keys.sort
+ end
+
+ def registerhelp(option,text='')
+ @helptext['unknown'] = if text.empty? then option else text end
+ end
+
+ def helpkeys(option='.*')
+ @helptext.keys.sort.grep(/#{option}/)
+ end
+
+ def helptext(option)
+ @helptext.fetch(option,'')
+ end
+
+ def help?(option)
+ @helptext[option] && ! @helptext[option].empty?
+ end
+
+ def helplength
+ n = 0
+ @helptext.keys.each do |h|
+ n = h.length if h.length>n
+ end
+ return n
+ end
+
+ def expand
+
+ # todo : '' or false, depending on type
+ # @options.clear
+ # @arguments.clear
+
+ dirtyvalue(@original).split(' ').each do |arg|
+ case arg
+ when /^[#{@prefix}][#{@prefix}](.+?)\=(.*?)$/ then locatedouble($1,$2)
+ when /^[#{@prefix}][#{@prefix}](.+?)$/ then locatedouble($1,false)
+ when /^[#{@prefix}](.)\=(.)$/ then locatesingle($1,$2)
+ when /^[#{@prefix}](.+?)$/ then locateseries($1,false)
+ when /^[\+\-]+/o then # do nothing
+ else
+ arguments.push(arg)
+ end
+ end
+
+ @options or @unchecked or @arguments
+
+ end
+
+ def extend (str)
+ @original = @original + ' ' + str
+ end
+
+ def replace (str)
+ @original = str
+ end
+
+ def show
+ # print "-- options --\n"
+ @options.keys.sort.each do |key|
+ print "option: #{key} -> #{@options[key]}\n"
+ end
+ # print "-- arguments --\n"
+ @arguments.each_index do |key|
+ print "argument: #{key} -> #{@arguments[key]}\n"
+ end
+ end
+
+ def option(str,default=nil)
+ if @options.key?(str) then
+ @options[str]
+ elsif default then
+ default
+ else
+ @options[str]
+ end
+ end
+
+ def checkedoption(str,default='')
+ if @options.key?(str) then
+ if @options[str].empty? then default else @options[str] end
+ else
+ default
+ end
+ end
+
+ def foundoption(str,default='')
+ str = str.split(',') if str.class == String
+ str.each do |s|
+ return str if @options.key?(str)
+ end
+ return default
+ end
+
+ def oneof(*key)
+ [*key].flatten.compact.each do |k|
+ return true if @options.key?(k) && @options[k]
+ end
+ return false
+ end
+
+ def setoption(str,value)
+ @options[str] = value
+ end
+
+ def getoption(str,value='') # value ?
+ @options[str]
+ end
+
+ def argument(n=0)
+ if n.class == String then
+ case n
+ when 'first' then argument(0)
+ when 'second' then argument(1)
+ when 'third' then argument(2)
+ else
+ argument(0)
+ end
+ elsif @arguments[n] then
+ @arguments[n]
+ else
+ ''
+ end
+ end
+
+ # a few local methods, cannot be defined nested (yet)
+
+ private
+
+ def dirtyvalue(value)
+ if value then
+ value.gsub(/([\"\'])(.*?)\1/) do
+ $2.gsub(/\s+/o, "\xFF")
+ end
+ else
+ ''
+ end
+ end
+
+ def cleanvalue(value)
+ if value then
+ # value.sub(/^([\"\'])(.*?)\1$/) { $2.gsub(/\xFF/o, ' ') }
+ value.gsub(/\xFF/o, ' ')
+ else
+ ''
+ end
+ end
+
+ def locatedouble(key, value)
+
+ foundkey, foundkind = nil, nil
+
+ @registered.each do |option, shortcut, kind|
+ if option == key then
+ foundkey, foundkind = option, kind
+ break
+ end
+ end
+ unless foundkey then
+ @registered.each do |option, shortcut, kind|
+ n = 0
+ begin
+ re = /^#{key}/i
+ rescue
+ key = key.inspect.sub(/^\"(.*)\"$/) do $1 end
+ re = /^#{key}/i
+ ensure
+ if option =~ re then
+ case n
+ when 0
+ foundkey, foundkind, n = option, kind, 1
+ when 1
+ # ambiguous matches, like --fix => --fixme --fixyou
+ foundkey, foundkind = nil, nil
+ break
+ end
+ end
+ end
+ end
+ end
+ if foundkey then
+ @provided[foundkey] = true
+ if foundkind == VALUE then
+ @options[foundkey] = cleanvalue(value)
+ else
+ @options[foundkey] = true
+ end
+ else
+ if value.class == FalseClass then
+ @unchecked[key] = true
+ else
+ @unchecked[key] = cleanvalue(value)
+ end
+ end
+
+ end
+
+ def locatesingle(key, value)
+
+ @registered.each do |option, shortcut, kind|
+ if shortcut == key then
+ @provided[option] = true
+ @options[option] = if kind == VALUE then '' else cleanvalue(value) end
+ break
+ end
+ end
+
+ end
+
+ def locateseries(series, value)
+
+ series.each do |key|
+ locatesingle(key,cleanvalue(value))
+ end
+
+ end
+
+ public
+
+ attr_reader :arguments, :options, :original, :unchecked
+
+end
+
+# options = CommandLine.new
+#
+# options.register("filename", "f", CommandLine::VALUE)
+# options.register("request" , "r", CommandLine::VALUE)
+# options.register("verbose" , "v", CommandLine::FLAG)
+#
+# options.expand
+# options.extend(str)
+# options.show
+#
+# c = CommandLine.new
+#
+# c.registervalue('aaaa')
+# c.registervalue('test')
+# c.registervalue('zzzz')
+#
+# c.registerhelp('aaaa','some aaaa to enter')
+# c.registerhelp('test','some text to enter')
+# c.registerhelp('zzzz','some zzzz to enter')
+#
+# c.registermandate('test')
+#
+# c.expand
+#
+# class CommandLine
+#
+# def showhelp (banner,*str)
+# if helpkeys(*str).length>0
+# print banner
+# helpkeys(*str).each do |h|
+# print helptext(h) + "\n"
+# end
+# true
+# else
+# false
+# end
+# end
+#
+# def showmandate(banner)
+# if forgotten.length>0
+# print banner
+# forgotten.each do |f|
+# print helptext(f) + "\n"
+# end
+# true
+# else
+# false
+# end
+# end
+#
+# end
+#
+# c.showhelp("you can provide:\n\n")
+# c.showmandate("you also need to provide:\n\n")