Class: Clin::OptionParser

Inherits:
Object
  • Object
show all
Defined in:
lib/clin/option_parser.rb

Overview

Class that handler the option parsing part of command parsing. It separate the options from the arguments

Constant Summary collapse

LONG_OPTION_REGEX =
/\A(?<name>--[^=]*)(?:=(?<value>.*))?/m
SHORT_OPTION_REGEX =
/\A(?<name>-.)(?<value>(=).*|.+)?/m

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(command, argv) ⇒ OptionParser

Returns a new instance of OptionParser.



21
22
23
24
25
26
27
28
29
# File 'lib/clin/option_parser.rb', line 21

def initialize(command, argv)
  @errors = []
  @command = command
  @options = {}
  @original_argv = argv
  @argv = argv.clone
  @arguments = []
  @skipped_options = []
end

Instance Attribute Details

#argumentsObject (readonly)

List of arguments(i.e. Argv segments that are not options)



10
11
12
# File 'lib/clin/option_parser.rb', line 10

def arguments
  @arguments
end

#errorsObject (readonly)

List of errors encountered



13
14
15
# File 'lib/clin/option_parser.rb', line 13

def errors
  @errors
end

#optionsObject (readonly)

Parsed options are store here



16
17
18
# File 'lib/clin/option_parser.rb', line 16

def options
  @options
end

#skipped_optionsObject (readonly)

Any option skipped(if the command allow it) will be listed in here



19
20
21
# File 'lib/clin/option_parser.rb', line 19

def skipped_options
  @skipped_options
end

Instance Method Details

#add_error(err) ⇒ Object



156
157
158
# File 'lib/clin/option_parser.rb', line 156

def add_error(err)
  @errors << err
end

#complete(value) ⇒ Object

Get the next possible argument in the list if the value is nil. Only get the next argument in the list if:

  • value is nil

  • the next argument is not an option(start with ‘-’)

Parameters:

  • value (String)

    current option value.



106
107
108
109
110
111
112
# File 'lib/clin/option_parser.rb', line 106

def complete(value)
  if value.nil? && @argv.any? && !@argv.first.start_with?('-')
    @argv.shift
  else
    value
  end
end

#handle_unknown_option(name, value) ⇒ Object

Handle the case where the option was not defined in the command. Add [UnknownOptionError] if the command doesn’t allow unknown options.

Parameters:

  • name (String)

    name used in the command.

  • value (String)

    Value of the option if applicable.



147
148
149
150
151
152
153
154
# File 'lib/clin/option_parser.rb', line 147

def handle_unknown_option(name, value)
  unless @command.skip_options?
    add_error Clin::UnknownOptionError.new(name)
    return
  end
  value = complete(value)
  @skipped_options += [name, value]
end

#parseHash

Parse the argument for the command. Options can also be accessed with #options “‘ # Suppose verbose and opt are defined option for the command. parser = OptionParser.new(command, %w(arg1 arg2 -v –opt val)) parser.parse #=> true, opt: ’val’ Get the arguments parser.argv # => [‘arg1’, ‘arg2’] “‘

Returns:

  • (Hash)

    return the options parsed



41
42
43
44
45
# File 'lib/clin/option_parser.rb', line 41

def parse
  while parse_next
  end
  @options
end

#parse_compact_flag_options(options) ⇒ Object

Parse compact flag_options(e.g. For -abc it will be called with ‘bc’)

Parameters:

  • options (String)

    List of options where each char should correspond to a short option



131
132
133
134
135
136
137
138
139
140
141
# File 'lib/clin/option_parser.rb', line 131

def parse_compact_flag_options(options)
  options.each_char do |s|
    option = @command.find_option_by(short: "-#{s}")
    if option && !option.flag?
      message = "Cannot combine short options that expect argument: #{option}"
      add_error Clin::OptionError.new(message, option)
      break
    end
    parse_flag_option(option, nil, true)
  end
end

#parse_flag_option(option, value, short) ⇒ Object

Parse a flag option(No argument) Add [OptionUnexpectedArgumentError] If value is defined and the long version was used. Short flag option can be merged together(i.e these are equivalent: -abc, -a -b -c) In that case the value will be ‘bc’. It will then try to parse b and c as flag options.



118
119
120
121
122
123
124
125
126
127
# File 'lib/clin/option_parser.rb', line 118

def parse_flag_option(option, value, short)
  return option.trigger(self, @options, true) if value.nil?
  unless short # Short can also have the format -abc
    return add_error Clin::OptionUnexpectedArgumentError.new(option, value)
  end

  option.trigger(self, @options, true)
  # The value is expected to be other flag options
  parse_compact_flag_options(value)
end

#parse_long(name, value) ⇒ Object

Parse a long option If the value is nil and the option allow argument it will try to use the next argument

Parameters:

  • name (String)

    name of the option(–verbose)

  • value (String)

    value of the option



70
71
72
73
# File 'lib/clin/option_parser.rb', line 70

def parse_long(name, value)
  option = @command.find_option_by(long: name)
  parse_option(option, name, value, false)
end

#parse_nextBoolean

Fetch the next next argument and parse the option or store it as an argument

Returns:

  • (Boolean)

    true if it parsed anything, false if there are no more argument to parse



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/clin/option_parser.rb', line 49

def parse_next
  return false if @argv.empty?
  case (arg = @argv.shift)
  when LONG_OPTION_REGEX
    name = Regexp.last_match[:name]
    value = Regexp.last_match[:value]
    parse_long(name, value)
  when SHORT_OPTION_REGEX
    name = Regexp.last_match[:name]
    value = Regexp.last_match[:value]
    parse_short(name, value)
  else
    @arguments << arg
  end
  true
end

#parse_option(option, name, value, short) ⇒ Object

Parse the given option. If the value is nil and the option allow argument it will try to use the next argument

Parameters:

  • option (Clin::Option)
  • name (String)

    name it was given in the command

  • value (String)

    value of the option



89
90
91
92
93
94
95
96
97
98
99
# File 'lib/clin/option_parser.rb', line 89

def parse_option(option, name, value, short)
  return handle_unknown_option(name, value) if option.nil?
  return parse_flag_option(option, value, short) if option.flag?

  value = complete(value)
  if value.nil? && !option.argument_optional?
    return add_error Clin::MissingOptionArgumentError.new(option)
  end
  value ||= true
  option.trigger(self, @options, value)
end

#parse_short(name, value) ⇒ Object

Parse a long option If the value is nil and the option allow argument it will try to use the next argument

Parameters:

  • name (String)

    name of the option(-v)

  • value (String)

    value of the option



79
80
81
82
# File 'lib/clin/option_parser.rb', line 79

def parse_short(name, value)
  option = @command.find_option_by(short: name)
  parse_option(option, name, value, true)
end