dencli 0.4.0 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/example.rb +19 -8
- data/lib/dencli/cmd.rb +84 -51
- data/lib/dencli/sub.rb +71 -8
- data/lib/dencli/version.rb +1 -1
- data/lib/dencli.rb +23 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b51686dc165e8a0fa5dad00dea71e56a4007be3ad050de0e7a73b3f7587baefa
|
4
|
+
data.tar.gz: 97ce2e6f4bb16974e8b1375133fbcbf8be7b1d4f15491935ebcda55557b3784f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5a98c654de4a78a1dc07c41a8cd2dffcba9d34b57c03b80784b8d652f155d5a53f54370906ec51404c0b6df45a4e387fb8027b5938539780a50e680b9dfbd123
|
7
|
+
data.tar.gz: 3a0e657604254c35e65ae6c501af0c79fd6887b7cb45b8a4ea1693c6fd666eddf04d5e3b060841bf6b0619c35bfdd6af61e98d9598090c9101f4631d993d84ee
|
data/bin/example.rb
CHANGED
@@ -4,16 +4,27 @@ require 'pathname'
|
|
4
4
|
$:.unshift Pathname.new(__FILE__).dirname.dirname.join('lib').to_s
|
5
5
|
require 'dencli'
|
6
6
|
|
7
|
-
cli = DenCli.new
|
8
|
-
cli.cmd( :
|
9
|
-
|
10
|
-
|
11
|
-
cli.cmd( :args, "Expects and prints given arguments", &lambda {|a, b, c:, d:, e:|
|
7
|
+
cli = DenCli.new :example, "This is an example for generate a DenCli-API"
|
8
|
+
cli.cmd( :args, "Expects and prints given arguments",
|
9
|
+
&lambda {|a, b, c:, d:, e:, f:, g:|
|
12
10
|
p a: a, b: b, c: c, d: d, e: e
|
13
11
|
}).
|
14
12
|
opt( :c, '-c=ForC', "Option c").
|
15
|
-
opt( :d, '-
|
16
|
-
opt( :e, '-e', "Toggle e", default: false)
|
13
|
+
opt( :d, '-dForD', "Option d", default: "something").
|
14
|
+
opt( :e, '-e', "Toggle e", default: false).
|
15
|
+
opt( :f, '--[no-]f', "Toggle f", default: false).
|
16
|
+
opt( :g, '--long-option=sth', "Long option, no short option", default: "nothing").
|
17
|
+
opt( :h, '-hsth', "No long option, only short option", default: "nothing")
|
18
|
+
|
19
|
+
cli.cmd( :example, "I have an example command") { STDERR.puts "This is an example" }
|
20
|
+
cli.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*args, full:|
|
21
|
+
if full
|
22
|
+
cli.help_full *args, output: STDERR
|
23
|
+
else
|
24
|
+
cli.help *args, output: STDERR
|
25
|
+
end
|
26
|
+
}).
|
27
|
+
opt( :full, '-f', '--[no-]full', "Print all commands and sub-commands.", default: false)
|
17
28
|
|
18
29
|
cli.sub( :more, "Sub-Commands are also possible with a new cli") do |sub|
|
19
30
|
sub.cmd( :help, "", aliases: [nil, '-h', '--help']) {|*args| STDERR.puts sub.help(*args) }
|
@@ -29,7 +40,7 @@ cli.sub( :more, "Sub-Commands are also possible with a new cli") do |sub|
|
|
29
40
|
opt( :e, '-e', "Toggle e")
|
30
41
|
|
31
42
|
sub.sub( :deeper, "You want to have Sub-Sub-Commands?") do |sub2|
|
32
|
-
sub2.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*args|
|
43
|
+
sub2.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*args| sub2.help( *args, output: STDERR) })
|
33
44
|
sub2.cmd( :last, "The last example", &lambda { STDERR.puts "The last example" })
|
34
45
|
|
35
46
|
sub2.sub( :'sub-commands', "Endless Sub-Sub- ...") do |sub3|
|
data/lib/dencli/cmd.rb
CHANGED
@@ -7,6 +7,12 @@ class DenCli::CMD
|
|
7
7
|
def initialize parent, name, description, exe
|
8
8
|
raise "Proc expected, instead of: #{exe.inspect}" unless Proc === exe
|
9
9
|
@parent, @name, @description, @exe = parent, name, description, lambda( &exe)
|
10
|
+
@parameters = @exe.parameters
|
11
|
+
@arguments_required = @exe.parameters.select {|e| :req == e[0] }.map {|e| e[1] }
|
12
|
+
@arguments_additional = @exe.parameters.select {|e| :opt == e[0] }.map {|e| e[1] }
|
13
|
+
@arguments = @exe.parameters.select {|e| :req == e[0] or :opt == e[0] }.map {|e| e[1] }
|
14
|
+
@options_required = @exe.parameters.select {|e| :keyreq == e[0] }.map {|e| e[1] }
|
15
|
+
@options_additional = @exe.parameters.select {|e| :key == e[0] }.map {|e| e[1] }
|
10
16
|
@options = {}
|
11
17
|
completion {|*a| [] }
|
12
18
|
end
|
@@ -14,19 +20,17 @@ class DenCli::CMD
|
|
14
20
|
def _full_cmd( post) parent._full_cmd [@name]+post end
|
15
21
|
def full_cmd() _full_cmd [] end
|
16
22
|
|
17
|
-
|
18
|
-
|
23
|
+
attr_reader :parameters,
|
24
|
+
:arguments_required, :arguments_additional, :arguments,
|
25
|
+
:options_required, :options_additional
|
19
26
|
alias required arguments_required
|
20
|
-
def arguments_additional() @exe.parameters.select {|e| :opt == e[0] }.map {|e| e[1] } end
|
21
27
|
alias additional arguments_additional
|
22
|
-
def arguments() @exe.parameters.select {|e| :req == e[0] or :opt == e[0] }.map {|e| e[1] } end
|
23
|
-
def options_required() @exe.parameters.select {|e| :keyreq == e[0] }.map {|e| e[1] } end
|
24
|
-
def options_additional() @exe.parameters.select {|e| :key == e[0] }.map {|e| e[1] } end
|
25
28
|
|
26
|
-
def
|
27
|
-
|
29
|
+
def complete *pre, str
|
30
|
+
@completion.call *pre, str
|
31
|
+
end
|
28
32
|
|
29
|
-
def call
|
33
|
+
def call *as
|
30
34
|
os = {}
|
31
35
|
unless @options.empty?
|
32
36
|
# options like --abc | -x will be provided in os
|
@@ -53,25 +57,58 @@ class DenCli::CMD
|
|
53
57
|
end
|
54
58
|
kr = @options.select {|_, o| o.required? and not os.has_key? o.name }
|
55
59
|
unless kr.empty?
|
56
|
-
raise DenCli::UsageError, "Missing argument(s): #{kr.map {|o| o.
|
60
|
+
raise DenCli::UsageError, "Missing argument(s): #{kr.map {|_, o| o.long || o.short }.join ', '}"
|
57
61
|
end
|
58
62
|
end
|
59
63
|
@exe.call *as, **os
|
60
64
|
end
|
61
65
|
|
62
|
-
def usage
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
) : '
|
66
|
+
def usage output: nil
|
67
|
+
output ||= ''
|
68
|
+
_usage output
|
69
|
+
output
|
70
|
+
end
|
71
|
+
|
72
|
+
def _usage output
|
73
|
+
output << full_cmd.join( ' ')
|
74
|
+
@options.each do |_, o|
|
75
|
+
s = "#{o.short||o.long}#{(!o.short && o.val) ? ?= : ''}#{o.val}"
|
76
|
+
output << (o.required? ? " #{s}" : " [#{s}]")
|
77
|
+
end
|
78
|
+
if @exe.lambda?
|
79
|
+
required.each {|s| output << " <#{s}>" }
|
80
|
+
output << " [#{additional.map{|s|"<#{s}>"}.join " "}]" unless additional.empty?
|
81
|
+
else
|
82
|
+
output << ' ...'
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def commands *args
|
87
|
+
yield name, self
|
72
88
|
end
|
73
89
|
|
74
|
-
def
|
90
|
+
def goto *args
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
def help output: nil
|
95
|
+
output ||= ''
|
96
|
+
_help output
|
97
|
+
output
|
98
|
+
end
|
99
|
+
|
100
|
+
def _help output
|
101
|
+
output << "Usage: #{usage}\n#{description}\n"
|
102
|
+
_help_options output
|
103
|
+
end
|
104
|
+
|
105
|
+
def help_options output: nil
|
106
|
+
output ||= ''
|
107
|
+
_help_options output
|
108
|
+
output
|
109
|
+
end
|
110
|
+
|
111
|
+
def _help_options output
|
75
112
|
sc, lc, dc = 0, 0, 0
|
76
113
|
@options.each do |_, o|
|
77
114
|
s = o.short&.length || 0
|
@@ -89,8 +126,8 @@ class DenCli::CMD
|
|
89
126
|
end
|
90
127
|
dc = d if dc < d
|
91
128
|
end
|
92
|
-
format = " %-#{sc}s%s %-#{lc}s %s"
|
93
|
-
@options.map
|
129
|
+
format = " %-#{sc}s%s %-#{lc}s %s\n"
|
130
|
+
@options.map do |_, o|
|
94
131
|
s, l, v, y = o.short, o.long, o.val, ','
|
95
132
|
if l.nil?
|
96
133
|
s += "=#{v}" if v
|
@@ -101,8 +138,8 @@ class DenCli::CMD
|
|
101
138
|
end
|
102
139
|
d = o.desc || ''
|
103
140
|
d += " (#{o.default})" if o.default?
|
104
|
-
format % [ s, y, l, d ]
|
105
|
-
|
141
|
+
output << format % [ s, y, l, d ]
|
142
|
+
end
|
106
143
|
end
|
107
144
|
|
108
145
|
def completion &exe
|
@@ -116,34 +153,29 @@ class DenCli::CMD
|
|
116
153
|
def default?() NilClass != @default end
|
117
154
|
def default() NilClass == @default ? nil : @default end
|
118
155
|
|
119
|
-
def
|
120
|
-
long = short = val = nil
|
156
|
+
def parse_opt_string opt
|
121
157
|
case opt
|
122
|
-
when /\A(
|
123
|
-
long, val = $1,
|
124
|
-
when /\A(--[
|
125
|
-
long, val = $1,
|
126
|
-
when /\A(
|
127
|
-
|
128
|
-
when /\A(-[^=-]
|
129
|
-
short, val = $1,
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
when /\A(--[^=-]+)=(.+)\z/
|
135
|
-
long, val = $1, val || $2
|
136
|
-
when /\A(--[^=-]+)\z/
|
137
|
-
long, val = $1, nil
|
138
|
-
when /\A(-[^=-]+)=(.+)\z/
|
139
|
-
short, val = $1, val || $2
|
140
|
-
when /\A(-[^=-]+)\z/
|
141
|
-
short, val = $1, nil
|
142
|
-
else raise ArgumentError, "Unexpected format for option: #{alt.inspect}"
|
143
|
-
end
|
158
|
+
when /\A(--\[no-\][^=]+)\z/
|
159
|
+
@long, @val = $1, nil
|
160
|
+
when /\A(--[^=]+)=(.+)\z/
|
161
|
+
@long, @val = $1, $2 || @val
|
162
|
+
when /\A(--[^=]+)\z/
|
163
|
+
@long, @val = $1, nil
|
164
|
+
when /\A(-[^=-])=?(.+)\z/
|
165
|
+
@short, @val = $1, $2 || @val
|
166
|
+
when /\A(-[^=-])\z/
|
167
|
+
@short, @val = $1, nil
|
168
|
+
else
|
169
|
+
raise ArgumentError, "Unexpected format for option: #{opt.inspect}"
|
144
170
|
end
|
145
|
-
|
146
|
-
|
171
|
+
end
|
172
|
+
private :parse_opt_string
|
173
|
+
|
174
|
+
def initialize cmd, name, opt, *alts, desc, default: NilClass, **os, &conv
|
175
|
+
@name, @desc, @default, @os, @conv, @val =
|
176
|
+
name.to_s.to_sym, desc, default, os, conv || lambda{|v|v}, nil
|
177
|
+
parse_opt_string opt
|
178
|
+
alts.each &method( :parse_opt_string)
|
147
179
|
@req =
|
148
180
|
if NilClass != default
|
149
181
|
false
|
@@ -155,6 +187,7 @@ class DenCli::CMD
|
|
155
187
|
end
|
156
188
|
|
157
189
|
def on parser, store
|
190
|
+
store[@name] = @default if default?
|
158
191
|
parser.on "#{@short}#{@val ? ?= : ''}#{@val}", "#{@long}#{@val ? ?= : ''}#{@val}", **@os do |val|
|
159
192
|
store[@name] = @conv[val]
|
160
193
|
end
|
data/lib/dencli/sub.rb
CHANGED
@@ -4,6 +4,9 @@ class DenCli::Sub
|
|
4
4
|
attr_reader :parent, :name, :description, :subs, :aliases
|
5
5
|
|
6
6
|
def initialize parent, name, description
|
7
|
+
#DenCli::assert_type self, __method__, :name, name, Symbol
|
8
|
+
#DenCli::assert_type self, __method__, :parent, parent, DenCli, DenCli::Sub
|
9
|
+
#DenCli::assert_type self, __method__, :description, description, String
|
7
10
|
@parent, @name, @description, @subs, @aliases = parent, name, "-> #{description}", {}, {}
|
8
11
|
end
|
9
12
|
|
@@ -15,16 +18,72 @@ class DenCli::Sub
|
|
15
18
|
"#{full_cmd.join ' '} ..."
|
16
19
|
end
|
17
20
|
|
18
|
-
def help n = nil, *a
|
21
|
+
def help n = nil, *a, output: nil
|
22
|
+
output ||= ''
|
23
|
+
_help output, n, *a
|
24
|
+
output
|
25
|
+
end
|
26
|
+
|
27
|
+
def _help output, n = nil, *a
|
19
28
|
if n.nil?
|
20
|
-
|
21
|
-
|
22
|
-
@subs.each do |k, c|
|
23
|
-
r += " % -#{m}s %s\n" % [c.usage, c.description] unless k.nil?
|
24
|
-
end
|
25
|
-
r
|
29
|
+
output << "#{full_cmd.join ' '}: #{description}\n\n"
|
30
|
+
self.class._help_commands output, @subs
|
26
31
|
elsif @aliases.has_key? n
|
27
|
-
@aliases[n].
|
32
|
+
@aliases[n]._help output, *a
|
33
|
+
else
|
34
|
+
raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def commands &exe
|
39
|
+
yield name, self
|
40
|
+
@subs.each {|k, c| c.commands &exe }
|
41
|
+
end
|
42
|
+
|
43
|
+
def help_commands output: nil
|
44
|
+
output ||= ''
|
45
|
+
self.class._help_commands output, subs.map {|_,c| c}
|
46
|
+
output
|
47
|
+
end
|
48
|
+
|
49
|
+
def self._help_commands output, subs
|
50
|
+
m = subs.map {|_name,c| x = c.usage.length; 25 < x ? 0 : x }.max
|
51
|
+
subs.each do |_name, c|
|
52
|
+
if 25 < c.usage.length
|
53
|
+
output << "% -#{m}s\n#{' ' * m} " % [c.usage]
|
54
|
+
else
|
55
|
+
output << "% -#{m}s " % [c.usage]
|
56
|
+
end
|
57
|
+
n = m+2
|
58
|
+
prefix = nil
|
59
|
+
c.description.split /\n/ do |l|
|
60
|
+
c = 0
|
61
|
+
l.split %r< > do |w|
|
62
|
+
if prefix
|
63
|
+
output << prefix
|
64
|
+
prefix = nil
|
65
|
+
end
|
66
|
+
wl = w.length
|
67
|
+
if 75 < c+wl
|
68
|
+
output << "\n#{' ' * n}#{w}"
|
69
|
+
c = n+2+wl
|
70
|
+
else
|
71
|
+
output << " #{w}"
|
72
|
+
c += 1 + wl
|
73
|
+
end
|
74
|
+
end
|
75
|
+
prefix = "\n#{' ' * n}"
|
76
|
+
end
|
77
|
+
output << "\n"
|
78
|
+
end
|
79
|
+
output
|
80
|
+
end
|
81
|
+
|
82
|
+
def goto *a
|
83
|
+
return self if a.empty?
|
84
|
+
n, *a = *a
|
85
|
+
if @aliases.has_key? n
|
86
|
+
@aliases[n].goto *a
|
28
87
|
else
|
29
88
|
raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}"
|
30
89
|
end
|
@@ -40,6 +99,10 @@ class DenCli::Sub
|
|
40
99
|
end
|
41
100
|
|
42
101
|
def _add name, min, obj, aliases
|
102
|
+
#DenCli::assert_type self, __method__, :name, name, Symbol, NilClass
|
103
|
+
#DenCli::assert_type self, __method__, :min, min, Integer, NilClass
|
104
|
+
#DenCli::assert_type self, __method__, :obj, obj, DenCli::Sub, DenCli::CMD
|
105
|
+
#DenCli::assert_type self, __method__, :aliases, aliases, Array, NilClass
|
43
106
|
name = name.to_s unless name.nil?
|
44
107
|
@subs[name] = obj
|
45
108
|
DenCli.gen_aliases( name, min) {|a| @aliases[a] = obj }
|
data/lib/dencli/version.rb
CHANGED
data/lib/dencli.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
require 'optparse'
|
2
2
|
|
3
|
+
|
3
4
|
class DenCli
|
5
|
+
def self.assert_type klass, method, argument_name, object, *types
|
6
|
+
unless types.any? {|type| object.is_a? type }
|
7
|
+
raise ArgumentError, "#{klass.name}.#{method} expects #{types.map( &:to_s).join '|' } for #{argument_name}, not: #{object.inspect}"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
4
11
|
class UsageError < ::RuntimeError
|
5
12
|
end
|
6
13
|
class UnknownCommand < UsageError
|
@@ -80,8 +87,22 @@ class DenCli
|
|
80
87
|
@subs.call *a
|
81
88
|
end
|
82
89
|
|
83
|
-
def
|
84
|
-
@subs.
|
90
|
+
def usage *args, **opts
|
91
|
+
@subs.usage *args, **opts
|
92
|
+
end
|
93
|
+
|
94
|
+
def help *args, **opts
|
95
|
+
@subs.help *args, **opts
|
96
|
+
end
|
97
|
+
|
98
|
+
def help_full *args, output: nil
|
99
|
+
output ||= STDOUT
|
100
|
+
x = @subs.goto *args
|
101
|
+
_help_full output, x
|
102
|
+
end
|
103
|
+
|
104
|
+
def _help_full output, subs
|
105
|
+
Sub._help_commands output, subs.to_enum( :commands)
|
85
106
|
end
|
86
107
|
|
87
108
|
def [] k
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dencli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Denis Knauf
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|