sender 1.3 → 1.4

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/CHANGELOG.rdoc CHANGED
@@ -26,3 +26,9 @@ in the long term, I am investing what needs to be done for the special case.
26
26
 
27
27
  Added init_sender_callbacks( sender, caller ) to take care of :initialize issue. Include Sender module in your class to activate and
28
28
  :init_sender_callbacks( __sender__, __caller__ ) will be called on self from self.class.new before self.initialize.
29
+
30
+ === 1.4 2010-06-29
31
+
32
+ Removed init_sender_callbacks that were added in 1.3.
33
+ New implementation of backtrace- now works for :initialize.
34
+ __sender__ and __caller__ now work for :initialize and return the object and method that called :new.
data/Makefile CHANGED
@@ -53,7 +53,7 @@ COUTFLAG = -o
53
53
  RUBY_EXTCONF_H =
54
54
  cflags = $(optflags) $(debugflags) $(warnflags)
55
55
  optflags =
56
- debugflags = -g
56
+ debugflags = -gdwarf-2 -g3
57
57
  warnflags = -Wall -Wno-parentheses
58
58
  CFLAGS = -fno-common $(cflags) -fno-common -pipe -fno-common
59
59
  INCFLAGS = -I. -I$(arch_hdrdir) -I$(hdrdir)/ruby/backward -I$(hdrdir) -I$(srcdir) -I/usr/src/ruby
data/Manifest.txt CHANGED
@@ -4,6 +4,7 @@ Makefile
4
4
  Manifest.txt
5
5
  README.rdoc
6
6
  Rakefile
7
+ VERSION.rdoc
7
8
  ext/sender/RPSender_internal.c
8
9
  ext/sender/RPSender_internal.h
9
10
  ext/sender/RubySourceSupport.c
@@ -24,6 +25,7 @@ ext/sender/rb_Global.h
24
25
  ext/sender/rb_Global_internal.h
25
26
  ext/sender/rb_Kernel.c
26
27
  ext/sender/rb_Kernel.h
28
+ ext/sender/rb_Kernel_internal.h
27
29
  ext/sender/regenc.h
28
30
  ext/sender/regint.h
29
31
  ext/sender/regparse.h
data/README.rdoc CHANGED
@@ -28,28 +28,42 @@ which allows contents of the backtrace to be queried.
28
28
 
29
29
  == EXAMPLE:
30
30
 
31
- require 'sender'
32
-
33
31
  require '../sender/lib/sender/sender'
34
32
 
35
33
  require 'pp'
36
34
 
37
35
  class Test
38
-
36
+
37
+ def initialize
38
+ puts 'In method <Test>:initialize'
39
+ puts 'Sender was: ' + __sender__.pretty_inspect.to_s
40
+ puts 'Caller was: ' + __caller__.to_s
41
+ end
42
+
39
43
  def test
44
+ puts 'In <Test>:test'
40
45
  self.another_test
41
46
  end
42
-
47
+
43
48
  def another_test
49
+ puts 'In method <Test>:another_test'
44
50
  test2 = Test2.new
45
51
  test2.and_another_test_in_another_object
46
52
  end
47
-
53
+
48
54
  end
49
55
 
50
56
  class Test2
51
-
57
+
58
+ def initialize
59
+ puts 'In method <Test2>:initialize'
60
+ puts 'Sender was: ' + __sender__.pretty_inspect.to_s
61
+ puts 'Caller was: ' + __caller__.to_s
62
+ end
63
+
52
64
  def and_another_test_in_another_object
65
+ puts 'In method <Test2>:and_another_test_in_another_object'
66
+ pp self
53
67
  puts 'Sender was: ' + __sender__.pretty_inspect.to_s
54
68
  puts 'Caller was: ' + __caller__.to_s
55
69
  pp Kernel.backtrace
@@ -60,26 +74,56 @@ which allows contents of the backtrace to be queried.
60
74
  pp Kernel.backtrace_includes?( $test )
61
75
  pp Kernel.backtrace_includes?( :another_test, Test, $test )
62
76
  puts 'These should be false:'
63
- pp Kernel.backtrace_includes?( :non_existing_function )
77
+ pp Kernel.backtrace_includes?( :yet_another_test )
64
78
  pp Kernel.backtrace_includes?( Test2 )
65
79
  pp Kernel.backtrace_includes?( self )
66
- pp Kernel.backtrace_includes?( :non_existing_function, Test2, self )
80
+ pp Kernel.backtrace_includes?( :yet_another_test, Test2, self )
67
81
  end
68
-
82
+
69
83
  end
70
84
 
71
85
  $test = Test.new
72
86
  $test.test
87
+
88
+ puts 'Finished Test.'
89
+ exit
73
90
 
74
91
  == EXAMPLE's OUTPUT:
75
92
 
76
- Sender was: #<Test:0x0000010101ef18>
77
- Caller was: and_another_test_in_another_object
78
- [{:object=>#<Test:0x0000010101ef18>, :method=>:another_test},
79
- {:object=>#<Test:0x0000010101ef18>, :method=>:test},
80
- {:object=>main}]
81
- [{:object=>#<Test:0x0000010101ef18>, :method=>:another_test},
82
- {:object=>#<Test:0x0000010101ef18>, :method=>:test}]
93
+ In method <Test>:initialize
94
+ Sender was: main
95
+ Caller was: <main>
96
+ In <Test>:test
97
+ In method <Test>:another_test
98
+ In method <Test2>:initialize
99
+ Sender was: #<Test:0x0000010180ddf8>
100
+ Caller was: another_test
101
+ In method <Test2>:and_another_test_in_another_object
102
+ #<Test2:0x0000010180b158>
103
+ Sender was: #<Test:0x0000010180ddf8>
104
+ Caller was: another_test
105
+ [{:object=>#<Test2:0x0000010180b158>,
106
+ :file=>"sender_test.rb",
107
+ :line=>39,
108
+ :method=>"and_another_test_in_another_object"},
109
+ {:object=>#<Test:0x0000010180ddf8>,
110
+ :file=>"sender_test.rb",
111
+ :line=>21,
112
+ :method=>"another_test"},
113
+ {:object=>#<Test:0x0000010180ddf8>,
114
+ :file=>"sender_test.rb",
115
+ :line=>15,
116
+ :method=>"test"},
117
+ {:object=>main, :file=>"sender_test.rb", :line=>56, :method=>"<main>"},
118
+ {:object=>main, :file=>"<main>", :line=>0, :method=>"<main>"}]
119
+ [{:object=>#<Test2:0x0000010180b158>,
120
+ :file=>"sender_test.rb",
121
+ :line=>40,
122
+ :method=>"and_another_test_in_another_object"},
123
+ {:object=>#<Test:0x0000010180ddf8>,
124
+ :file=>"sender_test.rb",
125
+ :line=>21,
126
+ :method=>"another_test"}]
83
127
  These should be true:
84
128
  true
85
129
  true
@@ -90,6 +134,7 @@ which allows contents of the backtrace to be queried.
90
134
  false
91
135
  false
92
136
  false
137
+ Finished Test.
93
138
 
94
139
  == LICENSE:
95
140
 
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ Hoe.spec 'sender' do
11
11
  self.spec_extras = { :extensions => ["ext/sender/extconf.rb"] }
12
12
  self.extra_dev_deps << ['rake-compiler', '>= 0']
13
13
 
14
- self.version="1.3"
14
+ self.version=File.open( 'VERSION.rdoc' ).readline
15
15
 
16
16
  Rake::ExtensionTask.new( 'sender', spec ) do |ext|
17
17
  ext.lib_dir = File.join('lib', 'sender')
data/VERSION.rdoc ADDED
@@ -0,0 +1 @@
1
+ 1.4
@@ -2,9 +2,9 @@
2
2
  #include "RPSender_internal.h"
3
3
  #include "RubySourceSupport.h"
4
4
 
5
- /*************************
6
- * framePriorToCurrent *
7
- ************************/
5
+ /******************
6
+ * framePriorTo *
7
+ *****************/
8
8
 
9
9
  rb_control_frame_t* RPRuby_internal_framePriorTo( rb_control_frame_t* c_control_frame ) {
10
10
 
@@ -35,32 +35,3 @@ rb_control_frame_t* RPRuby_internal_framePriorTo( rb_control_frame_t* c_control_
35
35
 
36
36
  }
37
37
 
38
- /**********************************
39
- * backtraceHashForControlFrame *
40
- *********************************/
41
-
42
- VALUE RPSender_internal_backtraceHashForControlFrame( rb_control_frame_t* c_control_frame ) {
43
-
44
- // create new hash for this frame
45
- VALUE rb_frame_hash = rb_hash_new();
46
-
47
- // get object and set in hash
48
- VALUE rb_object_for_frame = c_control_frame->self;
49
- // if we get nil we're done with our backtrace
50
- rb_hash_aset( rb_frame_hash,
51
- ID2SYM( rb_intern( "object" ) ),
52
- rb_object_for_frame );
53
-
54
- // get method and set in hash
55
- ID c_frame_function_id = frame_func_id( c_control_frame );
56
- // main has no method name
57
- if ( c_frame_function_id != 0) {
58
- VALUE rb_method_for_frame = ID2SYM( c_frame_function_id );
59
- rb_hash_aset( rb_frame_hash,
60
- ID2SYM( rb_intern( "method" ) ),
61
- rb_method_for_frame );
62
-
63
- }
64
-
65
- return rb_frame_hash;
66
- }
@@ -5,6 +5,6 @@
5
5
  #include "eval_intern.h"
6
6
 
7
7
  rb_control_frame_t* RPRuby_internal_framePriorTo( rb_control_frame_t* control_frame );
8
- VALUE RPSender_internal_backtraceHashForControlFrame( rb_control_frame_t* c_control_frame );
8
+ VALUE RPSender_internal_backtraceHashForControlFrame( const rb_control_frame_t* c_top_of_control_frame );
9
9
 
10
10
  #endif
@@ -1,6 +1,11 @@
1
1
 
2
2
  #include "RubySourceSupport.h"
3
3
 
4
+ #include "rb_Kernel.h"
5
+ #include "RPSender_internal.h"
6
+
7
+ #include "iseq.h"
8
+
4
9
  // Taken from eval.c in Ruby source
5
10
  // No header, so easiest way to integrate was to copy the code and make my own header.
6
11
  // Previously declared static; otherwise unchanged
@@ -38,3 +43,33 @@ ID rb_frame_caller(void)
38
43
  return frame_func_id(prev_cfp);
39
44
  }
40
45
 
46
+ int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
47
+ {
48
+ int line_no = 0;
49
+ const rb_iseq_t *iseq = cfp->iseq;
50
+
51
+ if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
52
+ rb_num_t i;
53
+ size_t pos = cfp->pc - cfp->iseq->iseq_encoded;
54
+
55
+ for (i = 0; i < iseq->insn_info_size; i++) {
56
+ if (iseq->insn_info_table[i].position == pos) {
57
+ if (i == 0) goto found;
58
+ line_no = iseq->insn_info_table[i - 1].line_no;
59
+ goto found;
60
+ }
61
+ }
62
+ line_no = iseq->insn_info_table[i - 1].line_no;
63
+ }
64
+ found:
65
+ return line_no;
66
+ }
67
+
68
+
69
+
70
+
71
+
72
+
73
+
74
+
75
+
@@ -7,5 +7,6 @@
7
7
 
8
8
  ID frame_func_id( rb_control_frame_t *cfp );
9
9
  ID rb_frame_caller(void);
10
+ int rb_vm_get_sourceline(const rb_control_frame_t *cfp);
10
11
 
11
12
  #endif
@@ -1,5 +1,6 @@
1
1
 
2
2
  #include "rb_Global.h"
3
+ #include "rb_Kernel.h"
3
4
 
4
5
  // Internals from ruby that aren't included in the ruby lib
5
6
  #include "RubySourceSupport.h"
@@ -34,17 +35,31 @@ void Init_senderGlobal() {
34
35
  * Return object sending message to receiver.
35
36
  */
36
37
  VALUE rb_RPRuby_Sender___sender__() {
38
+
39
+ // we want 3 levels of backtrace:
40
+ // 1: current call to __method__ (__method__ in context)
41
+ // 2: the frame we want, unless it is :new (call to context: __sender__)
42
+ // 3: the frame we want in the case #2 is :new
43
+ VALUE rb_backtrace_limit = INT2FIX( 3 );
44
+
45
+ VALUE rb_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 1,
46
+ & rb_backtrace_limit,
47
+ rb_mKernel );
37
48
 
38
- // get the frame prior to current frame
39
- rb_control_frame_t* c_sending_frame = RPRuby_internal_framePriorTo( NULL );
49
+ VALUE rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, 1 );
50
+
51
+ VALUE rb_caller = rb_hash_aref( rb_backtrace_frame_hash,
52
+ ID2SYM( rb_intern( "method" ) ) );
40
53
 
41
- // make sure the current frame wasn't the first frame or return nil
42
- if ( c_sending_frame == NULL ) {
43
- return Qnil;
54
+ if ( rb_caller == ID2SYM( rb_intern( "new" ) ) ) {
55
+ rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, 2 );
44
56
  }
45
57
 
58
+ VALUE rb_sender = rb_hash_aref( rb_backtrace_frame_hash,
59
+ ID2SYM( rb_intern( "object" ) ) );
60
+
46
61
  // assuming we have a previous frame, return its rb_self (our current receiver's sender)
47
- return c_sending_frame->self;
62
+ return rb_sender;
48
63
  }
49
64
 
50
65
  /***************
@@ -59,14 +74,30 @@ VALUE rb_RPRuby_Sender___sender__() {
59
74
  */
60
75
  VALUE rb_RPRuby_Sender___caller__() {
61
76
 
62
- // get the frame prior to current frame
63
- rb_control_frame_t* c_sending_frame = RPRuby_internal_framePriorTo( NULL );
77
+
78
+ // we want 3 levels of backtrace:
79
+ // 1: current call to __method__ (__method__ in context)
80
+ // 2: the frame we want, unless it is :new (call to context: __sender__)
81
+ // 3: the frame we want in the case #2 is :new
82
+ VALUE rb_backtrace_limit = INT2FIX( 3 );
64
83
 
65
- // make sure the current frame wasn't the first frame or return nil
66
- if ( c_sending_frame == NULL ) {
67
- return Qnil;
84
+ VALUE rb_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 1,
85
+ & rb_backtrace_limit,
86
+ rb_mKernel );
87
+
88
+ VALUE rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, 1 );
89
+
90
+ VALUE rb_caller = rb_hash_aref( rb_backtrace_frame_hash,
91
+ ID2SYM( rb_intern( "method" ) ) );
92
+
93
+ if ( rb_caller == ID2SYM( rb_intern( "new" ) ) ) {
94
+ rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, 2 );
95
+
96
+ rb_caller = rb_hash_aref( rb_backtrace_frame_hash,
97
+ ID2SYM( rb_intern( "method" ) ) );
68
98
  }
69
99
 
70
- return ID2SYM( frame_func_id( c_sending_frame ) );
100
+ // assuming we have a previous frame, return its rb_self (our current receiver's sender)
101
+ return rb_caller;
71
102
  }
72
103
 
@@ -3,5 +3,6 @@
3
3
  #define RP_SENDER_CALLER_GLOBAL_INTERNAL
4
4
 
5
5
  rb_control_frame_t* RPRuby_internal_framePriorTo();
6
+ rb_control_instruction_t* RPRuby_internal_instructionPriorTo( rb_control_instruction_t* c_control_instruction );
6
7
 
7
8
  #endif
@@ -1,5 +1,6 @@
1
1
 
2
2
  #include "rb_Kernel.h"
3
+ #include "rb_Kernel_internal.h"
3
4
 
4
5
  #include "RPSender_internal.h"
5
6
 
@@ -28,60 +29,73 @@ void Init_senderKernel() {
28
29
 
29
30
  /*
30
31
  * call-seq:
31
- * __backtrace__( number_of_frames = nil ) -> [ { :object => object, :method => method }, ... ]
32
+ * Kernel.backtrace( number_of_frames = nil ) -> [ { :object => object, :method => method }, ... ]
32
33
  *
33
34
  * Return array of hashes with object and method frame information for backtrace.
34
35
  * Specifying number_of_frames will cause only the last number_of_frames to be returned.
36
+ * Kernel.backtrace returns all frames including the current context (__method__/__callee__).
35
37
  */
36
38
  VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
37
39
  VALUE* args,
38
40
  VALUE rb_self ) {
39
-
40
- // create return array
41
- VALUE rb_return_array = rb_ary_new();
42
-
43
- // for each previous frame
44
- rb_control_frame_t* c_control_frame = NULL;
45
- int c_stack_level = 0;
46
- int c_max_stack_level = 0;
41
+
42
+ // Get max stack level from args if it is there
43
+ int c_max_stack_level = 0;
47
44
  if ( argc ) {
48
45
  c_max_stack_level = FIX2INT( args[ 0 ] );
46
+
47
+ // if max_stack_level is 0 return empty array
48
+ if ( c_max_stack_level == 0 ) {
49
+ return rb_ary_new();
50
+ }
51
+ // if max_stack_level < 0, throw error
52
+ else if ( c_max_stack_level < 0 ) {
53
+ rb_raise( rb_eArgError, RPRUBY_SENDER_ERROR_STACK_LEVEL_LESS_THAN_ZERO );
54
+ }
55
+
49
56
  }
50
- // loop while we have a prior control frame
51
- while ( ( c_control_frame = RPRuby_internal_framePriorTo( c_control_frame ) ) != NULL
52
- // and as long as we either have no stack limit specified, or until we reach the stack limit
57
+
58
+ rb_thread_t* c_thread = GET_THREAD();
59
+ // Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
60
+ rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp );
61
+
62
+ // c_top_of_control_frame describes the top edge of the stack trace
63
+ // set c_top_of_control_frame to the first frame in <main>
64
+ rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) );
65
+
66
+ VALUE rb_return_array = rb_ary_new();
67
+
68
+ int c_stack_level = 0;
69
+ // for each control frame:
70
+ while ( c_current_context_frame < c_top_of_control_frame
53
71
  && ( argc == 0
54
- || c_stack_level < c_max_stack_level ) ) {
55
-
56
- // get hash of info for this frame
57
- VALUE rb_frame_hash = RPSender_internal_backtraceHashForControlFrame( c_control_frame );
58
-
59
- if ( rb_frame_hash == Qnil ) {
60
- break;
61
- }
62
-
72
+ || c_stack_level < c_max_stack_level ) ) {
73
+
74
+ VALUE rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
75
+
63
76
  // push hash to array
64
77
  rb_ary_push( rb_return_array,
65
78
  rb_frame_hash );
66
-
67
- c_stack_level++;
68
- }
69
-
70
- // return return array
71
- return rb_return_array;
79
+
80
+ c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
81
+ c_stack_level++;
82
+ }
83
+
84
+ return rb_return_array;
72
85
  }
