dencli/lib/dencli/cmd.rb

81 lines
2.1 KiB
Ruby

require_relative '../dencli'
class DenCli::CMD
attr_reader :parent, :name, :description, :exe, :completion, :options
def initialize parent, name, description, exe
raise "Proc expected, instead of: #{exe.inspect}" unless Proc === exe
@parent, @name, @description, @exe = parent, name, description, lambda( &exe)
@options = []
completion {|*a| [] }
end
def _full_cmd( post) parent._full_cmd [@name]+post end
def full_cmd() _full_cmd [] end
def parameters() @exe.parameters end
def required() @exe.parameters.select{|e|:req == e[0]}.map{|e|e[1]} end
def additional() @exe.parameters.select{|e|:opt == e[0]}.map{|e|e[1]} end
def call( *as)
if @options.empty?
@exe.call *as
else
os = {}
options = OptionParser.new
options.banner = "#{full_cmd.join ' '}"
@options.each do |(aname, aas, aos, aexe)|
os[aname] = aos[aname] if aos.has_key? :default
options.on( *aas) {|val| os[aname] = aexe[val] }
end
as = options.parse! as
if @exe.lambda?
pars = required
if as.length < pars.length
raise DenCli::UsageError, "Missing parameter(s): #{pars[as.length..-1].join " "}"
end
if parameters.select{|e|:rest == e[0]}.empty?
pars = pars + additional
if as.length > pars.length
raise DenCli::UsageError, "Unused parameter(s): #{as[-pars.length..-1].shelljoin}"
end
end
end
@exe.call *as, **os
end
end
def usage
"#{parent.full_cmd.join ' '} #{name} "+
@options.map{|(_,(o,_,_,_),_)|"[#{o}] "}.join( '')+
(@exe.lambda? ? (
required.join( " ")+
(additional.empty? ? "" : " [#{additional.join " "}]")
) : '...')
end
def help
"#{usage}\n#{description}"
end
def complete( *pre, str) @completion.call *pre, str end
def completion &exe
@completion = exe
self
end
def opt name, *as, **os, &exe
@options.push [name.to_s.to_sym, as, os, exe || lambda{|val|val} ]
self
end
def inspect
"#<%s:0x%x %s @name=%p @description=%p @parent=<%s:0x%x %s> @exe=<arity=%d>>" % [
self.class.name, self.object_id, self.full_cmd,
@name, @description, @parent.class.name, @parent.class.object_id, @parent.full_cmd,
@exe.arity
]
end
end