OptionParser for Ruby

# 要約

コマンドラインオプション解析用ライブラリ。

サポートしている機能:

1. 短い形式と長い形式のオプションスイッチを混在可能。 短形式のスイッチは一つにまとめることも可能。
2. スイッチの指定とハンドラをそれぞれ一箇所にまとめて書ける。
3. スイッチの引数は自動的に指定したクラスに変換される。
4. オプションサマリを作れる。
5. 後から、あるいは途中でオプションを追加できる。

# 概要

## クラス構成

- OptionParser フロントエンド
- OptionParser::Switch それぞれのスイッチ
- OptionParser::List オプションリスト

- OptionParser::ParseError オプション解析時のエラー

  - OptionParser::AmbiguousOption
  - OptionParser::NeedlessArgument
  - OptionParser::MissingArgument
  - OptionParser::InvalidOption

  - OptionParser::InvalidArgument

    - OptionParser::AmbiguousArgument

## オブジェクト関連図

    +--------------+
    | OptionParser |<>-----+
    +--------------+       |          	       +--------+
                           |          	     ,-| Switch |
         on_head -------->+-------------+    /  +--------+
         accept/reject -->| List        |<|>-
                          |             |<|>-  +----------+
         on ------------->+-------------+    `-| argument |
                          :             :      |  class   |
                          +-------------+      |==========|
         on_tail -------->|             |      |pattern   |
                          +-------------+      |----------|
    OptionParser.accept ->| DefaultList |      |converter |
                 reject   |(全インスタン|      +----------+
                          | スで共有)   |
                          +-------------+

# クラス & モジュール

## OptionParser::Switch

各スイッチのクラス。

### インスタンスメソッド

`OptionParser::Switch#parse(arg, val) {semi-error handler}`

  引数をパース、変換してarg、block、変換結果を返す。

  @convへの引数:

    @patternにマッチした部分文字列のリスト、 $&, $1, $2 など。

  Parameters:
    arg

      スイッチに直に指定されていた引数の文字列。

    val

      スイッチ以降の引数。

    `block`

      エラーかも知れないときに例外を`yield`する。

`OptionParser::Switch#summarize(sdone, ldone, width, max, indent)`

  オプションサマリを作る。

  Parameters:
    sdone

      すでにサマリに入っている短形式オプションをキーとするハッシュ。

    ldone

      すでにサマリに入っている長形式オプションをキーとするハッシュ。

    width

      左側のオプションリスト部分の幅。 オプションの説明はその右側、width桁目から始まる。

    max

      左側の最大幅。 オプションはmax桁以内に詰められる。

    indent

      各行をインデントするための文字列。

    `block`

      各行ごとに渡される(改行は付かない)。

`OptionParser::Switch#-@`

  反転したブーリアンスイッチ(@blockに渡される引数が反転される)を作る

## OptionParser::List

単一のオプションリスト、短／長形式のオプション文字列からスイッチへのマッピング、受け付けられる引数タイプからパターンとコンバータへのマッピングを提供する。 サマリもここで提供される。

### クラスメソッド

### インスタンスメソッド

`OptionParser::List#atype`

  引数タイプからパターン／コンバータのペアへのマップ。

`OptionParser::List#short`

  短形式のオプションスイッチからスイッチオブジェクトへのマップ。

`OptionParser::List#long`

  長形式のオプションスイッチからスイッチオブジェクトへのマップ。

`OptionParser::List#list`

  全スイッチとサマリ文字列のリスト。

`OptionParser::List#prepend(switch, short_opts, long_opts, nolong_opts)`

  switchをリストの頭に挿入して、短／長／否定形式のオプションに対応させる。

`OptionParser::List#append(switch, short_opts, long_opts, nolong_opts)`

  switchをリストの最後に追加して、短／長／否定形式のオプションに対応させる。

  Parameters:
    switch

      挿入するOptionParser::Switchインスタンス。

    short_opts

      switchに対応する短形式オプションのリスト。

    long_opts

      switchに対応する長形式オプションのリスト。

    nolong_opts

      `"no-"`のつく否定形式のオプションのリスト。

