6
1

More than 5 years have passed since last update.

RipperでRubyのコードを解析したい

Last updated at Posted at 2018-04-19
1 / 12

やりたいこと

  • メソッドのコメントにannotationを書いておき、そのannotationが付いたのはどのクラスのどのメソッドなのか、を知りたい。
  • そしてその結果をOkuribitoに渡して使われていないメソッドを監視したい。

Ripperを試してみる

  • Rubyに付属するRubyパーサ
  • Rubyのコードを読ませると、on_xxxのイベントを受けられる。
  • 上から読んでいってイベントが上がってくる Scanner
  • 解析して結果を教えてくれる Parser

イベントの種別

irb(main):002:0> require 'ripper'
=> true
irb(main):003:0>
irb(main):004:0> Ripper::SCANNER_EVENTS
=> [:CHAR, :__end__, :backref, :backtick, :comma, :comment, :const, :cvar, :embdoc, :embdoc_beg, :embdoc_end, :embexpr_beg, :embexpr_end, :embvar, :float, :gvar, :heredoc_beg, :heredoc_end, :ident, :ignored_nl, :imaginary, :int, :ivar, :kw, :label, :label_end, :lbrace, :lbracket, :lparen, :nl, :op, :period, :qsymbols_beg, :qwords_beg, :rational, :rbrace, :rbracket, :regexp_beg, :regexp_end, :rparen, :semicolon, :sp, :symbeg, :symbols_beg, :tlambda, :tlambeg, :tstring_beg, :tstring_content, :tstring_end, :words_beg, :words_sep]

以下が見やすい。


パースされるテストコード

class Target
  # @okuribito
  def self.class_method
    puts 1
  end

  # @okuribito
  def instance_method
    puts 2
  end

  def self.active_class_method
    puts 3
  end

  def active_instance_method
    puts 4
  end
end

Scan

require 'ripper'
require 'cgi'

class ScanTest < Ripper::Filter
  def on_default(event, tok, f)
    # 有効にすると全部得られます。
    # puts "#{__method__} #{tok} #{event}"
  end

  def on_ident(tok, f)
    puts "#{__method__} #{tok}"
  end

  def on_comment(tok, f)
    puts "#{__method__} #{tok}"
  end
end

puts ScanTest.new(ARGF).parse('')

ruby parser.rb target.rb
on_comment # @okuribito
on_ident class_method
on_ident puts
on_comment # okuribito
on_ident instance_method
on_ident puts
on_ident active_class_method
on_ident puts
on_ident active_instance_method
on_ident puts

コメントは得られたがメソッドやクラスはすべてon_identでくるため判別不可能。


Parser

pp Ripper.sexp_raw(ARGF.read)
[:program,
 [:stmts_add,
  [:stmts_new],
  [:class,
   [:const_ref, [:@const, "Target", [1, 6]]],
   nil,
   [:bodystmt,
    [:stmts_add,
     [:stmts_add,
      [:stmts_add,
       [:stmts_add,
        [:stmts_add, [:stmts_new], [:void_stmt]],
        [:defs,
         [:var_ref, [:@kw, "self", [3, 6]]],
         [:@period, ".", [3, 10]],
         [:@ident, "class_method", [3, 11]],
         [:params, nil, nil, nil, nil, nil, nil, nil],
         [:bodystmt,
          [:stmts_add,
           [:stmts_new],
           [:command,
            [:@ident, "puts", [4, 4]],
            [:args_add_block,
             [:args_add, [:args_new], [:@int, "1", [4, 9]]],
             false]]],
          nil,
          nil,
          nil]]],
       [:def,
        [:@ident, "instance_method", [8, 6]],
        [:params, nil, nil, nil, nil, nil, nil, nil],
        [:bodystmt,
         [:stmts_add,
          [:stmts_new],
          [:command,
           [:@ident, "puts", [9, 4]],
           [:args_add_block,
            [:args_add, [:args_new], [:@int, "2", [9, 9]]],
            false]]],
         nil,
         nil,
         nil]]],
      [:defs,
       [:var_ref, [:@kw, "self", [12, 6]]],
       [:@period, ".", [12, 10]],
       [:@ident, "active_class_method", [12, 11]],
       [:params, nil, nil, nil, nil, nil, nil, nil],
       [:bodystmt,
        [:stmts_add,
         [:stmts_new],
         [:command,
          [:@ident, "puts", [13, 4]],
          [:args_add_block,
           [:args_add, [:args_new], [:@int, "3", [13, 9]]],
           false]]],
        nil,
        nil,
        nil]]],
     [:def,
      [:@ident, "active_instance_method", [16, 6]],
      [:params, nil, nil, nil, nil, nil, nil, nil],
      [:bodystmt,
       [:stmts_add,
        [:stmts_new],
        [:command,
         [:@ident, "puts", [17, 4]],
         [:args_add_block,
          [:args_add, [:args_new], [:@int, "4", [17, 9]]],
          false]]],
       nil,
       nil,
       nil]]],
    nil,
    nil,
    nil]]]]

コメントは得られなかった…。


To be continued...

rdocではできてるので、rdocのコードを追ってみる。

rdocはRipper::Filterでやっている様子。
なるほど、人間が読んでいくのと同じような感じで読んでいくのだな…

6
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
1