sender 1.5.7 → 1.5.8

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,37 @@
1
+
2
+ #include "RPSender_internal.h"
3
+ #include "RubySourceSupport.h"
4
+
5
+ /******************
6
+ * framePriorTo *
7
+ *****************/
8
+
9
+ rb_control_frame_t* RPRuby_internal_framePriorTo( rb_control_frame_t* c_control_frame ) {
10
+
11
+ rb_thread_t* c_thread = GET_THREAD();
12
+ rb_control_frame_t* c_prior_control_frame = NULL;
13
+ // get the current frame pointer
14
+ if ( c_control_frame == NULL ) {
15
+ c_control_frame = c_thread->cfp;
16
+ }
17
+
18
+ if ( ( c_prior_control_frame = rb_vm_get_ruby_level_next_cfp( c_thread, c_control_frame ) ) != 0) {
19
+
20
+ // not sure why we have to call this a second time after it was called at the end of rb_vm_get_ruby_level_next_cfp,
21
+ // but for some reason it seems to be necessary
22
+ c_prior_control_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_prior_control_frame );
23
+
24
+ }
25
+ else {
26
+ c_prior_control_frame = NULL;
27
+ }
28
+
29
+ // if we have a nil object we've passed main, we're done
30
+ if ( c_prior_control_frame->self == Qnil ) {
31
+ return NULL;
32
+ }
33
+
34
+ return c_prior_control_frame;
35
+
36
+ }
37
+
@@ -0,0 +1,15 @@
1
+ #ifndef RP_SENDER_INTERNAL
2
+ #define RP_SENDER_INTERNAL
3
+
4
+ #include "ruby.h"
5
+ #include "eval_intern.h"
6
+
7
+ typedef enum BOOL_e {
8
+ FALSE,
9
+ TRUE
10
+ } BOOL;
11
+
12
+ rb_control_frame_t* RPRuby_internal_framePriorTo( rb_control_frame_t* control_frame );
13
+ VALUE RPSender_internal_backtraceHashForControlFrame( const rb_control_frame_t* c_top_of_control_frame );
14
+
15
+ #endif
@@ -0,0 +1,47 @@
1
+
2
+ #include "RubySourceSupport.h"
3
+
4
+ #include "rb_Kernel.h"
5
+ #include "RPSender_internal.h"
6
+
7
+ #include "iseq.h"
8
+
9
+ // Taken from eval.c in Ruby source
10
+ // No header, so easiest way to integrate was to copy the code and make my own header.
11
+ // Previously declared static; otherwise unchanged
12
+
13
+ int rb_vm_get_sourceline(const rb_control_frame_t *cfp)
14
+ {
15
+ int line_no = 0;
16
+ const rb_iseq_t *iseq = cfp->iseq;
17
+
18
+ if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
19
+ rb_num_t i;
20
+ size_t pos = cfp->pc - cfp->iseq->iseq_encoded;
21
+
22
+ for (i = 0; i < iseq->insn_info_size; i++) {
23
+ if (iseq->insn_info_table[i].position == pos) {
24
+ if (i == 0) goto found;
25
+ line_no = iseq->insn_info_table[i - 1].line_no;
26
+ goto found;
27
+ }
28
+ }
29
+ line_no = iseq->insn_info_table[i - 1].line_no;
30
+ }
31
+ found:
32
+ return line_no;
33
+ }
34
+
35
+ struct enumerator* enumerator_ptr(VALUE obj)
36
+ {
37
+ struct enumerator *ptr;
38
+
39
+ Data_Get_Struct(obj, struct enumerator, ptr);
40
+
41
+ // modified because a call to a local version of enumerator_mark won't verify
42
+
43
+ if (!ptr || ptr->obj == Qundef) {
44
+ rb_raise(rb_eArgError, "uninitialized enumerator");
45
+ }
46
+ return ptr;
47
+ }
@@ -0,0 +1,77 @@
1
+ #ifndef RP_SENDER_RUBY_SOURCE_SUPPORT
2
+ #define RP_SENDER_RUBY_SOURCE_SUPPORT
3
+
4
+ #include "ruby.h"
5
+ #include "eval_intern.h"
6
+ #include "version.h"
7
+ #if RUBY_PATCHLEVEL == -1
8
+ #include "vm_core.h"
9
+ #endif
10
+ #include "method.h"
11
+
12
+ #define MAX_POSBUF 128
13
+
14
+ enum context_type {
15
+ CONTINUATION_CONTEXT = 0,
16
+ FIBER_CONTEXT = 1,
17
+ ROOT_FIBER_CONTEXT = 2
18
+ };
19
+
20
+ typedef struct rb_context_struct {
21
+ enum context_type type;
22
+ VALUE self;
23
+ int argc;
24
+ VALUE value;
25
+ VALUE *vm_stack;
26
+ #ifdef CAPTURE_JUST_VALID_VM_STACK
27
+ int vm_stack_slen; /* length of stack (head of th->stack) */
28
+ int vm_stack_clen; /* length of control frames (tail of th->stack) */
29
+ #endif
30
+ VALUE *machine_stack;
31
+ VALUE *machine_stack_src;
32
+ #ifdef __ia64
33
+ VALUE *machine_register_stack;
34
+ VALUE *machine_register_stack_src;
35
+ int machine_register_stack_size;
36
+ #endif
37
+ rb_thread_t saved_thread;
38
+ rb_jmpbuf_t jmpbuf;
39
+ int machine_stack_size;
40
+ } rb_context_t;
41
+
42
+ enum fiber_status {
43
+ CREATED,
44
+ RUNNING,
45
+ TERMINATED
46
+ };
47
+
48
+ typedef struct rb_fiber_struct {
49
+ rb_context_t cont;
50
+ VALUE prev;
51
+ enum fiber_status status;
52
+ struct rb_fiber_struct *prev_fiber;
53
+ struct rb_fiber_struct *next_fiber;
54
+ } rb_fiber_t;
55
+
56
+ struct enumerator {
57
+ VALUE obj;
58
+ ID meth;
59
+ VALUE args;
60
+ VALUE fib;
61
+ VALUE dst;
62
+ VALUE no_next;
63
+ };
64
+
65
+ #define GetFiberPtr(obj, ptr) do {\
66
+ ptr = (rb_fiber_t*)DATA_PTR(obj);\
67
+ if (!ptr) rb_raise(rb_eFiberError, "uninitialized fiber");\
68
+ } while(0)
69
+
70
+
71
+ ID frame_func_id( rb_control_frame_t *cfp );
72
+ ID rb_frame_caller(void);
73
+ int rb_vm_get_sourceline(const rb_control_frame_t *cfp);
74
+ void control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp);
75
+ struct enumerator* enumerator_ptr(VALUE obj);
76
+
77
+ #endif
@@ -0,0 +1,151 @@
1
+
2
+ #include "rb_Global.h"
3
+ #include "rb_Kernel.h"
4
+
5
+ // Internals from ruby that aren't included in the ruby lib
6
+ #include "RubySourceSupport.h"
7
+
8
+ #include "eval_intern.h"
9
+
10
+ /***********
11
+ * Global *
12
+ ***********/
13
+
14
+ void Init_senderGlobal() {
15
+
16
+ rb_define_global_function( "__sender__", rb_RPRuby_Sender___sender__, 0 );
17
+ rb_define_global_function( "__caller__", rb_RPRuby_Sender___caller__, 0 );
18
+
19
+ }
20
+
21
+ /***************************************************************************************************************************************************************
22
+ ****************************************************************************************************************************************************************
23
+ Ruby Global Methods
24
+ ****************************************************************************************************************************************************************
25
+ ***************************************************************************************************************************************************************/
26
+
27
+ /***************
28
+ * __sender__ *
29
+ ***************/
30
+
31
+ /*
32
+ * call-seq:
33
+ * __sender__ -> object
34
+ *
35
+ * Return object sending message to receiver.
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 );
48
+
49
+ int c_backtrace_index = 1;
50
+
51
+ VALUE rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index );
52
+
53
+ VALUE rb_caller = rb_hash_aref( rb_backtrace_frame_hash,
54
+ ID2SYM( rb_intern( "method" ) ) );
55
+
56
+ // if we get :initialize as our caller and our __method__ is :initialize, we need to go up the chain
57
+ // until our caller is no longer :initialize or :new
58
+ while ( rb_caller == ID2SYM( rb_intern( "initialize" ) ) ) {
59
+ c_backtrace_index++;
60
+ rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index );
61
+ rb_caller = rb_hash_aref( rb_backtrace_frame_hash,
62
+ ID2SYM( rb_intern( "method" ) ) );
63
+
64
+ // we have one parent past our current method; if that is also :initialize, get the whole backtrace
65
+ if ( c_backtrace_index == 2 ) {
66
+ rb_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 0, NULL, rb_mKernel );
67
+ }
68
+ }
69
+
70
+ // if we get "new" as our caller we need to get the next level, as we are in :initialize
71
+ // and want to know what called :new
72
+ //
73
+ // since we might have had to go up the chain from :initialize through parents before getting here we
74
+ // want to use a separate if statement
75
+ if ( rb_caller == ID2SYM( rb_intern( "new" ) ) ) {
76
+ c_backtrace_index++;
77
+ rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index );
78
+ }
79
+
80
+ VALUE rb_sender = rb_hash_aref( rb_backtrace_frame_hash,
81
+ ID2SYM( rb_intern( "object" ) ) );
82
+
83
+ // assuming we have a previous frame, return its rb_self (our current receiver's sender)
84
+ return rb_sender;
85
+ }
86
+
87
+ /***************
88
+ * __caller__ *
89
+ ***************/
90
+
91
+ /*
92
+ * call-seq:
93
+ * __caller__ -> object
94
+ *
95
+ * Return method sending message to receiver.
96
+ */
97
+ VALUE rb_RPRuby_Sender___caller__() {
98
+
99
+
100
+ // we want 3 levels of backtrace:
101
+ // 1: current call to __method__ (__method__ in context)
102
+ // 2: the frame we want, unless it is :new (call to context: __sender__)
103
+ // 3: the frame we want in the case #2 is :new
104
+ VALUE rb_backtrace_limit = INT2FIX( 3 );
105
+
106
+ VALUE rb_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 1,
107
+ & rb_backtrace_limit,
108
+ rb_mKernel );
109
+
110
+ int c_backtrace_index = 1;
111
+
112
+ VALUE rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index );
113
+
114
+ VALUE rb_caller = rb_hash_aref( rb_backtrace_frame_hash,
115
+ ID2SYM( rb_intern( "method" ) ) );
116
+
117
+ // we want to compare our caller as we go up the chain to our first caller to deal with super methods
118
+ // we have a symbol so no cloning is necessary (or appropriate)
119
+ VALUE rb_first_caller = rb_hash_aref( rb_ary_entry( rb_backtrace_array, 0 ),
120
+ ID2SYM( rb_intern( "method" ) ) );
121
+
122
+ // if we get :initialize as our caller and our __method__ is :initialize, we need to go up the chain
123
+ // until our caller is no longer :initialize or :new
124
+ while ( rb_caller == rb_first_caller ) {
125
+ c_backtrace_index++;
126
+ rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index );
127
+ rb_caller = rb_hash_aref( rb_backtrace_frame_hash,
128
+ ID2SYM( rb_intern( "method" ) ) );
129
+
130
+ // we have one parent past our current method; if that is also :initialize, get the whole backtrace
131
+ if ( c_backtrace_index == 2 ) {
132
+ rb_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 0, NULL, rb_mKernel );
133
+ }
134
+ }
135
+
136
+ // if we get "new" as our caller we need to get the next level, as we are in :initialize
137
+ // and want to know what called :new
138
+ //
139
+ // since we might have had to go up the chain from :initialize through parents before getting here we
140
+ // want to use a separate if statement
141
+ if ( rb_caller == ID2SYM( rb_intern( "new" ) ) ) {
142
+ c_backtrace_index++;
143
+ rb_backtrace_frame_hash = rb_ary_entry( rb_backtrace_array, c_backtrace_index );
144
+ rb_caller = rb_hash_aref( rb_backtrace_frame_hash,
145
+ ID2SYM( rb_intern( "method" ) ) );
146
+ }
147
+
148
+ // assuming we have a previous frame, return its rb_self (our current receiver's sender)
149
+ return rb_caller;
150
+ }
151
+
@@ -0,0 +1,11 @@
1
+ #ifndef RP_SENDER_GLOBAL
2
+ #define RP_SENDER_GLOBAL
3
+
4
+ #include "RPSender_internal.h"
5
+
6
+ void Init_senderGlobal();
7
+
8
+ VALUE rb_RPRuby_Sender___sender__();
9
+ VALUE rb_RPRuby_Sender___caller__();
10
+
11
+ #endif
@@ -0,0 +1,8 @@
1
+
2
+ #ifndef RP_SENDER_CALLER_GLOBAL_INTERNAL
3
+ #define RP_SENDER_CALLER_GLOBAL_INTERNAL
4
+
5
+ rb_control_frame_t* RPRuby_internal_framePriorTo();
6
+ rb_control_instruction_t* RPRuby_internal_instructionPriorTo( rb_control_instruction_t* c_control_instruction );
7
+
8
+ #endif
@@ -0,0 +1,683 @@
1
+
2
+ #include "rb_Kernel.h"
3
+ #include "rb_Kernel_internal.h"
4
+
5
+ #include "RPSender_internal.h"
6
+
7
+ #include "RubySourceSupport.h"
8
+
9
+ /***********
10
+ * Kernel *
11
+ ***********/
12
+
13
+ void Init_senderKernel() {
14
+
15
+ rb_define_singleton_method( rb_mKernel, "backtrace", rb_RPRuby_Sender_Kernel_backtrace, -1 );
16
+ rb_define_singleton_method( rb_mKernel, "each_backtrace_frame", rb_RPRuby_Sender_Kernel_each_backtrace_frame, -1 );
17
+ rb_define_singleton_method( rb_mKernel, "backtrace_includes?", rb_RPRuby_Sender_Kernel_backtrace_includes, -1 );
18
+ rb_define_singleton_method( rb_mKernel, "backtrace_includes_one_of?", rb_RPRuby_Sender_Kernel_backtrace_includes_one_of, -1 );
19
+ rb_define_singleton_method( rb_mKernel, "backtrace_frame_with", rb_RPRuby_Sender_Kernel_backtrace_frame_with, -1 );
20
+ rb_define_singleton_method( rb_mKernel, "backtrace_frames_with", rb_RPRuby_Sender_Kernel_backtrace_frames_with, -1 );
21
+
22
+
23
+ }
24
+
25
+ static VALUE rb_eFiberError;
26
+
27
+ #define RPRUBY_SENDER_ERROR_NO_ENUMERATORS "Enumerators not currently enabled due to difficulty with Fiber support."
28
+
29
+ /***************************************************************************************************************************************************************
30
+ ****************************************************************************************************************************************************************
31
+ Ruby Kernel Methods
32
+ ****************************************************************************************************************************************************************
33
+ ***************************************************************************************************************************************************************/
34
+
35
+ /**********************
36
+ * Kernel.backtrace *
37
+ *********************/
38
+
39
+ /*
40
+ * call-seq:
41
+ * Kernel.backtrace( number_of_frames = nil ) -> [ { :object => object, :method => method }, ... ]
42
+ *
43
+ * Return array of hashes with object and method frame information for backtrace.
44
+ * Specifying number_of_frames will cause only the last number_of_frames to be returned.
45
+ * Kernel.backtrace returns all frames including the current context (__method__/__callee__).
46
+ */
47
+ VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
48
+ VALUE* args,
49
+ VALUE rb_self ) {
50
+
51
+ // Get max stack level from args if it is there
52
+ int c_max_stack_level = 0;
53
+ if ( argc ) {
54
+ c_max_stack_level = FIX2INT( args[ 0 ] );
55
+
56
+ // if max_stack_level is 0 return empty array
57
+ if ( c_max_stack_level == 0 ) {
58
+ return rb_ary_new();
59
+ }
60
+ // if max_stack_level < 0, throw error
61
+ else if ( c_max_stack_level < 0 ) {
62
+ rb_raise( rb_eArgError, RPRUBY_SENDER_ERROR_STACK_LEVEL_LESS_THAN_ZERO );
63
+ }
64
+
65
+ }
66
+
67
+ rb_thread_t* c_thread = GET_THREAD();
68
+ // Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
69
+ rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp );
70
+
71
+ // c_top_of_control_frame describes the top edge of the stack trace
72
+ // set c_top_of_control_frame to the first frame in <main>
73
+ 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 ) ) );
74
+
75
+ VALUE rb_return_array = rb_ary_new();
76
+
77
+ int c_stack_level = 0;
78
+ // for each control frame:
79
+ while ( c_current_context_frame < c_top_of_control_frame
80
+ && ( argc == 0
81
+ || c_stack_level < c_max_stack_level ) ) {
82
+
83
+ VALUE rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
84
+
85
+ if ( rb_frame_hash == Qnil ) {
86
+ break;
87
+ }
88
+
89
+ // push hash to array
90
+ rb_ary_push( rb_return_array,
91
+ rb_frame_hash );
92
+
93
+ c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
94
+ c_stack_level++;
95
+ }
96
+
97
+ return rb_return_array;
98
+ }
99
+
100
+ /*********************************
101
+ * Kernel.each_backtrace_frame *
102
+ ********************************/
103
+
104
+ /*
105
+ * call-seq:
106
+ * Kernel.each_backtrace_frame( & block )
107
+ *
108
+ * Return array of hashes with object and method frame information for backtrace.
109
+ * Specifying number_of_frames will cause only the last number_of_frames to be returned.
110
+ * Kernel.backtrace returns all frames including the current context (__method__/__callee__).
111
+ */
112
+ VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc,
113
+ VALUE* args,
114
+ VALUE rb_self ) {
115
+
116
+ rb_thread_t* c_thread = GET_THREAD();
117
+ // Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
118
+ rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) );
119
+
120
+ // c_top_of_control_frame describes the top edge of the stack trace
121
+ // set c_top_of_control_frame to the first frame in <main>
122
+ 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 ) ) );
123
+
124
+ VALUE rb_stored_backtrace_array = Qnil;
125
+
126
+ // if we were passed a stored backtrace array, use it
127
+ if ( argc == 1
128
+ && TYPE( args[ 0 ] ) == T_ARRAY ) {
129
+ rb_stored_backtrace_array = args[ 0 ];
130
+ }
131
+
132
+ // for each control frame:
133
+ while ( c_current_context_frame < c_top_of_control_frame ) {
134
+
135
+ VALUE rb_frame_hash;
136
+ // if we are using a stored backtrace we don't need to ask for a new hash
137
+ if ( rb_stored_backtrace_array == Qnil ) {
138
+ rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
139
+ }
140
+ else {
141
+ rb_frame_hash = rb_ary_shift( rb_stored_backtrace_array );
142
+ }
143
+
144
+ if ( rb_frame_hash == Qnil ) {
145
+ break;
146
+ }
147
+
148
+ // if we try to iterate using an Enumerator we will lose our context
149
+ if ( ! rb_block_given_p() ) {
150
+
151
+ // we solve this by assuming that the desired context is the moment when each_backtrace_frame is called
152
+ // this allows us to store the backtrace and iterate it as we want
153
+ // the only downside is that we have to get the entire backtrace first in order to store it
154
+ rb_stored_backtrace_array = rb_RPRuby_Sender_Kernel_backtrace( 0,
155
+ NULL,
156
+ rb_self );
157
+
158
+ RETURN_ENUMERATOR( rb_self, 1, & rb_stored_backtrace_array );
159
+ }
160
+
161
+ // otherwise, yield the block
162
+ rb_yield( rb_frame_hash );
163
+
164
+ // only move the frame if we are not using a stored backtrace
165
+ if ( rb_stored_backtrace_array == Qnil ) {
166
+ c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
167
+ }
168
+ }
169
+
170
+ return Qnil;
171
+ }
172
+
173
+ /********************************
174
+ * Kernel.backtrace_includes? *
175
+ *******************************/
176
+
177
+ /*
178
+ * call-seq:
179
+ * Kernel.backtrace_includes?( method_or_object, ... ) -> true or false
180
+ * Kernel.backtrace_includes?( number_of_frames, method_or_object, ... ) -> true or false
181
+ *
182
+ * Returns whether specified methods or objects or classes are in the current backtrace context.
183
+ * Kernel.backtrace_includes? begins with the prior frame, so asking if the backtrace includes the current method
184
+ * will only report true if the current method is part of the earlier call chain.
185
+ */
186
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
187
+ VALUE* args,
188
+ VALUE rb_self ) {
189
+
190
+ // this function is also used for
191
+ // * backtrace_includes_one_of?
192
+ // * backtrace_includes_frame?
193
+ // * backtrace_includes_one_of_frames?
194
+
195
+ // create tracking array
196
+ VALUE rb_tracking_array = rb_ary_new();
197
+
198
+ // populate tracking array with methods/objects
199
+ // optional - if first arg is Qtrue, we are looking for one of the args instead of all of the args
200
+ int c_which_arg = 0;
201
+ BOOL c_requires_all_items = TRUE;
202
+ if ( args[ 0 ] == Qnil
203
+ || ( argc > 1
204
+ && args[ 1 ] == Qnil ) ) {
205
+ c_which_arg++;
206
+ c_requires_all_items = FALSE;
207
+ }
208
+ BOOL c_return_frame = FALSE;
209
+ if ( args[ 0 ] == Qfalse
210
+ || ( argc > 1
211
+ && args[ 1 ] == Qfalse ) ) {
212
+ c_which_arg++;
213
+ c_return_frame = TRUE;
214
+ }
215
+ BOOL c_return_all_frames = FALSE;
216
+ if ( args[ 0 ] == Qtrue
217
+ || ( argc > 1
218
+ && args[ 1 ] == Qtrue ) ) {
219
+ c_which_arg++;
220
+ c_return_all_frames = TRUE;
221
+ }
222
+ int c_args_offset = c_which_arg;
223
+ for ( ; c_which_arg < argc ; c_which_arg++ ) {
224
+ rb_ary_push( rb_tracking_array,
225
+ args[ c_which_arg ] );
226
+ }
227
+
228
+ rb_thread_t* c_thread = GET_THREAD();
229
+ // Get the current frame - we're doing a backtrace, so our current working frame to start is the first previous thread
230
+ rb_control_frame_t* c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( RUBY_VM_PREVIOUS_CONTROL_FRAME( c_thread->cfp ) );
231
+
232
+ // c_top_of_control_frame describes the top edge of the stack trace
233
+ // set c_top_of_control_frame to the first frame in <main>
234
+ 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 ) ) );
235
+
236
+ VALUE rb_test_index_array = rb_ary_new();
237
+ // :object
238
+ // instance or class
239
+ rb_ary_push( rb_test_index_array,
240
+ ID2SYM( rb_intern( "object" ) ) );
241
+ // :method
242
+ rb_ary_push( rb_test_index_array,
243
+ ID2SYM( rb_intern( "method" ) ) );
244
+ // :file
245
+ rb_ary_push( rb_test_index_array,
246
+ ID2SYM( rb_intern( "file" ) ) );
247
+ // :line
248
+ rb_ary_push( rb_test_index_array,
249
+ ID2SYM( rb_intern( "line" ) ) );
250
+
251
+ // only used if c_return_all_frames == TRUE
252
+ VALUE rb_frame_hashes_array = Qnil;
253
+ if ( c_return_all_frames == TRUE ) {
254
+ rb_frame_hashes_array = rb_ary_new();
255
+ }
256
+
257
+ VALUE rb_frame_hash = Qnil;
258
+
259
+ // for each control frame:
260
+ while ( c_current_context_frame < c_top_of_control_frame ) {
261
+
262
+ // iterate each array member
263
+ int c_which_member;
264
+ for ( c_which_member = 0 ; c_which_member < RARRAY_LEN( rb_tracking_array ) ; c_which_member++ ) {
265
+
266
+ VALUE rb_this_arg = args[ c_which_member + c_args_offset ];
267
+
268
+ BOOL matched = FALSE;
269
+
270
+ rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
271
+
272
+ // if we have a hash we are testing multiple items in a frame
273
+ if ( TYPE( rb_this_arg ) == T_HASH ) {
274
+
275
+ VALUE rb_frame_test_array = rb_obj_clone( rb_test_index_array );
276
+
277
+ // for each element that we could test for
278
+ int c_which_index;
279
+ int c_skipped_index_count = 0;
280
+ for ( c_which_index = 0 ; c_which_index < RARRAY_LEN( rb_frame_test_array ) ; c_which_index++ ) {
281
+
282
+ VALUE rb_this_index = RARRAY_PTR( rb_frame_test_array )[ c_which_index ];
283
+
284
+ // see if our requested test hash includes the potential test element
285
+ if ( rb_hash_lookup( rb_this_arg,
286
+ rb_this_index ) != Qnil ) {
287
+
288
+ VALUE rb_required_element = rb_hash_aref( rb_this_arg,
289
+ rb_this_index );
290
+ VALUE rb_frame_element = rb_hash_aref( rb_frame_hash,
291
+ rb_this_index );
292
+
293
+ // if it does, we need to see if the current frame's element matches this element
294
+ VALUE rb_required_element_klass;
295
+ if ( rb_required_element == rb_frame_element
296
+ // if we have a string, which is a filename
297
+ || ( TYPE( rb_required_element ) == T_STRING
298
+ && rb_funcall( rb_frame_element, rb_intern( "==" ), 1, rb_required_element ) == Qtrue )
299
+ // if we have a class, which is a special case for :object
300
+ || ( rb_this_index == ID2SYM( rb_intern( "class" ) )
301
+ && ( rb_required_element_klass = ( ( TYPE( rb_required_element ) == T_CLASS ) ? rb_required_element : rb_funcall( rb_required_element, rb_intern( "class" ), 0 ) ) )
302
+ && rb_required_element_klass == rb_required_element ) ) {
303
+
304
+ rb_ary_delete_at( rb_frame_test_array,
305
+ c_which_index );
306
+ c_which_index--;
307
+ }
308
+ }
309
+ else {
310
+ c_skipped_index_count++;
311
+ }
312
+
313
+ if ( RARRAY_LEN( rb_frame_test_array ) == c_skipped_index_count ) {
314
+ if ( c_return_frame == TRUE ) {
315
+ return rb_frame_hash;
316
+ }
317
+ else if ( c_return_all_frames == TRUE ) {
318
+ rb_ary_push( rb_frame_hashes_array,
319
+ rb_frame_hash );
320
+ }
321
+ else {
322
+ return Qtrue;
323
+ }
324
+ }
325
+ }
326
+ }
327
+ else {
328
+
329
+ // :object => <class:instance>
330
+ if ( TYPE( rb_this_arg ) == T_OBJECT ) {
331
+
332
+ if ( rb_hash_aref( rb_frame_hash,
333
+ ID2SYM( rb_intern( "object" ) ) ) == rb_this_arg ) {
334
+ matched = TRUE;
335
+ }
336
+ }
337
+ // :object => <class>
338
+ else if ( TYPE( rb_this_arg ) == T_CLASS ) {
339
+
340
+ VALUE rb_frame_object = rb_hash_aref( rb_frame_hash,
341
+ ID2SYM( rb_intern( "object" ) ) );
342
+ VALUE rb_frame_object_klass = TYPE( rb_frame_object ) == T_CLASS ? rb_frame_object : rb_funcall( rb_frame_object, rb_intern( "class" ), 0 );
343
+ if ( rb_frame_object_klass == rb_this_arg ) {
344
+ matched = TRUE;
345
+ }
346
+ }
347
+ // :method => :method
348
+ else if ( TYPE( rb_this_arg ) == T_SYMBOL ) {
349
+
350
+ if ( rb_hash_aref( rb_frame_hash,
351
+ ID2SYM( rb_intern( "method" ) ) ) == rb_this_arg ) {
352
+ matched = TRUE;
353
+ }
354
+ }
355
+ // :file => "filename"
356
+ else if ( TYPE( rb_this_arg ) == T_STRING ) {
357
+ VALUE rb_filename = rb_hash_aref( rb_frame_hash,
358
+ ID2SYM( rb_intern( "file" ) ) );
359
+ VALUE rb_comparison = rb_funcall( rb_filename, rb_intern( "==" ), 1, rb_this_arg );
360
+ if ( rb_comparison == Qtrue ) {
361
+ matched = TRUE;
362
+ }
363
+ }
364
+ // :line => number
365
+ else if ( TYPE( rb_this_arg ) == T_FIXNUM ) {
366
+ if ( rb_hash_aref( rb_frame_hash,
367
+ ID2SYM( rb_intern( "line" ) ) ) == rb_this_arg ) {
368
+ matched = TRUE;
369
+ }
370
+ }
371
+
372
+ // if array member exists in frame, remove from array
373
+ if ( matched ) {
374
+ if ( c_requires_all_items == FALSE ) {
375
+ if ( c_return_frame == TRUE ) {
376
+ return rb_frame_hash;
377
+ }
378
+ else {
379
+ return Qtrue;
380
+ }
381
+
382
+ }
383
+ else {
384
+
385
+ // delete this index
386
+ rb_ary_delete_at( rb_tracking_array,
387
+ c_which_member );
388
+
389
+ // decrement the loop iterator so that the increase is offset
390
+ // this is necessary since we just removed an index and are iterating vs. the length of the array
391
+ c_which_member--;
392
+ }
393
+ }
394
+ }
395
+ }
396
+
397
+ // if array is empty, return true
398
+ // we check here as well as at the end so we can stop iterating the backtrace if we find all our items
399
+ if ( RARRAY_LEN( rb_tracking_array ) == 0 ) {
400
+ if ( c_return_frame == TRUE ) {
401
+ return rb_frame_hash;
402
+ }
403
+ else if ( c_return_all_frames == TRUE ) {
404
+ rb_ary_push( rb_frame_hashes_array,
405
+ rb_frame_hash );
406
+ return rb_frame_hashes_array;
407
+ }
408
+ else {
409
+ return Qtrue;
410
+ }
411
+ }
412
+ c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
413
+ }
414
+
415
+ if ( c_return_all_frames == TRUE
416
+ && RARRAY_LEN( rb_frame_hashes_array ) > 0 ) {
417
+ return rb_frame_hashes_array;
418
+ }
419
+ // if we finish iterating frames and still have items in the array, return false
420
+ else if ( RARRAY_LEN( rb_tracking_array ) > 0 ) {
421
+ if ( c_return_frame == TRUE ) {
422
+ return Qnil;
423
+ }
424
+ else {
425
+ return Qfalse;
426
+ }
427
+ }
428
+ // otherwise, return true
429
+ else if ( c_return_frame == TRUE ) {
430
+ return rb_frame_hash;
431
+ }
432
+ else {
433
+ return Qtrue;
434
+ }
435
+ // we don't get here
436
+ return Qnil;
437
+ }
438
+
439
+ /***************************************
440
+ * Kernel.backtrace_includes_one_of? *
441
+ **************************************/
442
+
443
+ /*
444
+ * call-seq:
445
+ * Kernel.backtrace_includes_one_of?( method_or_object, ... ) -> true or false
446
+ * Kernel.backtrace_includes_one_of?( number_of_frames, method_or_object, ... ) -> true or false
447
+ *
448
+ * Returns whether one of the specified methods or objects or classes are in the current backtrace context.
449
+ * Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
450
+ * will only report true if the current method is part of the earlier call chain.
451
+ */
452
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes_one_of( int argc,
453
+ VALUE* args,
454
+ VALUE rb_self ) {
455
+
456
+ // method implemented as special case of backtrace_includes?
457
+
458
+ // create a new array starting with Qtrue and then followed by args
459
+ VALUE c_methods_array[ argc + 1 ];
460
+ c_methods_array[ 0 ] = Qnil;
461
+ int c_which_arg;
462
+ for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
463
+ c_methods_array[ c_which_arg + 1 ] = args[ c_which_arg ];
464
+ }
465
+ return rb_RPRuby_Sender_Kernel_backtrace_includes( argc + 1,
466
+ c_methods_array,
467
+ rb_self );
468
+ }
469
+
470
+ /*********************************
471
+ * Kernel.backtrace_frame_with *
472
+ ********************************/
473
+
474
+ /*
475
+ * call-seq:
476
+ * Kernel.backtrace_frame_with( method_or_object, ... ) -> true or false
477
+ * Kernel.backtrace_frame_with( number_of_frames, method_or_object, ... ) -> true or false
478
+ *
479
+ * Returns first frame matching specifications, which work like Kernel.backtrace_includes?.
480
+ * Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
481
+ * will only report true if the current method is part of the earlier call chain.
482
+ */
483
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_frame_with( int argc,
484
+ VALUE* args,
485
+ VALUE rb_self ) {
486
+
487
+ // create a new array starting with Qtrue and then followed by args
488
+ VALUE c_methods_array[ argc + 1 ];
489
+ // Qfalse tells backtrace_includes to return frame hash instead of true/false
490
+ c_methods_array[ 0 ] = Qfalse;
491
+ int c_which_arg;
492
+ for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
493
+ c_methods_array[ c_which_arg + 1 ] = args[ c_which_arg ];
494
+ }
495
+ return rb_RPRuby_Sender_Kernel_backtrace_includes_one_of( argc + 1,
496
+ c_methods_array,
497
+ rb_self );
498
+ }
499
+
500
+ /**********************************
501
+ * Kernel.backtrace_frames_with *
502
+ *********************************/
503
+
504
+ /*
505
+ * call-seq:
506
+ * Kernel.backtrace_frames_with( method_or_object, ... ) -> true or false
507
+ * Kernel.backtrace_frames_with( number_of_frames, method_or_object, ... ) -> true or false
508
+ *
509
+ * Returns all frames matching specifications, which work like Kernel.backtrace_includes?.
510
+ * Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
511
+ * will only report true if the current method is part of the earlier call chain.
512
+ */
513
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_frames_with( int argc,
514
+ VALUE* args,
515
+ VALUE rb_self ) {
516
+
517
+
518
+ // create a new array starting with Qtrue and then followed by args
519
+ VALUE c_methods_array[ argc + 1 ];
520
+ // Qtrue tells backtrace_includes to return all frame hashes specified instead of the first
521
+ c_methods_array[ 0 ] = Qtrue;
522
+ int c_which_arg;
523
+ for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
524
+ c_methods_array[ c_which_arg + 1 ] = args[ c_which_arg ];
525
+ }
526
+ return rb_RPRuby_Sender_Kernel_backtrace_includes( argc + 1,
527
+ c_methods_array,
528
+ rb_self );
529
+ }
530
+
531
+ /***************************************************************************************************************************************************************
532
+ ****************************************************************************************************************************************************************
533
+ Internal Methods
534
+ ****************************************************************************************************************************************************************
535
+ ***************************************************************************************************************************************************************/
536
+
537
+ /**********************************
538
+ * backtraceHashForControlFrame *
539
+ *********************************/
540
+
541
+ VALUE rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( rb_control_frame_t** c_current_frame ) {
542
+
543
+ const char* c_method_name = NULL;
544
+ int c_sourcefile_line = 0;
545
+
546
+ // create new hash for this frame
547
+ VALUE rb_frame_hash = rb_hash_new();
548
+
549
+ VALUE rb_sourcefile_name = Qnil;
550
+ VALUE rb_sourcefile_line = Qnil;
551
+ VALUE rb_method_name = Qnil;
552
+ VALUE rb_object_for_frame = Qnil;
553
+
554
+ if ( ( *c_current_frame )->iseq != 0 ) {
555
+
556
+ if ( ( *c_current_frame )->pc != 0 ) {
557
+
558
+ rb_iseq_t *iseq = ( *c_current_frame )->iseq;
559
+
560
+ // get sourcefile name and set in hash
561
+ rb_sourcefile_name = iseq->filename;
562
+
563
+ // get sourcefile line and set in hash
564
+ c_sourcefile_line = rb_vm_get_sourceline( *c_current_frame );
565
+ rb_sourcefile_line = INT2FIX( c_sourcefile_line );
566
+
567
+ // get name of instruction sequence
568
+ rb_method_name = ID2SYM( rb_intern( StringValuePtr( iseq->name ) ) );
569
+ rb_object_for_frame = ( *c_current_frame )->self;
570
+ }
571
+ }
572
+ else if ( RUBYVM_CFUNC_FRAME_P( *c_current_frame ) ) {
573
+
574
+ // get name of method
575
+
576
+ #if RUBY_PATCHLEVEL >= -1
577
+ // For 1.9.2:
578
+ const rb_method_entry_t* c_method_for_frame = ( *c_current_frame )->me;
579
+ c_method_name = rb_id2name( c_method_for_frame->called_id );
580
+ #else
581
+ // For 1.9.1:
582
+ c_method_name = rb_id2name( ( *c_current_frame )->method_id );
583
+ #endif
584
+
585
+ rb_method_name = ( c_method_name == NULL ? Qnil : ID2SYM( rb_intern( c_method_name ) ) );
586
+ rb_object_for_frame = ( *c_current_frame )->self;
587
+ }
588
+ // we have to test this case - it works for blocks but there may be other cases too
589
+ else if ( ( *c_current_frame )->block_iseq != 0
590
+ && ( *c_current_frame )->pc == 0) {
591
+
592
+ // If we got here we have a fiber
593
+ // There doesn't seem to be much that we can tell about a fiber's context
594
+
595
+ VALUE rb_current_fiber = rb_fiber_current();
596
+ rb_fiber_t* c_current_fiber = NULL;
597
+
598
+ GetFiberPtr( rb_current_fiber,
599
+ c_current_fiber);
600
+
601
+ rb_context_t* c_context = & c_current_fiber->cont;
602
+
603
+ // rb_block_t* c_blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP( *c_current_frame );
604
+
605
+ rb_object_for_frame = ( *c_current_frame )->self;
606
+
607
+ // get sourcefile name and set in hash
608
+ rb_sourcefile_name = Qnil;
609
+
610
+ // get sourcefile line and set in hash
611
+ rb_sourcefile_line = Qnil;
612
+
613
+ // get name of instruction sequence
614
+ rb_method_name = rb_str_new2( "<Fiber>" );
615
+
616
+ // if we have a fiber we also include its ruby reference since we have so little other context
617
+ rb_hash_aset( rb_frame_hash,
618
+ ID2SYM( rb_intern( "fiber" ) ),
619
+ c_context->self );
620
+
621
+ // The one time that we know a fiber is in use in the Ruby base is with Enumerators
622
+ // For now we will handle that with a special case
623
+
624
+ VALUE rb_enumerator_class = rb_const_get( rb_cObject,
625
+ rb_intern( "Enumerator" ) );
626
+
627
+ VALUE rb_object_for_frame_klass = ( ( TYPE( rb_object_for_frame ) == T_CLASS ) ? rb_object_for_frame : rb_funcall( rb_object_for_frame, rb_intern( "class" ), 0 ) );
628
+
629
+ VALUE rb_ancestors = rb_funcall( rb_object_for_frame_klass,
630
+ rb_intern( "ancestors" ),
631
+ 0 );
632
+
633
+ if ( rb_ary_includes( rb_ancestors,
634
+ rb_enumerator_class ) ) {
635
+
636
+ struct enumerator* c_enumerator = enumerator_ptr( rb_object_for_frame );
637
+
638
+ rb_object_for_frame = c_enumerator->obj;
639
+ rb_method_name = ID2SYM( c_enumerator->meth );
640
+ }
641
+
642
+ }
643
+ else if ( ( *c_current_frame )->block_iseq == 0
644
+ && ( *c_current_frame )->pc == 0) {
645
+ // this happens after we had a fiber and we try to go up - which doesn't make sense with a fiber
646
+ // not sure what we want to do here, if anything
647
+ return Qnil;
648
+ }
649
+ else {
650
+ // The third possibility is that we have an iseq frame with nil params for what we want
651
+ // In that case we can simply return the next frame
652
+ *c_current_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( *c_current_frame );
653
+
654
+ // in theory this could crash because we are going forward a frame when we don't know what's there
655
+ // in practice I think we are ok, since we are only jumping forward from nil frames which should never be at the end
656
+ // at least - I don't think they should... we shall see.
657
+ //
658
+ // a fix would be to check the next frame, but that requires access to the thread or the limit cfp,
659
+ // which requires passing more context; so for now, I'm leaving it there
660
+
661
+ return rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( c_current_frame );
662
+ }
663
+
664
+ // Push values to return hash
665
+
666
+ rb_hash_aset( rb_frame_hash,
667
+ ID2SYM( rb_intern( "object" ) ),
668
+ rb_object_for_frame );
669
+
670
+ rb_hash_aset( rb_frame_hash,
671
+ ID2SYM( rb_intern( "file" ) ),
672
+ rb_sourcefile_name );
673
+
674
+ rb_hash_aset( rb_frame_hash,
675
+ ID2SYM( rb_intern( "line" ) ),
676
+ rb_sourcefile_line );
677
+
678
+ rb_hash_aset( rb_frame_hash,
679
+ ID2SYM( rb_intern( "method" ) ),
680
+ rb_method_name );
681
+
682
+ return rb_frame_hash;
683
+ }
@@ -0,0 +1,31 @@
1
+
2
+ #ifndef RP_SENDER_KERNEL
3
+ #define RP_SENDER_KERNEL
4
+
5
+ #include "ruby.h"
6
+
7
+ #define RPRUBY_SENDER_ERROR_STACK_LEVEL_LESS_THAN_ZERO "Maximum level for stack trace specified was less than zero."
8
+
9
+ void Init_senderKernel();
10
+
11
+ VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
12
+ VALUE* args,
13
+ VALUE rb_self );
14
+ VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc,
15
+ VALUE* args,
16
+ VALUE rb_self );
17
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
18
+ VALUE* args,
19
+ VALUE rb_self );
20
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes_one_of( int argc,
21
+ VALUE* args,
22
+ VALUE rb_self );
23
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_frame_with( int argc,
24
+ VALUE* args,
25
+ VALUE rb_self );
26
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_frames_with( int argc,
27
+ VALUE* args,
28
+ VALUE rb_self );
29
+
30
+
31
+ #endif
@@ -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
@@ -0,0 +1,16 @@
1
+
2
+ #include "rb_Global.h"
3
+ #include "rb_Kernel.h"
4
+
5
+ /*************
6
+ * Init *
7
+ *************/
8
+
9
+ // Called from ruby when RPBDB module is initialized
10
+ void Init_sender() {
11
+
12
+ Init_senderGlobal();
13
+ Init_senderKernel();
14
+
15
+ }
16
+
@@ -0,0 +1,22 @@
1
+ require "test/unit"
2
+ require "sender"
3
+
4
+ class TestSender < Test::Unit::TestCase
5
+
6
+ def test___sender__
7
+ assert_equal self, __sender__
8
+ end
9
+
10
+ def test___caller__
11
+ assert_equal :run, __caller__
12
+ end
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
+
22
+ end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 5
8
- - 7
9
- version: 1.5.7
8
+ - 8
9
+ version: 1.5.8
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-10-28 00:00:00 -04:00
17
+ date: 2011-02-12 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -65,10 +65,20 @@ extensions:
65
65
  extra_rdoc_files: []
66
66
 
67
67
  files:
68
- - lib/sender.rb
69
- - lib/VERSION.rdoc
70
- - README.rdoc
71
68
  - ext/sender/extconf.rb
69
+ - ext/sender/rb_Global.c
70
+ - ext/sender/rb_Global.h
71
+ - ext/sender/rb_Global_internal.h
72
+ - ext/sender/rb_Kernel.c
73
+ - ext/sender/rb_Kernel.h
74
+ - ext/sender/rb_Kernel_internal.h
75
+ - ext/sender/RPSender_internal.c
76
+ - ext/sender/RPSender_internal.h
77
+ - ext/sender/RubySourceSupport.c
78
+ - ext/sender/RubySourceSupport.h
79
+ - ext/sender/sender.c
80
+ - test/test_sender.rb
81
+ - README.rdoc
72
82
  has_rdoc: true
73
83
  homepage: http://rubygems.org/gems/sender
74
84
  licenses: []
data/lib/VERSION.rdoc DELETED
@@ -1 +0,0 @@
1
- 1.5.4
data/lib/sender.rb DELETED
@@ -1,5 +0,0 @@
1
- require 'sender/sender'
2
-
3
- module Sender
4
-
5
- end