dencli 0.5.1 → 0.5.5
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 +216 -18
- data/lib/dencli/cmd.rb +45 -27
- data/lib/dencli/interactive.rb +1 -1
- data/lib/dencli/sub.rb +60 -35
- data/lib/dencli/version.rb +1 -1
- data/lib/dencli.rb +8 -3
- 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: b4f8e9d3af41176bba078797a33ed1116dee0d1bbdfdce64b4662ba084c0630e
|
4
|
+
data.tar.gz: 38c29fe476f8c31af57706a915fb5503a9f0ef3f81aab74675206980013bbd6a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a028b051a9ae055280811ba2dbe61f7e4c1ed9452cc015c4dea75f429ffa4ff768baaf0373aee46fa316563840fbd2abe450a7437647555dc117e2beabcd740b
|
7
|
+
data.tar.gz: 2dee7a4e46e861dec67df330db80789ba9dcb2ea05f7274853e8963235ee52a3e04572be72c2ed1c33351e9cae6a87ad809cfd32bd48fd6ec393b99a5e0ba7b5
|
data/bin/example.rb
CHANGED
@@ -1,34 +1,232 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'pathname'
|
4
|
-
|
5
|
-
require '
|
4
|
+
require 'shellwords'
|
5
|
+
require 'stringio'
|
6
|
+
require 'ipaddr'
|
7
|
+
require_relative '../lib/dencli'
|
6
8
|
|
7
9
|
cli = DenCli.new :example, "This is an example for generate a DenCli-API"
|
10
|
+
|
11
|
+
class Capture
|
12
|
+
def initialize cli, verbose:
|
13
|
+
@cli, @counter, @verbose = cli, 0, verbose
|
14
|
+
end
|
15
|
+
|
16
|
+
def capture
|
17
|
+
@args = NilClass
|
18
|
+
@counter += 1
|
19
|
+
stdout, stderr = $stdout, $stderr
|
20
|
+
$stdout = $stderr = StringIO.new
|
21
|
+
begin
|
22
|
+
yield stdout, stderr
|
23
|
+
ensure
|
24
|
+
$stderr, $stdout = stderr, stdout
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def args= args
|
29
|
+
@args = args
|
30
|
+
end
|
31
|
+
|
32
|
+
def logstart command
|
33
|
+
STDERR.printf "[% 4d] \e[1;35m? \e[0m %s tests %s\r", @counter, $0.shellescape, command.shelljoin
|
34
|
+
end
|
35
|
+
|
36
|
+
def logok info, command
|
37
|
+
STDERR.printf "[% 4d] \e[1;32mok\e[0m %s | %s tests %s\e[J\n", @counter, info, $0.shellescape, command.shelljoin
|
38
|
+
end
|
39
|
+
|
40
|
+
def logfail command
|
41
|
+
STDERR.printf "[% 4d] \e[1;31mer\e[0m %s tests %s\e[J\n", @counter, $0.shellescape, command.shelljoin
|
42
|
+
end
|
43
|
+
|
44
|
+
def logexception prefix, exception
|
45
|
+
loginfo "#{prefix} (#{exception.class.name}) #{exception}"
|
46
|
+
exception.backtrace[0...-Kernel.caller.length].each {|l| loginfo " #{l}" }
|
47
|
+
end
|
48
|
+
|
49
|
+
def loginfo text
|
50
|
+
STDERR.printf " %s\n", text
|
51
|
+
end
|
52
|
+
|
53
|
+
def should_ok expect, *command
|
54
|
+
logstart command
|
55
|
+
$capture.capture { @cli.call 'tests', *command }
|
56
|
+
if expect === @args
|
57
|
+
logok @args, command
|
58
|
+
else
|
59
|
+
logfail command
|
60
|
+
loginfo "expected args: #{expect.inspect}"
|
61
|
+
loginfo "given args: #{@args.inspect}"
|
62
|
+
STDERR.puts
|
63
|
+
end
|
64
|
+
rescue SystemExit
|
65
|
+
if 0 == $!.status
|
66
|
+
logok @args, command
|
67
|
+
else
|
68
|
+
logfail command
|
69
|
+
end
|
70
|
+
rescue Object
|
71
|
+
logfail command
|
72
|
+
logexception "unexpected raise:", $!
|
73
|
+
STDERR.puts
|
74
|
+
end
|
75
|
+
|
76
|
+
def should_fail exception, message, *command
|
77
|
+
logstart command
|
78
|
+
$capture.capture { @cli.call 'tests', *command }
|
79
|
+
logfail command
|
80
|
+
rescue exception
|
81
|
+
if message === $!.message
|
82
|
+
logok exception, command
|
83
|
+
if @verbose
|
84
|
+
logexception "raised:", $!
|
85
|
+
STDERR.puts
|
86
|
+
end
|
87
|
+
else
|
88
|
+
logexception "unexpected message:", $!
|
89
|
+
STDERR.puts
|
90
|
+
end
|
91
|
+
rescue Object
|
92
|
+
logfail command
|
93
|
+
logexception "unexpected raised:", $!
|
94
|
+
STDERR.puts
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
cli.sub :tests, "Some tests", noshortaliases: true do |tcli|
|
99
|
+
OptionParser.accept IPAddr do |arg|
|
100
|
+
begin
|
101
|
+
IPAddr.new arg
|
102
|
+
rescue IPAddr::InvalidAddressError
|
103
|
+
raise OptionParser::InvalidArgument, "#{$!.message}: #{arg}"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
tcli.cmd( :'-', "No arguments no options expected", &lambda {|| $capture.args = [] })
|
108
|
+
tcli.cmd( :'arg', "", &lambda {|one| $capture.args = [one] })
|
109
|
+
tcli.cmd( :'oar', "", &lambda {|one=nil| $capture.args = [one] })
|
110
|
+
tcli.cmd( :'arg-arg', "", &lambda {|one, two| $capture.args = [one, two] })
|
111
|
+
tcli.cmd( :'oar-oar', "", &lambda {|one=nil, two=nil| $capture.args = [one, two] })
|
112
|
+
tcli.cmd( :'arg-oar', "expected", &lambda {|one, two=nil| $capture.args = [one, two] })
|
113
|
+
tcli.cmd( :'oar-arg', "expected", &lambda {|one=nil, two| $capture.args = [one, two] })
|
114
|
+
tcli.cmd( :'bool', '', &lambda {|a:| $capture.args = [a] }).opt(:a, '-a', '')
|
115
|
+
tcli.cmd( :'optbool', '', &lambda {|a: nil| $capture.args = [a] }).opt(:a, '-a', '')
|
116
|
+
tcli.cmd( :'defbool', '', &lambda {|a:| $capture.args = [a] }).opt(:a, '-a', '', default: 'default')
|
117
|
+
tcli.cmd( :'str', '', &lambda {|a:| $capture.args = [a] }).opt(:a, '-a=STR', '')
|
118
|
+
tcli.cmd( :'lstr', '', &lambda {|a:| $capture.args = [a] }).opt(:a, '--astr=STR', '')
|
119
|
+
tcli.cmd( :'bstr', '', &lambda {|a:| $capture.args = [a] }).opt(:a, '-a', '--astr=STR', '')
|
120
|
+
tcli.cmd( :'ipaddr', '', &lambda {|a:| $capture&.args = [a] }).opt(:a, '-a', '--addr=ADDR', IPAddr, '')
|
121
|
+
|
122
|
+
tcli.cmd( :run, "Run all tests") do |verbose:|
|
123
|
+
$capture = Capture.new cli, verbose: verbose
|
124
|
+
|
125
|
+
$capture.should_fail DenCli::UnknownCommand, //, 'unknown-command'
|
126
|
+
|
127
|
+
$capture.should_ok [], '-'
|
128
|
+
$capture.should_fail DenCli::UsageError, //, '-', 'unexpected'
|
129
|
+
|
130
|
+
$capture.should_ok %w[first], 'arg', 'first'
|
131
|
+
$capture.should_fail DenCli::UsageError, //, 'arg'
|
132
|
+
$capture.should_fail DenCli::UsageError, //, 'arg', 'first', 'unexpected'
|
133
|
+
|
134
|
+
$capture.should_ok %w[first], 'oar', 'first'
|
135
|
+
$capture.should_ok [nil], 'oar'
|
136
|
+
$capture.should_fail DenCli::UsageError, //, 'oar', 'first', 'unexpected'
|
137
|
+
|
138
|
+
$capture.should_ok %w[first two], 'oar-oar', 'first', 'two'
|
139
|
+
$capture.should_ok ['first', nil], 'oar-oar', 'first'
|
140
|
+
$capture.should_ok [nil,nil], 'oar-oar'
|
141
|
+
$capture.should_fail DenCli::UsageError, //, 'oar-oar', 'first', 'two', 'unexpected'
|
142
|
+
|
143
|
+
$capture.should_ok %w[first two], 'arg-oar', 'first', 'two'
|
144
|
+
$capture.should_ok ['first', nil], 'arg-oar', 'first'
|
145
|
+
$capture.should_fail DenCli::UsageError, //, 'arg-oar'
|
146
|
+
|
147
|
+
$capture.should_ok [nil, 'first'], 'oar-arg', 'first'
|
148
|
+
$capture.should_ok ['first', 'second'], 'oar-arg', 'first', 'second'
|
149
|
+
$capture.should_fail DenCli::UsageError, //, 'oar-arg'
|
150
|
+
$capture.should_fail DenCli::UsageError, //, 'oar-arg', 'first', 'two', 'unexpected'
|
151
|
+
|
152
|
+
$capture.should_ok [true], 'bool', '-a'
|
153
|
+
$capture.should_fail DenCli::UsageError, //, 'bool'
|
154
|
+
$capture.should_fail DenCli::UsageError, //, 'bool', '-a', 'unexpected'
|
155
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'bool', '-b'
|
156
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'bool', '--unexpected'
|
157
|
+
$capture.should_fail DenCli::UsageError, //, 'bool', 'unexpected'
|
158
|
+
|
159
|
+
$capture.should_ok [true], 'optbool', '-a'
|
160
|
+
$capture.should_ok [nil], 'optbool'
|
161
|
+
$capture.should_fail DenCli::UsageError, //, 'optbool', '-a', 'unexpected'
|
162
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'optbool', '-b'
|
163
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'optbool', '--unexpected'
|
164
|
+
$capture.should_fail DenCli::UsageError, //, 'optbool', 'unexpected'
|
165
|
+
|
166
|
+
$capture.should_ok [true], 'defbool', '-a'
|
167
|
+
$capture.should_ok ['default'], 'defbool'
|
168
|
+
$capture.should_fail DenCli::UsageError, //, 'defbool', '-a', 'unexpected'
|
169
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'defbool', '-b'
|
170
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'defbool', '--unexpected'
|
171
|
+
$capture.should_fail DenCli::UsageError, //, 'defbool', 'unexpected'
|
172
|
+
|
173
|
+
$capture.should_ok %w[first], 'str', '-a', 'first'
|
174
|
+
$capture.should_ok %w[first], 'str', '-afirst'
|
175
|
+
$capture.should_fail OptionParser::MissingArgument, //, 'str', '-a'
|
176
|
+
$capture.should_fail DenCli::UsageError, //, 'str'
|
177
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'str', '-b'
|
178
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'str', '--unexpected'
|
179
|
+
$capture.should_fail DenCli::UsageError, //, 'str', 'unexpected'
|
180
|
+
|
181
|
+
$capture.should_ok %w[first], 'lstr', '--astr', 'first'
|
182
|
+
$capture.should_ok %w[first], 'lstr', '--astr=first'
|
183
|
+
$capture.should_fail OptionParser::MissingArgument, //, 'lstr', '--astr'
|
184
|
+
$capture.should_fail DenCli::UsageError, //, 'lstr'
|
185
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'lstr', '-b'
|
186
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'lstr', '--unexpected'
|
187
|
+
$capture.should_fail DenCli::UsageError, //, 'lstr', 'unexpected'
|
188
|
+
|
189
|
+
$capture.should_ok %w[first], 'bstr', '-a', 'first'
|
190
|
+
$capture.should_ok %w[first], 'bstr', '-afirst'
|
191
|
+
$capture.should_ok %w[first], 'bstr', '--astr', 'first'
|
192
|
+
$capture.should_ok %w[first], 'bstr', '--astr=first'
|
193
|
+
$capture.should_fail OptionParser::MissingArgument, //, 'bstr', '--astr'
|
194
|
+
$capture.should_fail OptionParser::MissingArgument, //, 'bstr', '-a'
|
195
|
+
$capture.should_fail DenCli::UsageError, //, 'bstr'
|
196
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'bstr', '-b'
|
197
|
+
$capture.should_fail OptionParser::InvalidOption, //, 'bstr', '--unexpected'
|
198
|
+
$capture.should_fail DenCli::UsageError, //, 'bstr', 'unexpected'
|
199
|
+
|
200
|
+
$capture.should_ok [IPAddr.new('1.2.3.4')], 'ipaddr', '-a', '1.2.3.4'
|
201
|
+
$capture.should_fail OptionParser::InvalidArgument, /invalid address/, 'ipaddr', '-a', '1.2.3.400'
|
202
|
+
end.opt( :verbose, '-v', 'Prints additional information per test', default: false)
|
203
|
+
end
|
204
|
+
|
8
205
|
cli.cmd( :args, "Expects and prints given arguments",
|
9
|
-
&lambda {|a, b, c:, d:, e:|
|
206
|
+
&lambda {|a, b, c:, d:, e:, f:, g:|
|
10
207
|
p a: a, b: b, c: c, d: d, e: e
|
11
208
|
}).
|
12
209
|
opt( :c, '-c=ForC', "Option c").
|
13
|
-
opt( :d, '-
|
210
|
+
opt( :d, '-dForD', "Option d", default: "something").
|
14
211
|
opt( :e, '-e', "Toggle e", default: false).
|
15
|
-
opt( :f, '--[no-]f', "Toggle f", default: false)
|
212
|
+
opt( :f, '--[no-]f', "Toggle f", default: false).
|
213
|
+
opt( :g, '--long-option=sth', "Long option, no short option", default: "nothing").
|
214
|
+
opt( :h, '-hsth', "No long option, only short option", default: "nothing")
|
16
215
|
|
17
|
-
cli.cmd( :example, "I have an example command") {
|
18
|
-
cli.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*
|
216
|
+
cli.cmd( :example, "I have an example command") { $stderr.puts "This is an example" }
|
217
|
+
cli.cmd( :help, "An example for help", aliases: [nil, '-h', '--help'], &lambda {|*commands, full:|
|
19
218
|
if full
|
20
|
-
cli.help_full *
|
219
|
+
cli.help_full *commands, output: $stderr
|
21
220
|
else
|
22
|
-
cli.help *
|
221
|
+
cli.help *commands, output: $stderr
|
23
222
|
end
|
24
223
|
}).
|
25
224
|
opt( :full, '-f', '--[no-]full', "Print all commands and sub-commands.", default: false)
|
26
225
|
|
27
226
|
cli.sub( :more, "Sub-Commands are also possible with a new cli") do |sub|
|
28
|
-
sub.cmd( :help, "", aliases: [nil, '-h', '--help']) {|*args|
|
29
|
-
sub.cmd( :
|
30
|
-
sub.cmd( :
|
31
|
-
sub.cmd( :foo, "BAR") { STDERR.puts "FOO bar"}
|
227
|
+
sub.cmd( :help, "", aliases: [nil, '-h', '--help']) {|*args| $stderr.puts sub.help(*args) }
|
228
|
+
sub.cmd( :example, "Here is an example, too") { $stderr.puts "This is an other example" }
|
229
|
+
sub.cmd( :foo, "BAR") { $stderr.puts "FOO bar"}
|
32
230
|
|
33
231
|
sub.cmd( :args, "Expects and prints given arguments", &lambda {|a, b=1, c:, d: 5, e:|
|
34
232
|
p a: a, b: b, c: c, d: d, e: e
|
@@ -38,12 +236,12 @@ cli.sub( :more, "Sub-Commands are also possible with a new cli") do |sub|
|
|
38
236
|
opt( :e, '-e', "Toggle e")
|
39
237
|
|
40
238
|
sub.sub( :deeper, "You want to have Sub-Sub-Commands?") do |sub2|
|
41
|
-
sub2.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*
|
42
|
-
sub2.cmd( :last, "The last example", &lambda {
|
239
|
+
sub2.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*commands| sub2.help( *commands, output: $stderr) })
|
240
|
+
sub2.cmd( :last, "The last example", &lambda { $stderr.puts "The last example" })
|
43
241
|
|
44
242
|
sub2.sub( :'sub-commands', "Endless Sub-Sub- ...") do |sub3|
|
45
|
-
sub3.cmd( :help, "") {|*args|
|
46
|
-
sub3.cmd( :hehe, "The real last example", min: 2) {
|
243
|
+
sub3.cmd( :help, "") {|*args| $stderr.puts sub3.help( sub3, *args) }
|
244
|
+
sub3.cmd( :hehe, "The real last example", min: 2) { $stderr.puts "Trust me!" }
|
47
245
|
end
|
48
246
|
end
|
49
247
|
end
|
@@ -51,6 +249,6 @@ end
|
|
51
249
|
begin
|
52
250
|
cli.call *ARGV
|
53
251
|
rescue DenCli::UsageError
|
54
|
-
|
252
|
+
$stderr.puts $!
|
55
253
|
exit 1
|
56
254
|
end
|
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,14 +20,11 @@ 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
29
|
def complete *pre, str
|
27
30
|
@completion.call *pre, str
|
@@ -54,10 +57,14 @@ class DenCli::CMD
|
|
54
57
|
end
|
55
58
|
kr = @options.select {|_, o| o.required? and not os.has_key? o.name }
|
56
59
|
unless kr.empty?
|
57
|
-
raise DenCli::UsageError, "Missing argument(s): #{kr.map {|o| o.long || o.short }.join ', '}"
|
60
|
+
raise DenCli::UsageError, "Missing argument(s): #{kr.map {|_, o| o.long || o.short }.join ', '}"
|
58
61
|
end
|
59
62
|
end
|
60
|
-
|
63
|
+
if os.empty?
|
64
|
+
@exe.call *as
|
65
|
+
else
|
66
|
+
@exe.call *as, **os
|
67
|
+
end
|
61
68
|
end
|
62
69
|
|
63
70
|
def usage output: nil
|
@@ -69,14 +76,22 @@ class DenCli::CMD
|
|
69
76
|
def _usage output
|
70
77
|
output << full_cmd.join( ' ')
|
71
78
|
@options.each do |_, o|
|
72
|
-
s = "#{o.short||o.long}#{o.val ? ?= : ''}#{o.val}"
|
79
|
+
s = "#{o.short||o.long}#{(!o.short && o.val) ? ?= : ''}#{o.val}"
|
73
80
|
output << (o.required? ? " #{s}" : " [#{s}]")
|
74
81
|
end
|
75
82
|
if @exe.lambda?
|
76
|
-
|
77
|
-
|
83
|
+
parameters.each do |(type, name)|
|
84
|
+
case type
|
85
|
+
when :req
|
86
|
+
output << " <#{name}>"
|
87
|
+
when :opt
|
88
|
+
output << " [<#{name}>]"
|
89
|
+
when :rest
|
90
|
+
output << " [<#{name}> ...]"
|
91
|
+
end
|
92
|
+
end
|
78
93
|
else
|
79
|
-
output << ' ...'
|
94
|
+
output << ' [...]'
|
80
95
|
end
|
81
96
|
end
|
82
97
|
|
@@ -127,7 +142,7 @@ class DenCli::CMD
|
|
127
142
|
@options.map do |_, o|
|
128
143
|
s, l, v, y = o.short, o.long, o.val, ','
|
129
144
|
if l.nil?
|
130
|
-
s += "
|
145
|
+
s += "#{v}" if v
|
131
146
|
y = ' '
|
132
147
|
elsif s.nil?
|
133
148
|
l += "=#{v}" if v
|
@@ -145,7 +160,7 @@ class DenCli::CMD
|
|
145
160
|
end
|
146
161
|
|
147
162
|
class Opt
|
148
|
-
attr_reader :name, :long, :short, :
|
163
|
+
attr_reader :name, :long, :short, :type, :val, :desc, :conv, :req
|
149
164
|
def required?() @req end
|
150
165
|
def default?() NilClass != @default end
|
151
166
|
def default() NilClass == @default ? nil : @default end
|
@@ -158,9 +173,9 @@ class DenCli::CMD
|
|
158
173
|
@long, @val = $1, $2 || @val
|
159
174
|
when /\A(--[^=]+)\z/
|
160
175
|
@long, @val = $1, nil
|
161
|
-
when /\A(-[^=-]
|
176
|
+
when /\A(-[^=-])=?(.+)\z/
|
162
177
|
@short, @val = $1, $2 || @val
|
163
|
-
when /\A(-[^=-]
|
178
|
+
when /\A(-[^=-])\z/
|
164
179
|
@short, @val = $1, nil
|
165
180
|
else
|
166
181
|
raise ArgumentError, "Unexpected format for option: #{opt.inspect}"
|
@@ -168,11 +183,12 @@ class DenCli::CMD
|
|
168
183
|
end
|
169
184
|
private :parse_opt_string
|
170
185
|
|
171
|
-
def initialize cmd, name, opt, *
|
172
|
-
@name, @desc, @default, @
|
173
|
-
name.to_s.to_sym, desc, default,
|
186
|
+
def initialize cmd, name, opt, *args, desc, default: NilClass, &conv
|
187
|
+
@name, @desc, @default, @conv, @val, @type =
|
188
|
+
name.to_s.to_sym, desc, default, conv || lambda{|v|v}, nil, nil
|
174
189
|
parse_opt_string opt
|
175
|
-
|
190
|
+
@type = args.pop if OptionParser.top.atype.has_key? args.last
|
191
|
+
args.each &method( :parse_opt_string)
|
176
192
|
@req =
|
177
193
|
if NilClass != default
|
178
194
|
false
|
@@ -185,30 +201,32 @@ class DenCli::CMD
|
|
185
201
|
|
186
202
|
def on parser, store
|
187
203
|
store[@name] = @default if default?
|
188
|
-
|
204
|
+
short = "#{@short}#{@val ? ?= : ''}#{@val}"
|
205
|
+
long = "#{@long}#{@val ? ?= : ''}#{@val}"
|
206
|
+
parser.on short, long, *[@type].compact do |val|
|
189
207
|
store[@name] = @conv[val]
|
190
208
|
end
|
191
209
|
end
|
192
210
|
|
193
211
|
def inspect
|
194
|
-
"#<%s:0x%
|
212
|
+
"#<%s:0x%x %s %s %s %s (%p) %p conv=%s>" % [
|
195
213
|
self.class.name, object_id, @req ? "<#{@name}>" : "[#{@name}]",
|
196
|
-
@short, @long, @val, @default, @desc, @
|
214
|
+
@short, @long, @val, @default, @desc, @type ? " type=#{type}" : '',
|
197
215
|
@exe ? "<#{@exe.lambda? ? :lambda: :proc} ##{@exe.arity}>" : "nil"
|
198
216
|
]
|
199
217
|
end
|
200
218
|
end
|
201
219
|
|
202
|
-
def opt name, opt, *
|
203
|
-
r = Opt.new( self, name, opt, *
|
220
|
+
def opt name, opt, *args, desc, default: NilClass, &conv
|
221
|
+
r = Opt.new( self, name, opt, *args, desc, default: default, &conv)
|
204
222
|
@options[r.name] = r
|
205
223
|
self
|
206
224
|
end
|
207
225
|
|
208
226
|
def inspect
|
209
|
-
"#<%s:0x%x %s @name=%p @description=%p @parent=<%s:0x%x %s> @exe=<arity=%d>>" % [
|
227
|
+
"#<%s:0x%x %s @name=%p @description=%p @options=%p @parent=<%s:0x%x %s> @exe=<arity=%d>>" % [
|
210
228
|
self.class.name, self.object_id, self.full_cmd,
|
211
|
-
@name, @description, @parent.class.name, @parent.class.object_id, @parent.full_cmd,
|
229
|
+
@name, @description, @options.values, @parent.class.name, @parent.class.object_id, @parent.full_cmd,
|
212
230
|
@exe.arity
|
213
231
|
]
|
214
232
|
end
|
data/lib/dencli/interactive.rb
CHANGED
data/lib/dencli/sub.rb
CHANGED
@@ -3,19 +3,31 @@ require_relative '../dencli'
|
|
3
3
|
class DenCli::Sub
|
4
4
|
attr_reader :parent, :name, :description, :subs, :aliases
|
5
5
|
|
6
|
-
def initialize parent, name, description
|
6
|
+
def initialize parent, name, description, noshortaliases: nil
|
7
7
|
#DenCli::assert_type self, __method__, :name, name, Symbol
|
8
8
|
#DenCli::assert_type self, __method__, :parent, parent, DenCli, DenCli::Sub
|
9
9
|
#DenCli::assert_type self, __method__, :description, description, String
|
10
10
|
@parent, @name, @description, @subs, @aliases = parent, name, "-> #{description}", {}, {}
|
11
|
+
@noshortaliases = ! ! noshortaliases
|
11
12
|
end
|
12
13
|
|
13
14
|
def _full_cmd( post) parent._full_cmd [@name]+post end
|
14
15
|
def full_cmd() _full_cmd [] end
|
15
16
|
def []( k) @aliases[k] end
|
16
17
|
|
17
|
-
def usage
|
18
|
-
|
18
|
+
def usage output: nil
|
19
|
+
output ||= ''
|
20
|
+
_usage output
|
21
|
+
output
|
22
|
+
end
|
23
|
+
|
24
|
+
def _usage output
|
25
|
+
output << full_cmd.join( ' ')
|
26
|
+
if @aliases.has_key? nil
|
27
|
+
output << " [<command> ...]"
|
28
|
+
else
|
29
|
+
output << " <command> [...]"
|
30
|
+
end
|
19
31
|
end
|
20
32
|
|
21
33
|
def help n = nil, *a, output: nil
|
@@ -46,37 +58,39 @@ class DenCli::Sub
|
|
46
58
|
output
|
47
59
|
end
|
48
60
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
c
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
61
|
+
class <<self
|
62
|
+
def _help_commands output, subs
|
63
|
+
m = subs.map {|_name,c| x = c.usage.length; 25 < x ? 0 : x }.max
|
64
|
+
subs.each do |_name, c|
|
65
|
+
if 25 < c.usage.length
|
66
|
+
output << "% -#{m}s\n#{' ' * m} " % [c.usage]
|
67
|
+
else
|
68
|
+
output << "% -#{m}s " % [c.usage]
|
69
|
+
end
|
70
|
+
n = m+2
|
71
|
+
prefix = nil
|
72
|
+
c.description.split( /\n/).each do |l|
|
73
|
+
c = 0
|
74
|
+
l.split( %r< >).each do |w|
|
75
|
+
if prefix
|
76
|
+
output << prefix
|
77
|
+
prefix = nil
|
78
|
+
end
|
79
|
+
wl = w.length
|
80
|
+
if 75 < c+wl
|
81
|
+
output << "\n#{' ' * n}#{w}"
|
82
|
+
c = n+2+wl
|
83
|
+
else
|
84
|
+
output << " #{w}"
|
85
|
+
c += 1 + wl
|
86
|
+
end
|
73
87
|
end
|
88
|
+
prefix = "\n#{' ' * n}"
|
74
89
|
end
|
75
|
-
|
90
|
+
output << "\n"
|
76
91
|
end
|
77
|
-
output
|
92
|
+
output
|
78
93
|
end
|
79
|
-
output
|
80
94
|
end
|
81
95
|
|
82
96
|
def goto *a
|
@@ -105,16 +119,27 @@ class DenCli::Sub
|
|
105
119
|
#DenCli::assert_type self, __method__, :aliases, aliases, Array, NilClass
|
106
120
|
name = name.to_s unless name.nil?
|
107
121
|
@subs[name] = obj
|
108
|
-
|
122
|
+
if @noshortaliases
|
123
|
+
warn "Command/Alias already exists: #{full_cmd.join ' '} #{name}" if @aliases.has_key? name
|
124
|
+
@aliases[name] = obj
|
125
|
+
else
|
126
|
+
DenCli.gen_aliases name, min do |a|
|
127
|
+
warn "Command/Alias already exists: #{full_cmd.join ' '} #{a}" if @aliases.has_key? a
|
128
|
+
@aliases[a] ||= obj
|
129
|
+
end
|
130
|
+
end
|
109
131
|
if aliases
|
110
|
-
[*aliases].each
|
132
|
+
[*aliases].each do |a|
|
133
|
+
raise ArgumentError, "Alias already exists: #{full_cmd.join ' '} #{a}" if @aliases.has_key? a
|
134
|
+
@aliases[a] = obj
|
135
|
+
end
|
111
136
|
end
|
112
137
|
obj
|
113
138
|
end
|
114
139
|
private :_add
|
115
140
|
|
116
|
-
def sub name, description, min: nil, aliases: nil, &exe
|
117
|
-
r = _add name, min, DenCli::Sub.new( self, name, description), aliases
|
141
|
+
def sub name, description, min: nil, aliases: nil, noshortaliases: nil, &exe
|
142
|
+
r = _add name, min, DenCli::Sub.new( self, name, description, noshortaliases: noshortaliases), aliases
|
118
143
|
block_given? ? yield( r) : r
|
119
144
|
end
|
120
145
|
|
@@ -128,7 +153,7 @@ class DenCli::Sub
|
|
128
153
|
elsif sub = @subs[pre[0]]
|
129
154
|
sub.complete *pre[1..-1], str
|
130
155
|
else
|
131
|
-
|
156
|
+
$stdout.print "\a"
|
132
157
|
end
|
133
158
|
end
|
134
159
|
|
data/lib/dencli/version.rb
CHANGED
data/lib/dencli.rb
CHANGED
@@ -51,11 +51,16 @@ class DenCli
|
|
51
51
|
# `g(:abc)` => `["a", "ab", "abc"]`
|
52
52
|
# `g(:abcdef, 4)` => `["abcd", "abcde", "abcdef"]`
|
53
53
|
def gen_aliases cmd, min = nil
|
54
|
-
|
54
|
+
case min
|
55
|
+
when false then min = cmd.length
|
56
|
+
when nil then min = 1
|
57
|
+
end
|
58
|
+
r = ([min, 1].max - 1).upto cmd.length-2
|
55
59
|
if block_given?
|
56
60
|
r.each {|i| yield cmd[0..i] }
|
61
|
+
yield cmd
|
57
62
|
else
|
58
|
-
r.map {|i| cmd[0..i] }
|
63
|
+
r.map {|i| cmd[0..i] } + [cmd]
|
59
64
|
end
|
60
65
|
end
|
61
66
|
alias g gen_aliases
|
@@ -96,7 +101,7 @@ class DenCli
|
|
96
101
|
end
|
97
102
|
|
98
103
|
def help_full *args, output: nil
|
99
|
-
output ||=
|
104
|
+
output ||= $stdout
|
100
105
|
x = @subs.goto *args
|
101
106
|
_help_full output, x
|
102
107
|
end
|
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.5.
|
4
|
+
version: 0.5.5
|
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-12-
|
11
|
+
date: 2021-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|