dencli 0.5.1 → 0.5.5

Sign up to get free protection for your applications and to get access to all the features.
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