ripperの基本的な使い方はRubyの標準添付ライブラリripperでRubyのソースをパースするで紹介した。 きょうはRubyのバージョンとripperの関係について少し書いておく。
実はripperはRubyのバージョンアップに伴って、きちんと新バージョンで追加された文法にも対応しているようなのだ。
例えばRuby 1.9のripperで、Ruby 2.0で導入されたキーワード引数を使ったソースのS式を取得してみると、うまくパースすることができない。
require 'ripper'
require 'pp'
src = <<SRC
def foo(a:1, b:2, c:3)
end
SRC
pp Ripper.sexp(src)
Ruby 1.9のripperによるパース結果
[:program, [:@int, "1", [1, 10]]]
これと全く同じコードをRuby 2.0のripperで動かしてみると、先ほどはパースできていなかったキーワード引数が、きちんとパースできていることが確認できる。
Ruby 2.0のripperによるパース結果
[:program,
[[:def,
[:@ident, "foo", [1, 4]],
[:paren,
[:params,
nil,
nil,
nil,
nil,
[[[:@label, "a:", [1, 8]], [:@int, "1", [1, 10]]],
[[:@label, "b:", [1, 13]], [:@int, "2", [1, 15]]],
[[:@label, "c:", [1, 18]], [:@int, "3", [1, 20]]]],
nil,
nil]],
[:bodystmt, [[:void_stmt]], nil, nil, nil]]]]
同様に、Ruby 2.1で導入された3.14r
のような有理数の数値リテラルは、Ruby 2.0のripperではfloatの値とパースされてしまうが、Ruby 2.1のripperでは有理数としてパースできるようになっている。
require 'ripper'
require 'pp'
src = <<SRC
pi = 3.14r
SRC
pp Ripper.sexp(src)
Ruby 2.0のripperによるパース結果
[:program,
[[:assign, [:var_field, [:@ident, "pi", [1, 0]]], [:@float, "3.14", [1, 5]]]]]
Ruby 2.1のripperによるパース結果
[:program,
[[:assign,
[:var_field, [:@ident, "pi", [1, 0]]],
[:@rational, "3.14r", [1, 5]]]]]
ripperすごい!(何度目だっ) Ruby 2.0のripperはRuby 2.0のコードを、Ruby 2.1のripperはRuby 2.1のコードを、きちんとパースすることができている。ますますripperが好きになってきたぞ。