nub 0.0.50 → 0.0.51

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/lib/nub/commander.rb +113 -50
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 627778afb0e5b413aa85a3b1a7182e8a15d81b8c084733cf89f477e7c92e9a0f
4
- data.tar.gz: f7f523646f54628242273367e2eb9803dd3f586f31a283797bb176cecd00da34
3
+ metadata.gz: c58496cf243b60e9ca662e07c1e8c30a0dba10bb6cd290d748df9b9f93d7897b
4
+ data.tar.gz: 5a918972eb7de66173b9c2ec31eccb396804a900d2cf3b25cb9b3c046e863256
5
5
  SHA512:
6
- metadata.gz: afecc349dd342d53a177078bfaae6cda4ef69482a1c3ee68598337692ad3d70e7688aecf3140349ec839a5c5d3bf132ebe64e64fce0be53c9777a1550f5ef87f
7
- data.tar.gz: daf23c611f74974a8704afb8da1f6f8e26422942e31218e1bd05609eacbce81c4dd99d9428373bd5ff00bf0161f1f8b68d4ebadbd91ac12f323f78a1a5f18f66
6
+ metadata.gz: 4eefd3a45e934ebc542d862ab1e867c3e88d8eb3f07fa5de50d525e305cb22e594027ba9523c280480ceaa37c62fe4021d2a4d820edcf8001ff8f49cb1dfa7e6
7
+ data.tar.gz: 53ae4e3e35ef1c7d496539bb2fb4649b79c021a663bddc6411d671ee10ea10ed9ed7af62f1152597ecdd97792f1bc9ea78e495871426bc1592acb607014635b4
data/README.md CHANGED
@@ -51,7 +51,7 @@ 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
53
  set in the commands results using the ***:global*** symbol. Global options are given on the command
54
- line before anything else.
54
+ line before anything else in the case of positional, but anywhere in the case of named.
55
55
 
56
56
  ***Shared*** options are options that are added with the command ***add_shared*** function before
57
57
  any commands and are added to all commands.
data/lib/nub/commander.rb CHANGED
@@ -174,7 +174,7 @@ class Commander
174
174
  end
175
175
 
176
176
  # Returns banner string
177
- # @returns [String] the app's banner
177
+ # @return [String] the app's banner
178
178
  def banner
179
179
  version = @version.nil? ? "" : "_v#{@version}"
180
180
  banner = "#{@app}#{version}\n#{'-' * 80}".colorize(:light_yellow)
@@ -182,7 +182,7 @@ class Commander
182
182
  end
183
183
 
184
184
  # Return the app's help string
185
- # @returns [String] the app's help string
185
+ # @return [String] the app's help string
186
186
  def help
187
187
  help = @app.nil? ? "" : "#{banner}\n"
188
188
  if !@examples.nil? && !@examples.empty?
@@ -201,17 +201,14 @@ class Commander
201
201
 
202
202
  # Construct the command line parser and parse
203
203
  def parse!
204
+ cmd_names = @config.map{|x| x.name }
204
205
 
205
206
  # Set help if nothing was given
206
207
  ARGV.clear and ARGV << '-h' if ARGV.empty?
207
-
208
- # Process global options
209
- #---------------------------------------------------------------------------
210
- cmd_names = @config.map{|x| x.name }
211
- ARGV.unshift('global') if @config.find{|x| x.name == 'global'}
212
208
 
213
209
  # Process command options
214
210
  #---------------------------------------------------------------------------
