def parse(cmdline = ARGV)
vals = {}
required = {}
opt :version, "Print version and exit" if @version && ! (@specs[:version] || @long["version"])
opt :help, "Show this message" unless @specs[:help] || @long["help"]
@specs.each do |sym, opts|
required[sym] = true if opts.required?
vals[sym] = opts.default
vals[sym] = [] if opts.multi && !opts.default
end
resolve_default_short_options!
given_args = {}
@leftovers = each_arg cmdline do |arg, params|
arg, negative_given = if arg =~ /^--no-([^-]\S*)$/
["--#{$1}", true]
else
[arg, false]
end
sym = case arg
when /^-([^-])$/ then @short[$1]
when /^--([^-]\S*)$/ then @long[$1] || @long["no-#{$1}"]
else raise CommandlineError, "invalid argument syntax: '#{arg}'"
end
sym = nil if arg =~ /--no-/
next nil if ignore_invalid_options && !sym
raise CommandlineError, "unknown argument '#{arg}'" unless sym
if given_args.include?(sym) && !@specs[sym].multi?
raise CommandlineError, "option '#{arg}' specified multiple times"
end
given_args[sym] ||= {}
given_args[sym][:arg] = arg
given_args[sym][:negative_given] = negative_given
given_args[sym][:params] ||= []
num_params_taken = 0
unless params.empty?
if @specs[sym].single_arg?
given_args[sym][:params] << params[0, 1]
num_params_taken = 1
elsif @specs[sym].multi_arg?
given_args[sym][:params] << params
num_params_taken = params.size
end
end
num_params_taken
end
raise VersionNeeded if given_args.include? :version
raise HelpNeeded if given_args.include? :help
@constraints.each do |type, syms|
constraint_sym = syms.find { |sym| given_args[sym] }
next unless constraint_sym
case type
when :depends
syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym].long} requires --#{@specs[sym].long}" unless given_args.include? sym }
when :conflicts
syms.each { |sym| raise CommandlineError, "--#{@specs[constraint_sym].long} conflicts with --#{@specs[sym].long}" if given_args.include?(sym) && (sym != constraint_sym) }
end
end
required.each do |sym, val|
raise CommandlineError, "option --#{@specs[sym].long} must be specified" unless given_args.include? sym
end
given_args.each do |sym, given_data|
arg, params, negative_given = given_data.values_at :arg, :params, :negative_given
opts = @specs[sym]
if params.empty? && !opts.flag?
raise CommandlineError, "option '#{arg}' needs a parameter" unless opts.default
params << (opts.array_default? ? opts.default.clone : [opts.default])
end
vals["#{sym}_given".intern] = true
vals[sym] = opts.parse(params, negative_given)
if opts.single_arg?
if opts.multi?
vals[sym] = vals[sym].map { |p| p[0] }
else
vals[sym] = vals[sym][0][0]
end
elsif opts.multi_arg? && !opts.multi?
vals[sym] = vals[sym][0]
end
opts.callback.call(vals[sym]) if opts.callback
end
cmdline.clear
@leftovers.each { |l| cmdline << l }
class << vals
def method_missing(m, *_args)
self[m] || self[m.to_s]
end
end
vals
end