class OptConfig

Attributes

file[RW]
idlist[RW]
idlist=[RW]
ignore_unknown_file_option[RW]
section[RW]

Public Class Methods

new(default_attr={}) click to toggle source

初期化

default_attr には各オプション属性のデフォルト値を Hash で指定可能。 オプション属性以外にも以下のものを指定できる。これらは OptConfig オブジェクト自身に影響する。

:file

オプションファイル名 (String)。デフォルト: なし。

:section

オプションファイル名のセクション名 (String または String の配列)。デフォルト: なし。

:ignore_unknown_file_option

オプションファイル内に未知のオプションがあっtた時に無視するか(true)エラーにするか(false)。デフォルト: true。

:stop_at_non_option_argument

オプションでない引数でオプションの解釈をやめるか(true)、それ以降もオプションの解釈を続けるか(false)。デフォルト: false。

# File lib/optconfig.rb, line 141
def initialize(default_attr={})
  @default_attr = default_attr
  @option_seq = []
  @options = {}
  @file = default_attr[:file]
  @section = default_attr[:section] && [default_attr[:section]].flatten
  @stop_at_non_option_argument = default_attr[:stop_at_non_option_argument]
  @ignore_unknown_file_option = default_attr.key?(:ignore_unknown_file_option) ? default_attr[:ignore_unknown_file_option] : true
  @obsolete_behavior = false
  @specified = {}               # オプションが指定されたかどうかを保持
end

Public Instance Methods

[](name) click to toggle source

オプションの値を返す

name

オプション名

例外

UnknownOption

# File lib/optconfig.rb, line 291
def [](name)
  raise UnknownOption, "unknown option: #{name}" unless @options.key? name
  @options[name].value
end
option(*args) click to toggle source

オプション定義

args

オプション名(String) のリスト、オプションの属性(Hash)

戻り値

Option オブジェクト

例外

RuntimeError

オプションが既に定義されている

# File lib/optconfig.rb, line 163
def option(*args)
  args = args.dup
  if args.last.is_a? Hash
    attr = args.pop
    attr = @default_attr.merge attr
  else
    attr = @default_attr
  end
  args.push attr
  opt = Option.new *args
  opt.name.each do |n|
    raise "option #{n} is already defined" if @options.key? n
    @options[n] = opt
  end
  @option_seq << opt
end
options=(option) click to toggle source

オプション定義(古いインタフェース)

option

オプション定義(ハッシュ)

# File lib/optconfig.rb, line 182
def options=(option)
  @options.clear
  @option_seq.clear
  option.each do |k,v|
    v = [v] unless v.is_a? Array
    arg = k.is_a?(Array) ? k : [k]
    arg.push({:format=>v[0], :default=>v[1]})
    opt = Option.new *arg
    opt.name.each do |n|
      raise "option #{n} is already defined" if @options.key? n
      @options[n] = opt
    end
    @option_seq << opt
  end
  @obsolete_behavior = true
  option
end
parse(argv=[]) click to toggle source

argv のオプションを解析する

argv

文字列の配列

戻り値

argv からオプションを取り除いたもの

# File lib/optconfig.rb, line 251
def parse(argv=[])
  parse!(argv.dup)
end
parse!(argv=[]) click to toggle source

argv のオプションを解析し、オプションを取り除いたものに置き換える

argv

配列

戻り値

argv

残りの引数

# File lib/optconfig.rb, line 204
def parse!(argv=[])
  orig_argv_size = argv.size
  ret = []
  @specified.clear
  @option_seq.each do |opt|
    opt.value = opt.ovalue = opt.default
    begin
      opt.value = check_option opt.name.first, opt.default if opt.default.is_a? String
    rescue OptConfig::Error
      # 無視
    end
  end
  parse_file @file if @file
  @specified.clear

  until argv.empty?
    arg = argv.shift
    case arg
    when "--"
      ret.concat argv
      break
    when /\A--[a-zA-Z0-9_]/
      parse_long_opt arg.sub(/\A--/, ""), argv
    when /\A-[a-zA-Z0-9]/
      parse_short_opt arg.sub(/\A-/, ""), argv
    else
      ret.push arg
      if @stop_at_non_option_argument
        ret.concat argv
        break
      end
    end
  end

  if @obsolete_behavior
    n = orig_argv_size - ret.size
    argv.replace ret
    return n
  end
  argv.replace ret
  return argv
