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
@@ -0,0 +1,49 @@
|
|
1
|
+
module Ruby
|
2
|
+
class Reflection
|
3
|
+
class StackFrameMirror < Mirror
|
4
|
+
include AbstractReflection::StackFrameMirror
|
5
|
+
reflect! ThreadMirror::Frame
|
6
|
+
|
7
|
+
attr_reader :name
|
8
|
+
attr_reader :method
|
9
|
+
|
10
|
+
def initialize(obj)
|
11
|
+
super
|
12
|
+
@name = obj.method
|
13
|
+
@index = obj.index
|
14
|
+
@method = find_method_for(obj.file, obj.line)
|
15
|
+
@thread = obj.thread
|
16
|
+
end
|
17
|
+
|
18
|
+
def step_offset
|
19
|
+
@method.step_offsets.index(source_offset)
|
20
|
+
end
|
21
|
+
|
22
|
+
def source_offset
|
23
|
+
if next_frame = @thread.stack[@index - 1]
|
24
|
+
s = @method.send_offsets[next_frame.name]
|
25
|
+
end
|
26
|
+
s || raise(CapabilitiesExceeded)
|
27
|
+
end
|
28
|
+
|
29
|
+
def selector
|
30
|
+
@name
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
def find_method_for(file, line)
|
35
|
+
# Find all methods that are in the same file and start before
|
36
|
+
# or on the current line of execution
|
37
|
+
possible_methods = reflection.implementations_of(@name).select do |m|
|
38
|
+
f, l = m.send(:source_location)
|
39
|
+
f == file && l.to_i <= line.to_i
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sort by source location. The last method will be the method
|
43
|
+
# that starts closest to the current line of execution. This
|
44
|
+
# should (for most purposes) be the method we're looking for
|
45
|
+
possible_methods.sort_by {|m| m.send(:source_location).last }.last
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Modeled after Andrzej Filinski's article "Representing
|
3
|
+
# Monads" at POPL'94, and a Scheme implementation of it.
|
4
|
+
# http://citeseer.ist.psu.edu/filinski94representing.html
|
5
|
+
#
|
6
|
+
# Copyright 2004–2011 Christian Neukirchen
|
7
|
+
module ShiftReset
|
8
|
+
@@metacont = lambda do |x|
|
9
|
+
raise RuntimeError, "You forgot the top-level reset..."
|
10
|
+
end
|
11
|
+
|
12
|
+
def reset(&block)
|
13
|
+
mc = @@metacont
|
14
|
+
callcc do |k|
|
15
|
+
@@metacont = lambda do |v|
|
16
|
+
@@metacont = mc
|
17
|
+
k.call v
|
18
|
+
end
|
19
|
+
x = block.call
|
20
|
+
@@metacont.call x
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def shift(&block)
|
25
|
+
callcc do |k|
|
26
|
+
@@metacont.call block.call(lambda {|*v| reset { k.call *v } })
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'ruby/reflection/support/shift_reset'
|
2
|
+
require 'continuation' unless defined? callcc
|
3
|
+
|
4
|
+
module Ruby
|
5
|
+
class Reflection
|
6
|
+
class ThreadMirror < ObjectMirror
|
7
|
+
include AbstractReflection::ThreadMirror
|
8
|
+
include ShiftReset
|
9
|
+
reflect! Thread
|
10
|
+
Frame = Struct.new :method, :index, :file, :line, :thread
|
11
|
+
|
12
|
+
def status
|
13
|
+
s = @subject.status
|
14
|
+
if s.respond_to? :to_str
|
15
|
+
s.to_str
|
16
|
+
elsif s.nil?
|
17
|
+
"aborted"
|
18
|
+
else
|
19
|
+
"dead"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def run
|
24
|
+
@subject.run
|
25
|
+
end
|
26
|
+
|
27
|
+
def stack
|
28
|
+
if bt = @subject.backtrace
|
29
|
+
bt.each_with_index.collect do |str, idx|
|
30
|
+
file, line, method_spec = str.split(':')
|
31
|
+
method_spec =~ /\`([^']+)'/
|
32
|
+
method = $1
|
33
|
+
frame = Frame.new method, idx, file, line, self
|
34
|
+
reflection.reflect frame
|
35
|
+
end
|
36
|
+
else
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def return_value
|
42
|
+
return nil if @subject.alive?
|
43
|
+
@subject.value
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/rubymirrors.gemspec
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "rubymirrors"
|
3
|
+
s.version = "0.0.1"
|
4
|
+
s.platform = Gem::Platform::RUBY
|
5
|
+
s.authors = ["Tim Felgentreff"]
|
6
|
+
s.email = ["timfelgentreff@gmail.com"]
|
7
|
+
s.summary = "Mirror API for Ruby"
|
8
|
+
s.description = File.read(File.expand_path("../README.md", __FILE__))
|
9
|
+
s.files = `git ls-files`.split("\n")
|
10
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
11
|
+
s.require_paths = ["lib"]
|
12
|
+
end
|
data/spec/class_spec.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'fixtures/class_spec'
|
3
|
+
|
4
|
+
describe "ClassMirror" do
|
5
|
+
|
6
|
+
before do
|
7
|
+
@r = reflection
|
8
|
+
@m = reflection.reflect(ClassFixture)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "queries" do
|
12
|
+
it "name" do
|
13
|
+
@m.name.should == ClassFixture.name
|
14
|
+
end
|
15
|
+
|
16
|
+
it "known instance variables" do
|
17
|
+
names = @m.instance_variables.collect(&:name)
|
18
|
+
names.should include("@a", "@b")
|
19
|
+
end
|
20
|
+
|
21
|
+
it "known class variables" do
|
22
|
+
names = @m.class_variables.collect(&:name)
|
23
|
+
names.should include "@@cva"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "known class instance variables" do
|
27
|
+
names = @m.class_instance_variables.collect(&:name)
|
28
|
+
names.should include "@civa"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "known constants" do
|
32
|
+
names = @m.constants.collect(&:name)
|
33
|
+
names.should include "Foo"
|
34
|
+
end
|
35
|
+
|
36
|
+
it "can return a mirror on a particular constant" do
|
37
|
+
@m.constant("Foo").name.should == "Foo"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "can find a nested constant" do
|
41
|
+
cname = ClassFixture::ClassFixtureNested::ClassFixtureNestedNested.name
|
42
|
+
ct = @m.constant(cname)
|
43
|
+
ct.name.should == "ClassFixtureNestedNested"
|
44
|
+
ct.value.name.should == cname
|
45
|
+
end
|
46
|
+
|
47
|
+
it "known inner classes" do
|
48
|
+
@m.nested_classes.first.name.should == ClassFixture::ClassFixtureNested.name
|
49
|
+
end
|
50
|
+
|
51
|
+
it "known instance methods" do
|
52
|
+
@m.methods.size.should == ClassFixture.instance_methods(false).size
|
53
|
+
end
|
54
|
+
|
55
|
+
it "can return one particular method" do
|
56
|
+
n = ClassFixture.instance_methods.first
|
57
|
+
@m.method(n).mirrors?(ClassFixture.instance_method(n)).should == true
|
58
|
+
end
|
59
|
+
|
60
|
+
it "ancestors" do
|
61
|
+
ancestorsnames = [*ClassFixture.ancestors.collect(&:name)]
|
62
|
+
@m.ancestors.collect(&:name).should include *ancestorsnames
|
63
|
+
end
|
64
|
+
|
65
|
+
it "superclass" do
|
66
|
+
@m.superclass.name.should == ClassFixture.superclass.name
|
67
|
+
end
|
68
|
+
|
69
|
+
it "known subclasses" do
|
70
|
+
@m.subclasses.size.should == 1
|
71
|
+
end
|
72
|
+
|
73
|
+
it "mixins" do
|
74
|
+
@m.mixins.first.name.should == ClassFixtureModule.name
|
75
|
+
end
|
76
|
+
|
77
|
+
it "nesting" do
|
78
|
+
m = @r.reflect ClassFixture::ClassFixtureNested
|
79
|
+
nesting = m.nesting
|
80
|
+
nesting.should == [ClassFixture::ClassFixtureNested, ClassFixture]
|
81
|
+
end
|
82
|
+
|
83
|
+
it "source locations" do
|
84
|
+
@m.source_files.any? {|l| l =~ /spec\/class_spec.rb/ }.should.be_true
|
85
|
+
@m.source_files.any? {|l| l =~ /fixtures\/class_spec.rb/ }.should.be_true
|
86
|
+
end
|
87
|
+
|
88
|
+
it "value of a known constant" do
|
89
|
+
@m.constant("Foo").value.name.should == "Bar".inspect
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/spec/field_spec.rb
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
require File.expand_path('../spec_helper', __FILE__)
|
2
|
+
require 'fixtures/field_spec'
|
3
|
+
|
4
|
+
describe "FieldMirror" do
|
5
|
+
describe "variables", :shared => true do
|
6
|
+
it "reports the ivar name as name" do
|
7
|
+
@m.name.should == @nom
|
8
|
+
end
|
9
|
+
|
10
|
+
it "reports the var value" do
|
11
|
+
@m.value.name.should == @nom.sub(/@@?/, '').inspect
|
12
|
+
end
|
13
|
+
|
14
|
+
it "can change the value" do
|
15
|
+
old_value = @o.send(:"#{@class_side}_variable_get", @nom)
|
16
|
+
@m.value = "changed"
|
17
|
+
@o.send(:"#{@class_side}_variable_get", @nom).should == "changed"
|
18
|
+
@m.value = old_value
|
19
|
+
end
|
20
|
+
|
21
|
+
it "always shows the current value" do
|
22
|
+
@m.value.name.should == @nom.sub(/@@?/, '').inspect
|
23
|
+
@o.send(:"#{@class_side}_variable_set", @nom, "changed")
|
24
|
+
@m.value.name.should == "changed".inspect
|
25
|
+
end
|
26
|
+
|
27
|
+
it "reports vars as private only" do
|
28
|
+
@m.private?.should be_true
|
29
|
+
@m.protected?.should be_false
|
30
|
+
@m.public?.should be_false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "instance variables" do
|
35
|
+
before(:each) do
|
36
|
+
@o = FieldFixture.new
|
37
|
+
@om = reflection.reflect(@o)
|
38
|
+
@m = @om.variables.first
|
39
|
+
@nom = "@ivar"
|
40
|
+
@class_side = "instance"
|
41
|
+
end
|
42
|
+
|
43
|
+
it_behaves_like "variables", "instance variables"
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "class instance variables" do
|
47
|
+
before(:each) do
|
48
|
+
@o = FieldFixture
|
49
|
+
@om = reflection.reflect(@o)
|
50
|
+
@m = @om.variables.first
|
51
|
+
@nom = "@civar"
|
52
|
+
@class_side = "instance"
|
53
|
+
end
|
54
|
+
|
55
|
+
it_behaves_like "variables", "class instance variables"
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "class variables" do
|
59
|
+
before(:each) do
|
60
|
+
@o = FieldFixture
|
61
|
+
@om = reflection.reflect(@o)
|
62
|
+
@m = @om.class_variables.first
|
63
|
+
@nom = "@@cvar"
|
64
|
+
@class_side = "class"
|
65
|
+
end
|
66
|
+
|
67
|
+
it_behaves_like "variables", "class variables"
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "constants" do
|
71
|
+
before(:each) do
|
72
|
+
@o = FieldFixture
|
73
|
+
@om = reflection.reflect(@o)
|
74
|
+
@m = @om.constants.first
|
75
|
+
@name = "CONSTANT"
|
76
|
+
end
|
77
|
+
|
78
|
+
it "reports the constant name as name" do
|
79
|
+
@m.name.should == @name
|
80
|
+
end
|
81
|
+
|
82
|
+
it "reports the ivar value" do
|
83
|
+
@m.value.name.should == @name.downcase.inspect
|
84
|
+
end
|
85
|
+
|
86
|
+
it "can change the value" do
|
87
|
+
old_value = @m.value.reflectee
|
88
|
+
@m.value = "changed"
|
89
|
+
@o.const_get(@name).should == "changed"
|
90
|
+
@m.value = old_value
|
91
|
+
end
|
92
|
+
|
93
|
+
it "always shows the current value" do
|
94
|
+
@m.value.name.should == @name.downcase.inspect
|
95
|
+
@o.const_set(@name, "changed")
|
96
|
+
@m.value.name.should == "changed".inspect
|
97
|
+
end
|
98
|
+
|
99
|
+
it "reports constants as public" do
|
100
|
+
@m.private?.should be_false
|
101
|
+
@m.protected?.should be_false
|
102
|
+
@m.public?.should be_true
|
103
|
+
end
|
104
|
+
|
105
|
+
it "can delete a constant" do
|
106
|
+
@m.delete
|
107
|
+
@om.constants.should_not include @m
|
108
|
+
|
109
|
+
@m = @om.reflectee.const_set(@m.name, @name)
|
110
|
+
end
|
111
|
+
|
112
|
+
it "can add a constant" do
|
113
|
+
cst = @om.constant("MyNewlyAddedConstant")
|
114
|
+
@om.constants.collect(&:name).should_not include("MyNewlyAddedConstant")
|
115
|
+
cst.value = "MyNewlyAddedConstant"
|
116
|
+
@om.constants.collect(&:name).should include("MyNewlyAddedConstant")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module ClassFixtureModule
|
2
|
+
end
|
3
|
+
|
4
|
+
class ClassFixture
|
5
|
+
Foo = "Bar"
|
6
|
+
|
7
|
+
class ClassFixtureNested
|
8
|
+
class ClassFixtureNestedNested
|
9
|
+
end
|
10
|
+
end
|
11
|
+
include ClassFixtureModule
|
12
|
+
|
13
|
+
attr_accessor :b
|
14
|
+
def a
|
15
|
+
@a = 1
|
16
|
+
@@cvb = 1
|
17
|
+
end
|
18
|
+
|
19
|
+
@@cva = 1
|
20
|
+
@civa = 1
|
21
|
+
|
22
|
+
def self.b
|
23
|
+
@@cvc = 1
|
24
|
+
@civb = 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class ClassFixtureSubclass < ClassFixture; end
|
29
|
+
class ClassFixtureSubclassSubclass < ClassFixtureSubclass; end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class MethodSpecFixture
|
2
|
+
def source_location
|
3
|
+
[__FILE__, __LINE__, __method__.to_s, self.class]
|
4
|
+
end
|
5
|
+
|
6
|
+
def removeable_method
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_p_public; end
|
10
|
+
def method_p_private; end
|
11
|
+
private :method_p_private
|
12
|
+
def method_p_protected; end
|
13
|
+
protected :method_p_protected
|
14
|
+
end
|