rubymirrors 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/Gemfile +7 -0
  2. data/README.md +30 -0
  3. data/Rakefile +13 -0
  4. data/lib/abstract_reflection.rb +112 -0
  5. data/lib/abstract_reflection/class_mirror.rb +150 -0
  6. data/lib/abstract_reflection/compiler_mirror.rb +31 -0
  7. data/lib/abstract_reflection/field_mirror.rb +35 -0
  8. data/lib/abstract_reflection/gc_mirror.rb +19 -0
  9. data/lib/abstract_reflection/method_mirror.rb +253 -0
  10. data/lib/abstract_reflection/mirror.rb +108 -0
  11. data/lib/abstract_reflection/object_mirror.rb +48 -0
  12. data/lib/abstract_reflection/stack_frame_mirror.rb +61 -0
  13. data/lib/abstract_reflection/thread_mirror.rb +64 -0
  14. data/lib/maglev/reflection.rb +49 -0
  15. data/lib/maglev/reflection/class_mirror.rb +157 -0
  16. data/lib/maglev/reflection/core_ext/class_organizer.rb +20 -0
  17. data/lib/maglev/reflection/core_ext/maglev.rb +5 -0
  18. data/lib/maglev/reflection/core_ext/method.rb +154 -0
  19. data/lib/maglev/reflection/core_ext/module.rb +41 -0
  20. data/lib/maglev/reflection/core_ext/object.rb +4 -0
  21. data/lib/maglev/reflection/core_ext/thread.rb +226 -0
  22. data/lib/maglev/reflection/field_mirror.rb +39 -0
  23. data/lib/maglev/reflection/field_mirror/fixed_instance_variable_mirror.rb +25 -0
  24. data/lib/maglev/reflection/method_mirror.rb +149 -0
  25. data/lib/maglev/reflection/mirror.rb +6 -0
  26. data/lib/maglev/reflection/object_mirror.rb +18 -0
  27. data/lib/maglev/reflection/stack_frame_mirror.rb +104 -0
  28. data/lib/maglev/reflection/thread_mirror.rb +116 -0
  29. data/lib/rubinius/reflection.rb +6 -0
  30. data/lib/ruby/reflection.rb +74 -0
  31. data/lib/ruby/reflection/class_mirror.rb +89 -0
  32. data/lib/ruby/reflection/field_mirror.rb +32 -0
  33. data/lib/ruby/reflection/field_mirror/class_variable_mirror.rb +25 -0
  34. data/lib/ruby/reflection/field_mirror/constant_mirror.rb +36 -0
  35. data/lib/ruby/reflection/field_mirror/instance_variable_mirror.rb +25 -0
  36. data/lib/ruby/reflection/method_mirror.rb +122 -0
  37. data/lib/ruby/reflection/mirror.rb +12 -0
  38. data/lib/ruby/reflection/object_mirror.rb +25 -0
  39. data/lib/ruby/reflection/stack_frame_mirror.rb +49 -0
  40. data/lib/ruby/reflection/support/shift_reset.rb +29 -0
  41. data/lib/ruby/reflection/thread_mirror.rb +47 -0
  42. data/rubymirrors.gemspec +12 -0
  43. data/spec/class_spec.rb +92 -0
  44. data/spec/field_spec.rb +119 -0
  45. data/spec/fixtures/class_spec.rb +29 -0
  46. data/spec/fixtures/field_spec.rb +9 -0
  47. data/spec/fixtures/method_spec.rb +14 -0
  48. data/spec/fixtures/object_spec.rb +5 -0
  49. data/spec/fixtures/reflect_spec.rb +14 -0
  50. data/spec/fixtures/stack_frame_spec.rb +5 -0
  51. data/spec/fixtures/thread_spec.rb +5 -0
  52. data/spec/frame_spec.rb +80 -0
  53. data/spec/method_spec.rb +166 -0
  54. data/spec/object_spec.rb +18 -0
  55. data/spec/reflection_spec.rb +74 -0
  56. data/spec/spec_helper.rb +16 -0
  57. data/spec/spec_helper/mspec_patch.rb +29 -0
  58. data/spec/spec_helper/multiple_reflections.rb +14 -0
  59. data/spec/thread_spec.rb +142 -0
  60. metadata +173 -0
@@ -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
@@ -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
@@ -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
@@ -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
+
@@ -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