sender 1.4.3 → 1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/CHANGELOG.rdoc CHANGED
@@ -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