rbs 4.0.0.dev.4 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) 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 +18 -11
  5. data/.github/workflows/comments.yml +5 -3
  6. data/.github/workflows/dependabot.yml +2 -2
  7. data/.github/workflows/ruby.yml +27 -34
  8. data/.github/workflows/rust.yml +95 -0
  9. data/.github/workflows/typecheck.yml +2 -2
  10. data/.github/workflows/windows.yml +2 -2
  11. data/.rubocop.yml +1 -1
  12. data/CHANGELOG.md +323 -0
  13. data/README.md +1 -1
  14. data/Rakefile +43 -33
  15. data/Steepfile +1 -0
  16. data/config.yml +426 -24
  17. data/core/array.rbs +307 -227
  18. data/core/basic_object.rbs +9 -8
  19. data/core/binding.rbs +0 -2
  20. data/core/builtin.rbs +2 -2
  21. data/core/class.rbs +6 -5
  22. data/core/comparable.rbs +55 -34
  23. data/core/complex.rbs +104 -78
  24. data/core/dir.rbs +61 -49
  25. data/core/encoding.rbs +12 -15
  26. data/core/enumerable.rbs +179 -87
  27. data/core/enumerator/arithmetic_sequence.rbs +70 -0
  28. data/core/enumerator.rbs +65 -2
  29. data/core/errno.rbs +11 -2
  30. data/core/errors.rbs +58 -29
  31. data/core/exception.rbs +13 -13
  32. data/core/fiber.rbs +74 -54
  33. data/core/file.rbs +280 -177
  34. data/core/file_test.rbs +3 -3
  35. data/core/float.rbs +257 -92
  36. data/core/gc.rbs +425 -281
  37. data/core/hash.rbs +1045 -739
  38. data/core/integer.rbs +135 -137
  39. data/core/io/buffer.rbs +53 -42
  40. data/core/io/wait.rbs +13 -35
  41. data/core/io.rbs +192 -144
  42. data/core/kernel.rbs +216 -155
  43. data/core/marshal.rbs +4 -4
  44. data/core/match_data.rbs +15 -13
  45. data/core/math.rbs +107 -66
  46. data/core/method.rbs +69 -33
  47. data/core/module.rbs +244 -106
  48. data/core/nil_class.rbs +7 -6
  49. data/core/numeric.rbs +74 -63
  50. data/core/object.rbs +9 -11
  51. data/core/object_space.rbs +30 -23
  52. data/core/pathname.rbs +1322 -0
  53. data/core/proc.rbs +95 -58
  54. data/core/process.rbs +222 -202
  55. data/core/ractor.rbs +371 -515
  56. data/core/random.rbs +21 -3
  57. data/core/range.rbs +159 -57
  58. data/core/rational.rbs +60 -89
  59. data/core/rbs/unnamed/argf.rbs +60 -53
  60. data/core/rbs/unnamed/env_class.rbs +19 -14
  61. data/core/rbs/unnamed/main_class.rbs +123 -0
  62. data/core/rbs/unnamed/random.rbs +11 -118
  63. data/core/regexp.rbs +258 -214
  64. data/core/ruby.rbs +53 -0
  65. data/core/ruby_vm.rbs +38 -34
  66. data/core/rubygems/config_file.rbs +5 -5
  67. data/core/rubygems/errors.rbs +4 -71
  68. data/core/rubygems/requirement.rbs +5 -5
  69. data/core/rubygems/rubygems.rbs +16 -82
  70. data/core/rubygems/version.rbs +2 -3
  71. data/core/set.rbs +490 -360
  72. data/core/signal.rbs +26 -16
  73. data/core/string.rbs +3234 -1285
  74. data/core/struct.rbs +27 -26
  75. data/core/symbol.rbs +41 -34
  76. data/core/thread.rbs +135 -67
  77. data/core/time.rbs +81 -50
  78. data/core/trace_point.rbs +41 -35
  79. data/core/true_class.rbs +2 -2
  80. data/core/unbound_method.rbs +24 -16
  81. data/core/warning.rbs +7 -7
  82. data/docs/aliases.md +79 -0
  83. data/docs/collection.md +3 -3
  84. data/docs/config.md +171 -0
  85. data/docs/encoding.md +56 -0
  86. data/docs/gem.md +0 -1
  87. data/docs/inline.md +576 -0
  88. data/docs/sigs.md +3 -3
  89. data/docs/syntax.md +46 -16
  90. data/docs/type_fingerprint.md +21 -0
  91. data/exe/rbs +1 -1
  92. data/ext/rbs_extension/ast_translation.c +544 -116
  93. data/ext/rbs_extension/ast_translation.h +3 -0
  94. data/ext/rbs_extension/class_constants.c +16 -2
  95. data/ext/rbs_extension/class_constants.h +8 -0
  96. data/ext/rbs_extension/extconf.rb +5 -1
  97. data/ext/rbs_extension/legacy_location.c +33 -56
  98. data/ext/rbs_extension/legacy_location.h +37 -0
  99. data/ext/rbs_extension/main.c +44 -35
  100. data/include/rbs/ast.h +448 -173
  101. data/include/rbs/defines.h +27 -0
  102. data/include/rbs/lexer.h +30 -11
  103. data/include/rbs/location.h +25 -44
  104. data/include/rbs/parser.h +6 -6
  105. data/include/rbs/string.h +0 -2
  106. data/include/rbs/util/rbs_allocator.h +34 -13
  107. data/include/rbs/util/rbs_assert.h +12 -1
  108. data/include/rbs/util/rbs_constant_pool.h +0 -3
  109. data/include/rbs/util/rbs_encoding.h +2 -0
  110. data/include/rbs/util/rbs_unescape.h +2 -1
  111. data/include/rbs.h +8 -0
  112. data/lib/rbs/ast/annotation.rb +1 -1
  113. data/lib/rbs/ast/comment.rb +1 -1
  114. data/lib/rbs/ast/declarations.rb +10 -10
  115. data/lib/rbs/ast/members.rb +14 -14
  116. data/lib/rbs/ast/ruby/annotations.rb +293 -3
  117. data/lib/rbs/ast/ruby/comment_block.rb +24 -0
  118. data/lib/rbs/ast/ruby/declarations.rb +198 -3
  119. data/lib/rbs/ast/ruby/helpers/constant_helper.rb +4 -0
  120. data/lib/rbs/ast/ruby/members.rb +532 -22
  121. data/lib/rbs/ast/type_param.rb +24 -4
  122. data/lib/rbs/buffer.rb +20 -15
  123. data/lib/rbs/cli/diff.rb +16 -15
  124. data/lib/rbs/cli/validate.rb +38 -106
  125. data/lib/rbs/cli.rb +52 -19
  126. data/lib/rbs/collection/config/lockfile_generator.rb +14 -2
  127. data/lib/rbs/collection/sources/git.rb +1 -0
  128. data/lib/rbs/definition.rb +1 -1
  129. data/lib/rbs/definition_builder/ancestor_builder.rb +62 -9
  130. data/lib/rbs/definition_builder/method_builder.rb +20 -0
  131. data/lib/rbs/definition_builder.rb +147 -25
  132. data/lib/rbs/diff.rb +7 -1
  133. data/lib/rbs/environment.rb +227 -74
  134. data/lib/rbs/environment_loader.rb +0 -6
  135. data/lib/rbs/errors.rb +27 -18
  136. data/lib/rbs/inline_parser.rb +342 -6
  137. data/lib/rbs/location_aux.rb +1 -1
  138. data/lib/rbs/locator.rb +5 -1
  139. data/lib/rbs/method_type.rb +5 -3
  140. data/lib/rbs/parser_aux.rb +20 -7
  141. data/lib/rbs/prototype/helpers.rb +57 -0
  142. data/lib/rbs/prototype/rb.rb +3 -28
  143. data/lib/rbs/prototype/rbi.rb +3 -20
  144. data/lib/rbs/prototype/runtime.rb +8 -0
  145. data/lib/rbs/resolver/constant_resolver.rb +2 -2
  146. data/lib/rbs/resolver/type_name_resolver.rb +116 -38
  147. data/lib/rbs/subtractor.rb +3 -1
  148. data/lib/rbs/test/type_check.rb +19 -2
  149. data/lib/rbs/type_name.rb +1 -1
  150. data/lib/rbs/types.rb +88 -78
  151. data/lib/rbs/unit_test/type_assertions.rb +35 -8
  152. data/lib/rbs/validator.rb +2 -2
  153. data/lib/rbs/version.rb +1 -1
  154. data/lib/rbs.rb +1 -2
  155. data/lib/rdoc/discover.rb +1 -1
  156. data/lib/rdoc_plugin/parser.rb +1 -1
  157. data/rbs.gemspec +4 -3
  158. data/rust/.gitignore +1 -0
  159. data/rust/Cargo.lock +378 -0
  160. data/rust/Cargo.toml +7 -0
  161. data/rust/ruby-rbs/Cargo.toml +22 -0
  162. data/rust/ruby-rbs/build.rs +764 -0
  163. data/rust/ruby-rbs/examples/locations.rs +60 -0
  164. data/rust/ruby-rbs/src/lib.rs +1 -0
  165. data/rust/ruby-rbs/src/node/mod.rs +742 -0
  166. data/rust/ruby-rbs/tests/sanity.rs +47 -0
  167. data/rust/ruby-rbs/vendor/rbs/config.yml +1 -0
  168. data/rust/ruby-rbs-sys/Cargo.toml +23 -0
  169. data/rust/ruby-rbs-sys/build.rs +204 -0
  170. data/rust/ruby-rbs-sys/src/lib.rs +50 -0
  171. data/rust/ruby-rbs-sys/vendor/rbs/include +1 -0
  172. data/rust/ruby-rbs-sys/vendor/rbs/src +1 -0
  173. data/rust/ruby-rbs-sys/wrapper.h +1 -0
  174. data/schema/typeParam.json +17 -1
  175. data/sig/ast/ruby/annotations.rbs +315 -4
  176. data/sig/ast/ruby/comment_block.rbs +8 -0
  177. data/sig/ast/ruby/declarations.rbs +102 -4
  178. data/sig/ast/ruby/members.rbs +108 -2
  179. data/sig/cli/diff.rbs +5 -11
  180. data/sig/cli/validate.rbs +12 -8
  181. data/sig/cli.rbs +18 -18
  182. data/sig/definition.rbs +6 -1
  183. data/sig/definition_builder.rbs +2 -0
  184. data/sig/environment.rbs +70 -12
  185. data/sig/errors.rbs +13 -14
  186. data/sig/inline_parser.rbs +39 -2
  187. data/sig/locator.rbs +0 -2
  188. data/sig/manifest.yaml +0 -1
  189. data/sig/method_builder.rbs +3 -1
  190. data/sig/parser.rbs +31 -13
  191. data/sig/prototype/helpers.rbs +2 -0
  192. data/sig/resolver/type_name_resolver.rbs +35 -7
  193. data/sig/source.rbs +3 -3
  194. data/sig/type_param.rbs +13 -8
  195. data/sig/types.rbs +6 -7
  196. data/sig/unit_test/spy.rbs +0 -8
  197. data/sig/unit_test/type_assertions.rbs +11 -0
  198. data/src/ast.c +410 -153
  199. data/src/lexer.c +1392 -1313
  200. data/src/lexer.re +3 -0
  201. data/src/lexstate.c +58 -37
  202. data/src/location.c +8 -48
  203. data/src/parser.c +977 -516
  204. data/src/string.c +0 -48
  205. data/src/util/rbs_allocator.c +89 -71
  206. data/src/util/rbs_assert.c +1 -1
  207. data/src/util/rbs_buffer.c +2 -2
  208. data/src/util/rbs_constant_pool.c +10 -14
  209. data/src/util/rbs_encoding.c +4 -8
  210. data/src/util/rbs_unescape.c +56 -20
  211. data/stdlib/bigdecimal/0/big_decimal.rbs +116 -98
  212. data/stdlib/bigdecimal-math/0/big_math.rbs +169 -8
  213. data/stdlib/cgi/0/core.rbs +9 -393
  214. data/stdlib/cgi/0/manifest.yaml +1 -0
  215. data/stdlib/cgi-escape/0/escape.rbs +171 -0
  216. data/stdlib/coverage/0/coverage.rbs +7 -4
  217. data/stdlib/date/0/date.rbs +92 -79
  218. data/stdlib/date/0/date_time.rbs +25 -24
  219. data/stdlib/delegate/0/delegator.rbs +10 -7
  220. data/stdlib/did_you_mean/0/did_you_mean.rbs +17 -16
  221. data/stdlib/digest/0/digest.rbs +110 -0
  222. data/stdlib/erb/0/erb.rbs +748 -347
  223. data/stdlib/etc/0/etc.rbs +55 -50
  224. data/stdlib/fileutils/0/fileutils.rbs +158 -139
  225. data/stdlib/forwardable/0/forwardable.rbs +13 -10
  226. data/stdlib/io-console/0/io-console.rbs +2 -2
  227. data/stdlib/json/0/json.rbs +217 -136
  228. data/stdlib/monitor/0/monitor.rbs +3 -3
  229. data/stdlib/net-http/0/net-http.rbs +162 -134
  230. data/stdlib/objspace/0/objspace.rbs +17 -34
  231. data/stdlib/open-uri/0/open-uri.rbs +48 -8
  232. data/stdlib/open3/0/open3.rbs +469 -10
  233. data/stdlib/openssl/0/openssl.rbs +475 -357
  234. data/stdlib/optparse/0/optparse.rbs +26 -17
  235. data/stdlib/pathname/0/pathname.rbs +11 -1381
  236. data/stdlib/pp/0/pp.rbs +9 -8
  237. data/stdlib/prettyprint/0/prettyprint.rbs +7 -7
  238. data/stdlib/pstore/0/pstore.rbs +35 -30
  239. data/stdlib/psych/0/psych.rbs +65 -12
  240. data/stdlib/psych/0/store.rbs +2 -4
  241. data/stdlib/pty/0/pty.rbs +9 -6
  242. data/stdlib/random-formatter/0/random-formatter.rbs +277 -0
  243. data/stdlib/rdoc/0/code_object.rbs +2 -1
  244. data/stdlib/rdoc/0/parser.rbs +1 -1
  245. data/stdlib/rdoc/0/rdoc.rbs +1 -1
  246. data/stdlib/rdoc/0/store.rbs +1 -1
  247. data/stdlib/resolv/0/resolv.rbs +25 -68
  248. data/stdlib/ripper/0/ripper.rbs +22 -19
  249. data/stdlib/securerandom/0/manifest.yaml +2 -0
  250. data/stdlib/securerandom/0/securerandom.rbs +7 -20
  251. data/stdlib/shellwords/0/shellwords.rbs +2 -2
  252. data/stdlib/singleton/0/singleton.rbs +3 -0
  253. data/stdlib/socket/0/addrinfo.rbs +7 -7
  254. data/stdlib/socket/0/basic_socket.rbs +3 -3
  255. data/stdlib/socket/0/ip_socket.rbs +10 -8
  256. data/stdlib/socket/0/socket.rbs +23 -10
  257. data/stdlib/socket/0/tcp_server.rbs +1 -1
  258. data/stdlib/socket/0/tcp_socket.rbs +11 -3
  259. data/stdlib/socket/0/udp_socket.rbs +1 -1
  260. data/stdlib/socket/0/unix_server.rbs +1 -1
  261. data/stdlib/stringio/0/stringio.rbs +1177 -85
  262. data/stdlib/strscan/0/string_scanner.rbs +27 -25
  263. data/stdlib/tempfile/0/tempfile.rbs +25 -21
  264. data/stdlib/time/0/time.rbs +8 -6
  265. data/stdlib/timeout/0/timeout.rbs +63 -7
  266. data/stdlib/tsort/0/cyclic.rbs +3 -0
  267. data/stdlib/tsort/0/tsort.rbs +7 -6
  268. data/stdlib/uri/0/common.rbs +42 -20
  269. data/stdlib/uri/0/file.rbs +3 -3
  270. data/stdlib/uri/0/generic.rbs +26 -18
  271. data/stdlib/uri/0/http.rbs +2 -2
  272. data/stdlib/uri/0/ldap.rbs +2 -2
  273. data/stdlib/uri/0/mailto.rbs +3 -3
  274. data/stdlib/uri/0/rfc2396_parser.rbs +12 -12
  275. data/stdlib/zlib/0/deflate.rbs +4 -3
  276. data/stdlib/zlib/0/gzip_reader.rbs +6 -6
  277. data/stdlib/zlib/0/gzip_writer.rbs +14 -12
  278. data/stdlib/zlib/0/inflate.rbs +1 -1
  279. data/stdlib/zlib/0/need_dict.rbs +1 -1
  280. data/stdlib/zlib/0/zstream.rbs +1 -0
  281. metadata +50 -6
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
@@ -142,8 +96,9 @@
142
96
  # object.
143
97
  #
144
98
  # Deep cloning of objects may be slow, and sometimes impossible. Alternatively,
145
- # `move: true` may be used during sending. This will *move* the unshareable
146
- # object to the receiving ractor, making it inaccessible to the sending ractor.
99
+ # <code>move: true</code> may be used during sending. This will *move* the
100
+ # unshareable object to the receiving ractor, making it inaccessible to the
101
+ # sending ractor.
147
102
  #
148
103
  # data = ['foo', 'bar']
149
104
  # r = Ractor.new do
@@ -151,7 +106,7 @@
151
106
  # puts "In ractor: #{data_in_ractor.object_id}, #{data_in_ractor[0].object_id}"
152
107
  # end
153
108
  # r.send(data, move: true)
154
- # r.take
109
+ # r.join
155
110
  # puts "Outside: moved? #{Ractor::MovedObject === data}"
156
111
  # puts "Outside: #{data.inspect}"
157
112
  #
@@ -161,14 +116,14 @@
161
116
  # Outside: moved? true
162
117
  # test.rb:9:in `method_missing': can not send any methods to a moved object (Ractor::MovedError)
163
118
  #
164
- # Notice that even `inspect` (and more basic methods like `__id__`) is
119
+ # Notice that even `inspect` and more basic methods like `__id__` are
165
120
  # inaccessible on a moved object.
