rbs 3.3.2 → 3.4.0
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/.github/workflows/comments.yml +2 -5
- data/.github/workflows/ruby.yml +7 -8
- data/.github/workflows/typecheck.yml +37 -0
- data/CHANGELOG.md +65 -0
- data/Gemfile +1 -1
- data/Gemfile.lock +11 -11
- data/README.md +1 -0
- data/Rakefile +2 -2
- 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 +54 -121
- 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/gem.md +58 -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 +10 -2
- 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/minitest/0/minitest/test/lifecycle_hooks.rbs +6 -6
- 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 +24 -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
|