require_relative '../dencli' class DenCli::Sub attr_reader :parent, :name, :description, :subs, :aliases def initialize parent, name, description @parent, @name, @description, @subs, @aliases = parent, name, "-> #{description}", {}, {} end def _full_cmd( post) parent._full_cmd [@name]+post end def full_cmd() _full_cmd [] end def []( k) @aliases[k] end def usage "#{full_cmd.join ' '} ..." end def help n = nil, *a, output: nil output ||= '' _help output, n, *a output end def _help output, n = nil, *a if n.nil? output << "#{full_cmd.join ' '}: #{description}\n\n" self.class._help_commands output, @subs elsif @aliases.has_key? n @aliases[n]._help output, *a else raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}" end end def commands &exe yield self @subs.each {|k, c| c.commands &exe } end def help_commands output: nil output ||= '' self.class._help_commands output, subs.map {|_,c| c} output end def self._help_commands output, subs m = subs.map {|c| x = c.usage.length; 25 < x ? 0 : x }.max subs.each do |c| if 25 < c.usage.length output << "% -#{m}s\n#{' ' * m} " % [c.usage] else output << "% -#{m}s " % [c.usage] end n = m+2 prefix = nil c.description.split /\n/ do |l| c = 0 l.split %r< > do |w| if prefix output << prefix prefix = nil end wl = w.length if 75 < c+wl output << "\n#{' ' * n}#{w}" c = n+2+wl else output << " #{w}" c += 1 + wl end end prefix = "\n#{' ' * n}" end output << "\n" end output end def goto *a return self if a.empty? n, *a = *a if @aliases.has_key? n @aliases[n].goto *a else raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}" end end def call *a n, *a = *a if @aliases.has_key? n @aliases[n].call *a else raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}" end end def _add name, min, obj, aliases name = name.to_s unless name.nil? @subs[name] = obj DenCli.gen_aliases( name, min) {|a| @aliases[a] = obj } if aliases [*aliases].each {|a| @aliases[a] = obj } end obj end private :_add def sub name, description, min: nil, aliases: nil, &exe r = _add name, min, DenCli::Sub.new( self, name, description), aliases block_given? ? yield( r) : r end def cmd name, description, min: nil, aliases: nil, &exe _add name, min, DenCli::CMD.new( self, name, description, exe), aliases end def complete *pre, str if pre.empty? @subs.keys.grep /\A#{Regexp.escape str}/ elsif sub = @subs[pre[0]] sub.complete *pre[1..-1], str else STDOUT.print "\a" end end def inspect "#<%s:0x%x %s @name=%p @description=%p @subs={%s} @aliases={%s} @parent=<%s:0x%x %s>>" % [ self.class.name, self.object_id, self.full_cmd, @name, @description, @subs.keys.join(', '), @aliases.keys.join(', '), @parent.class.name, @parent.class.object_id, @parent.full_cmd ] end end