Class: ArgParser::Definition
- Inherits:
-
Object
- Object
- ArgParser::Definition
- Defined in:
- lib/arg-parser/definition.rb
Overview
Represents the collection of possible command-line arguments for a script.
Instance Attribute Summary collapse
-
#purpose ⇒ String
A short description of the purpose of the script, for display when showing the usage help.
-
#title ⇒ String
A title for the script, displayed at the top of the usage and help outputs.
Instance Method Summary collapse
-
#<<(arg) ⇒ Object
Adds the specified argument to the command-line definition.
-
#[](key) ⇒ Argument
The argument with the specified key.
-
#args ⇒ Array
All arguments that have been defined.
-
#errors ⇒ Object
Return an array of parse errors.
-
#flag_arg(key, desc, opts = {}, &block) ⇒ Object
Add a flag argument to the set of arguments in this command-line argument definition.
-
#flag_args ⇒ Array
The flag arguments that have been defined.
-
#flag_args? ⇒ Boolean
True if any flag arguments have been defined.
-
#has_key?(key) ⇒ Argument
The argument for the given key if it exists, or nil if it does not.
-
#initialize {|_self| ... } ⇒ Definition
constructor
Create a new Definition, which is a collection of valid Arguments to be used when parsing a command-line.
-
#keyword_arg(key, desc, opts = {}, &block) ⇒ Object
Add a keyword argument to the set of arguments in this command-line argument definition.
-
#keyword_args ⇒ Array
The keyword arguments that have been defined.
-
#keyword_args? ⇒ Boolean
True if any keyword arguments have been defined.
-
#non_positional_args ⇒ Array
The non-positional (i.e. keyword and flag) arguments that have been defined.
-
#non_positional_args? ⇒ Boolean
True if any non-positional arguments have been defined.
-
#parse(args = ARGV) ⇒ OpenStruct, false
Parse the
args
array of arguments using this command-line definition. -
#parser ⇒ Parser
A Parser instance that can be used to parse this command-line Definition.
-
#positional_arg(key, desc, opts = {}, &block) ⇒ Object
Add a positional argument to the set of arguments in this command-line argument definition.
-
#positional_args ⇒ Array
All positional arguments that have been defined.
-
#positional_args? ⇒ Boolean
True if any positional arguments have been defined.
-
#require_any_of(*keys) ⇒ Object
Individual arguments are optional, but at least one of
keys
arguments is required. -
#require_one_of(*keys) ⇒ Object
Individual arguments are optional, but exactly one of
keys
arguments is required. -
#requires_some? ⇒ Boolean
True if at least one argument is required out of multiple optional args.
-
#rest_arg(key, desc, opts = {}, &block) ⇒ Object
Add a rest argument to the set of arguments in this command-line argument definition.
-
#rest_args ⇒ RestArgument
The RestArgument defined for this command-line, or nil if no RestArgument is defined.
-
#rest_args? ⇒ Boolean
True if a RestArgument has been defined.
-
#show_help(out = STDOUT, width = 80) ⇒ Array
Generates a more detailed help screen.
-
#show_help? ⇒ Boolean
Whether user indicated they would like help on supported arguments.
-
#show_usage(out = STDERR, width = 80) ⇒ Object
Generates a usage display string.
-
#show_usage? ⇒ Boolean
Whether user indicated they would like help on usage.
-
#size ⇒ Integer
The number of arguments that have been defined.
-
#validate_requirements(args) ⇒ Array
Validates the supplied
args
Hash object, verifying that any argument set requirements have been satisfied. -
#value_args ⇒ Array
All the positional, keyword, and rest arguments that have been defined.
-
#wrap_text(text, width) ⇒ Array
Utility method for wrapping lines of
text
atwidth
characters.
Constructor Details
#initialize {|_self| ... } ⇒ Definition
Create a new Definition, which is a collection of valid Arguments to be used when parsing a command-line.
21 22 23 24 25 26 27 |
# File 'lib/arg-parser/definition.rb', line 21 def initialize @arguments = {} @short_keys = {} @require_set = Hash.new{ |h,k| h[k] = [] } @title = $0.respond_to?(:titleize) ? $0.titleize : $0 yield self if block_given? end |
Instance Attribute Details
#purpose ⇒ String
Returns A short description of the purpose of the script, for display when showing the usage help.
16 17 18 |
# File 'lib/arg-parser/definition.rb', line 16 def purpose @purpose end |
#title ⇒ String
Returns A title for the script, displayed at the top of the usage and help outputs.
13 14 15 |
# File 'lib/arg-parser/definition.rb', line 13 def title @title end |
Instance Method Details
#<<(arg) ⇒ Object
Adds the specified argument to the command-line definition.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/arg-parser/definition.rb', line 51 def <<(arg) case arg when PositionalArgument, KeywordArgument, FlagArgument, RestArgument if @arguments[arg.key] raise ArgumentError, "An argument with key '#{arg.key}' has already been defined" end if arg.short_key && @short_keys[arg.short_key] raise ArgumentError, "An argument with short key '#{arg.short_key}' has already been defined" end if arg.is_a?(RestArgument) && rest_args raise ArgumentError, "Only one rest argument can be defined" end @arguments[arg.key] = arg @short_keys[arg.short_key] = arg if arg.short_key else raise ArgumentError, "arg must be an instance of PositionalArgument, KeywordArgument, " + "FlagArgument or RestArgument" end end |
#[](key) ⇒ Argument
Returns the argument with the specified key.
41 42 43 44 |
# File 'lib/arg-parser/definition.rb', line 41 def [](key) arg = has_key?(key) arg or raise NoSuchArgumentError, "No argument defined for key '#{Argument.to_key(key)}'" end |
#args ⇒ Array
Returns all arguments that have been defined.
198 199 200 |
# File 'lib/arg-parser/definition.rb', line 198 def args @arguments.values end |
#errors ⇒ Object
Return an array of parse errors.
147 148 149 |
# File 'lib/arg-parser/definition.rb', line 147 def errors parser.errors end |
#flag_arg(key, desc, opts = {}, &block) ⇒ Object
Add a flag argument to the set of arguments in this command-line argument definition.
91 92 93 |
# File 'lib/arg-parser/definition.rb', line 91 def flag_arg(key, desc, opts = {}, &block) self << ArgParser::FlagArgument.new(key, desc, opts, &block) end |
#flag_args ⇒ Array
Returns the flag arguments that have been defined.
241 242 243 |
# File 'lib/arg-parser/definition.rb', line 241 def flag_args @arguments.values.select{ |arg| FlagArgument === arg } end |
#flag_args? ⇒ Boolean
Returns True if any flag arguments have been defined.
247 248 249 |
# File 'lib/arg-parser/definition.rb', line 247 def flag_args? flag_args.size > 0 end |
#has_key?(key) ⇒ Argument
Returns the argument for the given key if it exists, or nil if it does not.
32 33 34 35 |
# File 'lib/arg-parser/definition.rb', line 32 def has_key?(key) k = Argument.to_key(key) @arguments[k] || @short_keys[k] end |
#keyword_arg(key, desc, opts = {}, &block) ⇒ Object
Add a keyword argument to the set of arguments in this command-line argument definition.
83 84 85 |
# File 'lib/arg-parser/definition.rb', line 83 def keyword_arg(key, desc, opts = {}, &block) self << ArgParser::KeywordArgument.new(key, desc, opts, &block) end |
#keyword_args ⇒ Array
Returns the keyword arguments that have been defined.
229 230 231 |
# File 'lib/arg-parser/definition.rb', line 229 def keyword_args @arguments.values.select{ |arg| KeywordArgument === arg } end |
#keyword_args? ⇒ Boolean
Returns True if any keyword arguments have been defined.
235 236 237 |
# File 'lib/arg-parser/definition.rb', line 235 def keyword_args? keyword_args.size > 0 end |
#non_positional_args ⇒ Array
Returns the non-positional (i.e. keyword and flag) arguments that have been defined.
217 218 219 |
# File 'lib/arg-parser/definition.rb', line 217 def non_positional_args @arguments.values.reject{ |arg| PositionalArgument === arg || RestArgument === arg } end |
#non_positional_args? ⇒ Boolean
Returns True if any non-positional arguments have been defined.
223 224 225 |
# File 'lib/arg-parser/definition.rb', line 223 def non_positional_args? non_positional_args.size > 0 end |
#parse(args = ARGV) ⇒ OpenStruct, false
Parse the args
array of arguments using this command-line definition.
arguments defined as accessors, and the parsed or default values for each argument as values. If unsuccessful, returns false indicating a parse failure.
140 141 142 |
# File 'lib/arg-parser/definition.rb', line 140 def parse(args = ARGV) parser.parse(args) end |
#parser ⇒ Parser
Returns a Parser instance that can be used to parse this command-line Definition.
126 127 128 |
# File 'lib/arg-parser/definition.rb', line 126 def parser @parser ||= Parser.new(self) end |
#positional_arg(key, desc, opts = {}, &block) ⇒ Object
Add a positional argument to the set of arguments in this command-line argument definition.
75 76 77 |
# File 'lib/arg-parser/definition.rb', line 75 def positional_arg(key, desc, opts = {}, &block) self << ArgParser::PositionalArgument.new(key, desc, opts, &block) end |
#positional_args ⇒ Array
Returns all positional arguments that have been defined.
204 205 206 |
# File 'lib/arg-parser/definition.rb', line 204 def positional_args @arguments.values.select{ |arg| PositionalArgument === arg } end |
#positional_args? ⇒ Boolean
Returns True if any positional arguments have been defined.
210 211 212 |
# File 'lib/arg-parser/definition.rb', line 210 def positional_args? positional_args.size > 0 end |
#require_any_of(*keys) ⇒ Object
Individual arguments are optional, but at least one of keys
arguments is required.
113 114 115 |
# File 'lib/arg-parser/definition.rb', line 113 def require_any_of(*keys) @require_set[:any] << keys.map{ |k| self[k] } end |
#require_one_of(*keys) ⇒ Object
Individual arguments are optional, but exactly one of keys
arguments is required.
106 107 108 |
# File 'lib/arg-parser/definition.rb', line 106 def require_one_of(*keys) @require_set[:one] << keys.map{ |k| self[k] } end |
#requires_some? ⇒ Boolean
True if at least one argument is required out of multiple optional args.
119 120 121 |
# File 'lib/arg-parser/definition.rb', line 119 def requires_some? @require_set.size > 0 end |
#rest_arg(key, desc, opts = {}, &block) ⇒ Object
Add a rest argument to the set of arguments in this command-line argument definition.
99 100 101 |
# File 'lib/arg-parser/definition.rb', line 99 def rest_arg(key, desc, opts = {}, &block) self << ArgParser::RestArgument.new(key, desc, opts, &block) end |
#rest_args ⇒ RestArgument
Returns the RestArgument defined for this command-line, or nil if no RestArgument is defined.
254 255 256 |
# File 'lib/arg-parser/definition.rb', line 254 def rest_args @arguments.values.find{ |arg| RestArgument === arg } end |
#rest_args? ⇒ Boolean
Returns True if a RestArgument has been defined.
260 261 262 |
# File 'lib/arg-parser/definition.rb', line 260 def rest_args? !!rest_args end |
#show_help(out = STDOUT, width = 80) ⇒ Array
Generates a more detailed help screen.
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
# File 'lib/arg-parser/definition.rb', line 300 def show_help(out = STDOUT, width = 80) lines = ['', ''] lines << title lines << title.gsub(/./, '=') lines << '' if purpose lines.concat(wrap_text(purpose, width)) lines << '' lines << '' end lines << 'USAGE' lines << '-----' pos_args = positional_args opt_args = size - pos_args.size usage_args = pos_args.map(&:to_use) usage_args << (requires_some? ? 'OPTIONS' : '[OPTIONS]') if opt_args > 0 usage_args << rest_args.to_use if rest_args? lines.concat(wrap_text(" #{RUBY_ENGINE} #{$0} #{usage_args.join(' ')}", width)) lines << '' if positional_args? max = positional_args.map{ |a| a.to_s.length }.max pos_args = positional_args pos_args << rest_args if rest_args? pos_args.each do |arg| if arg.usage_break lines << '' lines << arg.usage_break end desc = arg.description desc << "\n[Default: #{arg.default}]" unless arg.default.nil? wrap_text(desc, width - max - 6).each_with_index do |line, i| lines << " %-#{max}s %s" % [[arg.to_s][i], line] end end lines << '' end if non_positional_args? lines << '' lines << 'OPTIONS' lines << '-------' max = non_positional_args.map{ |a| a.to_use.length }.max non_positional_args.each do |arg| if arg.usage_break lines << '' lines << arg.usage_break end desc = arg.description desc << "\n[Default: #{arg.default}]" unless arg.default.nil? wrap_text(desc, width - max - 6).each_with_index do |line, i| lines << " %-#{max}s %s" % [[arg.to_use][i], line] end end end lines << '' lines.each{ |line| line.length < width ? out.puts(line) : out.print(line) } if out lines end |
#show_help? ⇒ Boolean
Whether user indicated they would like help on supported arguments.
161 162 163 |
# File 'lib/arg-parser/definition.rb', line 161 def show_help? parser.show_help? end |
#show_usage(out = STDERR, width = 80) ⇒ Object
Generates a usage display string
279 280 281 282 283 284 285 286 287 288 289 290 291 292 |
# File 'lib/arg-parser/definition.rb', line 279 def show_usage(out = STDERR, width = 80) lines = [''] pos_args = positional_args opt_args = size - pos_args.size usage_args = pos_args.map(&:to_use) usage_args << (requires_some? ? 'OPTIONS' : '[OPTIONS]') if opt_args > 0 usage_args << rest_args.to_use if rest_args? lines.concat(wrap_text("USAGE: #{RUBY_ENGINE} #{$0} #{usage_args.join(' ')}", width)) lines << '' lines << 'Specify the /? or --help option for more detailed help' lines << '' lines.each{ |line| out.puts line } if out lines end |
#show_usage? ⇒ Boolean
Whether user indicated they would like help on usage.
154 155 156 |
# File 'lib/arg-parser/definition.rb', line 154 def show_usage? parser.show_usage? end |
#size ⇒ Integer
Returns the number of arguments that have been defined.
273 274 275 |
# File 'lib/arg-parser/definition.rb', line 273 def size @arguments.size end |
#validate_requirements(args) ⇒ Array
Validates the supplied args
Hash object, verifying that any argument set requirements have been satisfied. Returns an array of error messages for each set requirement that is not satisfied.
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 |
# File 'lib/arg-parser/definition.rb', line 174 def validate_requirements(args) errors = [] @require_set.each do |req, sets| sets.each do |set| count = set.count{ |arg| args.has_key?(arg.key) && args[arg.key] } case req when :one if count == 0 errors << "No argument has been specified for one of: #{set.join(', ')}" elsif count > 1 errors << "Only one argument can been specified from: #{set.join(', ')}" end when :any if count == 0 errors << "At least one of the arguments must be specified from: #{set.join(', ')}" end end end end errors end |
#value_args ⇒ Array
Returns all the positional, keyword, and rest arguments that have been defined.
267 268 269 |
# File 'lib/arg-parser/definition.rb', line 267 def value_args @arguments.values.select{ |arg| ValueArgument === arg } end |
#wrap_text(text, width) ⇒ Array
Utility method for wrapping lines of text
at width
characters.
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 |
# File 'lib/arg-parser/definition.rb', line 369 def wrap_text(text, width) if width > 0 && (text.length > width || text.index("\n")) lines = [] start, nl_pos, ws_pos, wb_pos, end_pos = 0, 0, 0, 0, text.rindex(/[^\s]/) while start < end_pos last_start = start nl_pos = text.index("\n", start) ws_pos = text.rindex(/ +/, start + width) wb_pos = text.rindex(/[\-,.;#)}\]\/\\]/, start + width - 1) ### Debug code ### #STDERR.puts self #ind = ' ' * end_pos #ind[start] = '(' #ind[start+width < end_pos ? start+width : end_pos] = ']' #ind[nl_pos] = 'n' if nl_pos #ind[wb_pos] = 'b' if wb_pos #ind[ws_pos] = 's' if ws_pos #STDERR.puts ind ### End debug code ### if nl_pos && nl_pos <= start + width lines << text[start...nl_pos].strip start = nl_pos + 1 elsif end_pos < start + width lines << text[start..end_pos] start = end_pos elsif ws_pos && ws_pos > start && ((wb_pos.nil? || ws_pos > wb_pos) || (wb_pos && wb_pos > 5 && wb_pos - 5 < ws_pos)) lines << text[start...ws_pos] start = text.index(/[^\s]/, ws_pos + 1) elsif wb_pos && wb_pos > start lines << text[start..wb_pos] start = wb_pos + 1 else lines << text[start...(start+width)] start += width end if start <= last_start # Detect an infinite loop, and just return the original text STDERR.puts "Inifinite loop detected at #{__FILE__}:#{__LINE__}" STDERR.puts " width: #{width}, start: #{start}, nl_pos: #{nl_pos}, " + "ws_pos: #{ws_pos}, wb_pos: #{wb_pos}" return [text] end end lines else [text] end end |