`OptionParser::List#search(id, key) [{block}]`

  keyをidのリストから検索する。

  Parameters:
    id

      検索するリスト。

    k

      検索するキー。

    `Block`

      見付かったときにその値で呼び出される。

`OptionParser::List#complete(id, opt, *pat, &block)`

  optをidのリストから*patで補完して検索する。

  Parameters:
    id

      検索するリスト。

    opt

      検索するキー。

    *pat

      補完に使うパターン。

    `Block`

      見付かったときにその値で呼び出される。

`OptionParser::List#summarize(*args) {...}`

  サマリテーブルを作る。 一行ごとに`block`を呼び出す。 `@list`の要素は`summarize`できる必要がある。

  Parameters:
    args

      そのまま各要素の summarize に渡される。

    `block`

      各行ごとに渡される(改行は付かない)。

## OptionParser

オプションパーサのフロントエンド。

### 定数

`OptionParser::ArgumentStyle`

  取りうる引数のスタイルの種類。 値はそれぞれ:

  `OptionParser::NO_ARGUMENT`

    引数を取らないスイッチ。

  `OptionParser::REQUIRED_ARGUMENT`

    引数が必須のスイッチ。 直後に引数が`=`で指定されていなければ、次の文字列を引数とみなす。 空の引数を指定するときは、`=`だけをつける。

  `OptionParser::OPTIONAL_ARGUMENT`

    オプショナルな引数を取るスイッチ。 つまり引数を付けても付けなくてもよい。

  引数を指定するときは`--switch=argument`(長形式)か、 `-Xargument`(短形式)とする。 短形式では、引数パターンにマッチする部分だけが引数として認識される。

`OptionParser::DefaultList`

  '--'のように全OptionParserインスタンスで共有するスイッチや、デフォルトの引数クラスを持つ。

### クラスメソッド

`OptionParser.with([banner[, width[, indent]]]) [{...}]`

  新しいインスタンスを作成して、イテレータとして呼ばれているときにはブロックをそのインスタンスのコンテクストで評価してから、返す。 この動作は以前の`new`と同じだが、depricatedなメソッド。

  cf. OptionParser#initialize

  Parameters:
    banner

      バナーメッセージ。

    width

      サマリの幅。

    indent

      サマリのインデント文字列。

    `Block`

      作成したインスタンスのコンテクストで評価される。

`OptionParser.new([banner[, width[, indent]]]) [{...}]`

  インスタンスを初期化する。 イテレータとして呼ばれている場合は、自分自身を渡す。

  Parameters:
    banner

      バナーメッセージ。 デフォルトは`nil`。

    width

      サマリの幅。 デフォルトは32

    indent

      サマリのインデント。 デフォルトは空白4個。

    `Block`

      selfが渡される。

`OptionParser.terminate([arg])`

  オプションの解析を終了させる。 省略可能なargが与えられていると、コマンドライン引数に戻される。

  Parameters:
    arg

      最初のオプションでない引数として戻される文字列。

`OptionParser.accept(t, [pat]) {...}`
`OptionParser#accept(t, [pat]) {...}`

  指定したクラスのオプション引数を受け付けられるようにする。

  Parameters:
    t

      引数クラスを指定するオブジェクト、通常は`Class`。

    pat

      引数のパターン。 tが`match`を持っていればそれがデフォルト。

    `Block`

      引数の文字列を受け取って要求されるクラスに変換する。

`OptionParser.reject(t)`
`OptionParser#reject(t)`

  指定したクラスのオプション引数を受け付けないようにする。

  Parameters:
    t

      引数クラスを指定するオブジェクト。

### インスタンスメソッド

`OptionParser#banner`
`OptionParser#banner=(heading)`

  サマリの先頭に出力されるバナー。

`OptionParser#summary_width`
`OptionParser#summary_width=(width)`

  サマリのオプションリスト部分の幅。 `Numeric`である要がある。

