Module: InstanceVariableTracer

Defined in:
lib/instance_variable_tracer.rb,
lib/instance_variable_tracer/version.rb

Constant Summary collapse

VERSION =
"0.1.0"

Class Method Summary collapse

Class Method Details

.start(target_instance_variable_name:, target_class_name: nil) ⇒ Object

usage: InstanceVariableTracer.start(target_instance_variable_name: “@books”)



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/instance_variable_tracer.rb', line 5

def self.start(target_instance_variable_name:, target_class_name: nil)
  TracePoint.trace(:line) do |tp|
    # TracePointで止めてASTを確認し、インスタンス変数への代入かどうかを調べる
    # puts "[TP:#{tp.event}] #{tp.path}:#{tp.lineno} #{tp.method_id} #{tp.defined_class}"
    begin
      line = File.open(tp.path, "r"){|f| f.readlines[tp.lineno - 1] } # TODO: ファイルがないクラスでは使えない
    rescue Errno::ENOENT => e
      # p "File.open error"
      # p tp
      # p tp.path
    end
    next unless line

    # AST取得
    begin
      node = RubyVM::AbstractSyntaxTree.parse(line).children.last
    rescue Exception => e # 乱暴
      next
    end

    # インスタンス変数への代入かを調べる
    next unless node.type == :IASGN

    # クラス名を調べる
    if target_class_name
      target_class = Kernel.const_get(target_class_name)
      next unless tp.self.is_a?(target_class)
    end

    # インスタンス変数名を調べる
    instance_variable_name = node.children.first
    next unless instance_variable_name == target_instance_variable_name.to_sym

    puts "#{target_class_name} #{target_instance_variable_name} is assigned in #{tp.path}:#{tp.lineno} #{tp.method_id} #{tp.defined_class}"
  end
end