diff --git a/stdlib/io-nonblock/0/io-nonblock.rbs b/stdlib/io-nonblock/0/io-nonblock.rbs new file mode 100644 index 000000000..71a82fd7d --- /dev/null +++ b/stdlib/io-nonblock/0/io-nonblock.rbs @@ -0,0 +1,68 @@ +%a{annotate:rdoc:skip} +class IO + # + # Yields `self` in non-blocking mode. + # + # When `false` is given as an argument, `self` is yielded in blocking mode. The + # original mode is restored after the block is executed. + # + def nonblock: [T] (?boolish nb) { (self) -> T } -> T + + # + # Enables non-blocking mode on a stream when set to `true`, and blocking mode + # when set to `false`. + # + # This method set or clear O_NONBLOCK flag for the file descriptor in *ios*. + # + # The behavior of most IO methods is not affected by this flag because they + # retry system calls to complete their task after EAGAIN and partial read/write. + # (An exception is IO#syswrite which doesn't retry.) + # + # This method can be used to clear non-blocking mode of standard I/O. Since + # nonblocking methods (read_nonblock, etc.) set non-blocking mode but they + # doesn't clear it, this method is usable as follows. + # + # END { STDOUT.nonblock = false } + # STDOUT.write_nonblock("foo") + # + # Since the flag is shared across processes and many non-Ruby commands doesn't + # expect standard I/O with non-blocking mode, it would be safe to clear the flag + # before Ruby program exits. + # + # For example following Ruby program leaves STDIN/STDOUT/STDER non-blocking + # mode. (STDIN, STDOUT and STDERR are connected to a terminal. So making one of + # them nonblocking-mode effects other two.) Thus cat command try to read from + # standard input and it causes "Resource temporarily unavailable" error + # (EAGAIN). + # + # % ruby -e ' + # STDOUT.write_nonblock("foo\n")'; cat + # foo + # cat: -: Resource temporarily unavailable + # + # Clearing the flag makes the behavior of cat command normal. (cat command waits + # input from standard input.) + # + # % ruby -rio/nonblock -e ' + # END { STDOUT.nonblock = false } + # STDOUT.write_nonblock("foo") + # '; cat + # foo + # + def nonblock=: (boolish value) -> self + + # + # Returns `true` if an IO object is in non-blocking mode. + # + def nonblock?: () -> bool +end diff --git a/test/stdlib/IO_nonblock_test.rb b/test/stdlib/IO_nonblock_test.rb new file mode 100644 index 000000000..12c61d1a0 --- /dev/null +++ b/test/stdlib/IO_nonblock_test.rb @@ -0,0 +1,37 @@ +require_relative "test_helper" +require "io/nonblock" + +class IONonblockTest < Test::Unit::TestCase + include TestHelper + + library "io-nonblock" + testing "::IO" + + def setup + @r, @w = IO.pipe + end + + def teardown + @r.close + @w.close + end + + def test_nonblock + assert_send_type "() { (IO) -> Integer } -> Integer", + @r, :nonblock do 1 end + assert_send_type "(bool) { (IO) -> Integer } -> Integer", + @r, :nonblock, false do 1 end + end + + def test_nonblock_assign + assert_send_type "(bool) -> IO", + @r, :nonblock=, true + assert_send_type "(bool) -> IO", + @r, :nonblock=, false + end + + def test_nonblock? + assert_send_type "() -> bool", + @r, :nonblock? + end +end