dencli/lib/dencli.rb

120 lines
2.5 KiB
Ruby
Executable File

require 'optparse'
class DenCli
def self.assert_type klass, method, argument_name, object, *types
unless types.any? {|type| object.is_a? type }
raise ArgumentError, "#{klass.name}.#{method} expects #{types.map( &:to_s).join '|' } for #{argument_name}, not: #{object.inspect}"
end
end
class UsageError < ::RuntimeError
end
class UnknownCommand < UsageError
end
require_relative 'dencli/cmd'
require_relative 'dencli/sub'
require_relative 'dencli/interactive'
require_relative 'dencli/version'
class <<self
# Helper Function for generate Regular Expressions of string,
# which matches all strings which has parts fron beginning of the given string.
# `n("abc")` would produce: `/(?:a|ab|abc)/`
# You can define a minimum length to match:
# `n("abcdef",4)` => `/abcd(?:|e|ef)/`
def n s, min = nil
min ||= 1
/#{s.length <= min ?
Regexp.quote(s) :
"#{Regexp.quote s[0...min]}#{
s[min...-1].
reverse.
each_char.
reduce( "#{Regexp.quote s[-1]}?") {|f,n|
"(?:#{Regexp.quote n}#{f})?"
}
}"
}/
end
# Wraps `n(s,min=)` in a full matching RegExp with ending `\0`:
# `r("abc")` would produce: `/\A(?:a|ab|abc)\0\z/`
# You can define a minimum length to match:
# `r("abcdef",4)` => `/\aabcd(?:|e|ef)\0\z/`
def r s, min = nil
/\A#{n s, min}\0\z/
end
# Generates a list of aliases for given `cmd`:
# `g(:abc)` => `["a", "ab", "abc"]`
# `g(:abcdef, 4)` => `["abcd", "abcde", "abcdef"]`
def gen_aliases cmd, min = nil
case min
when false then min = cmd.length
when nil then min = 1
end
r = ([min, 1].max - 1).upto cmd.length-2
if block_given?
r.each {|i| yield cmd[0..i] }
yield cmd
else
r.map {|i| cmd[0..i] } + [cmd]
end
end
alias g gen_aliases
end
attr_reader :subs
def initialize progname, description
@subs = Sub.new self, progname, description
end
def full_cmd
[]
end
def _full_cmd post
post
end
def []( k) @subs[k] end
def has?( k) @subs.has? k end
def sub *a, **o, &exe
@subs.sub *a, **o, &exe
end
def cmd *a, **o, &exe
@subs.cmd *a, **o, &exe
end
def call *a
@subs.call *a
end
def usage *args, **opts
@subs.usage *args, **opts
end
def help *args, **opts
@subs.help *args, **opts
end
def help_full *args, output: nil
output ||= $stdout
x = @subs.goto *args
_help_full output, x
end
def _help_full output, subs
Sub._help_commands output, subs.to_enum( :commands)
end
def interactive *args, **opts
Interactive.new self, *args, **opts
end
end