Class Boson::OptionParser

  1. lib/boson/option_parser.rb
Parent: Object

This class concisely defines commandline options that when parsed produce a Hash of option keys and values. Additional points:

  • Setting option values should follow conventions in *nix environments. See examples below.
  • By default, there are 5 option types, each which produce different objects for option values.
  • The default option types can produce objects for one or more of the following Ruby classes: String, Integer, Float, Array, Hash, FalseClass, TrueClass.
  • Users can define their own option types which create objects for any Ruby class. See Options.
  • Each option type can have attributes to enable more features (see
  • When options are parsed by parse(), an IndifferentAccessHash hash is returned.
  • Options are also called switches, parameters, flags etc.
  • Option parsing stops when it comes across a ’—’.

Default option types:

This option has no passed value. To toogle a boolean, prepend with ’—no-’. Multiple booleans can be joined together.
'--debug'    -> {:debug=>true}
'--no-debug' -> {:debug=>false}
'--no-d'     -> {:debug=>false}
'-d -f -t' same as '-dft'
Sets values by separating name from value with space or ’=’.
'--color red' -> {:color=>'red'}
'--color=red' -> {:color=>'red'}
'--color "gotta love spaces"' -> {:color=>'gotta love spaces'}
Sets values as :string does or by appending number right after aliased name. Shortened form can be appended to joined booleans.
'-n3'  -> {:num=>3}
'-dn3' -> {:debug=>true, :num=>3}
Sets values as :string does. Multiple values are split by a configurable character Default is ’,’ (see Passing ’*’ refers to all known :values.
'--fields 1,2,3' -> {:fields=>['1','2','3']}
'--fields *'     -> {:fields=>['1','2','3']}
Sets values as :string does. Key-value pairs are split by ’:’ and pairs are split by a configurable character (default ’,’). Multiple keys can be joined to one value. Passing ’*’ as a key refers to all known :keys.
'--fields a:b,c:d' -> {:fields=>{'a'=>'b', 'c'=>'d'} }
'--fields a,b:d'   -> {:fields=>{'a'=>'d', 'b'=>'d'} }
'--fields *:d'     -> {:fields=>{'a'=>'d', 'b'=>'d', 'c'=>'d'} }

This is a modified version of Yehuda Katz’s Thor::Options class which is a modified version of Daniel Berger’s Getopt::Long class (licensed under Ruby’s license).

Classes and Modules

Class Boson::OptionParser::Error


NUMERIC = /(\d*\.\d+|\d+)/
LONG_RE = /^(--\w+[-\w+]*)$/
SHORT_RE = /^(-[a-zA-Z])$/i
EQ_RE = /^(--\w+[-\w+]*|-[a-zA-Z])=(.*)$/i
SHORT_SQ_RE = /^-([a-zA-Z]{2,})$/i
SHORT_NUM = /^(-[a-zA-Z])#{NUMERIC}$/i
STOP_STRINGS = %w{-- -}


leading_non_opts [R]
opt_aliases [R]
trailing_non_opts [R]

Public class methods

new (opts)

Takes a hash of options. Each option, a key-value pair, must provide the option’s name and type. Names longer than one character are accessed with ’—’ while one character names are accessed with ’-’. Names can be symbols, strings or even dasherized strings: :debug=>:boolean, 'level'=>:numeric,

Options can have default values and implicit types simply by changing the option type for the default value: :debug=>true, 'level'=>3.1, :fields=>%w{f1 f2}

By default every option name longer than one character is given an alias, the first character from its name. For example, the —fields option has -f as its alias. You can override the default alias by providing your own option aliases as an array in the option’s key. [:debug, :damnit, :D]=>true

Note that aliases are accessed the same way as option names. For the above, —debug, —damnit and -D all refer to the same option.

Options can have additional attributes by passing a hash to the option value instead of a type or default: :fields=>{:type=>:array, :values=>%w{f1 f2 f3},

These attributes are available when an option is parsed via current_attributes(). Here are the available option attributes for the default option types:

This or :default is required. Available types are :string, :boolean, :array, :numeric, :hash.
This or :type is required. This is the default value an option has when not passed.
This is the value an option has when passed as a boolean. However, by enabling this an option can only have explicit values with ’=’ i.e. ’—index=alias’ and no ’—index alias’. If this value is a string, it is parsed as any option value would be. Otherwise, the value is passed directly without parsing.
Boolean indicating if option is required. Option parses raises error if value not given. Default is false.
Alternative way to define option aliases with an option name or an array of them. Useful in yaml files. Setting to false will prevent creating an automatic alias.
An array of values an option can have. Available for :array and :string options. Values here can be aliased by typing a unique string it starts with or underscore aliasing (see Util.underscore_search). For example, for values foo, odd and obnoxiously_long, f refers to foo, od to odd and o_l to obnoxiously_long.
Boolean indicating if an option enforces values in :values or :keys. Default is true. For :array, :hash and :string options.
For :array and :hash options. A string or regular expression on which an array value splits to produce an array of values. Default is ’,’.
:hash option only. An array of values a hash option’s keys can have. Keys can be aliased just like :values.
For :hash option only. Default keys to assume when only a value is given. Multiple keys can be joined by the :split character. Defaults to first key of :keys if :keys given.
For :array option with a :values attribute. Boolean indicating that each option value does a regular expression search of :values. If there are values that match, they replace the original option value. If none, then the original option value is used.
[show source]
# File lib/boson/option_parser.rb, line 165
    def initialize(opts)
      @defaults = {}
      @opt_aliases = {}
      @leading_non_opts, @trailing_non_opts = [], []

      # build hash of dashed options to option types
      # type can be a hash of opt attributes, a default value or a type symbol
      @opt_types = opts.inject({}) do |mem, (name, type)|
        name, *aliases = name if name.is_a?(Array)
        name = name.to_s
        # we need both nice and dasherized form of option name
        if name.index('-') == 0
          nice_name = undasherize name
          nice_name = name
          name = dasherize name
        # store for later
        @opt_aliases[nice_name] = aliases || []

        if type.is_a?(Hash)
          @option_attributes ||= {}
          @option_attributes[nice_name] = type
          @opt_aliases[nice_name] = Array(type[:alias]) if type.key?(:alias)
          @defaults[nice_name] = type[:default] if type[:default]
          @option_attributes[nice_name][:enum] = true if (type.key?(:values) || type.key?(:keys)) &&
          @option_attributes[nice_name][:default_keys] ||= type[:keys][0] if type.key?(:keys)
          type = type[:type] || (!type[:default].nil? ? determine_option_type(type[:default]) : :boolean)

        # set defaults
        case type
        when TrueClass                     then  @defaults[nice_name] = true
        when FalseClass                    then  @defaults[nice_name] = false
        else @defaults[nice_name] = type unless type.is_a?(Symbol)
        mem[name] = !type.nil? ? determine_option_type(type) : type

      # generate hash of dashed aliases to dashed options
      @opt_aliases = @opt_aliases.sort.inject({}) {|h, (nice_name, aliases)|
        name = dasherize nice_name
        # allow for aliases as symbols! {|e| e.to_s.index('-') == 0 || e == false ? e : dasherize(e.to_s) }
        if aliases.empty? and nice_name.length > 1
          opt_alias = nice_name[0,1]
          opt_alias = h.key?("-"+opt_alias) ? "-"+opt_alias.capitalize : "-"+opt_alias
          h[opt_alias] ||= name unless @opt_types.key?(opt_alias)
          aliases.each {|e| h[e] = name if !@opt_types.key?(e) && e != false }
parse (options, args=ARGV)

Given options to pass to, this method parses ARGV and returns the remaining arguments and a hash of parsed options. This is useful for scripts outside of Boson.

[show source]
# File lib/boson/option_parser.rb, line 86
    def self.parse(options, args=ARGV)
      @opt_parser ||= new(options)
      parsed_options = @opt_parser.parse(args)
      [@opt_parser.non_opts, parsed_options]
usage ()

Usage string summarizing options defined in parse

[show source]
# File lib/boson/option_parser.rb, line 93
    def self.usage

Public instance methods

aliases ()

List of option aliases

[show source]
# File lib/boson/option_parser.rb, line 349
    def aliases {|e| undasherize e }
current_attributes ()

Hash of option attributes for the currently parsed option. Any hash keys passed to an option are available here. This means that an option type can have any user-defined attributes available during option parsing and object creation.

[show source]
# File lib/boson/option_parser.rb, line 324
    def current_attributes
      @option_attributes && @option_attributes[@current_option] || {}
dasherize (str)

Adds dashes to an option name i.e. ‘date’ -> ’—date’ and ‘d’ -> ’-d’.

[show source]
# File lib/boson/option_parser.rb, line 334
    def dasherize(str)
      (str.length > 1 ? "--" : "-") + str
default_usage (opt, val)

Helper method to generate usage. Takes a dashed option and a string value indicating an option value’s format.

[show source]
# File lib/boson/option_parser.rb, line 267
    def default_usage(opt, val)
      opt + "=" + (@defaults[undasherize(opt)] || val).to_s
formatted_usage ()

Generates one-line usage of all options.

[show source]
# File lib/boson/option_parser.rb, line 272
    def formatted_usage
      return "" if @opt_types.empty? do |opt, type|
        val = respond_to?("usage_for_#{type}", true) ? send("usage_for_#{type}", opt) : "#{opt}=:#{type}"
        "[" + val + "]"
      end.join(" ")
names ()

List of option names

[show source]
# File lib/boson/option_parser.rb, line 344
    def names {|e| undasherize e }
non_opts ()

Array of arguments left after defined options have been parsed out by parse.

[show source]
# File lib/boson/option_parser.rb, line 106
    def non_opts
      leading_non_opts + trailing_non_opts
option_attributes ()

Hash of option names mapped to hash of its external attributes

[show source]
# File lib/boson/option_parser.rb, line 312
    def option_attributes
      @option_attributes || {}
option_type (opt)
[show source]
# File lib/boson/option_parser.rb, line 353
    def option_type(opt)
      if opt =~ /^--no-(\w+)$/
        @opt_types[opt] || @opt_types[dasherize($1)] || @opt_types[original_no_opt($1)]
parse (args, flags={})

Parses an array of arguments for defined options to return an IndifferentAccessHash. Once the parser recognizes a valid option, it continues to parse until an non option argument is detected. Flags that can be passed to the parser:

  • :opts_before_args: When true options must come before arguments. Default is false.
  • :delete_invalid_opts: When true deletes any invalid options left after parsing. Will stop deleting if it comes across - or —. Default is false.
[show source]
# File lib/boson/option_parser.rb, line 228
    def parse(args, flags={})
      @args = args
      # start with defaults
      hash = @defaults
      @leading_non_opts = []
      unless flags[:opts_before_args]
        @leading_non_opts << shift until current_is_option? || @args.empty? || STOP_STRINGS.include?(peek)

      while current_is_option?
        case @original_current_option = shift
        when SHORT_SQ_RE
          unshift $1.split('').map { |f| "-#{f}" }
        when EQ_RE, SHORT_NUM
          unshift $2
          option = $1
        when LONG_RE, SHORT_RE
          option = $1

        dashed_option = normalize_option(option)
        @current_option = undasherize(dashed_option)
        type = option_type(dashed_option)
        value = create_option_value(type)
        # set on different line since current_option may change
        hash[@current_option.to_sym] = value

      @trailing_non_opts = @args
      check_required! hash
      delete_invalid_opts if flags[:delete_invalid_opts]
print_usage_table (render_options={})

More verbose option help in the form of a table.

[show source]
# File lib/boson/option_parser.rb, line 283
    def print_usage_table(render_options={})
      user_fields = render_options.delete(:fields)
      fields = get_usage_fields user_fields
      (fields << :default).uniq! if render_options.delete(:local) || user_fields == '*'
      opts = all_options_with_fields fields
      fields.delete(:default) if fields.include?(:default) && opts.all? {|e| e[:default].nil? }
      render_options = default_render_options.merge(:fields=>fields).merge(render_options)
      View.render opts, render_options
to_s ()

Alias for formatted_usage

types ()

List of option types

[show source]
# File lib/boson/option_parser.rb, line 339
    def types
undasherize (str)

Removes dashes from a dashed option i.e. ’—date’ -> ‘date’ and ’-d’ -> ‘d’.

[show source]
# File lib/boson/option_parser.rb, line 329
    def undasherize(str)
      str.sub(/^-{1,2}/, '')