dencli 0.4.0 → 0.5.3

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