sender 1.4.3 → 1.5

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.rdoc CHANGED
@@ -40,3 +40,17 @@ Fixed path problem for VERSION.rdoc.
40
40
  === 1.4.3 2010-06-29
41
41
 
42
42
  Fixed problems with superclass method definitions so __sender__ and __caller__ return the caller to the first method in the class chain.
43
+
44
+ === 1.5 2010-07-09
45
+
46
+ Added to Kernel:
47
+ * :each_backtrace_frame
48
+ * :backtrace_includes?
49
+ * :backtrace_includes_one_of?
50
+ * :backtrace_frame_with
51
+ * :backtrace_frames_with
52
+
53
+ Added Hash-specification support for context inspection. Now functions take element value (object instance, class, method symbol, filename string,
54
+ line number fixnum) or Hash containing frame detail specification.
55
+
56
+ Added Enumerator support. Non-block enumeration will iterate the backtrace that was the active context when :each_backtrace_frame was called.
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 = -gdwarf-2 -g3
56
+ debugflags = -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/README.rdoc CHANGED
@@ -4,9 +4,11 @@ http://rubygems.org/gems/sender
4
4
 
5
5
  == DESCRIPTION:
6
6
 
7
- Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1, as well
8
- as providing object-oriented :backtrace supporting n-levels backward, and :backtrace_includes?,
9
- which allows contents of the backtrace to be queried.
7
+ Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1.
8
+
9
+ Also provides object-oriented :backtrace supporting n-levels backward, :each_backtrace_frame for iteration, :backtrace_includes?,
10
+ and :backtrace_includes_one_of? for context inspection, and :backtrace_frame_with and :backtrace_frames_with, which return
11
+ matching frame information for the frame(s) matching the given description.
10
12
 
11
13
  == SUMMARY:
12
14
 
@@ -17,10 +19,14 @@ which allows contents of the backtrace to be queried.
17
19
  * __caller__
18
20
  * backtrace
19
21
  * backtrace( frames_to_trace_backward )
20
- * backtrace_includes?( Class )
21
- * backtrace_includes?( class_instance )
22
- * backtrace_includes?( :symbol )
23
- * backtrace_includes?( Class, class_instance, :symbol, ... )
22
+ * backtrace_includes?( Class, class_instance, :symbol, {frame_hash}, ... )
23
+ * backtrace_includes?( frames_to_trace_backward, Class, class_instance, :symbol, {frame_hash}, ... )
24
+ * backtrace_includes_one_of?( Class, class_instance, :symbol, {frame_hash}, ... )
25
+ * backtrace_includes_one_of?( frames_to_trace_backward, Class, class_instance, :symbol, {frame_hash}, ... )
26
+ * backtrace_frame_with( Class, class_instance, :symbol, {frame_hash}, ... )
27
+ * backtrace_frame_with( frames_to_trace_backward, Class, class_instance, :symbol, {frame_hash}, ... )
28
+ * backtrace_frames_with( Class, class_instance, :symbol, {frame_hash}, ... )
29
+ * backtrace_frames_with( frames_to_trace_backward, Class, class_instance, :symbol, {frame_hash}, ... )
24
30
 
25
31
  == INSTALL:
26
32
 
@@ -29,73 +35,103 @@ which allows contents of the backtrace to be queried.
29
35
  == EXAMPLE:
30
36
 
31
37
  require 'sender'
32
-
33
38
  require 'pp'
34
39
 
35
40
  class Test
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
-
43
- def test
44
- puts 'In <Test>:test'
45
- self.another_test
46
- end
47
-
48
- def another_test
49
- puts 'In method <Test>:another_test'
50
- test2 = Test2.new
51
- test2.and_another_test_in_another_object
52
- end
53
-
54
- def and_another_test_in_another_object
55
- puts 'In method <Test>:and_another_test_in_another_object'
56
- puts 'Sender was: ' + __sender__.pretty_inspect.to_s
57
- puts 'Caller was: ' + __caller__.to_s
58
- end
59
-
41
+
42
+ def initialize
43
+ puts 'In method <Test>:initialize'
44
+ puts 'Sender was: ' + __sender__.pretty_inspect.to_s
45
+ puts 'Caller was: ' + __caller__.to_s
46
+ end
47
+
48
+ def test
49
+ puts 'In <Test>:test'
50
+ self.another_test
51
+ end
52
+
53
+ def another_test
54
+ puts 'In method <Test>:another_test'
55
+ test2 = Test2.new
56
+ test2.and_another_test_in_another_object
57
+ end
58
+
59
+ def and_another_test_in_another_object
60
+ puts 'In method <Test>:and_another_test_in_another_object'
61
+ puts 'Sender was: ' + __sender__.pretty_inspect.to_s
62
+ puts 'Caller was: ' + __caller__.to_s
63
+ end
64
+
60
65
  end
61
66
 
62
67
  class Test2 < Test
63
-
64
- def initialize
65
- puts 'In method <Test2>:initialize'
66
- super
67
- puts 'Sender was: ' + __sender__.pretty_inspect.to_s
68
- puts 'Caller was: ' + __caller__.to_s
69
- pp Kernel.backtrace
70
- end
71
-
72
- def and_another_test_in_another_object
73
- puts 'In method <Test2>:and_another_test_in_another_object'
74
- super
75
- pp self
76
- puts 'Sender was: ' + __sender__.pretty_inspect.to_s
77
- puts 'Caller was: ' + __caller__.to_s
78
- pp Kernel.backtrace
79
- pp Kernel.backtrace( 2 )
80
- puts 'These should be true:'
81
- pp Kernel.backtrace_includes?( :another_test )
82
- pp Kernel.backtrace_includes?( Test )
83
- pp Kernel.backtrace_includes?( $test )
84
- pp Kernel.backtrace_includes?( :another_test, Test, $test )
85
- puts 'These should be false:'
86
- pp Kernel.backtrace_includes?( :yet_another_test )
87
- pp Kernel.backtrace_includes?( Test2 )
88
- pp Kernel.backtrace_includes?( self )
89
- pp Kernel.backtrace_includes?( :yet_another_test, Test2, self )
90
- end
91
-
92
- end
93
68
 
94
- $test = Test.new
95
- $test.test
69
+ def initialize
70
+ puts 'In method <Test2>:initialize'
71
+ super
72
+ puts 'Sender was: ' + __sender__.pretty_inspect.to_s
73
+ puts 'Caller was: ' + __caller__.to_s
74
+ pp Kernel.backtrace
75
+ end
76
+
77
+ def and_another_test_in_another_object
78
+ puts 'In method <Test2>:and_another_test_in_another_object'
79
+ super
80
+ pp self
81
+ puts 'Sender was: ' + __sender__.pretty_inspect.to_s
82
+ puts 'Caller was: ' + __caller__.to_s
83
+ pp Kernel.backtrace
84
+ pp Kernel.backtrace( 2 )
85
+ puts 'These should be true:'
86
+ pp Kernel.backtrace_includes?( :another_test )
87
+ pp Kernel.backtrace_includes?( Test )
88
+ pp Kernel.backtrace_includes?( $test )
89
+ pp Kernel.backtrace_includes?( :another_test, Test, $test )
90
+ pp Kernel.backtrace_includes?( "sender_test.rb" )
91
+ puts 'These should be false:'
92
+ pp Kernel.backtrace_includes?( :yet_another_test )
93
+ pp Kernel.backtrace_includes?( Test2 )
94
+ pp Kernel.backtrace_includes?( self )
95
+ pp Kernel.backtrace_includes?( :yet_another_test, Test2, self )
96
+ pp Kernel.backtrace_includes?( "sender_test.rbi" )
97
+
98
+ puts 'And now we get a step by step backtrace'
99
+ which_step = 1
100
+ Kernel.each_backtrace_frame do |this_frame|
101
+ puts 'Frame number ' + which_step.to_s + ':'
102
+ pp this_frame
103
+ which_step += 1
104
+ end
105
+ puts 'And now we try a backtrace inside a block.'
106
+ block_item = [ 'one_item' ]
107
+ block_item.each do |this_item|
108
+ pp Kernel.backtrace
109
+ end
96
110
 
97
- puts 'Finished Test.'
98
- exit
111
+ puts 'And :backtrace_includes_one_of?; this should be true:'
112
+ pp Kernel.backtrace_includes_one_of?( :some_method_that_does_not_exit, :another_test, :test, :some_other_test_that_does_not_exist )
113
+ puts 'as should this:'
114
+ pp Kernel.backtrace_includes_one_of?( { :method => :another_test, :object => $test }, { :method => :test } )
115
+
116
+ puts 'And :backtrace_frame_with; this should be a Hash:'
117
+ pp Kernel.backtrace_frame_with( :test )
118
+ puts 'as should this:'
119
+ pp Kernel.backtrace_frame_with( "sender_test.rb" )
120
+
121
+ puts 'And :backtrace_frames_with; this should be an Array of Hashes'
122
+ pp Kernel.backtrace_frames_with( :object => $test )
123
+ puts 'as should this:'
124
+ pp Kernel.backtrace_frames_with( :file => "sender_test.rb" )
125
+
126
+ puts 'And try iterating with an Enumerator'
127
+ enumerator = Kernel.each_backtrace_frame
128
+ pp enumerator
129
+ while result = enumerator.next
130
+ pp result
131
+ end
132
+
133
+ end
134
+ end
99
135
 
100
136
  == EXAMPLE's OUTPUT:
101
137
 
@@ -106,65 +142,155 @@ which allows contents of the backtrace to be queried.
106
142
  In method <Test>:another_test
107
143
  In method <Test2>:initialize
108
144
  In method <Test>:initialize
109
- Sender was: #<Test:0x0000010102a400>
145
+ Sender was: #<Test:0x0000010081ba10>
110
146
  Caller was: another_test
111
- Sender was: #<Test:0x0000010102a400>
147
+ Sender was: #<Test:0x0000010081ba10>
112
148
  Caller was: another_test
