class PryMoves::Tracer
Public Class Methods
new(command, pry_start_options)
click to toggle source
# File lib/pry-moves/tracer.rb, line 11 def initialize(command, pry_start_options) @command = command @pry_start_options = pry_start_options end
Public Instance Methods
stop_tracing()
click to toggle source
# File lib/pry-moves/tracer.rb, line 54 def stop_tracing trace_obj.set_trace_func nil Pry.config.disable_breakpoints = false end
trace()
click to toggle source
# File lib/pry-moves/tracer.rb, line 16 def trace @action = @command[:action] #puts "COMMAND: #{@action}" binding_ = @command[:binding] set_traced_method binding_ @recursion_level -= 1 if @pry_start_options.delete :exit_from_method case @action when :step @step_into_funcs = nil func = @command[:param] if func == '+' @step_in_everywhere = true elsif func @step_into_funcs = [func] @step_into_funcs << '=initialize' if func == 'new' or func == '=new' @caller_digest = frame_digest(binding_) end when :finish @method_to_finish = @method @block_to_finish = (binding_.frame_type == :block) && frame_digest(binding_) when :next if @command[:param] == 'blockless' @stay_at_frame = frame_digest(binding_) end when :iterate @iteration_start_line = binding_.eval('__LINE__') @caller_digest = frame_digest(binding_) when :goto @goto_line = @command[:param].to_i end start_tracing end
Private Instance Methods
debug_info(file, line, id)
click to toggle source
# File lib/pry-moves/tracer.rb, line 124 def debug_info(file, line, id) puts "📽 Action:#{@action}; recur:#{@recursion_level}; #{@method[:file]}:#{file}" puts "#{id} #{@method[:start]} > #{line} > #{@method[:end]}" end
exit_from_method()
click to toggle source
# File lib/pry-moves/tracer.rb, line 134 def exit_from_method @pry_start_options[:exit_from_method] = true true end
frame_digest(binding_)
click to toggle source
# File lib/pry-moves/tracer.rb, line 77 def frame_digest(binding_) #puts "frame_digest for: #{binding_.eval '__callee__'}" Digest::MD5.hexdigest binding_.instance_variable_get('@iseq').disasm end
method_matches?(method)
click to toggle source
# File lib/pry-moves/tracer.rb, line 106 def method_matches?(method) @step_into_funcs.any? do |pattern| if pattern.start_with? '=' "=#{method}" == pattern else method.include? pattern end end end
pry_puts(text)
click to toggle source
# File lib/pry-moves/tracer.rb, line 130 def pry_puts(text) @command[:pry].output.puts text end
redirect_step_into?(binding_)
click to toggle source
# File lib/pry-moves/tracer.rb, line 116 def redirect_step_into?(binding_) return false unless binding_.local_variable_defined? :debug_redirect debug_redirect = binding_.local_variable_get(:debug_redirect) @step_into_funcs = [debug_redirect.to_s] if debug_redirect true end
start_tracing()
click to toggle source
# File lib/pry-moves/tracer.rb, line 61 def start_tracing #puts "##trace_obj #{trace_obj}" Pry.config.disable_breakpoints = true trace_obj.set_trace_func method(:tracing_func).to_proc end
trace_obj()
click to toggle source
You can't call set_trace_func or Thread.current.set_trace_func recursively even in different threads 😪 But! 💡 The hack is - you can call Thread.current.set_trace_func from inside of set_trace_func! 🤗
# File lib/pry-moves/tracer.rb, line 72 def trace_obj Thread.current[:pry_moves_debug] ? Thread.current : Kernel end
tracing_func(event, file, line, id, binding_, klass)
click to toggle source
# File lib/pry-moves/tracer.rb, line 82 def tracing_func(event, file, line, id, binding_, klass) # printf ": %8s %s:%-2d %10s %8s rec:#{@recursion_level} st:#{@c_stack_level}\n", event, file, line, id, klass # Ignore traces inside pry-moves code return if file && TRACE_IGNORE_FILES.include?(File.expand_path(file)) catch (:skip) do if send "trace_#{@action}", event, file, line, id, binding_ stop_tracing Pry.start(binding_, @pry_start_options) # for cases when currently traced method called more times recursively elsif %w(call return).include?(event) and within_current_method?(file, line) and @method[:name] == id # fix for bug in traced_method: return for dynamic methods has line number inside of caller delta = event == 'call' ? 1 : -1 #puts "recursion #{event}: #{delta}; changed: #{@recursion_level} => #{@recursion_level + delta}" @recursion_level += delta elsif %w(c-call c-return).include?(event) delta = event == 'c-call' ? 1 : -1 @c_stack_level += delta end end end