nub 0.0.50 → 0.0.51

Sign up to get free protection for your applications and to get access to all the features.
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