nub 0.0.25 → 0.0.27
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/nub.rb +1 -1
- data/lib/nub/commander.rb +277 -0
- data/lib/nub/sys.rb +17 -2
- metadata +3 -3
- data/lib/nub/cmds.rb +0 -146
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d5f8ebb6c991951280634bd778890442ead23922928d9a113f6f04449660c5d
|
4
|
+
data.tar.gz: 49b25510286dcd087882043bd49209b63bb2688bb338054c1dd3a7d34d5da97c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ae5491f1c835a8d9de56127c1b486a875195fd12259834a928c5bc9dd915964114a11c6c8a0b1d795c99d9c121386a72f271d9e48c2b6a66014777a8058c8b77
|
7
|
+
data.tar.gz: 1d19f786cfda8a5f21b4913ce42b6b22ad38a4a62bacafb3b72ddea9a4b14556be2d923a3194fb660f82a75977e8ade4573412863caa4993e122d33dba294965
|
data/lib/nub.rb
CHANGED
@@ -0,0 +1,277 @@
|
|
1
|
+
#MIT License
|
2
|
+
#Copyright (c) 2018 phR0ze
|
3
|
+
#
|
4
|
+
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
+
#of this software and associated documentation files (the "Software"), to deal
|
6
|
+
#in the Software without restriction, including without limitation the rights
|
7
|
+
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
#copies of the Software, and to permit persons to whom the Software is
|
9
|
+
#furnished to do so, subject to the following conditions:
|
10
|
+
#
|
11
|
+
#The above copyright notice and this permission notice shall be included in all
|
12
|
+
#copies or substantial portions of the Software.
|
13
|
+
#
|
14
|
+
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
+
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
+
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
+
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
+
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
+
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
+
#SOFTWARE.
|
21
|
+
|
22
|
+
require 'colorize'
|
23
|
+
|
24
|
+
# Command option encapsulation
|
25
|
+
class Option
|
26
|
+
attr_reader(:key)
|
27
|
+
attr_reader(:short)
|
28
|
+
attr_reader(:long)
|
29
|
+
attr_reader(:hint)
|
30
|
+
attr_reader(:desc)
|
31
|
+
attr_reader(:type)
|
32
|
+
attr_reader(:allowed)
|
33
|
+
attr_reader(:required)
|
34
|
+
|
35
|
+
# Create a new option instance
|
36
|
+
# @param key [String] option short hand, long hand and hint e.g. -s|--skip=COMPONENTS
|
37
|
+
# @param desc [String] the option's description
|
38
|
+
# @param type [Type] the option's type
|
39
|
+
# @param required [Bool] require the option if true else optional
|
40
|
+
# @param allowed [Array] array of allowed string values
|
41
|
+
def initialize(key, desc, type:nil, required:false, allowed:[])
|
42
|
+
@hint = nil
|
43
|
+
@long = nil
|
44
|
+
@short = nil
|
45
|
+
@desc = desc
|
46
|
+
@allowed = allowed || []
|
47
|
+
@required = required || false
|
48
|
+
|
49
|
+
# Parse the key into its components (short hand, long hand, and hint)
|
50
|
+
#https://bneijt.nl/pr/ruby-regular-expressions/
|
51
|
+
# Valid forms to look for with chars [a-zA-Z0-9-_=|]
|
52
|
+
# --help, --help=HINT, -h|--help, -h|--help=HINT
|
53
|
+
!puts("Error: invalid option key #{key}".colorize(:red)) and
|
54
|
+
exit if key && (key.count('=') > 1 or key.count('|') > 1 or !key[/[^\w\-=|]/].nil? or
|
55
|
+
key[/(^--[a-zA-Z0-9\-_]+$)|(^--[a-zA-Z\-_]+=\w+$)|(^-[a-zA-Z]\|--[a-zA-Z0-9\-_]+$)|(^-[a-zA-Z]\|--[a-zA-Z0-9\-_]+=\w+$)/].nil?)
|
56
|
+
@key = key
|
57
|
+
if key
|
58
|
+
@hint = key[/.*=(.*)$/, 1]
|
59
|
+
@short = key[/^(-\w).*$/, 1]
|
60
|
+
@long = key[/(--[\w\-]+)(=.+)*$/, 1]
|
61
|
+
else
|
62
|
+
# Always require positional options
|
63
|
+
@required = true
|
64
|
+
end
|
65
|
+
|
66
|
+
# Validate and set type
|
67
|
+
!puts("Error: invalid option type #{type}".colorize(:red)) and
|
68
|
+
exit if ![String, Integer, Array, nil].any?{|x| type == x}
|
69
|
+
!puts("Error: option type must be set".colorize(:red)) and
|
70
|
+
exit if @hint && !type
|
71
|
+
@type = String if !key && !type
|
72
|
+
@type = FalseClass if key and !type
|
73
|
+
@type = type if type
|
74
|
+
|
75
|
+
# Validate allowed
|
76
|
+
if @allowed.any?
|
77
|
+
allowed_type = @allowed.first.class
|
78
|
+
!puts("Error: mixed allowed types".colorize(:red)) and
|
79
|
+
exit if @allowed.any?{|x| x.class != allowed_type}
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# An implementation of git like command syntax for ruby applications:
|
85
|
+
# see https://github.com/phR0ze/ruby-nub
|
86
|
+
class Commander
|
87
|
+
attr_accessor(:cmds)
|
88
|
+
attr_reader(:config)
|
89
|
+
attr_reader(:banner)
|
90
|
+
|
91
|
+
Command = Struct.new(:name, :desc, :opts, :help)
|
92
|
+
|
93
|
+
# Initialize the commands for your application
|
94
|
+
# @param app [String] application name e.g. reduce
|
95
|
+
# @param version [String] version of the application e.g. 1.0.0
|
96
|
+
# @param examples [String] optional examples to list after the title before usage
|
97
|
+
def initialize(app, version, examples:nil)
|
98
|
+
@app = app
|
99
|
+
@version = version
|
100
|
+
@examples = examples
|
101
|
+
!puts("Error: app name and version are required".colorize(:red)) and
|
102
|
+
exit if @app.nil? or @app.empty? or @version.nil? or @version.empty?
|
103
|
+
|
104
|
+
@help_opt = Option.new('-h|--help', 'Print command/options help')
|
105
|
+
@just = 40
|
106
|
+
|
107
|
+
# Configuration - ordered list of commands
|
108
|
+
@config = []
|
109
|
+
|
110
|
+
# Incoming user set commands/options
|
111
|
+
# {command_name => {}}
|
112
|
+
@cmds = {}
|
113
|
+
end
|
114
|
+
|
115
|
+
# Hash like accessor for checking if a command or option is set
|
116
|
+
def [](key)
|
117
|
+
return @cmds[key] if @cmds[key]
|
118
|
+
end
|
119
|
+
|
120
|
+
# Add a command to the command list
|
121
|
+
# @param cmd [String] name of the command
|
122
|
+
# @param desc [String] description of the command
|
123
|
+
# @param opts [List] list of command options
|
124
|
+
def add(cmd, desc, options:[])
|
125
|
+
!puts("Error: command names must be pure lowercase letters".colorize(:red)) and
|
126
|
+
exit if cmd =~ /[^a-z]/
|
127
|
+
|
128
|
+
# Build help for command
|
129
|
+
help = "#{banner}\n#{desc}\n\nUsage: ./#{@app} #{cmd} [options]\n"
|
130
|
+
options << @help_opt
|
131
|
+
|
132
|
+
# Add positional options first
|
133
|
+
sorted_options = options.select{|x| x.key.nil?}
|
134
|
+
sorted_options += options.select{|x| !x.key.nil?}.sort{|x,y| x.key <=> y.key}
|
135
|
+
positional_index = -1
|
136
|
+
sorted_options.each{|x|
|
137
|
+
required = x.required ? ", Required" : ""
|
138
|
+
allowed = x.allowed.empty? ? "" : " (#{x.allowed * ','})"
|
139
|
+
positional_index += 1 if x.key.nil?
|
140
|
+
key = x.key.nil? ? "#{cmd}#{positional_index}" : x.key
|
141
|
+
type = x.type == FalseClass ? "Flag" : x.type
|
142
|
+
help += " #{key.ljust(@just)}#{x.desc}#{allowed}: #{type}#{required}\n"
|
143
|
+
}
|
144
|
+
|
145
|
+
# Create the command in the command config
|
146
|
+
@config << Command.new(cmd, desc, sorted_options, help)
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns banner string
|
150
|
+
# @returns [String] the app's banner
|
151
|
+
def banner
|
152
|
+
banner = "#{@app}_v#{@version}\n#{'-' * 80}".colorize(:light_yellow)
|
153
|
+
return banner
|
154
|
+
end
|
155
|
+
|
156
|
+
# Return the app's help string
|
157
|
+
# @returns [String] the app's help string
|
158
|
+
def help
|
159
|
+
help = "#{banner}\n"
|
160
|
+
help += "Examples:\n#{@examples}\n\n" if !@examples.nil? && !@examples.empty?
|
161
|
+
help += "Usage: ./#{@app} [commands] [options]\n"
|
162
|
+
help += " #{'-h|--help'.ljust(@just)}Print command/options help: Flag\n"
|
163
|
+
help += "COMMANDS:\n"
|
164
|
+
@config.each{|x| help += " #{x.name.ljust(@just)}#{x.desc}\n" }
|
165
|
+
help += "\nsee './#{@app} COMMAND --help' for specific command help\n"
|
166
|
+
|
167
|
+
return help
|
168
|
+
end
|
169
|
+
|
170
|
+
# Construct the command line parser and parse
|
171
|
+
def parse!
|
172
|
+
|
173
|
+
# Set help if nothing was given
|
174
|
+
ARGV.clear and ARGV << '-h' if ARGV.empty?
|
175
|
+
|
176
|
+
# Process global options
|
177
|
+
#---------------------------------------------------------------------------
|
178
|
+
cmd_names = @config.map{|x| x.name }
|
179
|
+
globals = ARGV.take_while{|x| !cmd_names.include?(x)}
|
180
|
+
!puts(help) and exit if globals.any?
|
181
|
+
|
182
|
+
# Process command options
|
183
|
+
#---------------------------------------------------------------------------
|
184
|
+
loop {
|
185
|
+
break if ARGV.first.nil?
|
186
|
+
|
187
|
+
if !(cmd = @config.find{|x| x.name == ARGV.first}).nil?
|
188
|
+
@cmds[ARGV.shift.to_sym] = {}
|
189
|
+
cmd_names.reject!{|x| x == cmd.name}
|
190
|
+
|
191
|
+
# Collect command options
|
192
|
+
opts = ARGV.take_while{|x| !cmd_names.include?(x) }
|
193
|
+
ARGV.shift(opts.size)
|
194
|
+
cmd_pos_opts = cmd.opts.select{|x| x.key.nil? }
|
195
|
+
cmd_named_opts = cmd.opts.select{|x| !x.key.nil? }
|
196
|
+
!puts("Error: positional option required".colorize(:red)) && !puts(cmd.help) and
|
197
|
+
exit if opts.size < cmd_pos_opts.size
|
198
|
+
|
199
|
+
# Process command options
|
200
|
+
pos = -1
|
201
|
+
loop {
|
202
|
+
break if opts.first.nil?
|
203
|
+
opt = opts.shift
|
204
|
+
cmd_opt = nil
|
205
|
+
value = nil
|
206
|
+
sym = nil
|
207
|
+
|
208
|
+
# Validate/set named options
|
209
|
+
# --------------------------------------------------------------------
|
210
|
+
# e.g. -s, --skip, --skip=VALUE
|
211
|
+
if opt.start_with?('-')
|
212
|
+
short = opt[/^(-\w).*$/, 1]
|
213
|
+
long = opt[/(--[\w\-]+)(=.+)*$/, 1]
|
214
|
+
value = opt[/.*=(.*)$/, 1]
|
215
|
+
|
216
|
+
# Set symbol converting dashes to underscores for named options
|
217
|
+
if (cmd_opt = cmd_named_opts.find{|x| x.short == short || x.long == long})
|
218
|
+
sym = cmd_opt.long[2..-1].gsub("-", "_").to_sym
|
219
|
+
|
220
|
+
# Collect value
|
221
|
+
if cmd_opt.type == FalseClass
|
222
|
+
value = true if !value
|
223
|
+
elsif !value
|
224
|
+
value = opts.shift
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Validate/set positional options
|
229
|
+
# --------------------------------------------------------------------
|
230
|
+
else
|
231
|
+
pos += 1
|
232
|
+
cmd_opt = cmd_pos_opts.shift
|
233
|
+
!puts("Error: invalid positional option '#{opt}'".colorize(:red)) && !puts(cmd.help) and
|
234
|
+
exit if cmd_opt.nil?
|
235
|
+
value = opt
|
236
|
+
sym = "#{cmd.name}#{pos}".to_sym
|
237
|
+
end
|
238
|
+
|
239
|
+
# Convert value to appropriate type
|
240
|
+
# --------------------------------------------------------------------
|
241
|
+
if value
|
242
|
+
if cmd_opt.type == Integer
|
243
|
+
value = value.to_i
|
244
|
+
|
245
|
+
# Validate allowed values
|
246
|
+
if cmd_opt.allowed.any?
|
247
|
+
!puts("Error: invalid integer value '#{value}'".colorize(:red)) && !puts(cmd.help) and
|
248
|
+
exit if !cmd_opt.allowed.include?(value)
|
249
|
+
end
|
250
|
+
|
251
|
+
elsif cmd_opt.type == Array
|
252
|
+
value = value.split(',')
|
253
|
+
|
254
|
+
# Validate allowed values
|
255
|
+
if cmd_opt.allowed.any?
|
256
|
+
value.each{|x|
|
257
|
+
!puts("Error: invalid array value '#{x}'".colorize(:red)) && !puts(cmd.help) and
|
258
|
+
exit if !cmd_opt.allowed.include?(x)
|
259
|
+
}
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Set option with value
|
265
|
+
# --------------------------------------------------------------------
|
266
|
+
!puts("Error: unknown named option '#{opt}' given".colorize(:red)) && !puts(cmd.help) and exit if !sym
|
267
|
+
@cmds[cmd.name.to_sym][sym] = value
|
268
|
+
}
|
269
|
+
end
|
270
|
+
}
|
271
|
+
|
272
|
+
# Ensure all options were consumed
|
273
|
+
!puts("Error: invalid options #{ARGV}".colorize(:red)) and exit if ARGV.any?
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
# vim: ft=ruby:ts=2:sw=2:sts=2
|
data/lib/nub/sys.rb
CHANGED
@@ -20,11 +20,26 @@
|
|
20
20
|
#SOFTWARE.
|
21
21
|
|
22
22
|
require 'io/console'
|
23
|
+
require 'ostruct'
|
24
|
+
require 'stringio'
|
23
25
|
|
24
|
-
|
26
|
+
module Sys
|
27
|
+
|
28
|
+
# Capture STDOUT to a string
|
29
|
+
# @returns [String] the redirected output
|
30
|
+
def self.capture(&block)
|
31
|
+
stdout, stderr = StringIO.new, StringIO.new
|
32
|
+
$stdout, $stderr = stdout, stderr
|
33
|
+
|
34
|
+
result = block.call
|
35
|
+
|
36
|
+
$stdout, $stderr = STDOUT, STDERR
|
37
|
+
|
38
|
+
return OpenStruct.new(result: result, stdout: stdout.string, stderr: stderr.string)
|
39
|
+
end
|
25
40
|
|
26
41
|
# Wait for any key to be pressed
|
27
|
-
def any_key?
|
42
|
+
def self.any_key?
|
28
43
|
begin
|
29
44
|
state = `stty -g`
|
30
45
|
`stty raw -echo -icanon isig`
|
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.27
|
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-03-
|
11
|
+
date: 2018-03-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -101,7 +101,7 @@ extensions: []
|
|
101
101
|
extra_rdoc_files: []
|
102
102
|
files:
|
103
103
|
- lib/nub.rb
|
104
|
-
- lib/nub/
|
104
|
+
- lib/nub/commander.rb
|
105
105
|
- lib/nub/config.rb
|
106
106
|
- lib/nub/log.rb
|
107
107
|
- lib/nub/net.rb
|
data/lib/nub/cmds.rb
DELETED
@@ -1,146 +0,0 @@
|
|
1
|
-
#MIT License
|
2
|
-
#Copyright (c) 2018 phR0ze
|
3
|
-
#
|
4
|
-
#Permission is hereby granted, free of charge, to any person obtaining a copy
|
5
|
-
#of this software and associated documentation files (the "Software"), to deal
|
6
|
-
#in the Software without restriction, including without limitation the rights
|
7
|
-
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
-
#copies of the Software, and to permit persons to whom the Software is
|
9
|
-
#furnished to do so, subject to the following conditions:
|
10
|
-
#
|
11
|
-
#The above copyright notice and this permission notice shall be included in all
|
12
|
-
#copies or substantial portions of the Software.
|
13
|
-
#
|
14
|
-
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
15
|
-
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
16
|
-
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
17
|
-
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
18
|
-
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
19
|
-
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
20
|
-
#SOFTWARE.
|
21
|
-
|
22
|
-
require 'optparse'
|
23
|
-
require 'colorize'
|
24
|
-
|
25
|
-
# Command option class provides a way to encapsulate a command with
|
26
|
-
# any additional properties.
|
27
|
-
class CmdOpt
|
28
|
-
attr_reader(:key)
|
29
|
-
attr_reader(:conf)
|
30
|
-
attr_reader(:type)
|
31
|
-
attr_reader(:desc)
|
32
|
-
attr_reader(:required)
|
33
|
-
def initialize(conf, desc, type:nil, required:false)
|
34
|
-
@conf = conf.gsub(' ', '=')
|
35
|
-
@key = conf.gsub('-', '').split('=').first.to_sym
|
36
|
-
@type = type
|
37
|
-
@desc = desc
|
38
|
-
@required = required
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Simple command wrapper around options parsing
|
43
|
-
# When multiple commands are given they share the options passed along with them
|
44
|
-
class Cmds
|
45
|
-
|
46
|
-
# Option and command names have all hyphens removed
|
47
|
-
attr_accessor(:cmds)
|
48
|
-
attr_accessor(:opts)
|
49
|
-
|
50
|
-
# Initialize the commands for your application
|
51
|
-
# Params:
|
52
|
-
# +app+:: application name e.g. reduce
|
53
|
-
# +version+:: version of the application e.g. 1.0.0
|
54
|
-
# +examples+:: optional examples to list after the title before usage
|
55
|
-
def initialize(app, version, examples)
|
56
|
-
@opts = {}
|
57
|
-
@cmds = {}
|
58
|
-
@cmds_config = {}
|
59
|
-
|
60
|
-
@app = app
|
61
|
-
@version = version
|
62
|
-
@examples = examples || ''
|
63
|
-
end
|
64
|
-
|
65
|
-
# Hash like accessor for checking if a command is set
|
66
|
-
def [](key)
|
67
|
-
return @cmds[key] if @cmds[key]
|
68
|
-
return @opts[key] if @opts[key]
|
69
|
-
end
|
70
|
-
|
71
|
-
# Hash like accessor for editing options
|
72
|
-
def []=(key, value)
|
73
|
-
@opts[key] = value
|
74
|
-
end
|
75
|
-
|
76
|
-
# Add a command to the command list
|
77
|
-
# Params:
|
78
|
-
# +cmd+:: name of the command
|
79
|
-
# +desc+:: description of the command
|
80
|
-
# +opts+:: list of command options
|
81
|
-
def add(cmd, desc, opts)
|
82
|
-
@cmds_config[cmd] = {desc: desc, inopts: opts, outopts: OptionParser.new{|parser|
|
83
|
-
required = opts.map{|x| x.conf if x.required}.compact * ' '
|
84
|
-
required += ' ' if not required.empty?
|
85
|
-
parser.banner = "#{banner}\nUsage: ./#{@app} #{cmd} #{required}[options]"
|
86
|
-
opts.each{|opt| parser.on(opt.conf, opt.type, opt.desc){|x| @opts[opt.key] = x }}
|
87
|
-
}}
|
88
|
-
end
|
89
|
-
|
90
|
-
# Returns banner string
|
91
|
-
def banner
|
92
|
-
banner = "#{@app}_v#{@version}\n#{'-' * 80}".colorize(:light_yellow)
|
93
|
-
return banner
|
94
|
-
end
|
95
|
-
|
96
|
-
# Construct the command line parser and parse
|
97
|
-
def parse!
|
98
|
-
|
99
|
-
# Construct help for the application
|
100
|
-
help = "COMMANDS:\n"
|
101
|
-
@cmds_config.each{|k,v| help += " #{k.ljust(33, ' ')}#{v[:desc]}\n" }
|
102
|
-
help += "\nsee './#{@app} COMMAND --help' for specific command info"
|
103
|
-
|
104
|
-
# Construct top level option parser
|
105
|
-
@optparser = OptionParser.new do |parser|
|
106
|
-
parser.banner = "#{banner}\n#{@examples}Usage: ./#{@app} commands [options]"
|
107
|
-
parser.on('-h', '--help', 'Print command/options help') {|x| !puts(parser) and exit }
|
108
|
-
parser.separator(help)
|
109
|
-
end
|
110
|
-
|
111
|
-
# Invoke the option parser with help if any un-recognized commands are given
|
112
|
-
cmds = ARGV.select{|x| not x.start_with?('-')}
|
113
|
-
ARGV.clear and ARGV << '-h' if ARGV.empty? or cmds.any?{|x| not @cmds_config[x]}
|
114
|
-
cmds.each{|x| puts("Error: Invalid command '#{x}'".colorize(:red)) if not @cmds_config[x]}
|
115
|
-
@optparser.order!
|
116
|
-
|
117
|
-
# Now remove them from ARGV leaving only options
|
118
|
-
ARGV.reject!{|x| not x.start_with?('-')}
|
119
|
-
|
120
|
-
# Parse each command which will consume options from ARGV
|
121
|
-
cmds.each do |cmd|
|
122
|
-
begin
|
123
|
-
@cmds[cmd.gsub('-', '_').to_sym] = true
|
124
|
-
@cmds_config[cmd][:outopts].order!
|
125
|
-
|
126
|
-
# Ensure that all required options were given
|
127
|
-
@cmds_config[cmd][:inopts].each{|x|
|
128
|
-
if x.required and not @opts[x.key]
|
129
|
-
puts("Error: Missing required option '#{x.key}'".colorize(:red))
|
130
|
-
ARGV.clear and ARGV << "-h"
|
131
|
-
@cmds_config[cmd][:outopts].order!
|
132
|
-
end
|
133
|
-
}
|
134
|
-
rescue OptionParser::InvalidOption => e
|
135
|
-
# Options parser will raise an invalid exception if it doesn't recognize something
|
136
|
-
# However we want to ignore that as it may be another command's option
|
137
|
-
ARGV << e.to_s[/(-.*)/, 1]
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
# Ensure all options were consumed
|
142
|
-
!puts("Error: invalid options #{ARGV}".colorize(:red)) and exit if ARGV.any?
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
# vim: ft=ruby:ts=2:sw=2:sts=2
|