[前][次][番号順一覧][スレッド一覧]

ruby-changes:30616

From: tenderlove <ko1@a...>
Date: Tue, 27 Aug 2013 07:41:54 +0900 (JST)
Subject: [ruby-changes:30616] tenderlove:r42695 (trunk): * io.c (io_read_nonblock): support non-blocking reads without raising

tenderlove	2013-08-27 07:41:44 +0900 (Tue, 27 Aug 2013)

  New Revision: 42695

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=42695

  Log:
    * io.c (io_read_nonblock): support non-blocking reads without raising
      exceptions. As in: `io.read_nonblock(size, exception: false)`
      [ruby-core:38666] [Feature #5138]
    * ext/openssl/ossl_ssl.c (ossl_ssl_read_internal): ditto
    * ext/stringio/stringio.c (strio_sysread): ditto
    * io.c (rb_io_write_nonblock): support non-blocking writes without
      raising an exception.
    * ext/openssl/ossl_ssl.c (ossl_ssl_write_internal): ditto
    * test/openssl/test_pair.rb (class OpenSSL): tests
    * test/ruby/test_io.rb (class TestIO): ditto
    * test/socket/test_nonblock.rb (class TestSocketNonblock): ditto
    * test/stringio/test_stringio.rb (class TestStringIO): ditto

  Modified files:
    trunk/ChangeLog
    trunk/ext/openssl/lib/openssl/buffering.rb
    trunk/ext/openssl/ossl_ssl.c
    trunk/ext/stringio/stringio.c
    trunk/io.c
    trunk/test/openssl/test_pair.rb
    trunk/test/ruby/test_io.rb
    trunk/test/socket/test_nonblock.rb
    trunk/test/stringio/test_stringio.rb
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 42694)
+++ ChangeLog	(revision 42695)
@@ -1,3 +1,18 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Aug 27 07:35:05 2013  Aaron Patterson <aaron@t...>
+
+	* io.c (io_read_nonblock): support non-blocking reads without raising
+	  exceptions. As in: `io.read_nonblock(size, exception: false)`
+	  [ruby-core:38666] [Feature #5138]
+	* ext/openssl/ossl_ssl.c (ossl_ssl_read_internal): ditto
+	* ext/stringio/stringio.c (strio_sysread): ditto
+	* io.c (rb_io_write_nonblock): support non-blocking writes without
+	  raising an exception.
+	* ext/openssl/ossl_ssl.c (ossl_ssl_write_internal): ditto
+	* test/openssl/test_pair.rb (class OpenSSL): tests
+	* test/ruby/test_io.rb (class TestIO): ditto
+	* test/socket/test_nonblock.rb (class TestSocketNonblock): ditto
+	* test/stringio/test_stringio.rb (class TestStringIO): ditto
+
 Tue Aug 27 05:24:34 2013  Eric Hodel  <drbrain@s...>
 
 	* lib/rubygems:  Import RubyGems 2.1.0 Release Candidate
Index: io.c
===================================================================
--- io.c	(revision 42694)
+++ io.c	(revision 42695)
@@ -159,7 +159,7 @@ static VALUE argf; https://github.com/ruby/ruby/blob/trunk/io.c#L159
 
 static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding;
 static VALUE sym_mode, sym_perm, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
-static VALUE sym_textmode, sym_binmode, sym_autoclose;
+static VALUE sym_textmode, sym_binmode, sym_autoclose, sym_exception;
 static VALUE sym_SET, sym_CUR, sym_END;
 #ifdef SEEK_DATA
 static VALUE sym_DATA;
@@ -2413,14 +2413,14 @@ read_internal_call(VALUE arg) https://github.com/ruby/ruby/blob/trunk/io.c#L2413
 }
 
 static VALUE
-io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
+io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock, int no_exception)
 {
     rb_io_t *fptr;
     VALUE length, str;
     long n, len;
     struct read_internal_arg arg;
 
-    rb_scan_args(argc, argv, "11", &length, &str);
+    rb_scan_args(argc, argv, "11:", &length, &str, NULL);
 
     if ((len = NUM2LONG(length)) < 0) {
 	rb_raise(rb_eArgError, "negative length %ld given", len);
@@ -2452,8 +2452,12 @@ io_getpartial(int argc, VALUE *argv, VAL https://github.com/ruby/ruby/blob/trunk/io.c#L2452
         if (n < 0) {
             if (!nonblock && rb_io_wait_readable(fptr->fd))
                 goto again;
-            if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
-                rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "read would block");
+            if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
+                if (no_exception)
+                    return ID2SYM(rb_intern("wait_readable"));
+                else
+		    rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "read would block");
+            }
             rb_sys_fail_path(fptr->pathv);
         }
     }
@@ -2529,7 +2533,7 @@ io_readpartial(int argc, VALUE *argv, VA https://github.com/ruby/ruby/blob/trunk/io.c#L2533
 {
     VALUE ret;
 
-    ret = io_getpartial(argc, argv, io, 0);
+    ret = io_getpartial(argc, argv, io, 0, 0);
     if (NIL_P(ret))
         rb_eof_error();
     return ret;
@@ -2590,16 +2594,62 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/io.c#L2594
 io_read_nonblock(int argc, VALUE *argv, VALUE io)
 {
     VALUE ret;
+    VALUE opts = Qnil;
+    int no_exception = 0;
 
-    ret = io_getpartial(argc, argv, io, 1);
-    if (NIL_P(ret))
-        rb_eof_error();
+    rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
+
+    if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
+	no_exception = 1;
+
+    ret = io_getpartial(argc, argv, io, 1, no_exception);
+
+    if (NIL_P(ret)) {
+	if (no_exception)
+	    return Qnil;
+	else
+	    rb_eof_error();
+    }
     return ret;
 }
 
+static VALUE
+io_write_nonblock(VALUE io, VALUE str, int no_exception)
+{
+    rb_io_t *fptr;
+    long n;
+
+    if (!RB_TYPE_P(str, T_STRING))
+	str = rb_obj_as_string(str);
+
+    io = GetWriteIO(io);
+    GetOpenFile(io, fptr);
+    rb_io_check_writable(fptr);
+
+    if (io_fflush(fptr) < 0)
+        rb_sys_fail(0);
+
+    rb_io_set_nonblock(fptr);
+    n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
+
+    if (n == -1) {
+        if (errno == EWOULDBLOCK || errno == EAGAIN) {
+	    if (no_exception) {
+		return ID2SYM(rb_intern("wait_writable"));
+	    } else {
+		rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
+	    }
+	}
+        rb_sys_fail_path(fptr->pathv);
+    }
+
+    return LONG2FIX(n);
+}
+
 /*
  *  call-seq:
  *     ios.write_nonblock(string)   -> integer
+ *     ios.write_nonblock(string [, options])   -> integer
  *
  *  Writes the given string to <em>ios</em> using
  *  the write(2) system call after O_NONBLOCK is set for
@@ -2648,34 +2698,25 @@ io_read_nonblock(int argc, VALUE *argv, https://github.com/ruby/ruby/blob/trunk/io.c#L2698
  *  according to the kind of the IO object.
  *  In such cases, write_nonblock raises <code>Errno::EBADF</code>.
  *
+ *  By specifying `exception: false`, the options hash allows you to indicate
+ *  that write_nonblock should not raise an IO::WaitWritable exception, but
+ *  return the symbol :wait_writable instead.
+ *
  */
 
 static VALUE
-rb_io_write_nonblock(VALUE io, VALUE str)
+rb_io_write_nonblock(int argc, VALUE *argv, VALUE io)
 {
-    rb_io_t *fptr;
-    long n;
-
-    if (!RB_TYPE_P(str, T_STRING))
-	str = rb_obj_as_string(str);
-
-    io = GetWriteIO(io);
-    GetOpenFile(io, fptr);
-    rb_io_check_writable(fptr);
-
-    if (io_fflush(fptr) < 0)
-        rb_sys_fail(0);
+    VALUE str;
+    VALUE opts = Qnil;
+    int no_exceptions = 0;
 
-    rb_io_set_nonblock(fptr);
-    n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
+    rb_scan_args(argc, argv, "10:", &str, &opts);
 
-    if (n == -1) {
-        if (errno == EWOULDBLOCK || errno == EAGAIN)
-            rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
-        rb_sys_fail_path(fptr->pathv);
-    }
+    if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
+	no_exceptions = 1;
 
-    return LONG2FIX(n);
+    return io_write_nonblock(io, str, no_exceptions);
 }
 
 /*
@@ -10809,7 +10850,7 @@ argf_getpartial(int argc, VALUE *argv, V https://github.com/ruby/ruby/blob/trunk/io.c#L10850
 			 RUBY_METHOD_FUNC(0), Qnil, rb_eEOFError, (VALUE)0);
     }
     else {
-        tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock);
+        tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock, 0);
     }
     if (NIL_P(tmp)) {
         if (ARGF.next_p == -1) {
@@ -11851,7 +11892,7 @@ Init_IO(void) https://github.com/ruby/ruby/blob/trunk/io.c#L11892
     rb_define_method(rb_cIO, "readlines",  rb_io_readlines, -1);
 
     rb_define_method(rb_cIO, "read_nonblock",  io_read_nonblock, -1);
-    rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, 1);
+    rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, -1);
     rb_define_method(rb_cIO, "readpartial",  io_readpartial, -1);
     rb_define_method(rb_cIO, "read",  io_read, -1);
     rb_define_method(rb_cIO, "write", io_write_m, 1);
@@ -12056,4 +12097,5 @@ Init_IO(void) https://github.com/ruby/ruby/blob/trunk/io.c#L12097
 #ifdef SEEK_HOLE
     sym_HOLE = ID2SYM(rb_intern("HOLE"));
 #endif
+    sym_exception = ID2SYM(rb_intern("exception"));
 }
Index: ext/openssl/ossl_ssl.c
===================================================================
--- ext/openssl/ossl_ssl.c	(revision 42694)
+++ ext/openssl/ossl_ssl.c	(revision 42695)
@@ -103,6 +103,8 @@ static const char *ossl_ssl_attrs[] = { https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L103
 
 ID ID_callback_state;
 
+static VALUE sym_exception;
+
 /*
  * SSLContext class
  */
@@ -1373,10 +1375,16 @@ ossl_ssl_read_internal(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1375
 {
     SSL *ssl;
     int ilen, nread = 0;
+    int no_exception = 0;
     VALUE len, str;
     rb_io_t *fptr;
+    VALUE opts = Qnil;
+
+    rb_scan_args(argc, argv, "11:", &len, &str, &opts);
+
+    if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
+	no_exception = 1;
 
-    rb_scan_args(argc, argv, "11", &len, &str);
     ilen = NUM2INT(len);
     if(NIL_P(str)) str = rb_str_new(0, ilen);
     else{
@@ -1397,17 +1405,23 @@ ossl_ssl_read_internal(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1405
 	    case SSL_ERROR_NONE:
 		goto end;
 	    case SSL_ERROR_ZERO_RETURN:
+		if (no_exception) { return Qnil; }
 		rb_eof_error();
 	    case SSL_ERROR_WANT_WRITE:
+		if (no_exception) { return ID2SYM(rb_intern("wait_writable")); }
                 write_would_block(nonblock);
                 rb_io_wait_writable(FPTR_TO_FD(fptr));
                 continue;
 	    case SSL_ERROR_WANT_READ:
+		if (no_exception) { return ID2SYM(rb_intern("wait_readable")); }
                 read_would_block(nonblock);
                 rb_io_wait_readable(FPTR_TO_FD(fptr));
 		continue;
 	    case SSL_ERROR_SYSCALL:
-		if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
+		if(ERR_peek_error() == 0 && nread == 0) {
+		    if (no_exception) { return Qnil; }
+		    rb_eof_error();
+		}
 		rb_sys_fail(0);
 	    default:
 		ossl_raise(eSSLError, "SSL_read");
@@ -1445,9 +1459,11 @@ ossl_ssl_read(int argc, VALUE *argv, VAL https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1459
  * call-seq:
  *    ssl.sysread_nonblock(length) => string
  *    ssl.sysread_nonblock(length, buffer) => buffer
+ *    ssl.sysread_nonblock(length[, buffer [, opts]) => buffer
  *
  * A non-blocking version of #sysread.  Raises an SSLError if reading would
- * block.
+ * block.  If "exception: false" is passed, this method returns a symbol of
+ * :wait_writable, :wait_writable, or nil, rather than raising an exception.
  *
  * Reads +length+ bytes from the SSL connection.  If a pre-allocated +buffer+
  * is provided the data will be written into it.
@@ -1459,7 +1475,7 @@ ossl_ssl_read_nonblock(int argc, VALUE * https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1475
 }
 
 static VALUE
-ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock)
+ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock, int no_exception)
 {
     SSL *ssl;
     int nwrite = 0;
@@ -1476,10 +1492,12 @@ ossl_ssl_write_internal(VALUE self, VALU https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1492
 	    case SSL_ERROR_NONE:
 		goto end;
 	    case SSL_ERROR_WANT_WRITE:
+		if (no_exception) { return ID2SYM(rb_intern("wait_writable")); }
                 write_would_block(nonblock);
                 rb_io_wait_writable(FPTR_TO_FD(fptr));
                 continue;
 	    case SSL_ERROR_WANT_READ:
+		if (no_exception) { return ID2SYM(rb_intern("wait_readable")); }
                 read_would_block(nonblock);
                 rb_io_wait_readable(FPTR_TO_FD(fptr));
                 continue;
@@ -1509,7 +1527,7 @@ ossl_ssl_write_internal(VALUE self, VALU https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1527
 static VALUE
 ossl_ssl_write(VALUE self, VALUE str)
 {
-    return ossl_ssl_write_internal(self, str, 0);
+    return ossl_ssl_write_internal(self, str, 0, 0);
 }
 
 /*
@@ -1520,9 +1538,18 @@ ossl_ssl_write(VALUE self, VALUE str) https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L1538
  * SSLError if writing would block.
  */
 static VALUE
-ossl_ssl_write_nonblock(VALUE self, VALUE str)
+ossl_ssl_write_nonblock(int argc, VALUE *argv, VALUE self)
 {
-    return ossl_ssl_write_internal(self, str, 1);
+    VALUE str;
+    VALUE opts = Qnil;
+    int no_exception = 0;
+
+    rb_scan_args(argc, argv, "1:", &str, &opts);
+
+    if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
+	no_exception = 1;
+
+    return ossl_ssl_write_internal(self, str, 1, no_exception);
 }
 
 /*
@@ -2168,7 +2195,7 @@ Init_ossl_ssl() https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L2195
     rb_define_method(cSSLSocket, "sysread",    ossl_ssl_read, -1);
     rb_define_private_method(cSSLSocket, "sysread_nonblock",    ossl_ssl_read_nonblock, -1);
     rb_define_method(cSSLSocket, "syswrite",   ossl_ssl_write, 1);
-    rb_define_private_method(cSSLSocket, "syswrite_nonblock",    ossl_ssl_write_nonblock, 1);
+    rb_define_private_method(cSSLSocket, "syswrite_nonblock",    ossl_ssl_write_nonblock, -1);
     rb_define_method(cSSLSocket, "sysclose",   ossl_ssl_close, 0);
     rb_define_method(cSSLSocket, "cert",       ossl_ssl_get_cert, 0);
     rb_define_method(cSSLSocket, "peer_cert",  ossl_ssl_get_peer_cert, 0);
@@ -2239,4 +2266,6 @@ Init_ossl_ssl() https://github.com/ruby/ruby/blob/trunk/ext/openssl/ossl_ssl.c#L2266
     ossl_ssl_def_const(OP_PKCS1_CHECK_2);
     ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG);
     ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG);
+
+    sym_exception = ID2SYM(rb_intern("exception"));
 }
Index: ext/openssl/lib/openssl/buffering.rb
===================================================================
--- ext/openssl/lib/openssl/buffering.rb	(revision 42694)
+++ ext/openssl/lib/openssl/buffering.rb	(revision 42695)
@@ -161,7 +161,7 @@ module OpenSSL::Buffering https://github.com/ruby/ruby/blob/trunk/ext/openssl/lib/openssl/buffering.rb#L161
   # when the peer requests a new TLS/SSL handshake.  See openssl the FAQ for
   # more details.  http://www.openssl.org/support/faq.html
 
-  def read_nonblock(maxlen, buf=nil)
+  def read_nonblock(maxlen, buf=nil, exception: true)
     if maxlen == 0
       if buf
         buf.clear
@@ -171,7 +171,7 @@ module OpenSSL::Buffering https://github.com/ruby/ruby/blob/trunk/ext/openssl/lib/openssl/buffering.rb#L171
       end
     end
     if @rbuffer.empty?
-      return sysread_nonblock(maxlen, buf)
+      return sysread_nonblock(maxlen, buf, exception: exception)
     end
     ret = consume_rbuff(maxlen)
     if buf
@@ -370,9 +370,9 @@ module OpenSSL::Buffering https://github.com/ruby/ruby/blob/trunk/ext/openssl/lib/openssl/buffering.rb#L370
   # is when the peer requests a new TLS/SSL handshake.  See the openssl FAQ
   # for more details.  http://www.openssl.org/support/faq.html
 
-  def write_nonblock(s)
+  def write_nonblock(s, exception: true)
     flush
-    syswrite_nonblock(s)
+    syswrite_nonblock(s, exception: exception)
   end
 
   ##
Index: ext/stringio/stringio.c
===================================================================
--- ext/stringio/stringio.c	(revision 42694)
+++ ext/stringio/stringio.c	(revision 42695)
@@ -119,6 +119,8 @@ typedef char strio_flags_check[(STRIO_RE https://github.com/ruby/ruby/blob/trunk/ext/stringio/stringio.c#L119
 #define READABLE(strio) STRIO_MODE_SET_P(strio, READABLE)
 #define WRITABLE(strio) STRIO_MODE_SET_P(strio, WRITABLE)
 
+static VALUE sym_exception;
+
 static struct StringIO*
 readable(VALUE strio)
 {
@@ -1327,7 +1329,6 @@ strio_read(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/ext/stringio/stringio.c#L1329
  * call-seq:
  *   strio.sysread(integer[, outbuf])    -> string
  *   strio.readpartial(integer[, outbuf])    -> string
- *   strio.read_nonblock(integer[, outbuf])    -> string
  *
  * Similar to #read, but raises +EOFError+ at end of string instead of
  * returning +nil+, as well as IO#sysread does.
@@ -1342,8 +1343,50 @@ strio_sysread(int argc, VALUE *argv, VAL https://github.com/ruby/ruby/blob/trunk/ext/stringio/stringio.c#L1343
     return val;
 }
 
+/*
+ * call-seq:
+ *   strio.read_nonblock(integer[, outbuf [, opts]])    -> string
+ *
+ * Similar to #read, but raises +EOFError+ at end of string unless the
+ * +exception: false+ option is passed in.
+ */
+static VALUE
+strio_read_nonblock(int argc, VALUE *argv, VALUE self)
+{
+    VALUE opts = Qnil;
+    int no_exception = 0;
+
+    rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
+
+    if (!NIL_P(opts)) {
+	argc--;
+
+	if (Qfalse == rb_hash_aref(opts, sym_exception))
+	    no_exception = 1;
+    }
+
+    VALUE val = strio_read(argc, argv, self);
+    if (NIL_P(val)) {
+	if (no_exception)
+	    return Qnil;
+	else
+	    rb_eof_error();
+    }
+
+    return val;
+}
+
 #define strio_syswrite rb_io_write
 
+static VALUE
+strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self)
+{
+    VALUE str;
+
+    rb_scan_args(argc, argv, "10:", &str, NULL);
+    return strio_syswrite(self, str);
+}
+
 #define strio_isatty strio_false
 
 #define strio_pid strio_nil
@@ -1542,7 +1585,7 @@ Init_stringio() https://github.com/ruby/ruby/blob/trunk/ext/stringio/stringio.c#L1585
 	rb_define_method(mReadable, "readline", strio_readline, -1);
 	rb_define_method(mReadable, "sysread", strio_sysread, -1);
 	rb_define_method(mReadable, "readpartial", strio_sysread, -1);
-	rb_define_method(mReadable, "read_nonblock", strio_sysread, -1);
+	rb_define_method(mReadable, "read_nonblock", strio_read_nonblock, -1);
 	rb_include_module(StringIO, mReadable);
     }
     {
@@ -1552,7 +1595,9 @@ Init_stringio() https://github.com/ruby/ruby/blob/trunk/ext/stringio/stringio.c#L1595
 	rb_define_method(mWritable, "printf", strio_printf, -1);
 	rb_define_method(mWritable, "puts", strio_puts, -1);
 	rb_define_method(mWritable, "syswrite", strio_syswrite, 1);
-	rb_define_method(mWritable, "write_nonblock", strio_syswrite, 1);
+	rb_define_method(mWritable, "write_nonblock", strio_syswrite_nonblock, -1);
 	rb_include_module(StringIO, mWritable);
     }
+
+    sym_exception = ID2SYM(rb_intern("exception"));
 }
Index: test/ruby/test_io.rb
===================================================================
--- test/ruby/test_io.rb	(revision 42694)
+++ test/ruby/test_io.rb	(revision 42695)
@@ -1205,6 +1205,16 @@ class TestIO < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1205
     }
   end
 
+  def test_write_nonblock_simple_no_exceptions
+    skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
+    pipe(proc do |w|
+      w.write_nonblock('1', exception: false)
+      w.close
+    end, proc do |r|
+      assert_equal("1", r.read)
+    end)
+  end
+
   def test_read_nonblock_error
     return if !have_nonblock?
     skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
@@ -1215,6 +1225,41 @@ class TestIO < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1225
         assert_kind_of(IO::WaitReadable, $!)
       end
     }
+
+    with_pipe {|r, w|
+      begin
+        r.read_nonblock 4096, ""
+      rescue Errno::EWOULDBLOCK
+        assert_kind_of(IO::WaitReadable, $!)
+      end
+    }
+  end
+
+  def test_read_nonblock_no_exceptions
+    return if !have_nonblock?
+    skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
+    with_pipe {|r, w|
+      assert_equal :wait_readable, r.read_nonblock(4096, exception: false)
+      w.puts "HI!"
+      assert_equal "HI!\n", r.read_nonblock(4096, exception: false)
+      w.close
+      assert_equal nil, r.read_nonblock(4096, exception: false)
+    }
+  end
+
+  def test_read_nonblock_with_buffer_no_exceptions
+    return if !have_nonblock?
+    skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
+    with_pipe {|r, w|
+      assert_equal :wait_readable, r.read_nonblock(4096, "", exception: false)
+      w.puts "HI!"
+      buf = "buf"
+      value = r.read_nonblock(4096, buf, exception: false)
+      assert_equal value, "HI!\n"
+      assert buf.equal?(value)
+      w.close
+      assert_equal nil, r.read_nonblock(4096, "", exception: false)
+    }
   end
 
   def test_write_nonblock_error
@@ -1231,6 +1276,20 @@ class TestIO < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_io.rb#L1276
     }
   end
 
+  def test_write_nonblock_no_exceptions
+   (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]