end
parse_file(filename) click to toggle source

ファイルからオプションを読み込む

filename

ファイル名

例外

UnknownOption

# File lib/optconfig.rb, line 259
def parse_file(filename)
  cur_sect = nil
  File.open filename do |f|
    f.each_line do |line|
      line.chomp!
      next if line =~ /\A#|\A\s*\z/
      if line =~ /\A\[(.*)\]\z/
        cur_sect = $1
        next
      end
      if @section.nil? or @section.empty? or @section.include? cur_sect
        name, value = line.split(/\s*=\s*|\s+/, 2)
        begin
          name, = long_option name, false
          raise UnknownOption, "unknown option: #{name}" unless @options[name].in_config
          if value
            parse_long_opt "#{name}=#{value}", [], false
          else
            parse_long_opt name, [], false
          end
        rescue UnknownOption
          raise unless @ignore_unknown_file_option
        end
      end
    end
  end
end
usage() click to toggle source

オプションの説明文字列を返す

# File lib/optconfig.rb, line 297
def usage
  ret = ""
  @option_seq.each do |opt|
    next unless opt.description
    short = []
    long = []
    opt.usage_name.each do |n|
      if n.size == 1
        short << "-#{n}"
      else
        long << "--#{n}"
      end
    end
    line = "  "+(short+long).join(", ")
    if opt.description.empty?
      ret << line+"\n"
      next
    end
    if line.length >= 25
      line << "\n                          "
    else
      line << " "*(26-line.length)
    end
    desc = opt.description.gsub(/%s/, opt.ovalue.to_s).split "\n"
    line << desc.shift+"\n"
    desc.each do |d|
      line << "                          #{d}\n"
    end
    ret << line
  end
  ret
end

Private Instance Methods

check_option(name, value) click to toggle source

オプション名と値の正当性を確認

name

オプション名

value

値 (String)

戻り値

value の評価結果

例外

UnnecessaryArgument, ArgumentRequired, InvalidArgument

# File lib/optconfig.rb, line 366
def check_option(name, value)
  a = @options[name].argument
  f = @options[name].format
  raise UnnecessaryArgument, "option argument is unnecessary: #{name}" if a == false or (a.nil? and !f)
  return true if a == :optional and value.nil?
  raise ArgumentRequired, "argument required: #{name}" if value.nil?
  return value if f == true
  if f == :boolean
    return true if ["1","true","enable","yes","y","on"].include? value.downcase
    return false if ["0","false","disable","no","n","off"].include? value.downcase
    raise InvalidArgument, "invalid boolean value: #{name}"
  end
  begin
    return StringValidator.validate(f, value)
  rescue StringValidator::Error => e
    raise InvalidArgument, "invalid argument for option `#{name}': #{e.message}: #{value}"
  end
end
long_option(name, completion) click to toggle source

長いオプション名の確認

name

オプション名

completion

補完の有無

戻り値

String

補完後オプション名

true/false

“no-” prefix 指定?

例外

UnknownOption