166
121
  #
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.
122
+ # `Class` and `Module` objects are shareable and their class/module definitions
123
+ # are shared between ractors. Ractor objects are also shareable. All operations
124
+ # on shareable objects are thread-safe across ractors. Defining mutable,
125
+ # shareable objects in Ruby is not possible, but C extensions can introduce
126
+ # them.
172
127
  #
173
128
  # It is prohibited to access (get) instance variables of shareable objects in
174
129
  # other ractors if the values of the variables aren't shareable. This can occur
@@ -189,7 +144,7 @@
189
144
  # puts "I can't see #{cls.tricky}"
190
145
  # cls.tricky = true # doesn't get here, but this would also raise an error
191
146
  # end
192
- # r.take
147
+ # r.join
193
148
  # # I see C
194
149
  # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
195
150
  #
@@ -203,7 +158,7 @@
203
158
  # puts "GOOD=#{GOOD}"
204
159
  # puts "BAD=#{BAD}"
205
160
  # end
206
- # r.take
161
+ # r.join
207
162
  # # GOOD=good
208
163
  # # can not access non-shareable objects in constant Object::BAD by non-main Ractor. (NameError)
209
164
  #
@@ -213,12 +168,12 @@
213
168
  # puts "I see #{C}"
214
169
  # puts "I can't see #{C.tricky}"
215
170
  # end
216
- # r.take
171
+ # r.join
217
172
  # # I see C
218
173
  # # can not access instance variables of classes/modules from non-main Ractors (RuntimeError)
219
174
  #
220
- # See also the description of `# shareable_constant_value` pragma in [Comments
221
- # syntax](rdoc-ref:syntax/comments.rdoc) explanation.
175
+ # See also the description of <code># shareable_constant_value</code> pragma in
176
+ # [Comments syntax](rdoc-ref:syntax/comments.rdoc) explanation.
222
177
  #
223
178
  # ## Ractors vs threads
224
179
  #
@@ -229,20 +184,21 @@
229
184
  # a = 1
230
185
  # Thread.new {puts "Thread in ractor: a=#{a}"}.join
231
186
  # end
232
- # r.take
187
+ # r.join
233
188
  # # Here "Thread in ractor: a=1" will be printed
234
189
  #
235
190
  # ## Note on code examples
236
191
  #
237
192
  # 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).
193
+ # ractors to make progress or finish.
239
194
  #
240
195
  # def wait
241
196
  # sleep(0.1)
242
197
  # end
243
198
  #
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.
199
+ # This is **only for demonstration purposes** and shouldn't be used in a real
200
+ # code. Most of the time, #join is used to wait for ractors to finish and
201
+ # Ractor.receive is used to wait for messages.
246
202
  #
247
203
  # ## Reference
248
204
  #
@@ -261,7 +217,7 @@ class Ractor
261
217
  # rdoc-file=ractor.rb
262
218
  # - [](sym)
263
219
  # -->
264
- # get a value from ractor-local storage of current Ractor
220
+ # Gets a value from ractor-local storage for the current Ractor.
265
221
  #
266
222
  def self.[]: (Symbol) -> untyped
267
223
 
@@ -269,7 +225,7 @@ class Ractor
269
225
  # rdoc-file=ractor.rb
270
226
  # - []=(sym, val)
271
227
  # -->
272
- # set a value in ractor-local storage of current Ractor
228
+ # Sets a value in ractor-local storage for the current Ractor.
273
229
  #
274
230
  def self.[]=: (Symbol, untyped) -> untyped
275
231
 
@@ -277,13 +233,13 @@ class Ractor
277
233
  # rdoc-file=ractor.rb
278
234
  # - count()
279
235
  # -->
280
- # Returns the number of Ractors currently running or blocking (waiting).
236
+ # Returns the number of ractors currently running or blocking (waiting).
281
237
  #
282
238
  # Ractor.count #=> 1
283
- # r = Ractor.new(name: 'example') { Ractor.yield(1) }
239
+ # r = Ractor.new(name: 'example') { Ractor.receive }
284
240
  # Ractor.count #=> 2 (main + example ractor)
