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,108 @@
|
|
1
|
+
module AbstractReflection
|
2
|
+
# The basic mirror. This is the lib code. It is also the factory to
|
3
|
+
# use for creating new mirrors on any kind of object. Its #reflect
|
4
|
+
# class method will return an appropriate mirror for a given object,
|
5
|
+
# provided one has been registered. The [ObjectMirror] class should
|
6
|
+
# have been registered as the fallback case for any kind of object,
|
7
|
+
# but that may depend on the specific API implementation.
|
8
|
+
module Mirror
|
9
|
+
module ClassMethods
|
10
|
+
@@mirrors = []
|
11
|
+
|
12
|
+
# Reflect on the passed object. This is the default factory for
|
13
|
+
# creating new mirrors, and it will try and find the appropriate
|
14
|
+
# mirror from the list of registered mirrors.
|
15
|
+
#
|
16
|
+
# @param [Object] the object to reflect upon. This need not be the
|
17
|
+
# actual object represented - it can itself be just a
|
18
|
+
# representation. It is really up to the mirror to decide what to
|
19
|
+
# do with it
|
20
|
+
# @param [Reflection] the instance of a Reflection this mirror was
|
21
|
+
# spawned in.
|
22
|
+
def reflect(obj, reflection)
|
23
|
+
target_mirror = nil
|
24
|
+
@@mirrors.detect {|klass| target_mirror = klass.mirror_class(obj) }
|
25
|
+
raise CapabilitiesExceeded if target_mirror.nil?
|
26
|
+
target_mirror.new(obj, reflection)
|
27
|
+
end
|
28
|
+
|
29
|
+
# The constructor, sets the @reflection instance variable before
|
30
|
+
# calling initialize.
|
31
|
+
def new(obj, reflection)
|
32
|
+
basic_new_object = allocate
|
33
|
+
basic_new_object.reflection = reflection
|
34
|
+
basic_new_object.send(:initialize, obj)
|
35
|
+
basic_new_object
|
36
|
+
end
|
37
|
+
|
38
|
+
# Decides whether the given class can reflect on [obj]
|
39
|
+
# @param [Object] the object to reflect upon
|
40
|
+
# @return [true, false]
|
41
|
+
def reflects?(obj)
|
42
|
+
@reflected_modules.any? { |mod| mod === obj }
|
43
|
+
end
|
44
|
+
|
45
|
+
# A shortcut to define reflects? behavior.
|
46
|
+
# @param [Module] the module whose instances this mirror reflects
|
47
|
+
def reflect!(*modules)
|
48
|
+
@reflected_modules = modules
|
49
|
+
register_mirror self
|
50
|
+
end
|
51
|
+
|
52
|
+
# Some objects may be more useful with a specialized kind of
|
53
|
+
# mirror. This method can be used to register new mirror
|
54
|
+
# classes. If used within a module, each class that includes
|
55
|
+
# that specific module is registered upon inclusion.
|
56
|
+
#
|
57
|
+
# @param [Module] The class or module to register
|
58
|
+
#
|
59
|
+
# @return [Mirror] returns self
|
60
|
+
def register_mirror(klass)
|
61
|
+
@@mirrors.unshift klass
|
62
|
+
@@mirrors.uniq!
|
63
|
+
self
|
64
|
+
end
|
65
|
+
|
66
|
+
# @param [Object] the object to reflect upon
|
67
|
+
#
|
68
|
+
# @return [Mirror, NilClass] the class to instantiate as mirror,
|
69
|
+
# using #new, or nil, if non is known
|
70
|
+
def mirror_class(obj)
|
71
|
+
self if reflects?(obj)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Only define this once, and always get the ClassMethods from
|
75
|
+
# the current module. When [Mirror] is included in another
|
76
|
+
# module, this will enable that module to also define ClassMethods
|
77
|
+
# to mix in when included. Additionally, if [Mirror] had registered
|
78
|
+
# itself for matching specific objects, this registration is forwarded
|
79
|
+
# to the class.
|
80
|
+
def included(base)
|
81
|
+
base.extend(const_get("ClassMethods")) if const_defined?("ClassMethods")
|
82
|
+
base.const_set(:CapabilitiesExceeded, CapabilitiesExceeded)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
extend ClassMethods
|
87
|
+
attr_accessor :reflection
|
88
|
+
|
89
|
+
def initialize(obj)
|
90
|
+
@subject = obj
|
91
|
+
end
|
92
|
+
|
93
|
+
# A generic representation of the object under observation.
|
94
|
+
def name
|
95
|
+
@subject.inspect
|
96
|
+
end
|
97
|
+
|
98
|
+
# The equivalent to #==/#eql? for comparison of mirrors against objects
|
99
|
+
def mirrors?(other)
|
100
|
+
@subject == other
|
101
|
+
end
|
102
|
+
|
103
|
+
# Accessor to the reflected object
|
104
|
+
def reflectee
|
105
|
+
@subject
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module AbstractReflection
|
2
|
+
# A mirror class. It is the most generic mirror and should be able
|
3
|
+
# to reflect on any object you can get at in a given system.
|
4
|
+
module ObjectMirror
|
5
|
+
include Mirror
|
6
|
+
|
7
|
+
# @return [FieldMirror] the instance variables of the object
|
8
|
+
def variables
|
9
|
+
raise CapabilitiesExceeded
|
10
|
+
end
|
11
|
+
|
12
|
+
# @return [FieldMirror] the class variables of the object or its class
|
13
|
+
def class_variables
|
14
|
+
raise CapabilitiesExceeded
|
15
|
+
end
|
16
|
+
|
17
|
+
# @return [ClassMirror] the a class mirror on the runtime class object
|
18
|
+
def target_class
|
19
|
+
raise CapabilitiesExceeded
|
20
|
+
end
|
21
|
+
|
22
|
+
# Searches the system for other objects that have references to
|
23
|
+
# this one.
|
24
|
+
#
|
25
|
+
# @return [Array<ObjectMirror>]
|
26
|
+
def objects_with_references
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns the transitive closure (the full object tree under this
|
30
|
+
# object, without duplicates).
|
31
|
+
#
|
32
|
+
# @return [Hash<ObjectMirror => Hash<...,...>>] nested hashes
|
33
|
+
def transitive_closure
|
34
|
+
end
|
35
|
+
|
36
|
+
# Searches for a reference path from this object to another given
|
37
|
+
# object.
|
38
|
+
#
|
39
|
+
# @return [Array<ObjectMirror>, NilClass] the object path or nil, if none
|
40
|
+
def path_to(obj)
|
41
|
+
end
|
42
|
+
|
43
|
+
# The instance_eval known from Ruby. Should return the result or a
|
44
|
+
# representation thereof.
|
45
|
+
def instance_eval
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module AbstractReflection
|
2
|
+
module StackFrameMirror
|
3
|
+
include Mirror
|
4
|
+
|
5
|
+
def restart
|
6
|
+
raise CapabilitiesExceeded
|
7
|
+
end
|
8
|
+
|
9
|
+
def pop
|
10
|
+
raise CapabilitiesExceeded
|
11
|
+
end
|
12
|
+
|
13
|
+
def step(length = :over)
|
14
|
+
raise CapabilitiesExceeded
|
15
|
+
end
|
16
|
+
|
17
|
+
def receiver
|
18
|
+
raise CapabilitiesExceeded
|
19
|
+
end
|
20
|
+
|
21
|
+
def self
|
22
|
+
raise CapabilitiesExceeded
|
23
|
+
end
|
24
|
+
|
25
|
+
def selector
|
26
|
+
raise CapabilitiesExceeded
|
27
|
+
end
|
28
|
+
|
29
|
+
def ip_offset
|
30
|
+
raise CapabilitiesExceeded
|
31
|
+
end
|
32
|
+
|
33
|
+
def step_offset
|
34
|
+
raise CapabilitiesExceeded
|
35
|
+
end
|
36
|
+
|
37
|
+
def source_offset
|
38
|
+
raise CapabilitiesExceeded
|
39
|
+
end
|
40
|
+
|
41
|
+
def arguments
|
42
|
+
raise CapabilitiesExceeded
|
43
|
+
end
|
44
|
+
|
45
|
+
def locals
|
46
|
+
raise CapabilitiesExceeded
|
47
|
+
end
|
48
|
+
|
49
|
+
def variable_context
|
50
|
+
raise CapabilitiesExceeded
|
51
|
+
end
|
52
|
+
|
53
|
+
def binding
|
54
|
+
raise CapabilitiesExceeded
|
55
|
+
end
|
56
|
+
|
57
|
+
def method
|
58
|
+
raise CapabilitiesExceeded
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module AbstractReflection
|
2
|
+
module ThreadMirror
|
3
|
+
include Mirror
|
4
|
+
|
5
|
+
def stop
|
6
|
+
raise CapabilitiesExceeded
|
7
|
+
end
|
8
|
+
|
9
|
+
def run
|
10
|
+
raise CapabilitiesExceeded
|
11
|
+
end
|
12
|
+
|
13
|
+
def kill
|
14
|
+
raise CapabilitiesExceeded
|
15
|
+
end
|
16
|
+
|
17
|
+
def return_value
|
18
|
+
raise CapabilitiesExceeded
|
19
|
+
end
|
20
|
+
|
21
|
+
def status
|
22
|
+
raise CapabilitiesExceeded
|
23
|
+
end
|
24
|
+
|
25
|
+
def stack
|
26
|
+
raise CapabilitiesExceeded
|
27
|
+
end
|
28
|
+
|
29
|
+
def step(length = :over)
|
30
|
+
raise CapabilitiesExceeded
|
31
|
+
end
|
32
|
+
|
33
|
+
def breakpoints
|
34
|
+
raise CapabilitiesExceeded
|
35
|
+
end
|
36
|
+
|
37
|
+
def thread_data
|
38
|
+
raise CapabilitiesExceeded
|
39
|
+
end
|
40
|
+
|
41
|
+
def compiler
|
42
|
+
raise CapabilitiesExceeded
|
43
|
+
end
|
44
|
+
|
45
|
+
# Installs an exception block in the thread. This is no rescue,
|
46
|
+
# the block will be executed for the given exception type, but it
|
47
|
+
# will not prevent the exception from propagating through the
|
48
|
+
# thread.
|
49
|
+
#
|
50
|
+
# @param [Exception, Array<Exception>] the exception(s) to rescue
|
51
|
+
# @param [Block] the exception handler
|
52
|
+
def handle_exception(e = Exception, &block)
|
53
|
+
raise CapabilitiesExceeded
|
54
|
+
end
|
55
|
+
|
56
|
+
def reset
|
57
|
+
raise CapabilitiesExceeded
|
58
|
+
end
|
59
|
+
|
60
|
+
def shift
|
61
|
+
raise CapabilitiesExceeded
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'ruby/reflection'
|
2
|
+
require 'maglev/reflection/core_ext/class_organizer'
|
3
|
+
|
4
|
+
module Maglev
|
5
|
+
class Reflection < Ruby::Reflection
|
6
|
+
def modules
|
7
|
+
mirror_modules_satisfying {|m| Module === m && !(Class === m) }
|
8
|
+
end
|
9
|
+
|
10
|
+
def classes
|
11
|
+
mirror_modules_satisfying {|m| Class === m }
|
12
|
+
end
|
13
|
+
|
14
|
+
def implementations_of(str)
|
15
|
+
if sym = Symbol.__existing_symbol(str.to_s)
|
16
|
+
class_list = ClassOrganizer.cached_organizer.implementors_of sym
|
17
|
+
class_list.collect {|cls| self.reflect(cls).method sym }
|
18
|
+
else
|
19
|
+
[]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def senders_of(str)
|
24
|
+
if sym = Symbol.__existing_symbol(str.to_s)
|
25
|
+
meth_list = ClassOrganizer.cached_organizer.senders_of sym
|
26
|
+
meth_list.collect do |m|
|
27
|
+
self.reflect(m.__in_class).method m.__name
|
28
|
+
end
|
29
|
+
else
|
30
|
+
[]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def mirror_modules_satisfying
|
36
|
+
modules = self.reflect(Object).each_module
|
37
|
+
modules = modules.select {|m| yield m }
|
38
|
+
modules.collect {|m| self.reflect m }
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
require 'maglev/reflection/mirror'
|
44
|
+
require 'maglev/reflection/object_mirror'
|
45
|
+
require 'maglev/reflection/field_mirror'
|
46
|
+
require 'maglev/reflection/thread_mirror'
|
47
|
+
require 'maglev/reflection/stack_frame_mirror'
|
48
|
+
require 'maglev/reflection/class_mirror'
|
49
|
+
require 'maglev/reflection/method_mirror'
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'maglev/reflection/core_ext/module'
|
2
|
+
|
3
|
+
module Maglev
|
4
|
+
class Reflection
|
5
|
+
class ClassMirror < ObjectMirror
|
6
|
+
include AbstractReflection::ClassMirror
|
7
|
+
reflect! Module
|
8
|
+
|
9
|
+
def singleton_instance
|
10
|
+
raise TypeError, "not a singleton class" unless self.singleton_class?
|
11
|
+
if self.inspect =~ /^#<Class:.*>$/
|
12
|
+
|
13
|
+
else
|
14
|
+
raise NotImplementedError, "not implemented yet"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def singleton_class
|
19
|
+
reflection.reflect @subject.singleton_class
|
20
|
+
end
|
21
|
+
|
22
|
+
def singleton_class?
|
23
|
+
self.name =~ /^\#<Class:.*>$/
|
24
|
+
end
|
25
|
+
|
26
|
+
def compile_method(source, selector = nil)
|
27
|
+
meth_dict = instance_methods(false) + methods(false)
|
28
|
+
if selector || (md = /^\s*def\s+(?:self\.)?([^;\( \n]+)/.match(source))
|
29
|
+
selector = selector || md[1]
|
30
|
+
begin
|
31
|
+
method(selector).source!(source, true)
|
32
|
+
rescue NameError, TypeError
|
33
|
+
class_eval(source)
|
34
|
+
end
|
35
|
+
else
|
36
|
+
class_eval(source)
|
37
|
+
end
|
38
|
+
new_meth_dict = instance_methods(false) + methods(false)
|
39
|
+
new_method_selector = if new_meth_dict > meth_dict
|
40
|
+
(new_meth_dict - meth_dict).first
|
41
|
+
else
|
42
|
+
selector
|
43
|
+
end
|
44
|
+
method(new_method_selector) if new_method_selector
|
45
|
+
end
|
46
|
+
|
47
|
+
def instance_variables
|
48
|
+
if (fixed_ivs = @subject.__inst_var_names).empty?
|
49
|
+
raise AbstractReflection::CapabilitiesExceeded
|
50
|
+
else
|
51
|
+
field_mirrors fixed_ivs
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def class_variables
|
56
|
+
field_mirrors @subject.class_variables
|
57
|
+
end
|
58
|
+
|
59
|
+
def class_instance_variables
|
60
|
+
field_mirrors @subject.instance_variables
|
61
|
+
end
|
62
|
+
|
63
|
+
def nested_classes
|
64
|
+
constants.collect(&:value).select {|c| ClassMirror === c }
|
65
|
+
end
|
66
|
+
|
67
|
+
def source_files
|
68
|
+
method_objects = @subject.instance_methods(false).collect do |name|
|
69
|
+
@subject.instance_method(name)
|
70
|
+
end
|
71
|
+
method_objects += @subject.methods(false).collect do |name|
|
72
|
+
@subject.method(name)
|
73
|
+
end
|
74
|
+
method_objects.collect(&:source_location).collect(&:first).uniq
|
75
|
+
end
|
76
|
+
|
77
|
+
def mixins
|
78
|
+
mirrors @subject.ancestors.reject {|m| m.is_a? Class }
|
79
|
+
end
|
80
|
+
|
81
|
+
def superclass
|
82
|
+
self.class.new @subject.superclass
|
83
|
+
end
|
84
|
+
|
85
|
+
def subclasses
|
86
|
+
ary = []
|
87
|
+
each_module do |m|
|
88
|
+
ary << m if m.superclass && m.superclass.mirrors?(@subject)
|
89
|
+
end
|
90
|
+
ary
|
91
|
+
end
|
92
|
+
|
93
|
+
def ancestors
|
94
|
+
mirrors @subject.ancestors
|
95
|
+
end
|
96
|
+
|
97
|
+
def constant(str)
|
98
|
+
path = str.to_s.split("::")
|
99
|
+
c = path[0..-2].inject(@subject) {|klass,str| klass.const_get(str) }
|
100
|
+
field_mirror c, path.last
|
101
|
+
rescue NameError
|
102
|
+
nil
|
103
|
+
end
|
104
|
+
|
105
|
+
def constants
|
106
|
+
field_mirrors (@subject.constants - @subject.instance_variables)
|
107
|
+
end
|
108
|
+
|
109
|
+
def method(name)
|
110
|
+
reflection.reflect @subject.instance_method(name.to_s)
|
111
|
+
end
|
112
|
+
|
113
|
+
def methods
|
114
|
+
@subject.instance_methods(false)
|
115
|
+
end
|
116
|
+
|
117
|
+
def nesting
|
118
|
+
ary = [@subject]
|
119
|
+
while (ns = ary.last.__transient_namespace(1)) &&
|
120
|
+
(par = ns.parent) &&
|
121
|
+
(nxt = par.my_class)
|
122
|
+
break if nxt.nil? || nxt == Object
|
123
|
+
ary << nxt
|
124
|
+
end
|
125
|
+
ary
|
126
|
+
end
|
127
|
+
|
128
|
+
# Maglev specific, not public reflection API.
|
129
|
+
#
|
130
|
+
# Traverse the Ruby namespace hierarchy and execute block for
|
131
|
+
# all classes and modules. Returns an IdentitySet of all
|
132
|
+
# classes and modules found. Skips autoloads (i.e., does not
|
133
|
+
# trigger them and does not yield them to the block).
|
134
|
+
#
|
135
|
+
# @param [Module] klass The Class or Module object to start traversal.
|
136
|
+
# Default is Object.
|
137
|
+
#
|
138
|
+
# @param [IdentitySet] rg The recursion guard used to prevent infinite
|
139
|
+
# loops; also used as return value.
|
140
|
+
#
|
141
|
+
# @return [IdentitySet] An IdentitySet of all the Classes and Modules
|
142
|
+
# registered in the Ruby namespace
|
143
|
+
#
|
144
|
+
def each_module(from=Object, rg=IdentitySet.new, &block)
|
145
|
+
unless rg.include?(from)
|
146
|
+
rg.add from
|
147
|
+
yield reflection.reflect(from) if block
|
148
|
+
if ns = from.__transient_namespace(1)
|
149
|
+
ns.values.each {|c| each_module(c, rg, &block) if Module === c }
|
150
|
+
end
|
151
|
+
end
|
152
|
+
rg
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|