# File lib/optconfig.rb, line 447
def long_option(name, completion)
  n = completion ? long_option_completion(name) : name.size > 1 && @options.key?(name) ? name : nil
  return n, false if n
  if name =~ /\Ano-([a-zA-Z0-9][a-zA-Z0-9_-]+)\z/
    n = completion ? long_option_completion($1) : name.size > 1 && @options.key?(name) ? name : nil
    return n, true if n and (@options[n].may_not_take_argument? or @options[n].format == :boolean)
  end
  name2 = name.gsub(/_/, "-")
  n = completion ? long_option_completion(name2) : name.size > 1 && @options.key?(name2) ? name2 : nil
  return n, false if n and @options[n].underscore_is_hyphen
  if name2 =~ /\Ano-([a-zA-Z0-9][a-zA-Z0-9_-]+)\z/
    n = completion ? long_option_completion($1) : name.size > 1 && @options.key?(name2) ? name2 : nil
    return n, true if n and @options[n].underscore_is_hyphen and (@options[n].may_not_take_argument? or @options[n].format == :boolean)
  end
  raise UnknownOption, "unknown option: #{name}"
end
long_option_completion(opt) click to toggle source

長いオプション名の補完

opt

オプション名

戻り値

オプション名 / nil(未知のオプション)

例外

AmbiguousOption

# File lib/optconfig.rb, line 470
def long_option_completion(opt)
  return opt if @options.key? opt
  candidate = @options.keys.sort.select{|k| opt == k[0, opt.size]}.select{|k| @options[k].completion}
  raise AmbiguousOption, "ambiguous option: #{opt} (candidate are #{candidate.join(", ")})" if candidate.size > 1
  return nil if candidate.empty? or not @options[candidate.first].completion
  return candidate.first
end
parse_long_opt(name, argv, completion=true) click to toggle source

長い名前のオプションの解釈

name

オプション名

argv

それ以降の文字列配列

completion

補完の有無

戻り値

Option オブジェクト

# File lib/optconfig.rb, line 391
def parse_long_opt(name, argv, completion=true)
  if name.include? "="
    n, v = name.split "=", 2
    n, invert = long_option n, completion
    set_option n, v
    @options[n].value = !@options[n].value if invert
    return @options[n]
  end
  n, invert = long_option name, completion
  opt = @options[n]
  if opt.argument == false or opt.argument == :optional or
      (opt.argument.nil? and !opt.format)
    set_option n, !invert
    return @options[n]
  end
  set_option n, argv.shift
  @options[n].value = !@options[n].value if invert
  return @options[n]
end
parse_short_opt(name, argv) click to toggle source

短い名前のオプションの解釈

name

オプション名

argv

それ以降の文字列配列

戻り値

Option オブジェクト

# File lib/optconfig.rb, line 416
def parse_short_opt(name, argv)
  arg = name.dup
  until arg.empty?
    n = arg.slice!(0, 1)
    raise UnknownOption, "unknown option: #{n}" unless @options.key? n
    opt = @options[n]
    if opt.argument == false or (opt.argument.nil? and !opt.format)
      set_option n, true
      next
    end
    unless arg.empty?
      set_option n, arg
      return @options[n]
    end
    if opt.argument == :optional
      set_option n, true
      return @options[n]
    end
    set_option n, argv.shift
    return @options[n]
  end
end
set_option(name, value) click to toggle source

オプションに値を設定

name

オプション名

value

値(String,true,false)

例外

UnknownOption, DuplicatedOption

# File lib/optconfig.rb, line 337
def set_option(name, value)
  raise UnknownOption, "unknown option: #{name}" unless @options.key? name
  opt = @options[name]
  ovalue = value
  value = opt.pre_proc.call name, opt, value if opt.pre_proc
  raise DuplicatedOption, "duplicated option: #{name}" if !opt.multiple and @specified[@options[name]]
  value = check_option name, value unless value == true or value == false
  value = opt.proc.call name, opt, value if opt.proc
  if opt.multiple == :last or !opt.multiple
    opt.value = value
    opt.ovalue = ovalue
  else
    unless @specified[@options[name]]
      opt.value = []
      opt.ovalue = []
    end
    opt.value << value
    opt.ovalue << ovalue
  end
  @specified[@options[name]] = true
end