2021-01-03 13:42:00 +01:00
|
|
|
require 'optparse'
|
|
|
|
|
2021-12-07 23:48:28 +01:00
|
|
|
|
2020-12-13 15:54:09 +01:00
|
|
|
class DenCli
|
2021-12-07 23:48:28 +01:00
|
|
|
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
|
|
|
|
|
2020-12-13 15:54:09 +01:00
|
|
|
class UsageError < ::RuntimeError
|
|
|
|
end
|
|
|
|
class UnknownCommand < UsageError
|
|
|
|
end
|
|
|
|
|
2020-12-27 23:00:53 +01:00
|
|
|
require_relative 'dencli/cmd'
|
|
|
|
require_relative 'dencli/sub'
|
|
|
|
require_relative 'dencli/interactive'
|
|
|
|
require_relative 'dencli/version'
|
|
|
|
|
2020-12-13 15:54:09 +01:00
|
|
|
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
|
2021-12-09 13:28:46 +01:00
|
|
|
case min
|
|
|
|
when false then min = cmd.length
|
|
|
|
when nil then min = 1
|
|
|
|
end
|
|
|
|
r = ([min, 1].max - 1).upto cmd.length-2
|
2020-12-13 15:54:09 +01:00
|
|
|
if block_given?
|
|
|
|
r.each {|i| yield cmd[0..i] }
|
2021-12-09 13:28:46 +01:00
|
|
|
yield cmd
|
2020-12-13 15:54:09 +01:00
|
|
|
else
|
2021-12-09 13:28:46 +01:00
|
|
|
r.map {|i| cmd[0..i] } + [cmd]
|
2020-12-13 15:54:09 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
alias g gen_aliases
|
|
|
|
end
|
|
|
|
|
2020-12-27 23:00:53 +01:00
|
|
|
attr_reader :subs
|
2020-12-13 15:54:09 +01:00
|
|
|
|
2021-01-03 13:42:00 +01:00
|
|
|
def initialize progname, description
|
|
|
|
@subs = Sub.new self, progname, description
|
2020-12-13 15:54:09 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def full_cmd
|
|
|
|
[]
|
|
|
|
end
|
|
|
|
|
|
|
|
def _full_cmd post
|
|
|
|
post
|
|
|
|
end
|
|
|
|
|
2021-09-06 18:34:31 +02:00
|
|
|
def sub *a, **o, &exe
|
|
|
|
@subs.sub *a, **o, &exe
|
2020-12-13 15:54:09 +01:00
|
|
|
end
|
|
|
|
|
2021-09-06 18:34:31 +02:00
|
|
|
def cmd *a, **o, &exe
|
|
|
|
@subs.cmd *a, **o, &exe
|
2020-12-13 15:54:09 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def call *a
|
|
|
|
@subs.call *a
|
|
|
|
end
|
|
|
|
|
2021-11-30 23:09:06 +01:00
|
|
|
def usage *args, **opts
|
|
|
|
@subs.usage *args, **opts
|
|
|
|
end
|
|
|
|
|
|
|
|
def help *args, **opts
|
|
|
|
@subs.help *args, **opts
|
|
|
|
end
|
|
|
|
|
|
|
|
def help_full *args, output: nil
|
2021-12-09 13:02:12 +01:00
|
|
|
output ||= $stdout
|
2021-11-30 23:09:06 +01:00
|
|
|
x = @subs.goto *args
|
|
|
|
_help_full output, x
|
|
|
|
end
|
|
|
|
|
|
|
|
def _help_full output, subs
|
|
|
|
Sub._help_commands output, subs.to_enum( :commands)
|
2020-12-13 15:54:09 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
def [] k
|
|
|
|
@subs[k]
|
|
|
|
end
|
2020-12-27 23:00:53 +01:00
|
|
|
|
|
|
|
def interactive *args, **opts
|
|
|
|
Interactive.new self, *args, **opts
|
|
|
|
end
|
2020-12-13 15:54:09 +01:00
|
|
|
end
|