73
86
 
87
+
74
88
  /*****************************
75
89
  * __backtrace_includes?__ *
76
90
  ****************************/
77
91
 
78
92
  /*
79
93
  * call-seq:
80
- * __backtrace_includes?( method_or_object, ... ) -> true or false
81
- * __backtrace_includes?( number_of_frames, method_or_object, ... ) -> true or false
94
+ * Kernel.backtrace_includes?( method_or_object, ... ) -> true or false
95
+ * Kernel.backtrace_includes?( number_of_frames, method_or_object, ... ) -> true or false
82
96
  *
83
97
  * Returns whether specified methods or objects or classes are in the current backtrace context.
84
- * Backtrace begins with the prior frame, so asking if the backtrace includes the current method
98
+ * Kernel.backtrace_includes? begins with the prior frame, so asking if the backtrace includes the current method
85
99
  * will only report true if the current method is part of the earlier call chain.
86
100
  */
87
101
  VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
@@ -91,66 +105,74 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
91
105
  // create tracking array
92
106
  VALUE rb_tracking_array = rb_ary_new();
93
107
 
94
- // populate array with methods/objects
108
+ // populate tracking array with methods/objects
95
109
  int c_which_arg = 0;
96
110
  for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
97
111
  rb_ary_push( rb_tracking_array,
98
112
  args[ c_which_arg ] );
99
113
  }
114
+
115
+ rb_thread_t* c_thread = GET_THREAD();
116
+ // Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
117
+ rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) );
100
118
 
101
- // for each previous frame
102
- rb_control_frame_t* c_control_frame = NULL;
103
- while ( ( c_control_frame = RPRuby_internal_framePriorTo( c_control_frame ) ) != NULL ) {
119
+ // c_top_of_control_frame describes the top edge of the stack trace
120
+ // set c_top_of_control_frame to the first frame in <main>
121
+ rb_control_frame_t* c_top_of_control_frame = RUBY_VM_NEXT_CONTROL_FRAME( RUBY_VM_NEXT_CONTROL_FRAME( (void *)( c_thread->stack + c_thread->stack_size ) ) );
104
122
 
123
+ // for each control frame:
124
+ while ( c_current_context_frame < c_top_of_control_frame ) {
125
+
105
126
  // iterate each array member
106
127
  int c_which_member;
107
128
  for ( c_which_member = 0 ; c_which_member < RARRAY_LEN( rb_tracking_array ) ; c_which_member++ ) {
108
-
129
+
109
130
  VALUE rb_array_member = args[ c_which_member ];
110
-
131
+
111
132
  int matched = 0;
112
-
133
+
113
134
  // if rb_array_member is a class
114
135
  if ( TYPE( rb_array_member ) == T_CLASS ) {
115
136
  // if rb_array_member is the current frame's object's class
116
- if ( rb_array_member == rb_class_of( c_control_frame->self ) ) {
137
+ if ( rb_array_member == rb_class_of( c_current_context_frame->self ) ) {
117
138
  matched = 1;
118
139
  }
119
140
  }
120
141
  // if rb_array_member is a method symbol and matches our current frame's method
121
142
  else if ( TYPE( rb_array_member ) == T_SYMBOL ) {
122
-
123
- if ( rb_to_id( rb_array_member ) == frame_func_id( c_control_frame ) ) {
143
+
144
+ if ( rb_to_id( rb_array_member ) == frame_func_id( c_current_context_frame ) ) {
124
145
  matched = 1;
125
146
  }
126
147
  }
127
148
  // if rb_array_member is an object
128
149
  else if ( TYPE( rb_array_member ) == T_OBJECT ) {
129
150
  // if rb_array_member is the current frame's object (self)
130
- if ( rb_array_member == c_control_frame->self ) {
151
+ if ( rb_array_member == c_current_context_frame->self ) {
131
152
  matched = 1;
132
153
  }
133
154
  }
134
-
155
+
135
156
  // if array member exists in frame, remove from array
136
157
  if ( matched ) {
137
158
  // delete this index
138
159
  rb_ary_delete_at( rb_tracking_array,
139
160
  c_which_member );
140
-
161
+
141
162
  // decrement the loop iterator so that the increase is offset
142
163
  // this is necessary since we just removed an index and are iterating vs. the length of the array
143
164
  c_which_member--;
144
165
  }
145
166
  }
146
-
167
+
147
168
  // if array is empty, return true
148
169
  // we check here as well as at the end so we can stop iterating the backtrace if we find all our items
149
170
  if ( RARRAY_LEN( rb_tracking_array ) == 0 ) {
150
171
  return Qtrue;
151
- }
172
+ }
173
+ c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
152
174
  }
153
-
175
+
154
176
  // if we finish iterating frames and still have items in the array, return false
155
177
  if ( RARRAY_LEN( rb_tracking_array ) > 0 ) {
156
178
  return Qfalse;
@@ -160,3 +182,79 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
160
182
  return Qtrue;
161
183
  }
162
184
 
185
+ /**********************************
186
+ * backtraceHashForControlFrame *
187
+ *********************************/
188
+
189
+ VALUE rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( rb_control_frame_t** c_current_frame ) {
190
+
191
+ const char* c_method_name = NULL;
192
+ int c_sourcefile_line = 0;
193
+
194
+ // create new hash for this frame
195
+ VALUE rb_frame_hash = rb_hash_new();
196
+
197
+ VALUE rb_sourcefile_name = Qnil;
198
+ VALUE rb_sourcefile_line = Qnil;
199
+ VALUE rb_method_name = Qnil;
200
+ VALUE rb_object_for_frame = Qnil;
201
+
202
+ if ( ( *c_current_frame )->iseq != 0 ) {
203
+
204
+ if ( ( *c_current_frame )->pc != 0 ) {
205
+
206
+ rb_iseq_t *iseq = ( *c_current_frame )->iseq;
207
+
208
+ // get sourcefile name and set in hash
209
+ rb_sourcefile_name = iseq->filename;
210
+
211
+ // get sourcefile line and set in hash
212
+ c_sourcefile_line = rb_vm_get_sourceline( *c_current_frame );
213
+ rb_sourcefile_line = INT2FIX( c_sourcefile_line );
214
+
215
+ // get name of instruction sequence
216
+ rb_method_name = ID2SYM( rb_intern( StringValuePtr( iseq->name ) ) );
217
+ }
218
+ }
219
+ else if ( RUBYVM_CFUNC_FRAME_P( *c_current_frame ) ) {
220
+
221
+ // get name of method
222
+ c_method_name = rb_id2name( ( *c_current_frame )->method_id );
223
+ rb_method_name = ( c_method_name == NULL ? Qnil : ID2SYM( rb_intern( c_method_name ) ) );
224
+ }
225
+ else {
226
+ // The third possibility is that we have an iseq frame with nil params for what we want
227
+ // In that case we can simply return the next frame
228
+ *c_current_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( *c_current_frame );
229
+
230
+ // in theory this could crash because we are going forward a frame when we don't know what's there
231
+ // in practice I think we are ok, since we are only jumping forward from nil frames which should never be at the end
232
+ // at least - I don't think they should... we shall see.
233
+ //
234
+ // a fix would be to check the next frame, but that requires access to the thread or the limit cfp,
235
+ // which requires passing more context; so for now, I'm leaving it there
236
+
237
+ return rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( c_current_frame );
238
+ }
239
+
240
+ // Push values to return hash
241
+
242
+ rb_object_for_frame = ( *c_current_frame )->self;
243
+ rb_hash_aset( rb_frame_hash,
244
+ ID2SYM( rb_intern( "object" ) ),
245
+ rb_object_for_frame );
246
+
247
+ rb_hash_aset( rb_frame_hash,
248
+ ID2SYM( rb_intern( "file" ) ),
249
+ rb_sourcefile_name );
250
+
251
+ rb_hash_aset( rb_frame_hash,
252
+ ID2SYM( rb_intern( "line" ) ),
253
+ rb_sourcefile_line );
254
+
255
+ rb_hash_aset( rb_frame_hash,
256
+ ID2SYM( rb_intern( "method" ) ),
257
+ rb_method_name );
258
+
259
+ return rb_frame_hash;
260
+ }
@@ -4,11 +4,13 @@
4
4
 
5
5
  #include "ruby.h"
6
6
 
7
+ #define RPRUBY_SENDER_ERROR_STACK_LEVEL_LESS_THAN_ZERO "Maximum level for stack trace specified was less than zero."
8
+
7
9
  void Init_senderKernel();
8
10
 
9
- VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
10
- VALUE* args,
11
- VALUE rb_self );
11
+ VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
12
+ VALUE* args,
13
+ VALUE rb_self );
12
14
  VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
13
15
  VALUE* args,
14
16
  VALUE rb_self );
