Class: ArgParser::Parser
- Inherits:
-
Object
- Object
- ArgParser::Parser
- Defined in:
- lib/arg-parser/parser.rb
Overview
Parser for parsing a command-line
Instance Attribute Summary collapse
-
#definition ⇒ Definition
readonly
The supported Arguments to be used when parsing the command-line.
-
#errors ⇒ Array
readonly
An Array of error message Strings generated during parsing.
Instance Method Summary collapse
-
#classify_tokens(tokens) ⇒ Object
Evaluate the list of values in
tokens
, and classify them as either keyword/value pairs, or positional arguments. -
#initialize(definition = nil) ⇒ Parser
constructor
Instantiates a new command-line parser, with the specified command- line definition.
-
#method_missing(mthd, *args) ⇒ Object
Delegate unknown methods to the associated argument Definition object.
-
#parse(tokens = ARGV) ⇒ Object
Parse the specified Array of
tokens
, or ARGV iftokens
is nil. -
#process_args(pos_vals, kw_vals, rest_vals) ⇒ Object
Process arguments using the supplied
pos_vals
Array of positional argument values, and thekw_vals
Hash of keyword/value. -
#show_help? ⇒ Boolean
Flag set during parsing if the user has requested the help display to be shown (via –help or /?).
-
#show_usage? ⇒ Boolean
Flag set during parsing if the usage display should be shown.
Constructor Details
#initialize(definition = nil) ⇒ Parser
Instantiates a new command-line parser, with the specified command- line definition. A Parser instance delegates unknown methods to the Definition, so its possible to work only with a Parser instance to both define and parse a command-line.
32 33 34 35 |
# File 'lib/arg-parser/parser.rb', line 32 def initialize(definition = nil) @definition = definition || Definition.new @errors = [] end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(mthd, *args) ⇒ Object
Delegate unknown methods to the associated argument Definition object.
59 60 61 62 63 64 65 |
# File 'lib/arg-parser/parser.rb', line 59 def method_missing(mthd, *args) if @definition.respond_to?(mthd) @definition.send(mthd, *args) else super end end |
Instance Attribute Details
#definition ⇒ Definition (readonly)
Returns The supported Arguments to be used when parsing the command-line.
8 9 10 |
# File 'lib/arg-parser/parser.rb', line 8 def definition @definition end |
#errors ⇒ Array (readonly)
Returns An Array of error message Strings generated during parsing.
11 12 13 |
# File 'lib/arg-parser/parser.rb', line 11 def errors @errors end |
Instance Method Details
#classify_tokens(tokens) ⇒ Object
Evaluate the list of values in tokens
, and classify them as either keyword/value pairs, or positional arguments. Ideally this would be done without any reference to the defined arguments, but unfortunately a keyword arg cannot be distinguished from a flag arg followed by a positional arg without the context of what arguments are expected.
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# File 'lib/arg-parser/parser.rb', line 73 def classify_tokens(tokens) if tokens.is_a?(String) require 'csv' tokens = CSV.parse(tokens, col_sep: ' ').first end tokens = [] unless tokens pos_vals = [] kw_vals = {} rest_vals = [] arg = nil tokens.each_with_index do |token, i| case token when '/?', '-?', '--help' @show_help = true when /^-([a-z0-9]+)/i $1.to_s.each_char do |sk| kw_vals[arg] = nil if arg arg = @definition[sk] if FlagArgument === arg kw_vals[arg] = true arg = nil end end when /^(?:--|\/)(no-)?(.+)/i kw_vals[arg] = nil if arg arg = @definition[$2] if FlagArgument === arg || (KeywordArgument === arg && $1) kw_vals[arg] = $1 ? false : true arg = nil end when '--' # All subsequent values are rest args kw_vals[arg] = nil if arg rest_vals = tokens[(i + 1)..-1] break else if arg kw_vals[arg] = token else pos_vals << token arg = @definition.positional_args[i] end tokens[i] = '******' if arg && arg.sensitive? arg = nil end end kw_vals[arg] = nil if arg [pos_vals, kw_vals, rest_vals] end |
#parse(tokens = ARGV) ⇒ Object
Parse the specified Array of tokens
, or ARGV if tokens
is nil. Returns false if unable to parse successfully, or an OpenStruct with accessors for every defined argument. Arguments whose values are not specified will contain the agument default value, or nil if no default is specified.
43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/arg-parser/parser.rb', line 43 def parse(tokens = ARGV) @show_usage = nil @show_help = nil @errors = [] begin pos_vals, kw_vals, rest_vals = classify_tokens(tokens) args = process_args(pos_vals, kw_vals, rest_vals) unless @show_help rescue NoSuchArgumentError => ex self.errors << ex. @show_usage = true end (@show_usage || @show_help) ? false : args end |
#process_args(pos_vals, kw_vals, rest_vals) ⇒ Object
Process arguments using the supplied pos_vals
Array of positional argument values, and the kw_vals
Hash of keyword/value.
127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 |
# File 'lib/arg-parser/parser.rb', line 127 def process_args(pos_vals, kw_vals, rest_vals) result = {} # Process positional arguments pos_args = @definition.positional_args pos_args.each_with_index do |arg, i| break if i >= pos_vals.length result[arg.key] = process_arg_val(arg, pos_vals[i], result) end if pos_vals.size > pos_args.size if @definition.rest_args? rest_vals = pos_vals[pos_args.size..-1] + rest_vals else self.errors << "#{pos_vals.size} positional #{pos_vals.size == 1 ? 'argument' : 'arguments'} #{ pos_vals.size == 1 ? 'was' : 'were'} supplied, but only #{pos_args.size} #{ pos_args.size == 1 ? 'is' : 'are'} defined" end end # Process key-word based arguments kw_vals.each do |arg, val| result[arg.key] = process_arg_val(arg, val, result) end # Process rest values if rest_arg = @definition.rest_args result[rest_arg.key] = process_arg_val(rest_arg, rest_vals, result) elsif rest_vals.size > 0 self.errors << "#{rest_vals.size} rest #{rest_vals.size == 1 ? 'value' : 'values'} #{ rest_vals.size == 1 ? 'was' : 'were'} supplied, but no rest argument is defined" end # Default unspecified arguments @definition.args.select{ |arg| !result.has_key?(arg.key) }.each do |arg| result[arg.key] = process_arg_val(arg, arg.default, result, true) end # Validate if any set requirements have been satisfied self.errors.concat(@definition.validate_requirements(result)) if self.errors.size > 0 @show_usage = true elsif result.empty? BasicObject.new else props = result.keys @definition.args.each{ |arg| props << arg.key unless result.has_key?(arg.key) } args = Struct.new(*props) args.new(*result.values) end end |
#show_help? ⇒ Boolean
Returns Flag set during parsing if the user has requested the help display to be shown (via –help or /?).
19 20 21 |
# File 'lib/arg-parser/parser.rb', line 19 def show_help? @show_help end |
#show_usage? ⇒ Boolean
Returns Flag set during parsing if the usage display should be shown. Set if there are any parse errors encountered.
14 15 16 |
# File 'lib/arg-parser/parser.rb', line 14 def show_usage? @show_usage end |