Class: Cri::OptionParser
- Inherits:
-
Object
- Object
- Cri::OptionParser
- Defined in:
- lib/SANStore/cri/option_parser.rb
Overview
Cri::OptionParser is used for parsing commandline options.
Defined Under Namespace
Classes: IllegalOptionError, OptionRequiresAnArgumentError
Class Method Summary collapse
-
.parse(arguments_and_options, definitions) ⇒ Object
Parses the commandline arguments in
arguments_and_options
, using the commandline option definitions indefinitions
.
Class Method Details
.parse(arguments_and_options, definitions) ⇒ Object
Parses the commandline arguments in arguments_and_options
, using the commandline option definitions in definitions
.
arguments_and_options
is an array of commandline arguments and options. This will usually be ARGV
.
definitions
contains a list of hashes defining which options are allowed and how they will be handled. Such a hash has three keys:
- :short
-
The short name of the option, e.g.
a
. Do not include the ‘-’ prefix. - :long
-
The long name of the option, e.g.
all
. Do not include the ‘–’ prefix. - :argument
-
Whether this option’s argument is required (:required), optional (:optional) or forbidden (:forbidden).
A sample array of definition hashes could look like this:
[
{ :short => 'a', :long => 'all', :argument => :forbidden },
{ :short => 'p', :long => 'port', :argument => :required },
]
During parsing, two errors can be raised:
- IllegalOptionError
-
An unrecognised option was encountered, i.e. an option that is not present in the list of option definitions.
- OptionRequiresAnArgumentError
-
An option was found that did not have a value, even though this value was required.
What will be returned, is a hash with two keys, :arguments and :options. The :arguments value contains a list of arguments, and the :options value contains a hash with key-value pairs for each option. Options without values will have a nil
value instead.
For example, the following commandline options (which should not be passed as a string, but as an array of strings):
foo -xyz -a hiss -s -m please --level 50 --father=ani -n luke squeak
with the following option definitions:
[
{ :short => 'x', :long => 'xxx', :argument => :forbidden },
{ :short => 'y', :long => 'yyy', :argument => :forbidden },
{ :short => 'z', :long => 'zzz', :argument => :forbidden },
{ :short => 'a', :long => 'all', :argument => :forbidden },
{ :short => 's', :long => 'stuff', :argument => :optional },
{ :short => 'm', :long => 'more', :argument => :optional },
{ :short => 'l', :long => 'level', :argument => :required },
{ :short => 'f', :long => 'father', :argument => :required },
{ :short => 'n', :long => 'name', :argument => :required }
]
will be translated into:
{
:arguments => [ 'foo', 'hiss', 'squeak' ],
:options => {
:xxx => true,
:yyy => true,
:zzz => true,
:all => true,
:stuff => true,
:more => 'please',
:level => '50',
:father => 'ani',
:name => 'luke'
}
}
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 123 124 125 126 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 177 178 179 180 181 182 |
# File 'lib/SANStore/cri/option_parser.rb', line 88 def self.parse(, definitions) # Don't touch original argument = .dup # Initialize arguments = [] = {} # Determines whether we've passed the '--' marker or not = false loop do # Get next item e = .shift break if e.nil? # Handle end-of-options marker if e == '--' = true # Handle incomplete options elsif e =~ /^--./ and ! # Get option key, and option value if included if e =~ /^--([^=]+)=(.+)$/ option_key = $1 option_value = $2 else option_key = e[2..-1] option_value = nil end # Find definition definition = definitions.find { |d| d[:long] == option_key } raise IllegalOptionError.new(option_key) if definition.nil? if [ :required, :optional ].include?(definition[:argument]) # Get option value if necessary if option_value.nil? option_value = .shift if option_value.nil? || option_value =~ /^-/ if definition[:argument] == :required raise OptionRequiresAnArgumentError.new(option_key) else .unshift(option_value) option_value = true end end end # Store option [definition[:long].to_sym] = option_value else # Store option [definition[:long].to_sym] = true end # Handle -xyz options elsif e =~ /^-./ and ! # Get option keys option_keys = e[1..-1].scan(/./) # For each key option_keys.each do |option_key| # Find definition definition = definitions.find { |d| d[:short] == option_key } raise IllegalOptionError.new(option_key) if definition.nil? if option_keys.length > 1 and definition[:argument] == :required # This is a combined option and it requires an argument, so complain raise OptionRequiresAnArgumentError.new(option_key) elsif [ :required, :optional ].include?(definition[:argument]) # Get option value option_value = .shift if option_value.nil? || option_value =~ /^-/ if definition[:argument] == :required raise OptionRequiresAnArgumentError.new(option_key) else .unshift(option_value) option_value = true end end # Store option [definition[:long].to_sym] = option_value else # Store option [definition[:long].to_sym] = true end end # Handle normal arguments else arguments << e end end { :options => , :arguments => arguments } end |