@@ -0,0 +1,10 @@
1
+
2
+ #ifndef RP_SENDER_KERNEL_INTERNAL
3
+ #define RP_SENDER_KERNEL_INTERNAL
4
+
5
+ #include "ruby.h"
6
+ #include "eval_intern.h"
7
+
8
+ VALUE rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( rb_control_frame_t** c_current_frame );
9
+
10
+ #endif
Binary file
data/lib/sender.rb CHANGED
@@ -2,33 +2,6 @@ require 'sender/sender'
2
2
 
3
3
  module Sender
4
4
 
5
- # VERSION is set by hoe
6
-
7
- ##############
8
- # included #
9
- ##############
10
-
11
- def self.included( module_or_class_const )
12
-
13
- # define a class method "new" on self that calls :init_sender_callbacks if it is defined
14
- module_or_class_const.class_eval do
15
-
16
- #########
17
- # new #
18
- #########
19
-
20
- def new( *args )
21
- new_self = super( *args )
22
- if self.respond_to?( :init_sender_callbacks )
23
- # :init_sender_callbacks allows callback parameters to be defined during initialization
24
- # it is called automatically when the object is created, prior to calling Object.initialize
25
- self.__send__( :init_sender_callbacks, __sender__, __caller__ )
26
- end
27
- return new_self
28
- end
29
-
30
- end
31
-
32
- end
5
+ Version = File.open( 'VERSION.rdoc' ).readline
33
6
 