211
+ order_globals!
215
212
  loop {
216
213
  break if ARGV.first.nil?
217
214
 
@@ -275,26 +272,15 @@ class Commander
275
272
  # Validate/set named options
276
273
  # --------------------------------------------------------------------
277
274
  # e.g. -s, --skip, --skip=VALUE
278
- if opt.start_with?('-')
279
- short = opt[@short_regex, 1]
280
- long = opt[@long_regex, 1]
281
- value = opt[@value_regex, 1]
282
-
283
- # Set symbol converting dashes to underscores for named options
284
- if (cmd_opt = cmd_named_opts.find{|x| x.short == short || x.long == long})
285
- sym = cmd_opt.long[2..-1].gsub("-", "_").to_sym
286
-
287
- # Handle help for the command
288
- !puts(help) and exit if cmd.name == 'global' && sym == :help
289
- !puts(cmd.help) and exit if sym == :help
290
-
291
- # Collect value
292
- if cmd_opt.type == FalseClass
293
- value = true if !value
294
- elsif !value
295
- value = opts.shift
296
- end
297
- end
275
+ if (match = match_named(opt, cmd)).hit?
276
+ sym = match.sym
277
+ cmd_opt = match.opt
278
+ value = match.value
279
+ value = match.flag? || opts.shift if !value
280
+
281
+ # Handle help for the command
282
+ !puts(help) and exit if cmd.name == 'global' && match.sym == :help
283
+ !puts(cmd.help) and exit if match.sym == :help
298
284
 
299
285
  # Validate/set positional options
300
286
  # --------------------------------------------------------------------
@@ -309,28 +295,7 @@ class Commander
309
295
 
310
296
  # Convert value to appropriate type and validate against allowed
311
297
  # --------------------------------------------------------------------
312
- if value
313
- if cmd_opt.type == String
314
- if cmd_opt.allowed.any?
315
- !puts("Error: invalid string value '#{value}'!".colorize(:red)) && !puts(cmd.help) and
316
- exit if !cmd_opt.allowed.include?(value)
317
- end
318
- elsif cmd_opt.type == Integer
319
- value = value.to_i
320
- if cmd_opt.allowed.any?
321
- !puts("Error: invalid integer value '#{value}'!".colorize(:red)) && !puts(cmd.help) and
322
- exit if !cmd_opt.allowed.include?(value)
323
- end
324
- elsif cmd_opt.type == Array
325
- value = value.split(',')
326
- if cmd_opt.allowed.any?
327
- value.each{|x|
328
- !puts("Error: invalid array value '#{x}'!".colorize(:red)) && !puts(cmd.help) and
329
- exit if !cmd_opt.allowed.include?(x)
330
- }
331
- end
332
- end
333
- end
298
+ value = convert_value(value, cmd, cmd_opt)
334
299
 
335
300
  # Set option with value
336
301
  # --------------------------------------------------------------------
@@ -360,12 +325,110 @@ class Commander
360
325
  # Private methods
361
326
  #-----------------------------------------------------------------------------
362
327
  private
328
+ OptionMatch = Struct.new(:arg, :sym, :value, :opt) do
329
+ def hit?
330
+ return !!sym
331
+ end
332
+ def flag?
333
+ return opt.type == FalseClass
334
+ end
335
+ end
336
+
337
+ # Parses the command line, moving all global options to the begining
338
+ # and inserting the global command
339
+ def order_globals!
340
+ if !(global_cmd = @config.find{|x| x.name == 'global'}).nil?
341
+ ARGV.delete('global')
342
+
343
+ # Collect positional and named options from begining
344
+ globals = ARGV.take_while{|x| !@config.any?{|y| y.name == x}}
345
+ ARGV.shift(globals.size)
346
+
347
+ # Collect named options throughout
348
+ i = -1
349
+ cmd = nil
350
+ while (i += 1) < ARGV.size do
351
+
352
+ # Set command and skip command and matching options
353
+ if !(_cmd = @config.find{|x| x.name == ARGV[i]}).nil?
354
+ cmd = _cmd; next
355
+ end
356
+ next if cmd && match_named(ARGV[i], cmd).hit?
357
+
358
+ # Collect global matches
359
+ if (match = match_named(ARGV[i], global_cmd)).hit?
360
+ globals << ARGV.delete_at(i)
361
+ globals << ARGV.delete_at(i) if !match.flag?
362
+ i -= 1
363
+ end
364
+ end
365
+
366
+ # Re-insert options in correct order at end with command
367
+ globals.reverse.each{|x| ARGV.unshift(x)}
368
+ ARGV.unshift('global')
369
+ end
370
+ end
371
+
372
+ # Match the given command line arg with a configured named option
373
+ # @param opt [String] the command line argument given
374
+ # @param cmd [Command] configured command to match against
375
+ # @return [OptionMatch]] struct with some helper functions
376
+ def match_named(opt, cmd)
377
+ match = OptionMatch.new(opt)
378
+ cmd_named_opts = cmd.opts.select{|x| !x.key.nil? }
379
+
380
+ if opt.start_with?('-')
381
+ short = opt[@short_regex, 1]
382
+ long = opt[@long_regex, 1]
383
+ match.value = opt[@value_regex, 1]
384
+
385
+ # Set symbol converting dashes to underscores for named options
386
+ if (cmd_opt = cmd_named_opts.find{|x| x.short == short || x.long == long})
387
+ match.opt = cmd_opt
388
+ match.sym = cmd_opt.long[2..-1].gsub("-", "_").to_sym
389
+ end
390
+ end
391
+
392
+ return match
393
+ end
394
+
395
+ # Convert the given option value to appropriate type and validate against allowed
396
+ # @param value [String] type to convert and and check
397
+ # @param cmd [Command] configured command to reference
398
+ # @param opt [Option] matching option to validate against
399
+ # @return [String|Integer|Array] depending on option type
400
+ def convert_value(value, cmd, opt)
401
+ if value
402
+ if opt.type == String
403
+ if opt.allowed.any?
404
+ !puts("Error: invalid string value '#{value}'!".colorize(:red)) && !puts(cmd.help) and
405
+ exit if !opt.allowed.include?(value)
406
+ end
407
+ elsif opt.type == Integer
408
+ value = value.to_i
409
+ if opt.allowed.any?
410
+ !puts("Error: invalid integer value '#{value}'!".colorize(:red)) && !puts(cmd.help) and
411
+ exit if !opt.allowed.include?(value)
412
+ end
413
+ elsif opt.type == Array
414
+ value = value.split(',')
415
+ if opt.allowed.any?
416
+ value.each{|x|
417
+ !puts("Error: invalid array value '#{x}'!".colorize(:red)) && !puts(cmd.help) and
418
+ exit if !opt.allowed.include?(x)
419
+ }
420
+ end
421
+ end
422
+ end
423
+
424
+ return value
425
+ end
363
426
 
364
427
  # Add a command to the command list
365
428
  # @param cmd [String] name of the command
366
429
  # @param desc [String] description of the command
367
430
  # @param opts [List] list of command options
368
- # @returns cmd [Command] new command
431
+ # @return [Command] new command
369
432
  def add_cmd(cmd, desc, options)
370
433
  Log.die("command names must be pure lowercase letters") if cmd =~ /[^a-z]/
371
434
 
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.50
4
+ version: 0.0.51
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-09 00:00:00.000000000 Z
11
+ date: 2018-04-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize