rbs 3.10.2 → 4.0.0.dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/comments.yml +2 -2
  3. data/.github/workflows/ruby.yml +24 -34
  4. data/.github/workflows/typecheck.yml +3 -1
  5. data/.github/workflows/windows.yml +2 -2
  6. data/.gitignore +0 -4
  7. data/CHANGELOG.md +0 -107
  8. data/README.md +1 -38
  9. data/Rakefile +20 -142
  10. data/Steepfile +1 -0
  11. data/config.yml +43 -1
  12. data/core/array.rbs +46 -96
  13. data/core/comparable.rbs +6 -13
  14. data/core/complex.rbs +25 -40
  15. data/core/dir.rbs +4 -4
  16. data/core/encoding.rbs +9 -6
  17. data/core/enumerable.rbs +3 -90
  18. data/core/enumerator.rbs +1 -43
  19. data/core/errno.rbs +0 -8
  20. data/core/errors.rbs +1 -28
  21. data/core/exception.rbs +2 -2
  22. data/core/fiber.rbs +20 -29
  23. data/core/file.rbs +19 -49
  24. data/core/file_test.rbs +1 -1
  25. data/core/float.rbs +33 -224
  26. data/core/gc.rbs +281 -417
  27. data/core/hash.rbs +727 -1023
  28. data/core/integer.rbs +63 -104
  29. data/core/io/buffer.rbs +10 -21
  30. data/core/io/wait.rbs +33 -11
  31. data/core/io.rbs +12 -14
  32. data/core/kernel.rbs +51 -61
  33. data/core/marshal.rbs +1 -1
  34. data/core/match_data.rbs +1 -1
  35. data/core/math.rbs +3 -42
  36. data/core/method.rbs +25 -63
  37. data/core/module.rbs +23 -101
  38. data/core/nil_class.rbs +3 -3
  39. data/core/numeric.rbs +17 -25
  40. data/core/object.rbs +3 -3
  41. data/core/object_space.rbs +15 -21
  42. data/core/proc.rbs +24 -30
  43. data/core/process.rbs +2 -2
  44. data/core/ractor.rbs +509 -361
  45. data/core/range.rbs +8 -7
  46. data/core/rational.rbs +34 -56
  47. data/core/rbs/unnamed/argf.rbs +2 -2
  48. data/core/rbs/unnamed/env_class.rbs +1 -1
  49. data/core/rbs/unnamed/random.rbs +2 -4
  50. data/core/regexp.rbs +20 -25
  51. data/core/ruby_vm.rbs +4 -6
  52. data/core/rubygems/errors.rbs +70 -3
  53. data/core/rubygems/rubygems.rbs +79 -11
  54. data/core/rubygems/version.rbs +3 -2
  55. data/core/set.rbs +359 -488
  56. data/core/signal.rbs +14 -24
  57. data/core/string.rbs +1236 -3165
  58. data/core/struct.rbs +1 -1
  59. data/core/symbol.rbs +11 -17
  60. data/core/thread.rbs +33 -95
  61. data/core/time.rbs +9 -35
  62. data/core/trace_point.rbs +4 -7
  63. data/core/unbound_method.rbs +6 -14
  64. data/docs/collection.md +2 -2
  65. data/docs/gem.md +1 -0
  66. data/docs/sigs.md +3 -3
  67. data/ext/rbs_extension/ast_translation.c +1077 -944
  68. data/ext/rbs_extension/ast_translation.h +0 -7
  69. data/ext/rbs_extension/class_constants.c +83 -71
  70. data/ext/rbs_extension/class_constants.h +7 -4
  71. data/ext/rbs_extension/extconf.rb +2 -24
  72. data/ext/rbs_extension/legacy_location.c +172 -173
  73. data/ext/rbs_extension/legacy_location.h +3 -8
  74. data/ext/rbs_extension/main.c +289 -239
  75. data/ext/rbs_extension/rbs_extension.h +0 -3
  76. data/ext/rbs_extension/rbs_string_bridging.h +0 -4
  77. data/include/rbs/ast.h +98 -37
  78. data/include/rbs/defines.h +12 -38
  79. data/include/rbs/lexer.h +114 -126
  80. data/include/rbs/location.h +14 -14
  81. data/include/rbs/parser.h +37 -21
  82. data/include/rbs/string.h +5 -3
  83. data/include/rbs/util/rbs_allocator.h +19 -40
  84. data/include/rbs/util/rbs_assert.h +1 -12
  85. data/include/rbs/util/rbs_constant_pool.h +3 -3
  86. data/include/rbs/util/rbs_encoding.h +1 -3
  87. data/include/rbs/util/rbs_unescape.h +1 -2
  88. data/lib/rbs/ast/ruby/annotations.rb +119 -0
  89. data/lib/rbs/ast/ruby/comment_block.rb +221 -0
  90. data/lib/rbs/ast/ruby/declarations.rb +86 -0
  91. data/lib/rbs/ast/ruby/helpers/constant_helper.rb +24 -0
  92. data/lib/rbs/ast/ruby/helpers/location_helper.rb +15 -0
  93. data/lib/rbs/ast/ruby/members.rb +213 -0
  94. data/lib/rbs/buffer.rb +104 -24
  95. data/lib/rbs/cli/validate.rb +40 -35
  96. data/lib/rbs/cli.rb +5 -6
  97. data/lib/rbs/collection/config/lockfile_generator.rb +0 -8
  98. data/lib/rbs/collection.rb +0 -1
  99. data/lib/rbs/definition.rb +6 -1
  100. data/lib/rbs/definition_builder/ancestor_builder.rb +65 -62
  101. data/lib/rbs/definition_builder/method_builder.rb +45 -30
  102. data/lib/rbs/definition_builder.rb +44 -9
  103. data/lib/rbs/environment/class_entry.rb +69 -0
  104. data/lib/rbs/environment/module_entry.rb +66 -0
  105. data/lib/rbs/environment.rb +244 -218
  106. data/lib/rbs/environment_loader.rb +8 -2
  107. data/lib/rbs/errors.rb +5 -4
  108. data/lib/rbs/inline_parser/comment_association.rb +117 -0
  109. data/lib/rbs/inline_parser.rb +206 -0
  110. data/lib/rbs/location_aux.rb +35 -3
  111. data/lib/rbs/parser_aux.rb +11 -6
  112. data/lib/rbs/prototype/runtime.rb +2 -2
  113. data/lib/rbs/resolver/constant_resolver.rb +2 -2
  114. data/lib/rbs/resolver/type_name_resolver.rb +38 -124
  115. data/lib/rbs/source.rb +99 -0
  116. data/lib/rbs/subtractor.rb +5 -6
  117. data/lib/rbs/test/type_check.rb +0 -14
  118. data/lib/rbs/types.rb +1 -3
  119. data/lib/rbs/version.rb +1 -1
  120. data/lib/rbs.rb +13 -1
  121. data/lib/rdoc/discover.rb +1 -1
  122. data/lib/rdoc_plugin/parser.rb +1 -1
  123. data/rbs.gemspec +1 -0
  124. data/sig/ancestor_builder.rbs +1 -1
  125. data/sig/ast/ruby/annotations.rbs +110 -0
  126. data/sig/ast/ruby/comment_block.rbs +119 -0
  127. data/sig/ast/ruby/declarations.rbs +60 -0
  128. data/sig/ast/ruby/helpers/constant_helper.rbs +11 -0
  129. data/sig/ast/ruby/helpers/location_helper.rbs +15 -0
  130. data/sig/ast/ruby/members.rbs +72 -0
  131. data/sig/buffer.rbs +63 -5
  132. data/sig/definition.rbs +1 -0
  133. data/sig/definition_builder.rbs +1 -1
  134. data/sig/environment/class_entry.rbs +50 -0
  135. data/sig/environment/module_entry.rbs +50 -0
  136. data/sig/environment.rbs +28 -133
  137. data/sig/errors.rbs +13 -6
  138. data/sig/inline_parser/comment_association.rbs +71 -0
  139. data/sig/inline_parser.rbs +87 -0
  140. data/sig/location.rbs +32 -7
  141. data/sig/manifest.yaml +1 -0
  142. data/sig/method_builder.rbs +7 -4
  143. data/sig/parser.rbs +16 -20
  144. data/sig/resolver/type_name_resolver.rbs +7 -38
  145. data/sig/source.rbs +48 -0
  146. data/sig/types.rbs +1 -4
  147. data/src/ast.c +290 -201
  148. data/src/lexer.c +2813 -2902
  149. data/src/lexer.re +4 -0
  150. data/src/lexstate.c +155 -169
  151. data/src/location.c +40 -40
  152. data/src/parser.c +2665 -2433
  153. data/src/string.c +48 -0
  154. data/src/util/rbs_allocator.c +76 -92
  155. data/src/util/rbs_assert.c +10 -10
  156. data/src/util/rbs_buffer.c +2 -2
  157. data/src/util/rbs_constant_pool.c +15 -13
  158. data/src/util/rbs_encoding.c +4062 -20097
  159. data/src/util/rbs_unescape.c +48 -85
  160. data/stdlib/bigdecimal/0/big_decimal.rbs +82 -100
  161. data/stdlib/bigdecimal-math/0/big_math.rbs +8 -169
  162. data/stdlib/cgi/0/core.rbs +393 -9
  163. data/stdlib/cgi/0/manifest.yaml +0 -1
  164. data/stdlib/coverage/0/coverage.rbs +1 -3
  165. data/stdlib/date/0/date.rbs +59 -67
  166. data/stdlib/date/0/date_time.rbs +1 -1
  167. data/stdlib/delegate/0/delegator.rbs +7 -10
  168. data/stdlib/erb/0/erb.rbs +347 -737
  169. data/stdlib/fileutils/0/fileutils.rbs +13 -18
  170. data/stdlib/forwardable/0/forwardable.rbs +0 -3
  171. data/stdlib/json/0/json.rbs +48 -68
  172. data/stdlib/net-http/0/net-http.rbs +0 -3
  173. data/stdlib/objspace/0/objspace.rbs +4 -9
  174. data/stdlib/open-uri/0/open-uri.rbs +0 -40
  175. data/stdlib/openssl/0/openssl.rbs +228 -331
  176. data/stdlib/optparse/0/optparse.rbs +3 -3
  177. data/stdlib/pathname/0/pathname.rbs +1380 -10
  178. data/stdlib/psych/0/psych.rbs +3 -3
  179. data/stdlib/rdoc/0/rdoc.rbs +1 -1
  180. data/stdlib/resolv/0/resolv.rbs +68 -25
  181. data/stdlib/ripper/0/ripper.rbs +2 -5
  182. data/stdlib/singleton/0/singleton.rbs +0 -3
  183. data/stdlib/socket/0/socket.rbs +1 -13
  184. data/stdlib/socket/0/tcp_socket.rbs +2 -10
  185. data/stdlib/stringio/0/stringio.rbs +85 -1176
  186. data/stdlib/strscan/0/string_scanner.rbs +31 -31
  187. data/stdlib/tempfile/0/tempfile.rbs +3 -3
  188. data/stdlib/time/0/time.rbs +1 -1
  189. data/stdlib/timeout/0/timeout.rbs +7 -63
  190. data/stdlib/tsort/0/cyclic.rbs +0 -3
  191. data/stdlib/uri/0/common.rbs +2 -11
  192. data/stdlib/uri/0/file.rbs +1 -1
  193. data/stdlib/uri/0/generic.rbs +16 -17
  194. data/stdlib/uri/0/rfc2396_parser.rbs +7 -6
  195. data/stdlib/zlib/0/zstream.rbs +0 -1
  196. metadata +39 -12
  197. data/.clang-format +0 -74
  198. data/.clangd +0 -2
  199. data/.github/workflows/c-check.yml +0 -54
  200. data/core/pathname.rbs +0 -1272
  201. data/core/ruby.rbs +0 -53
  202. data/docs/aliases.md +0 -79
  203. data/docs/encoding.md +0 -56
  204. data/ext/rbs_extension/compat.h +0 -10
  205. data/stdlib/cgi-escape/0/escape.rbs +0 -171
data/core/ractor.rbs CHANGED
@@ -1,19 +1,22 @@
1
1
  # <!-- rdoc-file=ractor.rb -->
2
- # Ractor.new creates a new Ractor, which can run in parallel with other ractors.
2
+ # Ractor is an Actor-model abstraction for Ruby that provides thread-safe
3
+ # parallel execution.
4
+ #
5
+ # Ractor.new makes a new Ractor, which can run in parallel.
3
6
  #
4
7
  # # The simplest ractor
5
8
  # r = Ractor.new {puts "I am in Ractor!"}
6
- # r.join # wait for it to finish
9
+ # r.take # wait for it to finish
7
10
  # # Here, "I am in Ractor!" is printed
8
11
  #
9
12
  # Ractors do not share all objects with each other. There are two main benefits
10
13
  # to this: across ractors, thread-safety concerns such as data-races and
11
14
  # race-conditions are not possible. The other benefit is parallelism.
12
15
  #
13
- # To achieve this, object sharing is limited across ractors. Unlike in threads,
14
- # ractors can't access all the objects available in other ractors. For example,
15
- # objects normally available through variables in the outer scope are prohibited
16
- # from being used across ractors.
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.
17
20
  #
18
21
  # a = 1
19
22
  # r = Ractor.new {puts "I am in Ractor! a=#{a}"}
@@ -24,37 +27,80 @@
24
27
  # a = 1
25
28
  # r = Ractor.new(a) { |a1| puts "I am in Ractor! a=#{a1}"}
26
29
  #
27
- # On CRuby (the default implementation), the Global Virtual Machine Lock (GVL)
28
- # is held per ractor, so ractors can run in parallel. This is unlike the
29
- # situation with threads on CRuby.
30
+ # On CRuby (the default implementation), Global Virtual Machine Lock (GVL) is
31
+ # held per ractor, so ractors can perform in parallel without locking each
32
+ # other. This is unlike the situation with threads on CRuby.
30
33
  #
31
34
  # Instead of accessing shared state, objects should be passed to and from
32
35
  # ractors by sending and receiving them as messages.
33
36
  #
34
37
  # a = 1
35
38
  # r = Ractor.new do
36
- # a_in_ractor = receive # receive blocks the Thread until our default port gets sent a message
39
+ # a_in_ractor = receive # receive blocks until somebody passes a message
37
40
  # puts "I am in Ractor! a=#{a_in_ractor}"
38
41
  # end
39
42
  # r.send(a) # pass it
40
- # r.join
43
+ # r.take
41
44
  # # Here, "I am in Ractor! a=1" is printed
42
45
  #
46
+ # There are two pairs of methods for sending/receiving messages:
47
+ #
48
+ # * Ractor#send and Ractor.receive for when the *sender* knows the receiver
49
+ # (push);
50
+ # * Ractor.yield and Ractor#take for when the *receiver* knows the sender
51
+ # (pull);
52
+ #
43
53
  # In addition to that, any arguments passed to Ractor.new are passed to the
44
54
  # block and available there as if received by Ractor.receive, and the last block
45
- # value can be received with Ractor#value.
55
+ # value is sent outside of the ractor as if sent by Ractor.yield.
56
+ #
57
+ # A little demonstration of a classic ping-pong:
58
+ #
59
+ # server = Ractor.new(name: "server") do
60
+ # puts "Server starts: #{self.inspect}"
61
+ # puts "Server sends: ping"
62
+ # Ractor.yield 'ping' # The server doesn't know the receiver and sends to whoever interested
63
+ # received = Ractor.receive # The server doesn't know the sender and receives from whoever sent
64
+ # puts "Server received: #{received}"
65
+ # end
66
+ #
67
+ # client = Ractor.new(server) do |srv| # The server is sent to the client, and available as srv
68
+ # puts "Client starts: #{self.inspect}"
69
+ # received = srv.take # The client takes a message from the server
70
+ # puts "Client received from " \
71
+ # "#{srv.inspect}: #{received}"
72
+ # puts "Client sends to " \
73
+ # "#{srv.inspect}: pong"
74
+ # srv.send 'pong' # The client sends a message to the server
75
+ # end
76
+ #
77
+ # [client, server].each(&:take) # Wait until they both finish
78
+ #
79
+ # This will output something like:
80
+ #
81
+ # Server starts: #<Ractor:#2 server test.rb:1 running>
82
+ # Server sends: ping
83
+ # Client starts: #<Ractor:#3 test.rb:8 running>
84
+ # Client received from #<Ractor:#2 server test.rb:1 blocking>: ping
85
+ # Client sends to #<Ractor:#2 server test.rb:1 blocking>: pong
86
+ # Server received: pong
87
+ #
88
+ # Ractors receive their messages via the *incoming port*, and send them to the
89
+ # *outgoing port*. Either one can be disabled with Ractor#close_incoming and
90
+ # Ractor#close_outgoing, respectively. When a ractor terminates, its ports are
91
+ # closed automatically.
46
92
  #
47
93
  # ## Shareable and unshareable objects
48
94
  #
49
- # When an object is sent to a ractor, it's important to understand whether the
50
- # object is shareable or unshareable. Most Ruby objects are unshareable objects.
51
- # Even frozen objects can be unshareable if they contain (through their instance
52
- # variables) unfrozen objects.
95
+ # When an object is sent to and from a ractor, it's important to understand
96
+ # whether the object is shareable or unshareable. Most Ruby objects are
97
+ # unshareable objects. Even frozen objects can be unshareable if they contain
98
+ # (through their instance variables) unfrozen objects.
53
99
  #
54
- # Shareable objects are those which can be used by several ractors at once
55
- # without compromising thread-safety, for example numbers, `true` and `false`.
100
+ # Shareable objects are those which can be used by several threads without
101
+ # compromising thread-safety, for example numbers, `true` and `false`.
56
102
  # Ractor.shareable? allows you to check this, and Ractor.make_shareable tries to
57
- # make the object shareable if it's not already and gives an error if it can't
103
+ # make the object shareable if it's not already, and gives an error if it can't
58
104
  # do it.
59
105
  #
60
106
  # Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are shareable
@@ -70,25 +116,25 @@
70
116
  # ary[0].frozen? #=> true
71
117
  # ary[1].frozen? #=> true
72
118
  #
73
- # When a shareable object is sent via #send, no additional processing occurs on
74
- # it and it becomes usable by both ractors. When an unshareable object is sent,
75
- # it can be either *copied* or *moved*. Copying is the default, and it copies
76
- # the object fully by deep cloning (Object#clone) the non-shareable parts of its
77
- # structure.
119
+ # When a shareable object is sent (via #send or Ractor.yield), no additional
120
+ # processing occurs on it. It just becomes usable by both ractors. When an
121
+ # unshareable object is sent, it can be either *copied* or *moved*. The first is
122
+ # the default, and it copies the object fully by deep cloning (Object#clone) the
123
+ # non-shareable parts of its structure.
78
124
  #
79
- # data = ['foo'.dup, 'bar'.freeze]
125
+ # data = ['foo', 'bar'.freeze]
80
126
  # r = Ractor.new do
81
127
  # data2 = Ractor.receive
82
128
  # puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}"
83
129
  # end
84
130
  # r.send(data)
85
- # r.join
131
+ # r.take
86
132
  # puts "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"
87
133
  #
88
134
  # This will output something like:
89
135
  #
90
- # In ractor: 8, 16, 24
91
- # Outside : 32, 40, 24
136
+ # In ractor: 340, 360, 320
137
+ # Outside : 380, 400, 320
92
138
  #
93
139
  # Note that the object ids of the array and the non-frozen string inside the
94
140
  # array have changed in the ractor because they are different objects. The
@@ -105,7 +151,7 @@
105
151
  # puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}"
106
152
  # end
107
153
  # r.send(data, move: true)
108
- # r.join
154
+ # r.take
109
155
  # puts "Outside: moved? #{Ractor::MovedObject === data}"
110
156
  # puts "Outside: #{data.inspect}"
111
157
  #
@@ -115,14 +161,14 @@
115
161
  # Outside: moved? true
116
162
  # test.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError)
117
163
  #
118
- # Notice that even `inspect` and more basic methods like `__id__` are
164
+ # Notice that even `inspect` (and more basic methods like `__id__`) is
119
165
  # inaccessible on a moved object.
120
166
  #
121
- # `Class` and `Module` objects are shareable and their class/module definitions
122
- # are shared between ractors. Ractor objects are also shareable. All operations
123
- # on shareable objects are thread-safe across ractors. Defining mutable,
124
- # shareable objects in Ruby is not possible, but C extensions can introduce
125
- # them.
167
+ # Class and Module objects are shareable so the class/module definitions are
168
+ # shared between ractors. Ractor objects are also shareable. All operations on
169
+ # shareable objects are thread-safe, so the thread-safety property will be kept.
170
+ # We can not define mutable shareable objects in Ruby, but C extensions can
171
+ # introduce them.
126
172
  #
127
173
  # It is prohibited to access (get) instance variables of shareable objects in
128
174
  # other ractors if the values of the variables aren't shareable. This can occur
@@ -143,7 +189,7 @@
143
189
  # puts "I can't see #{cls.tricky}"
144
190
  # cls.tricky = true # doesn't get here, but this would also raise an error
145
191
  # end
146
- # r.join
192
+ # r.take
147
193
  # # I see C
148
194
  # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
149
195
  #
@@ -157,7 +203,7 @@
157
203
  # puts "GOOD=#{GOOD}"
158
204
  # puts "BAD=#{BAD}"
159
205
  # end
160
- # r.join
206
+ # r.take
161
207
  # # GOOD=good
162
208
  # # can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError)
163
209
  #
@@ -167,7 +213,7 @@
167
213
  # puts "I see #{C}"
168
214
  # puts "I can't see #{C.tricky}"
169
215
  # end
170
- # r.join
216
+ # r.take
171
217
  # # I see C
172
218
  # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
173
219
  #
@@ -183,21 +229,20 @@
183
229
  # a = 1
184
230
  # Thread.new {puts "Thread in ractor: a=#{a}"}.join
185
231
  # end
186
- # r.join
232
+ # r.take
187
233
  # # Here "Thread in ractor: a=1" will be printed
188
234
  #
189
235
  # ## Note on code examples
190
236
  #
191
237
  # In the examples below, sometimes we use the following method to wait for
192
- # ractors to make progress or finish.
238
+ # ractors that are not currently blocked to finish (or to make progress).
193
239
  #
194
240
  # def wait
195
241
  # sleep(0.1)
196
242
  # end
197
243
  #
198
- # This is **only for demonstration purposes** and shouldn't be used in a real
199
- # code. Most of the time, #join is used to wait for ractors to finish and
200
- # Ractor.receive is used to wait for messages.
244
+ # It is **only for demonstration purposes** and shouldn't be used in a real
245
+ # code. Most of the time, #take is used to wait for ractors to finish.
201
246
  #
202
247
  # ## Reference
203
248
  #
@@ -216,7 +261,7 @@ class Ractor
216
261
  # rdoc-file=ractor.rb
217
262
  # - [](sym)
218
263
  # -->
219
- # Gets a value from ractor-local storage for the current Ractor.
264
+ # get a value from ractor-local storage of current Ractor
220
265
  #
221
266
  def self.[]: (Symbol) -> untyped
222
267
 
@@ -224,7 +269,7 @@ class Ractor
224
269
  # rdoc-file=ractor.rb
225
270
  # - []=(sym, val)
226
271
  # -->
227
- # Sets a value in ractor-local storage for the current Ractor.
272
+ # set a value in ractor-local storage of current Ractor
228
273
  #
229
274
  def self.[]=: (Symbol, untyped) -> untyped
230
275
 
@@ -232,13 +277,13 @@ class Ractor
232
277
  # rdoc-file=ractor.rb
233
278
  # - count()
234
279
  # -->
235
- # Returns the number of ractors currently running or blocking (waiting).
280
+ # Returns the number of Ractors currently running or blocking (waiting).
236
281
  #
237
282
  # Ractor.count #=> 1
238
- # r = Ractor.new(name: 'example') { Ractor.receive }
283
+ # r = Ractor.new(name: 'example') { Ractor.yield(1) }
239
284
  # Ractor.count #=> 2 (main + example ractor)
240
- # r << 42 # r's Ractor.receive will resume
241
- # r.join # wait for r's termination
285
+ # r.take # wait for Ractor.yield(1)
286
+ # r.take # wait until r will finish
242
287
  # Ractor.count #=> 1
243
288
  #
244
289
  def self.count: () -> Integer
@@ -257,7 +302,7 @@ class Ractor
257
302
  # rdoc-file=ractor.rb
258
303
  # - main()
259
304
  # -->
260
- # Returns the main ractor.
305
+ # returns main ractor
261
306
  #
262
307
  def self.main: () -> Ractor
263
308
 
@@ -265,7 +310,7 @@ class Ractor
265
310
  # rdoc-file=ractor.rb
266
311
  # - main?()
267
312
  # -->
268
- # Returns true if the current ractor is the main ractor.
313
+ # return true if the current ractor is main ractor
269
314
  #
270
315
  def self.main?: () -> boolish
271
316
 
@@ -273,7 +318,7 @@ class Ractor
273
318
  # rdoc-file=ractor.rb
274
319
  # - Ractor.make_shareable(obj, copy: false) -> shareable_obj
275
320
  # -->
276
- # Makes `obj` shareable between ractors.
321
+ # Make `obj` shareable between ractors.
277
322
  #
278
323
  # `obj` and all the objects it refers to will be frozen, unless they are already
279
324
  # shareable.
@@ -312,13 +357,13 @@ class Ractor
312
357
  # rdoc-file=ractor.rb
313
358
  # - Ractor.new(*args, name: nil) {|*args| block } -> ractor
314
359
  # -->
315
- # Creates a new Ractor with args and a block.
360
+ # Create a new Ractor with args and a block.
316
361
  #
317
- # The given block (Proc) is isolated (can't access any outer variables). `self`
318
- # inside the block will refer to the current Ractor.
362
+ # The given block (Proc) will be isolated (can't access any outer variables).
363
+ # `self` inside the block will refer to the current Ractor.
319
364
  #
320
365
  # r = Ractor.new { puts "Hi, I am #{self.inspect}" }
321
- # r.join
366
+ # r.take
322
367
  # # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
323
368
  #
324
369
  # Any `args` passed are propagated to the block arguments by the same rules as
@@ -330,14 +375,14 @@ class Ractor
330
375
  # r = Ractor.new(arg) {|received_arg|
331
376
  # puts "Received: #{received_arg} (##{received_arg.object_id})"
332
377
  # }
333
- # r.join
378
+ # r.take
334
379
  # # Prints:
335
380
  # # Passing: [1, 2, 3] (#280)
336
381
  # # Received: [1, 2, 3] (#300)
337
382
  #
338
383
  # Ractor's `name` can be set for debugging purposes:
339
384
  #
340
- # r = Ractor.new(name: 'my ractor') {}; r.join
385
+ # r = Ractor.new(name: 'my ractor') {}; r.take
341
386
  # p r
342
387
  # #=> #<Ractor:#3 my ractor test.rb:1 terminated>
343
388
  #
@@ -345,12 +390,128 @@ class Ractor
345
390
 
346
391
  # <!--
347
392
  # rdoc-file=ractor.rb
348
- # - Ractor.receive -> obj
393
+ # - Ractor.receive -> msg
349
394
  # -->
350
- # Receives a message from the current ractor's default port.
395
+ # Receive a message from the incoming port of the current ractor (which was sent
396
+ # there by #send from another ractor).
397
+ #
398
+ # r = Ractor.new do
399
+ # v1 = Ractor.receive
400
+ # puts "Received: #{v1}"
401
+ # end
402
+ # r.send('message1')
403
+ # r.take
404
+ # # Here will be printed: "Received: message1"
405
+ #
406
+ # Alternatively, the private instance method `receive` may be used:
407
+ #
408
+ # r = Ractor.new do
409
+ # v1 = receive
410
+ # puts "Received: #{v1}"
411
+ # end
412
+ # r.send('message1')
413
+ # r.take
414
+ # # This prints: "Received: message1"
415
+ #
416
+ # The method blocks if the queue is empty.
417
+ #
418
+ # r = Ractor.new do
419
+ # puts "Before first receive"
420
+ # v1 = Ractor.receive
421
+ # puts "Received: #{v1}"
422
+ # v2 = Ractor.receive
423
+ # puts "Received: #{v2}"
424
+ # end
425
+ # wait
426
+ # puts "Still not received"
427
+ # r.send('message1')
428
+ # wait
429
+ # puts "Still received only one"
430
+ # r.send('message2')
431
+ # r.take
432
+ #
433
+ # Output:
434
+ #
435
+ # Before first receive
436
+ # Still not received
437
+ # Received: message1
438
+ # Still received only one
439
+ # Received: message2
440
+ #
441
+ # If close_incoming was called on the ractor, the method raises
442
+ # Ractor::ClosedError if there are no more messages in the incoming queue:
443
+ #
444
+ # Ractor.new do
445
+ # close_incoming
446
+ # receive
447
+ # end
448
+ # wait
449
+ # # in `receive': The incoming port is already closed => #<Ractor:#2 test.rb:1 running> (Ractor::ClosedError)
351
450
  #
352
451
  def self.receive: () -> untyped
353
452
 
453
+ # <!--
454
+ # rdoc-file=ractor.rb
455
+ # - Ractor.receive_if {|msg| block } -> msg
456
+ # -->
457
+ # Receive only a specific message.
458
+ #
459
+ # Instead of Ractor.receive, Ractor.receive_if can be given a pattern (or any
460
+ # filter) in a block and you can choose the messages to accept that are
461
+ # available in your ractor's incoming queue.
462
+ #
463
+ # r = Ractor.new do
464
+ # p Ractor.receive_if{|msg| msg.match?(/foo/)} #=> "foo3"
465
+ # p Ractor.receive_if{|msg| msg.match?(/bar/)} #=> "bar1"
466
+ # p Ractor.receive_if{|msg| msg.match?(/baz/)} #=> "baz2"
467
+ # end
468
+ # r << "bar1"
469
+ # r << "baz2"
470
+ # r << "foo3"
471
+ # r.take
472
+ #
473
+ # This will output:
474
+ #
475
+ # foo3
476
+ # bar1
477
+ # baz2
478
+ #
479
+ # If the block returns a truthy value, the message is removed from the incoming
480
+ # queue and returned. Otherwise, the message remains in the incoming queue and
481
+ # the next messages are checked by the given block.
482
+ #
483
+ # If there are no messages left in the incoming queue, the method will block
484
+ # until new messages arrive.
485
+ #
486
+ # If the block is escaped by break/return/exception/throw, the message is
487
+ # removed from the incoming queue as if a truthy value had been returned.
488
+ #
489
+ # r = Ractor.new do
490
+ # val = Ractor.receive_if{|msg| msg.is_a?(Array)}
491
+ # puts "Received successfully: #{val}"
492
+ # end
493
+ #
494
+ # r.send(1)
495
+ # r.send('test')
496
+ # wait
497
+ # puts "2 non-matching sent, nothing received"
498
+ # r.send([1, 2, 3])
499
+ # wait
500
+ #
501
+ # Prints:
502
+ #
503
+ # 2 non-matching sent, nothing received
504
+ # Received successfully: [1, 2, 3]
505
+ #
506
+ # Note that you can not call receive/receive_if in the given block recursively.
507
+ # You should not do any tasks in the block other than message filtration.
508
+ #
509
+ # Ractor.current << true
510
+ # Ractor.receive_if{|msg| Ractor.receive}
511
+ # #=> `receive': can not call receive/receive_if recursively (Ractor::Error)
512
+ #
513
+ def self.receive_if: () { (untyped) -> boolish } -> untyped
514
+
354
515
  # <!--
355
516
  # rdoc-file=ractor.rb
356
517
  # - recv()
@@ -360,50 +521,57 @@ class Ractor
360
521
 
361
522
  # <!--
362
523
  # rdoc-file=ractor.rb
363
- # - Ractor.select(*ractors_or_ports) -> [ractor or port, obj]
524
+ # - Ractor.select(*ractors, [yield_value:, move: false]) -> [ractor or symbol, obj]
364
525
  # -->
365
- # Blocks the current Thread until one of the given ports has received a message.
366
- # Returns an array of two elements where the first element is the Port and the
367
- # second is the received object. This method can also accept Ractor objects
368
- # themselves, and in that case will wait until one has terminated and return a
369
- # two-element array where the first element is the ractor and the second is its
370
- # termination value.
371
- #
372
- # p1, p2 = Ractor::Port.new, Ractor::Port.new
373
- # ps = [p1, p2]
374
- # rs = 2.times.map do |i|
375
- # Ractor.new(ps.shift, i) do |p, i|
376
- # sleep rand(0.99)
377
- # p.send("r#{i}")
378
- # sleep rand(0.99)
379
- # "r#{i} done"
380
- # end
381
- # end
526
+ # Wait for any ractor to have something in its outgoing port, read from this
527
+ # ractor, and then return that ractor and the object received.
528
+ #
529
+ # r1 = Ractor.new {Ractor.yield 'from 1'}
530
+ # r2 = Ractor.new {Ractor.yield 'from 2'}
531
+ #
532
+ # r, obj = Ractor.select(r1, r2)
533
+ #
534
+ # puts "received #{obj.inspect} from #{r.inspect}"
535
+ # # Prints: received "from 1" from #<Ractor:#2 test.rb:1 running>
536
+ # # But could just as well print "from r2" here, either prints could be first.
382
537
  #
383
- # waiting_on = [p1, p2, *rs]
384
- # until waiting_on.empty?
385
- # received_on, obj = Ractor.select(*waiting_on)
386
- # waiting_on.delete(received_on)
387
- # puts obj
538
+ # If one of the given ractors is the current ractor, and it is selected, `r`
539
+ # will contain the `:receive` symbol instead of the ractor object.
540
+ #
541
+ # r1 = Ractor.new(Ractor.current) do |main|
542
+ # main.send 'to main'
543
+ # Ractor.yield 'from 1'
544
+ # end
545
+ # r2 = Ractor.new do
546
+ # Ractor.yield 'from 2'
388
547
  # end
389
548
  #
390
- # # r0
391
- # # r1
392
- # # r1 done
393
- # # r0 done
549
+ # r, obj = Ractor.select(r1, r2, Ractor.current)
550
+ # puts "received #{obj.inspect} from #{r.inspect}"
551
+ # # Could print: received "to main" from :receive
394
552
  #
395
- # The following example is almost equivalent to `ractors.map(&:value)` except
396
- # the thread is unblocked when any of the ractors has terminated as opposed to
397
- # waiting for their termination in the array element order.
553
+ # If `yield_value` is provided, that value may be yielded if another ractor is
554
+ # calling #take. In this case, the pair `[:yield, nil]` is returned:
398
555
  #
399
- # values = []
400
- # until ractors.empty?
401
- # r, val = Ractor.select(*ractors)
402
- # ractors.delete(r)
403
- # values << val
556
+ # r1 = Ractor.new(Ractor.current) do |main|
557
+ # puts "Received from main: #{main.take}"
404
558
  # end
405
559
  #
406
- def self.select: (?) -> Array[untyped]
560
+ # puts "Trying to select"
561
+ # r, obj = Ractor.select(r1, Ractor.current, yield_value: 123)
562
+ # wait
563
+ # puts "Received #{obj.inspect} from #{r.inspect}"
564
+ #
565
+ # This will print:
566
+ #
567
+ # Trying to select
568
+ # Received from main: 123
569
+ # Received nil from :yield
570
+ #
571
+ # `move` boolean flag defines whether yielded value will be copied (default) or
572
+ # moved.
573
+ #
574
+ def self.select: (*Ractor ractors, ?move: boolish, ?yield_value: untyped) -> [ Ractor | Symbol, untyped ]
407
575
 
408
576
  # <!--
409
577
  # rdoc-file=ractor.rb
@@ -411,7 +579,7 @@ class Ractor
411
579
  # -->
412
580
  # Checks if the object is shareable by ractors.
413
581
  #
414
- # Ractor.shareable?(1) #=> true -- numbers are shareable
582
+ # Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are frozen
415
583
  # Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
416
584
  # Ractor.shareable?('foo'.freeze) #=> true
417
585
  #
@@ -420,44 +588,13 @@ class Ractor
420
588
  #
421
589
  def self.shareable?: (untyped obj) -> bool
422
590
 
423
- # <!--
424
- # rdoc-file=ractor.rb
425
- # - Ractor.shareable_proc(self: nil){} -> shareable proc
426
- # -->
427
- # Returns a shareable copy of the given block's Proc. The value of `self` in the
428
- # Proc will be replaced with the value passed via the `self:` keyword, or `nil`
429
- # if not given.
430
- #
431
- # In a shareable Proc, access to any outer variables if prohibited.
432
- #
433
- # a = 42
434
- # Ractor.shareable_proc{ p a }
435
- # #=> can not isolate a Proc because it accesses outer variables (a). (ArgumentError)
436
- #
437
- # The value of `self` in the Proc must be a shareable object.
438
- #
439
- # Ractor.shareable_proc(self: self){}
440
- # #=> self should be shareable: main (Ractor::IsolationError)
441
- #
442
- def self.shareable_proc: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T
443
- | [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T
444
-
445
- # <!--
446
- # rdoc-file=ractor.rb
447
- # - Ractor.shareable_lambda(self: nil){} -> shareable lambda
448
- # -->
449
- # Same as Ractor.shareable_proc, but returns a lambda Proc.
450
- #
451
- def self.shareable_lambda: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T
452
- | [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T
453
-
454
591
  # <!--
455
592
  # rdoc-file=ractor.rb
456
593
  # - Ractor.store_if_absent(key){ init_block }
457
594
  # -->
458
- # If the corresponding ractor-local value is not set, yields a value with
459
- # init_block and stores the value in a thread-safe manner. This method returns
460
- # the stored value.
595
+ # If the correponding value is not set, yield a value with init_block and store
596
+ # the value in thread-safe manner. This method returns corresponding stored
597
+ # value.
461
598
  #
462
599
  # (1..10).map{
463
600
  # Thread.new(it){|i|
@@ -470,7 +607,47 @@ class Ractor
470
607
 
471
608
  # <!--
472
609
  # rdoc-file=ractor.rb
473
- # - <<(...)
610
+ # - Ractor.yield(msg, move: false) -> nil
611
+ # -->
612
+ # Send a message to the current ractor's outgoing port to be accepted by #take.
613
+ #
614
+ # r = Ractor.new {Ractor.yield 'Hello from ractor'}
615
+ # puts r.take
616
+ # # Prints: "Hello from ractor"
617
+ #
618
+ # This method is blocking, and will return only when somebody consumes the sent
619
+ # message.
620
+ #
621
+ # r = Ractor.new do
622
+ # Ractor.yield 'Hello from ractor'
623
+ # puts "Ractor: after yield"
624
+ # end
625
+ # wait
626
+ # puts "Still not taken"
627
+ # puts r.take
628
+ #
629
+ # This will print:
630
+ #
631
+ # Still not taken
632
+ # Hello from ractor
633
+ # Ractor: after yield
634
+ #
635
+ # If the outgoing port was closed with #close_outgoing, the method will raise:
636
+ #
637
+ # r = Ractor.new do
638
+ # close_outgoing
639
+ # Ractor.yield 'Hello from ractor'
640
+ # end
641
+ # wait
642
+ # # `yield': The outgoing-port is already closed (Ractor::ClosedError)
643
+ #
644
+ # The meaning of the `move` argument is the same as for #send.
645
+ #
646
+ def self.yield: (untyped obj, ?move: boolish) -> untyped
647
+
648
+ # <!--
649
+ # rdoc-file=ractor.rb
650
+ # - <<(obj, move: false)
474
651
  # -->
475
652
  #
476
653
  alias << send
@@ -479,117 +656,225 @@ class Ractor
479
656
  # rdoc-file=ractor.rb
480
657
  # - [](sym)
481
658
  # -->
482
- # Gets a value from ractor-local storage for the current Ractor. Obsolete, use
659
+ # get a value from ractor-local storage of current Ractor Obsolete and use
483
660
  # Ractor.[] instead.
484
661
  #
485
- %a{deprecated: Use Ractor.[] instead}
486
662
  def []: (interned sym) -> untyped
487
663
 
488
664
  # <!--
489
665
  # rdoc-file=ractor.rb
490
666
  # - []=(sym, val)
491
667
  # -->
492
- # Sets a value in ractor-local storage for the current Ractor. Obsolete, use
668
+ # set a value in ractor-local storage of current Ractor Obsolete and use
493
669
  # Ractor.[]= instead.
494
670
  #
495
- %a{deprecated: Use Ractor.[]= instead}
496
671
  def []=: [T] (interned sym, T val) -> T
497
672
 
498
673
  # <!--
499
674
  # rdoc-file=ractor.rb
500
- # - ractor.default_port -> port object
675
+ # - ractor.close_incoming -> true | false
501
676
  # -->
502
- # Returns the default port of the Ractor.
677
+ # Closes the incoming port and returns whether it was already closed. All
678
+ # further attempts to Ractor.receive in the ractor, and #send to the ractor will
679
+ # fail with Ractor::ClosedError.
503
680
  #
504
- def default_port: () -> Port[untyped]
681
+ # r = Ractor.new {sleep(500)}
682
+ # r.close_incoming #=> false
683
+ # r.close_incoming #=> true
684
+ # r.send('test')
685
+ # # Ractor::ClosedError (The incoming-port is already closed)
686
+ #
687
+ def close_incoming: () -> bool
505
688
 
506
689
  # <!--
507
690
  # rdoc-file=ractor.rb
508
- # - inspect()
691
+ # - ractor.close_outgoing -> true | false
509
692
  # -->
693
+ # Closes the outgoing port and returns whether it was already closed. All
694
+ # further attempts to Ractor.yield in the ractor, and #take from the ractor will
695
+ # fail with Ractor::ClosedError.
510
696
  #
511
- def inspect: () -> String
697
+ # r = Ractor.new {sleep(500)}
698
+ # r.close_outgoing #=> false
699
+ # r.close_outgoing #=> true
700
+ # r.take
701
+ # # Ractor::ClosedError (The outgoing-port is already closed)
702
+ #
703
+ def close_outgoing: () -> bool
512
704
 
513
705
  # <!--
514
706
  # rdoc-file=ractor.rb
515
- # - ractor.join -> self
707
+ # - inspect()
516
708
  # -->
517
- # Waits for the termination of the Ractor. If the Ractor was aborted (terminated
518
- # by an unhandled exception), the exception is raised in the current ractor.
519
- #
520
- # Ractor.new{}.join #=> ractor
521
709
  #
522
- # Ractor.new{ raise "foo" }.join
523
- # #=> raises the exception "foo (RuntimeError)"
524
- #
525
- def join: () -> self
710
+ def inspect: () -> String
526
711
 
527
712
  # <!--
528
713
  # rdoc-file=ractor.rb
529
714
  # - name()
530
715
  # -->
531
- # Returns the name set in Ractor.new, or `nil`.
716
+ # The name set in Ractor.new, or `nil`.
532
717
  #
533
718
  def name: () -> String?
534
719
 
535
720
  # <!--
536
721
  # rdoc-file=ractor.rb
537
- # - ractor.monitor(port) -> self
722
+ # - ractor.send(msg, move: false) -> self
538
723
  # -->
539
- # Registers the port as a monitoring port for this ractor. When the ractor
540
- # terminates, the port receives a Symbol object.
724
+ # Send a message to a Ractor's incoming queue to be accepted by Ractor.receive.
541
725
  #
542
- # * `:exited` is sent if the ractor terminates without an unhandled exception.
543
- # * `:aborted` is sent if the ractor terminates by an unhandled exception.
726
+ # r = Ractor.new do
727
+ # value = Ractor.receive
728
+ # puts "Received #{value}"
729
+ # end
730
+ # r.send 'message'
731
+ # # Prints: "Received: message"
544
732
  #
545
- # r = Ractor.new{ some_task() }
546
- # r.monitor(port = Ractor::Port.new)
547
- # port.receive #=> :exited and r is terminated
733
+ # The method is non-blocking (will return immediately even if the ractor is not
734
+ # ready to receive anything):
548
735
  #
549
- # r = Ractor.new{ raise "foo" }
550
- # r.monitor(port = Ractor::Port.new)
551
- # port.receive #=> :aborted and r is terminated by the RuntimeError "foo"
736
+ # r = Ractor.new {sleep(5)}
737
+ # r.send('test')
738
+ # puts "Sent successfully"
739
+ # # Prints: "Sent successfully" immediately
552
740
  #
553
- def monitor: [T < Symbol] (Port[T]) -> untyped
554
-
555
- # <!--
556
- # rdoc-file=ractor.rb
557
- # - ractor.send(msg, move: false) -> self
558
- # -->
559
- # This is equivalent to Port#send to the ractor's #default_port.
741
+ # An attempt to send to a ractor which already finished its execution will raise
742
+ # Ractor::ClosedError.
743
+ #
744
+ # r = Ractor.new {}
745
+ # r.take
746
+ # p r
747
+ # # "#<Ractor:#6 (irb):23 terminated>"
748
+ # r.send('test')
749
+ # # Ractor::ClosedError (The incoming-port is already closed)
750
+ #
751
+ # If close_incoming was called on the ractor, the method also raises
752
+ # Ractor::ClosedError.
753
+ #
754
+ # r = Ractor.new do
755
+ # sleep(500)
756
+ # receive
757
+ # end
758
+ # r.close_incoming
759
+ # r.send('test')
760
+ # # Ractor::ClosedError (The incoming-port is already closed)
761
+ # # The error is raised immediately, not when the ractor tries to receive
762
+ #
763
+ # If the `obj` is unshareable, by default it will be copied into the receiving
764
+ # ractor by deep cloning. If `move: true` is passed, the object is *moved* into
765
+ # the receiving ractor and becomes inaccessible to the sender.
766
+ #
767
+ # r = Ractor.new {puts "Received: #{receive}"}
768
+ # msg = 'message'
769
+ # r.send(msg, move: true)
770
+ # r.take
771
+ # p msg
772
+ #
773
+ # This prints:
774
+ #
775
+ # Received: message
776
+ # in `p': undefined method `inspect' for #<Ractor::MovedObject:0x000055c99b9b69b8>
777
+ #
778
+ # All references to the object and its parts will become invalid to the sender.
779
+ #
780
+ # r = Ractor.new {puts "Received: #{receive}"}
781
+ # s = 'message'
782
+ # ary = [s]
783
+ # copy = ary.dup
784
+ # r.send(ary, move: true)
785
+ #
786
+ # s.inspect
787
+ # # Ractor::MovedError (can not send any methods to a moved object)
788
+ # ary.class
789
+ # # Ractor::MovedError (can not send any methods to a moved object)
790
+ # copy.class
791
+ # # => Array, it is different object
792
+ # copy[0].inspect
793
+ # # Ractor::MovedError (can not send any methods to a moved object)
794
+ # # ...but its item was still a reference to `s`, which was moved
795
+ #
796
+ # If the object is shareable, `move: true` has no effect on it:
797
+ #
798
+ # r = Ractor.new {puts "Received: #{receive}"}
799
+ # s = 'message'.freeze
800
+ # r.send(s, move: true)
801
+ # s.inspect #=> "message", still available
560
802
  #
561
803
  def send: (untyped obj, ?move: boolish) -> Ractor
562
804
 
563
805
  # <!--
564
806
  # rdoc-file=ractor.rb
565
- # - to_s()
807
+ # - ractor.take -> msg
566
808
  # -->
809
+ # Get a message from the ractor's outgoing port, which was put there by
810
+ # Ractor.yield or at ractor's termination.
567
811
  #
568
- alias to_s inspect
569
-
570
- # <!--
571
- # rdoc-file=ractor.rb
572
- # - ractor.unmonitor(port) -> self
573
- # -->
574
- # Unregisters the port from the monitoring ports for this ractor.
812
+ # r = Ractor.new do
813
+ # Ractor.yield 'explicit yield'
814
+ # 'last value'
815
+ # end
816
+ # puts r.take #=> 'explicit yield'
817
+ # puts r.take #=> 'last value'
818
+ # puts r.take # Ractor::ClosedError (The outgoing-port is already closed)
819
+ #
820
+ # The fact that the last value is also sent to the outgoing port means that
821
+ # `take` can be used as an analog of Thread#join ("just wait until ractor
822
+ # finishes"). However, it will raise if somebody has already consumed that
823
+ # message.
824
+ #
825
+ # If the outgoing port was closed with #close_outgoing, the method will raise
826
+ # Ractor::ClosedError.
827
+ #
828
+ # r = Ractor.new do
829
+ # sleep(500)
830
+ # Ractor.yield 'Hello from ractor'
831
+ # end
832
+ # r.close_outgoing
833
+ # r.take
834
+ # # Ractor::ClosedError (The outgoing-port is already closed)
835
+ # # The error would be raised immediately, not when ractor will try to receive
836
+ #
837
+ # If an uncaught exception is raised in the Ractor, it is propagated by take as
838
+ # a Ractor::RemoteError.
839
+ #
840
+ # r = Ractor.new {raise "Something weird happened"}
575
841
  #
576
- def unmonitor: (Port[untyped]) -> self
842
+ # begin
843
+ # r.take
844
+ # rescue => e
845
+ # p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
846
+ # p e.ractor == r # => true
847
+ # p e.cause # => #<RuntimeError: Something weird happened>
848
+ # end
849
+ #
850
+ # Ractor::ClosedError is a descendant of StopIteration, so the termination of
851
+ # the ractor will break out of any loops that receive this message without
852
+ # propagating the error:
853
+ #
854
+ # r = Ractor.new do
855
+ # 3.times {|i| Ractor.yield "message #{i}"}
856
+ # "finishing"
857
+ # end
858
+ #
859
+ # loop {puts "Received: " + r.take}
860
+ # puts "Continue successfully"
861
+ #
862
+ # This will print:
863
+ #
864
+ # Received: message 0
865
+ # Received: message 1
866
+ # Received: message 2
867
+ # Received: finishing
868
+ # Continue successfully
869
+ #
870
+ def take: () -> untyped
577
871
 
578
872
  # <!--
579
873
  # rdoc-file=ractor.rb
580
- # - ractor.value -> obj
874
+ # - to_s()
581
875
  # -->
582
- # Waits for `ractor` to complete and returns its value or raises the exception
583
- # which terminated the Ractor. The termination value will be moved to the
584
- # calling Ractor. Therefore, at most 1 Ractor can receive another ractor's
585
- # termination value.
586
- #
587
- # r = Ractor.new{ [1, 2] }
588
- # r.value #=> [1, 2] (unshareable object)
589
- #
590
- # Ractor.new(r){|r| r.value} #=> Ractor::Error
591
876
  #
592
- def value: () -> untyped
877
+ alias to_s inspect
593
878
 
594
879
  private
595
880
 
@@ -619,35 +904,49 @@ class Ractor
619
904
  # <!-- rdoc-file=ractor.c -->
620
905
  # Raised when an attempt is made to send a message to a closed port, or to
621
906
  # retrieve a message from a closed and empty port. Ports may be closed
622
- # explicitly with Ractor::Port#close and are closed implicitly when a Ractor
623
- # terminates.
907
+ # explicitly with Ractor#close_outgoing/close_incoming and are closed implicitly
908
+ # when a Ractor terminates.
909
+ #
910
+ # r = Ractor.new { sleep(500) }
911
+ # r.close_outgoing
912
+ # r.take # Ractor::ClosedError
913
+ #
914
+ # ClosedError is a descendant of StopIteration, so the closing of the ractor
915
+ # will break the loops without propagating the error:
916
+ #
917
+ # r = Ractor.new do
918
+ # loop do
919
+ # msg = receive # raises ClosedError and loop traps it
920
+ # puts "Received: #{msg}"
921
+ # end
922
+ # puts "loop exited"
923
+ # end
624
924
  #
625
- # port = Ractor::Port.new
626
- # port.close
627
- # port << "test" # Ractor::ClosedError
628
- # port.receive # Ractor::ClosedError
925
+ # 3.times{|i| r << i}
926
+ # r.close_incoming
927
+ # r.take
928
+ # puts "Continue successfully"
629
929
  #
630
- # ClosedError is a descendant of StopIteration, so the closing of a port will
631
- # break out of loops without propagating the error.
930
+ # This will print:
931
+ #
932
+ # Received: 0
933
+ # Received: 1
934
+ # Received: 2
935
+ # loop exited
936
+ # Continue successfully
632
937
  #
633
938
  class ClosedError < StopIteration
634
939
  end
635
940
 
636
- # <!-- rdoc-file=ractor.c -->
637
- # The parent class of Ractor-related error classes.
638
- #
639
941
  class Error < RuntimeError
640
942
  end
641
943
 
642
- # <!-- rdoc-file=ractor.c -->
643
- # Raised on attempt to make a Ractor-unshareable object Ractor-shareable.
644
- #
645
944
  class IsolationError < Ractor::Error
646
945
  end
647
946
 
648
947
  # <!-- rdoc-file=ractor.c -->
649
948
  # Raised on an attempt to access an object which was moved in Ractor#send or
650
- # Ractor::Port#send.
949
+ # Ractor.yield.
651
950
  #
652
951
  # r = Ractor.new { sleep }
653
952
  #
@@ -661,7 +960,7 @@ class Ractor
661
960
 
662
961
  # <!-- rdoc-file=ractor.c -->
663
962
  # A special object which replaces any value that was moved to another ractor in
664
- # Ractor#send or Ractor::Port#send. Any attempt to access the object results in
963
+ # Ractor#send or Ractor.yield. Any attempt to access the object results in
665
964
  # Ractor::MovedError.
666
965
  #
667
966
  # r = Ractor.new { receive }
@@ -738,163 +1037,15 @@ class Ractor
738
1037
  def method_missing: (*untyped) -> untyped
739
1038
  end
740
1039
 
741
- # <!-- rdoc-file=ractor.rb -->
742
- # Port objects transmit messages between Ractors.
743
- #
744
- class Port[T = untyped]
745
- # <!--
746
- # rdoc-file=ractor.rb
747
- # - <<(obj, move: false)
748
- # -->
749
- #
750
- alias << send
751
-
752
- # <!--
753
- # rdoc-file=ractor.rb
754
- # - port.close
755
- # -->
756
- # Closes the port. Sending to a closed port is prohibited. Receiving is also
757
- # prohibited if there are no messages in its message queue.
758
- #
759
- # Only the Ractor which created the port is allowed to close it.
760
- #
761
- # port = Ractor::Port.new
762
- # Ractor.new port do |port|
763
- # port.close #=> closing port by other ractors is not allowed (Ractor::Error)
764
- # end.join
765
- #
766
- def close: () -> void
767
-
768
- # <!--
769
- # rdoc-file=ractor.rb
770
- # - port.closed? -> true/false
771
- # -->
772
- # Returns whether or not the port is closed.
773
- #
774
- def closed?: () -> bool
775
-
776
- # <!--
777
- # rdoc-file=ractor.rb
778
- # - port.inspect -> string
779
- # -->
780
- #
781
- def inspect: () -> String
782
-
783
- # <!--
784
- # rdoc-file=ractor.rb
785
- # - port.receive -> msg
786
- # -->
787
- # Receives a message from the port (which was sent there by Port#send). Only the
788
- # ractor that created the port can receive messages this way.
789
- #
790
- # port = Ractor::Port.new
791
- # r = Ractor.new port do |port|
792
- # port.send('message1')
793
- # end
794
- #
795
- # v1 = port.receive
796
- # puts "Received: #{v1}"
797
- # r.join
798
- # # This will print: "Received: message1"
799
- #
800
- # The method blocks the current Thread if the message queue is empty.
801
- #
802
- # port = Ractor::Port.new
803
- # r = Ractor.new port do |port|
804
- # wait
805
- # puts "Still not received"
806
- # port.send('message1')
807
- # wait
808
- # puts "Still received only one"
809
- # port.send('message2')
810
- # end
811
- # puts "Before first receive"
812
- # v1 = port.receive
813
- # puts "Received: #{v1}"
814
- # v2 = port.receive
815
- # puts "Received: #{v2}"
816
- # r.join
817
- #
818
- # Output:
819
- #
820
- # Before first receive
821
- # Still not received
822
- # Received: message1
823
- # Still received only one
824
- # Received: message2
825
- #
826
- # If the port is closed and there are no more messages in the message queue, the
827
- # method raises Ractor::ClosedError.
828
- #
829
- # port = Ractor::Port.new
830
- # port.close
831
- # port.receive #=> raise Ractor::ClosedError
832
- #
833
- def receive: () -> T
834
-
835
- # <!--
836
- # rdoc-file=ractor.rb
837
- # - port.send(msg, move: false) -> self
838
- # -->
839
- # Sends a message to the port to be accepted by port.receive.
840
- #
841
- # port = Ractor::Port.new
842
- # r = Ractor.new(port) do |port|
843
- # port.send 'message'
844
- # end
845
- # value = port.receive
846
- # puts "Received #{value}"
847
- # # Prints: "Received: message"
848
- #
849
- # The method is non-blocking (it will return immediately even if the ractor that
850
- # created the port is not ready to receive anything):
851
- #
852
- # port = Ractor::Port.new
853
- # r = Ractor.new(port) do |port|
854
- # port.send 'test'
855
- # puts "Sent successfully"
856
- # # Prints: "Sent successfully" immediately
857
- # end
858
- #
859
- # An attempt to send to a closed port will raise Ractor::ClosedError.
860
- #
861
- # r = Ractor.new {Ractor::Port.new}
862
- # r.join
863
- # p r
864
- # # "#<Ractor:#6 (irb):23 terminated>"
865
- # port = r.value
866
- # port.send('test') # raise Ractor::ClosedError
867
- #
868
- # If the `obj` is unshareable, by default it will be copied into the receiving
869
- # ractor by deep cloning.
870
- #
871
- # If the object is shareable, a reference to the object will be sent to the
872
- # receiving ractor.
873
- #
874
- def send: (T obj, ?move: boolish) -> self
875
-
876
- private
877
-
878
- # <!--
879
- # rdoc-file=ractor_sync.c
880
- # - Ractor::Port.new -> new_port
881
- # -->
882
- # Returns a new Ractor::Port object.
883
- #
884
- def initialize: () -> void
885
-
886
- def initialize_copy: (untyped) -> untyped
887
- end
888
-
889
1040
  # <!-- rdoc-file=ractor.c -->
890
- # Raised on Ractor#join or Ractor#value if there was an uncaught exception in
891
- # the Ractor. Its `cause` will contain the original exception, and `ractor` is
892
- # the original ractor it was raised in.
1041
+ # Raised on attempt to Ractor#take if there was an uncaught exception in the
1042
+ # Ractor. Its `cause` will contain the original exception, and `ractor` is the
1043
+ # original ractor it was raised in.
893
1044
  #
894
1045
  # r = Ractor.new { raise "Something weird happened" }
895
1046
  #
896
1047
  # begin
897
- # r.value
1048
+ # r.take
898
1049
  # rescue => e
899
1050
  # p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
900
1051
  # p e.ractor == r # => true
@@ -903,14 +1054,11 @@ class Ractor
903
1054
  #
904
1055
  class RemoteError < Ractor::Error
905
1056
  # <!-- rdoc-file=ractor.rb -->
906
- # The Ractor in which the uncaught exception was raised.
1057
+ # The Ractor an uncaught exception is raised in.
907
1058
  #
908
1059
  def ractor: () -> Ractor
909
1060
  end
910
1061
 
911
- # <!-- rdoc-file=ractor.c -->
912
- # Raised when Ractor-unsafe C-methods is invoked by a non-main Ractor.
913
- #
914
1062
  class UnsafeError < Ractor::Error
915
1063
  end
916
1064