34
7
  end
data/sender.gemspec CHANGED
@@ -2,18 +2,18 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{sender}
5
- s.version = "1.3"
5
+ s.version = "1.4"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Asher"]
9
- s.date = %q{2010-06-27}
9
+ s.date = %q{2010-06-29}
10
10
  s.description = %q{Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1, as well
11
11
  as providing object-oriented :backtrace supporting n-levels backward, and :backtrace_includes?,
12
12
  which allows contents of the backtrace to be queried.}
13
13
  s.email = ["asher@ridiculouspower.com"]
14
14
  s.extensions = ["ext/sender/extconf.rb"]
15
- s.extra_rdoc_files = ["Manifest.txt", "CHANGELOG.rdoc", "README.rdoc"]
16
- s.files = [".autotest", "CHANGELOG.rdoc", "Makefile", "Manifest.txt", "README.rdoc", "Rakefile", "ext/sender/RPSender_internal.c", "ext/sender/RPSender_internal.h", "ext/sender/RubySourceSupport.c", "ext/sender/RubySourceSupport.h", "ext/sender/debug.h", "ext/sender/dln.h", "ext/sender/encdb.h", "ext/sender/eval_intern.h", "ext/sender/extconf.rb", "ext/sender/gc.h", "ext/sender/id.h", "ext/sender/iseq.h", "ext/sender/main.c", "ext/sender/node.h", "ext/sender/parse.h", "ext/sender/rb_Global.c", "ext/sender/rb_Global.h", "ext/sender/rb_Global_internal.h", "ext/sender/rb_Kernel.c", "ext/sender/rb_Kernel.h", "ext/sender/regenc.h", "ext/sender/regint.h", "ext/sender/regparse.h", "ext/sender/revision.h", "ext/sender/thread_pthread.h", "ext/sender/thread_win32.h", "ext/sender/transcode_data.h", "ext/sender/transdb.h", "ext/sender/version.h", "ext/sender/vm_core.h", "ext/sender/vm_exec.h", "ext/sender/vm_insnhelper.h", "ext/sender/vm_opts.h", "lib/sender.rb", "lib/sender/sender.bundle", "sender.gemspec", "test/test_sender.rb"]
15
+ s.extra_rdoc_files = ["Manifest.txt", "CHANGELOG.rdoc", "README.rdoc", "VERSION.rdoc"]
16
+ s.files = [".autotest", "CHANGELOG.rdoc", "Makefile", "Manifest.txt", "README.rdoc", "Rakefile", "VERSION.rdoc", "ext/sender/RPSender_internal.c", "ext/sender/RPSender_internal.h", "ext/sender/RubySourceSupport.c", "ext/sender/RubySourceSupport.h", "ext/sender/debug.h", "ext/sender/dln.h", "ext/sender/encdb.h", "ext/sender/eval_intern.h", "ext/sender/extconf.rb", "ext/sender/gc.h", "ext/sender/id.h", "ext/sender/iseq.h", "ext/sender/main.c", "ext/sender/node.h", "ext/sender/parse.h", "ext/sender/rb_Global.c", "ext/sender/rb_Global.h", "ext/sender/rb_Global_internal.h", "ext/sender/rb_Kernel.c", "ext/sender/rb_Kernel.h", "ext/sender/rb_Kernel_internal.h", "ext/sender/regenc.h", "ext/sender/regint.h", "ext/sender/regparse.h", "ext/sender/revision.h", "ext/sender/thread_pthread.h", "ext/sender/thread_win32.h", "ext/sender/transcode_data.h", "ext/sender/transdb.h", "ext/sender/version.h", "ext/sender/vm_core.h", "ext/sender/vm_exec.h", "ext/sender/vm_insnhelper.h", "ext/sender/vm_opts.h", "lib/sender.rb", "lib/sender/sender.bundle", "sender.gemspec", "test/test_sender.rb"]
17
17
  s.homepage = %q{http://rubygems.org/gems/sender}
18
18
  s.rdoc_options = ["--main", "README.rdoc"]
19
19
  s.require_paths = ["lib"]
data/test/test_sender.rb CHANGED
@@ -11,4 +11,12 @@ class TestSender < Test::Unit::TestCase
11
11
  assert_equal :run, __caller__
12
12
  end
13
13
 
14
+ def test_Kernel_backtrace
15
+ # not sure how to test this
16
+ end
17
+
18
+ def test_Kernel_backtrace_includes
19
+ # not sure how to test this
20
+ end
21
+
14
22
  end
metadata CHANGED
@@ -1,12 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sender
3
3
  version: !ruby/object:Gem::Version
4
- hash: 9
4
+ hash: 7
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 3
9
- version: "1.3"
8
+ - 4
9
+ version: "1.4"
10
10
  platform: ruby
11
11
  authors:
12
12
  - Asher
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-06-27 00:00:00 -04:00
17
+ date: 2010-06-29 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -77,6 +77,7 @@ extra_rdoc_files:
77
77
  - Manifest.txt
78
78
  - CHANGELOG.rdoc
79
79
  - README.rdoc
80
+ - VERSION.rdoc
80
81
  files:
81
82
  - .autotest
82
83
  - CHANGELOG.rdoc
@@ -84,6 +85,7 @@ files:
84
85
  - Manifest.txt
85
86
  - README.rdoc
86
87
  - Rakefile
88
+ - VERSION.rdoc
87
89
  - ext/sender/RPSender_internal.c
88
90
  - ext/sender/RPSender_internal.h
89
91
  - ext/sender/RubySourceSupport.c
@@ -104,6 +106,7 @@ files:
104
106
  - ext/sender/rb_Global_internal.h
105
107
  - ext/sender/rb_Kernel.c
106
108
  - ext/sender/rb_Kernel.h
109
+ - ext/sender/rb_Kernel_internal.h
107
110
  - ext/sender/regenc.h
108
111
  - ext/sender/regint.h
109
112
  - ext/sender/regparse.h