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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f6fa7e69d426f92f554f31e17adc226687c6851b53f11750fe2887e856d7e99
4
- data.tar.gz: 9e2b3b52bed172e5a3b17f8556bb5bc90a4fa613bc631d6ccf3eff5a7e6bcbdb
3
+ metadata.gz: b4f8e9d3af41176bba078797a33ed1116dee0d1bbdfdce64b4662ba084c0630e
4
+ data.tar.gz: 38c29fe476f8c31af57706a915fb5503a9f0ef3f81aab74675206980013bbd6a
5
5
  SHA512:
6
- metadata.gz: 3e8c379293addfafee9b688c1eb02c336616ce1e66522bb98d94966eacf3e5fa1a23f5e7df1de6f731d97700fd44ea1188f0f8e8f30e6729459799254348bf5f
7
- data.tar.gz: ae7fe49dd995e7fd186fa7f52c4c9f85f4e35c5b70fc6f3e11a59082cb395ae50bab87e455475241e39048a2c559fe2336a4fad8809434577c117c3565efcaff
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
- $:.unshift Pathname.new(__FILE__).dirname.dirname.join('lib').to_s
5
- require 'dencli'
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, '-d=ForD', "Option d", default: "something").
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") { STDERR.puts "This is an example" }
18
- cli.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*args, full:|
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 *args, output: STDERR
219
+ cli.help_full *commands, output: $stderr
21
220
  else
22
- cli.help *args, output: STDERR
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| STDERR.puts sub.help(*args) }
29
- sub.cmd( :help, "") {|*args| STDERR.puts cli.help( 'more', *args) }
30
- sub.cmd( :example, "Here is an example, too") { STDERR.puts "This is an other example" }
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 {|*args| sub2.help( *args, output: STDERR) })
42
- sub2.cmd( :last, "The last example", &lambda { STDERR.puts "The last example" })
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| STDERR.puts sub3.help( sub3, *args) }
46
- sub3.cmd( :hehe, "The real last example", min: 2) { STDERR.puts "Trust me!" }
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
- STDERR.puts $!
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
- def parameters() @exe.parameters end
18
- def arguments_required() @exe.parameters.select {|e| :req == e[0] }.map {|e| e[1] } end
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
- @exe.call *as, **os
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
- required.each {|s| output << " <#{s}>" }
77
- output << " [#{additional.map{|s|"<#{s}>"}.join " "}]" unless additional.empty?
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 += "=#{v}" if v
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, :val, :desc, :os, :conv, :req
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(-[^=-]+)=(.+)\z/
176
+ when /\A(-[^=-])=?(.+)\z/
162
177
  @short, @val = $1, $2 || @val
163
- when /\A(-[^=-]+)\z/
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, *alts, desc, default: NilClass, **os, &conv
172
- @name, @desc, @default, @os, @conv, @val =
173
- name.to_s.to_sym, desc, default, os, conv || lambda{|v|v}, nil
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
- alts.each &method( :parse_opt_string)
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
- parser.on "#{@short}#{@val ? ?= : ''}#{@val}", "#{@long}#{@val ? ?= : ''}#{@val}", **@os do |val|
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%016x %s %s %s %s (%p) %p os=%p conv=%s>" % [
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, @os,
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, *alts, desc, **os, &conv
203
- r = Opt.new( self, name, opt, *alts, desc, **os, &conv)
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
@@ -121,7 +121,7 @@ class DenCli::Interactive
121
121
  begin
122
122
  cur.call *line
123
123
  rescue ::DenCli::UsageError
124
- STDERR.puts "! #$!"
124
+ $stderr.puts "! #$!"
125
125
  end
126
126
  true
127
127
  end
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
- "#{full_cmd.join ' '} ..."
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
- 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
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
- prefix = "\n#{' ' * n}"
90
+ output << "\n"
76
91
  end
77
- output << "\n"
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
- DenCli.gen_aliases( name, min) {|a| @aliases[a] = obj }
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 {|a| @aliases[a] = obj }
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
- STDOUT.print "\a"
156
+ $stdout.print "\a"
132
157
  end
133
158
  end
134
159
 
@@ -1,3 +1,3 @@
1
1
  class DenCli
2
- VERSION = '0.5.1'
2
+ VERSION = '0.5.5'
3
3
  end
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
- r = ((min||1)-1).upto cmd.length-1
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 ||= STDOUT
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.1
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-07 00:00:00.000000000 Z
11
+ date: 2021-12-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec