backtracer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README +39 -0
- data/Rakefile +14 -0
- data/VERSION +1 -0
- data/examples/crash.rb +10 -0
- data/examples/crash_longer.rb +22 -0
- data/examples/example_test_all_output +39 -0
- data/examples/example_test_large_output +42 -0
- data/examples/run_all_styles_of_backtracer.rb +12 -0
- data/examples/run_large_style_output.rb +1 -0
- data/lib/backtrace_nothing_swallowed.rb +6 -0
- data/lib/backtrace_with_code_and_locals.rb +2 -0
- data/lib/backtracer.rb +16 -0
- data/lib/core_backtracer.rb +277 -0
- metadata +70 -0
data/README
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
ruby_backtracer: a library to output higher quality backtraces if an unhandled exception is raised
|
2
|
+
|
3
|
+
ex:
|
4
|
+
running given script examples/crash.rb used to output:
|
5
|
+
examples>ruby crash.rb
|
6
|
+
crash.rb:2:in `go2': unhandled exception
|
7
|
+
from crash.rb:6:in `go'
|
8
|
+
from crash.rb:9
|
9
|
+
|
10
|
+
now outputs:
|
11
|
+
examples>ruby -r../backtrace_with_code_and_locals crash.rb
|
12
|
+
|
13
|
+
unhandled exception: crash.rb:2: raise
|
14
|
+
locals: {"a"=>"3", "b"=>55}
|
15
|
+
from:
|
16
|
+
crash.rb:1 go2(a=>3, b=>55)
|
17
|
+
locals: {"a"=>"3", "b"=>55}
|
18
|
+
crash.rb:5 go(a=>3)
|
19
|
+
locals: {"a"=>"3"}
|
20
|
+
|
21
|
+
Now wasn't that prettier?
|
22
|
+
|
23
|
+
There are several other tracing options provided, if you don't want as much output, or want more speed. Specify which by script name.
|
24
|
+
|
25
|
+
ex: backtrace_nothing_swallowed.rb outputs the same as the default exception output, except it doesn't have the
|
26
|
+
...skip 24 lines...
|
27
|
+
line in the middle (also no speed slowdown, and no local variables displayed).
|
28
|
+
|
29
|
+
Try them out by running test_all.rb in the examples folder, or eyeball the example output files in examples/example_output*
|
30
|
+
|
31
|
+
http://github.com/rogerdpack/ruby_backtracer/tree/master
|
32
|
+
|
33
|
+
Note: some options depends on ruby-debug [MRI] gem, some don't.
|
34
|
+
|
35
|
+
To install clone from github, above, then ruby -rscriptname your_script.
|
36
|
+
|
37
|
+
related projects: unroller, http://eigenclass.org/hiki/method+arguments+via+introspection, liveconsole, ruby-debug
|
38
|
+
|
39
|
+
send comments to rogerdpack on github.
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.name = "backtracer"
|
5
|
+
gemspec.summary = gemspec.description = "Quality backtraces for ruby"
|
6
|
+
gemspec.email = "rogerdpack@gmail.com"
|
7
|
+
# gemspec.homepage = "http://github.com/technicalpickles/the-perfect-gem"
|
8
|
+
# gemspec.description = "TODO"
|
9
|
+
# gemspec.authors = ["Josh Nichols"]
|
10
|
+
# gemspec.dependency
|
11
|
+
end
|
12
|
+
rescue LoadError
|
13
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
14
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/examples/crash.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# more "complicated" file to show off backtraces
|
2
|
+
def go2(a, b)
|
3
|
+
3
|
4
|
+
b = 3
|
5
|
+
within_go2 = 4
|
6
|
+
raise
|
7
|
+
end
|
8
|
+
def go(a);
|
9
|
+
within_go = 2
|
10
|
+
go2(a, 55);
|
11
|
+
'abc'
|
12
|
+
end
|
13
|
+
|
14
|
+
def does_nothing a
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
does_nothing 3
|
19
|
+
does_nothing 4
|
20
|
+
does_nothing 5
|
21
|
+
|
22
|
+
go '3'
|
@@ -0,0 +1,39 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
|
4
|
+
running ruby -r../backtrace_nothing_swallowed.rb crash.rb
|
5
|
+
crash.rb:2:in `go2': unhandled exception
|
6
|
+
from crash.rb:6:in `go'
|
7
|
+
from crash.rb:9
|
8
|
+
====
|
9
|
+
crash.rb:2:in `go2'
|
10
|
+
crash.rb:6:in `go'
|
11
|
+
crash.rb:9
|
12
|
+
====
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
running ruby -r../backtrace_with_code.rb crash.rb
|
17
|
+
crash.rb:2:in `go2': unhandled exception
|
18
|
+
from crash.rb:6:in `go'
|
19
|
+
from crash.rb:9
|
20
|
+
====
|
21
|
+
crash.rb:2:in `go2'
|
22
|
+
raise
|
23
|
+
crash.rb:6:in `go'
|
24
|
+
go2(a, 55);
|
25
|
+
crash.rb:9
|
26
|
+
go '3'
|
27
|
+
====
|
28
|
+
|
29
|
+
|
30
|
+
|
31
|
+
running ruby -r../backtrace_with_code_and_locals.rb crash.rb
|
32
|
+
|
33
|
+
unhandled exception: crash.rb:2: raise
|
34
|
+
locals: {"a"=>"3", "b"=>55}
|
35
|
+
from:
|
36
|
+
crash.rb:1 go2(a=>3, b=>55)
|
37
|
+
locals: {"a"=>"3", "b"=>55}
|
38
|
+
crash.rb:5 go(a=>3)
|
39
|
+
locals: {"a"=>"3"}
|
@@ -0,0 +1,42 @@
|
|
1
|
+
ruby 1.8.6 (2009-3-4 mbari 8B/0x8770 on patchlevel 287) [i686-linux]
|
2
|
+
#0:crash.rb:1::-: def go2(a, b)
|
3
|
+
|#0:crash.rb:1:Module:>: def go2(a, b)
|
4
|
+
args were []
|
5
|
+
#0:crash.rb:1:Module:<: def go2(a, b)
|
6
|
+
#0:crash.rb:5::-: def go(a);
|
7
|
+
|#0:crash.rb:5:Module:>: def go(a);
|
8
|
+
args were []
|
9
|
+
#0:crash.rb:5:Module:<: def go(a);
|
10
|
+
#0:crash.rb:9::-: go '3'
|
11
|
+
|#0:crash.rb:5:Object:>: def go(a);
|
12
|
+
args were [["a", "3"]]
|
13
|
+
|#0:crash.rb:6:Object:-: go2(a, 55);
|
14
|
+
| |#0:crash.rb:1:Object:>: def go2(a, b)
|
15
|
+
args were [["a", "3"], ["b", 55]]
|
16
|
+
| |#0:crash.rb:2:Object:-: raise
|
17
|
+
| | |#0:crash.rb:2:Kernel:>: raise
|
18
|
+
args were []
|
19
|
+
| | | |#0:crash.rb:2:Class:>: raise
|
20
|
+
args were []
|
21
|
+
| | | | |#0:crash.rb:2:Exception:>: raise
|
22
|
+
args were []
|
23
|
+
| | | |#0:crash.rb:2:Exception:<: raise
|
24
|
+
| | |#0:crash.rb:2:Class:<: raise
|
25
|
+
| | | |#0:crash.rb:2:Exception:>: raise
|
26
|
+
args were []
|
27
|
+
| | |#0:crash.rb:2:Exception:<: raise
|
28
|
+
| | | |#0:crash.rb:2:Exception:>: raise
|
29
|
+
args were []
|
30
|
+
| | |#0:crash.rb:2:Exception:<: raise
|
31
|
+
| | |#0:crash.rb:2:Object:R: raise
|
32
|
+
| |#0:crash.rb:2:Kernel:<: raise
|
33
|
+
|#0:crash.rb:3:Object:<: end
|
34
|
+
#0:crash.rb:7:Object:<: end
|
35
|
+
|
36
|
+
unhandled exception: crash.rb:2: raise
|
37
|
+
locals: {"a"=>"3", "b"=>55}
|
38
|
+
from:
|
39
|
+
crash.rb:1 go2(a=>3, b=>55)
|
40
|
+
locals: {"a"=>"3", "b"=>55}
|
41
|
+
crash.rb:5 go(a=>3)
|
42
|
+
locals: {"a"=>"3"}
|
@@ -0,0 +1,12 @@
|
|
1
|
+
for file in Dir.glob("../lib/backtrace_*") do
|
2
|
+
commands = []
|
3
|
+
for crash_file in ['crash.rb'] do
|
4
|
+
commands << "ruby -r#{file} #{crash_file}"
|
5
|
+
end
|
6
|
+
#commands << "ruby -v -r../backtrace_with_code_and_locals.rb ../crash.rb"
|
7
|
+
for command in commands
|
8
|
+
puts "\n\n\nrunning #{command}\n"
|
9
|
+
system(command)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
system "ruby -v -r../lib/backtrace_with_code_and_locals.rb crash.rb"
|
data/lib/backtracer.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# this one display full BT with code, at the end [no performance loss]
|
2
|
+
SCRIPT_LINES__ = {}
|
3
|
+
at_exit {
|
4
|
+
puts "==== "
|
5
|
+
|
6
|
+
backtrace_with_code = $!.backtrace.map{|bt|
|
7
|
+
file, line, junk = bt.split(":")
|
8
|
+
line = line.to_i - 1
|
9
|
+
actual_file = SCRIPT_LINES__[file]
|
10
|
+
actual_line = actual_file[line] if actual_file
|
11
|
+
"#{bt}\n\t#{actual_line.strip if actual_line}"
|
12
|
+
}
|
13
|
+
|
14
|
+
puts backtrace_with_code
|
15
|
+
puts "===="
|
16
|
+
}
|
@@ -0,0 +1,277 @@
|
|
1
|
+
#
|
2
|
+
# backtracer.rb - display backtrace of most recent error on exit [quality back trace, mind you]
|
3
|
+
# based off tracer.rb, unroller, python
|
4
|
+
# original tracer.rb by Keiju ISHITSUKA(Nippon Rational Inc.)
|
5
|
+
# Tons of the code is useless and could be removed, but at least it works
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'ruby-debug'
|
9
|
+
Debugger.start # we use this to track args.
|
10
|
+
|
11
|
+
#Debugger.keep_frame_binding = true # whatever this did :P
|
12
|
+
#
|
13
|
+
# tracer main class
|
14
|
+
#
|
15
|
+
class Tracer
|
16
|
+
@RCS_ID='-$Id: tracer.rb,v 1.8 1998/05/19 03:42:49 keiju Exp keiju $-'
|
17
|
+
|
18
|
+
@stdout = STDOUT
|
19
|
+
@verbose = false
|
20
|
+
class << self
|
21
|
+
attr :verbose, true
|
22
|
+
alias verbose? verbose
|
23
|
+
attr :stdout, true
|
24
|
+
end
|
25
|
+
|
26
|
+
EVENT_SYMBOL = {
|
27
|
+
"line" => "-",
|
28
|
+
"call" => ">",
|
29
|
+
"return" => "<",
|
30
|
+
"class" => "C",
|
31
|
+
"end" => "E",
|
32
|
+
"c-call" => ">",
|
33
|
+
"c-return" => "<",
|
34
|
+
"raise" => "R"
|
35
|
+
}
|
36
|
+
|
37
|
+
def initialize
|
38
|
+
@threads = Hash.new
|
39
|
+
if defined? Thread.main
|
40
|
+
@threads[Thread.main.object_id] = 0
|
41
|
+
else
|
42
|
+
@threads[Thread.current.object_id] = 0
|
43
|
+
end
|
44
|
+
|
45
|
+
@get_line_procs = {}
|
46
|
+
|
47
|
+
@filters = []
|
48
|
+
end
|
49
|
+
|
50
|
+
def stdout
|
51
|
+
Tracer.stdout
|
52
|
+
end
|
53
|
+
|
54
|
+
def on
|
55
|
+
if block_given?
|
56
|
+
on
|
57
|
+
begin
|
58
|
+
yield
|
59
|
+
ensure
|
60
|
+
off
|
61
|
+
end
|
62
|
+
else
|
63
|
+
set_trace_func method(:trace_func).to_proc
|
64
|
+
stdout.print "Trace on\n" if Tracer.verbose?
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def off
|
69
|
+
set_trace_func nil
|
70
|
+
stdout.print "Trace off\n" if Tracer.verbose?
|
71
|
+
end
|
72
|
+
|
73
|
+
def add_filter(p = proc)
|
74
|
+
@filters.push p
|
75
|
+
end
|
76
|
+
|
77
|
+
def set_get_line_procs(file, p = proc)
|
78
|
+
@get_line_procs[file] = p
|
79
|
+
end
|
80
|
+
|
81
|
+
def get_line(file, line)
|
82
|
+
self.class.get_line(file, line)
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.get_line(file, line)
|
86
|
+
@get_line_procs ||= {}
|
87
|
+
if p = @get_line_procs[file]
|
88
|
+
return p.call(line)
|
89
|
+
end
|
90
|
+
|
91
|
+
unless list = SCRIPT_LINES__[file]
|
92
|
+
begin
|
93
|
+
f = open(file)
|
94
|
+
begin
|
95
|
+
SCRIPT_LINES__[file] = list = f.readlines
|
96
|
+
ensure
|
97
|
+
f.close
|
98
|
+
end
|
99
|
+
rescue
|
100
|
+
SCRIPT_LINES__[file] = list = []
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
if l = list[line - 1]
|
105
|
+
l
|
106
|
+
else
|
107
|
+
"-\n"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_thread_no
|
112
|
+
if no = @threads[Thread.current.object_id]
|
113
|
+
no
|
114
|
+
else
|
115
|
+
@threads[Thread.current.object_id] = @threads.size
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
require 'pp'
|
120
|
+
@@depths = {} # I think I added this [rdp]
|
121
|
+
@@last_line = nil
|
122
|
+
@@last_file = nil
|
123
|
+
@@last_symbol = nil
|
124
|
+
def trace_func(event, file, line, id, binding, klass, *nothing)
|
125
|
+
begin
|
126
|
+
return if file == __FILE__
|
127
|
+
|
128
|
+
type = EVENT_SYMBOL[event] # "<" or ">"
|
129
|
+
thread_no = get_thread_no
|
130
|
+
Thread.current['backtrace'] ||= []
|
131
|
+
@@depths[thread_no] ||= 0
|
132
|
+
Thread.current['backtrace'] << nil if Thread.current['backtrace'].length < (@@depths[thread_no] ) # pad it :)
|
133
|
+
if type == ">"
|
134
|
+
@@depths[thread_no] += 1
|
135
|
+
elsif type == "<"
|
136
|
+
@@depths[thread_no] -= 1
|
137
|
+
end
|
138
|
+
|
139
|
+
for p in @filters
|
140
|
+
return unless p.call event, file, line, id, binding, klass
|
141
|
+
end
|
142
|
+
return if file.include? 'ruby-debug' # debugger output
|
143
|
+
|
144
|
+
saved_crit = Thread.critical
|
145
|
+
Thread.critical = true
|
146
|
+
# TODO only do the backtrace if last command was 'raise'
|
147
|
+
if type == 'R'
|
148
|
+
Thread.current['backtrace'][@@depths[thread_no] - 1] = [[file, line], [], binding]
|
149
|
+
Thread.current['backtrace'] = Thread.current['backtrace'][0..@@depths[thread_no]] # clear old stuffs
|
150
|
+
end
|
151
|
+
|
152
|
+
if [file, line] != @@last_line # for output sake [not output too many lines]
|
153
|
+
if @@last_symbol == '>' # then we need to add to the backtrace--we've advanced down a call in the callstack and can now glean its variables' values
|
154
|
+
previous_frame_binding = Debugger.current_context.frame_binding(2)
|
155
|
+
collected = []
|
156
|
+
args = Debugger.current_context.frame_args 1 rescue nil # maybe it had no arguments [ltodo check]
|
157
|
+
|
158
|
+
if args
|
159
|
+
for arg in args
|
160
|
+
value = eval(arg, previous_frame_binding)
|
161
|
+
collected << [arg, value]
|
162
|
+
end
|
163
|
+
else
|
164
|
+
print "WEIRD--please report err spot 1, how to reproduce"
|
165
|
+
end
|
166
|
+
print 'args were ', collected.inspect, "\n" if $VERBOSE
|
167
|
+
|
168
|
+
Thread.current['backtrace'][@@depths[thread_no] - 1] = [[@@last_file, @@last_line], collected, previous_frame_binding]
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
out = " |" * @@depths[thread_no] + sprintf("#%d:%s:%d:%s:%s: %s",
|
173
|
+
get_thread_no,
|
174
|
+
file,
|
175
|
+
line,
|
176
|
+
klass || '',
|
177
|
+
type,
|
178
|
+
get_line(file, line))
|
179
|
+
|
180
|
+
print out if $VERBOSE
|
181
|
+
@@last_line = line
|
182
|
+
@@last_file = file
|
183
|
+
@@last_symbol = type
|
184
|
+
|
185
|
+
Thread.critical = saved_crit
|
186
|
+
rescue Exception => e
|
187
|
+
# TODO investigate print "BAD" + e.to_s + e.backtrace.inspect
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
Single = new
|
192
|
+
def Tracer.on
|
193
|
+
if block_given?
|
194
|
+
Single.on{yield}
|
195
|
+
else
|
196
|
+
Single.on
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def Tracer.off
|
201
|
+
Single.off
|
202
|
+
end
|
203
|
+
|
204
|
+
def Tracer.set_get_line_procs(file_name, p = proc)
|
205
|
+
Single.set_get_line_procs(file_name, p)
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
def Tracer.add_filter(p = proc)
|
210
|
+
Single.add_filter(p)
|
211
|
+
end
|
212
|
+
|
213
|
+
def Tracer.output_locals(previous_binding, prefix="\t\t")
|
214
|
+
locals_name = Kernel.eval("local_variables", previous_binding)
|
215
|
+
locals = {}
|
216
|
+
for name in locals_name do
|
217
|
+
locals[name] = Kernel.eval(name, previous_binding)
|
218
|
+
end
|
219
|
+
|
220
|
+
puts "#{prefix}locals: " + locals.inspect
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
at_exit do # at_exit seems to be run by the last running Thread. Or an exiting thread? Not sure for always.
|
225
|
+
off
|
226
|
+
raise_location = Thread.current['backtrace'].pop
|
227
|
+
loc = raise_location[0]
|
228
|
+
puts
|
229
|
+
puts "unhandled exception: #{loc[0]}:#{loc[1]}: #{get_line loc[0], loc[1]}"
|
230
|
+
if(defined?($NO_LOCALS))
|
231
|
+
no_locals = true
|
232
|
+
else
|
233
|
+
no_locals = false
|
234
|
+
end
|
235
|
+
output_locals(raise_location[2], "\t") unless no_locals
|
236
|
+
puts "\t from:\n"
|
237
|
+
|
238
|
+
# last most one is redundant with the raise one...
|
239
|
+
Thread.current['backtrace'].pop
|
240
|
+
|
241
|
+
for loc, params, binding in Thread.current['backtrace'].reverse do
|
242
|
+
original_line = get_line loc[0], loc[1]
|
243
|
+
# TODO handle non parentheses
|
244
|
+
line_no_params = original_line.split('(')[0]
|
245
|
+
line_no_params.gsub!('def ', '')
|
246
|
+
line_params = line_no_params + "("
|
247
|
+
comma = ""
|
248
|
+
for param in params do
|
249
|
+
line_params += param[0].to_s + "=>" + param[1].to_s + ", "
|
250
|
+
comma = ", "
|
251
|
+
end
|
252
|
+
line_params = line_params[0..-3] # strip off ending comma
|
253
|
+
line_params += ")" if line_params =~ /\(/
|
254
|
+
puts "\t#{loc[0]}:#{loc[1]} #{line_params}"
|
255
|
+
output_locals binding unless no_locals
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
exit!
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
|
264
|
+
Tracer::on
|
265
|
+
if $0 == __FILE__
|
266
|
+
# direct call
|
267
|
+
|
268
|
+
$0 = ARGV[0]
|
269
|
+
ARGV.shift
|
270
|
+
Tracer.on
|
271
|
+
require $0
|
272
|
+
elsif caller(0).size == 1
|
273
|
+
Tracer.on
|
274
|
+
end
|
275
|
+
|
276
|
+
# TODO: do are arg snapshots capture it right [soon enough]?
|
277
|
+
# TODO: don't output error if none thrown :)
|
metadata
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: backtracer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors: []
|
7
|
+
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-10-29 00:00:00 -06:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Quality backtraces for ruby
|
17
|
+
email: rogerdpack@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- README
|
26
|
+
- Rakefile
|
27
|
+
- VERSION
|
28
|
+
- examples/crash.rb
|
29
|
+
- examples/crash_longer.rb
|
30
|
+
- examples/example_test_all_output
|
31
|
+
- examples/example_test_large_output
|
32
|
+
- examples/run_all_styles_of_backtracer.rb
|
33
|
+
- examples/run_large_style_output.rb
|
34
|
+
- lib/backtrace_nothing_swallowed.rb
|
35
|
+
- lib/backtrace_with_code_and_locals.rb
|
36
|
+
- lib/backtracer.rb
|
37
|
+
- lib/core_backtracer.rb
|
38
|
+
has_rdoc: true
|
39
|
+
homepage:
|
40
|
+
licenses: []
|
41
|
+
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options:
|
44
|
+
- --charset=UTF-8
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.5
|
63
|
+
signing_key:
|
64
|
+
specification_version: 3
|
65
|
+
summary: Quality backtraces for ruby
|
66
|
+
test_files:
|
67
|
+
- examples/crash.rb
|
68
|
+
- examples/crash_longer.rb
|
69
|
+
- examples/run_all_styles_of_backtracer.rb
|
70
|
+
- examples/run_large_style_output.rb
|