dencli 0.5.5 → 0.5.6

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: b4f8e9d3af41176bba078797a33ed1116dee0d1bbdfdce64b4662ba084c0630e
4
- data.tar.gz: 38c29fe476f8c31af57706a915fb5503a9f0ef3f81aab74675206980013bbd6a
3
+ metadata.gz: 567eaa6ae13836be53cfc492496ae089be944c0a352f55023ac413e4f051c8d4
4
+ data.tar.gz: 7c3cb0ff03f0a738b56e785e8d2f9da76db16d0afab5c29fd5a53881476968cd
5
5
  SHA512:
6
- metadata.gz: a028b051a9ae055280811ba2dbe61f7e4c1ed9452cc015c4dea75f429ffa4ff768baaf0373aee46fa316563840fbd2abe450a7437647555dc117e2beabcd740b
7
- data.tar.gz: 2dee7a4e46e861dec67df330db80789ba9dcb2ea05f7274853e8963235ee52a3e04572be72c2ed1c33351e9cae6a87ad809cfd32bd48fd6ec393b99a5e0ba7b5
6
+ metadata.gz: d2bc0b876cc7eb05a8a778264c76c2721bc8328199042ae551793c4f744b4248845f2390558718cae07dd4da215b5d166caa391c0c503c7a65550549fe3e78a1
7
+ data.tar.gz: 634d5a0a2d0037b2c81e4b1d7b922413beb760b016b961560bd1bc8bfb85e5d34ed08e5947e38068ae6074f3f79f96cc5ab298d8c53b384d7a9adf6e809bb714
data/bin/example.rb CHANGED
@@ -95,7 +95,62 @@ class Capture
95
95
  end
96
96
  end
97
97
 
98
+ cli.cmd( :args, "Expects and prints given arguments",
99
+ &lambda {|a, b, c:, d:, e:, f:, g:|
100
+ p a: a, b: b, c: c, d: d, e: e
101
+ }).
102
+ opt( :c, '-c=ForC', "Option c").
103
+ opt( :d, '-dForD', "Option d", default: "something").
104
+ opt( :e, '-e', "Toggle e", default: false).
105
+ opt( :f, '--[no-]f', "Toggle f", default: false).
106
+ opt( :g, '--long-option=sth', "Long option, no short option", default: "nothing").
107
+ opt( :h, '-hsth', "No long option, only short option", default: "nothing")
108
+
109
+ cli.cmd( :example, "I have an example command") { $stderr.puts "This is an example" }
110
+ cli.cmd( :help, "An example for help", aliases: [nil, '-h', '--help'], &lambda {|*commands, full:|
111
+ if full
112
+ cli.help_full *commands, output: $stderr
113
+ else
114
+ cli.help *commands, output: $stderr
115
+ end
116
+ }).
117
+ opt( :full, '-f', '--[no-]full', "Print all commands and sub-commands.", default: false)
118
+
119
+ cli.sub( :more, "Sub-Commands are also possible with a new cli") do |sub|
120
+ sub.cmd( :help, "", aliases: [nil, '-h', '--help']) {|*args| $stderr.puts sub.help(*args) }
121
+ sub.cmd( :example, "Here is an example, too") { $stderr.puts "This is an other example" }
122
+ sub.cmd( :foo, "BAR") { $stderr.puts "FOO bar"}
123
+
124
+ sub.cmd( :args, "Expects and prints given arguments", &lambda {|a, b=1, c:, d: 5, e:|
125
+ p a: a, b: b, c: c, d: d, e: e
126
+ }).
127
+ opt( :c, '-c=ForC', "Option c").
128
+ opt( :d, '-d=ForD', "Option d (implicit default)").
129
+ opt( :e, '-e', "Toggle e")
130
+
131
+ sub.sub( :deeper, "You want to have Sub-Sub-Commands?") do |sub2|
132
+ sub2.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*commands| sub2.help( *commands, output: $stderr) })
133
+ sub2.cmd( :last, "The last example", &lambda { $stderr.puts "The last example" })
134
+
135
+ sub2.sub( :'sub-commands', "Endless Sub-Sub- ... with a special alias") do |sub3|
136
+ # h -> help
137
+ # he -> hehe
138
+ # hel -> help
139
+ # help -> help
140
+ # heh -> hehe
141
+ # hehe -> hehe
142
+ sub3.cmd( :help, "", min: 3, aliases: [nil, :h]) {|*args| $stderr.puts sub3.help( *args) }
143
+ sub3.cmd( :hehe, "The real last example", min: 2) { $stderr.puts "Trust me!" }
144
+ end
145
+ end
146
+ end
147
+
148
+ cli.cmd( :cli, "Interactive shell", min: 3, &lambda {||
149
+ cli.interactive( File.basename($0, '.rb')).run
150
+ })
151
+
98
152
  cli.sub :tests, "Some tests", noshortaliases: true do |tcli|
153
+ tcli.cmd( :help, "", min: 4) {|*args| $stderr.puts tcli.help( *args) }
99
154
  OptionParser.accept IPAddr do |arg|
100
155
  begin
101
156
  IPAddr.new arg
@@ -202,50 +257,6 @@ cli.sub :tests, "Some tests", noshortaliases: true do |tcli|
202
257
  end.opt( :verbose, '-v', 'Prints additional information per test', default: false)
203
258
  end
204
259
 
205
- cli.cmd( :args, "Expects and prints given arguments",
206
- &lambda {|a, b, c:, d:, e:, f:, g:|
207
- p a: a, b: b, c: c, d: d, e: e
208
- }).
209
- opt( :c, '-c=ForC', "Option c").
210
- opt( :d, '-dForD', "Option d", default: "something").
211
- opt( :e, '-e', "Toggle e", 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")
215
-
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:|
218
- if full
219
- cli.help_full *commands, output: $stderr
220
- else
221
- cli.help *commands, output: $stderr
222
- end
223
- }).
224
- opt( :full, '-f', '--[no-]full', "Print all commands and sub-commands.", default: false)
225
-
226
- cli.sub( :more, "Sub-Commands are also possible with a new cli") do |sub|
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"}
230
-
231
- sub.cmd( :args, "Expects and prints given arguments", &lambda {|a, b=1, c:, d: 5, e:|
232
- p a: a, b: b, c: c, d: d, e: e
233
- }).
234
- opt( :c, '-c=ForC', "Option c").
235
- opt( :d, '-d=ForD', "Option d (implicit default)").
236
- opt( :e, '-e', "Toggle e")
237
-
238
- sub.sub( :deeper, "You want to have Sub-Sub-Commands?") do |sub2|
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" })
241
-
242
- sub2.sub( :'sub-commands', "Endless Sub-Sub- ...") do |sub3|
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!" }
245
- end
246
- end
247
- end
248
-
249
260
  begin
250
261
  cli.call *ARGV
251
262
  rescue DenCli::UsageError
data/lib/dencli/cmd.rb CHANGED
@@ -2,11 +2,11 @@ require_relative '../dencli'
2
2
 
3
3
 
4
4
  class DenCli::CMD
5
- attr_reader :parent, :name, :description, :exe, :completion, :options
5
+ attr_reader :parent, :name, :description, :exe, :completion, :options, :defined_in
6
6
 
7
- def initialize parent, name, description, exe
7
+ def initialize parent, name, description, exe, defined_in
8
8
  raise "Proc expected, instead of: #{exe.inspect}" unless Proc === exe
9
- @parent, @name, @description, @exe = parent, name, description, lambda( &exe)
9
+ @parent, @name, @description, @exe, @defined_in = parent, name, description, lambda( &exe), defined_in
10
10
  @parameters = @exe.parameters
11
11
  @arguments_required = @exe.parameters.select {|e| :req == e[0] }.map {|e| e[1] }
12
12
  @arguments_additional = @exe.parameters.select {|e| :opt == e[0] }.map {|e| e[1] }
@@ -167,15 +167,15 @@ class DenCli::CMD
167
167
 
168
168
  def parse_opt_string opt
169
169
  case opt
170
- when /\A(--\[no-\][^=]+)\z/
170
+ when /\A(--\[no-\][^= ]+)\z/
171
171
  @long, @val = $1, nil
172
- when /\A(--[^=]+)=(.+)\z/
172
+ when /\A(--[^= ]+)[= ](.+)\z/
173
173
  @long, @val = $1, $2 || @val
174
- when /\A(--[^=]+)\z/
174
+ when /\A(--[^= ]+)\z/
175
175
  @long, @val = $1, nil
176
- when /\A(-[^=-])=?(.+)\z/
176
+ when /\A(-[^= -])[= ]?(.+)\z/
177
177
  @short, @val = $1, $2 || @val
178
- when /\A(-[^=-])\z/
178
+ when /\A(-[^= -])\z/
179
179
  @short, @val = $1, nil
180
180
  else
181
181
  raise ArgumentError, "Unexpected format for option: #{opt.inspect}"
@@ -17,12 +17,15 @@ class DenCli::Interactive
17
17
  end
18
18
  read_history if @histfile
19
19
 
20
- Readline.vi_editing_mode rescue NotImplementedError
20
+ begin
21
+ Readline.vi_editing_mode
22
+ rescue NotImplementedError
23
+ end
21
24
  Readline.completion_append_character = " "
22
25
  Readline.completion_proc = method :complete
23
26
 
24
27
  prepare_sub cl.subs
25
- cl.cmd :exit, "exit", min: 2 do
28
+ cl.cmd :exit, "exit", min: cl.has?(:ex) ? cl.has?(:exi) ? 4 : 3 : 2 do
26
29
  exit 0
27
30
  end
28
31
  cl.subs.aliases['?'] = cl.subs.subs['help']
@@ -90,14 +93,16 @@ class DenCli::Interactive
90
93
  c.subs.values.each do |n|
91
94
  case n
92
95
  when DenCli::Sub
93
- n.cmd :exit, "<- #{n.parent.full_cmd.join ' '} - #{n.parent.description[3..-1]}", min: 2 do
94
- @cur = n.parent
95
- end
96
+ n.cmd :exit,
97
+ "<- #{n.parent.full_cmd.join ' '} - #{n.parent.description[3..-1]}",
98
+ min: n.has?(:ex) ? n.has?( :exi) ? 4 : 3 : 2,
99
+ &lambda {|| @cur = n.parent }
100
+ n.aliases.delete nil
101
+ n.subs.delete nil
96
102
  n.cmd '', "", min: 2, aliases: [nil] do
97
103
  @cur = n
98
104
  end
99
- n.subs.delete ''
100
- n.aliases['?'] = n.subs['help']
105
+ n.aliases['?'] = n[:help] if n.has? :help and not n.has? '?'
101
106
  prepare_sub n
102
107
  when DenCli::CMD
103
108
  else raise "Unsupported sub-type: #{x}"
data/lib/dencli/sub.rb CHANGED
@@ -1,19 +1,21 @@
1
1
  require_relative '../dencli'
2
2
 
3
3
  class DenCli::Sub
4
- attr_reader :parent, :name, :description, :subs, :aliases
4
+ attr_reader :parent, :name, :description, :subs, :aliases, :defined_in
5
5
 
6
- def initialize parent, name, description, noshortaliases: nil
6
+ def initialize parent, name, description, noshortaliases: nil, defined_in: 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
+ @noshortaliases, @defined_in = ! ! noshortaliases, defined_in || Kernel.caller
12
12
  end
13
13
 
14
14
  def _full_cmd( post) parent._full_cmd [@name]+post end
15
15
  def full_cmd() _full_cmd [] end
16
- def []( k) @aliases[k] end
16
+ def []( name) @aliases[name&.to_s] end
17
+ def has?( name) @aliases.has_key? name&.to_s end
18
+
17
19
 
18
20
  def usage output: nil
19
21
  output ||= ''
@@ -40,8 +42,8 @@ class DenCli::Sub
40
42
  if n.nil?
41
43
  output << "#{full_cmd.join ' '}: #{description}\n\n"
42
44
  self.class._help_commands output, @subs
43
- elsif @aliases.has_key? n
44
- @aliases[n]._help output, *a
45
+ elsif has? n
46
+ self[n]._help output, *a
45
47
  else
46
48
  raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}"
47
49
  end
@@ -96,8 +98,8 @@ class DenCli::Sub
96
98
  def goto *a
97
99
  return self if a.empty?
98
100
  n, *a = *a
99
- if @aliases.has_key? n
100
- @aliases[n].goto *a
101
+ if has? n
102
+ self[n].goto *a
101
103
  else
102
104
  raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}"
103
105
  end
@@ -105,32 +107,33 @@ class DenCli::Sub
105
107
 
106
108
  def call *a
107
109
  n, *a = *a
108
- if @aliases.has_key? n
109
- @aliases[n].call *a
110
+ if has? n
111
+ self[n].call *a
110
112
  else
111
113
  raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}"
112
114
  end
113
115
  end
114
116
 
115
117
  def _add name, min, obj, aliases
116
- #DenCli::assert_type self, __method__, :name, name, Symbol, NilClass
118
+ #DenCli::assert_type self, __method__, :name, name, Symbol, String
117
119
  #DenCli::assert_type self, __method__, :min, min, Integer, NilClass
118
120
  #DenCli::assert_type self, __method__, :obj, obj, DenCli::Sub, DenCli::CMD
119
121
  #DenCli::assert_type self, __method__, :aliases, aliases, Array, NilClass
120
- name = name.to_s unless name.nil?
122
+ name = name.to_s
121
123
  @subs[name] = obj
122
124
  if @noshortaliases
123
- warn "Command/Alias already exists: #{full_cmd.join ' '} #{name}" if @aliases.has_key? name
125
+ warn "Command/Alias for #{obj.full_cmd} defined in #{obj.defined_in} already exists: #{full_cmd.join ' '} #{name}. Used by #{@aliases[name].full_cmd} defined in #{@aliases[name].defined_in}" if @aliases.has_key? name
124
126
  @aliases[name] = obj
125
127
  else
