@@ -363,7 +363,7 @@ class Ractor
363363 # -->
364364 # TBD
365365 #
366- def self.select : (?) -> untyped
366+ def self.select : (?) -> Array[ untyped ]
367367
368368 # <!--
369369 # rdoc-file=ractor.rb
@@ -380,6 +380,36 @@ class Ractor
380380 #
381381 def self.shareable? : (untyped obj) -> bool
382382
383+ # <!--
384+ # rdoc-file=ractor.rb
385+ # - Ractor.sharable_proc(self: nil){} -> sharable proc
386+ # -->
387+ # It returns shareable Proc object. The Proc object is shareable and the self in
388+ # a block will be replaced with the value passed via `self:` keyword.
389+ #
390+ # In a shareable Proc, you can not access to the outer variables.
391+ #
392+ # a = 42
393+ # Ractor.shareable_proc{ p a }
394+ # #=> can not isolate a Proc because it accesses outer variables (a). (ArgumentError)
395+ #
396+ # The `self` should be a sharable object
397+ #
398+ # Ractor.shareable_proc(self: self){}
399+ # #=> self should be shareable: main (Ractor::IsolationError)
400+ #
401+ def self.shareable_proc : [T] () { (?) [self : nil ] -> T } -> ^(?) [self : nil ] -> T
402+ | [T, S] (self : S) { (?) [self : S] -> T } -> ^(?) [self : S] -> T
403+
404+ # <!--
405+ # rdoc-file=ractor.rb
406+ # - Ractor.sharable_proc{} -> sharable proc
407+ # -->
408+ # Same as Ractor.sharable_proc, but returns lambda proc.
409+ #
410+ def self.shareable_lambda : [T] () { (?) [self : nil ] -> T } -> ^(?) [self : nil ] -> T
411+ | [T, S] (self : S) { (?) [self : S] -> T } -> ^(?) [self : S] -> T
412+
383413 # <!--
384414 # rdoc-file=ractor.rb
385415 # - Ractor.store_if_absent(key){ init_block }
@@ -424,13 +454,35 @@ class Ractor
424454 %a{deprecated: Use Ractor.[]= instead}
425455 def []= : [T] (interned sym, T val) -> T
426456
457+ # <!--
458+ # rdoc-file=ractor.rb
459+ # - ractor.default_port -> port object
460+ # -->
461+ # return default port of the Ractor.
462+ #
463+ def default_port : () -> Port[untyped ]
464+
427465 # <!--
428466 # rdoc-file=ractor.rb
429467 # - inspect()
430468 # -->
431469 #
432470 def inspect : () -> String
433471
472+ # <!--
473+ # rdoc-file=ractor.rb
474+ # - ractor.join -> self
475+ # -->
476+ # Wait for the termination of the Ractor. If the Ractor was aborted (terminated
477+ # with an exception), Ractor#value is called to raise an exception.
478+ #
479+ # Ractor.new{}.join #=> ractor
480+ #
481+ # Ractor.new{ raise "foo" }.join
482+ # #=> raise an exception "foo (RuntimeError)"
483+ #
484+ def join : () -> self
485+
434486 # <!--
435487 # rdoc-file=ractor.rb
436488 # - name()
@@ -439,6 +491,25 @@ class Ractor
439491 #
440492 def name : () -> String?
441493
494+ # <!--
495+ # rdoc-file=ractor.rb
496+ # - ractor.monitor(port) -> self
497+ # -->
498+ # Register port as a monitoring port. If the ractor terminated, the port
499+ # received a Symbol object. :exited will be sent if the ractor terminated
500+ # without an exception. :aborted will be sent if the ractor terminated with a
501+ # exception.
502+ #
503+ # r = Ractor.new{ some_task() }
504+ # r.monitor(port = Ractor::Port.new)
505+ # port.receive #=> :exited and r is terminated
506+ #
507+ # r = Ractor.new{ raise "foo" }
508+ # r.monitor(port = Ractor::Port.new)
509+ # port.receive #=> :terminated and r is terminated with an exception "foo"
510+ #
511+ def monitor : [T < Symbol] (Port[T]) -> untyped
512+
442513 # <!--
443514 # rdoc-file=ractor.rb
444515 # - ractor.send(msg) -> self
@@ -454,6 +525,29 @@ class Ractor
454525 #
455526 alias to_s inspect
456527
528+ # <!--
529+ # rdoc-file=ractor.rb
530+ # - ractor.unmonitor(port) -> self
531+ # -->
532+ # Unregister port from the monitoring ports.
533+ #
534+ def unmonitor : (Port[untyped ]) -> self
535+
536+ # <!--
537+ # rdoc-file=ractor.rb
538+ # - ractor.value -> obj
539+ # -->
540+ # Waits for `ractor` to complete, using #join, and return its value or raise the
541+ # exception which terminated the Ractor. The value will not be copied even if it
542+ # is unshareable object. Therefore at most 1 Ractor can get a value.
543+ #
544+ # r = Ractor.new{ [1, 2] }
545+ # r.value #=> [1, 2] (unshareable object)
546+ #
547+ # Ractor.new(r){|r| r.value} #=> Ractor::Error
548+ #
549+ def value : () -> untyped
550+
457551 private
458552
459553 # <!--
@@ -621,6 +715,166 @@ class Ractor
621715 def method_missing : (*untyped ) -> untyped
622716 end
623717
718+ # <!-- rdoc-file=ractor.rb -->
719+ # Port objects transmit messages between Ractors.
720+ #
721+ class Port [T = untyped ]
722+ # <!--
723+ # rdoc-file=ractor.rb
724+ # - <<(obj, move: false)
725+ # -->
726+ #
727+ alias << send
728+
729+ # <!--
730+ # rdoc-file=ractor.rb
731+ # - port.close
732+ # -->
733+ # Close the port. On the closed port, sending is not prohibited. Receiving is
734+ # also not allowed if there is no sent messages arrived before closing.
735+ #
736+ # port = Ractor::Port.new
737+ # Ractor.new port do |port|
738+ # port.send 1 # OK
739+ # port.send 2 # OK
740+ # port.close
741+ # port.send 3 # raise Ractor::ClosedError
742+ # end
743+ #
744+ # port.receive #=> 1
745+ # port.receive #=> 2
746+ # port.receive #=> raise Ractor::ClosedError
747+ #
748+ # Now, only a Ractor which creates the port is allowed to close ports.
749+ #
750+ # port = Ractor::Port.new
751+ # Ractor.new port do |port|
752+ # port.close #=> closing port by other ractors is not allowed (Ractor::Error)
753+ # end.join
754+ #
755+ def close : () -> void
756+
757+ # <!--
758+ # rdoc-file=ractor.rb
759+ # - port.closed? -> true/false
760+ # -->
761+ # Return the port is closed or not.
762+ #
763+ def closed? : () -> bool
764+
765+ # <!--
766+ # rdoc-file=ractor.rb
767+ # - port.inspect -> string
768+ # -->
769+ #
770+ def inspect : () -> String
771+
772+ # <!--
773+ # rdoc-file=ractor.rb
774+ # - port.receive -> msg
775+ # -->
776+ # Receive a message to the port (which was sent there by Port#send).
777+ #
778+ # port = Ractor::Port.new
779+ # r = Ractor.new port do |port|
780+ # port.send('message1')
781+ # end
782+ #
783+ # v1 = port.receive
784+ # puts "Received: #{v1}"
785+ # r.join
786+ # # Here will be printed: "Received: message1"
787+ #
788+ # The method blocks if the message queue is empty.
789+ #
790+ # port = Ractor::Port.new
791+ # r = Ractor.new port do |port|
792+ # wait
793+ # puts "Still not received"
794+ # port.send('message1')
795+ # wait
796+ # puts "Still received only one"
797+ # port.send('message2')
798+ # end
799+ # puts "Before first receive"
800+ # v1 = port.receive
801+ # puts "Received: #{v1}"
802+ # v2 = port.receive
803+ # puts "Received: #{v2}"
804+ # r.join
805+ #
806+ # Output:
807+ #
808+ # Before first receive
809+ # Still not received
810+ # Received: message1
811+ # Still received only one
812+ # Received: message2
813+ #
814+ # If close_incoming was called on the ractor, the method raises
815+ # Ractor::ClosedError if there are no more messages in the message queue:
816+ #
817+ # port = Ractor::Port.new
818+ # port.close
819+ # port.receive #=> raise Ractor::ClosedError
820+ #
821+ def receive : () -> T
822+
823+ # <!--
824+ # rdoc-file=ractor.rb
825+ # - port.send(msg, move: false) -> self
826+ # -->
827+ # Send a message to a port to be accepted by port.receive.
828+ #
829+ # port = Ractor::Port.new
830+ # r = Ractor.new do
831+ # r.send 'message'
832+ # end
833+ # value = port.receive
834+ # puts "Received #{value}"
835+ # # Prints: "Received: message"
836+ #
837+ # The method is non-blocking (will return immediately even if the ractor is not
838+ # ready to receive anything):
839+ #
840+ # port = Ractor::Port.new
841+ # r = Ractor.new(port) do |port|
842+ # port.send 'test'}
843+ # puts "Sent successfully"
844+ # # Prints: "Sent successfully" immediately
845+ # end
846+ #
847+ # An attempt to send to a port which already closed its execution will raise
848+ # Ractor::ClosedError.
849+ #
850+ # r = Ractor.new {Ractor::Port.new}
851+ # r.join
852+ # p r
853+ # # "#<Ractor:#6 (irb):23 terminated>"
854+ # port = r.value
855+ # port.send('test') # raise Ractor::ClosedError
856+ #
857+ # If the `obj` is unshareable, by default it will be copied into the receiving
858+ # ractor by deep cloning.
859+ #
860+ # If the object is shareable, it only send a reference to the object without
861+ # cloning.
862+ #
863+ def send : (T obj, ?move: boolish) -> self
864+
865+ private
866+
867+ # <!--
868+ # rdoc-file=ractor_sync.c
869+ # - Ractor::Port.new -> new_port
870+ # -->
871+ # Returns a new Ractor::Port object.
872+ #
873+ def initialize : () -> void
874+
875+ def initialize_copy : (untyped ) -> untyped
876+ end
877+
624878 # <!-- rdoc-file=ractor.c -->
625879 # Raised on attempt to Ractor#take if there was an uncaught exception in the
626880 # Ractor. Its `cause` will contain the original exception, and `ractor` is the
0 commit comments