optparseを使わずにオプション引数をパースしてみる

optparseは使いやすいです。引数は"-X"のショートタイプと"--xxxx"のロングタイプが使用できますし、すっきりとした記述で書けます。

ふと、"-test "のようなオプションはパースできないかと考えました。既に"-X"と"--xxxx"が処理できるのに"-xxxx"を処理する意味なんて。。いや、どうしてもハイフン1つでロングタイプを使いたいのです。

そこで自分向きの引数パーサを作ってみることにしました。
実はoptparseでもできるのかもしれませんが、お勉強ということで。
ウェブサイト上でいろいろ参考に。

引数の形は自分の好きなようにして、使い方はoptparseをベースに考えてみます。

class MiniOptparse
  def initialize(&block)
    @opt_list = []
    @banner = ""
    instance_eval(&block) if block_given?
  end
  attr_accessor :banner

  def scan_for_value(val, desc="", regex=nil, &block)
    val_sp = val.split(' ')
    bool = val_sp.size > 1 
    @opt_list << {
      val: val_sp[0],
      val_full: val,
      bool: bool,
      regex: regex,
      desc: desc,
      block: block
    }
  end 
  alias_method :on, :scan_for_value

  def parse(args)
    until args.size == 0
      found = nil 
      key = args.shift
      @opt_list.each do |opt|
        if (key.to_s == opt[:val].to_s)
          if opt[:bool]
            raise "Not Found argument" unless args.size > 0
            value = args.shift
            opt[:block].call(value.to_s)
          else
            opt[:block].call
          end
          found = true
          break
        end
      end
      unless found
        raise "Not Found args : #{key}."
      end
    end
  end

  def usage
    str = "\n"
    str << @banner << "\n"
    str << "\nUsage : <options>\n"
    @opt_list.each do |opt|
      str << sprintf("     %-32s %s\n", opt[:val_full], opt[:desc])
    end
    str << "\n"
    str
  end

end

if __FILE__ == $0
  opts = {}
  MiniOptparse.new do |o|
    o.banner = " % #{__FILE__} <options>"
    o.on('-test <value>', "This is test option.") {|v| opts[:test] = v}
    o.on("-help"        , "show this message."  ) { usage }
  end.parse(ARGV)

  #puts po.usage
  p opts
end

% ruby mini_optparse.rb -test sample
{:test=>"sample"}

いい感じにできました。
また、正規表現を実装できていませんが、それっぽくなったので良しとします。

とりあえず、ここまで。