113
- [{:object=>#<Test2:0x00000100823030>,
114
- :file=>"sender_test.rb",
115
- :line=>40,
116
- :method=>:initialize},
149
+ [{:object=>#<Test2:0x0000010081a7e8>,
150
+ :file=>"sender_test.rb",
151
+ :line=>39,
152
+ :method=>:initialize},
117
153
  {:object=>Test2, :file=>nil, :line=>nil, :method=>:new},
118
- {:object=>#<Test:0x0000010102a400>,
119
- :file=>"sender_test.rb",
120
- :line=>20,
121
- :method=>:another_test},
122
- {:object=>#<Test:0x0000010102a400>,
123
- :file=>"sender_test.rb",
124
- :line=>15,
125
- :method=>:test},
126
- {:object=>main, :file=>"sender_test.rb", :line=>66, :method=>:"<main>"},
154
+ {:object=>#<Test:0x0000010081ba10>,
155
+ :file=>"sender_test.rb",
156
+ :line=>20,
157
+ :method=>:another_test},
158
+ {:object=>#<Test:0x0000010081ba10>,
159
+ :file=>"sender_test.rb",
160
+ :line=>15,
161
+ :method=>:test},
162
+ {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"},
127
163
  {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"}]
128
164
  In method <Test2>:and_another_test_in_another_object
129
165
  In method <Test>:and_another_test_in_another_object
130
- This is the super method for :and_another_test_in_another_object
131
- Sender was: #<Test2:0x00000100823030>
166
+ Sender was: #<Test2:0x0000010081a7e8>
132
167
  Caller was: another_test
133
- #<Test2:0x00000100823030>
134
- Sender was: #<Test:0x0000010102a400>
168
+ #<Test2:0x0000010081a7e8>
169
+ Sender was: #<Test:0x0000010081ba10>
135
170
  Caller was: another_test
136
- [{:object=>#<Test2:0x00000100823030>,
137
- :file=>"sender_test.rb",
138
- :line=>49,
139
- :method=>:and_another_test_in_another_object},
140
- {:object=>#<Test:0x0000010102a400>,
141
- :file=>"sender_test.rb",
142
- :line=>21,
143
- :method=>:another_test},
144
- {:object=>#<Test:0x0000010102a400>,
145
- :file=>"sender_test.rb",
146
- :line=>15,
147
- :method=>:test},
148
- {:object=>main, :file=>"sender_test.rb", :line=>66, :method=>:"<main>"},
171
+ [{:object=>#<Test2:0x0000010081a7e8>,
172
+ :file=>"sender_test.rb",
173
+ :line=>48,
174
+ :method=>:and_another_test_in_another_object},
175
+ {:object=>#<Test:0x0000010081ba10>,
176
+ :file=>"sender_test.rb",
177
+ :line=>21,
178
+ :method=>:another_test},
179
+ {:object=>#<Test:0x0000010081ba10>,
180
+ :file=>"sender_test.rb",
181
+ :line=>15,
182
+ :method=>:test},
183
+ {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"},
149
184
  {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"}]
150
- [{:object=>#<Test2:0x00000100823030>,
151
- :file=>"sender_test.rb",
152
- :line=>50,
153
- :method=>:and_another_test_in_another_object},
154
- {:object=>#<Test:0x0000010102a400>,
155
- :file=>"sender_test.rb",
156
- :line=>21,
157
- :method=>:another_test}]
185
+ [{:object=>#<Test2:0x0000010081a7e8>,
186
+ :file=>"sender_test.rb",
187
+ :line=>49,
188
+ :method=>:and_another_test_in_another_object},
189
+ {:object=>#<Test:0x0000010081ba10>,
190
+ :file=>"sender_test.rb",
191
+ :line=>21,
192
+ :method=>:another_test}]
158
193
  These should be true:
159
194
  true
160
195
  true
161
196
  true
162
197
  true
198
+ true
163
199
  These should be false:
164
200
  false
165
201
  false
166
202
  false
167
203
  false
204
+ false
205
+ And now we get a step by step backtrace
206
+ Frame number 1:
207
+ {:object=>#<Test:0x0000010081ba10>,
208
+ :file=>"sender_test.rb",
209
+ :line=>21,
210
+ :method=>:another_test}
211
+ Frame number 2:
212
+ {:object=>#<Test:0x0000010081ba10>,
213
+ :file=>"sender_test.rb",
214
+ :line=>15,
215
+ :method=>:test}
216
+ Frame number 3:
217
+ {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"}
218
+ Frame number 4:
219
+ {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"}
220
+ And now we try a backtrace inside a block.
221
+ [{:object=>#<Test2:0x0000010081a7e8>,
222
+ :file=>"sender_test.rb",
223
+ :line=>73,
224
+ :method=>:"block in and_another_test_in_another_object"},
225
+ {:object=>["one_item"], :file=>nil, :line=>nil, :method=>:each},
226
+ {:object=>#<Test2:0x0000010081a7e8>,
227
+ :file=>"sender_test.rb",
228
+ :line=>72,
229
+ :method=>:and_another_test_in_another_object},
230
+ {:object=>#<Test:0x0000010081ba10>,
231
+ :file=>"sender_test.rb",
232
+ :line=>21,
233
+ :method=>:another_test},
234
+ {:object=>#<Test:0x0000010081ba10>,
235
+ :file=>"sender_test.rb",
236
+ :line=>15,
237
+ :method=>:test},
238
+ {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"},
239
+ {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"}]
240
+ And :backtrace_includes_one_of?; this should be true:
241
+ true
242
+ as should this:
243
+ true
244
+ And :backtrace_frame_with; this should be a Hash:
245
+ {:object=>#<Test:0x0000010081ba10>,
246
+ :file=>"sender_test.rb",
247
+ :line=>15,
248
+ :method=>:test}
249
+ as should this:
250
+ {:object=>#<Test:0x0000010081ba10>,
251
+ :file=>"sender_test.rb",
252
+ :line=>21,
253
+ :method=>:another_test}
254
+ And :backtrace_frames_with; this should be an Array of Hashes
255
+ [{:object=>#<Test:0x0000010081ba10>,
256
+ :file=>"sender_test.rb",
257
+ :line=>21,
258
+ :method=>:another_test},
259
+ {:object=>#<Test:0x0000010081ba10>,
260
+ :file=>"sender_test.rb",
261
+ :line=>15,
262
+ :method=>:test}]
263
+ as should this:
264
+ [{:object=>#<Test:0x0000010081ba10>,
265
+ :file=>"sender_test.rb",
266
+ :line=>21,
267
+ :method=>:another_test},
268
+ {:object=>#<Test:0x0000010081ba10>,
269
+ :file=>"sender_test.rb",
270
+ :line=>15,
271
+ :method=>:test},
272
+ {:object=>main, :file=>"sender_test.rb", :line=>96, :method=>:"<main>"}]
273
+ And try iterating with an Enumerator
274
+ #<Enumerator:0x000001010480e0>
275
+ {:object=>#<Test2:0x0000010081a388>,
276
+ :file=>"sender_test.rb",
277
+ :line=>92,
278
+ :method=>:and_another_test_in_another_object}
279
+ {:object=>#<Test:0x0000010081b770>,
280
+ :file=>"sender_test.rb",
281
+ :line=>21,
282
+ :method=>:another_test}
283
+ {:object=>#<Test:0x0000010081b770>,
284
+ :file=>"sender_test.rb",
285
+ :line=>15,
286
+ :method=>:test}
287
+ {:object=>main, :file=>"sender_test.rb", :line=>103, :method=>:"<main>"}
288
+ {:object=>main, :file=>"<main>", :line=>0, :method=>:"<main>"}
289
+ sender_test.rb:94:in `next': iteration reached at end (StopIteration)
290
+ from sender_test.rb:94:in `and_another_test_in_another_object'
291
+ from sender_test.rb:21:in `another_test'
292
+ from sender_test.rb:15:in `test'
293
+ from sender_test.rb:103:in `<main>'
168
294
  Finished Test.
169
295
 
170
296
  == LICENSE:
data/Rakefile CHANGED
@@ -5,13 +5,13 @@ require 'rake/extensiontask'
5
5
  Hoe.spec 'sender' do
6
6
  developer( 'Asher', 'asher@ridiculouspower.com' )
7
7
  self.rubyforge_name = 'asher'
8
+ self.version = File.open( 'VERSION.rdoc' ).readline
8
9
  self.readme_file = 'README.rdoc'
9
10
  self.history_file = 'CHANGELOG.rdoc'
10
11
  self.extra_rdoc_files = FileList['*.rdoc']
11
12
  self.spec_extras = { :extensions => ["ext/sender/extconf.rb"] }
12
13
  self.extra_dev_deps << ['rake-compiler', '>= 0']
13
14
 
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 CHANGED
@@ -1 +1 @@
1
- 1.4.3
1
+ 1.5
@@ -4,6 +4,11 @@
4
4
  #include "ruby.h"
5
5
  #include "eval_intern.h"
6
6
 
7
+ typedef enum BOOL_e {
8
+ FALSE,
9
+ TRUE
10
+ } BOOL;
11
+
7
12
  rb_control_frame_t* RPRuby_internal_framePriorTo( rb_control_frame_t* control_frame );
8
13
  VALUE RPSender_internal_backtraceHashForControlFrame( const rb_control_frame_t* c_top_of_control_frame );
9
14
 
@@ -65,11 +65,16 @@ found:
65
65
  return line_no;
66
66
  }
67
67
 
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
68
+ struct enumerator* enumerator_ptr(VALUE obj)
69
+ {
70
+ struct enumerator *ptr;
71
+
72
+ Data_Get_Struct(obj, struct enumerator, ptr);
73
+
74
+ // modified because a call to a local version of enumerator_mark won't verify
75
+
76
+ if (!ptr || ptr->obj == Qundef) {
77
+ rb_raise(rb_eArgError, "uninitialized enumerator");
78
+ }
79
+ return ptr;
80
+ }
@@ -5,8 +5,69 @@
5
5
  #include "eval_intern.h"
6
6
  #include "vm_core.h"
7
7
 
8
+ #define MAX_POSBUF 128
9
+
10
+ enum context_type {
11
+ CONTINUATION_CONTEXT = 0,
12
+ FIBER_CONTEXT = 1,
13
+ ROOT_FIBER_CONTEXT = 2
14
+ };
15
+
16
+ typedef struct rb_context_struct {
17
+ enum context_type type;
18
+ VALUE self;
19
+ int argc;
20
+ VALUE value;
21
+ VALUE *vm_stack;
22
+ #ifdef CAPTURE_JUST_VALID_VM_STACK
23
+ int vm_stack_slen; /* length of stack (head of th->stack) */
24
+ int vm_stack_clen; /* length of control frames (tail of th->stack) */
25
+ #endif
26
+ VALUE *machine_stack;
27
+ VALUE *machine_stack_src;
28
+ #ifdef __ia64
29
+ VALUE *machine_register_stack;
30
+ VALUE *machine_register_stack_src;
31
+ int machine_register_stack_size;
32
+ #endif
33
+ rb_thread_t saved_thread;
34
+ rb_jmpbuf_t jmpbuf;
35
+ int machine_stack_size;
36
+ } rb_context_t;
37
+
38
+ enum fiber_status {
39
+ CREATED,
40
+ RUNNING,
41
+ TERMINATED
42
+ };
43
+
44
+ typedef struct rb_fiber_struct {
45
+ rb_context_t cont;
46
+ VALUE prev;
47
+ enum fiber_status status;
48
+ struct rb_fiber_struct *prev_fiber;
49
+ struct rb_fiber_struct *next_fiber;
50
+ } rb_fiber_t;
51
+
52
+ struct enumerator {
53
+ VALUE obj;
54
+ ID meth;
55
+ VALUE args;
56
+ VALUE fib;
57
+ VALUE dst;
58
+ VALUE no_next;
59
+ };
60
+
61
+ #define GetFiberPtr(obj, ptr) do {\
62
+ ptr = (rb_fiber_t*)DATA_PTR(obj);\
63
+ if (!ptr) rb_raise(rb_eFiberError, "uninitialized fiber");\
64
+ } while(0)
65
+
66
+
8
67
  ID frame_func_id( rb_control_frame_t *cfp );
9
68
  ID rb_frame_caller(void);
10
69
  int rb_vm_get_sourceline(const rb_control_frame_t *cfp);
11
-
70
+ void control_frame_dump(rb_thread_t *th, rb_control_frame_t *cfp);
71
+ struct enumerator* enumerator_ptr(VALUE obj);
72
+
12
73
  #endif
@@ -12,20 +12,29 @@
12
12
 
13
13
  void Init_senderKernel() {
14
14
 
15
- rb_define_singleton_method( rb_mKernel, "backtrace", rb_RPRuby_Sender_Kernel_backtrace, -1 );
16
- rb_define_singleton_method( rb_mKernel, "backtrace_includes?", rb_RPRuby_Sender_Kernel_backtrace_includes, -1 );
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
+
17
22
 
18
23
  }
19
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
+
20
29
  /***************************************************************************************************************************************************************
21
30
  ****************************************************************************************************************************************************************
22
31
  Ruby Kernel Methods
23
32
  ****************************************************************************************************************************************************************
24
33
  ***************************************************************************************************************************************************************/
25
34
 
26
- /******************
27
- * __backtrace__ *
28
- ******************/
35
+ /**********************
36
+ * Kernel.backtrace *
37
+ *********************/
29
38
 
30
39
  /*
31
40
  * call-seq:
@@ -73,6 +82,10 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
73
82
 
74
83
  VALUE rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
75
84
 
85
+ if ( rb_frame_hash == Qnil ) {
86
+ break;
87
+ }
88
+
76
89
  // push hash to array
77
90
  rb_ary_push( rb_return_array,
78
91
  rb_frame_hash );
@@ -84,10 +97,83 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
84
97
  return rb_return_array;
85
98
  }
86
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
+ }
87
143
 
88
- /*****************************
89
- * __backtrace_includes?__ *
90
- ****************************/
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
+ //rb_raise( rb_eArgError, RPRUBY_SENDER_ERROR_NO_ENUMERATORS );
160
+ }
161
+
162
+ // otherwise, yield the block
163
+ rb_yield( rb_frame_hash );
164
+
165
+ // only move the frame if we are not using a stored backtrace
166
+ if ( rb_stored_backtrace_array == Qnil ) {
167
+ c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
168
+ }
169
+ }
170
+
171
+ return Qnil;
172
+ }
173
+
174
+ /********************************
175
+ * Kernel.backtrace_includes? *
176
+ *******************************/
91
177
 
92
178
  /*
93
179
  * call-seq:
@@ -102,12 +188,40 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
102
188
  VALUE* args,
103
189
  VALUE rb_self ) {
104
190
 
191
+ // this function is also used for
192
+ // * backtrace_includes_one_of?
193
+ // * backtrace_includes_frame?
194
+ // * backtrace_includes_one_of_frames?
195
+
105
196
  // create tracking array
106
197
  VALUE rb_tracking_array = rb_ary_new();
107
198
 
108
199
  // populate tracking array with methods/objects
109
- int c_which_arg = 0;
110
- for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
200
+ // optional - if first arg is Qtrue, we are looking for one of the args instead of all of the args
201
+ int c_which_arg = 0;
202
+ BOOL c_requires_all_items = TRUE;
203
+ if ( args[ 0 ] == Qnil
204
+ || ( argc > 1
205
+ && args[ 1 ] == Qnil ) ) {
206
+ c_which_arg++;
207
+ c_requires_all_items = FALSE;
208
+ }
209
+ BOOL c_return_frame = FALSE;
210
+ if ( args[ 0 ] == Qfalse
211
+ || ( argc > 1
212
+ && args[ 1 ] == Qfalse ) ) {
213
+ c_which_arg++;
214
+ c_return_frame = TRUE;
215
+ }
216
+ BOOL c_return_all_frames = FALSE;
217
+ if ( args[ 0 ] == Qtrue
218
+ || ( argc > 1
219
+ && args[ 1 ] == Qtrue ) ) {
220
+ c_which_arg++;
221
+ c_return_all_frames = TRUE;
222
+ }
223
+ int c_args_offset = c_which_arg;
224
+ for ( ; c_which_arg < argc ; c_which_arg++ ) {
111
225
  rb_ary_push( rb_tracking_array,
112
226
  args[ c_which_arg ] );
113
227
  }
@@ -120,6 +234,29 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
120
234
  // set c_top_of_control_frame to the first frame in <main>
121
235
  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 ) ) );
122
236
 
237
+ VALUE rb_test_index_array = rb_ary_new();
238
+ // :object
239
+ // instance or class
240
+ rb_ary_push( rb_test_index_array,
241
+ ID2SYM( rb_intern( "object" ) ) );
242
+ // :method
243
+ rb_ary_push( rb_test_index_array,
244
+ ID2SYM( rb_intern( "method" ) ) );
245
+ // :file
246
+ rb_ary_push( rb_test_index_array,
247
+ ID2SYM( rb_intern( "file" ) ) );
248
+ // :line
249
+ rb_ary_push( rb_test_index_array,
250
+ ID2SYM( rb_intern( "line" ) ) );
251
+
252
+ // only used if c_return_all_frames == TRUE
253
+ VALUE rb_frame_hashes_array = Qnil;
254
+ if ( c_return_all_frames == TRUE ) {
255
+ rb_frame_hashes_array = rb_ary_new();
256
+ }
257
+
258
+ VALUE rb_frame_hash;
259
+
123
260
  // for each control frame:
124
261
  while ( c_current_context_frame < c_top_of_control_frame ) {
125
262
 
@@ -127,61 +264,272 @@ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
127
264
  int c_which_member;
128
265
  for ( c_which_member = 0 ; c_which_member < RARRAY_LEN( rb_tracking_array ) ; c_which_member++ ) {
129
266
 
130
- VALUE rb_array_member = args[ c_which_member ];
267
+ VALUE rb_this_arg = args[ c_which_member + c_args_offset ];
131
268
 
132
- int matched = 0;
269
+ BOOL matched = FALSE;
133
270
 
134
- // if rb_array_member is a class
135
- if ( TYPE( rb_array_member ) == T_CLASS ) {
136
- // if rb_array_member is the current frame's object's class
137
- if ( rb_array_member == rb_class_of( c_current_context_frame->self ) ) {
138
- matched = 1;
271
+ rb_frame_hash = rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( & c_current_context_frame );
272
+
273
+ // if we have a hash we are testing multiple items in a frame
274
+ if ( TYPE( rb_this_arg ) == T_HASH ) {
275
+
276
+ VALUE rb_frame_test_array = rb_obj_clone( rb_test_index_array );
277
+
278
+ // for each element that we could test for
279
+ int c_which_index;
280
+ int c_skipped_index_count = 0;
281
+ for ( c_which_index = 0 ; c_which_index < RARRAY_LEN( rb_frame_test_array ) ; c_which_index++ ) {
282
+
283
+ VALUE rb_this_index = RARRAY_PTR( rb_frame_test_array )[ c_which_index ];
284
+
285
+ // see if our requested test hash includes the potential test element
286
+ if ( rb_hash_lookup( rb_this_arg,
287
+ rb_this_index ) != Qnil ) {
288
+
289
+ VALUE rb_required_element = rb_hash_aref( rb_this_arg,
290
+ rb_this_index );
291
+ VALUE rb_frame_element = rb_hash_aref( rb_frame_hash,
292
+ rb_this_index );
293
+
294
+ // if it does, we need to see if the current frame's element matches this element
295
+ VALUE rb_required_element_klass;
296
+ if ( rb_required_element == rb_frame_element
297
+ // if we have a string, which is a filename
298
+ || ( TYPE( rb_required_element ) == T_STRING
299
+ && rb_funcall( rb_frame_element, rb_intern( "==" ), 1, rb_required_element ) == Qtrue )
300
+ // if we have a class, which is a special case for :object
301
+ || ( rb_this_index == ID2SYM( rb_intern( "class" ) )
302
+ && ( rb_required_element_klass = ( ( TYPE( rb_required_element ) == T_CLASS ) ? rb_required_element : rb_funcall( rb_required_element, rb_intern( "class" ), 0 ) ) )
303
+ && rb_required_element_klass == rb_required_element ) ) {
304
+
305
+ rb_ary_delete_at( rb_frame_test_array,
306
+ c_which_index );
307
+ c_which_index--;
308
+ }
309
+ }
310
+ else {
311
+ c_skipped_index_count++;
312
+ }
313
+
314
+ if ( RARRAY_LEN( rb_frame_test_array ) == c_skipped_index_count ) {
315
+ if ( c_return_frame == TRUE ) {
316
+ return rb_frame_hash;
317
+ }
318
+ else if ( c_return_all_frames == TRUE ) {
319
+ rb_ary_push( rb_frame_hashes_array,
320
+ rb_frame_hash );
321
+ }
322
+ else {
323
+ return Qtrue;
324
+ }
325
+ }
139
326
  }
140
327
  }
141
- // if rb_array_member is a method symbol and matches our current frame's method
142
- else if ( TYPE( rb_array_member ) == T_SYMBOL ) {
143
-
144
- if ( rb_to_id( rb_array_member ) == frame_func_id( c_current_context_frame ) ) {
145
- matched = 1;
328
+ else {
329
+
330
+ // :object => <class:instance>
331
+ if ( TYPE( rb_this_arg ) == T_OBJECT ) {
332
+
333
+ if ( rb_hash_aref( rb_frame_hash,
334
+ ID2SYM( rb_intern( "object" ) ) ) == rb_this_arg ) {
335
+ matched = TRUE;
336
+ }
146
337
  }
147
- }
148
- // if rb_array_member is an object
149
- else if ( TYPE( rb_array_member ) == T_OBJECT ) {
150
- // if rb_array_member is the current frame's object (self)
151
- if ( rb_array_member == c_current_context_frame->self ) {
152
- matched = 1;
338
+ // :object => <class>
339
+ else if ( TYPE( rb_this_arg ) == T_CLASS ) {
340
+
341
+ VALUE rb_frame_object = rb_hash_aref( rb_frame_hash,
342
+ ID2SYM( rb_intern( "object" ) ) );
343
+ VALUE rb_frame_object_klass = TYPE( rb_frame_object ) == T_CLASS ? rb_frame_object : rb_funcall( rb_frame_object, rb_intern( "class" ), 0 );
344
+ if ( rb_frame_object_klass == rb_this_arg ) {
345
+ matched = TRUE;
346
+ }
347
+ }
348
+ // :method => :method
349
+ else if ( TYPE( rb_this_arg ) == T_SYMBOL ) {
350
+
351
+ if ( rb_hash_aref( rb_frame_hash,
352
+ ID2SYM( rb_intern( "method" ) ) ) == rb_this_arg ) {
353
+ matched = TRUE;
354
+ }
355
+ }
356
+ // :file => "filename"
357
+ else if ( TYPE( rb_this_arg ) == T_STRING ) {
358
+ VALUE rb_filename = rb_hash_aref( rb_frame_hash,
359
+ ID2SYM( rb_intern( "file" ) ) );
360
+ VALUE rb_comparison = rb_funcall( rb_filename, rb_intern( "==" ), 1, rb_this_arg );
361
+ if ( rb_comparison == Qtrue ) {
362
+ matched = TRUE;
363
+ }
364
+ }
365
+ // :line => number
366
+ else if ( TYPE( rb_this_arg ) == T_FIXNUM ) {
367
+ if ( rb_hash_aref( rb_frame_hash,
368
+ ID2SYM( rb_intern( "line" ) ) ) == rb_this_arg ) {
369
+ matched = TRUE;
370
+ }
153
371
  }
154
- }
155
-
156
- // if array member exists in frame, remove from array
157
- if ( matched ) {
158
- // delete this index
159
- rb_ary_delete_at( rb_tracking_array,
160
- c_which_member );
161
372
 
162
- // decrement the loop iterator so that the increase is offset
163
- // this is necessary since we just removed an index and are iterating vs. the length of the array
164
- c_which_member--;
373
+ // if array member exists in frame, remove from array
374
+ if ( matched ) {
375
+ if ( c_requires_all_items == FALSE ) {
376
+ if ( c_return_frame == TRUE ) {
377
+ return rb_frame_hash;
378
+ }
379
+ else {
380
+ return Qtrue;
381
+ }
382
+
383
+ }
384
+ else {
385
+
386
+ // delete this index
387
+ rb_ary_delete_at( rb_tracking_array,
388
+ c_which_member );
389
+
390
+ // decrement the loop iterator so that the increase is offset
391
+ // this is necessary since we just removed an index and are iterating vs. the length of the array
392
+ c_which_member--;
393
+ }
394
+ }
165
395
  }
166
396
  }
167
397
 
168
398
  // if array is empty, return true
169
399
  // we check here as well as at the end so we can stop iterating the backtrace if we find all our items
170
400
  if ( RARRAY_LEN( rb_tracking_array ) == 0 ) {
171
- return Qtrue;
401
+ if ( c_return_frame == TRUE ) {
402
+ return rb_frame_hash;
403
+ }
404
+ else if ( c_return_all_frames == TRUE ) {
405
+ rb_ary_push( rb_frame_hashes_array,
406
+ rb_frame_hash );
407
+ return rb_frame_hashes_array;
408
+ }
409
+ else {
410
+ return Qtrue;
411
+ }
172
412
  }
173
413
  c_current_context_frame = RUBY_VM_PREVIOUS_CONTROL_FRAME( c_current_context_frame );
174
414
  }
175
-
415
+
416
+ if ( c_return_all_frames == TRUE
417
+ && RARRAY_LEN( rb_frame_hashes_array ) > 0 ) {
418
+ return rb_frame_hashes_array;
419
+ }
176
420
  // if we finish iterating frames and still have items in the array, return false
177
- if ( RARRAY_LEN( rb_tracking_array ) > 0 ) {
421
+ else if ( RARRAY_LEN( rb_tracking_array ) > 0 ) {
178
422
  return Qfalse;
179
423
  }
180
-
181
424
  // otherwise, return true
182
- return Qtrue;
425
+ else if ( c_return_frame == TRUE ) {
426
+ return rb_frame_hash;
427
+ }
428
+ else {
429
+ return Qtrue;
430
+ }
431
+ // we don't get here
432
+ return Qnil;
433
+ }
434
+
435
+ /***************************************
436
+ * Kernel.backtrace_includes_one_of? *
437
+ **************************************/
438
+
439
+ /*
440
+ * call-seq:
441
+ * Kernel.backtrace_includes_one_of?( method_or_object, ... ) -> true or false
442
+ * Kernel.backtrace_includes_one_of?( number_of_frames, method_or_object, ... ) -> true or false
443
+ *
444
+ * Returns whether one of the specified methods or objects or classes are in the current backtrace context.
445
+ * Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
446
+ * will only report true if the current method is part of the earlier call chain.
447
+ */
448
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_includes_one_of( int argc,
449
+ VALUE* args,
450
+ VALUE rb_self ) {
451
+
452
+ // method implemented as special case of backtrace_includes?
453
+
454
+ // create a new array starting with Qtrue and then followed by args
455
+ VALUE c_methods_array[ argc + 1 ];
456
+ c_methods_array[ 0 ] = Qnil;
457
+ int c_which_arg;
458
+ for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
459
+ c_methods_array[ c_which_arg + 1 ] = args[ c_which_arg ];
460
+ }
461
+ return rb_RPRuby_Sender_Kernel_backtrace_includes( argc + 1,
462
+ c_methods_array,
463
+ rb_self );
464
+ }
465
+
466
+ /*********************************
467
+ * Kernel.backtrace_frame_with *
468
+ ********************************/
469
+
470
+ /*
471
+ * call-seq:
472
+ * Kernel.backtrace_frame_with( method_or_object, ... ) -> true or false
473
+ * Kernel.backtrace_frame_with( number_of_frames, method_or_object, ... ) -> true or false
474
+ *
475
+ * Returns first frame matching specifications, which work like Kernel.backtrace_includes?.
476
+ * Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
477
+ * will only report true if the current method is part of the earlier call chain.
478
+ */
479
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_frame_with( int argc,
480
+ VALUE* args,
481
+ VALUE rb_self ) {
482
+
483
+ // create a new array starting with Qtrue and then followed by args
484
+ VALUE c_methods_array[ argc + 1 ];
485
+ // Qfalse tells backtrace_includes to return frame hash instead of true/false
486
+ c_methods_array[ 0 ] = Qfalse;
487
+ int c_which_arg;
488
+ for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
489
+ c_methods_array[ c_which_arg + 1 ] = args[ c_which_arg ];
490
+ }
491
+ return rb_RPRuby_Sender_Kernel_backtrace_includes_one_of( argc + 1,
492
+ c_methods_array,
493
+ rb_self );
494
+ }
495
+
496
+ /**********************************
497
+ * Kernel.backtrace_frames_with *
498
+ *********************************/
499
+
500
+ /*
501
+ * call-seq:
502
+ * Kernel.backtrace_frames_with( method_or_object, ... ) -> true or false
503
+ * Kernel.backtrace_frames_with( number_of_frames, method_or_object, ... ) -> true or false
504
+ *
505
+ * Returns all frames matching specifications, which work like Kernel.backtrace_includes?.
506
+ * Kernel.backtrace_includes_one_of? begins with the prior frame, so asking if the backtrace includes the current method
507
+ * will only report true if the current method is part of the earlier call chain.
508
+ */
509
+ VALUE rb_RPRuby_Sender_Kernel_backtrace_frames_with( int argc,
510
+ VALUE* args,
511
+ VALUE rb_self ) {
512
+
513
+
514
+ // create a new array starting with Qtrue and then followed by args
515
+ VALUE c_methods_array[ argc + 1 ];
516
+ // Qtrue tells backtrace_includes to return all frame hashes specified instead of the first
517
+ c_methods_array[ 0 ] = Qtrue;
518
+ int c_which_arg;
519
+ for ( c_which_arg = 0 ; c_which_arg < argc ; c_which_arg++ ) {
520
+ c_methods_array[ c_which_arg + 1 ] = args[ c_which_arg ];
521
+ }
522
+ return rb_RPRuby_Sender_Kernel_backtrace_includes( argc + 1,
523
+ c_methods_array,
524
+ rb_self );
183
525
  }
184
526
 
527
+ /***************************************************************************************************************************************************************
528
+ ****************************************************************************************************************************************************************
529
+ Internal Methods
530
+ ****************************************************************************************************************************************************************
531
+ ***************************************************************************************************************************************************************/
532
+
185
533
  /**********************************
186
534
  * backtraceHashForControlFrame *
187
535
  *********************************/
@@ -214,6 +562,7 @@ VALUE rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( rb_control_
214
562
 
215
563
  // get name of instruction sequence
216
564
  rb_method_name = ID2SYM( rb_intern( StringValuePtr( iseq->name ) ) );
565
+ rb_object_for_frame = ( *c_current_frame )->self;
217
566
  }
218
567
  }
219
568
  else if ( RUBYVM_CFUNC_FRAME_P( *c_current_frame ) ) {
@@ -221,6 +570,68 @@ VALUE rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( rb_control_
221
570
  // get name of method
222
571
  c_method_name = rb_id2name( ( *c_current_frame )->method_id );
223
572
  rb_method_name = ( c_method_name == NULL ? Qnil : ID2SYM( rb_intern( c_method_name ) ) );
573
+ rb_object_for_frame = ( *c_current_frame )->self;
574
+ }
575
+ // we have to test this case - it works for blocks but there may be other cases too
576
+ else if ( ( *c_current_frame )->block_iseq != 0
577
+ && ( *c_current_frame )->pc == 0) {
578
+
579
+ // If we got here we have a fiber
580
+ // There doesn't seem to be much that we can tell about a fiber's context
581
+
582
+ VALUE rb_current_fiber = rb_fiber_current();
583
+ rb_fiber_t* c_current_fiber = NULL;
584
+
585
+ GetFiberPtr( rb_current_fiber,
586
+ c_current_fiber);
587
+
588
+ rb_context_t* c_context = & c_current_fiber->cont;
589
+
590
+ // rb_block_t* c_blockptr = RUBY_VM_GET_BLOCK_PTR_IN_CFP( *c_current_frame );
591
+
592
+ rb_object_for_frame = ( *c_current_frame )->self;
593
+
594
+ // get sourcefile name and set in hash
595
+ rb_sourcefile_name = Qnil;
596
+
597
+ // get sourcefile line and set in hash
598
+ rb_sourcefile_line = Qnil;
599
+
600
+ // get name of instruction sequence
601
+ rb_method_name = rb_str_new2( "<Fiber>" );
602
+
603
+ // if we have a fiber we also include its ruby reference since we have so little other context
604
+ rb_hash_aset( rb_frame_hash,
605
+ ID2SYM( rb_intern( "fiber" ) ),
606
+ c_context->self );
607
+
608
+ // The one time that we know a fiber is in use in the Ruby base is with Enumerators
609
+ // For now we will handle that with a special case
610
+
611
+ VALUE rb_enumerator_class = rb_const_get( rb_cObject,
612
+ rb_intern( "Enumerator" ) );
613
+
614
+ 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 ) );
615
+
616
+ VALUE rb_ancestors = rb_funcall( rb_object_for_frame_klass,
617
+ rb_intern( "ancestors" ),
618
+ 0 );
619
+
620
+ if ( rb_ary_includes( rb_ancestors,
621
+ rb_enumerator_class ) ) {
622
+
623
+ struct enumerator* c_enumerator = enumerator_ptr( rb_object_for_frame );
624
+
625
+ rb_object_for_frame = c_enumerator->obj;
626
+ rb_method_name = ID2SYM( c_enumerator->meth );
627
+ }
628
+
629
+ }
630
+ else if ( ( *c_current_frame )->block_iseq == 0
631
+ && ( *c_current_frame )->pc == 0) {
632
+ // this happens after we had a fiber and we try to go up - which doesn't make sense with a fiber
633
+ // not sure what we want to do here, if anything
634
+ return Qnil;
224
635
  }
225
636
  else {
226
637
  // The third possibility is that we have an iseq frame with nil params for what we want
@@ -239,7 +650,6 @@ VALUE rb_RPRuby_Sender_Kernel_internal_backtraceHashForControlFrame( rb_control_
239
650
 
240
651
  // Push values to return hash
241
652
 
242
- rb_object_for_frame = ( *c_current_frame )->self;
243
653
  rb_hash_aset( rb_frame_hash,
244
654
  ID2SYM( rb_intern( "object" ) ),
245
655
  rb_object_for_frame );
@@ -11,8 +11,21 @@
11
11
  VALUE rb_RPRuby_Sender_Kernel_backtrace( int argc,
12
12
  VALUE* args,
13
13
  VALUE rb_self );
14
+ VALUE rb_RPRuby_Sender_Kernel_each_backtrace_frame( int argc,
15
+ VALUE* args,
16
+ VALUE rb_self );
14
17
  VALUE rb_RPRuby_Sender_Kernel_backtrace_includes( int argc,
15
18
  VALUE* args,
16
19
  VALUE rb_self );
17
-
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
+
18
31
  #endif
data/lib/VERSION.rdoc CHANGED
@@ -1 +1 @@
1
- 1.4.3
1
+ 1.5
Binary file
data/sender.gemspec CHANGED
@@ -2,14 +2,16 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{sender}
5
- s.version = "1.4.3"
5
+ s.version = "1.5"
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-29}
10
- s.description = %q{Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1, as well
11
- as providing object-oriented :backtrace supporting n-levels backward, and :backtrace_includes?,
12
- which allows contents of the backtrace to be queried.}
9
+ s.date = %q{2010-07-09}
10
+ s.description = %q{Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1.
11
+
12
+ Also provides object-oriented :backtrace supporting n-levels backward, :each_backtrace_frame for iteration, :backtrace_includes?,
13
+ and :backtrace_includes_one_of? for context inspection, and :backtrace_frame_with and :backtrace_frames_with, which return
14
+ matching frame information for the frame(s) matching the given description.}
13
15
  s.email = ["asher@ridiculouspower.com"]
14
16
  s.extensions = ["ext/sender/extconf.rb"]
15
17
  s.extra_rdoc_files = ["Manifest.txt", "CHANGELOG.rdoc", "README.rdoc", "VERSION.rdoc"]
@@ -19,7 +21,7 @@ which allows contents of the backtrace to be queried.}
19
21
  s.require_paths = ["lib"]
20
22
  s.rubyforge_project = %q{asher}
21
23
  s.rubygems_version = %q{1.3.7}
22
- s.summary = %q{Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1, as well as providing object-oriented :backtrace supporting n-levels backward, and :backtrace_includes?, which allows contents of the backtrace to be queried.}
24
+ s.summary = %q{Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1}
23
25
  s.test_files = ["test/test_sender.rb"]
24
26
 
25
27
  if s.respond_to? :specification_version then
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sender
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
4
+ hash: 5
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 4
9
- - 3
10
- version: 1.4.3
8
+ - 5
9
+ version: "1.5"
11
10
  platform: ruby
12
11
  authors:
13
12
  - Asher
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-06-29 00:00:00 -04:00
17
+ date: 2010-07-09 00:00:00 -04:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -65,9 +64,11 @@ dependencies:
65
64
  type: :development
66
65
  version_requirements: *id003
67
66
  description: |-
68
- Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1, as well
69
- as providing object-oriented :backtrace supporting n-levels backward, and :backtrace_includes?,
70
- which allows contents of the backtrace to be queried.
67
+ Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1.
68
+
69
+ Also provides object-oriented :backtrace supporting n-levels backward, :each_backtrace_frame for iteration, :backtrace_includes?,
70
+ and :backtrace_includes_one_of? for context inspection, and :backtrace_frame_with and :backtrace_frames_with, which return
71
+ matching frame information for the frame(s) matching the given description.
71
72
  email:
72
73
  - asher@ridiculouspower.com
73
74
  executables: []
@@ -160,6 +161,6 @@ rubyforge_project: asher
160
161
  rubygems_version: 1.3.7
161
162
  signing_key:
162
163
  specification_version: 3
163
- summary: Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1, as well as providing object-oriented :backtrace supporting n-levels backward, and :backtrace_includes?, which allows contents of the backtrace to be queried.
164
+ summary: Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1
164
165
  test_files:
165
166
  - test/test_sender.rb