285
- # r.take # wait for Ractor.yield(1)
286
- # r.take # wait until r will finish
241
+ # r << 42 # r's Ractor.receive will resume
242
+ # r.join # wait for r's termination
287
243
  # Ractor.count #=> 1
288
244
  #
289
245
  def self.count: () -> Integer
@@ -302,7 +258,7 @@ class Ractor
302
258
  # rdoc-file=ractor.rb
303
259
  # - main()
304
260
  # -->
305
- # returns main ractor
261
+ # Returns the main ractor.
306
262
  #
307
263
  def self.main: () -> Ractor
308
264
 
@@ -310,7 +266,7 @@ class Ractor
310
266
  # rdoc-file=ractor.rb
311
267
  # - main?()
312
268
  # -->
313
- # return true if the current ractor is main ractor
269
+ # Returns true if the current ractor is the main ractor.
314
270
  #
315
271
  def self.main?: () -> boolish
316
272
 
@@ -318,7 +274,7 @@ class Ractor
318
274
  # rdoc-file=ractor.rb
319
275
  # - Ractor.make_shareable(obj, copy: false) -> shareable_obj
320
276
  # -->
321
- # Make `obj` shareable between ractors.
277
+ # Makes `obj` shareable between ractors.
322
278
  #
323
279
  # `obj` and all the objects it refers to will be frozen, unless they are already
324
280
  # shareable.
@@ -357,13 +313,13 @@ class Ractor
357
313
  # rdoc-file=ractor.rb
358
314
  # - Ractor.new(*args, name: nil) {|*args| block } -> ractor
359
315
  # -->
360
- # Create a new Ractor with args and a block.
316
+ # Creates a new Ractor with args and a block.
361
317
  #
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.
318
+ # The given block (Proc) is isolated (can't access any outer variables). `self`
319
+ # inside the block will refer to the current Ractor.
364
320
  #
365
321
  # r = Ractor.new { puts "Hi, I am #{self.inspect}" }
366
- # r.take
322
+ # r.join
367
323
  # # Prints "Hi, I am #<Ractor:#2 test.rb:1 running>"
368
324
  #
369
325
  # Any `args` passed are propagated to the block arguments by the same rules as
@@ -375,14 +331,14 @@ class Ractor
375
331
  # r = Ractor.new(arg) {|received_arg|
376
332
  # puts "Received: #{received_arg} (##{received_arg.object_id})"
377
333
  # }
378
- # r.take
334
+ # r.join
379
335
  # # Prints:
380
336
  # # Passing: [1, 2, 3] (#280)
381
337
  # # Received: [1, 2, 3] (#300)
382
338
  #
383
339
  # Ractor's `name` can be set for debugging purposes:
384
340
  #
385
- # r = Ractor.new(name: 'my ractor') {}; r.take
341
+ # r = Ractor.new(name: 'my ractor') {}; r.join
386
342
  # p r
387
343
  # #=> #<Ractor:#3 my ractor test.rb:1 terminated>
388
344
  #
@@ -390,128 +346,12 @@ class Ractor
390
346
 
391
347
  # <!--
392
348
  # rdoc-file=ractor.rb
393
- # - Ractor.receive -> msg
349
+ # - Ractor.receive -> obj
394
350
  # -->
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
+ # Receives a message from the current ractor's default port.
450
352
  #
451
353
  def self.receive: () -> untyped
452
354
 
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
355
  # <!--
516
356
  # rdoc-file=ractor.rb
517
357
  # - recv()
@@ -521,57 +361,51 @@ class Ractor
521
361
 
522
362
  # <!--
523
363
  # rdoc-file=ractor.rb
524
- # - Ractor.select(*ractors, [yield_value:, move: false]) -> [ractor or symbol, obj]
364
+ # - Ractor.select(*ractors_or_ports) -> [ractor or port, obj]
525
365
  # -->
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'
366
+ # Blocks the current Thread until one of the given ports has received a message.
367
+ # Returns an array of two elements where the first element is the Port and the
368
+ # second is the received object. This method can also accept Ractor objects
369
+ # themselves, and in that case will wait until one has terminated and return a
370
+ # two-element array where the first element is the ractor and the second is its
371
+ # termination value.
372
+ #
373
+ # p1, p2 = Ractor::Port.new, Ractor::Port.new
374
+ # ps = [p1, p2]
375
+ # rs = 2.times.map do |i|
376
+ # Ractor.new(ps.shift, i) do |p, i|
377
+ # sleep rand(0.99)
378
+ # p.send("r#{i}")
379
+ # sleep rand(0.99)
380
+ # "r#{i} done"
381
+ # end
547
382
  # end
548
383
  #
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}"
384
+ # waiting_on = [p1, p2, *rs]
385
+ # until waiting_on.empty?
386
+ # received_on, obj = Ractor.select(*waiting_on)
387
+ # waiting_on.delete(received_on)
388
+ # puts obj
558
389
  # end
559
390
  #
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.
391
+ # # r0
392
+ # # r1
393
+ # # r1 done
394
+ # # r0 done
395
+ #
396
+ # The following example is almost equivalent to
397
+ # <code>ractors.map(&:value)</code> except the thread is unblocked when any of
398
+ # the ractors has terminated as opposed to waiting for their termination in the
399
+ # array element order.
400
+ #
401
+ # values = []
402
+ # until ractors.empty?
403
+ # r, val = Ractor.select(*ractors)
404
+ # ractors.delete(r)
405
+ # values << val
406
+ # end
573
407
  #
574
- def self.select: (*Ractor ractors, ?move: boolish, ?yield_value: untyped) -> [ Ractor | Symbol, untyped ]
408
+ def self.select: (?) -> Array[untyped]
575
409
 
576
410
  # <!--
577
411
  # rdoc-file=ractor.rb
@@ -579,7 +413,7 @@ class Ractor
579
413
  # -->
580
414
  # Checks if the object is shareable by ractors.
581
415
  #
582
- # Ractor.shareable?(1) #=> true -- numbers and other immutable basic values are frozen
416
+ # Ractor.shareable?(1) #=> true -- numbers are shareable
583
417
  # Ractor.shareable?('foo') #=> false, unless the string is frozen due to # frozen_string_literal: true
584
418
  # Ractor.shareable?('foo'.freeze) #=> true
585
419
  #
@@ -588,13 +422,44 @@ class Ractor
588
422
  #
589
423
  def self.shareable?: (untyped obj) -> bool
590
424
 
425
+ # <!--
426
+ # rdoc-file=ractor.rb
427
+ # - Ractor.shareable_proc(self: nil){} -> shareable proc
428
+ # -->
429
+ # Returns a shareable copy of the given block's Proc. The value of `self` in the
430
+ # Proc will be replaced with the value passed via the <code>self:</code>
431
+ # keyword, or `nil` if not given.
432
+ #
433
+ # In a shareable Proc, access to any outer variables if prohibited.
434
+ #
435
+ # a = 42
436
+ # Ractor.shareable_proc{ p a }
437
+ # #=> can not isolate a Proc because it accesses outer variables (a). (ArgumentError)
438
+ #
439
+ # The value of `self` in the Proc must be a shareable object.
440
+ #
441
+ # Ractor.shareable_proc(self: self){}
442
+ # #=> self should be shareable: main (Ractor::IsolationError)
443
+ #
444
+ def self.shareable_proc: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T
445
+ | [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T
446
+
447
+ # <!--
448
+ # rdoc-file=ractor.rb
449
+ # - Ractor.shareable_lambda(self: nil){} -> shareable lambda
450
+ # -->
451
+ # Same as Ractor.shareable_proc, but returns a lambda Proc.
452
+ #
453
+ def self.shareable_lambda: [T] () { (?) [self: nil] -> T } -> ^(?) [self: nil] -> T
454
+ | [T, S] (self: S) { (?) [self: S] -> T } -> ^(?) [self: S] -> T
455
+
591
456
  # <!--
592
457
  # rdoc-file=ractor.rb
593
458
  # - Ractor.store_if_absent(key){ init_block }
594
459
  # -->
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.
460
+ # If the corresponding ractor-local value is not set, yields a value with
461
+ # init_block and stores the value in a thread-safe manner. This method returns
462
+ # the stored value.
598
463
  #
599
464
  # (1..10).map{
600
465
  # Thread.new(it){|i|
@@ -607,47 +472,7 @@ class Ractor
607
472
 
608
473
  # <!--
609
474
  # 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)
475
+ # - <<(...)
651
476
  # -->
652
477
  #
653
478
  alias << send
@@ -656,225 +481,119 @@ class Ractor
656
481
  # rdoc-file=ractor.rb
657
482
  # - [](sym)
658
483
  # -->
659
- # get a value from ractor-local storage of current Ractor Obsolete and use
484
+ # Gets a value from ractor-local storage for the current Ractor. Obsolete, use
660
485
  # Ractor.[] instead.
661
486
  #
487
+ %a{deprecated: Use Ractor.[] instead}
662
488
  def []: (interned sym) -> untyped
663
489
 
664
490
  # <!--
665
491
  # rdoc-file=ractor.rb
666
492
  # - []=(sym, val)
667
493
  # -->
668
- # set a value in ractor-local storage of current Ractor Obsolete and use
494
+ # Sets a value in ractor-local storage for the current Ractor. Obsolete, use
669
495
  # Ractor.[]= instead.
670
496
  #
497
+ %a{deprecated: Use Ractor.[]= instead}
671
498
  def []=: [T] (interned sym, T val) -> T
672
499
 
673
500
  # <!--
674
501
  # rdoc-file=ractor.rb
675
- # - ractor.close_incoming -> true | false
502
+ # - ractor.default_port -> port object
676
503
  # -->
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.
680
- #
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)
504
+ # Returns the default port of the Ractor.
686
505
  #
687
- def close_incoming: () -> bool
506
+ def default_port: () -> Port[untyped]
688
507
 
689
508
  # <!--
690
509
  # rdoc-file=ractor.rb
691
- # - ractor.close_outgoing -> true | false
510
+ # - inspect()
692
511
  # -->
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
512
  #
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
513
+ def inspect: () -> String
704
514
 
705
515
  # <!--
706
516
  # rdoc-file=ractor.rb
707
- # - inspect()
517
+ # - ractor.join -> self
708
518
  # -->
519
+ # Waits for the termination of the Ractor. If the Ractor was aborted (terminated
520
+ # by an unhandled exception), the exception is raised in the current ractor.
709
521
  #
710
- def inspect: () -> String
522
+ # Ractor.new{}.join #=> ractor
523
+ #
524
+ # Ractor.new{ raise "foo" }.join
525
+ # #=> raises the exception "foo (RuntimeError)"
526
+ #
527
+ def join: () -> self
711
528
 
712
529
  # <!--
713
530
  # rdoc-file=ractor.rb
714
531
  # - name()
715
532
  # -->
716
- # The name set in Ractor.new, or `nil`.
533
+ # Returns the name set in Ractor.new, or `nil`.
717
534
  #
718
535
  def name: () -> String?
719
536
 
720
537
  # <!--
721
538
  # rdoc-file=ractor.rb
722
- # - ractor.send(msg, move: false) -> self
539
+ # - ractor.monitor(port) -> self
723
540
  # -->
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.
541
+ # Registers the port as a monitoring port for this ractor. When the ractor
542
+ # terminates, the port receives a Symbol object.
766
543
  #