126
128
  DenCli.gen_aliases name, min do |a|
127
- warn "Command/Alias already exists: #{full_cmd.join ' '} #{a}" if @aliases.has_key? a
129
+ warn "Command/Alias for #{obj.full_cmd} defined in #{obj.defined_in} already exists: #{full_cmd.join ' '} #{a}. Used by #{@aliases[a].full_cmd} defined in #{@aliases[a].defined_in}" if @aliases.has_key? a
128
130
  @aliases[a] ||= obj
129
131
  end
130
132
  end
131
133
  if aliases
132
134
  [*aliases].each do |a|
133
- raise ArgumentError, "Alias already exists: #{full_cmd.join ' '} #{a}" if @aliases.has_key? a
135
+ a = a&.to_s
136
+ raise ArgumentError, "Alias for #{obj.full_cmd} defined in #{obj.defined_in} already exists: #{full_cmd.join ' '} #{a}. Used by #{@aliases[a].full_cmd} defined in #{@aliases[a].defined_in}" if @aliases.has_key? a
134
137
  @aliases[a] = obj
135
138
  end
136
139
  end
@@ -138,13 +141,51 @@ class DenCli::Sub
138
141
  end
139
142
  private :_add
140
143
 
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
144
+ # Define a new sub-menu:
145
+ #
146
+ # DenCli.new {|c|
147
+ # c.sub( 'sub-command') {|s|
148
+ # s.cmd( :hello, 'Greetings', &lambda {|| puts 'hello world' })
149
+ # }
150
+ # }
151
+ #
152
+ # # ./prog sub-command hello
153
+ #
154
+ # name should be a string/symbol. It will be converted to string.
155
+ # If provided, aliases must be a list of different aliases. It will be converted to string.
156
+ def sub name, description, min: nil, aliases: nil, noshortaliases: nil, defined_in: nil, &exe
157
+ r = _add name.to_s, min, DenCli::Sub.new( self, name, description, noshortaliases: noshortaliases, defined_in: defined_in || Kernel.caller.first), aliases
143
158
  block_given? ? yield( r) : r
144
159
  end
145
160
 
146
- def cmd name, description, min: nil, aliases: nil, &exe
147
- _add name, min, DenCli::CMD.new( self, name, description, exe), aliases
161
+ # Define a new command:
162
+ #
163
+ # DenCli.new {|c|
164
+ # c.cmd( :hello, 'Greetings', &lambda {|| puts 'hello world' })
165
+ # }
166
+ #
167
+ # # ./prog hello
168
+ # hello world
169
+ #
170
+ # name should be a string/symbol. It will be converted to string.
171
+ # If provided, aliases must be a list of different aliases. Except of nil, any alias will be converted to string.
172
+ # nil is an alias for a default command for sub-commands, but interactive shells.
173
+ #
174
+ # DenCli.new {|c|
175
+ # c.sub( :greetings, 'Hello, Welcome, ...') do |s|
176
+ # s.cmd( :hello, 'A simple Hello', aliases: %w[hello-world hello_world], &lambda {|| puts 'Hello World' })
177
+ # s.cmd( :welcome, 'More gracefull', aliases: [nil, 'welcome-world', :hello_world], &lambda {|| puts 'Welcome World' })
178
+ # }
179
+ # }
180
+ #
181
+ # # ./prog greetings
182
+ # Welcome World
183
+ # # ./prog greetings welcome
184
+ # Welcome World
185
+ # # ./prog greetings hello
186
+ # Hello World
187
+ def cmd name, description, min: nil, aliases: nil, defined_in: nil, &exe
188
+ _add name, min, DenCli::CMD.new( self, name, description, exe, defined_in || Kernel.caller.first), aliases
148
189
  end
149
190
 
150
191
  def complete *pre, str
@@ -1,3 +1,3 @@
1
1
  class DenCli
2
- VERSION = '0.5.5'
2
+ VERSION = '0.5.6'
3
3
  end
data/lib/dencli.rb CHANGED
@@ -80,6 +80,9 @@ class DenCli
80
80
  post
81
81
  end
82
82
 
83
+ def []( k) @subs[k] end
84
+ def has?( k) @subs.has? k end
85
+
83
86
  def sub *a, **o, &exe
84
87
  @subs.sub *a, **o, &exe
85
88
  end
@@ -110,10 +113,6 @@ class DenCli
110
113
  Sub._help_commands output, subs.to_enum( :commands)
111
114
  end
112
115
 
113
- def [] k
114
- @subs[k]
115
- end
116
-
117
116
  def interactive *args, **opts
118
117
  Interactive.new self, *args, **opts
119
118
  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.5
4
+ version: 0.5.6
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-31 00:00:00.000000000 Z
11
+ date: 2022-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec