rbs 4.0.0.dev.4 → 4.0.0.dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +14 -14
  3. data/.github/workflows/bundle-update.yml +60 -0
  4. data/.github/workflows/c-check.yml +11 -8
  5. data/.github/workflows/comments.yml +3 -3
  6. data/.github/workflows/dependabot.yml +1 -1
  7. data/.github/workflows/ruby.yml +17 -34
  8. data/.github/workflows/typecheck.yml +2 -2
  9. data/.github/workflows/valgrind.yml +42 -0
  10. data/.github/workflows/windows.yml +2 -2
  11. data/.rubocop.yml +1 -1
  12. data/README.md +1 -1
  13. data/Rakefile +32 -5
  14. data/config.yml +46 -0
  15. data/core/array.rbs +96 -46
  16. data/core/binding.rbs +0 -2
  17. data/core/builtin.rbs +2 -2
  18. data/core/comparable.rbs +13 -6
  19. data/core/complex.rbs +55 -41
  20. data/core/dir.rbs +4 -4
  21. data/core/encoding.rbs +7 -10
  22. data/core/enumerable.rbs +90 -3
  23. data/core/enumerator/arithmetic_sequence.rbs +70 -0
  24. data/core/enumerator.rbs +63 -1
  25. data/core/errno.rbs +8 -0
  26. data/core/errors.rbs +28 -1
  27. data/core/exception.rbs +2 -2
  28. data/core/fiber.rbs +40 -20
  29. data/core/file.rbs +108 -78
  30. data/core/file_test.rbs +1 -1
  31. data/core/float.rbs +225 -69
  32. data/core/gc.rbs +417 -281
  33. data/core/hash.rbs +1023 -727
  34. data/core/integer.rbs +104 -110
  35. data/core/io/buffer.rbs +21 -10
  36. data/core/io/wait.rbs +11 -33
  37. data/core/io.rbs +82 -19
  38. data/core/kernel.rbs +70 -59
  39. data/core/marshal.rbs +1 -1
  40. data/core/match_data.rbs +1 -1
  41. data/core/math.rbs +42 -3
  42. data/core/method.rbs +63 -27
  43. data/core/module.rbs +103 -26
  44. data/core/nil_class.rbs +3 -3
  45. data/core/numeric.rbs +43 -35
  46. data/core/object.rbs +3 -3
  47. data/core/object_space.rbs +21 -15
  48. data/core/pathname.rbs +1272 -0
  49. data/core/proc.rbs +30 -25
  50. data/core/process.rbs +4 -2
  51. data/core/ractor.rbs +361 -509
  52. data/core/random.rbs +17 -0
  53. data/core/range.rbs +113 -16
  54. data/core/rational.rbs +56 -85
  55. data/core/rbs/unnamed/argf.rbs +2 -2
  56. data/core/rbs/unnamed/env_class.rbs +1 -1
  57. data/core/rbs/unnamed/random.rbs +4 -113
  58. data/core/regexp.rbs +25 -20
  59. data/core/ruby.rbs +53 -0
  60. data/core/ruby_vm.rbs +6 -4
  61. data/core/rubygems/errors.rbs +3 -70
  62. data/core/rubygems/rubygems.rbs +11 -79
  63. data/core/rubygems/version.rbs +2 -3
  64. data/core/set.rbs +488 -359
  65. data/core/signal.rbs +24 -14
  66. data/core/string.rbs +3171 -1241
  67. data/core/struct.rbs +1 -1
  68. data/core/symbol.rbs +17 -11
  69. data/core/thread.rbs +95 -33
  70. data/core/time.rbs +35 -9
  71. data/core/trace_point.rbs +7 -4
  72. data/core/unbound_method.rbs +14 -6
  73. data/docs/aliases.md +79 -0
  74. data/docs/collection.md +2 -2
  75. data/docs/encoding.md +56 -0
  76. data/docs/gem.md +0 -1
  77. data/docs/inline.md +470 -0
  78. data/docs/sigs.md +3 -3
  79. data/docs/syntax.md +33 -4
  80. data/docs/type_fingerprint.md +21 -0
  81. data/exe/rbs +1 -1
  82. data/ext/rbs_extension/ast_translation.c +77 -3
  83. data/ext/rbs_extension/ast_translation.h +3 -0
  84. data/ext/rbs_extension/class_constants.c +8 -2
  85. data/ext/rbs_extension/class_constants.h +4 -0
  86. data/ext/rbs_extension/extconf.rb +5 -1
  87. data/ext/rbs_extension/legacy_location.c +5 -5
  88. data/ext/rbs_extension/main.c +37 -20
  89. data/include/rbs/ast.h +85 -38
  90. data/include/rbs/defines.h +27 -0
  91. data/include/rbs/lexer.h +30 -11
  92. data/include/rbs/parser.h +6 -6
  93. data/include/rbs/string.h +0 -2
  94. data/include/rbs/util/rbs_allocator.h +34 -13
  95. data/include/rbs/util/rbs_assert.h +12 -1
  96. data/include/rbs/util/rbs_encoding.h +2 -0
  97. data/include/rbs/util/rbs_unescape.h +2 -1
  98. data/lib/rbs/ast/annotation.rb +1 -1
  99. data/lib/rbs/ast/comment.rb +1 -1
  100. data/lib/rbs/ast/declarations.rb +10 -10
  101. data/lib/rbs/ast/members.rb +14 -14
  102. data/lib/rbs/ast/ruby/annotations.rb +137 -0
  103. data/lib/rbs/ast/ruby/comment_block.rb +24 -0
  104. data/lib/rbs/ast/ruby/declarations.rb +198 -3
  105. data/lib/rbs/ast/ruby/helpers/constant_helper.rb +4 -0
  106. data/lib/rbs/ast/ruby/members.rb +159 -1
  107. data/lib/rbs/ast/type_param.rb +24 -4
  108. data/lib/rbs/buffer.rb +20 -15
  109. data/lib/rbs/cli/diff.rb +16 -15
  110. data/lib/rbs/cli/validate.rb +38 -51
  111. data/lib/rbs/cli.rb +52 -19
  112. data/lib/rbs/collection/config/lockfile_generator.rb +8 -0
  113. data/lib/rbs/collection/sources/git.rb +1 -0
  114. data/lib/rbs/definition.rb +1 -1
  115. data/lib/rbs/definition_builder/ancestor_builder.rb +62 -9
  116. data/lib/rbs/definition_builder/method_builder.rb +20 -0
  117. data/lib/rbs/definition_builder.rb +91 -2
  118. data/lib/rbs/diff.rb +7 -1
  119. data/lib/rbs/environment.rb +227 -74
  120. data/lib/rbs/environment_loader.rb +0 -6
  121. data/lib/rbs/errors.rb +27 -7
  122. data/lib/rbs/inline_parser.rb +341 -5
  123. data/lib/rbs/location_aux.rb +1 -1
  124. data/lib/rbs/locator.rb +5 -1
  125. data/lib/rbs/method_type.rb +5 -3
  126. data/lib/rbs/parser_aux.rb +2 -2
  127. data/lib/rbs/prototype/rb.rb +2 -2
  128. data/lib/rbs/prototype/rbi.rb +2 -0
  129. data/lib/rbs/prototype/runtime.rb +8 -0
  130. data/lib/rbs/resolver/constant_resolver.rb +2 -2
  131. data/lib/rbs/resolver/type_name_resolver.rb +116 -38
  132. data/lib/rbs/subtractor.rb +3 -1
  133. data/lib/rbs/test/type_check.rb +16 -2
  134. data/lib/rbs/type_name.rb +1 -1
  135. data/lib/rbs/types.rb +27 -27
  136. data/lib/rbs/validator.rb +2 -2
  137. data/lib/rbs/version.rb +1 -1
  138. data/lib/rbs.rb +1 -1
  139. data/lib/rdoc/discover.rb +1 -1
  140. data/lib/rdoc_plugin/parser.rb +1 -1
  141. data/rbs.gemspec +3 -2
  142. data/schema/typeParam.json +17 -1
  143. data/sig/ast/ruby/annotations.rbs +124 -0
  144. data/sig/ast/ruby/comment_block.rbs +8 -0
  145. data/sig/ast/ruby/declarations.rbs +102 -4
  146. data/sig/ast/ruby/members.rbs +87 -1
  147. data/sig/cli/diff.rbs +5 -11
  148. data/sig/cli/validate.rbs +13 -4
  149. data/sig/cli.rbs +18 -18
  150. data/sig/definition.rbs +6 -1
  151. data/sig/environment.rbs +70 -12
  152. data/sig/errors.rbs +13 -6
  153. data/sig/inline_parser.rbs +39 -2
  154. data/sig/locator.rbs +0 -2
  155. data/sig/manifest.yaml +0 -1
  156. data/sig/method_builder.rbs +3 -1
  157. data/sig/method_types.rbs +1 -1
  158. data/sig/parser.rbs +16 -2
  159. data/sig/resolver/type_name_resolver.rbs +35 -7
  160. data/sig/source.rbs +3 -3
  161. data/sig/type_param.rbs +13 -8
  162. data/sig/types.rbs +4 -4
  163. data/src/ast.c +80 -1
  164. data/src/lexer.c +1392 -1313
  165. data/src/lexer.re +3 -0
  166. data/src/lexstate.c +58 -37
  167. data/src/location.c +4 -4
  168. data/src/parser.c +412 -145
  169. data/src/string.c +0 -48
  170. data/src/util/rbs_allocator.c +89 -71
  171. data/src/util/rbs_assert.c +1 -1
  172. data/src/util/rbs_buffer.c +2 -2
  173. data/src/util/rbs_constant_pool.c +10 -10
  174. data/src/util/rbs_encoding.c +4 -8
  175. data/src/util/rbs_unescape.c +56 -20
  176. data/stdlib/bigdecimal/0/big_decimal.rbs +100 -82
  177. data/stdlib/bigdecimal-math/0/big_math.rbs +169 -8
  178. data/stdlib/cgi/0/core.rbs +9 -393
  179. data/stdlib/cgi/0/manifest.yaml +1 -0
  180. data/stdlib/cgi-escape/0/escape.rbs +171 -0
  181. data/stdlib/coverage/0/coverage.rbs +3 -1
  182. data/stdlib/date/0/date.rbs +67 -59
  183. data/stdlib/date/0/date_time.rbs +1 -1
  184. data/stdlib/delegate/0/delegator.rbs +10 -7
  185. data/stdlib/digest/0/digest.rbs +110 -0
  186. data/stdlib/erb/0/erb.rbs +737 -347
  187. data/stdlib/fileutils/0/fileutils.rbs +20 -14
  188. data/stdlib/forwardable/0/forwardable.rbs +3 -0
  189. data/stdlib/json/0/json.rbs +82 -28
  190. data/stdlib/net-http/0/net-http.rbs +3 -0
  191. data/stdlib/objspace/0/objspace.rbs +9 -27
  192. data/stdlib/open-uri/0/open-uri.rbs +40 -0
  193. data/stdlib/open3/0/open3.rbs +459 -1
  194. data/stdlib/openssl/0/openssl.rbs +331 -228
  195. data/stdlib/optparse/0/optparse.rbs +8 -3
  196. data/stdlib/pathname/0/pathname.rbs +9 -1379
  197. data/stdlib/psych/0/psych.rbs +4 -4
  198. data/stdlib/random-formatter/0/random-formatter.rbs +277 -0
  199. data/stdlib/rdoc/0/code_object.rbs +2 -1
  200. data/stdlib/rdoc/0/parser.rbs +1 -1
  201. data/stdlib/rdoc/0/rdoc.rbs +1 -1
  202. data/stdlib/rdoc/0/store.rbs +1 -1
  203. data/stdlib/resolv/0/resolv.rbs +25 -68
  204. data/stdlib/ripper/0/ripper.rbs +2 -2
  205. data/stdlib/securerandom/0/manifest.yaml +2 -0
  206. data/stdlib/securerandom/0/securerandom.rbs +6 -19
  207. data/stdlib/singleton/0/singleton.rbs +3 -0
  208. data/stdlib/socket/0/socket.rbs +13 -1
  209. data/stdlib/socket/0/tcp_socket.rbs +10 -2
  210. data/stdlib/stringio/0/stringio.rbs +1176 -85
  211. data/stdlib/strscan/0/string_scanner.rbs +31 -31
  212. data/stdlib/tempfile/0/tempfile.rbs +3 -3
  213. data/stdlib/time/0/time.rbs +1 -1
  214. data/stdlib/timeout/0/timeout.rbs +63 -7
  215. data/stdlib/tsort/0/cyclic.rbs +3 -0
  216. data/stdlib/uri/0/common.rbs +16 -2
  217. data/stdlib/uri/0/file.rbs +1 -1
  218. data/stdlib/uri/0/generic.rbs +24 -16
  219. data/stdlib/uri/0/rfc2396_parser.rbs +6 -7
  220. data/stdlib/zlib/0/gzip_reader.rbs +2 -2
  221. data/stdlib/zlib/0/gzip_writer.rbs +1 -1
  222. data/stdlib/zlib/0/zstream.rbs +1 -0
  223. metadata +30 -4
data/core/ractor.rbs CHANGED
@@ -1,22 +1,19 @@
1
1
  # <!-- rdoc-file=ractor.rb -->
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.
2
+ # Ractor.new creates a new Ractor, which can run in parallel with other ractors.
6
3
  #
7
4
  # # The simplest ractor
8
5
  # r = Ractor.new {puts "I am in Ractor!"}
9
- # r.take # wait for it to finish
6
+ # r.join # wait for it to finish
10
7
  # # Here, "I am in Ractor!" is printed
11
8
  #
12
9
  # Ractors do not share all objects with each other. There are two main benefits
13
10
  # to this: across ractors, thread-safety concerns such as data-races and
14
11
  # race-conditions are not possible. The other benefit is parallelism.
15
12
  #
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.
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.
20
17
  #
21
18
  # a = 1
22
19
  # r = Ractor.new {puts "I am in Ractor! a=#{a}"}
@@ -27,80 +24,37 @@
27
24
  # a = 1
28
25
  # r = Ractor.new(a) { |a1| puts "I am in Ractor! a=#{a1}"}
29
26
  #
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.
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.
33
30
  #
34
31
  # Instead of accessing shared state, objects should be passed to and from
35
32
  # ractors by sending and receiving them as messages.
36
33
  #
37
34
  # a = 1
38
35
  # r = Ractor.new do
39
- # a_in_ractor = receive # receive blocks until somebody passes a message
36
+ # a_in_ractor = receive # receive blocks the Thread until our default port gets sent a message
40
37
  # puts "I am in Ractor! a=#{a_in_ractor}"
41
38
  # end
42
39
  # r.send(a) # pass it
43
- # r.take
40
+ # r.join
44
41
  # # Here, "I am in Ractor! a=1" is printed
45
42
  #
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
- #
53
43
  # In addition to that, any arguments passed to Ractor.new are passed to the
54
44
  # block and available there as if received by Ractor.receive, and the last block
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.
45
+ # value can be received with Ractor#value.
92
46
  #
93
47
  # ## Shareable and unshareable objects
94
48
  #
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.
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.
99
53
  #
100
- # Shareable objects are those which can be used by several threads without
101
- # compromising thread-safety, for example numbers, `true` and `false`.
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`.
102
56
  # Ractor.shareable? allows you to check this, and Ractor.make_shareable tries to
103
- # make the object shareable if it's not already, and gives an error if it can't
57
+ # make the object shareable if it's not already and gives an error if it can't
104
58
  # do it.
105
59
  #
106
60
  # Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are shareable
@@ -116,25 +70,25 @@
116
70
  # ary[0].frozen? #=> true
117
71
  # ary[1].frozen? #=> true
118
72
  #
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.
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.
124
78
  #
125
- # data = ['foo', 'bar'.freeze]
79
+ # data = ['foo'.dup, 'bar'.freeze]
126
80
  # r = Ractor.new do
127
81
  # data2 = Ractor.receive
128
82
  # puts "In ractor: #{data2.object_id}, #{data2[0].object_id}, #{data2[1].object_id}"
129
83
  # end
130
84
  # r.send(data)
131
- # r.take
85
+ # r.join
132
86
  # puts "Outside : #{data.object_id}, #{data[0].object_id}, #{data[1].object_id}"
133
87
  #
134
88
  # This will output something like:
135
89
  #
136
- # In ractor: 340, 360, 320
137
- # Outside : 380, 400, 320
90
+ # In ractor: 8, 16, 24
91
+ # Outside : 32, 40, 24
138
92
  #
139
93
  # Note that the object ids of the array and the non-frozen string inside the
140
94
  # array have changed in the ractor because they are different objects. The
@@ -151,7 +105,7 @@
151
105
  # puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}"
152
106
  # end
153
107
  # r.send(data, move: true)
154
- # r.take
108
+ # r.join
155
109
  # puts "Outside: moved? #{Ractor::MovedObject === data}"
156
110
  # puts "Outside: #{data.inspect}"
157
111
  #
@@ -161,14 +115,14 @@
161
115
  # Outside: moved? true
162
116
  # test.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError)
163
117
  #
164
- # Notice that even `inspect` (and more basic methods like `__id__`) is
118
+ # Notice that even `inspect` and more basic methods like `__id__` are
165
119
  # inaccessible on a moved object.
166
120
  #
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.
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.
172
126
  #
173
127
  # It is prohibited to access (get) instance variables of shareable objects in
174
128
  # other ractors if the values of the variables aren't shareable. This can occur
@@ -189,7 +143,7 @@
189
143
  # puts "I can't see #{cls.tricky}"
190
144
  # cls.tricky = true # doesn't get here, but this would also raise an error
191
145
  # end
192
- # r.take
146
+ # r.join
193
147
  # # I see C
194
148
  # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
195
149
  #
@@ -203,7 +157,7 @@
203
157
  # puts "GOOD=#{GOOD}"
204
158
  # puts "BAD=#{BAD}"
205
159
  # end
206
- # r.take
160
+ # r.join
207
161
  # # GOOD=good
208
162
  # # can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError)
209
163
  #
@@ -213,7 +167,7 @@
213
167
  # puts "I see #{C}"
214
168
  # puts "I can't see #{C.tricky}"
215
169
  # end
216
- # r.take
170
+ # r.join
217
171
  # # I see C
218
172
  # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
219
173
  #
@@ -229,20 +183,21 @@
229
183
  # a = 1
230
184
  # Thread.new {puts "Thread in ractor: a=#{a}"}.join
231
185
  # end
232
- # r.take
186
+ # r.join
233
187
  # # Here "Thread in ractor: a=1" will be printed
234
188
  #
235
189
  # ## Note on code examples
236
190
  #
237
191
  # In the examples below, sometimes we use the following method to wait for
238
- # ractors that are not currently blocked to finish (or to make progress).
192
+ # ractors to make progress or finish.
239
193
  #
240
194
  # def wait
241
195
  # sleep(0.1)
242
196
  # end
243
197
  #
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.
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.
246
201
  #
247
202
  # ## Reference
248
203
  #
@@ -261,7 +216,7 @@ class Ractor
261
216
  # rdoc-file=ractor.rb
262
217
  # - [](sym)
263
218
  # -->
264
- # get a value from ractor-local storage of current Ractor
219
+ # Gets a value from ractor-local storage for the current Ractor.
265
220
  #
266
221
  def self.[]: (Symbol) -> untyped
267
222
 
@@ -269,7 +224,7 @@ class Ractor
269
224
  # rdoc-file=ractor.rb
270
225
  # - []=(sym, val)
271
226
  # -->
272
- # set a value in ractor-local storage of current Ractor
227
+ # Sets a value in ractor-local storage for the current Ractor.
273
228
  #
274
229
  def self.[]=: (Symbol, untyped) -> untyped
275
230
 
@@ -277,13 +232,13 @@ class Ractor
277
232
  # rdoc-file=ractor.rb
278
233
  # - count()
279
234
  # -->
280
- # Returns the number of Ractors currently running or blocking (waiting).
235
+ # Returns the number of ractors currently running or blocking (waiting).
281
236
  #
282
237
  # Ractor.count #=> 1
283
- # r = Ractor.new(name: 'example') { Ractor.yield(1) }
238
+ # r = Ractor.new(name: 'example') { Ractor.receive }
284
239
  # Ractor.count #=> 2 (main + example ractor)
285
- # r.take # wait for Ractor.yield(1)
286
- # r.take # wait until r will finish
240
+ # r << 42 # r's Ractor.receive will resume
241
+ # r.join # wait for r's termination
287
242
  # Ractor.count #=> 1
288
243
  #
289
244
  def self.count: () -> Integer
@@ -302,7 +257,7 @@ class Ractor
302
257
  # rdoc-file=ractor.rb
303
258
  # - main()
304
259
  # -->
305
- # returns main ractor
260
+ # Returns the main ractor.
306
261
  #
307
262
  def self.main: () -> Ractor
308
263
 
@@ -310,7 +265,7 @@ class Ractor
310
265
  # rdoc-file=ractor.rb
311
266
  # - main?()
312
267
  # -->
313
- # return true if the current ractor is main ractor
268
+ # Returns true if the current ractor is the main ractor.
314
269
  #
315
270
  def self.main?: () -> boolish
316
271
 
@@ -318,7 +273,7 @@ class Ractor
318
273
  # rdoc-file=ractor.rb
319
274
  # - Ractor.make_shareable(obj, copy: false) -> shareable_obj
320
275
  # -->
321
- # Make `obj` shareable between ractors.
276
+ # Makes `obj` shareable between ractors.
322
277
  #
323
278
  # `obj` and all the objects it refers to will be frozen, unless they are already
324
279
  # shareable.
@@ -357,13 +312,13 @@ class Ractor
357
312
  # rdoc-file=ractor.rb
358
313
  # - Ractor.new(*args, name: nil) {|*args| block } -> ractor
359
314
  # -->
360
- # Create a new Ractor with args and a block.
315
+ # Creates a new Ractor with args and a block.
361
316
  #
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.
317
+ # The given block (Proc) is isolated (can't access any outer variables). `self`
318
+ # inside the block will refer to the current Ractor.
364
319
  #
365
320
  # r = Ractor.new { puts "Hi, I am #{self.inspect}" }
366
- # r.take
321
+ # r.join
367
322
  # # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
368
323
  #
369
324
  # Any `args` passed are propagated to the block arguments by the same rules as
@@ -375,14 +330,14 @@ class Ractor
375
330
  # r = Ractor.new(arg) {|received_arg|
376
331
  # puts "Received: #{received_arg} (##{received_arg.object_id})"
377
332
  # }
378
- # r.take
333
+ # r.join
379
334
  # # Prints:
380
335
  # # Passing: [1, 2, 3] (#280)
381
336
  # # Received: [1, 2, 3] (#300)
382
337
  #
383
338
  # Ractor's `name` can be set for debugging purposes:
384
339
  #
385
- # r = Ractor.new(name: 'my ractor') {}; r.take
340
+ # r = Ractor.new(name: 'my ractor') {}; r.join
386
341
  # p r
387
342
  # #=> #<Ractor:#3 my ractor test.rb:1 terminated>
388
343
  #
@@ -390,128 +345,12 @@ class Ractor
390
345
 
391
346
  # <!--
392
347
  # rdoc-file=ractor.rb
393
- # - Ractor.receive -> msg
348
+ # - Ractor.receive -> obj
394
349
  # -->
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)
350
+ # Receives a message from the current ractor's default port.
450
351
  #
451
352
  def self.receive: () -> untyped
452
353
 
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
-
515
354
  # <!--
516
355
  # rdoc-file=ractor.rb
517
356
  # - recv()
@@ -521,57 +360,50 @@ class Ractor
521
360
 
522
361
  # <!--
523
362
  # rdoc-file=ractor.rb
524
- # - Ractor.select(*ractors, [yield_value:, move: false]) -> [ractor or symbol, obj]
363
+ # - Ractor.select(*ractors_or_ports) -> [ractor or port, obj]
525
364
  # -->
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.
537
- #
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'
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
547
381
  # end
548
382
  #
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
552
- #
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:
555
- #
556
- # r1 = Ractor.new(Ractor.current) do |main|
557
- # puts "Received from main: #{main.take}"
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
558
388
  # end
559
389
  #
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:
390
+ # # r0
391
+ # # r1
392
+ # # r1 done
393
+ # # r0 done
566
394
  #
567
- # Trying to select
568
- # Received from main: 123
569
- # Received nil from :yield
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.
570
398
  #
571
- # `move` boolean flag defines whether yielded value will be copied (default) or
572
- # moved.
399
+ # values = []
400
+ # until ractors.empty?
401
+ # r, val = Ractor.select(*ractors)
402
+ # ractors.delete(r)
403
+ # values << val
404
+ # end
573
405
  #
574
- def self.select: (*Ractor ractors, ?move: boolish, ?yield_value: untyped) -> [ Ractor | Symbol, untyped ]
406
+ def self.select: (?) -> Array[untyped]
575
407
 
576
408
  # <!--
577
409
  # rdoc-file=ractor.rb
@@ -579,7 +411,7 @@ class Ractor
579
411
  # -->
580
412
  # Checks if the object is shareable by ractors.
581
413
  #
582
- # Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are frozen
414
+ # Ractor.shareable?(1) #=> true -- numbers are shareable
583
415
  # Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
584
416
  # Ractor.shareable?('foo'.freeze) #=> true
585
417
  #
@@ -588,13 +420,44 @@ class Ractor
588
420
  #
589
421
  def self.shareable?: (untyped obj) -> bool
590
422
 
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
+
591
454
  # <!--
592
455
  # rdoc-file=ractor.rb
593
456
  # - Ractor.store_if_absent(key){ init_block }
594
457
  # -->
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.
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.
598
461
  #
599
462
  # (1..10).map{
600
463
  # Thread.new(it){|i|
@@ -607,47 +470,7 @@ class Ractor
607
470
 
608
471
  # <!--
609
472
  # rdoc-file=ractor.rb
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)
473
+ # - <<(...)
651
474
  # -->
652
475
  #
653
476
  alias << send
@@ -656,225 +479,117 @@ class Ractor
656
479
  # rdoc-file=ractor.rb
657
480
  # - [](sym)
658
481
  # -->
659
- # get a value from ractor-local storage of current Ractor Obsolete and use
482
+ # Gets a value from ractor-local storage for the current Ractor. Obsolete, use
660
483
  # Ractor.[] instead.
661
484
  #
485
+ %a{deprecated: Use Ractor.[] instead}
662
486
  def []: (interned sym) -> untyped
663
487
 
664
488
  # <!--
665
489
  # rdoc-file=ractor.rb
666
490
  # - []=(sym, val)
667
491
  # -->
668
- # set a value in ractor-local storage of current Ractor Obsolete and use
492
+ # Sets a value in ractor-local storage for the current Ractor. Obsolete, use
669
493
  # Ractor.[]= instead.
670
494
  #
495
+ %a{deprecated: Use Ractor.[]= instead}
671
496
  def []=: [T] (interned sym, T val) -> T
672
497
 
673
498
  # <!--
674
499
  # rdoc-file=ractor.rb
675
- # - ractor.close_incoming -> true | false
500
+ # - ractor.default_port -> port object
676
501
  # -->
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.
502
+ # Returns the default port of the Ractor.
680
503
  #
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
504
+ def default_port: () -> Port[untyped]
688
505
 
689
506
  # <!--
690
507
  # rdoc-file=ractor.rb
691
- # - ractor.close_outgoing -> true | false
508
+ # - inspect()
692
509
  # -->
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.
696
- #
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
510
  #
703
- def close_outgoing: () -> bool
511
+ def inspect: () -> String
704
512
 
705
513
  # <!--
706
514
  # rdoc-file=ractor.rb
707
- # - inspect()
515
+ # - ractor.join -> self
708
516
  # -->
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.
709
519
  #
710
- def inspect: () -> String
520
+ # Ractor.new{}.join #=> ractor
521
+ #
522
+ # Ractor.new{ raise "foo" }.join
523
+ # #=> raises the exception "foo (RuntimeError)"
524
+ #
525
+ def join: () -> self
711
526
 
712
527
  # <!--
713
528
  # rdoc-file=ractor.rb
714
529
  # - name()
715
530
  # -->
716
- # The name set in Ractor.new, or `nil`.
531
+ # Returns the name set in Ractor.new, or `nil`.
717
532
  #
718
533
  def name: () -> String?
719
534
 
720
535
  # <!--
721
536
  # rdoc-file=ractor.rb
722
- # - ractor.send(msg, move: false) -> self
537
+ # - ractor.monitor(port) -> self
723
538
  # -->
724
- # Send a message to a Ractor's incoming queue to be accepted by Ractor.receive.
725
- #
726
- # r = Ractor.new do
727
- # value = Ractor.receive
728
- # puts "Received #{value}"
729
- # end
730
- # r.send 'message'
731
- # # Prints: "Received: message"
732
- #
733
- # The method is non-blocking (will return immediately even if the ractor is not
734
- # ready to receive anything):
735
- #
736
- # r = Ractor.new {sleep(5)}
737
- # r.send('test')
738
- # puts "Sent successfully"
739
- # # Prints: "Sent successfully" immediately
740
- #
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
539
+ # Registers the port as a monitoring port for this ractor. When the ractor
540
+ # terminates, the port receives a Symbol object.
772
541
  #
773
- # This prints:
542
+ # * `:exited` is sent if the ractor terminates without an unhandled exception.
543
+ # * `:aborted` is sent if the ractor terminates by an unhandled exception.
774
544
  #
775
- # Received: message
776
- # in `p': undefined method `inspect' for #<Ractor::MovedObject:0x000055c99b9b69b8>
545
+ # r = Ractor.new{ some_task() }
546
+ # r.monitor(port = Ractor::Port.new)
547
+ # port.receive #=> :exited and r is terminated
777
548
  #
778
- # All references to the object and its parts will become invalid to the sender.
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"
779
552
  #
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
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.
802
560
  #
803
561
  def send: (untyped obj, ?move: boolish) -> Ractor
804
562
 
805
563
  # <!--
806
564
  # rdoc-file=ractor.rb
807
- # - ractor.take -> msg
565
+ # - to_s()
808
566
  # -->
809
- # Get a message from the ractor's outgoing port, which was put there by
810
- # Ractor.yield or at ractor's termination.
811
- #
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"}
841
- #
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
567
  #
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
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.
869
575
  #
870
- def take: () -> untyped
576
+ def unmonitor: (Port[untyped]) -> self
871
577
 
872
578
  # <!--
873
579
  # rdoc-file=ractor.rb
874
- # - to_s()
580
+ # - ractor.value -> obj
875
581
  # -->
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.
876
586
  #
877
- alias to_s inspect
587
+ # r = Ractor.new{ [1, 2] }
588
+ # r.value #=> [1, 2] (unshareable object)
589
+ #
590
+ # Ractor.new(r){|r| r.value} #=> Ractor::Error
591
+ #
592
+ def value: () -> untyped
878
593
 
879
594
  private
880
595
 
@@ -904,49 +619,35 @@ class Ractor
904
619
  # <!-- rdoc-file=ractor.c -->
905
620
  # Raised when an attempt is made to send a message to a closed port, or to
906
621
  # retrieve a message from a closed and empty port. Ports may be closed
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
622
+ # explicitly with Ractor::Port#close and are closed implicitly when a Ractor
623
+ # terminates.
924
624
  #
925
- # 3.times{|i| r << i}
926
- # r.close_incoming
927
- # r.take
928
- # puts "Continue successfully"
625
+ # port = Ractor::Port.new
626
+ # port.close
627
+ # port << "test" # Ractor::ClosedError
628
+ # port.receive # Ractor::ClosedError
929
629
  #
930
- # This will print:
931
- #
932
- # Received: 0
933
- # Received: 1
934
- # Received: 2
935
- # loop exited
936
- # Continue successfully
630
+ # ClosedError is a descendant of StopIteration, so the closing of a port will
631
+ # break out of loops without propagating the error.
937
632
  #
938
633
  class ClosedError < StopIteration
939
634
  end
940
635
 
636
+ # <!-- rdoc-file=ractor.c -->
637
+ # The parent class of Ractor-related error classes.
638
+ #
941
639
  class Error < RuntimeError
942
640
  end
943
641
 
642
+ # <!-- rdoc-file=ractor.c -->
643
+ # Raised on attempt to make a Ractor-unshareable object Ractor-shareable.
644
+ #
944
645
  class IsolationError < Ractor::Error
945
646
  end
946
647
 
947
648
  # <!-- rdoc-file=ractor.c -->
948
649
  # Raised on an attempt to access an object which was moved in Ractor#send or
949
- # Ractor.yield.
650
+ # Ractor::Port#send.
950
651
  #
951
652
  # r = Ractor.new { sleep }
952
653
  #
@@ -960,7 +661,7 @@ class Ractor
960
661
 
961
662
  # <!-- rdoc-file=ractor.c -->
962
663
  # A special object which replaces any value that was moved to another ractor in
963
- # Ractor#send or Ractor.yield. Any attempt to access the object results in
664
+ # Ractor#send or Ractor::Port#send. Any attempt to access the object results in
964
665
  # Ractor::MovedError.
965
666
  #
966
667
  # r = Ractor.new { receive }
@@ -1037,15 +738,163 @@ class Ractor
1037
738
  def method_missing: (*untyped) -> untyped
1038
739
  end
1039
740
 
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
+
1040
889
  # <!-- rdoc-file=ractor.c -->
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.
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.
1044
893
  #
1045
894
  # r = Ractor.new { raise "Something weird happened" }
1046
895
  #
1047
896
  # begin
1048
- # r.take
897
+ # r.value
1049
898
  # rescue => e
1050
899
  # p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
1051
900
  # p e.ractor == r # => true
@@ -1054,11 +903,14 @@ class Ractor
1054
903
  #
1055
904
  class RemoteError < Ractor::Error
1056
905
  # <!-- rdoc-file=ractor.rb -->
1057
- # The Ractor an uncaught exception is raised in.
906
+ # The Ractor in which the uncaught exception was raised.
1058
907
  #
1059
908
  def ractor: () -> Ractor
1060
909
  end
1061
910
 
911
+ # <!-- rdoc-file=ractor.c -->
912
+ # Raised when Ractor-unsafe C-methods is invoked by a non-main Ractor.
913
+ #
1062
914
  class UnsafeError < Ractor::Error
1063
915
  end
1064
916