Module: Climate::ParsingMethods

Included in:
Command, Parser, Script
Defined in:
lib/climate/parser.rb

Instance Method Summary collapse

Instance Method Details

#arg(*args) ⇒ Object

Raises:



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/climate/parser.rb', line 97

def arg(*args)
  arg = Argument.new(*args)

  raise DefinitionError, "can not define more arguments after a multi " +
    " argument" if cli_arguments.any?(&:multi?)

  raise DefinitionError, "can not define a required argument after an " +
    "optional one" if cli_arguments.any?(&:optional?) && arg.required?

  cli_arguments << arg
end

#cli_argumentsObject



214
# File 'lib/climate/parser.rb', line 214

def cli_arguments       ; @cli_arguments ||= []       ; end

#cli_optionsObject



213
# File 'lib/climate/parser.rb', line 213

def cli_options         ; @cli_options ||= []         ; end

#conflicting_optionsObject



215
# File 'lib/climate/parser.rb', line 215

def conflicting_options ; @conflicting_options ||= [] ; end

#conflicts(*args) ⇒ Object



117
118
119
# File 'lib/climate/parser.rb', line 117

def conflicts(*args)
  conflicting_options << args
end

#dependent_optionsObject



216
# File 'lib/climate/parser.rb', line 216

def dependent_options   ; @dependent_options ||= []   ; end

#depends(*args) ⇒ Object



121
122
123
# File 'lib/climate/parser.rb', line 121

def depends(*args)
  dependent_options << args
end

#has_argument?(name) ⇒ Boolean

Returns:

  • (Boolean)


221
222
223
# File 'lib/climate/parser.rb', line 221

def has_argument?(name)
  cli_arguments.map(&:name).include?(name)
end

#has_arguments?Boolean

Returns:

  • (Boolean)


219
# File 'lib/climate/parser.rb', line 219

def has_arguments? ;   not cli_arguments.empty? ; end

#has_multi_argument?(name) ⇒ Boolean

Returns:

  • (Boolean)


229
230
231
# File 'lib/climate/parser.rb', line 229

def has_multi_argument?(name)
  cli_arguments.select(&:multi?).map(&:name).include?(name)
end

#has_options?Boolean

Returns:

  • (Boolean)


218
# File 'lib/climate/parser.rb', line 218

def has_options? ;     not cli_options.empty?   ; end

#has_required_argument?(name) ⇒ Boolean

Returns:

  • (Boolean)


225
226
227
# File 'lib/climate/parser.rb', line 225

def has_required_argument?(name)
  cli_arguments.select(&:required?).map(&:name).include?(name)
end

#opt(*args) ⇒ Object



109
110
111
# File 'lib/climate/parser.rb', line 109

def opt(*args)
  cli_options << Option.new(*args)
end

#parse(arguments, command = self) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
# File 'lib/climate/parser.rb', line 182

def parse(arguments, command=self)
  parser = self.trollop_parser

  begin
    options = parser.parse(arguments)
  rescue Trollop::CommandlineError => e
    if (m = /unknown argument '(.+)'/.match(e.message))
      raise UnexpectedArgumentError.new(m[1], command)
    elsif (m = /option (.+) must be specified/.match(e.message))
      raise MissingArgumentError.new(m[1], command)
    elsif  /.+ conflicts with .+/.match(e.message)
      raise ConflictingOptionError.new(e.message, command)
    elsif /.+ requires .+/.match(e.message)
      raise MissingArgumentError.new(e.message, command)
    else
      raise CommandError.new(e.message, command)
    end
  end

  # it would get weird if we allowed arguments alongside options, so
  # lets keep it one or t'other
  arguments, leftovers =
    if @stop_on
      [{}, parser.leftovers]
    else
      [self.parse_arguments(parser.leftovers), []]
    end

  [arguments, options, leftovers]
end

#parse_arguments(args, command = self) ⇒ Object



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
# File 'lib/climate/parser.rb', line 143

def parse_arguments(args, command=self)

  arg_list = cli_arguments

  if arg_list.none?(&:multi?) && args.size > arg_list.size
    raise UnexpectedArgumentError.new("#{args.size} for #{arg_list.size}", command)
  end

  # mung the last arguments to appear as one for multi args, this is fairly
  # ugly - thank heavens for unit tests
  if arg_list.last && arg_list.last.multi?
    multi_arg = arg_list.last
    last_args = args[(arg_list.size - 1)..-1] || []

    # depending on the number of args that were supplied, you may get nil
    # or an empty array because of how slicing works, either way we want nil
    # if no args were supplied so `required?` detection works below
    args = args[0...(arg_list.size - 1)] +
      [last_args.empty?? nil : last_args].compact
  end

  arg_list.zip(args).map do |argument, arg_value|
    arg_value ||= argument.default
    if argument.required? && arg_value.nil?
      raise MissingArgumentError.new(argument.name, command)
    end

    # empty list is nil for multi arg
    arg_value = [] if argument.multi? && arg_value.nil?

    # no arg given is different to an empty arg
    if arg_value.nil?
      {}
    else
      {argument.name => arg_value}
    end
  end.inject {|a,b| a.merge(b) } || {}
end

#stop_on(args) ⇒ Object



113
114
115
# File 'lib/climate/parser.rb', line 113

def stop_on(args)
  @stop_on = args
end

#trollop_parserObject



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/climate/parser.rb', line 125

def trollop_parser
  Trollop::Parser.new.tap do |parser|
    parser.stop_on @stop_on

    cli_options.each do |option|
      option.add_to(parser)
    end

    conflicting_options.each do |conflicting|
      parser.conflicts(*conflicting)
    end

    dependent_options.each do |dependent|
      parser.depends(*dependent)
    end
  end
end