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 +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
|