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