From fa5fbf8f6f70b338d5b99080af7558ba1407796d Mon Sep 17 00:00:00 2001 From: Denis Knauf Date: Sun, 3 Jan 2021 16:28:12 +0100 Subject: [PATCH] options instead of arguments. arguments checking against arity if lambda. help improved. --- lib/dencli/cmd.rb | 45 +++++++++++++++++++++++++++++++++++++-------- lib/dencli/sub.rb | 8 ++++++-- 2 files changed, 43 insertions(+), 10 deletions(-) diff --git a/lib/dencli/cmd.rb b/lib/dencli/cmd.rb index de0cf59..8d4dfd6 100644 --- a/lib/dencli/cmd.rb +++ b/lib/dencli/cmd.rb @@ -1,33 +1,62 @@ require_relative '../dencli' class DenCli::CMD - attr_reader :parent, :name, :description, :exe, :completion, :arguments + 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, exe - @arguments = [] + @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 @arguments.empty? + if @options.empty? @exe.call *as else os = {} options = OptionParser.new options.banner = "#{full_cmd.join ' '}" - @arguments.each do |(aname, aas, aos, aexe)| + @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 help() "#{parent.full_cmd.join ' '} #{name}\n#{description}" 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 @@ -36,8 +65,8 @@ class DenCli::CMD self end - def arg name, *as, **os, &exe - @arguments.push [name.to_s.to_sym, as, os, exe || lambda{|*a|a} ] + def opt name, *as, **os, &exe + @options.push [name.to_s.to_sym, as, os, exe || lambda{|val|val} ] self end diff --git a/lib/dencli/sub.rb b/lib/dencli/sub.rb index 0d06fea..5622d69 100644 --- a/lib/dencli/sub.rb +++ b/lib/dencli/sub.rb @@ -11,12 +11,16 @@ class DenCli::Sub def full_cmd() _full_cmd [] end def []( k) @aliases[k] end + def usage + "#{full_cmd.join ' '} ..." + end + def help n = nil, *a if n.nil? r = "#{full_cmd.join ' '}: #{description}\n\n" - m = @subs.map {|k,_| k.length }.max + m = @subs.map {|k,c| k.nil? ? 0 : c.usage.length }.max @subs.each do |k, c| - r += " % -#{m}s %s\n" % [k, c.description] unless k.nil? + r += " % -#{m}s %s\n" % [c.usage, c.description] unless k.nil? end r elsif @aliases.has_key? n