dencli 0.5.5 → 0.5.6

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: 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