`OptionParser#summary_indent`
`OptionParser#summary_indent=(indent)`

  サマリのインデント。 `String`でなければならない(もしくは `String`を`+`できるモノ)。

`OptionParser#program_name`
`OptionParser#program_name=(name)`

  エラーメッセージやデフォルトのバナーで出力されるプログラム名。 デフォルトは`$0`。

`OptionParser#top`

  on/on_head、accept/rejectの対象。

`OptionParser#base`

  on_tailの対象。

`OptionParser#new`

  新しい`List`を追加する。

`OptionParser#remove`

  最後の`List`を削除する。

`OptionParser#summarize(to = [], width = @summary_width, max = width - 1, indent = @summary_indent)`

  オプションサマリをtoに作る。 toを返す。

  Parameters:
    to

      出力先。 <<メソッドが必要。 デフォルトは`[]`。

    width

      左側、オプションリスト部の幅。 デフォルトは@summary_width。

    max

      左側で使える最大幅。 デフォルトは`width - 1`。

    indent

      インデント。 デフォルトは@summary_indent。

    `Block`

      イテレータとして呼ばれていると、各行ごとに呼び出される。

`OptionParser#to_str`
`OptionParser#to_s`

  オプションサマリ文字列を返す。

`OptionParser#to_a`

  オプションサマリを配列として返す。

`OptionParser#switch`

  OptionParser::Switchを作る。

  Parameters:
    opts

      オプション定義。

      引数スタイル

        OptionParser::ArgumentStyle参照。

      引数パターン

        受け付けられるオプション引数の形式。 OptionParser.acceptや OptionParser#acceptであらかじめ定義されているか、 `Regexp`などの`match`メソッドを持つオブジェクトでなければならない。 これは一度だけ指定できる(もしなければ`Object`とみなされる)が、さもなければ`ArgumentError`を起こす。

        cf. 引数として受け付けられるクラス.

      Hash
      Array

        取り得る引数の値。

      Proc
      Method

        handlerを与える別の手段。

      "--switch=MANDATORY", "--switch[=OPTIONAL]", "--switch"

        それぞれ引数が必須、省略可能、無しの長形式スイッチ。

      "-xMANDATORY", "-x[OPTIONAL]", "-x"

        それぞれ引数が必須、省略可能、無しの短形式スイッチ。

      "-[a-z]MANDATORY", "-[a-z][OPTIONAL]", "-[a-z]"

        キャラクタクラスにマッチする短形式のスイッチ (正規表現全てが使えるわけではない)。

      "=MANDATORY", "=[OPTIONAL]"

        引数スタイル。

      "description", ...

        このスイッチの説明。

    `Block`

      このスイッチが指定されたときに呼び出されるhandler。

`OptionParser#on(*opts) [{...}]`
`OptionParser#def_option(*opts) [{...}]`
`OptionParser#on_head(*opts) [{...}]`
`OptionParser#def_head_option(*opts) [{...}]`
`OptionParser#on_tail(*opts) [{...}]`
`OptionParser#def_tail_option(*opts) [{...}]`

  オプションスイッチとハンドラを定義する。 `on_head`、`def_head_option`と `on_tail`、`def_tail_option`はそれぞれスイッチをサマリの最初と最後におく。

  cf. OptionParser#switch.

`OptionParser#order(*argv) [{...}]`
`OptionParser#order!([argv = ARGV]) [{...}]`

  argvを出て来る順番にしたがって解析する。 オプションでない引数があると、イテレータとして呼ばれていればそれを渡して呼び出す。 さもなければ解析を終了する。 解析されずに残ったargvを返す。

  `order!`は配列自身を受け取って、スイッチを破壊的に取り除く。 デフォルトではARGVを解析する。

  Parameters:
    argv

      解析するコマンドライン引数の配列。

    `Block`

      オプションでない引数があると呼び出される。

`OptionParser#permute(*argv)`
`OptionParser#permute!([argv = ARGV])`

  argvを並び変えモードで解析して、オプションでない引数のリストを返す。

  `permute!`は配列自身を受け取って、スイッチを破壊的に取り除く。 デフォルトではARGVを解析する。

  Parameters:
    argv

      解析するコマンドライン引数の配列。

