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 +14 -0
- data/Makefile +1 -1
- data/README.rdoc +232 -106
- data/Rakefile +1 -1
- data/VERSION.rdoc +1 -1
- data/ext/sender/RPSender_internal.h +5 -0
- data/ext/sender/RubySourceSupport.c +13 -8
- data/ext/sender/RubySourceSupport.h +62 -1
- data/ext/sender/rb_Kernel.c +454 -44
- data/ext/sender/rb_Kernel.h +14 -1
- data/lib/VERSION.rdoc +1 -1
- data/lib/sender/sender.bundle +0 -0
- data/sender.gemspec +8 -6
- metadata +10 -9
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 = -
|
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
|
8
|
-
|
9
|
-
|
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
|
-
*
|
23
|
-
*
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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
|
-
|
95
|
-
|
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
|
-
|
98
|
-
|
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:
|
145
|
+
Sender was: #<Test:0x0000010081ba10>
|
110
146
|
Caller was: another_test
|
111
|
-
Sender was: #<Test:
|
147
|
+
Sender was: #<Test:0x0000010081ba10>
|
112
148
|
Caller was: another_test
|
113
|
-
[{:object=>#<Test2:
|
114
|
-
|
115
|
-
|
116
|
-
|
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:
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
{:object=>#<Test:
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
{:object=>main, :file=>"sender_test.rb", :line=>
|
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
|
-
|
131
|
-
Sender was: #<Test2:0x00000100823030>
|
166
|
+
Sender was: #<Test2:0x0000010081a7e8>
|
132
167
|
Caller was: another_test
|
133
|
-
#<Test2:
|
134
|
-
Sender was: #<Test:
|
168
|
+
#<Test2:0x0000010081a7e8>
|
169
|
+
Sender was: #<Test:0x0000010081ba10>
|
135
170
|
Caller was: another_test
|
136
|
-
[{:object=>#<Test2:
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
{:object=>#<Test:
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
{:object=>#<Test:
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
{:object=>main, :file=>"sender_test.rb", :line=>
|
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:
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
{:object=>#<Test:
|
155
|
-
|
156
|
-
|
157
|
-
|
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.
|
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
|
data/ext/sender/rb_Kernel.c
CHANGED
@@ -12,20 +12,29 @@
|
|
12
12
|
|
13
13
|
void Init_senderKernel() {
|
14
14
|
|
15
|
-
rb_define_singleton_method( rb_mKernel, "backtrace",
|
16
|
-
rb_define_singleton_method( rb_mKernel, "
|
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
|
-
*
|
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
|
-
|
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
|
-
|
110
|
-
|
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
|
267
|
+
VALUE rb_this_arg = args[ c_which_member + c_args_offset ];
|
131
268
|
|
132
|
-
|
269
|
+
BOOL matched = FALSE;
|
133
270
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
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
|
-
|
142
|
-
|
143
|
-
|
144
|
-
if
|
145
|
-
|
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
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
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
|
-
//
|
163
|
-
|
164
|
-
|
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
|
-
|
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
|
-
|
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 );
|
data/ext/sender/rb_Kernel.h
CHANGED
@@ -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.
|
1
|
+
1.5
|
data/lib/sender/sender.bundle
CHANGED
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.
|
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-
|
10
|
-
s.description = %q{Adds :__sender__ and :__caller__ to the built-in :__callee__ and :__method__ methods in Ruby 1.9.1
|
11
|
-
|
12
|
-
|
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
|
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:
|
4
|
+
hash: 5
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
|
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-
|
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
|
69
|
-
|
70
|
-
|
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
|
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
|