ractorize 0.0.4 → 0.0.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +159 -1
- data/src/ractorize/ractorized_object.rb +53 -10
- data/src/ractorize/thunk.rb +6 -8
- data/src/ractorize.rb +183 -6
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 717f8ece3185d394b66aade1e78947eb5bb859535a8fa4afdaa88e33ad821cc9
|
|
4
|
+
data.tar.gz: af1aeaf9cc3c4b76625ba228ed5ed60cd77afde597cbcafd4ca059ca2ec52488
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 188fa21adfbdeff96e906f1c38ed41beeab1f4e41d6581a4494cd3245611ae457848b8f0571cd04a83ba453a539073ff4152c2ac5b72ea395d40ed4ada0df4f4
|
|
7
|
+
data.tar.gz: 2c5ffbd40dbc7f2399eed5a8350eaa86a372e2cdc2efec07389c4a16be9deeeba9c9dea1490784306126629682b4444a8b0ffc6b321469b647e71a45c2c5db16
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [0.0.5] - 2026-05-30
|
|
2
|
+
|
|
3
|
+
- Support auto-freezing certain method-arguments
|
|
4
|
+
- Support moving method arguments if they are not shareable
|
|
5
|
+
- Give ractors a name to help with debugging
|
|
6
|
+
|
|
1
7
|
## [0.0.4] - 2026-05-23
|
|
2
8
|
|
|
3
9
|
- Prevent thunks from crossing ractor boundaries
|
data/README.md
CHANGED
|
@@ -68,9 +68,160 @@ took 0.195 seconds
|
|
|
68
68
|
$
|
|
69
69
|
```
|
|
70
70
|
|
|
71
|
+
## Advanced usage/some niceties
|
|
72
|
+
|
|
73
|
+
### Auto-freeze non-shareable stuff passed to ractorized objects/methods
|
|
74
|
+
|
|
75
|
+
Not really in the mood to track down all the strings you're sending to your ractorized objects
|
|
76
|
+
that happen to be non-shareable due to not being frozen? Or maybe you're in the mood
|
|
77
|
+
but don't control the code where they are being initialized? You can just auto-freeze them!
|
|
78
|
+
|
|
79
|
+
You can use `Ractorize.auto_freeze` for that.
|
|
80
|
+
|
|
81
|
+
A few flavors:
|
|
82
|
+
|
|
83
|
+
#### Auto-freezing any instance of a class
|
|
84
|
+
|
|
85
|
+
Let's just freeze all strings sent to any ractorized object.
|
|
86
|
+
|
|
87
|
+
```ruby
|
|
88
|
+
Ractorize.auto_freeze(String)
|
|
89
|
+
|
|
90
|
+
h = Ractorize[{}]
|
|
91
|
+
|
|
92
|
+
key = "foo"
|
|
93
|
+
value = "bar"
|
|
94
|
+
|
|
95
|
+
puts "value frozen? #{value.frozen?}"
|
|
96
|
+
h[key] = value
|
|
97
|
+
puts "value frozen? #{value.frozen?}"
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
This results in:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
key frozen? false value frozen? false
|
|
104
|
+
key frozen? true value frozen? true
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### Only auto-freezing stuff passed to a specific type of ractorized object
|
|
108
|
+
|
|
109
|
+
You can specify that auto-freezing should only apply to ractorized objects of a specific class.
|
|
110
|
+
|
|
111
|
+
Let's say you want to freeze stuff passed to ractorized instances of Array but not interfere with
|
|
112
|
+
anything ractorized instances of Hash might be doing. You can do this like so:
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
Ractorize.auto_freeze(Array, String)
|
|
116
|
+
|
|
117
|
+
h = Ractorize[{}]
|
|
118
|
+
|
|
119
|
+
key = "foo"
|
|
120
|
+
value = "bar"
|
|
121
|
+
|
|
122
|
+
puts "Before Hash#[]= value frozen? #{value.frozen?}"
|
|
123
|
+
h[key] = value
|
|
124
|
+
puts "After Hash#[]= value frozen? #{value.frozen?}"
|
|
125
|
+
|
|
126
|
+
a = Ractorize[[]]
|
|
127
|
+
|
|
128
|
+
a.push(value)
|
|
129
|
+
puts "After Array#push value frozen? #{value.frozen?}"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
This prints out:
|
|
133
|
+
|
|
134
|
+
```
|
|
135
|
+
Before Hash#[]= value frozen? false
|
|
136
|
+
After Hash#[]= value frozen? false
|
|
137
|
+
After Array#push value frozen? true
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
So only sending the string to an Array resulted in auto-freezing it.
|
|
141
|
+
|
|
142
|
+
#### programmatically expressing when to auto-freeze
|
|
143
|
+
|
|
144
|
+
You can also pass a proc to express whether or not to autofreeze an object:
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
Ractorize.auto_freeze(Ractor.shareable_proc { it.is_a?(String) && it =~ /baz/ })
|
|
148
|
+
|
|
149
|
+
a = Ractorize[[]]
|
|
150
|
+
|
|
151
|
+
strings = ["foo", "bar", "baz"]
|
|
152
|
+
|
|
153
|
+
strings.each { a.push(it) }
|
|
154
|
+
|
|
155
|
+
puts strings.map(&:frozen?).inspect
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
This outputs:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
[false, false, true]
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Notice that only the last string, which meets the criteria, was frozen.
|
|
165
|
+
|
|
166
|
+
### How to move arguments to the receiving ractorized object
|
|
167
|
+
|
|
168
|
+
You can express that you'd like an argument to be moved to the receiving ractorized object.
|
|
169
|
+
|
|
170
|
+
This allows you to not have to worry about if the argument is shareable or not.
|
|
171
|
+
|
|
172
|
+
You will get errors, though, when trying to make use of the moved argument in the calling
|
|
173
|
+
code, just like when using ractors directly and moving objects between them.
|
|
174
|
+
|
|
175
|
+
The interface is identical to `.auto_feeze` but through the method `.move_arg`:
|
|
176
|
+
|
|
177
|
+
```ruby
|
|
178
|
+
class Foo
|
|
179
|
+
def object_id_of(s) = s.object_id
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
foo = Ractorize[Foo.new]
|
|
183
|
+
s = "asdf"
|
|
184
|
+
|
|
185
|
+
puts "calling ractor s.object_id before #push: #{s.object_id}"
|
|
186
|
+
puts "object_id in receiving ractor Foo#object_id_of: #{foo.object_id_of(s)}"
|
|
187
|
+
puts "s.length in calling ractor: #{s.length}"
|
|
188
|
+
puts
|
|
189
|
+
|
|
190
|
+
puts "Configuring all String instances to be moved to receiving ractor"
|
|
191
|
+
puts
|
|
192
|
+
Ractorize.move_arg(String)
|
|
193
|
+
|
|
194
|
+
puts "calling ractor s.object_id before #push: #{s.object_id}"
|
|
195
|
+
puts "object_id in receiving ractor Foo#object_id_of: #{foo.object_id_of(s)}"
|
|
196
|
+
puts "s.length in calling ractor: #{s.length}"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
this outputs:
|
|
200
|
+
|
|
201
|
+
```
|
|
202
|
+
calling ractor s.object_id before #push: 896
|
|
203
|
+
object_id in receiving ractor Foo#object_id_of: 904
|
|
204
|
+
s.length in calling ractor: 4
|
|
205
|
+
|
|
206
|
+
Configuring all String instances to be moved to receiving ractor
|
|
207
|
+
|
|
208
|
+
calling ractor s.object_id before #push: 896
|
|
209
|
+
object_id in receiving ractor Foo#object_id_of: 896
|
|
210
|
+
example_scripts/auto_freeze/move-arg:25:in 'Ractor::MovedObject#method_missing': can not send any methods to a moved object (Ractor::MovedError)
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Notice that before we configure String to be moved, `foo` receives a copy of `s`, hence the different
|
|
214
|
+
object_id.
|
|
215
|
+
|
|
216
|
+
But once we configure String to be moved, now `foo` receives `s` instead of a copy, hence the object_id
|
|
217
|
+
being the same.
|
|
218
|
+
|
|
219
|
+
However, then when we try to print out the length of `s` in the calling ractor, we get a `Ractor::MovedError`.
|
|
220
|
+
|
|
71
221
|
## Gotchas
|
|
72
222
|
|
|
73
|
-
### Predicate methods not ending in "?" will always return truthy values!
|
|
223
|
+
### Predicate methods not ending in "?" in `if/unless/until/while/case/when/in` statements will always return truthy values!
|
|
224
|
+
|
|
74
225
|
If you try to use the return value of a ractorized object (or any instance of a ractorized class)
|
|
75
226
|
in a boolean expression, it will always be truthy!!
|
|
76
227
|
|
|
@@ -108,6 +259,13 @@ end
|
|
|
108
259
|
|
|
109
260
|
This will correctly print out `It's not empty!`.
|
|
110
261
|
|
|
262
|
+
Note that this isn't necessary with methods ending in "?" as this will automatically block
|
|
263
|
+
and return the boolean value.
|
|
264
|
+
|
|
265
|
+
Also, the predicate methods `==`, `!=` and `!` also will automatically block and return the boolean
|
|
266
|
+
value, just like methods ending in "?". So you can freely do `if Ractorize["asdf"] == "asdf"` works
|
|
267
|
+
perfectly fine just like predicate methods ending in "?".
|
|
268
|
+
|
|
111
269
|
### Calling a method on a closed ractorized object might result in a deadlock!
|
|
112
270
|
|
|
113
271
|
It will usually raise a `Ractor::CloseError` but once in a while it can deadlock.
|
|
@@ -4,7 +4,7 @@ require_relative "thunk"
|
|
|
4
4
|
module Ractorize
|
|
5
5
|
class RactorizedObject < BasicObject
|
|
6
6
|
def initialize(mode, *args, **opts, &block)
|
|
7
|
-
@ractor = ::Ractor.new(&RACTOR_PROC)
|
|
7
|
+
@ractor = ::Ractor.new(name: "#{args.first}<#{args.first.object_id}>", &RACTOR_PROC)
|
|
8
8
|
|
|
9
9
|
case mode
|
|
10
10
|
when :object
|
|
@@ -12,22 +12,46 @@ module Ractorize
|
|
|
12
12
|
|
|
13
13
|
outside_object = args.first
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
@__target_class__ = outside_object.class
|
|
16
16
|
|
|
17
17
|
if ::Ractor.shareable?(outside_object)
|
|
18
18
|
@ractor << outside_object
|
|
19
19
|
else
|
|
20
|
+
::Ractorize.resolve_all_thunks(outside_object)
|
|
20
21
|
@ractor.send(outside_object, move: true)
|
|
21
22
|
end
|
|
22
23
|
when :class
|
|
23
|
-
@ractor << :class
|
|
24
|
-
|
|
25
24
|
klass, *args = args
|
|
26
25
|
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
@__target_class__ = klass
|
|
27
|
+
|
|
28
|
+
to_move = ::Ractorize.prepare_args(@__target_class__, args, opts)
|
|
29
|
+
|
|
30
|
+
if to_move&.any?
|
|
31
|
+
@ractor << :class_arg_by_arg
|
|
32
|
+
@ractor << klass
|
|
33
|
+
|
|
34
|
+
args.each do |arg|
|
|
35
|
+
@ractor << :arg
|
|
36
|
+
@ractor.send(arg, move: to_move.include?(arg))
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
opts.each_pair do |name, value|
|
|
40
|
+
@ractor << :kwarg
|
|
41
|
+
@ractor << name
|
|
42
|
+
@ractor.send(value, move: to_move.include?(value))
|
|
43
|
+
end
|
|
29
44
|
|
|
30
|
-
|
|
45
|
+
if block
|
|
46
|
+
@ractor << :block
|
|
47
|
+
@ractor << block
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
@ractor << :done
|
|
51
|
+
else
|
|
52
|
+
@ractor << :class
|
|
53
|
+
@ractor << [klass, args.freeze, opts.dup.freeze, block].freeze
|
|
54
|
+
end
|
|
31
55
|
else
|
|
32
56
|
# :nocov:
|
|
33
57
|
::Kernel.raise "Invalid mode #{mode}"
|
|
@@ -53,10 +77,29 @@ module Ractorize
|
|
|
53
77
|
|
|
54
78
|
return_port = ::Ractor::Port.new
|
|
55
79
|
|
|
56
|
-
::Ractorize.
|
|
57
|
-
|
|
80
|
+
to_move = ::Ractorize.prepare_args(@__target_class__, args, opts)
|
|
81
|
+
|
|
82
|
+
if to_move&.any?
|
|
83
|
+
@ractor << [:__invoke_arg_by_arg__, [].freeze, {}.freeze, return_port, !!block]
|
|
84
|
+
|
|
85
|
+
args_port = return_port.receive
|
|
86
|
+
args_port << method_name
|
|
87
|
+
|
|
88
|
+
args.each do |arg|
|
|
89
|
+
args_port << :arg
|
|
90
|
+
args_port.send(arg, move: to_move.include?(arg))
|
|
91
|
+
end
|
|
58
92
|
|
|
59
|
-
|
|
93
|
+
opts.each_pair do |name, value|
|
|
94
|
+
args_port << :kwarg
|
|
95
|
+
args_port << name
|
|
96
|
+
args_port.send(value, move: to_move.include?(value))
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
args_port << :done
|
|
100
|
+
else
|
|
101
|
+
@ractor << [method_name, args.dup.freeze, opts.dup.freeze, return_port, !!block].freeze
|
|
102
|
+
end
|
|
60
103
|
|
|
61
104
|
if block
|
|
62
105
|
stop = false
|
data/src/ractorize/thunk.rb
CHANGED
|
@@ -28,7 +28,8 @@ module Ractorize
|
|
|
28
28
|
__return_value_port__.receive
|
|
29
29
|
else
|
|
30
30
|
# :nocov:
|
|
31
|
-
raise
|
|
31
|
+
::Kernel.raise EscapingRactorError,
|
|
32
|
+
"Somehow this thunk was passed between ractors but wasn't resolved first."
|
|
32
33
|
# :nocov:
|
|
33
34
|
end
|
|
34
35
|
|
|
@@ -43,12 +44,9 @@ module Ractorize
|
|
|
43
44
|
value
|
|
44
45
|
end
|
|
45
46
|
|
|
46
|
-
def !
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def ==(other)
|
|
51
|
-
__value__ == other || super
|
|
52
|
-
end
|
|
47
|
+
def ! = !__value__
|
|
48
|
+
def ==(other) = __value__ == other || super
|
|
49
|
+
def !=(other) = __value__ != other || super
|
|
50
|
+
def equal?(other) = __value__.equal?(other) || super
|
|
53
51
|
end
|
|
54
52
|
end
|
data/src/ractorize.rb
CHANGED
|
@@ -4,6 +4,55 @@ require_relative "ractorize/ractorized_class"
|
|
|
4
4
|
|
|
5
5
|
module Ractorize
|
|
6
6
|
class << self
|
|
7
|
+
# TODO: figure out a way to magically get a ractor-shareable proc from a non-ractor-shareable proc
|
|
8
|
+
def auto_freeze(target, class_or_proc = nil)
|
|
9
|
+
@auto_freeze = @auto_freeze ? @auto_freeze.dup : []
|
|
10
|
+
|
|
11
|
+
unless Ractor.shareable?(target)
|
|
12
|
+
# :nocov:
|
|
13
|
+
raise "#{target} isn't shareable so can't use it to auto-freeze"
|
|
14
|
+
# :nocov:
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
@auto_freeze << if class_or_proc
|
|
18
|
+
unless Ractor.shareable?(class_or_proc)
|
|
19
|
+
# :nocov:
|
|
20
|
+
raise "#{class_or_proc} isn't shareable so can't use it to auto-freeze"
|
|
21
|
+
# :nocov:
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
[target, class_or_proc]
|
|
25
|
+
else
|
|
26
|
+
target
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
@auto_freeze.freeze
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def move_arg(target, class_or_proc = nil)
|
|
33
|
+
@move_arg = @move_arg ? @move_arg.dup : []
|
|
34
|
+
|
|
35
|
+
unless Ractor.shareable?(target)
|
|
36
|
+
# :nocov:
|
|
37
|
+
raise "#{target} isn't shareable so can't use it to auto-freeze"
|
|
38
|
+
# :nocov:
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
@move_arg << if class_or_proc
|
|
42
|
+
unless Ractor.shareable?(class_or_proc)
|
|
43
|
+
# :nocov:
|
|
44
|
+
raise "#{class_or_proc} isn't shareable so can't use it to auto-freeze"
|
|
45
|
+
# :nocov:
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
[target, class_or_proc]
|
|
49
|
+
else
|
|
50
|
+
target
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
@move_arg.freeze
|
|
54
|
+
end
|
|
55
|
+
|
|
7
56
|
def any_thunks?(structure)
|
|
8
57
|
# rubocop:disable Lint/UnreachableLoop
|
|
9
58
|
each_thunk(structure) { return true }
|
|
@@ -17,6 +66,87 @@ module Ractorize
|
|
|
17
66
|
each_thunk(structure, &:__value__)
|
|
18
67
|
end
|
|
19
68
|
|
|
69
|
+
def to_move(target_class, args)
|
|
70
|
+
return unless @move_arg
|
|
71
|
+
|
|
72
|
+
move_set = nil
|
|
73
|
+
|
|
74
|
+
args.each do |arg|
|
|
75
|
+
next if Ractor.shareable?(arg)
|
|
76
|
+
|
|
77
|
+
@move_arg.each do |rule|
|
|
78
|
+
if rule.is_a?(::Array)
|
|
79
|
+
target, rule = rule
|
|
80
|
+
next unless target == target_class
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
move_it = if rule.is_a?(::Proc)
|
|
84
|
+
rule.call(arg)
|
|
85
|
+
else
|
|
86
|
+
rule === arg
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if move_it
|
|
90
|
+
move_set ||= Set.new
|
|
91
|
+
move_set << arg
|
|
92
|
+
break
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
move_set
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def apply_auto_freeze(target_class, arg)
|
|
101
|
+
return unless @auto_freeze
|
|
102
|
+
return if Ractor.shareable?(arg)
|
|
103
|
+
|
|
104
|
+
# TODO: should we handle instance variables like we do with thunks?
|
|
105
|
+
case arg
|
|
106
|
+
when ::Hash
|
|
107
|
+
arg.each_pair do |key, value|
|
|
108
|
+
apply_auto_freeze(target_class, key)
|
|
109
|
+
apply_auto_freeze(target_class, value)
|
|
110
|
+
end
|
|
111
|
+
when ::Array
|
|
112
|
+
arg.each { apply_auto_freeze(target_class, it) }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
return if Ractor.shareable?(arg)
|
|
116
|
+
|
|
117
|
+
@auto_freeze.each do |rule|
|
|
118
|
+
if rule.is_a?(::Array)
|
|
119
|
+
target, rule = rule
|
|
120
|
+
next unless target == target_class
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
freeze_it = if rule.is_a?(::Proc)
|
|
124
|
+
rule.call(arg)
|
|
125
|
+
else
|
|
126
|
+
rule === arg
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
if freeze_it
|
|
130
|
+
arg.freeze
|
|
131
|
+
break
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def prepare_args(target_class, args, opts, skip_move: false)
|
|
137
|
+
unless opts.empty?
|
|
138
|
+
args = [*args, *opts.values]
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
args.each { apply_auto_freeze(target_class, it) }
|
|
142
|
+
|
|
143
|
+
::Ractorize.resolve_all_thunks(args)
|
|
144
|
+
|
|
145
|
+
return nil if skip_move
|
|
146
|
+
|
|
147
|
+
to_move(target_class, args)
|
|
148
|
+
end
|
|
149
|
+
|
|
20
150
|
def each_thunk(structure, seen = Set.new, &block)
|
|
21
151
|
return block.call(structure) if Thunk === structure
|
|
22
152
|
return if seen.include?(structure)
|
|
@@ -40,6 +170,36 @@ module Ractorize
|
|
|
40
170
|
end
|
|
41
171
|
end
|
|
42
172
|
end
|
|
173
|
+
|
|
174
|
+
def extract_args(port_like)
|
|
175
|
+
args = []
|
|
176
|
+
opts = {}
|
|
177
|
+
block = nil
|
|
178
|
+
|
|
179
|
+
loop do
|
|
180
|
+
arg_type = port_like.__send__(:receive)
|
|
181
|
+
|
|
182
|
+
case arg_type
|
|
183
|
+
when :arg
|
|
184
|
+
args << port_like.__send__(:receive)
|
|
185
|
+
when :kwarg
|
|
186
|
+
name = port_like.__send__(:receive)
|
|
187
|
+
value = port_like.__send__(:receive)
|
|
188
|
+
|
|
189
|
+
opts[name] = value
|
|
190
|
+
when :block
|
|
191
|
+
block = port_like.__send__(:receive)
|
|
192
|
+
when :done
|
|
193
|
+
break
|
|
194
|
+
else
|
|
195
|
+
# :nocov:
|
|
196
|
+
::Kernel.raise "Unknown class_by_arg arg type #{arg_type}"
|
|
197
|
+
# :nocov:
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
[args, opts, block]
|
|
202
|
+
end
|
|
43
203
|
end
|
|
44
204
|
|
|
45
205
|
# Putting this in a constant so we can get test coverage on it since not sure how to get coverage
|
|
@@ -50,9 +210,19 @@ module Ractorize
|
|
|
50
210
|
object = case mode
|
|
51
211
|
when :class
|
|
52
212
|
klass, args, opts, block = receive
|
|
53
|
-
|
|
213
|
+
target_class = klass
|
|
214
|
+
klass.new(*args.freeze, **opts.freeze, &block)
|
|
54
215
|
when :object
|
|
55
|
-
receive
|
|
216
|
+
o = receive
|
|
217
|
+
target_class = o.class
|
|
218
|
+
o
|
|
219
|
+
when :class_arg_by_arg
|
|
220
|
+
klass = receive
|
|
221
|
+
target_class = klass
|
|
222
|
+
|
|
223
|
+
args, opts, block = ::Ractorize.extract_args(self)
|
|
224
|
+
|
|
225
|
+
klass.new(*args.freeze, **opts.freeze, &block)
|
|
56
226
|
else
|
|
57
227
|
# :nocov:
|
|
58
228
|
::Kernel.raise "Invalid mode #{mode}"
|
|
@@ -68,12 +238,19 @@ module Ractorize
|
|
|
68
238
|
close
|
|
69
239
|
break
|
|
70
240
|
else
|
|
241
|
+
if method_name == :__invoke_arg_by_arg__
|
|
242
|
+
args_port = Ractor::Port.new
|
|
243
|
+
return_port << args_port
|
|
244
|
+
|
|
245
|
+
method_name = args_port.receive
|
|
246
|
+
method_args, opts = ::Ractorize.extract_args(args_port)
|
|
247
|
+
end
|
|
248
|
+
|
|
71
249
|
if block_given
|
|
72
|
-
block_result_port = Ractor::Port.new
|
|
250
|
+
block_result_port = ::Ractor::Port.new
|
|
73
251
|
|
|
74
252
|
value = object.__send__(method_name, *method_args, **opts) do |*args, **opts, &b|
|
|
75
|
-
::Ractorize.
|
|
76
|
-
::Ractorize.resolve_all_thunks(opts)
|
|
253
|
+
::Ractorize.prepare_args(target_class, args, opts, skip_move: true)
|
|
77
254
|
|
|
78
255
|
return_port << [:yield, [args.dup.freeze, opts.dup.freeze, b].freeze, block_result_port].freeze
|
|
79
256
|
|
|
@@ -95,7 +272,7 @@ module Ractorize
|
|
|
95
272
|
else
|
|
96
273
|
value = object.__send__(method_name, *method_args, **opts)
|
|
97
274
|
|
|
98
|
-
value = value.__value__ while Thunk === value
|
|
275
|
+
value = value.__value__ while ::Ractorize::Thunk === value
|
|
99
276
|
|
|
100
277
|
return_port << value
|
|
101
278
|
end
|