Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1.
Also provides object-oriented :backtrace supporting n-levels backward, :each_backtrace_frame for iteration, :backtrace_includes?, and :backtrace_includes_one_of? for context inspection, and :backtrace_frame_with and :backtrace_frames_with, which return matching frame information for the frame(s) matching the given description.
Adds object-oriented backtrace, which returns :object, :method, :line, and :file for each stack frame, and which permits queries regarding backtrace contents. * __sender__ * __caller__ * backtrace * backtrace( frames_to_trace_backward ) * each_backtrace_frame * each_backtrace_frame( frames_to_trace_backward ) * backtrace_includes?( Class, class_instance, :symbol, {frame_hash}, ... ) * backtrace_includes?( frames_to_trace_backward, Class, class_instance, :symbol, {frame_hash}, ... ) * backtrace_includes_one_of?( Class, class_instance, :symbol, {frame_hash}, ... ) * backtrace_includes_one_of?( frames_to_trace_backward, Class, class_instance, :symbol, {frame_hash}, ... ) * backtrace_frame_with( Class, class_instance, :symbol, {frame_hash}, ... ) * backtrace_frame_with( frames_to_trace_backward, Class, class_instance, :symbol, {frame_hash}, ... ) * backtrace_frames_with( Class, class_instance, :symbol, {frame_hash}, ... ) * backtrace_frames_with( frames_to_trace_backward, Class, class_instance, :symbol, {frame_hash}, ... )
* sudo gem install sender
require 'sender' require 'pp' class Test def initialize puts 'In method <Test>:initialize' puts 'Sender was: ' + __sender__.pretty_inspect.to_s puts 'Caller was: ' + __caller__.to_s end def test puts 'In <Test>:test' self.another_test end def another_test puts 'In method <Test>:another_test' test2 = Test2.new test2.and_another_test_in_another_object end def and_another_test_in_another_object puts 'In method <Test>:and_another_test_in_another_object' puts 'Sender was: ' + __sender__.pretty_inspect.to_s puts 'Caller was: ' + __caller__.to_s end end class Test2 < Test def initialize puts 'In method <Test2>:initialize' super puts 'Sender was: ' + __sender__.pretty_inspect.to_s puts 'Caller was: ' + __caller__.to_s pp Kernel.backtrace end def and_another_test_in_another_object puts 'In method <Test2>:and_another_test_in_another_object' super pp self puts 'Sender was: ' + __sender__.pretty_inspect.to_s puts 'Caller was: ' + __caller__.to_s pp Kernel.backtrace pp Kernel.backtrace( 2 ) puts 'These should be true:' pp Kernel.backtrace_includes?( :another_test ) pp Kernel.backtrace_includes?( Test ) pp Kernel.backtrace_includes?( $test ) pp Kernel.backtrace_includes?( :another_test, Test, $test ) pp Kernel.backtrace_includes?( "sender_test.rb" ) puts 'These should be false:' pp Kernel.backtrace_includes?( :yet_another_test ) pp Kernel.backtrace_includes?( Test2 ) pp Kernel.backtrace_includes?( self ) pp Kernel.backtrace_includes?( :yet_another_test, Test2, self ) pp Kernel.backtrace_includes?( "sender_test.rbi" ) puts 'And now we get a step by step backtrace' which_step = 1 Kernel.each_backtrace_frame do |this_frame| puts 'Frame number ' + which_step.to_s + ':' pp this_frame which_step += 1 end puts 'And now we try a backtrace inside a block.' block_item = [ 'one_item' ] block_item.each do |this_item| pp Kernel.backtrace end puts 'And :backtrace_includes_one_of?; this should be true:' pp Kernel.backtrace_includes_one_of?( :some_method_that_does_not_exit, :another_test, :test, :some_other_test_that_does_not_exist ) puts 'as should this:' pp Kernel.backtrace_includes_one_of?( { :method => :another_test, :object => $test }, { :method => :test } ) puts 'And :backtrace_frame_with; this should be a Hash:' pp Kernel.backtrace_frame_with( :test ) puts 'as should this:' pp Kernel.backtrace_frame_with( "sender_test.rb" ) puts 'And :backtrace_frames_with; this should be an Array of Hashes' pp Kernel.backtrace_frames_with( :object => $test ) puts 'as should this:' pp Kernel.backtrace_frames_with( :file => "sender_test.rb" ) puts 'And try iterating with an Enumerator' enumerator = Kernel.each_backtrace_frame pp enumerator while result = enumerator.next pp result end end end
In method <Test>:initialize Sender was: main Caller was: <main> In <Test>:test In method <Test>:another_test In method <Test2>:initialize In method <Test>:initialize Sender was: #<Test:0x0000010081ba10> Caller was: another_test Sender was: #<Test:0x0000010081ba10> Caller was: another_test [{:object=>#<Test2:0x0000010081a7e8>, :file=>"sender_test.rb", :line=>39, :method=>:initialize}, {:object=>Test2, :file=>nil, :line=>nil, :method=>:new}, {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>20, :method=>:another_test}, {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>15, :method=>:test}, {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"}, {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"}] In method <Test2>:and_another_test_in_another_object In method <Test>:and_another_test_in_another_object Sender was: #<Test2:0x0000010081a7e8> Caller was: another_test #<Test2:0x0000010081a7e8> Sender was: #<Test:0x0000010081ba10> Caller was: another_test [{:object=>#<Test2:0x0000010081a7e8>, :file=>"sender_test.rb", :line=>48, :method=>:and_another_test_in_another_object}, {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>21, :method=>:another_test}, {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>15, :method=>:test}, {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"}, {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"}] [{:object=>#<Test2:0x0000010081a7e8>, :file=>"sender_test.rb", :line=>49, :method=>:and_another_test_in_another_object}, {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>21, :method=>:another_test}] These should be true: true true true true true These should be false: false false false false false And now we get a step by step backtrace Frame number 1: {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>21, :method=>:another_test} Frame number 2: {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>15, :method=>:test} Frame number 3: {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"} Frame number 4: {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"} And now we try a backtrace inside a block. [{:object=>#<Test2:0x0000010081a7e8>, :file=>"sender_test.rb", :line=>73, :method=>:"block in and_another_test_in_another_object"}, {:object=>["one_item"], :file=>nil, :line=>nil, :method=>:each}, {:object=>#<Test2:0x0000010081a7e8>, :file=>"sender_test.rb", :line=>72, :method=>:and_another_test_in_another_object}, {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>21, :method=>:another_test}, {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>15, :method=>:test}, {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"}, {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"}] And :backtrace_includes_one_of?; this should be true: true as should this: true And :backtrace_frame_with; this should be a Hash: {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>15, :method=>:test} as should this: {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>21, :method=>:another_test} And :backtrace_frames_with; this should be an Array of Hashes [{:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>21, :method=>:another_test}, {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>15, :method=>:test}] as should this: [{:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>21, :method=>:another_test}, {:object=>#<Test:0x0000010081ba10>, :file=>"sender_test.rb", :line=>15, :method=>:test}, {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"}] And try iterating with an Enumerator #<Enumerator:0x000001010480e0> {:object=>#<Test2:0x0000010081a388>, :file=>"sender_test.rb", :line=>92, :method=>:and_another_test_in_another_object} {:object=>#<Test:0x0000010081b770>, :file=>"sender_test.rb", :line=>21, :method=>:another_test} {:object=>#<Test:0x0000010081b770>, :file=>"sender_test.rb", :line=>15, :method=>:test} {:object=>main, :file=>"sender_test.rb", :line=>103, :method=>:"<main>"} {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"} sender_test.rb:94:in `next': iteration reached at end (StopIteration) from sender_test.rb:94:in `and_another_test_in_another_object' from sender_test.rb:21:in `another_test' from sender_test.rb:15:in `test' from sender_test.rb:103:in `<main>' Finished Test.
(The MIT License) Copyright (c) 2010 Asher Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.