class BetterErrors::StackFrame

@private

Attributes

filename[R]
frame_binding[R]
line[R]
name[R]

Public Class Methods

from_exception(exception) click to toggle source
# File lib/better_errors/stack_frame.rb, line 6
def self.from_exception(exception)
  RaisedException.new(exception).backtrace
end
new(filename, line, name, frame_binding = nil) click to toggle source
# File lib/better_errors/stack_frame.rb, line 12
def initialize(filename, line, name, frame_binding = nil)
  @filename       = filename
  @line           = line
  @name           = name
  @frame_binding  = frame_binding

  set_pretty_method_name if frame_binding
end

Public Instance Methods

application?() click to toggle source
# File lib/better_errors/stack_frame.rb, line 21
def application?
  if root = BetterErrors.application_root
    filename.index(root) == 0 && filename.index("#{root}/vendor") != 0
  end
end
application_path() click to toggle source
# File lib/better_errors/stack_frame.rb, line 27
def application_path
  filename[(BetterErrors.application_root.length+1)..-1]
end
class_name() click to toggle source
# File lib/better_errors/stack_frame.rb, line 43
def class_name
  @class_name
end
context() click to toggle source
# File lib/better_errors/stack_frame.rb, line 51
def context
  if gem?
    :gem
  elsif application?
    :application
  else
    :dunno
  end
end
gem?() click to toggle source
# File lib/better_errors/stack_frame.rb, line 31
def gem?
  Gem.path.any? { |path| filename.index(path) == 0 }
end
gem_path() click to toggle source
# File lib/better_errors/stack_frame.rb, line 35
def gem_path
  if path = Gem.path.detect { |p| filename.index(p) == 0 }
    gem_name_and_version, path = filename.sub("#{path}/gems/", "").split("/", 2)
    /(?<gem_name>.+)-(?<gem_version>[\w.]+)/ =~ gem_name_and_version
    "#{gem_name} (#{gem_version}) #{path}"
  end
end
instance_variables() click to toggle source
# File lib/better_errors/stack_frame.rb, line 92
def instance_variables
  return {} unless frame_binding
  Hash[visible_instance_variables.map { |x|
    [x, frame_binding.eval(x.to_s)]
  }]
end
local_variable(name) click to toggle source
# File lib/better_errors/stack_frame.rb, line 86
def local_variable(name)
  get_local_variable(name) || eval_local_variable(name)
rescue NameError => ex
  "#{ex.class}: #{ex.message}"
end
local_variables() click to toggle source
# File lib/better_errors/stack_frame.rb, line 69
def local_variables
  return {} unless frame_binding

  lv = frame_binding.eval("local_variables")
  return {} unless lv

  lv.each_with_object({}) do |name, hash|
    # Ruby 2.2's local_variables will include the hidden #$! variable if
    # called from within a rescue context. This is not a valid variable name,
    # so the local_variable_get method complains. This should probably be
    # considered a bug in Ruby itself, but we need to work around it.
    next if name == :"\#$!"

    hash[name] = local_variable(name)
  end
end
method_name() click to toggle source
# File lib/better_errors/stack_frame.rb, line 47
def method_name
  @method_name || @name
end
pretty_path() click to toggle source
# File lib/better_errors/stack_frame.rb, line 61
def pretty_path
  case context
  when :application;  application_path
  when :gem;          gem_path
  else                filename
  end
end
to_s() click to toggle source
# File lib/better_errors/stack_frame.rb, line 106
def to_s
  "#{pretty_path}:#{line}:in `#{name}'"
end
visible_instance_variables() click to toggle source
# File lib/better_errors/stack_frame.rb, line 99
def visible_instance_variables
  iv = frame_binding.eval("instance_variables")
  return {} unless iv

  iv - BetterErrors.ignored_instance_variables
end

Private Instance Methods

eval_local_variable(name) click to toggle source
# File lib/better_errors/stack_frame.rb, line 132
def eval_local_variable(name)
  frame_binding.eval(name.to_s)
end
get_local_variable(name) click to toggle source
# File lib/better_errors/stack_frame.rb, line 126
def get_local_variable(name)
  if defined?(frame_binding.local_variable_get)
    frame_binding.local_variable_get(name)
  end
end
set_pretty_method_name() click to toggle source
# File lib/better_errors/stack_frame.rb, line 111
def set_pretty_method_name
  name =~ /\A(block (\([^)]+\) )?in )?/
  recv = frame_binding.eval("self")

  return unless method_name = frame_binding.eval("::Kernel.__method__")

  if Module === recv
    @class_name = "#{$1}#{recv}"
    @method_name = ".#{method_name}"
  else
    @class_name = "#{$1}#{Kernel.instance_method(:class).bind(recv).call}"
    @method_name = "##{method_name}"
  end
end