767
- # r = Ractor.new {puts "Received: #{receive}"}
768
- # msg = 'message'
769
- # r.send(msg, move: true)
770
- # r.take
771
- # p msg
544
+ # * <code>:exited</code> is sent if the ractor terminates without an unhandled
545
+ # exception.
546
+ # * <code>:aborted</code> is sent if the ractor terminates by an unhandled
547
+ # exception.
772
548
  #
773
- # This prints:
549
+ # r = Ractor.new{ some_task() }
550
+ # r.monitor(port = Ractor::Port.new)
551
+ # port.receive #=> :exited and r is terminated
774
552
  #
775
- # Received: message
776
- # in `p': undefined method `inspect' for #<Ractor::MovedObject:0x000055c99b9b69b8>
553
+ # r = Ractor.new{ raise "foo" }
554
+ # r.monitor(port = Ractor::Port.new)
555
+ # port.receive #=> :aborted and r is terminated by the RuntimeError "foo"
777
556
  #
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
557
+ def monitor: [T < Symbol] (Port[T]) -> untyped
558
+
559
+ # <!--
560
+ # rdoc-file=ractor.rb
561
+ # - ractor.send(msg, move: false) -> self
562
+ # -->
563
+ # This is equivalent to Port#send to the ractor's #default_port.
802
564
  #
803
565
  def send: (untyped obj, ?move: boolish) -> Ractor
804
566
 
805
567
  # <!--
806
568
  # rdoc-file=ractor.rb
807
- # - ractor.take -> msg
569
+ # - to_s()
808
570
  # -->
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
571
  #
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
572
+ alias to_s inspect
573
+
574
+ # <!--
575
+ # rdoc-file=ractor.rb
576
+ # - ractor.unmonitor(port) -> self
577
+ # -->
578
+ # Unregisters the port from the monitoring ports for this ractor.
869
579
  #
870
- def take: () -> untyped
580
+ def unmonitor: (Port[untyped]) -> self
871
581
 
872
582
  # <!--
873
583
  # rdoc-file=ractor.rb
874
- # - to_s()
584
+ # - ractor.value -> obj
875
585
  # -->
586
+ # Waits for `ractor` to complete and returns its value or raises the exception
587
+ # which terminated the Ractor. The termination value will be moved to the
588
+ # calling Ractor. Therefore, at most 1 Ractor can receive another ractor's
589
+ # termination value.
876
590
  #
877
- alias to_s inspect
591
+ # r = Ractor.new{ [1, 2] }
592
+ # r.value #=> [1, 2] (unshareable object)
593
+ #
594
+ # Ractor.new(r){|r| r.value} #=> Ractor::Error
595
+ #
596
+ def value: () -> untyped
878
597
 
879
598
  private
880
599
 
@@ -904,49 +623,35 @@ class Ractor
904
623
  # <!-- rdoc-file=ractor.c -->
905
624
  # Raised when an attempt is made to send a message to a closed port, or to
906
625
  # 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
626
+ # explicitly with Ractor::Port#close and are closed implicitly when a Ractor
627
+ # terminates.
924
628
  #
925
- # 3.times{|i| r << i}
926
- # r.close_incoming
927
- # r.take
928
- # puts "Continue successfully"
629
+ # port = Ractor::Port.new
630
+ # port.close
631
+ # port << "test" # Ractor::ClosedError
632
+ # port.receive # Ractor::ClosedError
929
633
  #
930
- # This will print:
931
- #
932
- # Received: 0
933
- # Received: 1
934
- # Received: 2
935
- # loop exited
936
- # Continue successfully
634
+ # ClosedError is a descendant of StopIteration, so the closing of a port will
635
+ # break out of loops without propagating the error.
937
636
  #
938
637
  class ClosedError < StopIteration
939
638
  end
940
639
 
640
+ # <!-- rdoc-file=ractor.c -->
641
+ # The parent class of Ractor-related error classes.
642
+ #
941
643
  class Error < RuntimeError
942
644
  end
943
645
 
646
+ # <!-- rdoc-file=ractor.c -->
647
+ # Raised on attempt to make a Ractor-unshareable object Ractor-shareable.
648
+ #
944
649
  class IsolationError < Ractor::Error
945
650
  end
946
651
 
947
652
  # <!-- rdoc-file=ractor.c -->
948
653
  # Raised on an attempt to access an object which was moved in Ractor#send or
949
- # Ractor.yield.
654
+ # Ractor::Port#send.
950
655
  #
951
656
  # r = Ractor.new { sleep }
952
657
  #
@@ -960,7 +665,7 @@ class Ractor
960
665
 
961
666
  # <!-- rdoc-file=ractor.c -->
962
667
  # 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
668
+ # Ractor#send or Ractor::Port#send. Any attempt to access the object results in
964
669
  # Ractor::MovedError.
965
670
  #
966
671
  # r = Ractor.new { receive }
@@ -1037,15 +742,163 @@ class Ractor
1037
742
  def method_missing: (*untyped) -> untyped
1038
743
  end
1039
744
 
