rubymirrors 0.0.1 → 0.0.2
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/lib/abstract_reflection/method_mirror.rb +2 -2
- data/lib/maglev/reflection/class_mirror.rb +1 -0
- data/lib/maglev/reflection/core_ext/class.rb +3 -0
- data/lib/maglev/reflection/core_ext/exception.rb +3 -0
- data/lib/maglev/reflection/core_ext/method.rb +5 -0
- data/lib/maglev/reflection/core_ext/module.rb +0 -1
- data/lib/maglev/reflection/core_ext/proc.rb +21 -0
- data/lib/maglev/reflection/core_ext/thread.rb +9 -2
- data/lib/maglev/reflection/field_mirror/fixed_instance_variable_mirror.rb +1 -0
- data/lib/maglev/reflection/method_mirror.rb +22 -0
- data/lib/maglev/reflection/support/partial_continuation.rb +50 -0
- data/lib/ruby/reflection/method_mirror.rb +25 -2
- data/rubymirrors.gemspec +1 -1
- metadata +67 -53
@@ -16,7 +16,7 @@ module AbstractReflection
|
|
16
16
|
def defining_class
|
17
17
|
raise CapabilitiesExceeded
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
# @return [String] The source code of this method
|
21
21
|
def source
|
22
22
|
raise CapabilitiesExceeded
|
@@ -39,7 +39,7 @@ module AbstractReflection
|
|
39
39
|
|
40
40
|
# Queries the method for it's arguments and returns a list of
|
41
41
|
# mirrors that hold name and value information.
|
42
|
-
#
|
42
|
+
#
|
43
43
|
# @return [Array<FieldMirror>]
|
44
44
|
def arguments
|
45
45
|
raise CapabilitiesExceeded
|
@@ -15,9 +15,14 @@ class GsNMethod
|
|
15
15
|
primitive '__ip_steps', '_ipSteps'
|
16
16
|
primitive '__opcode_info_at', '_opcodeInfoAt:'
|
17
17
|
primitive '__in_class', 'inClass'
|
18
|
+
primitive '__all_breakpoints_source_offsets', '_allBreakpointsSourceOffsets'
|
19
|
+
primitive '__set_break_at', 'setBreakAtStepPoint:'
|
20
|
+
primitive '__clear_break_at', 'clearBreakAtStepPoint:'
|
18
21
|
end
|
19
22
|
|
20
23
|
class UnboundMethod
|
24
|
+
primitive '__nonbridge_meth', '_nonBridgeMeth'
|
25
|
+
|
21
26
|
def __st_gsmeth
|
22
27
|
@_st_gsmeth
|
23
28
|
end
|
@@ -37,5 +37,4 @@ class Module
|
|
37
37
|
primitive '__inst_var_names', 'instVarNames'
|
38
38
|
primitive '__compile_method_category_environment_id', 'compileMethod:category:environmentId:'
|
39
39
|
primitive '__compile_method_category_environment_id', 'compileMethod:category:environmentId:'
|
40
|
-
primitive '__subclasses', 'subclasses'
|
41
40
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.expand_path("../method.rb", __FILE__)
|
2
|
+
require File.expand_path("../thread.rb", __FILE__)
|
3
|
+
|
4
|
+
class ExecBlock
|
5
|
+
primitive 'shift', 'shift'
|
6
|
+
primitive 'reset', 'reset'
|
7
|
+
end
|
8
|
+
|
9
|
+
class Proc
|
10
|
+
def __shift
|
11
|
+
@_st_block.shift
|
12
|
+
end
|
13
|
+
|
14
|
+
def __reset
|
15
|
+
@_st_block.reset
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Thread
|
20
|
+
primitive 'call', 'call:'
|
21
|
+
end
|
@@ -13,7 +13,8 @@ class Thread
|
|
13
13
|
# Remove all frames above [Fixnum]
|
14
14
|
primitive '__trim_stack_to_level', '_trimStackToLevel:'
|
15
15
|
# Change temporary at level to value
|
16
|
-
primitive '
|
16
|
+
primitive '__frame_at_temp_at_put', '_frameAt:tempAt:put:'
|
17
|
+
primitive '__frame_at_offset_of_temp_named', '_frameAt:offsetOfTempNamed:'
|
17
18
|
# => Array
|
18
19
|
# with:
|
19
20
|
# 1 gsMethod
|
@@ -33,7 +34,7 @@ class Thread
|
|
33
34
|
primitive 'convert_to_persistable_state', "convertToPersistableState"
|
34
35
|
primitive 'convert_to_runnable_state', 'convertToRunnableState'
|
35
36
|
primitive '__ar_stack', 'arStack'
|
36
|
-
primitive '__client_data', '
|
37
|
+
primitive '__client_data', 'clientData'
|
37
38
|
# Private. Returns an Array describing the specified level in the receiver.
|
38
39
|
# aLevel == 1 is top of stack. If aLevel is less than 1 or greater than
|
39
40
|
# stackDepth, returns nil.
|
@@ -62,6 +63,12 @@ class Thread
|
|
62
63
|
|
63
64
|
class_primitive '__installPartialContinuation_atLevel_value', 'installPartialContinuation:atLevel:value:'
|
64
65
|
class_primitive '__partialContinuationFromLevel_to', 'partialContinuationFromLevel:to:'
|
66
|
+
|
67
|
+
# Re-add behavior which was removed in GS 3.1.0.1
|
68
|
+
def __frame_at_temp_named_put(frameidx, tempname, value)
|
69
|
+
offset = __frame_at_offset_of_temp_named(frameidx, tempname)
|
70
|
+
__frame_at_temp_at_put(frameidx, offset, value)
|
71
|
+
end
|
65
72
|
end
|
66
73
|
|
67
74
|
# require 'maglev/objectlog'
|
@@ -113,7 +113,29 @@ module Maglev
|
|
113
113
|
gsmeth.__in_class.remove_method(selector)
|
114
114
|
end
|
115
115
|
|
116
|
+
def breakpoints
|
117
|
+
gsmeth.__all_breakpoints_source_offsets
|
118
|
+
end
|
119
|
+
|
120
|
+
def break(source_offset = 1)
|
121
|
+
step_point = find_step_point_just_before(source_offset)
|
122
|
+
if gsmeth.__is_method_for_block
|
123
|
+
gsmeth.__set_break_at_step_point(step_point)
|
124
|
+
else
|
125
|
+
@subject.__nonbridge_meth.__set_break_at_step_point(step_point)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def clear_break(source_offset)
|
130
|
+
gsmeth.__clear_break_at(find_step_point_just_before(source_offset))
|
131
|
+
end
|
132
|
+
|
116
133
|
private
|
134
|
+
def find_step_point_just_before(source_offset)
|
135
|
+
nxt = step_offsets.detect {|o| o > source_offset }
|
136
|
+
[step_offsets.index(nxt) - 1, 1].max
|
137
|
+
end
|
138
|
+
|
117
139
|
def wrap_gsmeth(gsmethod)
|
118
140
|
label = gsmethod.__name.to_s
|
119
141
|
cls = gsmethod.__in_class
|
@@ -0,0 +1,50 @@
|
|
1
|
+
class PartialContinuation
|
2
|
+
attr_accessor :markerBlock, :partial
|
3
|
+
|
4
|
+
def self.currentDomarkerBlock(block, markerBlock)
|
5
|
+
if (marker = markerBlock.call).nil?
|
6
|
+
raise RuntimeError, 'Marker not found when capturing partial continuation.'
|
7
|
+
end
|
8
|
+
return block.call to_offset_markerBlock(marker, 1, markerBlock)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.to_offset_markerBlock(method, offset, &block)
|
12
|
+
idx = find_frame_for(method)
|
13
|
+
partial = Thread.__partialContinuationFromLevel_to(3 + offset, idx)
|
14
|
+
new.tap do |o|
|
15
|
+
o.partial = partial
|
16
|
+
o.markerBlock = block
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find_frame_for(method)
|
21
|
+
index = 1
|
22
|
+
while frame = Thread.current.__frame_contents_at(index) do
|
23
|
+
if frame[0] == method
|
24
|
+
return level
|
25
|
+
else
|
26
|
+
level += 1
|
27
|
+
end
|
28
|
+
end
|
29
|
+
nil
|
30
|
+
end
|
31
|
+
|
32
|
+
def call(arg = nil)
|
33
|
+
marker = markerBlock.call
|
34
|
+
if marker.nil?
|
35
|
+
marker = Thread.current.__frame_contents_at(2).first
|
36
|
+
frameIndex = 2
|
37
|
+
else
|
38
|
+
frameIndex = self.class.find_frame_for marker
|
39
|
+
end
|
40
|
+
Thread.current.__installPartialContinuation_atLevel_value partial, frameIndex, arg
|
41
|
+
end
|
42
|
+
|
43
|
+
alias [] call
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_callcc
|
47
|
+
PartialContinuation.currentDomarkerBlock
|
48
|
+
currentDo: aBlock
|
49
|
+
markerBlock: [ self callbackMarker ]
|
50
|
+
end
|
@@ -23,7 +23,7 @@ module Ruby
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def line
|
26
|
-
source_location.last
|
26
|
+
source_location.last - 1
|
27
27
|
end
|
28
28
|
|
29
29
|
def line=(num)
|
@@ -77,6 +77,25 @@ module Ruby
|
|
77
77
|
|
78
78
|
def source
|
79
79
|
try_send(:source) or raise(CapabilitiesExceeded)
|
80
|
+
rescue => e
|
81
|
+
e.message
|
82
|
+
end
|
83
|
+
|
84
|
+
def source=(str)
|
85
|
+
src = try_send(:source)
|
86
|
+
raise "cannot write to source location" unless file and line and File.writable?(file)
|
87
|
+
|
88
|
+
f = File.read(file).lines.to_a
|
89
|
+
srclen = src.lines.to_a.size
|
90
|
+
prefix = f[0...line].join
|
91
|
+
method_src = f[line...line + srclen].join
|
92
|
+
postfix = f[line + srclen..-1].join
|
93
|
+
raise "source differs from runtime" unless method_src.strip == src.strip
|
94
|
+
|
95
|
+
File.open(file, 'w') {|f| f << prefix << str << postfix }
|
96
|
+
defining_class.reflectee.class_eval(str, file, line)
|
97
|
+
rescue Exception => e
|
98
|
+
raise CapabilitiesExceeded, e.message
|
80
99
|
end
|
81
100
|
|
82
101
|
def step_offsets
|
@@ -90,10 +109,14 @@ module Ruby
|
|
90
109
|
|
91
110
|
offsets = [0]
|
92
111
|
sends.each do |name|
|
93
|
-
|
112
|
+
next_offset = source[offsets.last..-1] =~ /#{Regexp.escape(name)}/
|
113
|
+
break unless next_offset
|
114
|
+
offsets << next_offset
|
94
115
|
end
|
95
116
|
offsets.shift
|
96
117
|
Hash[*sends.zip(offsets).flatten]
|
118
|
+
rescue Exception
|
119
|
+
return {}
|
97
120
|
end
|
98
121
|
|
99
122
|
private
|
data/rubymirrors.gemspec
CHANGED
metadata
CHANGED
@@ -1,64 +1,85 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubymirrors
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
|
-
segments:
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
- 1
|
10
|
-
version: 0.0.1
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- Tim Felgentreff
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
date: 2011-11-10 00:00:00 Z
|
12
|
+
date: 2012-10-25 00:00:00.000000000 Z
|
19
13
|
dependencies: []
|
14
|
+
description: ! '## A mirror API for Ruby
|
15
|
+
|
20
16
|
|
21
|
-
description: |
|
22
|
-
## A mirror API for Ruby
|
23
|
-
|
24
17
|
In various [research][p1] [projects][p2] the advantages of having a [mirror
|
18
|
+
|
25
19
|
API][p3] to separate reflection from a language implementation have
|
20
|
+
|
26
21
|
been discussed, and "industry grade" implementations exist for
|
22
|
+
|
27
23
|
[Java][p4] and [C#][p5]. This project aims at providing a number of
|
24
|
+
|
28
25
|
specs and classes that document a mirror API for Ruby. The mirror
|
26
|
+
|
29
27
|
implementation that is part of this project will use only those
|
28
|
+
|
30
29
|
language facilities that are available across Ruby implementations.
|
30
|
+
|
31
31
|
The specs, however, will also test behavior that cannot be provided in
|
32
|
+
|
32
33
|
such a manner. The idea here is that in time, all implementations
|
34
|
+
|
33
35
|
provide their own implementation of the mirror API, and all
|
36
|
+
|
34
37
|
implementations collaborate on this one spec.
|
35
|
-
|
38
|
+
|
39
|
+
|
36
40
|
Why do this, you ask? Because Ruby needs tools, and those tools need
|
41
|
+
|
37
42
|
to be written in Ruby. If they are not, then people will be excluded from
|
43
|
+
|
38
44
|
tinkering with their tools, thus impeding innovation. You only have to
|
39
|
-
|
45
|
+
|
46
|
+
look at Emacs or Smalltalk to see what''s possible when programmers can
|
47
|
+
|
40
48
|
extend their tools, all tools, in a language they feel comfortable
|
49
|
+
|
41
50
|
in. If we have a standard mirror API, all tools that are written **for**
|
51
|
+
|
42
52
|
Ruby, **in** Ruby, can be shared across implementations, while at the same time
|
53
|
+
|
43
54
|
allowing language implementers to use the facilities of their platform
|
55
|
+
|
44
56
|
to provide optimal reflective capabilities without tying them to
|
57
|
+
|
45
58
|
internals.
|
46
|
-
|
47
|
-
|
48
|
-
[
|
49
|
-
|
50
|
-
|
51
|
-
[
|
52
|
-
|
53
|
-
|
59
|
+
|
60
|
+
|
61
|
+
[p1]: http://www.cs.virginia.edu/~lorenz/papers/icse03/icse2003.pdf "Pluggable Reflection:
|
62
|
+
Decoupling Meta-Interface and Implementation"
|
63
|
+
|
64
|
+
[p2]: http://bracha.org/newspeak-spec.pdf "Newspeak Programming Language Draft Specification,
|
65
|
+
Version 0.06, pages 40 onward"
|
66
|
+
|
67
|
+
[p3]: http://www.hpi.uni-potsdam.de/hirschfeld/events/past/media/100105_Bracha_2010_LinguisticReflectionViaMirrors_HPI.mp4
|
68
|
+
"Linguistic Reflection Via Mirrors"
|
69
|
+
|
70
|
+
[p4]: http://bracha.org/mirrors.pdf "Mirrors: Design Principles for Meta-level Facilities
|
71
|
+
of Object-Oriented Programming Languages"
|
72
|
+
|
73
|
+
[p5]: http://oreilly.com/catalog/progcsharp/chapter/ch18.html "See esp. 18-3, highlighting
|
74
|
+
how C# reflection works on assembly rather than VM objects"
|
75
|
+
|
76
|
+
'
|
77
|
+
email:
|
54
78
|
- timfelgentreff@gmail.com
|
55
79
|
executables: []
|
56
|
-
|
57
80
|
extensions: []
|
58
|
-
|
59
81
|
extra_rdoc_files: []
|
60
|
-
|
61
|
-
files:
|
82
|
+
files:
|
62
83
|
- Gemfile
|
63
84
|
- README.md
|
64
85
|
- Rakefile
|
@@ -74,11 +95,14 @@ files:
|
|
74
95
|
- lib/abstract_reflection/thread_mirror.rb
|
75
96
|
- lib/maglev/reflection.rb
|
76
97
|
- lib/maglev/reflection/class_mirror.rb
|
98
|
+
- lib/maglev/reflection/core_ext/class.rb
|
77
99
|
- lib/maglev/reflection/core_ext/class_organizer.rb
|
100
|
+
- lib/maglev/reflection/core_ext/exception.rb
|
78
101
|
- lib/maglev/reflection/core_ext/maglev.rb
|
79
102
|
- lib/maglev/reflection/core_ext/method.rb
|
80
103
|
- lib/maglev/reflection/core_ext/module.rb
|
81
104
|
- lib/maglev/reflection/core_ext/object.rb
|
105
|
+
- lib/maglev/reflection/core_ext/proc.rb
|
82
106
|
- lib/maglev/reflection/core_ext/thread.rb
|
83
107
|
- lib/maglev/reflection/field_mirror.rb
|
84
108
|
- lib/maglev/reflection/field_mirror/fixed_instance_variable_mirror.rb
|
@@ -86,6 +110,7 @@ files:
|
|
86
110
|
- lib/maglev/reflection/mirror.rb
|
87
111
|
- lib/maglev/reflection/object_mirror.rb
|
88
112
|
- lib/maglev/reflection/stack_frame_mirror.rb
|
113
|
+
- lib/maglev/reflection/support/partial_continuation.rb
|
89
114
|
- lib/maglev/reflection/thread_mirror.rb
|
90
115
|
- lib/rubinius/reflection.rb
|
91
116
|
- lib/ruby/reflection.rb
|
@@ -120,40 +145,29 @@ files:
|
|
120
145
|
- spec/thread_spec.rb
|
121
146
|
homepage:
|
122
147
|
licenses: []
|
123
|
-
|
124
|
-
metadata: {}
|
125
|
-
|
126
148
|
post_install_message:
|
127
149
|
rdoc_options: []
|
128
|
-
|
129
|
-
require_paths:
|
150
|
+
require_paths:
|
130
151
|
- lib
|
131
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
152
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
132
153
|
none: false
|
133
|
-
requirements:
|
134
|
-
- -
|
135
|
-
- !ruby/object:Gem::Version
|
136
|
-
|
137
|
-
|
138
|
-
- 0
|
139
|
-
version: "0"
|
140
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
159
|
none: false
|
142
|
-
requirements:
|
143
|
-
- -
|
144
|
-
- !ruby/object:Gem::Version
|
145
|
-
|
146
|
-
segments:
|
147
|
-
- 0
|
148
|
-
version: "0"
|
160
|
+
requirements:
|
161
|
+
- - ! '>='
|
162
|
+
- !ruby/object:Gem::Version
|
163
|
+
version: '0'
|
149
164
|
requirements: []
|
150
|
-
|
151
165
|
rubyforge_project:
|
152
|
-
rubygems_version: 1.8.
|
166
|
+
rubygems_version: 1.8.23
|
153
167
|
signing_key:
|
154
|
-
specification_version:
|
168
|
+
specification_version: 3
|
155
169
|
summary: Mirror API for Ruby
|
156
|
-
test_files:
|
170
|
+
test_files:
|
157
171
|
- spec/class_spec.rb
|
158
172
|
- spec/field_spec.rb
|
159
173
|
- spec/fixtures/class_spec.rb
|