/sender

Adds :sender and :caller as well as other object-oriented backtrace methods to the built-in :callee and :method methods in Ruby 1.9.1.

Primary LanguageC

Sender

rubygems.org/gems/sender

DESCRIPTION:

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.

SUMMARY:

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}, ... )

INSTALL:

* sudo gem install sender

EXAMPLE:

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

EXAMPLE’s OUTPUT:

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.

LICENSE:

(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.