745
+ # <!-- rdoc-file=ractor.rb -->
746
+ # Port objects transmit messages between Ractors.
747
+ #
748
+ class Port[T = untyped]
749
+ # <!--
750
+ # rdoc-file=ractor.rb
751
+ # - <<(obj, move: false)
752
+ # -->
753
+ #
754
+ alias << send
755
+
756
+ # <!--
757
+ # rdoc-file=ractor.rb
758
+ # - port.close
759
+ # -->
760
+ # Closes the port. Sending to a closed port is prohibited. Receiving is also
761
+ # prohibited if there are no messages in its message queue.
762
+ #
763
+ # Only the Ractor which created the port is allowed to close it.
764
+ #
765
+ # port = Ractor::Port.new
766
+ # Ractor.new port do |port|
767
+ # port.close #=> closing port by other ractors is not allowed (Ractor::Error)
768
+ # end.join
769
+ #
770
+ def close: () -> void
771
+
772
+ # <!--
773
+ # rdoc-file=ractor.rb
774
+ # - port.closed? -> true/false
775
+ # -->
776
+ # Returns whether or not the port is closed.
777
+ #
778
+ def closed?: () -> bool
779
+
780
+ # <!--
781
+ # rdoc-file=ractor.rb
782
+ # - port.inspect -> string
783
+ # -->
784
+ #
785
+ def inspect: () -> String
786
+
787
+ # <!--
788
+ # rdoc-file=ractor.rb
789
+ # - port.receive -> msg
790
+ # -->
791
+ # Receives a message from the port (which was sent there by Port#send). Only the
792
+ # ractor that created the port can receive messages this way.
793
+ #
794
+ # port = Ractor::Port.new
795
+ # r = Ractor.new port do |port|
796
+ # port.send('message1')
797
+ # end
798
+ #
799
+ # v1 = port.receive
800
+ # puts "Received: #{v1}"
801
+ # r.join
802
+ # # This will print: "Received: message1"
803
+ #
804
+ # The method blocks the current Thread if the message queue is empty.
805
+ #
806
+ # port = Ractor::Port.new
807
+ # r = Ractor.new port do |port|
808
+ # wait
809
+ # puts "Still not received"
810
+ # port.send('message1')
811
+ # wait
812
+ # puts "Still received only one"
813
+ # port.send('message2')
814
+ # end
815
+ # puts "Before first receive"
816
+ # v1 = port.receive
817
+ # puts "Received: #{v1}"
818
+ # v2 = port.receive
819
+ # puts "Received: #{v2}"
820
+ # r.join
821
+ #
822
+ # Output:
823
+ #
824
+ # Before first receive
825
+ # Still not received
826
+ # Received: message1
827
+ # Still received only one
828
+ # Received: message2
829
+ #
830
+ # If the port is closed and there are no more messages in the message queue, the
831
+ # method raises Ractor::ClosedError.
832
+ #
833
+ # port = Ractor::Port.new
834
+ # port.close
835
+ # port.receive #=> raise Ractor::ClosedError
836
+ #
837
+ def receive: () -> T
838
+
839
+ # <!--
840
+ # rdoc-file=ractor.rb
841
+ # - port.send(msg, move: false) -> self
842
+ # -->
843
+ # Sends a message to the port to be accepted by port.receive.
844
+ #
845
+ # port = Ractor::Port.new
846
+ # r = Ractor.new(port) do |port|
847
+ # port.send 'message'
848
+ # end
849
+ # value = port.receive
850
+ # puts "Received #{value}"
851
+ # # Prints: "Received: message"
852
+ #
853
+ # The method is non-blocking (it will return immediately even if the ractor that
854
+ # created the port is not ready to receive anything):
855
+ #
856
+ # port = Ractor::Port.new
857
+ # r = Ractor.new(port) do |port|
858
+ # port.send 'test'
859
+ # puts "Sent successfully"
860
+ # # Prints: "Sent successfully" immediately
861
+ # end
862
+ #
863
+ # An attempt to send to a closed port will raise Ractor::ClosedError.
864
+ #
865
+ # r = Ractor.new {Ractor::Port.new}
866
+ # r.join
867
+ # p r
868
+ # # "#<Ractor:#6 (irb):23 terminated>"
869
+ # port = r.value
870
+ # port.send('test') # raise Ractor::ClosedError
871
+ #
872
+ # If the `obj` is unshareable, by default it will be copied into the receiving
873
+ # ractor by deep cloning.
874
+ #
875
+ # If the object is shareable, a reference to the object will be sent to the
876
+ # receiving ractor.
877
+ #
878
+ def send: (T obj, ?move: boolish) -> self
879
+
880
+ private
881
+
882
+ # <!--
883
+ # rdoc-file=ractor_sync.c
884
+ # - Ractor::Port.new -> new_port
885
+ # -->
886
+ # Returns a new Ractor::Port object.
887
+ #
888
+ def initialize: () -> void
889
+
890
+ def initialize_copy: (untyped) -> untyped
891
+ end
892
+
1040
893
  # <!-- 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.
894
+ # Raised on Ractor#join or Ractor#value if there was an uncaught exception in
895
+ # the Ractor. Its `cause` will contain the original exception, and `ractor` is
896
+ # the original ractor it was raised in.
1044
897
  #
1045
898
  # r = Ractor.new { raise "Something weird happened" }
1046
899
  #
1047
900
  # begin
1048
- # r.take
901
+ # r.value
1049
902
  # rescue => e
1050
903
  # p e # => #<Ractor::RemoteError: thrown by remote Ractor.>
1051
904
  # p e.ractor == r # => true
@@ -1054,11 +907,14 @@ class Ractor
1054
907
  #
1055
908
  class RemoteError < Ractor::Error
1056
909
  # <!-- rdoc-file=ractor.rb -->
1057
- # The Ractor an uncaught exception is raised in.
910
+ # The Ractor in which the uncaught exception was raised.
1058
911
  #
1059
912
  def ractor: () -> Ractor
1060
913
  end
1061
914
 
915
+ # <!-- rdoc-file=ractor.c -->
916
+ # Raised when Ractor-unsafe C-methods is invoked by a non-main Ractor.
917
+ #
1062
918
  class UnsafeError < Ractor::Error
1063
919
  end
1064
920