RubyVM::AST を便利に使いたいので gem を作った

github.com

さっと作りました。 rubygems には登録してません(名前が重複してるかすら調べてないや)

経緯

Ruby 2.6.0preview2 から RubyVM::AST モジュールが使えるようになりました。

Ruby 2.6.0-preview2 Released

RubyVM::AST [Experimental] Ruby 2.6 introduces RubyVM::AST module.

This module has parse method which parses a given ruby code of string and returns AST (Abstract Syntax Tree) nodes, and parse_file method which parses a given ruby code file and returns AST nodes.

RubyVM::AST::Node class is also introduced you can get location information and children nodes from Node objects. This feature is experimental. Compatibility of the structure of AST nodes are not guaranteed.

要約:

  • Experimental だよ。互換性とか全然まるっきり全く担保する気がないよ
  • parse, parse_file というメソッドがあって AST を返すよ

こいつは parse すると RubyVM::AST::Node を返します。tree なので子供がいるのですが children と呼ぶと RubyVM::AST::Node | NilClass の配列が返ります。

なんですけど、ちょっとわかりにくいんですよね。children の数は node_type によって固定なんですが覚えられないし、何番目が何かわからないし。ちなみに具体的な対応はこの辺を参照してください

なので雑に node_type 文字列を key にした Hash を返すようにしてみました。わーべんり(べんり?)

RubyVM::AST.parse("1 + 2").children
# => [nil, #<RubyVM::AST::Node(NODE_OPCALL(36) 1:0, 1:5): >]
require 'ast_tools/hash'
RubyVM::AST.parse("1 + 2").children
# => {"node_opcall"=>#<RubyVM::AST::Node(NODE_OPCALL(36) 1:0, 1:5): >}

他にももう少し RubyVM::AST を用いて遊ぶ予定があるのでそのときに使おうと思います


追記

ハイパーそうですねという感じなので使い方を変えました

https://github.com/hkdnet/ast_tools/pull/2

RubyVM::AST.parse("1 + 2").children
# => [nil, #<RubyVM::AST::Node(NODE_OPCALL(36) 1:0, 1:5): >]

AstTools::Hash.convert(RubyVM::AST.parse("1 + 2").children)
# => {"node_opcall"=>#<RubyVM::AST::Node(NODE_OPCALL(36) 1:0, 1:5): >}

# or refinement

module Foo
  using AstTools::Hash
  def self.foo
    RubyVM::AST.parse("1 + 2").children
    # => {"node_opcall"=>#<RubyVM::AST::Node(NODE_OPCALL(36) 1:0, 1:5): >}
  end
end