unroller 0.0.8 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Readme +34 -0
- data/lib/unroller.rb +77 -19
- metadata +2 -2
data/Readme
CHANGED
@@ -63,6 +63,32 @@ If you'd like to see the values of all local variables as they exist right befor
|
|
63
63
|
|
64
64
|
Note: You might like to know that the state of those variables is _after_ executing that line, too, but currently that's not possible.
|
65
65
|
|
66
|
+
Also, I haven't yet figured out a way to show the return value it's going to return with when we hit a 'return' event. That would be nice to have, too, if one can figure out how to implement it...
|
67
|
+
|
68
|
+
===Only tracing if a condition is met
|
69
|
+
|
70
|
+
For example, a lot of the time you will be in a loop or iterator and you will only be interested in what's going on <i>during certain iterations</i> of that loop.
|
71
|
+
|
72
|
+
There are two ways you can accomplish that selectivity:
|
73
|
+
|
74
|
+
The good old simple way:
|
75
|
+
|
76
|
+
Unroller::trace if name =~ /interesting/
|
77
|
+
code_that_may_or_may_not_be_traced
|
78
|
+
Unroller::trace_off
|
79
|
+
|
80
|
+
And the somewhat trickier but arguably more elegant way that still uses a block (which always gets executed):
|
81
|
+
|
82
|
+
Unroller::trace :if => { name =~ /interesting/ } do
|
83
|
+
code_that_may_or_may_not_be_traced
|
84
|
+
end
|
85
|
+
|
86
|
+
The other reason that the latter way is preferred is that the return value of the code-being-traced is preserved. With the first method, you could end up breaking things if the trace_off happens to be the last value in your method (because then the value of trace_off will be used as the return valuel).
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
Note: The actual application code (the code in the block passed to Unroller::trace, if using the block version) will _always_ get executed, with either of these methods. It is only the tracing that we are toggling, not the execution of the code within the trace(d) block.
|
91
|
+
|
66
92
|
===Reducing verbosity
|
67
93
|
|
68
94
|
This can generate some really *verbose* output... Not only can be impractical to try to *read* through the reams of pages it can produce, but it can also take an hour just to output it in the first place!
|
@@ -126,6 +152,9 @@ If you enable tracing from within that method, it will only show the calls that
|
|
126
152
|
|
127
153
|
So... you could always <tt>p caller(0)</tt> within your mystery function and then put a trace around one of the calls leading up to this call, a little further up the stack...
|
128
154
|
|
155
|
+
I know, wouldn't it be nice if you could just tell it, "Show me the execution traces for the 3 calls leading up to this call"? But alas, Unroller can only affect what happens _after_ it gets called, not before.
|
156
|
+
If I ever get around to writing an interactive tree-based UI for this, then I guess we could give the _impression_ of being able to show calls leading up to a certain call. But only by recording *all* calls and then hiding everything except the calls you're interested in...
|
157
|
+
|
129
158
|
|
130
159
|
===Usage in Rails
|
131
160
|
|
@@ -186,9 +215,14 @@ It's also sort of like a call stack (caller(0)). But unlike the callstack you us
|
|
186
215
|
|
187
216
|
==Possibly related projects
|
188
217
|
|
218
|
+
I didn't see any projects out there that did what I was wanting, so I wrote my own (and was surprised by how easy it was!). But if you know of any similar projects out there, let me know and I'll check it out.
|
219
|
+
|
220
|
+
Here are the closest projects I've run across so far...
|
189
221
|
* http://rubyforge.org/projects/dev-utils/ : Collects utilities that aid Ruby development, e.g. testing and debugging. Version 1.0 contains simple debug logging, tracing, and escaping to IRB.
|
190
222
|
* http://rubyforge.org/projects/ruby-uml/ : Generates uml diagrams by tracing the run of an application for analysation of an existing application and to provide support for refactorisations.
|
191
223
|
|
224
|
+
I've also heard rumors that Ruby comes standard with some kind of debugger (?) ... Maybe I wouldn't have written this if I'd known how to use that (is it any good?? is it easy to use??)... but... I still haven't even looked at that.
|
225
|
+
|
192
226
|
==To do
|
193
227
|
|
194
228
|
You're welcome to submit comments and/or patches.
|
data/lib/unroller.rb
CHANGED
@@ -65,6 +65,8 @@ class Unroller
|
|
65
65
|
@exclude_classes = []
|
66
66
|
@show_args = true
|
67
67
|
@show_locals = false
|
68
|
+
@show_filename_and_line_numbers = true
|
69
|
+
@include_c_calls = false # Might be useful if you're debugging your own C extension. Otherwise, we really don't care about C-calls because we can't see the source for them anyway...
|
68
70
|
@strip_comments = true # :todo:
|
69
71
|
@use_full_path = false # :todo:
|
70
72
|
@screen_width = 150
|
@@ -122,7 +124,8 @@ class Unroller
|
|
122
124
|
# 1. Sometimes (and I don't know why), the code that gets shown for a 'return' event doesn't even look like it has anything to do with a return...
|
123
125
|
# 2. If we've been stuck in this method for a long time and we're really deep, the user has probably forgotten by now which method we are returning from
|
124
126
|
# (the filename may give some clue, but not enough), so this is likely to be a welcome reminder a lot of the time.
|
125
|
-
@
|
127
|
+
@internal_depth = 0 # This is the "true" depth. It is incremented/decremented for *every* call/return, even those that we're not displaying. It is necessary for the implementation of "excluding_calls_made_within_unintersting_call", to detect when we get back to interesting land.
|
128
|
+
@depth = @initial_depth # This is the user-friendly depth. It only counts calls/returns that we *display*; it does not change when we enter into a call that we're not displaying (a "hidden" call).
|
126
129
|
@output_line = ''
|
127
130
|
@column_counter = 0
|
128
131
|
@tracing = false
|
@@ -168,7 +171,7 @@ class Unroller
|
|
168
171
|
#printf "- (event=%8s) (klass=%10s) (id=%10s) (%s:%-2d)\n", event, klass, id, file, line #if klass.to_s == 'false'
|
169
172
|
#puts 'false!!!!!!!'+klass.inspect if klass.to_s == 'false'
|
170
173
|
|
171
|
-
return if ['c-call', 'c-return'].include? event
|
174
|
+
return if ['c-call', 'c-return'].include? event unless include_c_calls
|
172
175
|
#(puts 'exclude') if @excluding_calls_made_within_unintersting_call unless event == 'return' # Until we hit a return and can break out of this uninteresting call, we don't want to do *anything*.
|
173
176
|
#return if uninteresting_class?(klass.to_s) unless (klass == false)
|
174
177
|
|
@@ -192,15 +195,17 @@ class Unroller
|
|
192
195
|
file_column file, line
|
193
196
|
newline
|
194
197
|
|
195
|
-
# The locals at this point will be simply be the arguments that were passed in to this method.
|
196
|
-
do_show_locals if show_args
|
197
|
-
|
198
198
|
@lines_output += 1
|
199
199
|
|
200
200
|
@call_stack.push fully_qualified_method
|
201
|
-
end
|
202
201
|
|
203
|
-
|
202
|
+
@depth += 1
|
203
|
+
#puts "++ Increased depth to #{depth}"
|
204
|
+
|
205
|
+
# The locals at this point will be simply be the arguments that were passed in to this method.
|
206
|
+
do_show_locals if show_args
|
207
|
+
end
|
208
|
+
@internal_depth += 1
|
204
209
|
|
205
210
|
|
206
211
|
when 'class'
|
@@ -220,11 +225,14 @@ class Unroller
|
|
220
225
|
|
221
226
|
|
222
227
|
when 'return'
|
223
|
-
puts "Warning: @depth < 0. You may wish to call trace with a :depth => depth value greater than #{@initial_depth}" if @depth < 0
|
224
|
-
@depth -= 1 unless @depth == 0
|
225
|
-
returning_from = @call_stack.pop
|
226
228
|
|
229
|
+
@internal_depth -= 1
|
227
230
|
unless skip_line?
|
231
|
+
puts "Warning: @depth < 0. You may wish to call trace with a :depth => depth value greater than #{@initial_depth}" if @depth-1 < 0
|
232
|
+
@depth -= 1 unless @depth == 0
|
233
|
+
#puts "-- Decreased depth to #{depth}"
|
234
|
+
returning_from = @call_stack.pop
|
235
|
+
|
228
236
|
code = code_for(file, line, '\\'.magenta, :green, suffix = " (returning from #{returning_from})".green)
|
229
237
|
code = code_for(file, line, '\\'.magenta + " (returning from #{returning_from})".green, :green) unless code =~ /return|end/
|
230
238
|
# I've seen some really weird statements listed as "return" statements.
|
@@ -242,11 +250,10 @@ class Unroller
|
|
242
250
|
end
|
243
251
|
|
244
252
|
# Did we just get out of an uninteresting call?? Are we back in interesting land again??
|
245
|
-
if
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
end
|
253
|
+
if @excluding_calls_made_within_unintersting_call and
|
254
|
+
@excluding_calls_made_within_unintersting_call == @internal_depth
|
255
|
+
puts "Yay, we're back in interesting land!"
|
256
|
+
@excluding_calls_made_within_unintersting_call = nil
|
250
257
|
end
|
251
258
|
|
252
259
|
|
@@ -290,7 +297,9 @@ class Unroller
|
|
290
297
|
end
|
291
298
|
|
292
299
|
def self.trace_off
|
293
|
-
@@instance.
|
300
|
+
if @@instance and @@instance.tracing
|
301
|
+
@@instance.trace_off
|
302
|
+
end
|
294
303
|
end
|
295
304
|
def trace_off
|
296
305
|
@tracing = false
|
@@ -306,6 +315,7 @@ protected
|
|
306
315
|
end
|
307
316
|
def do_show_locals
|
308
317
|
variables = Variables.new(:local, @binding)
|
318
|
+
# puts "In do_show_locals at depth #{depth}; event = #{@event}"
|
309
319
|
if variables.any?
|
310
320
|
column variables.to_s
|
311
321
|
newline
|
@@ -335,8 +345,8 @@ protected
|
|
335
345
|
|
336
346
|
returning(class_name =~ regexp) do |uninteresting|
|
337
347
|
if uninteresting && recursive && @excluding_calls_made_within_unintersting_call.nil?
|
338
|
-
puts "Turning tracing off until we get back to
|
339
|
-
@excluding_calls_made_within_unintersting_call = @
|
348
|
+
puts "Turning tracing off until we get back to internal_depth #{@internal_depth} again because we're calling uninteresting #{class_name}:#{@id}"
|
349
|
+
@excluding_calls_made_within_unintersting_call = @internal_depth
|
340
350
|
end
|
341
351
|
end
|
342
352
|
end
|
@@ -396,7 +406,9 @@ protected
|
|
396
406
|
end
|
397
407
|
|
398
408
|
def file_column(file, line)
|
399
|
-
|
409
|
+
if show_filename_and_line_numbers
|
410
|
+
column "#{file}:#{line}", :remainder, :chop_left, :magenta
|
411
|
+
end
|
400
412
|
end
|
401
413
|
|
402
414
|
#----------------------------------------------------------
|
@@ -453,6 +465,14 @@ end
|
|
453
465
|
|
454
466
|
|
455
467
|
if $0 == __FILE__
|
468
|
+
puts '-----------------------------------------------------------'
|
469
|
+
puts 'Can call trace_off even if not tracing'
|
470
|
+
Unroller::trace_off
|
471
|
+
|
472
|
+
puts '-----------------------------------------------------------'
|
473
|
+
puts 'Testing return value (should print 3 in this case)'
|
474
|
+
puts Unroller::trace { 1 + 2 }
|
475
|
+
|
456
476
|
puts '-----------------------------------------------------------'
|
457
477
|
puts 'Simple test'
|
458
478
|
def jump!(how_high = 3)
|
@@ -635,6 +655,44 @@ if $0 == __FILE__
|
|
635
655
|
create_an_instance_of_UninterestingClassThatCluttersUpOnesTraces
|
636
656
|
end
|
637
657
|
|
658
|
+
=begin HistoricalNote
|
659
|
+
# This test used to generate output more like this (note the extreme indenting):
|
660
|
+
|
661
|
+
| create_an_instance_of_UninterestingClassThatCluttersUpOnesTraces | unroller.rb:645
|
662
|
+
| + calling Object::create_an_instance_of_UninterestingClassThatCluttersUpOnesTraces
|
663
|
+
| / def create_an_instance_of_UninterestingClassThatCluttersUpOnesTraces | unroller.rb:641
|
664
|
+
| | Uninteresting::ClassThatCluttersUpOnesTraces.new.a | unroller.rb:642
|
665
|
+
| | | | | | | | | | + calling Interesting::method
|
666
|
+
| | | | | | | | | | / def self.method | unroller.rb:620
|
667
|
+
| | | | | | | | | | | '...' | unroller.rb:621
|
668
|
+
| | | | | | | | | | \ end (returning from Interesting::method) | unroller.rb:622
|
669
|
+
| | | | | | | | | | + calling Interesting::method
|
670
|
+
| | | | | | | | | | / def method | unroller.rb:623
|
671
|
+
| | | | | | | | | | | '...' | unroller.rb:624
|
672
|
+
| | | | | | | | | | \ end (returning from Interesting::method) | unroller.rb:625
|
673
|
+
| \ end (returning from )
|
674
|
+
|
675
|
+
# ... which is probably a technically more accurate picture of the current call stack. However, it
|
676
|
+
|
677
|
+
# This changed when the idea of an @internal_depth separate from the @depth (that the user sees) was introduced.
|
678
|
+
|
679
|
+
| create_an_instance_of_UninterestingClassThatCluttersUpOnesTraces | unroller.rb:655
|
680
|
+
| + calling Object::create_an_instance_of_UninterestingClassThatCluttersUpOnesTraces
|
681
|
+
| / def create_an_instance_of_UninterestingClassThatCluttersUpOnesTraces | unroller.rb:651
|
682
|
+
| | Uninteresting::ClassThatCluttersUpOnesTraces.new.a | unroller.rb:652
|
683
|
+
| | + calling Interesting::method
|
684
|
+
| | / def self.method | unroller.rb:630
|
685
|
+
| | | '...' | unroller.rb:631
|
686
|
+
| | \ end (returning from Interesting::method) | unroller.rb:632
|
687
|
+
| | + calling Interesting::method
|
688
|
+
| | / def method | unroller.rb:633
|
689
|
+
| | | '...' | unroller.rb:634
|
690
|
+
| | \ end (returning from Interesting::method) | unroller.rb:635
|
691
|
+
| \ end (returning from Object::create_an_instance_of_UninterestingClassThatCluttersUpOnesTraces) | unroller.rb:653
|
692
|
+
|
693
|
+
Much cleaner looking...
|
694
|
+
=end
|
695
|
+
|
638
696
|
puts '-----------------------------------------------------------'
|
639
697
|
puts 'Now let\'s be recursive! We should *not* see any calls to Interesting::* this time. But after we return from it, we should see the call to jump!'
|
640
698
|
Unroller::trace(:exclude_classes => [[/Uninteresting/, :recursive]]) do
|
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-04-
|
6
|
+
version: 0.0.10
|
7
|
+
date: 2007-04-23 00:00:00 -07:00
|
8
8
|
summary: A tool for generating human-readable "execution traces"
|
9
9
|
require_paths:
|
10
10
|
- lib
|