class PowerTrace::Entry
Constants
- ATTRIBUTE_COLORS
- DEFAULT_LINE_LIMIT
- EMPTY_ARRAY
- EMPTY_HASH
- EMPTY_STRING
- SET_IVAR_INSTRUCTION_REGEX
- SPACE
- UNDEFINED
Attributes
arguments[R]
filepath[R]
frame[R]
ivars[R]
line_number[R]
locals[R]
receiver[R]
Public Class Methods
new(frame)
click to toggle source
# File lib/power_trace/entry.rb, line 17 def initialize(frame) @frame = frame @filepath, @line_number = frame.source_location @receiver = frame.receiver @locals, @arguments = collect_locals_and_arguments @ivars = collect_ivars end
Public Instance Methods
arguments_string(options = {})
click to toggle source
# File lib/power_trace/entry.rb, line 33 def arguments_string(options = {}) <<~STR.chomp #{options[:indentation]}(Arguments) #{hash_to_string(arguments, false, options)} STR end
call_trace(options = {})
click to toggle source
# File lib/power_trace/entry.rb, line 54 def call_trace(options = {}) "#{location(options)}:in `#{name(options)}'" end
ivars_string(options = {})
click to toggle source
# File lib/power_trace/entry.rb, line 47 def ivars_string(options = {}) <<~STR.chomp #{options[:indentation]}(Instance Variables) #{hash_to_string(ivars, false, options)} STR end
locals_string(options = {})
click to toggle source
# File lib/power_trace/entry.rb, line 40 def locals_string(options = {}) <<~STR.chomp #{options[:indentation]}(Locals) #{hash_to_string(locals, false, options)} STR end
location(options = {})
click to toggle source
# File lib/power_trace/entry.rb, line 29 def location(options = {}) "#{filepath}:#{line_number}" end
name(options = {})
click to toggle source
# File lib/power_trace/entry.rb, line 25 def name(options = {}) frame.frame_description end
to_s(options = {})
click to toggle source
# File lib/power_trace/entry.rb, line 81 def to_s(options = {}) # this is to prevent entries from polluting each other's options # of course, that'd only happen if I did something stupid ;) assemble_string(options.dup) end
Private Instance Methods
assemble_string(options)
click to toggle source
# File lib/power_trace/entry.rb, line 93 def assemble_string(options) strings = [call_trace(options)] indentation = SPACE * (options[:extra_info_indent] || 0) options[:indentation] = indentation if arguments.present? strings << arguments_string(options) end if locals.present? strings << locals_string(options) end if ivars.present? strings << ivars_string(options) end strings.join("\n") end
collect_ivars()
click to toggle source
we need to make sure
-
the frame is iseq (vm instructions)
-
and the instructions contain `setinstancevariable` instructions
and only then we can start capturing instance variables from the frame this is to make sure we only capture the instance variables set inside the current method call otherwise, it'll create a lot noise
# File lib/power_trace/entry.rb, line 165 def collect_ivars iseq = frame.instance_variable_get(:@iseq) return EMPTY_HASH unless iseq set_ivar_instructios = iseq.disasm.split("\n").select { |i| i.match?(SET_IVAR_INSTRUCTION_REGEX) } return EMPTY_HASH unless set_ivar_instructios.present? new_ivars = set_ivar_instructios.map do |i| i.match(/:(@\w+),/)[1] end new_ivars.inject({}) do |hash, ivar_name| hash[ivar_name] = receiver.instance_variable_get(ivar_name.to_sym) hash end end
collect_locals_and_arguments()
click to toggle source
# File lib/power_trace/entry.rb, line 184 def collect_locals_and_arguments locals = {} arguments = {} frame.local_variables.each do |name| value = frame.local_variable_get(name) if method_parameters.include?(name) arguments[name] = value else locals[name] = value end end [locals, arguments] end
hash_to_string(hash, inspect, options)
click to toggle source
# File lib/power_trace/entry.rb, line 114 def hash_to_string(hash, inspect, options) truncation = options[:line_limit] || DEFAULT_LINE_LIMIT indentation = (options[:indentation] || EMPTY_STRING) + SPACE * 2 elements_string = hash.map do |key, value| value_string = value_to_string(value, truncation) "#{key.to_s}: #{value_string}" end.join("\n#{indentation}") "#{indentation}#{elements_string}" end
method()
click to toggle source
# File lib/power_trace/entry.rb, line 201 def method @method ||= Object.instance_method(:method).bind(@receiver).call(name) rescue NameError # if any part of the program uses Refinement to extend its methods # we might still get NoMethodError when trying to get that method outside the scope nil end
method_parameters()
click to toggle source
# File lib/power_trace/entry.rb, line 89 def method_parameters [] end
value_to_string(value, truncation)
click to toggle source
# File lib/power_trace/entry.rb, line 125 def value_to_string(value, truncation) case value when Array value.to_s.truncate(truncation, omission: "...]") when Hash elements_string = value.map do |key, val| value_string = value_to_string(val, truncation) "#{key.to_s}: #{value_string}" end.join(", ") "{#{elements_string}}".truncate(truncation, omission: "...}") when nil "nil" when Symbol ":#{value}" when String "\"#{value.truncate(truncation)}\"" else if defined?(ActiveRecord::Base) case value when ActiveRecord::Base value.inspect.truncate(truncation, omission: "...>") when ActiveRecord::Relation "#{value}, SQL - (#{value.to_sql})" else value.to_s.truncate(truncation) end else value.to_s.truncate(truncation) end end end