nub 0.0.51 → 0.0.52
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 +4 -4
- data/README.md +16 -14
- data/lib/nub/commander.rb +60 -39
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dbb6012caafc7ba2ef97052b8f8577ab631565d7b5964e111f2a02b52139c092
|
4
|
+
data.tar.gz: 29895378b9e02eae31af58d792c36406fbee2cc5759ab84dca4ede07bf7015d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2274e48efc5268a48fb3690fa0e85d487dbe69516160bd34fee2f76d10557ba72a1d8fdb42255846b14b1186df0ade53fa51cccec05abf093de17b1ed25964f0
|
7
|
+
data.tar.gz: 8c74aa5a469e44d0e710143ea3f553cf8d44133dfffc0129d0ccd18ccd4cf2029b2af4b512dae512ec35593a953e4f56bd8d4d6109db65ce0d46a8452a563211
|
data/README.md
CHANGED
@@ -46,15 +46,16 @@ more in a single command line expression. Each command in a chained command expr
|
|
46
46
|
own specific options (those coming after the command but before the next command) or if options are
|
47
47
|
omitted the required options from the next command will be used. The chained command options syntax
|
48
48
|
allows one to have a cleaner multi-command line expression with reusable options. Options are said
|
49
|
-
to apply in a chained command syntax when they are of the same type in the positional
|
50
|
-
type and name in the named case.
|
49
|
+
to apply in a chained command syntax when they are of the same type and position in the positional
|
50
|
+
case or same type and name in the named case.
|
51
51
|
|
52
52
|
***Global*** options are options that are added with the ***add_global*** function and will show up
|
53
|
-
set in the
|
54
|
-
|
53
|
+
set in the command results using the ***:global*** symbol. Global positional options must be given
|
54
|
+
before any other commands but global named options may appear anywhere in the command line
|
55
|
+
expression.
|
55
56
|
|
56
|
-
***Shared*** options are options that are added with the command ***add_shared*** function
|
57
|
-
any commands
|
57
|
+
***Shared*** options are options that are added with the command ***add_shared*** function. They
|
58
|
+
should be added before any commands are added. They are added to each command as an explicit option.
|
58
59
|
|
59
60
|
***Commander.new*** must be run from the app's executable file for it to pick up the app's filename
|
60
61
|
properly.
|
@@ -100,14 +101,15 @@ Example command line expressions:
|
|
100
101
|
### Options <a name="options"></a>
|
101
102
|
There are two kinds of options available for use, ***positional*** and ***named***. Positional
|
102
103
|
options are identified by the absence of preceding dash/dashes and interpreted according to the
|
103
|
-
order in which they were found. Positional options are a value being passed into the
|
104
|
-
Named options have a name that is prefixed with a dash (short hand) or two dashes
|
105
|
-
***-h*** or ***--help*** and may simply be a flag or pass in a value. Option
|
106
|
-
***type*** so that Commander can interpret how to use them. The supported value
|
107
|
-
***Flag, Integer, String, Array***. Values may be checked or not checked via the
|
108
|
-
config param. Positional options default to type String while named options default to
|
109
|
-
Positional options are named internally with the command concatted with a an int for
|
110
|
-
clean0*** zero based. Positional
|
104
|
+
order and number in which they were found. Positional options are a value being passed into the
|
105
|
+
application. Named options have a name that is prefixed with a dash (short hand) or two dashes
|
106
|
+
(long hand) e.g. ***-h*** or ***--help*** and may simply be a flag or pass in a value. Option
|
107
|
+
values require a ***type*** so that Commander can interpret how to use them. The supported value
|
108
|
+
types are ***Flag, Integer, String, Array***. Values may be checked or not checked via the
|
109
|
+
***allowed*** config param. Positional options default to type String while named options default to
|
110
|
+
type Flag. Positional options are named internally with the command concatted with a an int for
|
111
|
+
order ***e.g. clean0*** zero based. Positional options are given sequentially so you can't
|
112
|
+
skip one and specify the second, it must be one then two etc...
|
111
113
|
|
112
114
|
**Long Hand** form is always required for named options, short hand may or may not be given.
|
113
115
|
|
data/lib/nub/commander.rb
CHANGED
@@ -32,8 +32,8 @@ class Option
|
|
32
32
|
attr_reader(:hint)
|
33
33
|
attr_reader(:desc)
|
34
34
|
attr_reader(:type)
|
35
|
-
|
36
|
-
|
35
|
+
attr_accessor(:allowed)
|
36
|
+
attr_accessor(:required)
|
37
37
|
attr_accessor(:shared)
|
38
38
|
|
39
39
|
# Create a new option instance
|
@@ -62,9 +62,6 @@ class Option
|
|
62
62
|
@hint = key[/.*=(.*)$/, 1]
|
63
63
|
@short = key[/^(-\w).*$/, 1]
|
64
64
|
@long = key[/(--[\w\-]+)(=.+)*$/, 1]
|
65
|
-
else
|
66
|
-
# Always require positional options
|
67
|
-
@required = true
|
68
65
|
end
|
69
66
|
|
70
67
|
# Validate and set type
|
@@ -74,6 +71,9 @@ class Option
|
|
74
71
|
@type = FalseClass if key and !type
|
75
72
|
@type = type if type
|
76
73
|
|
74
|
+
# Validate hint is given for non flags
|
75
|
+
Log.die("option hint must be set") if @key && !@hint && @type != FalseClass
|
76
|
+
|
77
77
|
# Validate allowed
|
78
78
|
if @allowed.any?
|
79
79
|
allowed_type = @allowed.first.class
|
@@ -169,6 +169,7 @@ class Commander
|
|
169
169
|
Log.die("duplicate shared option '#{x.desc}' given") if @shared
|
170
170
|
.any?{|y| y.key == x.key && y.desc == x.desc && y.type == x.type}
|
171
171
|
x.shared = true
|
172
|
+
x.required = true
|
172
173
|
@shared << x
|
173
174
|
}
|
174
175
|
end
|
@@ -209,51 +210,25 @@ class Commander
|
|
209
210
|
# Process command options
|
210
211
|
#---------------------------------------------------------------------------
|
211
212
|
order_globals!
|
213
|
+
expand_chained_options!
|
212
214
|
loop {
|
213
215
|
break if ARGV.first.nil?
|
214
216
|
|
215
217
|
if !(cmd = @config.find{|x| x.name == ARGV.first}).nil?
|
216
|
-
@cmds[ARGV.shift.to_sym] = {}
|
217
|
-
cmd_names.reject!{|x| x == cmd.name}
|
218
|
-
|
219
|
-
# Command options as defined in configuration
|
220
|
-
cmd_pos_opts = cmd.opts.select{|x| x.key.nil? }
|
221
|
-
cmd_named_opts = cmd.opts.select{|x| !x.key.nil? }
|
218
|
+
@cmds[ARGV.shift.to_sym] = {} # Create command results entry
|
219
|
+
cmd_names.reject!{|x| x == cmd.name} # Remove command from possible commands
|
222
220
|
|
223
221
|
# Collect command options from args to compare against
|
224
222
|
opts = ARGV.take_while{|x| !cmd_names.include?(x) }
|
225
223
|
ARGV.shift(opts.size)
|
224
|
+
|
225
|
+
# Check that all required options were given
|
226
|
+
cmd_pos_opts = cmd.opts.select{|x| x.key.nil? }
|
227
|
+
cmd_named_opts = cmd.opts.select{|x| !x.key.nil? }
|
226
228
|
|
227
|
-
# All positional options are required. If they are not given then check for the 'chained
|
228
|
-
# command expression' case for positional options in the next command that satisfy the
|
229
|
-
# previous command's requirements and so on and so forth.
|
230
|
-
if opts.size == 0 && (cmd_pos_opts.any? || cmd_named_opts.any?{|x| x.required})
|
231
|
-
i = 0
|
232
|
-
while (i += 1) < ARGV.size do
|
233
|
-
opts = ARGV[i..-1].take_while{|x| !cmd_names.include?(x) }
|
234
|
-
break if opts.any?
|
235
|
-
end
|
236
|
-
|
237
|
-
# Check that the chained command options at least match types and size
|
238
|
-
if opts.any?
|
239
|
-
cmd_required = cmd.opts.select{|x| x.key.nil? || x.required}
|
240
|
-
other = @config.find{|x| x.name == ARGV[i-1]}
|
241
|
-
other_required = other.opts.select{|x| x.key.nil? || x.required}
|
242
|
-
|
243
|
-
!puts("Error: chained commands must have equal numbers of required options!".colorize(:red)) && !puts(cmd.help) and
|
244
|
-
exit if cmd_required.size != other_required.size
|
245
|
-
cmd_required.each_with_index{|x,i|
|
246
|
-
!puts("Error: chained command options are not type consistent!".colorize(:red)) && !puts(cmd.help) and
|
247
|
-
exit if x.type != other_required[i].type || x.key != other_required[i].key
|
248
|
-
}
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
# Check that all positional options were given
|
253
229
|
!puts("Error: positional option required!".colorize(:red)) && !puts(cmd.help) and
|
254
|
-
exit if opts.size < cmd_pos_opts.size
|
230
|
+
exit if opts.select{|x| !x.start_with?('-')}.size < cmd_pos_opts.select{|x| x.required}.size
|
255
231
|
|
256
|
-
# Check that all required named options where given
|
257
232
|
named_opts = opts.select{|x| x.start_with?('-')}
|
258
233
|
cmd_named_opts.select{|x| x.required}.each{|x|
|
259
234
|
!puts("Error: required option #{x.key} not given!".colorize(:red)) && !puts(cmd.help) and
|
@@ -369,6 +344,52 @@ class Commander
|
|
369
344
|
end
|
370
345
|
end
|
371
346
|
|
347
|
+
# Find chained options, copy and insert as needed.
|
348
|
+
# Globals should have already been ordered before calling this function
|
349
|
+
# Fail if validation doesn't pass
|
350
|
+
def expand_chained_options!
|
351
|
+
args = ARGV[0..-1]
|
352
|
+
results = {}
|
353
|
+
cmd_names = @config.map{|x| x.name }
|
354
|
+
|
355
|
+
chained = []
|
356
|
+
while args.any? do
|
357
|
+
if !(cmd = @config.find{|x| x.name == args.first}).nil?
|
358
|
+
results[args.shift] = [] # Add the command to the results
|
359
|
+
cmd_names.reject!{|x| x == cmd.name} # Remove command from possible commands
|
360
|
+
cmd_required = cmd.opts.select{|x| x.required}
|
361
|
+
|
362
|
+
# Collect command options from args to compare against
|
363
|
+
opts = args.take_while{|x| !cmd_names.include?(x)}
|
364
|
+
args.shift(opts.size)
|
365
|
+
|
366
|
+
# Globals are not to be considered for chaining
|
367
|
+
results[cmd.name].concat(opts) and next if cmd.name == 'global'
|
368
|
+
|
369
|
+
# Chained case is when no options are given but some are required
|
370
|
+
if opts.size == 0 && cmd.opts.any?{|x| x.required}
|
371
|
+
chained << cmd
|
372
|
+
else
|
373
|
+
results[cmd.name].concat(opts)
|
374
|
+
|
375
|
+
chained.each{|x|
|
376
|
+
other_required = x.opts.select{|x| x.required}
|
377
|
+
!puts("Error: chained commands must have equal numbers of required options!".colorize(:red)) && !puts(x.help) and
|
378
|
+
exit if cmd_required.size != other_required.size
|
379
|
+
cmd_required.each_with_index{|y,i|
|
380
|
+
!puts("Error: chained command options are not type consistent!".colorize(:red)) && !puts(x.help) and
|
381
|
+
exit if y.type != other_required[i].type || y.key != other_required[i].key
|
382
|
+
}
|
383
|
+
results[x.name].concat(opts)
|
384
|
+
}
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
|
389
|
+
# Set results as new ARGV command line expression
|
390
|
+
ARGV.clear and results.each{|k, v| ARGV << k; ARGV.concat(v)}
|
391
|
+
end
|
392
|
+
|
372
393
|
# Match the given command line arg with a configured named option
|
373
394
|
# @param opt [String] the command line argument given
|
374
395
|
# @param cmd [Command] configured command to match against
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nub
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.52
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Patrick Crummett
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-04-
|
11
|
+
date: 2018-04-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|