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,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
@@ -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
@@ -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
@@ -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,9 @@
1
+ class FieldFixture
2
+ attr_accessor :ivar
3
+ def initialize
4
+ @ivar = "ivar"
5
+ end
6
+ CONSTANT = "constant"
7
+ @@cvar = "cvar"
8
+ @civar = "civar"
9
+ 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
@@ -0,0 +1,5 @@
1
+ class ObjectFixture
2
+ def initialize
3
+ @ivar = "ivar"
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+
2
+ class ReflectClass
3
+ def unique_reflect_fixture_method
4
+ unique_reflect_sent_method
5
+ end
6
+
7
+ def unique_reflect_sent_method
8
+ end
9
+ end
10
+
11
+ module ReflectModule
12
+ end
13
+
14
+ reflect_string = "string"
@@ -0,0 +1,5 @@
1
+ class FrameFixture
2
+ def my_stop(argument); local = "local_value"; Thread.stop; end
3
+ def my_return; 2; end
4
+ def my_raise; raise "stop"; end
5
+ end
@@ -0,0 +1,5 @@
1
+ class ThreadFixture
2
+ def stop; Thread.stop; end
3
+ def return; 2; end
4
+ def t_raise; raise "stop"; end
5
+ end