`OptionParser#parse(*argv)`
`OptionParser#parse!([argv = ARGV])`

  環境変数`POSIXLY_CORRECT`がセットされているときは順序通りに、それ以外は並べ変えモードで、argvを解析する。

  `parse!`は配列自身を受け取って、スイッチを破壊的に取り除く。 デフォルトではARGVを解析する。

  Parameters:
    argv

      解析するコマンドライン引数の配列。

# 引数として受け付けられるクラス

Object

  任意の文字列、変換されない。 何も指定しないとこれになる。

String

  任意の空でない文字列、変換されない。

Integer

  Ruby/C的な整数、`0`で始まれば8進数、`0b`で始まれば2進数、 `0x`で始まれば16進数、それ以外は10進数とみなす。 符号も付けられる。 `Integer`に変換される。

Float

  実数形式、`Float`に変換される。

Numeric

  汎用の数値、整数形式なら`Integer`、実数形式なら `Float`に変換される。

OptionParser::DecimalInteger

  10進整数、`Integer`に変換される。

OptionParser::OctalInteger

  Ruby/C的な 8/16/2進整数、`Integer`に変換される。

OptionParser::DecimalNumeric

  10進整数／実数形式。 整数形式なら`Integer`、実数形式なら `Float`に変換される。

TrueClass

  ブーリアンスイッチ、存在すれば真、または`no-`が前に付いていれば偽。 もしくは`yes/no/true/false`で示される値。

FalseClass

  TrueClassと似ているが、デフォルトの値は`false`。

Array

  ","区切り文字列。

# 例外

## OptionParser::ParseError

OptionParserで発生する例外のベースクラス。

### スーパークラス

`RuntimeError`

### 定数

OptionParser::ParseError::Reason

  エラー原因。

### インスタンスメソッド

`OptionParser::ParseError#reason`

  エラーの理由を返す。

`OptionParser::ParseError#inspect`

  可読形式の文字列を返す。

`OptionParser::ParseError#message`
`OptionParser::ParseError#to_s`
`OptionParser::ParseError#to_str`

  デフォルトの文字列化メソッド、標準的なエラーメッセージ用。

## OptionParser::AmbiguousOption

補完が一意に決められないときに発生する。

### スーパークラス

OptionParser::ParseError

## OptionParser::NeedlessArgument

引数を取らないスイッチに引数が指定されていたときに発生する。

### スーパークラス

OptionParser::ParseError

## OptionParser::MissingArgument

引数が必要なスイッチに引数が無かったときに発生する。

### スーパークラス

OptionParser::ParseError

## OptionParser::InvalidOption

定義されていないスイッチで発生する。

### スーパークラス

OptionParser::ParseError

## OptionParser::InvalidArgument

与えられた引数がフォーマットに合わなかったときに発生する。

### スーパークラス

OptionParser::ParseError

## OptionParser::AmbiguousArgument

与えられた引数が一意に決定できなかったときに発生する。

### スーパークラス

OptionParser::InvalidArgument

# その他

## OptionParser::Arguable

コマンドライン引数の配列に、自分自身をパースする機能を拡張する。 `optparse.rb`を`require`すると、ARGVが拡張されている。

`OptionParser::Arguable#options=`

  OptionParserオブジェクトをセットする。 optが`false`か`nil`なら、 OptionParser::Arguable#optionsメソッドと OptionParser::Arguable#options=メソッドが未定義にされる。 つまり、このレシーバ経由でOptionParserオブジェクトにアクセスする方法は無くなる。

`OptionParser::Arguable#options [{...}]`

  実際のOptionParserオブジェクト。 設定されていなければ自動的に作られる。

  イテレータとして呼ばれると、OptionParserオブジェクトと共に呼び出して、その結果を戻り値とする。 このとき、OptionParser::ParseError例外は補足され、エラーメッセージをSTDERRに表示するだけで`nil`を返す。

  Parameters:
    `block`

      設定されているOptionParserのインスタンスとともに呼ばれる。

