やりたいこと
- メソッドのコメントに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
でやっている様子。
なるほど、人間が読んでいくのと同じような感じで読んでいくのだな…