Class: Clip::Parser

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeParser

:nodoc:



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

def initialize # :nodoc:
  @errors = {}
  @valid = true
  @longest = 10
  @help_long = "--help"
  @help_short = "-h"
end

Instance Attribute Details

Set the usage ‘banner’ displayed when calling to_s to display the usage message. If not set, the default will be used. If the value is set this completely replaces the default



36
37
38
# File 'lib/clip.rb', line 36

def banner
  @banner
end

#remainderObject (readonly)

Returns any remaining command line arguments that were not parsed because they were neither flags or option/value pairs



30
31
32
# File 'lib/clip.rb', line 30

def remainder
  @remainder
end

Instance Method Details

#errorsObject

Returns a Hash of errors (by the long name) of any errors encountered during parsing. If you simply want to display error messages to the user, you can just print out a call to the to_s method.



226
227
228
# File 'lib/clip.rb', line 226

def errors
  @errors
end

#flag(short, long, options = {}) ⇒ Object

Declare a parameter as a simple boolean flag. This declaration will create a “question” method matching the given long. For example, declaring with the name of ‘verbose’ will create a method on your parser called verbose?.

options

Valid options are:

  • desc: Descriptive text for the flag



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/clip.rb', line 126

def flag(short, long, options={})
  check_args(short, long)

  short = short.to_sym
  long = long.gsub('-', '_').to_sym
  self.class.class_eval do
    define_method("flag_#{long}") do
      instance_variable_set("@#{long}", true)
    end

    define_method("#{long}?") do
      instance_variable_get("@#{long}")
    end
  end

  self.options[long] = Flag.new(short, long, options)
  self.options[short] = self.options[long]
  self.order << self.options[long]
  check_longest(long)
end

#helpObject

Returns a formatted String indicating the usage of the parser, formatted to fit within 80 display columns.



233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
# File 'lib/clip.rb', line 233

def help
  out = ""
  if banner
    out << "#{banner}\n"
  else
    out << "Usage:\n"
  end

  order.each do |option|
    line = sprintf("-%-2s --%-#{@longest}s  ",
                   option.short,
                   option.long.to_s.gsub('_', '-'))

    out << line
    if line.length + option.description.length <= 80
      out << option.description
    else
      rem = 80 - line.length
      desc = option.description
      i = 0
      while i < desc.length
        out << "\n" if i > 0
        j = [i + rem, desc.length].min
        while desc[j..j] =~ /[\w\d]/
          j -= 1
        end
        chunk = desc[i..j].strip
        out << " " * line.length if i > 0
        out << chunk
        i = j + 1
      end
    end

    if option.has_default?
      out << " (default: #{option.default})"
    end

    if option.required?
      out << " REQUIRED"
    end
    out << "\n"
  end
  out
end

#help_with(short, long = "--help") ⇒ Object

Override the flag to trigger help usage. By default the short flag ‘-h’ and long flag ‘–help’ will trigger displaying usage. If you need to override this, particularly in the case of ‘-h’, call this method



43
44
45
46
# File 'lib/clip.rb', line 43

def help_with(short, long="--help")
  @help_short = short
  @help_long = long
end

#optional(short, long, options = {}, &block) ⇒ Object Also known as: opt

Declare an optional parameter for your parser. This creates an accessor method matching the long parameter and a present method long?. The short parameter indicates the single-letter equivalent. Options that use the ‘-’ character as a word separator are converted to method names using ‘_’. For example the name ‘exclude-files’ would create two methods named exclude_files and exclude_files?.

When the :multi option is enabled, the associated accessor method will return an Array instead of a single scalar value.

options

Valid options include:

  • desc: a helpful description (used for printing usage)

  • default: a default value to provide if one is not given

  • multi: indicates that mulitple values are okay for this param.

  • block: an optional block to process the parsed value

Note that specifying the :multi option means that the parameter can be specified several times with different values, or that a single comma-separated value can be specified which will then be broken up into separate tokens.



70
71
72
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
# File 'lib/clip.rb', line 70

def optional(short, long, options={}, &block)
  check_args(short, long)

  short = short.to_sym
  long = long.gsub('-', '_').to_sym

  var_name = "@#{long}".to_sym
  self.class.class_eval do
    define_method("#{long}=".to_sym) do |v|
      begin
        v = yield(v) if block_given?
        instance_variable_set(var_name, v)
      rescue StandardError => e
        @valid = false
        @errors[long] = e.message
      end
    end

    define_method(long.to_sym) do
      instance_variable_get(var_name)
    end

    define_method("#{long}?") do
      !instance_variable_get(var_name).nil?
    end
  end

  self.options[short] = self.options[long] =
    Option.new(short, long, options)

  self.order << self.options[long]
  check_longest(long)
end

#optionsObject

:nodoc:



293
294
295
# File 'lib/clip.rb', line 293

def options # :nodoc:
  (@options ||= {})
end

#orderObject

:nodoc:



297
298
299
# File 'lib/clip.rb', line 297

def order # :nodoc:
  (@order ||= [])
end

#parse(args) ⇒ Object

Parse the given args and set the corresponding instance fields to the given values. If any errors occurred during parsing you can get them from the Hash returned by the errors method.



159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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/clip.rb', line 159

def parse(args)
  @valid = true
  args = Shellwords::shellwords(args) unless args.kind_of?(Array)
  consumed = []
  option = nil

  args.each do |token|
    case token
    when @help_long, @help_short
      puts help
      exit 0

    when /\A--\z/
      consumed << token
      break

    when /^-(-)?\w/
      consumed << token
      param = token.sub(/^-(-)?/, '').gsub('-', '_').to_sym
      option = options[param]
      if option.nil?
        @errors[param] = "Unrecognized parameter"
        @valid = false
        next
      end

      if option.kind_of?(Flag)
        option.process(self, nil)
        option = nil
      end
    else
      if option
        consumed << token
        option.process(self, token)
        option = nil
      end
    end
  end

  @remainder = args - consumed

  # Find required options that are missing arguments
  options.each do |param, opt|
    if opt.kind_of?(Option) and self.send(opt.long).nil?
      if opt.required?
        @valid = false
        @errors[opt.long.to_sym] = "Missing required parameter: #{opt.long}"
      elsif opt.has_default?
        opt.process(self, opt.default)
      end
    end
  end
end

#required(short, long, options = {}, &block) ⇒ Object Also known as: req

Declare a required parameter for your parser. If this parameter is not provided in the parsed content, the parser instance will be invalid (i.e. where valid? returns false).

This method takes the same options as the optional method.



112
113
114
# File 'lib/clip.rb', line 112

def required(short, long, options={}, &block)
  optional(short, long, options.merge({ :required => true }), &block)
end

#to_sObject

Returns a formatted String of the help method prefixed by any parsing errors. Either way you have one method to call to let your users know what to do.



282
283
284
285
286
287
288
289
290
291
# File 'lib/clip.rb', line 282

def to_s
  out = ""
  unless valid?
    out << "Errors:\n"
    errors.each do |field, msg|
      out << "#{field}: #{msg}\n"
    end
  end
  out << help
end

#valid?Boolean

Indicates whether or not the parsing process succeeded. If this returns false you probably just want to print out a call to the to_s method.

Returns:

  • (Boolean)


217
218
219
# File 'lib/clip.rb', line 217

def valid?
  @valid
end