rubymirrors 0.0.1
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/Gemfile +7 -0
- data/README.md +30 -0
- data/Rakefile +13 -0
- data/lib/abstract_reflection.rb +112 -0
- data/lib/abstract_reflection/class_mirror.rb +150 -0
- data/lib/abstract_reflection/compiler_mirror.rb +31 -0
- data/lib/abstract_reflection/field_mirror.rb +35 -0
- data/lib/abstract_reflection/gc_mirror.rb +19 -0
- data/lib/abstract_reflection/method_mirror.rb +253 -0
- data/lib/abstract_reflection/mirror.rb +108 -0
- data/lib/abstract_reflection/object_mirror.rb +48 -0
- data/lib/abstract_reflection/stack_frame_mirror.rb +61 -0
- data/lib/abstract_reflection/thread_mirror.rb +64 -0
- data/lib/maglev/reflection.rb +49 -0
- data/lib/maglev/reflection/class_mirror.rb +157 -0
- data/lib/maglev/reflection/core_ext/class_organizer.rb +20 -0
- data/lib/maglev/reflection/core_ext/maglev.rb +5 -0
- data/lib/maglev/reflection/core_ext/method.rb +154 -0
- data/lib/maglev/reflection/core_ext/module.rb +41 -0
- data/lib/maglev/reflection/core_ext/object.rb +4 -0
- data/lib/maglev/reflection/core_ext/thread.rb +226 -0
- data/lib/maglev/reflection/field_mirror.rb +39 -0
- data/lib/maglev/reflection/field_mirror/fixed_instance_variable_mirror.rb +25 -0
- data/lib/maglev/reflection/method_mirror.rb +149 -0
- data/lib/maglev/reflection/mirror.rb +6 -0
- data/lib/maglev/reflection/object_mirror.rb +18 -0
- data/lib/maglev/reflection/stack_frame_mirror.rb +104 -0
- data/lib/maglev/reflection/thread_mirror.rb +116 -0
- data/lib/rubinius/reflection.rb +6 -0
- data/lib/ruby/reflection.rb +74 -0
- data/lib/ruby/reflection/class_mirror.rb +89 -0
- data/lib/ruby/reflection/field_mirror.rb +32 -0
- data/lib/ruby/reflection/field_mirror/class_variable_mirror.rb +25 -0
- data/lib/ruby/reflection/field_mirror/constant_mirror.rb +36 -0
- data/lib/ruby/reflection/field_mirror/instance_variable_mirror.rb +25 -0
- data/lib/ruby/reflection/method_mirror.rb +122 -0
- data/lib/ruby/reflection/mirror.rb +12 -0
- data/lib/ruby/reflection/object_mirror.rb +25 -0
- data/lib/ruby/reflection/stack_frame_mirror.rb +49 -0
- data/lib/ruby/reflection/support/shift_reset.rb +29 -0
- data/lib/ruby/reflection/thread_mirror.rb +47 -0
- data/rubymirrors.gemspec +12 -0
- data/spec/class_spec.rb +92 -0
- data/spec/field_spec.rb +119 -0
- data/spec/fixtures/class_spec.rb +29 -0
- data/spec/fixtures/field_spec.rb +9 -0
- data/spec/fixtures/method_spec.rb +14 -0
- data/spec/fixtures/object_spec.rb +5 -0
- data/spec/fixtures/reflect_spec.rb +14 -0
- data/spec/fixtures/stack_frame_spec.rb +5 -0
- data/spec/fixtures/thread_spec.rb +5 -0
- data/spec/frame_spec.rb +80 -0
- data/spec/method_spec.rb +166 -0
- data/spec/object_spec.rb +18 -0
- data/spec/reflection_spec.rb +74 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/spec_helper/mspec_patch.rb +29 -0
- data/spec/spec_helper/multiple_reflections.rb +14 -0
- data/spec/thread_spec.rb +142 -0
- metadata +173 -0
data/spec/frame_spec.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'fixtures/stack_frame_spec'
|
3
|
+
|
4
|
+
describe "StackFrameMirror" do
|
5
|
+
before(:each) do
|
6
|
+
@r = reflection
|
7
|
+
@t = Thread.start do
|
8
|
+
t = FrameFixture.new
|
9
|
+
t.my_stop("argument_value")
|
10
|
+
t.my_return
|
11
|
+
end
|
12
|
+
Thread.pass until @t.stop?
|
13
|
+
@m = @r.reflect(@t)
|
14
|
+
@s = @m.stack
|
15
|
+
@f = @s.detect {|frame| frame.name == "my_stop" }
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return StackFrameMirrors when reflecting on a Threads stack" do
|
19
|
+
@s.each {|a| a.should be_kind_of Reflection::StackFrameMirror }
|
20
|
+
end
|
21
|
+
|
22
|
+
it "the step offset" do
|
23
|
+
@f.step_offset.should be_kind_of Fixnum
|
24
|
+
end
|
25
|
+
|
26
|
+
it "the source offset" do
|
27
|
+
offs = @f.source_offset
|
28
|
+
offs.should be_kind_of Fixnum
|
29
|
+
offs.should < @f.method.source.size
|
30
|
+
end
|
31
|
+
|
32
|
+
it "the receiver" do
|
33
|
+
@f.receiver.target_class.name.should == "FrameFixture"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "the self should be the receiver for a regular method" do
|
37
|
+
@f.self.reflectee.should == @f.receiver.reflectee
|
38
|
+
end
|
39
|
+
|
40
|
+
it "the arguments" do
|
41
|
+
@f.arguments.keys.should == ["argument"]
|
42
|
+
@f.arguments.values.collect(&:name).should == ["argument_value".inspect]
|
43
|
+
end
|
44
|
+
|
45
|
+
it "the locals" do
|
46
|
+
@f.locals.keys.should include "local"
|
47
|
+
@f.locals.values.collect(&:name).should include "local_value".inspect
|
48
|
+
end
|
49
|
+
|
50
|
+
it "the variable context" do
|
51
|
+
pending
|
52
|
+
end
|
53
|
+
|
54
|
+
it "restart the frame" do
|
55
|
+
prev_step_offset = @f.step_offset
|
56
|
+
@f.restart
|
57
|
+
@f.step_offset.should < prev_step_offset
|
58
|
+
@m.stack.first.should == @f
|
59
|
+
end
|
60
|
+
|
61
|
+
it "pop the frame" do
|
62
|
+
frame_before_f = @s[@s.index(@f) + 1]
|
63
|
+
@f.pop
|
64
|
+
@m.stack.first.should == frame_before_f
|
65
|
+
end
|
66
|
+
|
67
|
+
it "step over the current call" do
|
68
|
+
@f.restart
|
69
|
+
prev_step_offset = @f.step_offset
|
70
|
+
@f.step(:over)
|
71
|
+
@f.step_offset.should == prev_step_offset + 1
|
72
|
+
end
|
73
|
+
|
74
|
+
it "step into the next call" do
|
75
|
+
@f.restart
|
76
|
+
@f.step(:into)
|
77
|
+
@m.stack[0].should_not == @f
|
78
|
+
@m.stack[1].should == @f
|
79
|
+
end
|
80
|
+
end
|
data/spec/method_spec.rb
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'fixtures/method_spec'
|
3
|
+
|
4
|
+
describe "MethodMirror" do
|
5
|
+
describe "runtime reflection" do
|
6
|
+
describe "structural queries" do
|
7
|
+
before(:each) do
|
8
|
+
@r = Reflection.new(nil)
|
9
|
+
@f = MethodSpecFixture
|
10
|
+
m = MethodSpecFixture.instance_method(:source_location)
|
11
|
+
@m = @r.reflect(m)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "file" do
|
15
|
+
@m.file.should == @f.new.source_location[0]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "line" do
|
19
|
+
@m.line.should == (@f.new.source_location[1] - 1)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "selector" do
|
23
|
+
@m.selector.should == @f.new.source_location[2]
|
24
|
+
end
|
25
|
+
|
26
|
+
it "defining class" do
|
27
|
+
@m.defining_class.name.should == @f.new.source_location[3].name
|
28
|
+
end
|
29
|
+
|
30
|
+
it "source" do
|
31
|
+
@m.source.should =~ /[__FILE__, __LINE__, __method__.to_s, self.class]/
|
32
|
+
end
|
33
|
+
|
34
|
+
it "line=" do
|
35
|
+
@m.line = 12
|
36
|
+
@m.line.should == 12
|
37
|
+
end
|
38
|
+
|
39
|
+
it "file=" do
|
40
|
+
@m.file = "no_file.rb"
|
41
|
+
@m.file.should == "no_file.rb"
|
42
|
+
end
|
43
|
+
|
44
|
+
it "source=" do
|
45
|
+
@m.source = @m.source.sub("__FILE__", "__FILE__.to_s")
|
46
|
+
@m.source.should =~ /[__FILE__.to_s, __LINE__, __method__.to_s, self.class]/
|
47
|
+
@m.defining_class.name.should == MethodSpecFixture.name
|
48
|
+
m = @r.reflect MethodSpecFixture.instance_method(:source_location)
|
49
|
+
m.source.should =~ /[__FILE__.to_s, __LINE__, __method__.to_s, self.class]/
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "runtime behavior queries" do
|
54
|
+
def method_b(a, aa, b = 1, bb = 2, *args, &block)
|
55
|
+
to_s
|
56
|
+
super
|
57
|
+
end
|
58
|
+
|
59
|
+
before do
|
60
|
+
@m = @r.reflect(method(:method_b))
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "arguments" do
|
64
|
+
it "argument list" do
|
65
|
+
@m.arguments.should include("a", "aa", "b", "bb", "args", "block")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "block argument" do
|
69
|
+
@m.block_argument.should == "block"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "required arguments" do
|
73
|
+
@m.required_arguments.should include("a", "aa")
|
74
|
+
end
|
75
|
+
|
76
|
+
it "optional arguments" do
|
77
|
+
@m.optional_arguments.should include("b", "bb")
|
78
|
+
end
|
79
|
+
|
80
|
+
it "splat argument" do
|
81
|
+
@m.splat_argument.should == "args"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "step_locations" do
|
86
|
+
@m.step_offsets.each do |l|
|
87
|
+
l.should be_kind_of(Fixnum)
|
88
|
+
l.should < @m.source.length
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it "message sends and their offsets" do
|
93
|
+
@m.send_offsets.should be_kind_of(Hash)
|
94
|
+
@m.send_offsets.keys.should include "to_s"
|
95
|
+
@m.send_offsets.values.first.should be_kind_of(Fixnum)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "ast" do
|
99
|
+
pending
|
100
|
+
end
|
101
|
+
|
102
|
+
it "bytecodes" do
|
103
|
+
pending
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "protection" do
|
107
|
+
before do
|
108
|
+
@cm = @r.reflect(MethodSpecFixture)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "is public" do
|
112
|
+
m = @cm.method(:method_p_public)
|
113
|
+
m.public?.should.be_true
|
114
|
+
m.protected?.should.be_false
|
115
|
+
m.private?.should.be_false
|
116
|
+
end
|
117
|
+
|
118
|
+
it "is private" do
|
119
|
+
m = @cm.method(:method_p_private)
|
120
|
+
m.public?.should.be_false
|
121
|
+
m.protected?.should.be_false
|
122
|
+
m.private?.should.be_true
|
123
|
+
end
|
124
|
+
|
125
|
+
it "is protected" do
|
126
|
+
m = @cm.method(:method_p_protected)
|
127
|
+
m.public?.should.be_false
|
128
|
+
m.protected?.should.be_true
|
129
|
+
m.private?.should.be_false
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
it "returns native code if it was JITted" do
|
134
|
+
pending
|
135
|
+
end
|
136
|
+
|
137
|
+
it "returns average execution time" do
|
138
|
+
@m.execution_time_average.should be_kind_of(Time)
|
139
|
+
end
|
140
|
+
|
141
|
+
it "can return an approximation about the overall execution time it has been on the stack for" do
|
142
|
+
@m.execution_time.should be_kind_of(Time)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "returns how many percent of the total process' execution time this method was active" do
|
146
|
+
@m.execution_time_share.should be_kind_of(Number)
|
147
|
+
@m.execution_time_share.should < 1
|
148
|
+
@m.execution_time_share.should > 0
|
149
|
+
end
|
150
|
+
|
151
|
+
it "returns invocation count" do
|
152
|
+
ic = @m.invocation_count
|
153
|
+
MethodSpecFixture.new.send(@m.selector)
|
154
|
+
@m.invocation_count.should == (ic + 1)
|
155
|
+
end
|
156
|
+
|
157
|
+
it "can delete a method from its home class" do
|
158
|
+
c = MethodSpecFixture
|
159
|
+
m = @r.reflect c.instance_method(:removeable_method)
|
160
|
+
c.instance_methods(false).map(&:to_s).should include("removeable_method")
|
161
|
+
m.delete
|
162
|
+
c.instance_methods(false).map(&:to_s).should_not include("removeable_method")
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
data/spec/object_spec.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'fixtures/object_spec'
|
3
|
+
|
4
|
+
describe "ObjectMirror" do
|
5
|
+
before do
|
6
|
+
@r = reflection
|
7
|
+
end
|
8
|
+
|
9
|
+
before(:each) do
|
10
|
+
@o = ObjectFixture.new
|
11
|
+
@m = @r.reflect(@o)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can query instance variables" do
|
15
|
+
vars = @m.variables
|
16
|
+
vars.collect(&:name).should == ["@ivar"]
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'fixtures/reflect_spec'
|
3
|
+
|
4
|
+
describe Reflection do
|
5
|
+
it "returns the type of codebase it can work on" do
|
6
|
+
Reflection.codebase.should be_kind_of(Class)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "queries" do
|
10
|
+
before do
|
11
|
+
@r = reflection
|
12
|
+
end
|
13
|
+
|
14
|
+
it "finds known modules" do
|
15
|
+
modules = @r.modules.collect(&:name)
|
16
|
+
modules.should include("ReflectModule")
|
17
|
+
modules.should_not include("ReflectClass")
|
18
|
+
end
|
19
|
+
|
20
|
+
it "finds known classes" do
|
21
|
+
classes = @r.classes.collect(&:name)
|
22
|
+
classes.should include("ReflectClass")
|
23
|
+
classes.should_not include("ReflectModule")
|
24
|
+
end
|
25
|
+
|
26
|
+
it "finds known instances of something" do
|
27
|
+
class MyObj; end
|
28
|
+
class My2Obj < MyObj; end
|
29
|
+
a = MyObj.new
|
30
|
+
b = My2Obj.new
|
31
|
+
instances = @r.instances_of(MyObj).collect(&:name)
|
32
|
+
instances.should include(a.inspect)
|
33
|
+
instances.should_not include(b.inspect)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can get vm objects id" do
|
37
|
+
o = Object.new
|
38
|
+
@r.object_by_id(o.object_id).name.should == o.inspect
|
39
|
+
end
|
40
|
+
|
41
|
+
it "can find implementors of a method" do
|
42
|
+
l = @r.implementations_of("unique_reflect_fixture_method")
|
43
|
+
l.should be_kind_of Array
|
44
|
+
l.size.should == 1
|
45
|
+
l.first.selector.should == "unique_reflect_fixture_method"
|
46
|
+
l.first.defining_class.name.should == "ReflectClass"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "can find senders of a method" do
|
50
|
+
l = @r.senders_of("unique_reflect_sent_method")
|
51
|
+
l.should be_kind_of Array
|
52
|
+
l.size.should == 1
|
53
|
+
l.first.selector.should == "unique_reflect_fixture_method"
|
54
|
+
l.first.defining_class.name.should == "ReflectClass"
|
55
|
+
end
|
56
|
+
|
57
|
+
it "returns all available threads" do
|
58
|
+
t = Thread.start {}
|
59
|
+
@r.threads.collect(&:name).should include(t.inspect)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "reports a platform" do
|
63
|
+
@r.platform.should == RUBY_PLATFORM
|
64
|
+
end
|
65
|
+
|
66
|
+
it "reports a ruby implementation" do
|
67
|
+
@r.engine.should == RUBY_ENGINE
|
68
|
+
end
|
69
|
+
|
70
|
+
it "reports the implementation's version" do
|
71
|
+
@r.version.should == Object.const_get(:"#{RUBY_ENGINE.upcase}_VERSION")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
RUBY_ENGINE = 'ruby' unless defined? RUBY_ENGINE
|
2
|
+
mirror_api = ENV["MIRRORS"] || RUBY_ENGINE
|
3
|
+
mirror_api = 'rubinius' if mirror_api == 'rbx'
|
4
|
+
|
5
|
+
$:.push File.expand_path("..", __FILE__)
|
6
|
+
$:.push File.expand_path("../../lib", __FILE__)
|
7
|
+
|
8
|
+
require "#{mirror_api}/reflection"
|
9
|
+
include Object.const_get(mirror_api.capitalize)
|
10
|
+
|
11
|
+
require 'spec_helper/mspec_patch'
|
12
|
+
require 'spec_helper/multiple_reflections'
|
13
|
+
|
14
|
+
class PendingError < StandardError; end
|
15
|
+
MSpec.store :guarding_exceptions, [Reflection::CapabilitiesExceeded, PendingError]
|
16
|
+
def pending; raise PendingError; end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class GuardException
|
2
|
+
def initialize(example, exception)
|
3
|
+
@message = example && example.description || "<no description>"
|
4
|
+
@exception = exception
|
5
|
+
@method = exception.backtrace.first
|
6
|
+
end
|
7
|
+
|
8
|
+
def finish(*args)
|
9
|
+
print "Skipped '#{@message}'\n\t#{@exception}\n\tin #{@method}).\n\n"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module MSpec
|
14
|
+
class << self
|
15
|
+
alias mspec_protect protect
|
16
|
+
|
17
|
+
def protect(location, &block)
|
18
|
+
wrapped_block = proc do
|
19
|
+
begin
|
20
|
+
instance_eval(&block)
|
21
|
+
rescue *MSpec.retrieve(:guarding_exceptions)
|
22
|
+
MSpec.expectation
|
23
|
+
MSpec.register :finish, GuardException.new(MSpec.current.state, $!)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
mspec_protect(location, &wrapped_block)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
class Object
|
4
|
+
def reflection
|
5
|
+
map = { File => proc { Reflection.new("fixtures/reflect") },
|
6
|
+
NilClass => proc { Reflection.new(nil) },
|
7
|
+
URI => proc do
|
8
|
+
run_drb_vm
|
9
|
+
Reflection.new(URI::Generic.new("drb", "127.0.0.1", "9128"))
|
10
|
+
end }
|
11
|
+
map[Reflection.codebase][]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
data/spec/thread_spec.rb
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'fixtures/thread_spec'
|
3
|
+
|
4
|
+
describe "ThreadMirror" do
|
5
|
+
before(:each) do
|
6
|
+
@r = reflection
|
7
|
+
@t = Thread.start do
|
8
|
+
t = ThreadFixture.new
|
9
|
+
t.stop
|
10
|
+
t.return
|
11
|
+
end
|
12
|
+
@m = reflection.reflect(@t)
|
13
|
+
sleep 0.1 until @t.stop?
|
14
|
+
end
|
15
|
+
|
16
|
+
after(:each) do
|
17
|
+
@t.kill
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "should query" do
|
21
|
+
it "the thread state" do
|
22
|
+
@m.status.should == "sleep"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "the thread return value" do
|
26
|
+
@m.run
|
27
|
+
sleep 0.1 until @t.stop?
|
28
|
+
@m.return_value.should == ThreadFixture.new.return
|
29
|
+
end
|
30
|
+
|
31
|
+
it "the stack" do
|
32
|
+
@m.stack.collect(&:name).should include "stop"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "should manipulate" do
|
37
|
+
it "should be able to resume the thread" do
|
38
|
+
@m.run
|
39
|
+
sleep 0.1 while @t.status
|
40
|
+
@m.status.should == "dead"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should install exception blocks" do
|
45
|
+
@t = Thread.start do
|
46
|
+
t = ThreadFixture.new
|
47
|
+
t.stop
|
48
|
+
t.t_raise
|
49
|
+
end
|
50
|
+
@m = @r.reflect(@t)
|
51
|
+
handled = false
|
52
|
+
@m.handle_exception Exception do |e|
|
53
|
+
handled = true
|
54
|
+
end
|
55
|
+
@m.run
|
56
|
+
begin @t.join rescue RuntimeError end
|
57
|
+
handled.should == true
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should handle the right thread exception blocks" do
|
61
|
+
t1 = Thread.start do
|
62
|
+
t = ThreadFixture.new
|
63
|
+
t.stop
|
64
|
+
t.t_raise
|
65
|
+
end
|
66
|
+
t2 = Thread.start do
|
67
|
+
t = ThreadFixture.new
|
68
|
+
t.stop
|
69
|
+
t.t_raise
|
70
|
+
end
|
71
|
+
m1 = @r.reflect(t1)
|
72
|
+
m2 = @r.reflect(t2)
|
73
|
+
handled = false
|
74
|
+
m1.handle_exception Exception do |e|
|
75
|
+
handled = true
|
76
|
+
end
|
77
|
+
m2.run
|
78
|
+
begin t2.join rescue RuntimeError end
|
79
|
+
handled.should == false
|
80
|
+
m1.run
|
81
|
+
begin t1.join rescue RuntimeError end
|
82
|
+
handled.should == true
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should handle the many thread exception blocks" do
|
86
|
+
t1 = Thread.start do
|
87
|
+
t = ThreadFixture.new
|
88
|
+
t.stop
|
89
|
+
t.t_raise
|
90
|
+
end
|
91
|
+
t2 = Thread.start do
|
92
|
+
t = ThreadFixture.new
|
93
|
+
t.stop
|
94
|
+
t.t_raise
|
95
|
+
end
|
96
|
+
m1 = @r.reflect(t1)
|
97
|
+
m2 = @r.reflect(t2)
|
98
|
+
handles = []
|
99
|
+
m1.handle_exception Exception do |e|
|
100
|
+
handles << "m1"
|
101
|
+
end
|
102
|
+
m2.handle_exception Exception do |e|
|
103
|
+
handles << "m2"
|
104
|
+
end
|
105
|
+
m1.run
|
106
|
+
begin t1.join rescue RuntimeError end
|
107
|
+
handles.should include "m1"
|
108
|
+
handles.should_not include "m2"
|
109
|
+
m2.run
|
110
|
+
begin t2.join rescue RuntimeError end
|
111
|
+
handles.should include "m1"
|
112
|
+
handles.should include "m2"
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "implement shift/reset" do
|
116
|
+
it "can be used to return what you want" do
|
117
|
+
retval = @r.reflect(Thread.current).reset do
|
118
|
+
@r.reflect(Thread.current).shift {|cc| cc.call "shifted" } + " test"
|
119
|
+
end
|
120
|
+
|
121
|
+
retval.should == "shifted test"
|
122
|
+
end
|
123
|
+
|
124
|
+
it "can drop the continuation" do
|
125
|
+
retval = @r.reflect(Thread.current).reset do
|
126
|
+
@r.reflect(Thread.current).shift {|cc| 1 } + 1
|
127
|
+
end
|
128
|
+
|
129
|
+
retval.should == 1
|
130
|
+
end
|
131
|
+
|
132
|
+
it "can be run and re-run" do
|
133
|
+
retval = @r.reflect(Thread.current).reset do
|
134
|
+
@r.reflect(Thread.current).shift do |cc|
|
135
|
+
cc.call(cc.call(1))
|
136
|
+
end + 1
|
137
|
+
end
|
138
|
+
|
139
|
+
retval.should == 3
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|