Class: ConfigParser

Inherits:
Object
  • Object
show all
Includes:
Utils
Defined in:
lib/config_parser.rb,
lib/config_parser/flag.rb,
lib/config_parser/list.rb,
lib/config_parser/utils.rb,
lib/config_parser/option.rb,
lib/config_parser/switch.rb,
lib/config_parser/version.rb

Overview

ConfigParser is an option parser that formalizes the pattern of setting parsed options into a hash. ConfigParser provides a similar declaration syntax as OptionParser but additionally supports option declaration using an attributes hash.

Defined Under Namespace

Modules: Utils Classes: Flag, List, Option, Switch

Constant Summary collapse

MAJOR =
0
MINOR =
5
TINY =
5
VERSION =
"#{MAJOR}.#{MINOR}.#{TINY}"

Constants included from Utils

Utils::DELIMITER, Utils::LONG_FLAG, Utils::NEST, Utils::OPTION, Utils::OPTION_BREAK, Utils::SHORT_FLAG, Utils::SWITCH

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Utils

guess_hint, guess_option_type, guess_option_type_by_arg_name, guess_option_type_by_value, longify, next_arg, option?, parse_attrs, prefix_long, shortify, wrap

Constructor Details

#initialize(config = {}, opts = {}) {|_self| ... } ⇒ ConfigParser

Initializes a new ConfigParser and passes it to the block, if given.

Yields:

  • (_self)

Yield Parameters:

  • _self (ConfigParser)

    the object that the method was called on


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# File 'lib/config_parser.rb', line 33

def initialize(config={}, opts={})
  opts = {
    :option_break => OPTION_BREAK,
    :preserve_option_break => false,
    :assign_defaults => true
  }.merge(opts)

  @registry = []
  @options = {}
  @config = config
  @option_break = opts[:option_break]
  @preserve_option_break = opts[:preserve_option_break]
  @assign_defaults = opts[:assign_defaults]

  yield(self) if block_given?
end

Instance Attribute Details

#assign_defaultsObject

Set to true to assign config defaults on parse.


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

def assign_defaults
  @assign_defaults
end

#configObject

The hash receiving parsed configs.


21
22
23
# File 'lib/config_parser.rb', line 21

def config
  @config
end

#option_breakObject

The argument to stop processing options.


24
25
26
# File 'lib/config_parser.rb', line 24

def option_break
  @option_break
end

#optionsObject (readonly)

A hash of (flag, Option) pairs mapping command line flags like '-s' or '–long' to the Option that handles them.


18
19
20
# File 'lib/config_parser.rb', line 18

def options
  @options
end

#preserve_option_breakObject

Set to true to preserve the option break.


27
28
29
# File 'lib/config_parser.rb', line 27

def preserve_option_break
  @preserve_option_break
end

#registryObject (readonly)

Returns an array of the options registered with self, in the order in which they were added. Separators are also stored in the registry.


14
15
16
# File 'lib/config_parser.rb', line 14

def registry
  @registry
end

Instance Method Details

#[](key) ⇒ Object

Returns the config value for key.


51
52
53
# File 'lib/config_parser.rb', line 51

def [](key)
  config[key]
end

#[]=(key, value) ⇒ Object

Sets the config value for key.


56
57
58
# File 'lib/config_parser.rb', line 56

def []=(key, value)
  config[key] = value
end

#add(key, default = nil, *args, &block) ⇒ Object

An alternate syntax for on, where the key and default attributes are set by the first two args. Like on, add can define option attributes using a series of args or with a trailing hash.

These are equivalent:

add(:opt, 'value', '-s', '--long', :desc => 'description')
on('-s', '--long', :desc => 'description', :key => :opt, :default => 'value')

201
202
203
204
205
206
# File 'lib/config_parser.rb', line 201

def add(key, default=nil, *args, &block)
  attrs = args.last.kind_of?(Hash) ? args.pop : {}
  attrs = attrs.merge(:key => key, :default => default)
  args << attrs
  on(*args, &block)
end

#on(*args, &block) ⇒ Object

Constructs an Option using args and registers it with self. The args may contain (in any order) a short switch, a long switch, and a description string. A callback may be provided as a block to process values for the option.

The option type (flag, switch, list, or option) is guessed from the args, and affects what is passed to the block.

psr = ConfigParser.new

# options take an argument on the long
# and receive the arg in the block
psr.on('-s', '--long ARG_NAME', 'description') do |arg|
  # ...
end

# the argname can be specified on a short
psr.on('-o ARG_NAME') do |arg|
  # ...
end

# use an argname with commas to make a list,
# each arg is passed to the block separately
psr.on('--list A,B,C') do |arg|
  # ...
end

# flags specify no argument, and the
# block takes no argument
psr.on('-f', '--flag') do
  # ...
end

# switches look like this; they get true
# or false in the block
psr.on('--[no-]switch') do |bool|
  # ...
end

If this is too ambiguous (and at times it is), provide a trailing hash defining all or part of the option. Note any object that responds to call may be set as the callback:

psr.on('-k', 'description',
  :long => '--key',
  :option_type => :list,
  :callback => lambda {|args| ... }
)