`OptionParser::Arguable#order!`
`OptionParser::Arguable#permute!`
`OptionParser::Arguable#parse!`

  selfを破壊的にパースして、selfを返す。 パースされなかった文字列だけを残す。

## OptionParser::Acceptables

OptionParserで定義されている、引数として受け付けられるパターンの定数を含んでいる。 今のところ`DecimalInteger`、`OctalInteger`、`DecimalNumeric`。 引数として受け付けられるクラス参照。

# Example

    require 'optparse'

    $0 = File.basename($0)

    # keywords
    CODES = %w[iso-2022-jp shift_jis euc-jp utf8 binary]
    CODE_ALIASES = {"jis" => "iso-2022-jp", "sjis" => "shift_jis"}
    POSSIBLE_CODES = "(#{(CODES+CODE_ALIASES.keys).join(',')})"

    vars = {}
    ARGV.options do
      |opts|
      opts.banner = "Usage: #{$0} [options] argv...\n"

      # separater
      opts.on_tail
      opts.on_tail("common options:")

      # no argument, shows at tail
      opts.on_tail("--help", "show this message") {puts opts; exit}

      # mandatory argument
      opts.on("-r", "--require=LIBRARY", String,
    	  "require the LIBRARY, before",
    	  "executing your script") {|vars[:library]|}

      # optional argument
      opts.on("-i", "--inplace=[EXTENSION]",
    	  "edit ARGV files in place", # multiline description
    	  "(make backup if EXTENSION supplied)") {|vars[:inplace]| vars[:inplace] ||= ''}

      opts.on("-N=[NUM]", Integer) {|vars[:number]|}

      # additional class
      # opts.on("-t", "--time=TIME", Time, "it's the time") {|vars[:time]|}

      # limit argument syntax
      opts.on("-[0-7]", "-F", "--irs=[OCTAL]", OptionParser::OctalInteger,
    	  "specify record separator", "(\\0, if no argument)") {|vars[:irs]|}

      # boolean switch(default true)
      vars[:exec] = true
      opts.on("-n", "--no-exec", "not really execute") {|vars[:exec]|}

      # array
      opts.on("-a", "--list[=LIST,LIST]", Array, "list") {|vars[:list]|}

      # fixed size array
      opts.on("--pair[=car,cdr]", Array, "pair") {|vars[:x], vars[:y]|}

      # keyword completion
      opts.on("--code=CODE", CODES, CODE_ALIASES, "select coding system", POSSIBLE_CODES) {|vars[:code]|}

      # optional argument with keyword completion
      opts.on("--type[=TYPE]", [:text, :binary], "select type(text, binary)") {|vars[:type]|}

      # boolean switch with optional argument(default false)
      opts.on("-v", "--[no-]verbose=[FLAG]", "run verbosely") {|vars[:verbose]|}

      # easy way, set local variable
      opts.on("-q", "--quit", "quit when ARGV is empty") {|vars[:quit]|}

      # adding on the fly
      opts.on("--add=SWITCH=[ARG]", "add option on the fly", /\A(\w+)(?:=.+)?\Z/) do
        |opt, var|
        opts.on("--#{opt}", "added in runtime", &eval("proc {|vars[:#{var}]|}"))
      end

      opts.on_head("specific optins:")

      # no argument
      opts.on_tail("--version", "show version") do
        puts OptionParser::Version.join('.')
        exit
      end
      opts.parse!
    end

    if (Fixnum === :-)
      class << vars
        def inspect
          "{" + collect {|k,v| ":#{k.id2name}=>#{v.inspect}"}.join(", ") + "}"
        end
      end
    end
    p vars
    (puts ARGV.options; exit) if vars[:quit]
    ARGV.options = nil		# no more parse
    puts "ARGV = #{ARGV.join(' ')}" if !ARGV.empty?
    #opts.variable.each {|sym| puts "#{sym} = #{opts.send(sym).inspect}"}