dencli 0.4.0 → 0.5.3

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: 127668bd8bd4de7dc572ce5c72be6403ca49e9da7690ceb7746c913a497495c3
4
- data.tar.gz: b28f1e67d5c029df9917f6f9609a8d0c718c8a6cda35a0cf1a283cf37a925adb
3
+ metadata.gz: b51686dc165e8a0fa5dad00dea71e56a4007be3ad050de0e7a73b3f7587baefa
4
+ data.tar.gz: 97ce2e6f4bb16974e8b1375133fbcbf8be7b1d4f15491935ebcda55557b3784f
5
5
  SHA512:
6
- metadata.gz: e5fce26cb4eae5698536a1c1ffbae0571783432acef83451477daf259ee6aed1699542f4a93909c1bc3ac25095b3153a1381f32efa827f489cb3885cba557e7d
7
- data.tar.gz: 8b22f6c8dfdd91fef4ce45819377ac5773e82a01ca168624dbff789d942cb32dec2677de396574198f7643f20f4401a32955239e67b621ecdebf5eb8847f854f
6
+ metadata.gz: 5a98c654de4a78a1dc07c41a8cd2dffcba9d34b57c03b80784b8d652f155d5a53f54370906ec51404c0b6df45a4e387fb8027b5938539780a50e680b9dfbd123
7
+ data.tar.gz: 3a0e657604254c35e65ae6c501af0c79fd6887b7cb45b8a4ea1693c6fd666eddf04d5e3b060841bf6b0619c35bfdd6af61e98d9598090c9101f4631d993d84ee
data/bin/example.rb CHANGED
@@ -4,16 +4,27 @@ require 'pathname'
4
4
  $:.unshift Pathname.new(__FILE__).dirname.dirname.join('lib').to_s
5
5
  require 'dencli'
6
6
 
7
- cli = DenCli.new 'example', "This is an example for generate a DenCli-API"
8
- cli.cmd( :example, "I have an example command") { STDERR.puts "This is an example" }
9
- cli.cmd( :help, "", aliases: [nil, '-h', '--help']) {|*args| STDERR.puts cli.help(*args) }
10
-
11
- cli.cmd( :args, "Expects and prints given arguments", &lambda {|a, b, c:, d:, e:|
7
+ cli = DenCli.new :example, "This is an example for generate a DenCli-API"
8
+ cli.cmd( :args, "Expects and prints given arguments",
9
+ &lambda {|a, b, c:, d:, e:, f:, g:|
12
10
  p a: a, b: b, c: c, d: d, e: e
13
11
  }).
14
12
  opt( :c, '-c=ForC', "Option c").
15
- opt( :d, '-d=ForD', "Option d", default: "something").
16
- opt( :e, '-e', "Toggle e", default: false)
13
+ opt( :d, '-dForD', "Option d", default: "something").
14
+ opt( :e, '-e', "Toggle e", default: false).
15
+ opt( :f, '--[no-]f', "Toggle f", default: false).
16
+ opt( :g, '--long-option=sth', "Long option, no short option", default: "nothing").
17
+ opt( :h, '-hsth', "No long option, only short option", default: "nothing")
18
+
19
+ cli.cmd( :example, "I have an example command") { STDERR.puts "This is an example" }
20
+ cli.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*args, full:|
21
+ if full
22
+ cli.help_full *args, output: STDERR
23
+ else
24
+ cli.help *args, output: STDERR
25
+ end
26
+ }).
27
+ opt( :full, '-f', '--[no-]full', "Print all commands and sub-commands.", default: false)
17
28
 
18
29
  cli.sub( :more, "Sub-Commands are also possible with a new cli") do |sub|
19
30
  sub.cmd( :help, "", aliases: [nil, '-h', '--help']) {|*args| STDERR.puts sub.help(*args) }
@@ -29,7 +40,7 @@ cli.sub( :more, "Sub-Commands are also possible with a new cli") do |sub|
29
40
  opt( :e, '-e', "Toggle e")
30
41
 
31
42
  sub.sub( :deeper, "You want to have Sub-Sub-Commands?") do |sub2|
32
- sub2.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*args| STDERR.puts sub2.help(*args) })
43
+ sub2.cmd( :help, "", aliases: [nil, '-h', '--help'], &lambda {|*args| sub2.help( *args, output: STDERR) })
33
44
  sub2.cmd( :last, "The last example", &lambda { STDERR.puts "The last example" })
34
45
 
35
46
  sub2.sub( :'sub-commands', "Endless Sub-Sub- ...") do |sub3|
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,19 +20,17 @@ 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
- def help() "Usage: #{usage}\n#{description}\n#{options_help}" end
27
- def complete( *pre, str) @completion.call *pre, str end
29
+ def complete *pre, str
30
+ @completion.call *pre, str
31
+ end
28
32
 
29
- def call( *as)
33
+ def call *as
30
34
  os = {}
31
35
  unless @options.empty?
32
36
  # options like --abc | -x will be provided in os
@@ -53,25 +57,58 @@ class DenCli::CMD
53
57
  end
54
58
  kr = @options.select {|_, o| o.required? and not os.has_key? o.name }
55
59
  unless kr.empty?
56
- raise DenCli::UsageError, "Missing argument(s): #{kr.map {|o| o.as.first }.join ', '}"
60
+ raise DenCli::UsageError, "Missing argument(s): #{kr.map {|_, o| o.long || o.short }.join ', '}"
57
61
  end
58
62
  end
59
63
  @exe.call *as, **os
60
64
  end
61
65
 
62
- def usage
63
- args =
64
- @options.map do |_, o|
65
- s = "#{o.short}#{o.val ? ?= : ''}#{o.val}"; o.required? ? "#{s} " : "[#{s}] "
66
- end
67
- "#{full_cmd.join ' '} #{args.join ''}"+
68
- (@exe.lambda? ? (
69
- required.map{|s|"<#{s}>"}.join( " ")+
70
- (additional.empty? ? "" : " [#{additional.map{|s|"<#{s}>"}.join " "}]")
71
- ) : '...')
66
+ def usage output: nil
67
+ output ||= ''
68
+ _usage output
69
+ output
70
+ end
71
+
72
+ def _usage output
73
+ output << full_cmd.join( ' ')
74
+ @options.each do |_, o|
75
+ s = "#{o.short||o.long}#{(!o.short && o.val) ? ?= : ''}#{o.val}"
76
+ output << (o.required? ? " #{s}" : " [#{s}]")
77
+ end
78
+ if @exe.lambda?
79
+ required.each {|s| output << " <#{s}>" }
80
+ output << " [#{additional.map{|s|"<#{s}>"}.join " "}]" unless additional.empty?
81
+ else
82
+ output << ' ...'
83
+ end
84
+ end
85
+
86
+ def commands *args
87
+ yield name, self
72
88
  end
73
89
 
74
- def options_help
90
+ def goto *args
91
+ self
92
+ end
93
+
94
+ def help output: nil
95
+ output ||= ''
96
+ _help output
97
+ output
98
+ end
99
+
100
+ def _help output
101
+ output << "Usage: #{usage}\n#{description}\n"
102
+ _help_options output
103
+ end
104
+
105
+ def help_options output: nil
106
+ output ||= ''
107
+ _help_options output
108
+ output
109
+ end
110
+
111
+ def _help_options output
75
112
  sc, lc, dc = 0, 0, 0
76
113
  @options.each do |_, o|
77
114
  s = o.short&.length || 0
@@ -89,8 +126,8 @@ class DenCli::CMD
89
126
  end
90
127
  dc = d if dc < d
91
128
  end
92
- format = " %-#{sc}s%s %-#{lc}s %s"
93
- @options.map {|_, o|
129
+ format = " %-#{sc}s%s %-#{lc}s %s\n"
130
+ @options.map do |_, o|
94
131
  s, l, v, y = o.short, o.long, o.val, ','
95
132
  if l.nil?
96
133
  s += "=#{v}" if v
@@ -101,8 +138,8 @@ class DenCli::CMD
101
138
  end
102
139
  d = o.desc || ''
103
140
  d += " (#{o.default})" if o.default?
104
- format % [ s, y, l, d ]
105
- }.join "\n"
141
+ output << format % [ s, y, l, d ]
142
+ end
106
143
  end
107
144
 
108
145
  def completion &exe
@@ -116,34 +153,29 @@ class DenCli::CMD
116
153
  def default?() NilClass != @default end
117
154
  def default() NilClass == @default ? nil : @default end
118
155
 
119
- def initialize cmd, name, opt, *alts, desc, default: NilClass, **os, &conv
120
- long = short = val = nil
156
+ def parse_opt_string opt
121
157
  case opt
122
- when /\A(--[^=-]+)=(.+)\z/
123
- long, val = $1, $2
124
- when /\A(--[^=-]+)\z/
125
- long, val = $1, nil
126
- when /\A(-[^=-]+)=(.+)\z/
127
- short, val = $1, $2
128
- when /\A(-[^=-]+)\z/
129
- short, val = $1, nil
130
- else raise ArgumentError, "Unexpected format for option: #{opt.inspect}"
131
- end
132
- alts.each do |alt|
133
- case alt
134
- when /\A(--[^=-]+)=(.+)\z/
135
- long, val = $1, val || $2
136
- when /\A(--[^=-]+)\z/
137
- long, val = $1, nil
138
- when /\A(-[^=-]+)=(.+)\z/
139
- short, val = $1, val || $2
140
- when /\A(-[^=-]+)\z/
141
- short, val = $1, nil
142
- else raise ArgumentError, "Unexpected format for option: #{alt.inspect}"
143
- end
158
+ when /\A(--\[no-\][^=]+)\z/
159
+ @long, @val = $1, nil
160
+ when /\A(--[^=]+)=(.+)\z/
161
+ @long, @val = $1, $2 || @val
162
+ when /\A(--[^=]+)\z/
163
+ @long, @val = $1, nil
164
+ when /\A(-[^=-])=?(.+)\z/
165
+ @short, @val = $1, $2 || @val
166
+ when /\A(-[^=-])\z/
167
+ @short, @val = $1, nil
168
+ else
169
+ raise ArgumentError, "Unexpected format for option: #{opt.inspect}"
144
170
  end
145
- @name, @short, @long, @val, @desc, @default, @os, @conv =
146
- name.to_s.to_sym, short, long, val, desc, default, os, conv || lambda{|v|v}
171
+ end
172
+ private :parse_opt_string
173
+
174
+ def initialize cmd, name, opt, *alts, desc, default: NilClass, **os, &conv
175
+ @name, @desc, @default, @os, @conv, @val =
176
+ name.to_s.to_sym, desc, default, os, conv || lambda{|v|v}, nil
177
+ parse_opt_string opt
178
+ alts.each &method( :parse_opt_string)
147
179
  @req =
148
180
  if NilClass != default
149
181
  false
@@ -155,6 +187,7 @@ class DenCli::CMD
155
187
  end
156
188
 
157
189
  def on parser, store
190
+ store[@name] = @default if default?
158
191
  parser.on "#{@short}#{@val ? ?= : ''}#{@val}", "#{@long}#{@val ? ?= : ''}#{@val}", **@os do |val|
159
192
  store[@name] = @conv[val]
160
193
  end
data/lib/dencli/sub.rb CHANGED
@@ -4,6 +4,9 @@ class DenCli::Sub
4
4
  attr_reader :parent, :name, :description, :subs, :aliases
5
5
 
6
6
  def initialize parent, name, description
7
+ #DenCli::assert_type self, __method__, :name, name, Symbol
8
+ #DenCli::assert_type self, __method__, :parent, parent, DenCli, DenCli::Sub
9
+ #DenCli::assert_type self, __method__, :description, description, String
7
10
  @parent, @name, @description, @subs, @aliases = parent, name, "-> #{description}", {}, {}
8
11
  end
9
12
 
@@ -15,16 +18,72 @@ class DenCli::Sub
15
18
  "#{full_cmd.join ' '} ..."
16
19
  end
17
20
 
18
- def help n = nil, *a
21
+ def help n = nil, *a, output: nil
22
+ output ||= ''
23
+ _help output, n, *a
24
+ output
25
+ end
26
+
27
+ def _help output, n = nil, *a
19
28
  if n.nil?
20
- r = "#{full_cmd.join ' '}: #{description}\n\n"
21
- m = @subs.map {|k,c| k.nil? ? 0 : c.usage.length }.max
22
- @subs.each do |k, c|
23
- r += " % -#{m}s %s\n" % [c.usage, c.description] unless k.nil?
24
- end
25
- r
29
+ output << "#{full_cmd.join ' '}: #{description}\n\n"
30
+ self.class._help_commands output, @subs
26
31
  elsif @aliases.has_key? n
27
- @aliases[n].help *a
32
+ @aliases[n]._help output, *a
33
+ else
34
+ raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}"
35
+ end
36
+ end
37
+
38
+ def commands &exe
39
+ yield name, self
40
+ @subs.each {|k, c| c.commands &exe }
41
+ end
42
+
43
+ def help_commands output: nil
44
+ output ||= ''
45
+ self.class._help_commands output, subs.map {|_,c| c}
46
+ output
47
+ end
48
+
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
73
+ end
74
+ end
75
+ prefix = "\n#{' ' * n}"
76
+ end
77
+ output << "\n"
78
+ end
79
+ output
80
+ end
81
+
82
+ def goto *a
83
+ return self if a.empty?
84
+ n, *a = *a
85
+ if @aliases.has_key? n
86
+ @aliases[n].goto *a
28
87
  else
29
88
  raise DenCli::UnknownCommand, "unknown command: #{_full_cmd( [n])[1..-1].join ' '}, available for #{full_cmd[1..-1].join' '}: #{@subs.keys.join ' '}"
30
89
  end
@@ -40,6 +99,10 @@ class DenCli::Sub
40
99
  end
41
100
 
42
101
  def _add name, min, obj, aliases
102
+ #DenCli::assert_type self, __method__, :name, name, Symbol, NilClass
103
+ #DenCli::assert_type self, __method__, :min, min, Integer, NilClass
104
+ #DenCli::assert_type self, __method__, :obj, obj, DenCli::Sub, DenCli::CMD
105
+ #DenCli::assert_type self, __method__, :aliases, aliases, Array, NilClass
43
106
  name = name.to_s unless name.nil?
44
107
  @subs[name] = obj
45
108
  DenCli.gen_aliases( name, min) {|a| @aliases[a] = obj }
@@ -1,3 +1,3 @@
1
1
  class DenCli
2
- VERSION = '0.4.0'
2
+ VERSION = '0.5.3'
3
3
  end
data/lib/dencli.rb CHANGED
@@ -1,6 +1,13 @@
1
1
  require 'optparse'
2
2
 
3
+
3
4
  class DenCli
5
+ def self.assert_type klass, method, argument_name, object, *types
6
+ unless types.any? {|type| object.is_a? type }
7
+ raise ArgumentError, "#{klass.name}.#{method} expects #{types.map( &:to_s).join '|' } for #{argument_name}, not: #{object.inspect}"
8
+ end
9
+ end
10
+
4
11
  class UsageError < ::RuntimeError
5
12
  end
6
13
  class UnknownCommand < UsageError
@@ -80,8 +87,22 @@ class DenCli
80
87
  @subs.call *a
81
88
  end
82
89
 
83
- def help *args
84
- @subs.help *args
90
+ def usage *args, **opts
91
+ @subs.usage *args, **opts
92
+ end
93
+
94
+ def help *args, **opts
95
+ @subs.help *args, **opts
96
+ end
97
+
98
+ def help_full *args, output: nil
99
+ output ||= STDOUT
100
+ x = @subs.goto *args
101
+ _help_full output, x
102
+ end
103
+
104
+ def _help_full output, subs
105
+ Sub._help_commands output, subs.to_enum( :commands)
85
106
  end
86
107
 
87
108
  def [] k
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.4.0
4
+ version: 0.5.3
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-11-30 00:00:00.000000000 Z
11
+ date: 2021-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec