cl 1.0.5 → 1.1.0
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 +5 -5
- data/CHANGELOG.md +7 -1
- data/Gemfile.lock +1 -1
- data/lib/cl.rb +0 -1
- data/lib/cl/cmd.rb +8 -4
- data/lib/cl/errors.rb +25 -3
- data/lib/cl/help/cmd.rb +14 -2
- data/lib/cl/helper.rb +2 -0
- data/lib/cl/helper/suggest.rb +12 -0
- data/lib/cl/opt.rb +83 -20
- data/lib/cl/opts.rb +0 -7
- data/lib/cl/opts/validate.rb +3 -2
- data/lib/cl/parser.rb +20 -29
- data/lib/cl/parser/format.rb +63 -0
- data/lib/cl/runner/default.rb +11 -2
- data/lib/cl/version.rb +1 -1
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 05d4a5fcd74cdf55dbf91276fdd200a5041c4aabef97ffa68849ad63b81b8d30
|
4
|
+
data.tar.gz: 143667a25f93a57662f7271353815f9c6d253055aa45510f666fb37880cdda86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b3a7e08f7c2271b0932b424d66dde47d75c758b579f0fae714bfcd42addf7f2d0cd1a4412b156757071e079b14bb32e9fbd70e43b3fb7a056bfd8efa6e0ab554
|
7
|
+
data.tar.gz: 3b32efded8658b8fce630613b3391157c9b295d8861b9000ed6fa679e8e7bb44904f34e474e6783399476c17dc4adbafd1552c050005f9df19f8323f77075247
|
data/CHANGELOG.md
CHANGED
@@ -1,10 +1,16 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 1.0.5 (2019-08-18)
|
4
|
+
|
5
|
+
### Fixed
|
6
|
+
|
7
|
+
* Fix an issue with alias names that contain the aliased name
|
8
|
+
|
3
9
|
## 1.0.4 (2019-08-15)
|
4
10
|
|
5
11
|
### Fixed
|
6
12
|
|
7
|
-
*
|
13
|
+
* Fix enum when used with `type: :array`
|
8
14
|
|
9
15
|
## 1.0.3 (2019-08-11)
|
10
16
|
|
data/Gemfile.lock
CHANGED
data/lib/cl.rb
CHANGED
data/lib/cl/cmd.rb
CHANGED
@@ -29,8 +29,9 @@ class Cl
|
|
29
29
|
registry.values
|
30
30
|
end
|
31
31
|
|
32
|
-
def parse(ctx, args)
|
33
|
-
|
32
|
+
def parse(ctx, cmd, args)
|
33
|
+
parser = Parser.new(cmd, args)
|
34
|
+
args, opts = parser.args, parser.opts unless self == Help
|
34
35
|
opts = merge(ctx.config[registry_key], opts) if ctx.config[registry_key]
|
35
36
|
[args, opts || {}]
|
36
37
|
end
|
@@ -39,11 +40,10 @@ class Cl
|
|
39
40
|
opt '--help', 'Get help on this command'
|
40
41
|
|
41
42
|
attr_reader :ctx, :args
|
42
|
-
attr_accessor :deprecations
|
43
43
|
|
44
44
|
def initialize(ctx, args)
|
45
|
-
args, opts = self.class.parse(ctx, args)
|
46
45
|
@ctx = ctx
|
46
|
+
args, opts = self.class.parse(ctx, self, args)
|
47
47
|
@opts = self.class.opts.apply(self, self.opts.merge(opts))
|
48
48
|
@args = self.class.args.apply(self, args, opts)
|
49
49
|
end
|
@@ -51,5 +51,9 @@ class Cl
|
|
51
51
|
def opts
|
52
52
|
@opts ||= {}
|
53
53
|
end
|
54
|
+
|
55
|
+
def deprecations
|
56
|
+
@deprecations ||= {}
|
57
|
+
end
|
54
58
|
end
|
55
59
|
end
|
data/lib/cl/errors.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'cl/helper/suggest'
|
2
|
+
|
1
3
|
class Cl
|
2
4
|
class Error < StandardError
|
3
5
|
MSGS = {
|
@@ -23,9 +25,17 @@ class Cl
|
|
23
25
|
OptionError = Class.new(Error)
|
24
26
|
|
25
27
|
class UnknownCmd < Error
|
26
|
-
|
28
|
+
attr_reader :runner, :args
|
29
|
+
|
30
|
+
def initialize(runner, args)
|
31
|
+
@runner = runner
|
32
|
+
@args = args
|
27
33
|
super(:unknown_cmd, args.join(' '))
|
28
34
|
end
|
35
|
+
|
36
|
+
def suggestions
|
37
|
+
runner.suggestions(args)
|
38
|
+
end
|
29
39
|
end
|
30
40
|
|
31
41
|
class RequiredOpts < OptionError
|
@@ -65,9 +75,21 @@ class Cl
|
|
65
75
|
end
|
66
76
|
|
67
77
|
class UnknownValues < OptionError
|
78
|
+
include Suggest
|
79
|
+
|
80
|
+
attr_reader :opts
|
81
|
+
|
68
82
|
def initialize(opts)
|
69
|
-
opts = opts
|
70
|
-
|
83
|
+
@opts = opts
|
84
|
+
opts = opts.map do |(opt, values, known)|
|
85
|
+
pairs = values.map { |value| [opt, value].join('=') }.join(' ')
|
86
|
+
"#{pairs} (known values: #{known.join(', ')})"
|
87
|
+
end
|
88
|
+
super(:unknown_values, opts.join(', '))
|
89
|
+
end
|
90
|
+
|
91
|
+
def suggestions
|
92
|
+
opts.map { |_, value, known| suggest(known, value) }.flatten
|
71
93
|
end
|
72
94
|
end
|
73
95
|
end
|
data/lib/cl/help/cmd.rb
CHANGED
@@ -55,7 +55,7 @@ class Cl
|
|
55
55
|
opts = cmd.opts.to_a
|
56
56
|
opts = opts.reject(&:internal?)
|
57
57
|
opts = opts - cmd.superclass.opts.to_a if common?
|
58
|
-
strs = Table.new(rjust(opts.map { |opt|
|
58
|
+
strs = Table.new(rjust(opts.map { |opt| opt_strs(opt) }))
|
59
59
|
opts = opts.map { |opt| format_obj(opt) }
|
60
60
|
Table.new(strs.rows.zip(opts))
|
61
61
|
end
|
@@ -65,12 +65,24 @@ class Cl
|
|
65
65
|
@cmmn ||= begin
|
66
66
|
opts = cmd.superclass.opts
|
67
67
|
opts = opts.reject(&:internal?)
|
68
|
-
strs = Table.new(rjust(opts.map
|
68
|
+
strs = Table.new(rjust(opts.map(&:strs)))
|
69
69
|
opts = opts.map { |opt| format_obj(opt) }
|
70
70
|
Table.new(strs.rows.zip(opts))
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
def opt_strs(opt)
|
75
|
+
return opt.strs if !opt.flag? || opt.help?
|
76
|
+
opts = [opt.short]
|
77
|
+
opts << negate(opt.long, opt.negate) if opt.long && opt.negate?
|
78
|
+
opts.compact
|
79
|
+
end
|
80
|
+
|
81
|
+
def negate(opt, negations)
|
82
|
+
negations = negations.map { |str| "#{str}-" }.join('|')
|
83
|
+
opt.dup.insert(2, "[#{negations}]")
|
84
|
+
end
|
85
|
+
|
74
86
|
def requireds
|
75
87
|
return unless cmd.required?
|
76
88
|
opts = cmd.required
|
data/lib/cl/helper.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
class Cl
|
2
|
+
module Suggest
|
3
|
+
include DidYouMean if defined?(DidYouMean)
|
4
|
+
|
5
|
+
def suggest(dict, value)
|
6
|
+
return [] unless defined?(DidYouMean)
|
7
|
+
Array(value).map do |value|
|
8
|
+
SpellChecker.new(dictionary: dict.map(&:to_s)).correct(value.to_s)
|
9
|
+
end.flatten
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/cl/opt.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
require 'cl/cast'
|
2
|
+
require 'cl/errors'
|
2
3
|
|
3
4
|
class Cl
|
4
5
|
class Opt < Struct.new(:strs, :opts, :block)
|
5
6
|
include Cast, Regex
|
6
7
|
|
8
|
+
OPTS = %i(
|
9
|
+
alias default deprecated description downcase eg enum example format
|
10
|
+
internal max min negate note required requires secret see sep type upcase
|
11
|
+
)
|
12
|
+
|
7
13
|
OPT = /^--(?:\[.*\])?(.*)$/
|
8
14
|
|
9
15
|
TYPES = {
|
@@ -13,9 +19,11 @@ class Cl
|
|
13
19
|
boolean: :flag
|
14
20
|
}
|
15
21
|
|
16
|
-
|
22
|
+
attr_reader :short, :long
|
23
|
+
|
24
|
+
def initialize(strs, *)
|
17
25
|
super
|
18
|
-
|
26
|
+
@short, @long = Validator.new(strs, opts).apply
|
19
27
|
end
|
20
28
|
|
21
29
|
def define(const)
|
@@ -28,19 +36,22 @@ class Cl
|
|
28
36
|
|
29
37
|
def name
|
30
38
|
return @name if instance_variable_defined?(:@name)
|
31
|
-
|
32
|
-
name = opt.split(' ').first.match(OPT)[1] if opt
|
39
|
+
name = long.split(' ').first.match(OPT)[1] if long
|
33
40
|
@name = name.sub('-', '_').to_sym if name
|
34
41
|
end
|
35
42
|
|
36
43
|
def type
|
37
|
-
TYPES[opts[:type]] || opts[:type] || infer_type
|
44
|
+
@type ||= TYPES[opts[:type]] || opts[:type] || infer_type
|
38
45
|
end
|
39
46
|
|
40
47
|
def infer_type
|
41
48
|
strs.any? { |str| str.split(' ').size > 1 } ? :string : :flag
|
42
49
|
end
|
43
50
|
|
51
|
+
def help?
|
52
|
+
name == :help
|
53
|
+
end
|
54
|
+
|
44
55
|
def flag?
|
45
56
|
type == :flag
|
46
57
|
end
|
@@ -65,13 +76,16 @@ class Cl
|
|
65
76
|
opts[:description]
|
66
77
|
end
|
67
78
|
|
68
|
-
def deprecated?
|
69
|
-
!!opts[:deprecated]
|
79
|
+
def deprecated?(name = nil)
|
80
|
+
name ? deprecated.first == name : !!opts[:deprecated]
|
70
81
|
end
|
71
82
|
|
72
83
|
def deprecated
|
84
|
+
# If it's a string then it's a deprecation message and the option itself
|
85
|
+
# is considered deprecated. If it's a symbol it refers to a deprecated
|
86
|
+
# alias, and the option's name is the deprecation message.
|
73
87
|
return [name, opts[:deprecated]] unless opts[:deprecated].is_a?(Symbol)
|
74
|
-
[opts[:deprecated], name]
|
88
|
+
opts[:deprecated] ? [opts[:deprecated], name] : []
|
75
89
|
end
|
76
90
|
|
77
91
|
def downcase?
|
@@ -99,6 +113,11 @@ class Cl
|
|
99
113
|
enum.any? { |obj| obj.is_a?(Regexp) ? obj =~ value.to_s : obj == value }
|
100
114
|
end
|
101
115
|
|
116
|
+
def unknown(value)
|
117
|
+
return value.reject { |value| known?(value) } if value.is_a?(Array)
|
118
|
+
known?(value) ? [] : Array(value)
|
119
|
+
end
|
120
|
+
|
102
121
|
def example?
|
103
122
|
!!opts[:example]
|
104
123
|
end
|
@@ -141,11 +160,11 @@ class Cl
|
|
141
160
|
end
|
142
161
|
|
143
162
|
def negate?
|
144
|
-
!!
|
163
|
+
!!negate
|
145
164
|
end
|
146
165
|
|
147
166
|
def negate
|
148
|
-
Array(opts[:negate])
|
167
|
+
['no'] + Array(opts[:negate]) if flag?
|
149
168
|
end
|
150
169
|
|
151
170
|
def note?
|
@@ -193,19 +212,63 @@ class Cl
|
|
193
212
|
super || method(:assign)
|
194
213
|
end
|
195
214
|
|
196
|
-
def assign(opts, type,
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
215
|
+
def assign(opts, type, _, value)
|
216
|
+
[name, *aliases].each do |name|
|
217
|
+
if array?
|
218
|
+
opts[name] ||= []
|
219
|
+
opts[name] << value
|
220
|
+
else
|
221
|
+
opts[name] = value
|
222
|
+
end
|
202
223
|
end
|
203
224
|
end
|
204
225
|
|
205
|
-
def
|
206
|
-
|
207
|
-
|
208
|
-
|
226
|
+
def long?(str)
|
227
|
+
str.start_with?('--')
|
228
|
+
end
|
229
|
+
|
230
|
+
class Validator < Struct.new(:strs, :opts)
|
231
|
+
SHORT = /^-\w( \w+)?$/
|
232
|
+
LONG = /^--[\w\-\[\]]+( \w+)?$/
|
233
|
+
|
234
|
+
MSGS = {
|
235
|
+
missing_strs: 'No option strings given. Pass one short -s and/or one --long option string.',
|
236
|
+
wrong_strs: 'Wrong option strings given. Pass one short -s and/or one --long option string.',
|
237
|
+
invalid_strs: 'Invalid option strings given: %p',
|
238
|
+
unknown_opts: 'Unknown options: %s'
|
239
|
+
}
|
240
|
+
|
241
|
+
def apply
|
242
|
+
error :missing_strs if strs.empty?
|
243
|
+
error :wrong_strs if short.size > 1 || long.size > 1
|
244
|
+
error :invalid_strs, invalid unless invalid.empty?
|
245
|
+
error :unknown_opts, unknown.map(&:inspect).join(', ') unless unknown.empty?
|
246
|
+
[short.first, long.first]
|
247
|
+
end
|
248
|
+
|
249
|
+
def unknown
|
250
|
+
@unknown ||= opts.keys - Opt::OPTS
|
251
|
+
end
|
252
|
+
|
253
|
+
def invalid
|
254
|
+
@invalid ||= strs.-(valid).join(', ')
|
255
|
+
end
|
256
|
+
|
257
|
+
def valid
|
258
|
+
strs.grep(Regexp.union(SHORT, LONG))
|
259
|
+
end
|
260
|
+
|
261
|
+
def short
|
262
|
+
strs.grep(SHORT)
|
263
|
+
end
|
264
|
+
|
265
|
+
def long
|
266
|
+
strs.grep(LONG)
|
267
|
+
end
|
268
|
+
|
269
|
+
def error(key, *args)
|
270
|
+
raise Cl::Error, MSGS[key] % args
|
271
|
+
end
|
209
272
|
end
|
210
273
|
end
|
211
274
|
end
|
data/lib/cl/opts.rb
CHANGED
@@ -18,7 +18,6 @@ class Cl
|
|
18
18
|
def apply(cmd, opts)
|
19
19
|
return opts if opts[:help]
|
20
20
|
orig = opts.dup
|
21
|
-
cmd.deprecations = deprecations(cmd, opts)
|
22
21
|
opts = defaults(cmd, opts)
|
23
22
|
opts = downcase(opts)
|
24
23
|
opts = upcase(opts)
|
@@ -66,12 +65,6 @@ class Cl
|
|
66
65
|
|
67
66
|
private
|
68
67
|
|
69
|
-
def deprecations(cmd, opts)
|
70
|
-
defs = cmd.class.opts.select(&:deprecated?)
|
71
|
-
defs = defs.select { |opt| opts.key?(opt.deprecated[0]) }
|
72
|
-
defs.map(&:deprecated).to_h
|
73
|
-
end
|
74
|
-
|
75
68
|
def defaults(cmd, opts)
|
76
69
|
select(&:default?).inject(opts) do |opts, opt|
|
77
70
|
next opts if opts.key?(opt.name)
|
data/lib/cl/opts/validate.rb
CHANGED
@@ -86,9 +86,10 @@ class Cl
|
|
86
86
|
|
87
87
|
def unknown
|
88
88
|
@unknown ||= opts.select(&:enum?).map do |opt|
|
89
|
-
|
89
|
+
unknown = opt.unknown(values[opt.name])
|
90
|
+
next if unknown.empty?
|
90
91
|
known = opt.enum.map { |str| format_regex(str) }
|
91
|
-
[opt.name,
|
92
|
+
[opt.name, unknown, known]
|
92
93
|
end.compact
|
93
94
|
end
|
94
95
|
end
|
data/lib/cl/parser.rb
CHANGED
@@ -1,47 +1,35 @@
|
|
1
1
|
require 'optparse'
|
2
|
+
require 'cl/parser/format'
|
2
3
|
|
3
4
|
class Cl
|
4
5
|
class Parser < OptionParser
|
5
|
-
attr_reader :opts
|
6
|
+
attr_reader :cmd, :args, :opts
|
6
7
|
|
7
|
-
def initialize(
|
8
|
+
def initialize(cmd, args)
|
9
|
+
@cmd = cmd
|
8
10
|
@opts = {}
|
11
|
+
opts = cmd.class.opts
|
9
12
|
|
10
13
|
super do
|
11
14
|
opts.each do |opt|
|
12
|
-
|
13
|
-
set(opt, value)
|
14
|
-
end
|
15
|
-
|
16
|
-
opt.aliases.each do |name|
|
17
|
-
on(*args_for(opt, [aliased(opt, name)])) do |value|
|
18
|
-
@opts[name] = set(opt, value)
|
19
|
-
end
|
15
|
+
Format.new(opt).strs.each do |str|
|
16
|
+
on(str) { |value| set(opt, str, value) }
|
20
17
|
end
|
21
18
|
end
|
22
19
|
end
|
23
20
|
|
24
|
-
args.
|
25
|
-
parse!(args)
|
26
|
-
end
|
27
|
-
|
28
|
-
def args_for(opt, strs)
|
29
|
-
args = dasherize(strs)
|
30
|
-
args = flagerize(args) if opt.flag?
|
31
|
-
args
|
32
|
-
end
|
33
|
-
|
34
|
-
def aliased(opt, name)
|
35
|
-
str = opt.strs.detect { |str| str.start_with?('--') } || raise
|
36
|
-
str.sub(/(#{opt.name}|#{opt.name.to_s.gsub('_', '-')})/, name.to_s)
|
21
|
+
orig = args.map(&:dup)
|
22
|
+
@args = parse!(normalize(opts, args))
|
37
23
|
end
|
38
24
|
|
39
25
|
# should consider negative arities (e.g. |one, *two|)
|
40
|
-
def set(opt, value)
|
26
|
+
def set(opt, str, value)
|
27
|
+
name = long?(str) ? opt_name(str) : opt.name
|
41
28
|
value = true if value.nil? && opt.flag?
|
42
|
-
args = [opts, opt.type,
|
29
|
+
args = [opts, opt.type, name, value]
|
43
30
|
args = args[-opt.block.arity, opt.block.arity]
|
44
31
|
instance_exec(*args, &opt.block)
|
32
|
+
cmd.deprecations[name] = opt.deprecated.last if opt.deprecated?(name)
|
45
33
|
end
|
46
34
|
|
47
35
|
def normalize(opts, args)
|
@@ -57,7 +45,7 @@ class Cl
|
|
57
45
|
end
|
58
46
|
|
59
47
|
def negation(opts, arg)
|
60
|
-
opts.detect do |opt|
|
48
|
+
opts.select(&:flag?).detect do |opt|
|
61
49
|
str = opt.negate.detect { |str| arg =~ /^--#{str}[-_]+#{opt.name}/ }
|
62
50
|
break str if str
|
63
51
|
end
|
@@ -71,9 +59,12 @@ class Cl
|
|
71
59
|
end
|
72
60
|
end
|
73
61
|
|
74
|
-
def
|
75
|
-
|
76
|
-
|
62
|
+
def long?(str)
|
63
|
+
str.start_with?('--')
|
64
|
+
end
|
65
|
+
|
66
|
+
def opt_name(str)
|
67
|
+
str.split(' ').first.sub(/--(\[no[_\-]\])?/, '').to_sym
|
77
68
|
end
|
78
69
|
end
|
79
70
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class Cl
|
2
|
+
class Parser < OptionParser
|
3
|
+
class Format < Struct.new(:opt)
|
4
|
+
NAME = /^(--(?:\[no-\])?)([^= ]+)/
|
5
|
+
|
6
|
+
def strs
|
7
|
+
strs = opt.strs + aliases
|
8
|
+
strs.map { |str| long?(str) ? long(str) : short(str) }.flatten
|
9
|
+
end
|
10
|
+
|
11
|
+
def long(str)
|
12
|
+
strs = [unnegate(str)]
|
13
|
+
strs = strs.map { |str| negated(str) }.flatten if flag?
|
14
|
+
strs = collect(strs, :dashed)
|
15
|
+
strs = collect(strs, :underscored)
|
16
|
+
strs = collect(strs, :valued) if flag?
|
17
|
+
strs.uniq
|
18
|
+
end
|
19
|
+
|
20
|
+
def short(str)
|
21
|
+
str = "#{str} #{opt.name.upcase}" unless opt.flag? || str.include?(' ')
|
22
|
+
str
|
23
|
+
end
|
24
|
+
|
25
|
+
def unnegate(str)
|
26
|
+
str.sub('--[no-]', '--')
|
27
|
+
end
|
28
|
+
|
29
|
+
def aliases
|
30
|
+
opt.aliases.map { |name| "--#{name} #{ name.upcase unless opt.flag?}".strip }
|
31
|
+
end
|
32
|
+
|
33
|
+
def collect(strs, mod)
|
34
|
+
strs = strs + strs.map { |str| send(mod, str) }
|
35
|
+
strs.flatten.uniq
|
36
|
+
end
|
37
|
+
|
38
|
+
def negated(str)
|
39
|
+
str.dup.insert(2, '[no-]')
|
40
|
+
end
|
41
|
+
|
42
|
+
def dashed(str)
|
43
|
+
str =~ NAME && str.sub("#{$1}#{$2}", "#{$1}#{$2.tr('_', '-')}") || str
|
44
|
+
end
|
45
|
+
|
46
|
+
def underscored(str)
|
47
|
+
str =~ NAME && str.sub("#{$1}#{$2}", "#{$1}#{$2.tr('-', '_')}") || str
|
48
|
+
end
|
49
|
+
|
50
|
+
def valued(str)
|
51
|
+
"#{str} [true|false|yes|no]"
|
52
|
+
end
|
53
|
+
|
54
|
+
def long?(str)
|
55
|
+
str.start_with?('--')
|
56
|
+
end
|
57
|
+
|
58
|
+
def flag?
|
59
|
+
opt.flag? && !opt.help?
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/cl/runner/default.rb
CHANGED
@@ -8,7 +8,7 @@ class Cl
|
|
8
8
|
Runner.register :default, self
|
9
9
|
|
10
10
|
extend Forwardable
|
11
|
-
include Merge
|
11
|
+
include Merge, Suggest
|
12
12
|
|
13
13
|
def_delegators :ctx, :abort
|
14
14
|
|
@@ -31,6 +31,11 @@ class Cl
|
|
31
31
|
Help.new(ctx, [cmd.registry_key])
|
32
32
|
end
|
33
33
|
|
34
|
+
def suggestions(args)
|
35
|
+
keys = args.inject([]) { |keys, arg| keys << [keys.last, arg].compact.join(':') }
|
36
|
+
keys.map { |key| suggest(providers.map(&:to_s), key) }.flatten
|
37
|
+
end
|
38
|
+
|
34
39
|
private
|
35
40
|
|
36
41
|
# Finds a command class to run for the given arguments.
|
@@ -63,10 +68,14 @@ class Cl
|
|
63
68
|
end
|
64
69
|
|
65
70
|
cmd, keys = keys[0].last
|
66
|
-
|
71
|
+
raise UnknownCmd.new(self, args) unless cmd
|
67
72
|
keys.each { |key| args.delete_at(args.index(key)) }
|
68
73
|
[cmd, args]
|
69
74
|
end
|
75
|
+
|
76
|
+
def providers
|
77
|
+
Cmd.registry.keys
|
78
|
+
end
|
70
79
|
end
|
71
80
|
end
|
72
81
|
end
|
data/lib/cl/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sven Fuchs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-08-
|
11
|
+
date: 2019-08-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: regstry
|
@@ -140,10 +140,12 @@ files:
|
|
140
140
|
- lib/cl/help/table.rb
|
141
141
|
- lib/cl/help/usage.rb
|
142
142
|
- lib/cl/helper.rb
|
143
|
+
- lib/cl/helper/suggest.rb
|
143
144
|
- lib/cl/opt.rb
|
144
145
|
- lib/cl/opts.rb
|
145
146
|
- lib/cl/opts/validate.rb
|
146
147
|
- lib/cl/parser.rb
|
148
|
+
- lib/cl/parser/format.rb
|
147
149
|
- lib/cl/runner.rb
|
148
150
|
- lib/cl/runner/default.rb
|
149
151
|
- lib/cl/runner/multi.rb
|
@@ -168,8 +170,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
168
170
|
- !ruby/object:Gem::Version
|
169
171
|
version: '0'
|
170
172
|
requirements: []
|
171
|
-
|
172
|
-
rubygems_version: 2.6.13
|
173
|
+
rubygems_version: 3.0.3
|
173
174
|
signing_key:
|
174
175
|
specification_version: 4
|
175
176
|
summary: Object-oriented OptionParser based CLI support
|