sender 1.5.7 → 1.5.8

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