rbs 3.3.2 → 3.4.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/comments.yml +2 -5
- data/.github/workflows/ruby.yml +7 -8
- data/.github/workflows/typecheck.yml +37 -0
- data/CHANGELOG.md +50 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +11 -11
- data/Steepfile +2 -2
- data/core/array.rbs +19 -49
- data/core/basic_object.rbs +2 -2
- data/core/comparable.rbs +17 -8
- data/core/complex.rbs +82 -43
- data/core/data.rbs +2 -4
- data/core/dir.rbs +635 -295
- data/core/enumerable.rbs +11 -18
- data/core/enumerator.rbs +37 -31
- data/core/errors.rbs +4 -0
- data/core/false_class.rbs +34 -15
- data/core/fiber.rbs +23 -0
- data/core/file.rbs +329 -120
- data/core/float.rbs +17 -32
- data/core/gc.rbs +17 -11
- data/core/hash.rbs +22 -44
- data/core/integer.rbs +82 -113
- data/core/io/buffer.rbs +90 -47
- data/core/io.rbs +39 -116
- data/core/kernel.rbs +442 -489
- data/core/match_data.rbs +55 -56
- data/core/module.rbs +45 -1
- data/core/nil_class.rbs +98 -35
- data/core/numeric.rbs +22 -32
- data/core/object_space/weak_key_map.rbs +102 -0
- data/core/process.rbs +1242 -655
- data/core/ractor.rbs +139 -120
- data/core/range.rbs +100 -4
- data/core/rational.rbs +0 -4
- data/core/rbs/unnamed/argf.rbs +16 -8
- data/core/rbs/unnamed/env_class.rbs +0 -24
- data/core/refinement.rbs +8 -0
- data/core/regexp.rbs +1149 -598
- data/core/ruby_vm.rbs +126 -12
- data/core/rubygems/platform.rbs +9 -0
- data/core/rubygems/rubygems.rbs +1 -1
- data/core/rubygems/version.rbs +5 -1
- data/core/set.rbs +20 -22
- data/core/signal.rbs +4 -4
- data/core/string.rbs +283 -230
- data/core/string_io.rbs +2 -14
- data/core/struct.rbs +404 -24
- data/core/symbol.rbs +1 -19
- data/core/thread.rbs +29 -12
- data/core/time.rbs +227 -104
- data/core/trace_point.rbs +2 -5
- data/core/true_class.rbs +54 -21
- data/core/warning.rbs +14 -11
- data/docs/data_and_struct.md +29 -0
- data/docs/syntax.md +3 -5
- data/docs/tools.md +1 -0
- data/ext/rbs_extension/lexer.c +643 -559
- data/ext/rbs_extension/lexer.re +5 -1
- data/ext/rbs_extension/parser.c +12 -3
- data/ext/rbs_extension/unescape.c +7 -47
- data/lib/rbs/cli/diff.rb +4 -1
- data/lib/rbs/cli/validate.rb +280 -0
- data/lib/rbs/cli.rb +2 -194
- data/lib/rbs/collection/config.rb +5 -6
- data/lib/rbs/collection/sources/git.rb +1 -1
- data/lib/rbs/collection.rb +1 -0
- data/lib/rbs/diff.rb +7 -4
- data/lib/rbs/errors.rb +11 -0
- data/lib/rbs/test/errors.rb +4 -1
- data/lib/rbs/test/guaranteed.rb +2 -3
- data/lib/rbs/test/type_check.rb +15 -10
- data/lib/rbs/test.rb +3 -3
- data/lib/rbs/types.rb +29 -0
- data/lib/rbs/unit_test/convertibles.rb +176 -0
- data/lib/rbs/unit_test/spy.rb +136 -0
- data/lib/rbs/unit_test/type_assertions.rb +341 -0
- data/lib/rbs/unit_test/with_aliases.rb +143 -0
- data/lib/rbs/unit_test.rb +6 -0
- data/lib/rbs/version.rb +1 -1
- data/sig/cli/validate.rbs +43 -0
- data/sig/diff.rbs +3 -1
- data/sig/errors.rbs +8 -0
- data/sig/rbs.rbs +1 -1
- data/sig/test/errors.rbs +52 -0
- data/sig/test/guranteed.rbs +9 -0
- data/sig/test/type_check.rbs +19 -0
- data/sig/test.rbs +82 -0
- data/sig/types.rbs +6 -1
- data/sig/unit_test/convertibles.rbs +154 -0
- data/sig/unit_test/spy.rbs +28 -0
- data/sig/unit_test/type_assertions.rbs +194 -0
- data/sig/unit_test/with_aliases.rbs +136 -0
- data/stdlib/base64/0/base64.rbs +307 -45
- data/stdlib/bigdecimal/0/big_decimal.rbs +35 -15
- data/stdlib/coverage/0/coverage.rbs +2 -2
- data/stdlib/csv/0/csv.rbs +25 -55
- data/stdlib/date/0/date.rbs +1 -43
- data/stdlib/date/0/date_time.rbs +1 -13
- data/stdlib/delegate/0/delegator.rbs +186 -0
- data/stdlib/delegate/0/kernel.rbs +47 -0
- data/stdlib/delegate/0/simple_delegator.rbs +98 -0
- data/stdlib/did_you_mean/0/did_you_mean.rbs +1 -1
- data/stdlib/erb/0/erb.rbs +2 -2
- data/stdlib/fileutils/0/fileutils.rbs +0 -19
- data/stdlib/io-console/0/io-console.rbs +12 -1
- data/stdlib/ipaddr/0/ipaddr.rbs +2 -1
- data/stdlib/json/0/json.rbs +320 -81
- data/stdlib/logger/0/logger.rbs +9 -5
- data/stdlib/monitor/0/monitor.rbs +78 -0
- data/stdlib/net-http/0/net-http.rbs +1880 -543
- data/stdlib/objspace/0/objspace.rbs +19 -13
- data/stdlib/openssl/0/openssl.rbs +508 -127
- data/stdlib/optparse/0/optparse.rbs +25 -11
- data/stdlib/pathname/0/pathname.rbs +1 -1
- data/stdlib/pp/0/pp.rbs +2 -5
- data/stdlib/prettyprint/0/prettyprint.rbs +2 -2
- data/stdlib/pstore/0/pstore.rbs +2 -4
- data/stdlib/rdoc/0/comment.rbs +1 -2
- data/stdlib/resolv/0/resolv.rbs +4 -2
- data/stdlib/socket/0/socket.rbs +2 -2
- data/stdlib/socket/0/unix_socket.rbs +2 -2
- data/stdlib/strscan/0/string_scanner.rbs +3 -2
- data/stdlib/tempfile/0/tempfile.rbs +1 -1
- data/stdlib/uri/0/common.rbs +245 -123
- metadata +23 -4
- data/lib/rbs/test/spy.rb +0 -6
data/core/ractor.rbs
CHANGED
@@ -2,41 +2,46 @@
|
|
2
2
|
# Ractor is an Actor-model abstraction for Ruby that provides thread-safe
|
3
3
|
# parallel execution.
|
4
4
|
#
|
5
|
-
# Ractor.new
|
5
|
+
# Ractor.new makes a new Ractor, which can run in parallel.
|
6
6
|
#
|
7
7
|
# # The simplest ractor
|
8
8
|
# r = Ractor.new {puts "I am in Ractor!"}
|
9
9
|
# r.take # wait for it to finish
|
10
|
-
# #
|
10
|
+
# # Here, "I am in Ractor!" is printed
|
11
11
|
#
|
12
|
-
# Ractors do not share
|
13
|
-
#
|
14
|
-
#
|
12
|
+
# Ractors do not share all objects with each other. There are two main benefits
|
13
|
+
# to this: across ractors, thread-safety concerns such as data-races and
|
14
|
+
# race-conditions are not possible. The other benefit is parallelism.
|
15
15
|
#
|
16
|
-
# To achieve this,
|
17
|
-
#
|
18
|
-
# objects
|
16
|
+
# To achieve this, object sharing is limited across ractors. For example, unlike
|
17
|
+
# in threads, ractors can't access all the objects available in other ractors.
|
18
|
+
# Even objects normally available through variables in the outer scope are
|
19
|
+
# prohibited from being used across ractors.
|
19
20
|
#
|
20
21
|
# a = 1
|
21
22
|
# r = Ractor.new {puts "I am in Ractor! a=#{a}"}
|
22
23
|
# # fails immediately with
|
23
24
|
# # ArgumentError (can not isolate a Proc because it accesses outer variables (a).)
|
24
25
|
#
|
26
|
+
# The object must be explicitly shared:
|
27
|
+
# a = 1
|
28
|
+
# r = Ractor.new(a) { |a1| puts "I am in Ractor! a=#{a1}"}
|
29
|
+
#
|
25
30
|
# On CRuby (the default implementation), Global Virtual Machine Lock (GVL) is
|
26
|
-
# held per ractor, so ractors
|
27
|
-
# other.
|
31
|
+
# held per ractor, so ractors can perform in parallel without locking each
|
32
|
+
# other. This is unlike the situation with threads on CRuby.
|
28
33
|
#
|
29
|
-
# Instead of accessing
|
30
|
-
#
|
34
|
+
# Instead of accessing shared state, objects should be passed to and from
|
35
|
+
# ractors by sending and receiving them as messages.
|
31
36
|
#
|
32
37
|
# a = 1
|
33
38
|
# r = Ractor.new do
|
34
|
-
# a_in_ractor = receive # receive blocks
|
39
|
+
# a_in_ractor = receive # receive blocks until somebody passes a message
|
35
40
|
# puts "I am in Ractor! a=#{a_in_ractor}"
|
36
41
|
# end
|
37
42
|
# r.send(a) # pass it
|
38
43
|
# r.take
|
39
|
-
# #
|
44
|
+
# # Here, "I am in Ractor! a=1" is printed
|
40
45
|
#
|
41
46
|
# There are two pairs of methods for sending/receiving messages:
|
42
47
|
#
|
@@ -46,13 +51,13 @@
|
|
46
51
|
# (pull);
|
47
52
|
#
|
48
53
|
#
|
49
|
-
# In addition to that,
|
50
|
-
# available there as if received by Ractor.receive, and the last block
|
51
|
-
#
|
54
|
+
# In addition to that, any arguments passed to Ractor.new are passed to the
|
55
|
+
# block and available there as if received by Ractor.receive, and the last block
|
56
|
+
# value is sent outside of the ractor as if sent by Ractor.yield.
|
52
57
|
#
|
53
|
-
# A little demonstration
|
58
|
+
# A little demonstration of a classic ping-pong:
|
54
59
|
#
|
55
|
-
# server = Ractor.new do
|
60
|
+
# server = Ractor.new(name: "server") do
|
56
61
|
# puts "Server starts: #{self.inspect}"
|
57
62
|
# puts "Server sends: ping"
|
58
63
|
# Ractor.yield 'ping' # The server doesn't know the receiver and sends to whoever interested
|
@@ -60,46 +65,49 @@
|
|
60
65
|
# puts "Server received: #{received}"
|
61
66
|
# end
|
62
67
|
#
|
63
|
-
# client = Ractor.new(server) do |srv| # The server is sent
|
68
|
+
# client = Ractor.new(server) do |srv| # The server is sent to the client, and available as srv
|
64
69
|
# puts "Client starts: #{self.inspect}"
|
65
|
-
# received = srv.take # The
|
70
|
+
# received = srv.take # The client takes a message from the server
|
66
71
|
# puts "Client received from " \
|
67
72
|
# "#{srv.inspect}: #{received}"
|
68
73
|
# puts "Client sends to " \
|
69
74
|
# "#{srv.inspect}: pong"
|
70
|
-
# srv.send 'pong' # The client sends a message
|
75
|
+
# srv.send 'pong' # The client sends a message to the server
|
71
76
|
# end
|
72
77
|
#
|
73
|
-
# [client, server].each(&:take) # Wait
|
78
|
+
# [client, server].each(&:take) # Wait until they both finish
|
74
79
|
#
|
75
|
-
# This will output:
|
80
|
+
# This will output something like:
|
76
81
|
#
|
77
|
-
# Server starts: #<Ractor:#2 test.rb:1 running>
|
82
|
+
# Server starts: #<Ractor:#2 server test.rb:1 running>
|
78
83
|
# Server sends: ping
|
79
84
|
# Client starts: #<Ractor:#3 test.rb:8 running>
|
80
|
-
# Client received from #<Ractor:#2
|
81
|
-
# Client sends to #<Ractor:#2
|
85
|
+
# Client received from #<Ractor:#2 server test.rb:1 blocking>: ping
|
86
|
+
# Client sends to #<Ractor:#2 server test.rb:1 blocking>: pong
|
82
87
|
# Server received: pong
|
83
88
|
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
# Ractor#
|
87
|
-
#
|
89
|
+
# Ractors receive their messages via the *incoming port*, and send them to the
|
90
|
+
# *outgoing port*. Either one can be disabled with Ractor#close_incoming and
|
91
|
+
# Ractor#close_outgoing, respectively. When a ractor terminates, its ports are
|
92
|
+
# closed automatically.
|
88
93
|
#
|
89
94
|
# ## Shareable and unshareable objects
|
90
95
|
#
|
91
|
-
# When
|
92
|
-
# whether the object is shareable or unshareable. Most
|
93
|
-
# unshareable objects.
|
96
|
+
# When an object is sent to and from a ractor, it's important to understand
|
97
|
+
# whether the object is shareable or unshareable. Most Ruby objects are
|
98
|
+
# unshareable objects. Even frozen objects can be unshareable if they contain
|
99
|
+
# (through their instance variables) unfrozen objects.
|
94
100
|
#
|
95
|
-
# Shareable objects are
|
96
|
-
#
|
97
|
-
# allows to check this, and Ractor.make_shareable tries to
|
98
|
-
# if it
|
101
|
+
# Shareable objects are those which can be used by several threads without
|
102
|
+
# compromising thread-safety, for example numbers, `true` and `false`.
|
103
|
+
# Ractor.shareable? allows you to check this, and Ractor.make_shareable tries to
|
104
|
+
# make the object shareable if it's not already, and gives an error if it can't
|
105
|
+
# do it.
|
99
106
|
#
|
100
|
-
# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are
|
101
|
-
# Ractor.shareable?('foo') #=> false, unless the string is frozen due to #
|
107
|
+
# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are shareable
|
108
|
+
# Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
|
102
109
|
# Ractor.shareable?('foo'.freeze) #=> true
|
110
|
+
# Ractor.shareable?([Object.new].freeze) #=> false, inner object is unfrozen
|
103
111
|
#
|
104
112
|
# ary = ['hello', 'world']
|
105
113
|
# ary.frozen? #=> false
|
@@ -110,9 +118,9 @@
|
|
110
118
|
# ary[1].frozen? #=> true
|
111
119
|
#
|
112
120
|
# When a shareable object is sent (via #send or Ractor.yield), no additional
|
113
|
-
# processing
|
121
|
+
# processing occurs on it. It just becomes usable by both ractors. When an
|
114
122
|
# unshareable object is sent, it can be either *copied* or *moved*. The first is
|
115
|
-
# the default, and it
|
123
|
+
# the default, and it copies the object fully by deep cloning (Object#clone) the
|
116
124
|
# non-shareable parts of its structure.
|
117
125
|
#
|
118
126
|
# data = ['foo', 'bar'.freeze]
|
@@ -124,18 +132,19 @@
|
|
124
132
|
# r.take
|
125
133
|
# puts "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"
|
126
134
|
#
|
127
|
-
# This will output:
|
135
|
+
# This will output something like:
|
128
136
|
#
|
129
137
|
# In ractor: 340, 360, 320
|
130
138
|
# Outside : 380, 400, 320
|
131
139
|
#
|
132
|
-
#
|
133
|
-
# changed
|
134
|
-
# array's element, which is a shareable frozen string,
|
140
|
+
# Note that the object ids of the array and the non-frozen string inside the
|
141
|
+
# array have changed in the ractor because they are different objects. The
|
142
|
+
# second array's element, which is a shareable frozen string, is the same
|
143
|
+
# object.
|
135
144
|
#
|
136
|
-
# Deep cloning of
|
137
|
-
#
|
138
|
-
# object to the receiving ractor, making it inaccessible
|
145
|
+
# Deep cloning of objects may be slow, and sometimes impossible. Alternatively,
|
146
|
+
# `move: true` may be used during sending. This will *move* the unshareable
|
147
|
+
# object to the receiving ractor, making it inaccessible to the sending ractor.
|
139
148
|
#
|
140
149
|
# data = ['foo', 'bar']
|
141
150
|
# r = Ractor.new do
|
@@ -156,15 +165,17 @@
|
|
156
165
|
# Notice that even `inspect` (and more basic methods like `__id__`) is
|
157
166
|
# inaccessible on a moved object.
|
158
167
|
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
# mutable objects are thread-safe, so the thread-safety property will be kept.
|
168
|
+
# Class and Module objects are shareable so the class/module definitions are
|
169
|
+
# shared between ractors. Ractor objects are also shareable. All operations on
|
170
|
+
# shareable objects are thread-safe, so the thread-safety property will be kept.
|
163
171
|
# We can not define mutable shareable objects in Ruby, but C extensions can
|
164
172
|
# introduce them.
|
165
173
|
#
|
166
|
-
# It is prohibited to access instance variables of
|
167
|
-
#
|
174
|
+
# It is prohibited to access (get) instance variables of shareable objects in
|
175
|
+
# other ractors if the values of the variables aren't shareable. This can occur
|
176
|
+
# because modules/classes are shareable, but they can have instance variables
|
177
|
+
# whose values are not. In non-main ractors, it's also prohibited to set
|
178
|
+
# instance variables on classes/modules (even if the value is shareable).
|
168
179
|
#
|
169
180
|
# class C
|
170
181
|
# class << self
|
@@ -172,11 +183,12 @@
|
|
172
183
|
# end
|
173
184
|
# end
|
174
185
|
#
|
175
|
-
# C.tricky =
|
186
|
+
# C.tricky = "unshareable".dup
|
176
187
|
#
|
177
188
|
# r = Ractor.new(C) do |cls|
|
178
189
|
# puts "I see #{cls}"
|
179
190
|
# puts "I can't see #{cls.tricky}"
|
191
|
+
# cls.tricky = true # doesn't get here, but this would also raise an error
|
180
192
|
# end
|
181
193
|
# r.take
|
182
194
|
# # I see C
|
@@ -186,7 +198,7 @@
|
|
186
198
|
# only one that can access non-shareable constants.
|
187
199
|
#
|
188
200
|
# GOOD = 'good'.freeze
|
189
|
-
# BAD = 'bad'
|
201
|
+
# BAD = 'bad'.dup
|
190
202
|
#
|
191
203
|
# r = Ractor.new do
|
192
204
|
# puts "GOOD=#{GOOD}"
|
@@ -211,8 +223,8 @@
|
|
211
223
|
#
|
212
224
|
# ## Ractors vs threads
|
213
225
|
#
|
214
|
-
# Each ractor
|
215
|
-
#
|
226
|
+
# Each ractor has its own main Thread. New threads can be created from inside
|
227
|
+
# ractors (and, on CRuby, they share the GVL with other threads of this ractor).
|
216
228
|
#
|
217
229
|
# r = Ractor.new do
|
218
230
|
# a = 1
|
@@ -223,16 +235,15 @@
|
|
223
235
|
#
|
224
236
|
# ## Note on code examples
|
225
237
|
#
|
226
|
-
# In examples below, sometimes we use the following method to wait
|
227
|
-
# that are not currently blocked
|
228
|
-
# method.
|
238
|
+
# In the examples below, sometimes we use the following method to wait for
|
239
|
+
# ractors that are not currently blocked to finish (or to make progress).
|
229
240
|
#
|
230
241
|
# def wait
|
231
242
|
# sleep(0.1)
|
232
243
|
# end
|
233
244
|
#
|
234
245
|
# It is **only for demonstration purposes** and shouldn't be used in a real
|
235
|
-
# code. Most of the
|
246
|
+
# code. Most of the time, #take is used to wait for ractors to finish.
|
236
247
|
#
|
237
248
|
# ## Reference
|
238
249
|
#
|
@@ -243,13 +254,13 @@ class Ractor
|
|
243
254
|
# rdoc-file=ractor.rb
|
244
255
|
# - count()
|
245
256
|
# -->
|
246
|
-
# Returns
|
257
|
+
# Returns the number of Ractors currently running or blocking (waiting).
|
247
258
|
#
|
248
259
|
# Ractor.count #=> 1
|
249
260
|
# r = Ractor.new(name: 'example') { Ractor.yield(1) }
|
250
261
|
# Ractor.count #=> 2 (main + example ractor)
|
251
262
|
# r.take # wait for Ractor.yield(1)
|
252
|
-
# r.take # wait
|
263
|
+
# r.take # wait until r will finish
|
253
264
|
# Ractor.count #=> 1
|
254
265
|
#
|
255
266
|
def self.count: () -> Integer
|
@@ -281,8 +292,8 @@ class Ractor
|
|
281
292
|
# `obj` and all the objects it refers to will be frozen, unless they are already
|
282
293
|
# shareable.
|
283
294
|
#
|
284
|
-
# If `copy` keyword is `true`,
|
285
|
-
#
|
295
|
+
# If `copy` keyword is `true`, it will copy objects before freezing them, and
|
296
|
+
# will not modify `obj` or its internal objects.
|
286
297
|
#
|
287
298
|
# Note that the specification and implementation of this method are not mature
|
288
299
|
# and may be changed in the future.
|
@@ -317,16 +328,16 @@ class Ractor
|
|
317
328
|
# -->
|
318
329
|
# Create a new Ractor with args and a block.
|
319
330
|
#
|
320
|
-
#
|
321
|
-
# inside the block will refer to the current Ractor.
|
331
|
+
# The given block (Proc) will be isolated (can't access any outer variables).
|
332
|
+
# `self` inside the block will refer to the current Ractor.
|
322
333
|
#
|
323
334
|
# r = Ractor.new { puts "Hi, I am #{self.inspect}" }
|
324
335
|
# r.take
|
325
336
|
# # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
|
326
337
|
#
|
327
|
-
# `args` passed
|
328
|
-
#
|
329
|
-
# shareable,
|
338
|
+
# Any `args` passed are propagated to the block arguments by the same rules as
|
339
|
+
# objects sent via #send/Ractor.receive. If an argument in `args` is not
|
340
|
+
# shareable, it will be copied (via deep cloning, which might be inefficient).
|
330
341
|
#
|
331
342
|
# arg = [1, 2, 3]
|
332
343
|
# puts "Passing: #{arg} (##{arg.object_id})"
|
@@ -340,7 +351,7 @@ class Ractor
|
|
340
351
|
#
|
341
352
|
# Ractor's `name` can be set for debugging purposes:
|
342
353
|
#
|
343
|
-
# r = Ractor.new(name: 'my ractor') {}
|
354
|
+
# r = Ractor.new(name: 'my ractor') {}; r.take
|
344
355
|
# p r
|
345
356
|
# #=> #<Ractor:#3 my ractor test.rb:1 terminated>
|
346
357
|
#
|
@@ -350,8 +361,8 @@ class Ractor
|
|
350
361
|
# rdoc-file=ractor.rb
|
351
362
|
# - Ractor.receive -> msg
|
352
363
|
# -->
|
353
|
-
# Receive
|
354
|
-
#
|
364
|
+
# Receive a message from the incoming port of the current ractor (which was sent
|
365
|
+
# there by #send from another ractor).
|
355
366
|
#
|
356
367
|
# r = Ractor.new do
|
357
368
|
# v1 = Ractor.receive
|
@@ -361,7 +372,7 @@ class Ractor
|
|
361
372
|
# r.take
|
362
373
|
# # Here will be printed: "Received: message1"
|
363
374
|
#
|
364
|
-
# Alternatively, private instance method `receive` may be used:
|
375
|
+
# Alternatively, the private instance method `receive` may be used:
|
365
376
|
#
|
366
377
|
# r = Ractor.new do
|
367
378
|
# v1 = receive
|
@@ -369,7 +380,7 @@ class Ractor
|
|
369
380
|
# end
|
370
381
|
# r.send('message1')
|
371
382
|
# r.take
|
372
|
-
# #
|
383
|
+
# # This prints: "Received: message1"
|
373
384
|
#
|
374
385
|
# The method blocks if the queue is empty.
|
375
386
|
#
|
@@ -397,7 +408,7 @@ class Ractor
|
|
397
408
|
# Received: message2
|
398
409
|
#
|
399
410
|
# If close_incoming was called on the ractor, the method raises
|
400
|
-
# Ractor::ClosedError if there are no more messages in incoming queue:
|
411
|
+
# Ractor::ClosedError if there are no more messages in the incoming queue:
|
401
412
|
#
|
402
413
|
# Ractor.new do
|
403
414
|
# close_incoming
|
@@ -414,8 +425,9 @@ class Ractor
|
|
414
425
|
# -->
|
415
426
|
# Receive only a specific message.
|
416
427
|
#
|
417
|
-
# Instead of Ractor.receive, Ractor.receive_if can
|
418
|
-
# and you can choose the
|
428
|
+
# Instead of Ractor.receive, Ractor.receive_if can be given a pattern (or any
|
429
|
+
# filter) in a block and you can choose the messages to accept that are
|
430
|
+
# available in your ractor's incoming queue.
|
419
431
|
#
|
420
432
|
# r = Ractor.new do
|
421
433
|
# p Ractor.receive_if{|msg| msg.match?(/foo/)} #=> "foo3"
|
@@ -433,9 +445,9 @@ class Ractor
|
|
433
445
|
# bar1
|
434
446
|
# baz2
|
435
447
|
#
|
436
|
-
# If the block returns a truthy value, the message
|
437
|
-
#
|
438
|
-
#
|
448
|
+
# If the block returns a truthy value, the message is removed from the incoming
|
449
|
+
# queue and returned. Otherwise, the message remains in the incoming queue and
|
450
|
+
# the next messages are checked by the given block.
|
439
451
|
#
|
440
452
|
# If there are no messages left in the incoming queue, the method will block
|
441
453
|
# until new messages arrive.
|
@@ -461,7 +473,7 @@ class Ractor
|
|
461
473
|
# Received successfully: [1, 2, 3]
|
462
474
|
#
|
463
475
|
# Note that you can not call receive/receive_if in the given block recursively.
|
464
|
-
#
|
476
|
+
# You should not do any tasks in the block other than message filtration.
|
465
477
|
#
|
466
478
|
# Ractor.current << true
|
467
479
|
# Ractor.receive_if{|msg| Ractor.receive}
|
@@ -480,8 +492,8 @@ class Ractor
|
|
480
492
|
# rdoc-file=ractor.rb
|
481
493
|
# - Ractor.select(*ractors, [yield_value:, move: false]) -> [ractor or symbol, obj]
|
482
494
|
# -->
|
483
|
-
#
|
484
|
-
#
|
495
|
+
# Wait for any ractor to have something in its outgoing port, read from this
|
496
|
+
# ractor, and then return that ractor and the object received.
|
485
497
|
#
|
486
498
|
# r1 = Ractor.new {Ractor.yield 'from 1'}
|
487
499
|
# r2 = Ractor.new {Ractor.yield 'from 2'}
|
@@ -490,9 +502,10 @@ class Ractor
|
|
490
502
|
#
|
491
503
|
# puts "received #{obj.inspect} from #{r.inspect}"
|
492
504
|
# # Prints: received "from 1" from #<Ractor:#2 test.rb:1 running>
|
505
|
+
# # But could just as well print "from r2" here, either prints could be first.
|
493
506
|
#
|
494
|
-
# If one of the given ractors is the current ractor, and it
|
495
|
-
#
|
507
|
+
# If one of the given ractors is the current ractor, and it is selected, `r`
|
508
|
+
# will contain the `:receive` symbol instead of the ractor object.
|
496
509
|
#
|
497
510
|
# r1 = Ractor.new(Ractor.current) do |main|
|
498
511
|
# main.send 'to main'
|
@@ -504,10 +517,10 @@ class Ractor
|
|
504
517
|
#
|
505
518
|
# r, obj = Ractor.select(r1, r2, Ractor.current)
|
506
519
|
# puts "received #{obj.inspect} from #{r.inspect}"
|
507
|
-
# #
|
520
|
+
# # Could print: received "to main" from :receive
|
508
521
|
#
|
509
|
-
# If `yield_value` is provided, that value may be yielded if another
|
510
|
-
# calling #take. In this case, the pair `[:yield, nil]`
|
522
|
+
# If `yield_value` is provided, that value may be yielded if another ractor is
|
523
|
+
# calling #take. In this case, the pair `[:yield, nil]` is returned:
|
511
524
|
#
|
512
525
|
# r1 = Ractor.new(Ractor.current) do |main|
|
513
526
|
# puts "Received from main: #{main.take}"
|
@@ -524,8 +537,8 @@ class Ractor
|
|
524
537
|
# Received from main: 123
|
525
538
|
# Received nil from :yield
|
526
539
|
#
|
527
|
-
# `move` boolean flag defines whether yielded value
|
528
|
-
#
|
540
|
+
# `move` boolean flag defines whether yielded value will be copied (default) or
|
541
|
+
# moved.
|
529
542
|
#
|
530
543
|
def self.select: (*Ractor ractors, ?move: boolish, ?yield_value: untyped) -> [ Ractor | Symbol, untyped ]
|
531
544
|
|
@@ -536,7 +549,7 @@ class Ractor
|
|
536
549
|
# Checks if the object is shareable by ractors.
|
537
550
|
#
|
538
551
|
# Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are frozen
|
539
|
-
# Ractor.shareable?('foo') #=> false, unless the string is frozen due to #
|
552
|
+
# Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
|
540
553
|
# Ractor.shareable?('foo'.freeze) #=> true
|
541
554
|
#
|
542
555
|
# See also the "Shareable and unshareable objects" section in the Ractor class
|
@@ -548,13 +561,13 @@ class Ractor
|
|
548
561
|
# rdoc-file=ractor.rb
|
549
562
|
# - Ractor.yield(msg, move: false) -> nil
|
550
563
|
# -->
|
551
|
-
# Send a message to the current ractor's outgoing port to be
|
564
|
+
# Send a message to the current ractor's outgoing port to be accepted by #take.
|
552
565
|
#
|
553
566
|
# r = Ractor.new {Ractor.yield 'Hello from ractor'}
|
554
567
|
# puts r.take
|
555
568
|
# # Prints: "Hello from ractor"
|
556
569
|
#
|
557
|
-
#
|
570
|
+
# This method is blocking, and will return only when somebody consumes the sent
|
558
571
|
# message.
|
559
572
|
#
|
560
573
|
# r = Ractor.new do
|
@@ -580,7 +593,7 @@ class Ractor
|
|
580
593
|
# wait
|
581
594
|
# # `yield': The outgoing-port is already closed (Ractor::ClosedError)
|
582
595
|
#
|
583
|
-
# The meaning of `move` argument is the same as for #send.
|
596
|
+
# The meaning of the `move` argument is the same as for #send.
|
584
597
|
#
|
585
598
|
def self.yield: (untyped obj, ?move: boolish) -> untyped
|
586
599
|
|
@@ -613,9 +626,9 @@ class Ractor
|
|
613
626
|
# rdoc-file=ractor.rb
|
614
627
|
# - ractor.close_incoming -> true | false
|
615
628
|
# -->
|
616
|
-
# Closes the incoming port and returns
|
617
|
-
# to Ractor.receive in the ractor, and #send to the ractor will
|
618
|
-
# Ractor::ClosedError.
|
629
|
+
# Closes the incoming port and returns whether it was already closed. All
|
630
|
+
# further attempts to Ractor.receive in the ractor, and #send to the ractor will
|
631
|
+
# fail with Ractor::ClosedError.
|
619
632
|
#
|
620
633
|
# r = Ractor.new {sleep(500)}
|
621
634
|
# r.close_incoming #=> false
|
@@ -629,9 +642,9 @@ class Ractor
|
|
629
642
|
# rdoc-file=ractor.rb
|
630
643
|
# - ractor.close_outgoing -> true | false
|
631
644
|
# -->
|
632
|
-
# Closes the outgoing port and returns
|
633
|
-
# to Ractor.yield in the ractor, and #take from the ractor will
|
634
|
-
# Ractor::ClosedError.
|
645
|
+
# Closes the outgoing port and returns whether it was already closed. All
|
646
|
+
# further attempts to Ractor.yield in the ractor, and #take from the ractor will
|
647
|
+
# fail with Ractor::ClosedError.
|
635
648
|
#
|
636
649
|
# r = Ractor.new {sleep(500)}
|
637
650
|
# r.close_outgoing #=> false
|
@@ -660,7 +673,7 @@ class Ractor
|
|
660
673
|
# rdoc-file=ractor.rb
|
661
674
|
# - ractor.send(msg, move: false) -> self
|
662
675
|
# -->
|
663
|
-
# Send a message to a Ractor's incoming queue to be
|
676
|
+
# Send a message to a Ractor's incoming queue to be accepted by Ractor.receive.
|
664
677
|
#
|
665
678
|
# r = Ractor.new do
|
666
679
|
# value = Ractor.receive
|
@@ -677,7 +690,7 @@ class Ractor
|
|
677
690
|
# puts "Sent successfully"
|
678
691
|
# # Prints: "Sent successfully" immediately
|
679
692
|
#
|
680
|
-
#
|
693
|
+
# An attempt to send to a ractor which already finished its execution will raise
|
681
694
|
# Ractor::ClosedError.
|
682
695
|
#
|
683
696
|
# r = Ractor.new {}
|
@@ -697,11 +710,11 @@ class Ractor
|
|
697
710
|
# r.close_incoming
|
698
711
|
# r.send('test')
|
699
712
|
# # Ractor::ClosedError (The incoming-port is already closed)
|
700
|
-
# # The error
|
713
|
+
# # The error is raised immediately, not when the ractor tries to receive
|
701
714
|
#
|
702
|
-
# If the `obj` is unshareable, by default it
|
703
|
-
# cloning. If
|
704
|
-
# becomes inaccessible to sender.
|
715
|
+
# If the `obj` is unshareable, by default it will be copied into the receiving
|
716
|
+
# ractor by deep cloning. If `move: true` is passed, the object is *moved* into
|
717
|
+
# the receiving ractor and becomes inaccessible to the sender.
|
705
718
|
#
|
706
719
|
# r = Ractor.new {puts "Received: #{receive}"}
|
707
720
|
# msg = 'message'
|
@@ -714,7 +727,7 @@ class Ractor
|
|
714
727
|
# Received: message
|
715
728
|
# in `p': undefined method `inspect' for #<Ractor::MovedObject:0x000055c99b9b69b8>
|
716
729
|
#
|
717
|
-
# All references to the object and its parts will become invalid
|
730
|
+
# All references to the object and its parts will become invalid to the sender.
|
718
731
|
#
|
719
732
|
# r = Ractor.new {puts "Received: #{receive}"}
|
720
733
|
# s = 'message'
|
@@ -732,7 +745,7 @@ class Ractor
|
|
732
745
|
# # Ractor::MovedError (can not send any methods to a moved object)
|
733
746
|
# # ...but its item was still a reference to `s`, which was moved
|
734
747
|
#
|
735
|
-
# If the object
|
748
|
+
# If the object is shareable, `move: true` has no effect on it:
|
736
749
|
#
|
737
750
|
# r = Ractor.new {puts "Received: #{receive}"}
|
738
751
|
# s = 'message'.freeze
|
@@ -745,8 +758,8 @@ class Ractor
|
|
745
758
|
# rdoc-file=ractor.rb
|
746
759
|
# - ractor.take -> msg
|
747
760
|
# -->
|
748
|
-
#
|
749
|
-
# Ractor.yield or at ractor's
|
761
|
+
# Get a message from the ractor's outgoing port, which was put there by
|
762
|
+
# Ractor.yield or at ractor's termination.
|
750
763
|
#
|
751
764
|
# r = Ractor.new do
|
752
765
|
# Ractor.yield 'explicit yield'
|
@@ -756,10 +769,10 @@ class Ractor
|
|
756
769
|
# puts r.take #=> 'last value'
|
757
770
|
# puts r.take # Ractor::ClosedError (The outgoing-port is already closed)
|
758
771
|
#
|
759
|
-
# The fact that the last value is also
|
760
|
-
# can be used as
|
761
|
-
#
|
762
|
-
#
|
772
|
+
# The fact that the last value is also sent to the outgoing port means that
|
773
|
+
# `take` can be used as an analog of Thread#join ("just wait until ractor
|
774
|
+
# finishes"). However, it will raise if somebody has already consumed that
|
775
|
+
# message.
|
763
776
|
#
|
764
777
|
# If the outgoing port was closed with #close_outgoing, the method will raise
|
765
778
|
# Ractor::ClosedError.
|
@@ -773,7 +786,7 @@ class Ractor
|
|
773
786
|
# # Ractor::ClosedError (The outgoing-port is already closed)
|
774
787
|
# # The error would be raised immediately, not when ractor will try to receive
|
775
788
|
#
|
776
|
-
# If an uncaught exception is raised in the Ractor, it is propagated
|
789
|
+
# If an uncaught exception is raised in the Ractor, it is propagated by take as
|
777
790
|
# a Ractor::RemoteError.
|
778
791
|
#
|
779
792
|
# r = Ractor.new {raise "Something weird happened"}
|
@@ -786,8 +799,9 @@ class Ractor
|
|
786
799
|
# p e.cause # => #<RuntimeError: Something weird happened>
|
787
800
|
# end
|
788
801
|
#
|
789
|
-
# Ractor::ClosedError is a descendant of StopIteration, so the
|
790
|
-
# ractor will break
|
802
|
+
# Ractor::ClosedError is a descendant of StopIteration, so the termination of
|
803
|
+
# the ractor will break out of any loops that receive this message without
|
804
|
+
# propagating the error:
|
791
805
|
#
|
792
806
|
# r = Ractor.new do
|
793
807
|
# 3.times {|i| Ractor.yield "message #{i}"}
|
@@ -828,6 +842,7 @@ class Ractor
|
|
828
842
|
# rdoc-file=ractor.rb
|
829
843
|
# - receive_if(&b)
|
830
844
|
# -->
|
845
|
+
# same as Ractor.receive_if
|
831
846
|
#
|
832
847
|
def receive_if: () { (untyped) -> boolish } -> untyped
|
833
848
|
|
@@ -999,4 +1014,8 @@ class Ractor
|
|
999
1014
|
|
1000
1015
|
class UnsafeError < Ractor::Error
|
1001
1016
|
end
|
1017
|
+
|
1018
|
+
%a{annotate:rdoc:skip}
|
1019
|
+
class Selector
|
1020
|
+
end
|
1002
1021
|
end
|