unroller 0.0.21 → 0.0.22
Sign up to get free protection for your applications and to get access to all the features.
- data/Readme +18 -4
- data/lib/unroller.rb +82 -35
- metadata +11 -2
data/Readme
CHANGED
@@ -54,13 +54,21 @@ Say I have an ActiveRecord model and want to know exactly what actually goes on
|
|
54
54
|
|
55
55
|
Screenshot[link:include/screenshot1.png]
|
56
56
|
|
57
|
-
|
57
|
+
(The above shows <tt>:display_style => :concise</tt>.)
|
58
|
+
|
59
|
+
This is much more efficient and reliable than manually tracing through the execution yourself! (Which would involve trying to guess which file the <tt>save!</tt> method would be defined in, searching for the file in the depths of <tt>/usr/lib/ruby/gems</tt>, scrolling down to the right line number, and repeating a zillion times...)
|
60
|
+
|
61
|
+
Here's an example of the interactive debugger mode:
|
62
|
+
|
63
|
+
Screenshot[link:include/screenshot_interactive.png]
|
64
|
+
|
65
|
+
(The above shows <tt>:display_style => :show_entire_method_body</tt>.)
|
58
66
|
|
59
67
|
===Inspecting variables
|
60
68
|
|
61
|
-
If you'd like to see the values of all arguments/parameters that were passed into the method for each method call, just pass in the
|
69
|
+
If you'd like to see the values of all arguments/parameters that were passed into the method for each method call, just pass in the <tt>:show_args => true</tt> option.
|
62
70
|
|
63
|
-
If you'd like to see the values of all local variables as they exist right before executing the current line, just pass in the
|
71
|
+
If you'd like to see the values of all local variables as they exist right before executing the current line, just pass in the <tt>:show_locals => true</tt> option.
|
64
72
|
|
65
73
|
Note: You might like to know that the state of those variables is _after_ executing that line, too, but currently that's not possible.
|
66
74
|
|
@@ -166,6 +174,12 @@ Here's one way you could try to answer that question...
|
|
166
174
|
|
167
175
|
===Usage in Rails
|
168
176
|
|
177
|
+
Unroller can be useful for debugging in development mode as well as in tests. Keep in mind that it requires a terminal onto which to output, so it will work if you've started your server with <tt>./script/server</tt>, but not if the server is detached from the terminal with <tt>./script/server -d</tt> or if it's being executed via FastCGI...
|
178
|
+
|
179
|
+
Rails has a lot of levels of abstractions, so even a seemingly simple call can generate many, many method calls. You may want to try using some of the filtering options, such as <tt>:exclude_classes</tt>, to reduce the verbosity of the output.
|
180
|
+
|
181
|
+
<b>Unrolling an action in your controller:</b>
|
182
|
+
|
169
183
|
If you want to see all code that gets executed within a certain action in your controller, you can just add this snippet to your controller, request the page, and watch the console where you have Webrick running as pages and pages of ActionController/ActionRecord code go flying by...
|
170
184
|
|
171
185
|
around_filter do |controller, action|
|
@@ -184,7 +198,7 @@ The dependencies include: facets, qualitysmith_extensions, colored, and extensio
|
|
184
198
|
|
185
199
|
It's pretty much fully functional, but may still have a couple rough edges.
|
186
200
|
|
187
|
-
|
201
|
+
Generally it behaves quite reliably and stably.
|
188
202
|
|
189
203
|
(Don't even *think* about leaving this in your production code!)
|
190
204
|
|
data/lib/unroller.rb
CHANGED
@@ -3,10 +3,11 @@ gem 'facets'
|
|
3
3
|
require 'facets/core/module/namespace'
|
4
4
|
require 'facets/core/kernel/with'
|
5
5
|
require 'facets/core/kernel/set_with'
|
6
|
-
require 'facets/core/string/bracket'
|
7
6
|
require 'facets/core/kernel/singleton_class'
|
8
7
|
require 'facets/core/symbol/to_proc'
|
8
|
+
require 'facets/core/string/bracket'
|
9
9
|
require 'facets/core/string/index_all'
|
10
|
+
require 'facets/core/hash/reverse_merge'
|
10
11
|
gem 'qualitysmith_extensions'
|
11
12
|
require 'qualitysmith_extensions/object/send_if_not_nil'
|
12
13
|
require 'qualitysmith_extensions/kernel/trap_chain'
|
@@ -21,6 +22,8 @@ require 'qualitysmith_extensions/enumerable/select_until'
|
|
21
22
|
require 'qualitysmith_extensions/module/bool_attr_accessor'
|
22
23
|
gem 'colored'
|
23
24
|
require 'colored'
|
25
|
+
gem 'extensions'
|
26
|
+
require 'extensions/object'
|
24
27
|
|
25
28
|
require 'English'
|
26
29
|
require 'pp'
|
@@ -86,6 +89,13 @@ class Unroller
|
|
86
89
|
"#{name} = #{value.inspect}"
|
87
90
|
end.join('; ').bracket(' (', ')')
|
88
91
|
end
|
92
|
+
def verbose_to_s
|
93
|
+
@variables.map do |variable|
|
94
|
+
name, value = *variable
|
95
|
+
"#{name} = " +
|
96
|
+
value.pp_s.gsub(/^/, ' ')
|
97
|
+
end.join("\n")
|
98
|
+
end
|
89
99
|
def any?
|
90
100
|
!@variables.empty?
|
91
101
|
end
|
@@ -114,8 +124,12 @@ class Unroller
|
|
114
124
|
|
115
125
|
|
116
126
|
|
127
|
+
def self.debug(options = {}, &block)
|
128
|
+
options.reverse_merge! :interactive => true, :display_style => :show_entire_method_body
|
129
|
+
self.trace options, &block
|
130
|
+
end
|
131
|
+
|
117
132
|
def self.trace(options = {}, &block)
|
118
|
-
#puts 'called self.trace'
|
119
133
|
if @@instance and @@instance.tracing
|
120
134
|
# In case they try to turn tracing on when it's already on... Assume it was an accident and don't do anything.
|
121
135
|
#puts "@@instance.tracing=#{@@instance.tracing}"
|
@@ -332,23 +346,27 @@ class Unroller
|
|
332
346
|
#zzz
|
333
347
|
when 'call'
|
334
348
|
unless skip_line?
|
335
|
-
|
349
|
+
depth_debug = '' #" (internal_depth about to be #{@internal_depth+1})"
|
350
|
+
column sprintf(' ' + '\\'.cyan + ' calling'.cyan + ' ' + '%s'.underline.cyan + depth_debug,
|
351
|
+
fully_qualified_method), @column_widths[0]
|
336
352
|
newline
|
337
353
|
|
338
|
-
puts
|
339
|
-
header_before_code_for_entire_method(file, line_num)
|
340
|
-
do_show_locals if show_args
|
341
|
-
ret = code_for_entire_method(file, line, klass, id, line, 0)
|
342
|
-
puts ret unless ret.nil?
|
343
|
-
puts
|
354
|
+
#puts
|
355
|
+
#header_before_code_for_entire_method(file, line_num)
|
356
|
+
#do_show_locals if show_args
|
357
|
+
#ret = code_for_entire_method(file, line, klass, id, line, 0)
|
358
|
+
#puts ret unless ret.nil?
|
359
|
+
#puts
|
344
360
|
|
345
361
|
@lines_output += 1
|
346
362
|
|
347
363
|
|
348
364
|
@depth += 1
|
349
365
|
end
|
350
|
-
|
366
|
+
|
367
|
+
@call_stack.push current_call
|
351
368
|
@internal_depth += 1
|
369
|
+
#puts "(@internal_depth+=1 ... #{@internal_depth})"
|
352
370
|
|
353
371
|
|
354
372
|
when 'class'
|
@@ -363,7 +381,7 @@ class Unroller
|
|
363
381
|
unless @last_call == current_call # Without this, I was seeing two consecutive events for the exact same line. This seems to be necessary because 'if foo()' is treated as two 'line' events: one for 'foo()' and one for 'if' (?)...
|
364
382
|
puts
|
365
383
|
header_before_code_for_entire_method(file, line_num)
|
366
|
-
do_show_locals if show_locals
|
384
|
+
do_show_locals if true #show_locals
|
367
385
|
ret = code_for_entire_method(inside_of.file, inside_of.line_num, @klass, @id, line, -1)
|
368
386
|
puts ret unless ret.nil?
|
369
387
|
puts
|
@@ -383,15 +401,16 @@ class Unroller
|
|
383
401
|
print "Debugger (" +
|
384
402
|
"Step out".menu_item(:red, 'u') + ' | ' +
|
385
403
|
"Step over (or Enter key)".menu_item(:cyan, 'v') + ' | ' +
|
386
|
-
"Step into (Space
|
404
|
+
"Step into (Space)".menu_item(:green, 'i') + ' | ' +
|
387
405
|
"show Locals".menu_item(:yellow, 'l') + ' | ' +
|
388
406
|
"Run".menu_item(:blue) +
|
389
407
|
') > '
|
390
408
|
response = $stdin.getc.chr.downcase
|
409
|
+
puts unless response == "\n"
|
391
410
|
|
392
411
|
case response
|
393
412
|
when 'l'
|
394
|
-
|
413
|
+
do_show_locals_verbosely
|
395
414
|
response = nil
|
396
415
|
end
|
397
416
|
end
|
@@ -402,6 +421,7 @@ class Unroller
|
|
402
421
|
@interactive = false
|
403
422
|
when 'u' # Step out
|
404
423
|
@silent_until_return_to_this_depth = @internal_depth - 1
|
424
|
+
#puts "Setting @silent_until_return_to_this_depth = #{@silent_until_return_to_this_depth}"
|
405
425
|
when 'v', "\n" # Step over = Ignore anything with a greater depth.
|
406
426
|
@only_makes_sense_if_next_event_is_call = true
|
407
427
|
@silent_until_return_to_this_depth = @internal_depth
|
@@ -418,29 +438,33 @@ class Unroller
|
|
418
438
|
when 'return'
|
419
439
|
|
420
440
|
@internal_depth -= 1
|
441
|
+
#puts "(@internal_depth-=1 ... #{@internal_depth})"
|
442
|
+
|
443
|
+
# Did we just get out of an uninteresting call?? Are we back in interesting land again??
|
444
|
+
if @silent_until_return_to_this_depth and
|
445
|
+
@silent_until_return_to_this_depth == @internal_depth
|
446
|
+
#puts "Yay, we're back in interesting land! (@internal_depth = #{@internal_depth})"
|
447
|
+
@silent_until_return_to_this_depth = nil
|
448
|
+
end
|
449
|
+
|
450
|
+
|
421
451
|
unless skip_line?
|
422
452
|
puts "Warning: @depth < 0. You may wish to call trace with a :depth => depth value greater than #{@initial_depth}" if @depth-1 < 0
|
423
453
|
@depth -= 1 unless @depth == 0
|
424
454
|
#puts "-- Decreased depth to #{depth}"
|
425
455
|
returning_from = @call_stack.last
|
426
456
|
|
427
|
-
|
457
|
+
depth_debug = '' #" (internal_depth was #{@internal_depth+1})"
|
458
|
+
column sprintf(' ' + '/'.cyan + ' returning from'.cyan + ' ' + '%s'.cyan + depth_debug,
|
459
|
+
returning_from && returning_from.full_name), @column_widths[0]
|
428
460
|
newline
|
429
461
|
|
430
462
|
@lines_output += 1
|
431
463
|
end
|
432
464
|
|
433
|
-
# Did we just get out of an uninteresting call?? Are we back in interesting land again??
|
434
|
-
if @silent_until_return_to_this_depth and
|
435
|
-
@silent_until_return_to_this_depth == @internal_depth
|
436
|
-
puts "Yay, we're back in interesting land!"
|
437
|
-
@silent_until_return_to_this_depth = nil
|
438
|
-
end
|
439
|
-
|
440
465
|
@call_stack.pop
|
441
466
|
|
442
467
|
|
443
|
-
|
444
468
|
when 'raise'
|
445
469
|
if !skip_line? or @always_show_raise_events
|
446
470
|
# We probably always want to see these (?)... Never skip displaying them, even if we are "too deep".
|
@@ -850,6 +874,15 @@ protected
|
|
850
874
|
def header_before_code_for_entire_method(file, line_num)
|
851
875
|
puts '' + "#{fully_qualified_method} (#{file}:#{line_num}) (#{@event}):".magenta if show_filename_and_line_numbers
|
852
876
|
end
|
877
|
+
|
878
|
+
def do_show_locals_verbosely
|
879
|
+
variables = Variables.new(:local, @binding)
|
880
|
+
if variables.any?
|
881
|
+
puts variables.verbose_to_s.yellow
|
882
|
+
end
|
883
|
+
end
|
884
|
+
|
885
|
+
|
853
886
|
end # class Unroller
|
854
887
|
|
855
888
|
|
@@ -1138,7 +1171,7 @@ if $0 == __FILE__
|
|
1138
1171
|
herald '-----------------------------------------------------------'
|
1139
1172
|
herald 'Test @exclude_methods'
|
1140
1173
|
herald 'Should only see calls to green, strong'
|
1141
|
-
class Wasabi
|
1174
|
+
class Wasabi #:nodoc:
|
1142
1175
|
def green
|
1143
1176
|
'...'
|
1144
1177
|
end
|
@@ -1170,7 +1203,7 @@ if $0 == __FILE__
|
|
1170
1203
|
herald '-----------------------------------------------------------'
|
1171
1204
|
herald 'Test @exclude_classes'
|
1172
1205
|
herald 'Should only see calls to Interesting::...'
|
1173
|
-
class Interesting
|
1206
|
+
class Interesting #:nodoc:
|
1174
1207
|
def self.method
|
1175
1208
|
'...'
|
1176
1209
|
end
|
@@ -1179,9 +1212,9 @@ if $0 == __FILE__
|
|
1179
1212
|
end
|
1180
1213
|
|
1181
1214
|
end
|
1182
|
-
module Uninteresting
|
1215
|
+
module Uninteresting #:nodoc:
|
1183
1216
|
|
1184
|
-
class ClassThatCluttersUpOnesTraces
|
1217
|
+
class ClassThatCluttersUpOnesTraces #:nodoc:
|
1185
1218
|
('a'..last='h').each do |method_name|
|
1186
1219
|
next_method_name = method_name.next unless method_name == last
|
1187
1220
|
eval <<-End, binding, __FILE__, __LINE__ + 1
|
@@ -1251,7 +1284,7 @@ if $0 == __FILE__
|
|
1251
1284
|
herald '-----------------------------------------------------------'
|
1252
1285
|
herald 'Test class definition'
|
1253
1286
|
Unroller::trace do
|
1254
|
-
class NewClass
|
1287
|
+
class NewClass #:nodoc:
|
1255
1288
|
def hi
|
1256
1289
|
'hi'
|
1257
1290
|
end
|
@@ -1283,12 +1316,12 @@ if $0 == __FILE__
|
|
1283
1316
|
|
1284
1317
|
herald '-----------------------------------------------------------'
|
1285
1318
|
herald 'Testing the :rails "preset"'
|
1286
|
-
module ActiveSupport
|
1319
|
+
module ActiveSupport #:nodoc:
|
1287
1320
|
def self.whatever
|
1288
1321
|
'whatever'
|
1289
1322
|
end
|
1290
1323
|
end
|
1291
|
-
module ActiveMongoose
|
1324
|
+
module ActiveMongoose #:nodoc:
|
1292
1325
|
def self.whatever
|
1293
1326
|
'whatever'
|
1294
1327
|
end
|
@@ -1301,14 +1334,14 @@ if $0 == __FILE__
|
|
1301
1334
|
|
1302
1335
|
herald '-----------------------------------------------------------'
|
1303
1336
|
herald 'Testing the :dependencies "preset"'
|
1304
|
-
module ActiveSupport
|
1305
|
-
module Dependencies
|
1337
|
+
module ActiveSupport #:nodoc:
|
1338
|
+
module Dependencies #:nodoc:
|
1306
1339
|
def self.whatever
|
1307
1340
|
'whatever'
|
1308
1341
|
end
|
1309
1342
|
end
|
1310
1343
|
end
|
1311
|
-
module Gem
|
1344
|
+
module Gem #:nodoc:
|
1312
1345
|
def self.whatever
|
1313
1346
|
'whatever'
|
1314
1347
|
end
|
@@ -1334,11 +1367,11 @@ if $0 == __FILE__
|
|
1334
1367
|
|
1335
1368
|
herald '-----------------------------------------------------------'
|
1336
1369
|
herald 'Testing watch_for_added_methods'
|
1337
|
-
class Foo
|
1370
|
+
class Foo #:nodoc:
|
1338
1371
|
def existing_method; end
|
1339
1372
|
end
|
1340
1373
|
Unroller::watch_for_added_methods(Foo, /interesting/) do
|
1341
|
-
class Foo
|
1374
|
+
class Foo #:nodoc:
|
1342
1375
|
def foo; end
|
1343
1376
|
def an_interesting_method; end
|
1344
1377
|
end
|
@@ -1371,6 +1404,19 @@ if $0 == __FILE__
|
|
1371
1404
|
big_ol_gaggle
|
1372
1405
|
end
|
1373
1406
|
|
1407
|
+
herald '-----------------------------------------------------------'
|
1408
|
+
herald 'Testing :interactive => true / interactive debugger'
|
1409
|
+
def factorial(x)
|
1410
|
+
if x == 1
|
1411
|
+
x
|
1412
|
+
else
|
1413
|
+
x * factorial(x - 1)
|
1414
|
+
end
|
1415
|
+
end
|
1416
|
+
Unroller::debug do
|
1417
|
+
factorial(4)
|
1418
|
+
end
|
1419
|
+
|
1374
1420
|
herald '-----------------------------------------------------------'
|
1375
1421
|
herald 'Testing :interactive => true / interactive debugger'
|
1376
1422
|
def subway
|
@@ -1396,7 +1442,8 @@ if $0 == __FILE__
|
|
1396
1442
|
_do = nil
|
1397
1443
|
_do = nil
|
1398
1444
|
end
|
1399
|
-
Unroller::trace :display_style => :show_entire_method_body, :interactive => true do
|
1445
|
+
#Unroller::trace :display_style => :show_entire_method_body, :interactive => true do
|
1446
|
+
Unroller::debug do
|
1400
1447
|
subway
|
1401
1448
|
end
|
1402
1449
|
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.2
|
|
3
3
|
specification_version: 1
|
4
4
|
name: unroller
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.0.
|
7
|
-
date: 2007-06-
|
6
|
+
version: 0.0.22
|
7
|
+
date: 2007-06-18 00:00:00 -07:00
|
8
8
|
summary: "Ruby Code Unroller: A tool for generating human-readable \"execution traces\""
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -84,3 +84,12 @@ dependencies:
|
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: 0.0.0
|
86
86
|
version:
|
87
|
+
- !ruby/object:Gem::Dependency
|
88
|
+
name: extensions
|
89
|
+
version_requirement:
|
90
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.0.0
|
95
|
+
version:
|