public
Description: Rubinius, the Ruby VM
Homepage: http://rubini.us
Clone URL: git://github.com/evanphx/rubinius.git
Search Repo:
rubinius / kernel / core / backtrace.rb
100644 105 lines (89 sloc) 2.223 kb
1
2
3
4
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
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
##
# Contains all logic for gathering and displaying backtraces.
 
class Backtrace
  include Enumerable
 
  attr_accessor :frames
  attr_accessor :top_context
  attr_accessor :first_color
  attr_accessor :kernel_color
  attr_accessor :eval_color
 
  def initialize
    @frames = []
    @top_context = nil
    @first_color = "\033[0;31m"
    @kernel_color = "\033[0;34m"
    @eval_color = "\033[0;33m"
  end
 
  def [](index)
    @frames[index]
  end
 
  def show(sep="\n", colorize = true)
    first = true
    color_config = Rubinius::RUBY_CONFIG["rbx.colorize_backtraces"]
    if color_config == "no" or color_config == "NO"
      colorize = false
      color = ""
      clear = ""
    else
      clear = "\033[0m"
    end
 
    formatted = @frames.map do |ctx|
      recv = ctx.describe
      loc = ctx.location
      color = color_from_loc(loc, first) if colorize
      first = false # special handling for first line
      times = @max - recv.size
      times = 0 if times < 0
      "#{color} #{' ' * times}#{recv} at #{loc}#{clear}"
    end
    return formatted.join(sep)
  end
 
  def join(sep)
    show
  end
 
  alias_method :to_s, :show
 
  def color_from_loc(loc, first)
    return @first_color if first
    if loc =~ /kernel/
      @kernel_color
    elsif loc =~ /\(eval\)/
      @eval_color
    else
      ""
    end
  end
 
  MAX_WIDTH = 40
 
  def fill_backtrace
    @max = 0
    @backtrace = []
    # Skip the first frame if we are raising an exception from
    # an eval's BlockContext
    if @frames.at(0).from_eval?
      frames = @frames[1, @frames.length - 1]
    else
      frames = @frames
    end
 
    frames.each_with_index do |ctx, i|
      str = ctx.describe
      @max = str.size if str.size > @max
      @backtrace << [str, ctx.location]
    end
    @max = MAX_WIDTH if @max > MAX_WIDTH
  end
 
  def self.backtrace(ctx=nil)
    ctx ||= MethodContext.current.sender
    obj = new()
    obj.top_context = ctx
    obj.frames = ctx.context_stack
 
    # TODO - Consider not doing this step if we know we want MRI output
    obj.fill_backtrace
    return obj
  end
 
  def each
    @backtrace.each { |f| yield f.last }
    self
  end
 
  def to_mri
    return @top_context.stack_trace_starting_at(0)
  end
end