The trailing hash wins if there is any overlap in the parsed attributes and those provided by the hash. The block wins if both a block and a callback are given.


183
184
185
# File 'lib/config_parser.rb', line 183

def on(*args, &block)
  register new_option(args, &block)
end

#on!(*args, &block) ⇒ Object

Same as on, but overrides options with overlapping flags.


188
189
190
# File 'lib/config_parser.rb', line 188

def on!(*args, &block)
  register new_option(args, &block), true
end

#parse(argv = ARGV, &block) ⇒ Object

Parses options from argv in a non-destructive manner. Parsing stops if an argument matching option_break is reached. If preserve_option_break is specified then the option break is preserved in the remaining arguments. Returns an array of arguments remaining after options have been removed.

If a string argv is provided, it will be splits into an array using Shellwords.


227
228
229
230
# File 'lib/config_parser.rb', line 227

def parse(argv=ARGV, &block)
  argv = argv.dup unless argv.kind_of?(String)
  parse!(argv, &block)
end

#parse!(argv = ARGV) ⇒ Object

Same as parse, but removes parsed args from argv.


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
277
278
279
280
281
282
283
284
# File 'lib/config_parser.rb', line 233

def parse!(argv=ARGV)
  argv = Shellwords.shellwords(argv) if argv.kind_of?(String)

  registry.each do |option|
    if assign_defaults && option.respond_to?(:assign_default)
      option.assign_default(config)
    end
  end

  args = []
  while !argv.empty?
    arg = argv.shift

    # add the remaining args and break
    # for the option break
    if option_break === arg
      argv.unshift(arg) if preserve_option_break
      break
    end

    # determine if the arg is an option
    unless option?(arg)
      args << arg
      next
    end

    flag, value = arg, nil

    # try the flag directly
    unless option = @options[flag]

      # then try --opt=value syntax
      flag, value = flag.split('=', 2)

      # then try -ovalue syntax
      if value.nil? && flag[1] != ?-
        flag, value = flag[0, 2], flag[2, flag.length - 2]
      end

      unless option = @options[flag]
        raise "unknown option: #{flag}"
      end
    end

    option.parse(flag, value, argv, config)
  end

  args.concat(argv)
  argv.replace(args)

  block_given? ? yield(argv, config) : argv
end

#register(option, override = false) ⇒ Object

Registers the option with self by adding it to the registry and mapping the option flags into options. Raises an error for conflicting flags. Returns option.

If override is specified, options with conflicting flags are removed and no error is raised. Note that this may remove multiple options.


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/config_parser.rb', line 71

def register(option, override=false)
  return nil if option.nil?

  if override
    existing = option.flags.collect {|flag| @options.delete(flag) }
    @registry -= existing
  end

  unless @registry.include?(option)
    @registry << option
  end

  option.flags.each do |flag|
    current = @options[flag]

    if current && current != option
      raise ArgumentError, "already mapped to a different option: #{flag}"
    end

    @options[flag] = option
  end

  option
end

#reset(options = {}) ⇒ Object

Resets each option and clears the config (if specified). Returns self.


287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'lib/config_parser.rb', line 287

def reset(options={})
  options = {
    :clear => true
  }.merge(options)

  registry.each do |option|
    if option.respond_to?(:reset)
      option.reset
    end
  end

  config.clear if options[:clear]
  self
end

#rm(key) ⇒ Object

Removes options by key. Any options with the specified key are removed. Returns the removed options.


210
211
212
213
214
215
216
217
218
# File 'lib/config_parser.rb', line 210

def rm(key)
  options.values.collect do |option| 
    if option.key == key 
      unregister(option)
    else
      nil
    end
  end.compact
end

#separator(str) ⇒ Object

Adds a separator string to self, used in to_s.


61
62
63
# File 'lib/config_parser.rb', line 61

def separator(str)
  @registry << str
end

#sort_opts!(&block) ⇒ Object

Sorts options in the registry as specified by the block. Groups of options as delimited by separators are sorted independently. If no block is given, options are sorted by their long and short keys.


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/config_parser.rb', line 107

def sort_opts!(&block)
  block ||= lambda {|option| (option.long || option.short).to_s.sub(/^-+/, '') }

  splits = []
  current = []

  options = self.options.values.uniq
  registry.each do |option|
    if options.include?(option)
      current << option
    else
      splits << current
      splits << option
      current = []
    end
  end

  splits << current
  @registry = splits.collect {|split| split.kind_of?(Array) ? split.sort_by(&block) : split }
  @registry.flatten!

  self
end

#to_s(opts = {}) ⇒ Object

Converts the options and separators in self into a help string suitable for display on the command line.


304
305
306
307
308
309
# File 'lib/config_parser.rb', line 304

def to_s(opts={})
  @registry.collect do |option|
    str = option.kind_of?(Flag) ? option.to_s(opts) : option.to_s
    str.rstrip
  end.join("\n") + "\n"
end

#unregister(option) ⇒ Object

Unregisters the option by removing it from the registry and options. Returns option.


98
99
100
101
102
# File 'lib/config_parser.rb', line 98

def unregister(option)
  @registry.delete(option)
  @options.delete_if {|key, value| option == value }
  option
end