[#28015] RCR: RUBY_VERSION_INT — Roger Pack <rogerdpack2@...>

Situation:

14 messages 2010/02/02

[#28113] [Bug #2723] $: length affects re-require time of already loaded files — Greg Hazel <redmine@...>

Bug #2723: $: length affects re-require time of already loaded files

16 messages 2010/02/08

[#28151] [Bug #2739] ruby 1.8.7 built with pthreads hangs under some circumstances — Joel Ebel <redmine@...>

Bug #2739: ruby 1.8.7 built with pthreads hangs under some circumstances

31 messages 2010/02/11

[#28188] [Bug #2750] build fails on win32/MinGW: "executable host ruby is required." even when --with-baseruby is used — Christian Bodt <redmine@...>

Bug #2750: build fails on win32/MinGW: "executable host ruby is required." even when --with-baseruby is used

9 messages 2010/02/16

[#28206] Is Math module a wrapper of libm? — Yusuke ENDOH <mame@...>

Hi matz --

23 messages 2010/02/18
[#28212] Re: Is Math module a wrapper of libm? — Yukihiro Matsumoto <matz@...> 2010/02/18

Hi,

[#28219] Re: Is Math module a wrapper of libm? — Yusuke ENDOH <mame@...> 2010/02/18

Hi,

[#28225] Re: Is Math module a wrapper of libm? — Marc-Andre Lafortune <ruby-core-mailing-list@...> 2010/02/18

Hi,

[#28233] Re: Is Math module a wrapper of libm? — Kenta Murata <muraken@...> 2010/02/18

Hi,

[#28265] Re: Is Math module a wrapper of libm? — Marc-Andre Lafortune <ruby-core-mailing-list@...> 2010/02/20

Hi,

[#28286] Re: Is Math module a wrapper of libm? — Kenta Murata <muraken@...> 2010/02/21

Hi

[#28291] Re: Is Math module a wrapper of libm? — Marc-Andre Lafortune <ruby-core-mailing-list@...> 2010/02/22

Hi!

[#28235] [Feature #2759] Regexp /g and /G options — Michael Fellinger <redmine@...>

Feature #2759: Regexp /g and /G options

35 messages 2010/02/18

[#28329] [ANN] Ruby 1.9.2dev has passed RubySpec! — Yusuke ENDOH <mame@...>

Hi,

12 messages 2010/02/24

[#28355] [ANN] Toward rich diversity of Ruby development. — Urabe Shyouhei <shyouhei@...>

A short announcement: thanks to some helps of GitHub people, I now have

12 messages 2010/02/27

[#28365] Indentifying key MRI-on-Windows issues — Jon <jon.forums@...>

In an effort to begin summarizing key MRI-on-Windows open issues I'm starting this thread in hopes that those interested will respond with details on the key MRI issues they feel need resolution for Windows users.

11 messages 2010/02/27
[#28690] Re: Indentifying key MRI-on-Windows issues — Roger Pack <rogerdpack2@...> 2010/03/16

> My key concern is http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-=

[ruby-core:28371] [Feature #1081] add File::write() convenience method

From: Yusuke Endoh <redmine@...>
Date: 2010-02-28 09:17:44 UTC
List: ruby-core #28371
Issue #1081 has been updated by Yusuke Endoh.


Hi,

> Please add a File::write() convenience method to the core Ruby API.

I have written a patch.  The API is similar to File.read except string:

  File.write(path, string[, offset])            #=> length written
  File.write(path, string[, offset], open_args) #=> length written

If offset is given, the file is not truncated.  Otherwise, truncated.

  $ ./ruby -e 'File.write("foo", "foo\nbar\nbaz\n")' && cat foo
  foo
  bar
  baz

  $ ./ruby -e 'File.write("foo", "BAR", 4)' && cat foo
  foo
  BAR
  baz

  $ ./ruby -e 'File.write("foo", "FOO\n")' && cat foo
  FOO

  $ ./ruby -e 'File.write("foo", "あいうえお", mode: "w", encoding: "EUC-JP")' && nkf -Ew foo
  あいうえお

I'll commit the patch if anyone says objection.


diff --git a/io.c b/io.c
index 8026ea3..08d4988 100644
--- a/io.c
+++ b/io.c
@@ -7701,7 +7701,7 @@ struct foreach_arg {
 };
 
 static void
-open_key_args(int argc, VALUE *argv, struct foreach_arg *arg)
+open_key_args_with_opt(int argc, VALUE *argv, struct foreach_arg *arg, int mandatory_argc, int default_mode, int default_perm)
 {
     VALUE opt, v;
 
@@ -7709,9 +7709,9 @@ open_key_args(int argc, VALUE *argv, struct foreach_arg *arg)
     arg->io = 0;
     arg->argc = argc - 1;
     arg->argv = argv + 1;
-    if (argc == 1) {
+    if (argc == mandatory_argc) {
       no_key:
-	arg->io = rb_io_open(argv[0], INT2NUM(O_RDONLY), INT2FIX(0666), Qnil);
+	arg->io = rb_io_open(argv[0], INT2NUM(default_mode), INT2FIX(default_perm), Qnil);
 	return;
     }
     opt = pop_last_hash(&arg->argc, arg->argv);
@@ -7736,9 +7736,23 @@ open_key_args(int argc, VALUE *argv, struct foreach_arg *arg)
 	rb_ary_clear(args);	/* prevent from GC */
 	return;
     }
+    if (default_mode != O_RDONLY && NIL_P(rb_hash_aref(opt, sym_mode))) {
+	opt = rb_hash_dup(opt);
+	rb_hash_aset(opt, sym_mode, INT2NUM(default_mode));
+    }
+    if (default_perm != 0666 && NIL_P(rb_hash_aref(opt, sym_perm))) {
+	opt = rb_hash_dup(opt);
+	rb_hash_aset(opt, sym_perm, INT2FIX(default_perm));
+    }
     arg->io = rb_io_open(argv[0], Qnil, Qnil, opt);
 }
 
+static void
+open_key_args(int argc, VALUE *argv, struct foreach_arg *arg)
+{
+    open_key_args_with_opt(argc, argv, arg, 1, O_RDONLY, 0666);
+}
+
 static VALUE
 io_s_foreach(struct foreach_arg *arg)
 {
@@ -7826,6 +7840,16 @@ io_s_read(struct foreach_arg *arg)
     return io_read(arg->argc, arg->argv, arg->io);
 }
 
+struct write_arg {
+    VALUE io, str;
+};
+
+static VALUE
+io_s_write(struct write_arg *arg)
+{
+    return io_write(arg->io, arg->str, 0);
+}
+
 struct seek_arg {
     VALUE io;
     VALUE offset;
@@ -7833,7 +7857,7 @@ struct seek_arg {
 };
 
 static VALUE
-seek_before_read(struct seek_arg *arg)
+seek_before_access(struct seek_arg *arg)
 {
     rb_io_binmode(arg->io);
     return rb_io_seek(arg->io, arg->offset, arg->mode);
@@ -7844,7 +7868,7 @@ seek_before_read(struct seek_arg *arg)
  *     IO.read(name, [length [, offset]] )   => string
  *     IO.read(name, [length [, offset]], open_args)   => string
  *
- *  Opens the file, optionally seeks to the given offset, then returns
+ *  Opens the file, optionally seeks to the given <i>offset</i>, then returns
  *  <i>length</i> bytes (defaulting to the rest of the file).
  *  <code>read</code> ensures the file is closed before returning.
  *
@@ -7886,7 +7910,7 @@ rb_io_s_read(int argc, VALUE *argv, VALUE io)
 	sarg.io = arg.io;
 	sarg.offset = offset;
 	sarg.mode = SEEK_SET;
-	rb_protect((VALUE (*)(VALUE))seek_before_read, (VALUE)&sarg, &state);
+	rb_protect((VALUE (*)(VALUE))seek_before_access, (VALUE)&sarg, &state);
 	if (state) {
 	    rb_io_close(arg.io);
 	    rb_jump_tag(state);
@@ -7900,9 +7924,9 @@ rb_io_s_read(int argc, VALUE *argv, VALUE io)
  *  call-seq:
  *     IO.binread(name, [length [, offset]] )   => string
  *
- *  Opens the file, optionally seeks to the given offset, then returns
+ *  Opens the file, optionally seeks to the given <i>offset</i>, then returns
  *  <i>length</i> bytes (defaulting to the rest of the file).
- *  <code>read</code> ensures the file is closed before returning.
+ *  <code>binread</code> ensures the file is closed before returning.
  *  The open mode would be "rb:ASCII-8BIT".
  *
  *     IO.binread("testfile")           #=> "This is line one\nThis is line two\nThis is line three\nAnd so on...\n"
@@ -7928,6 +7952,117 @@ rb_io_s_binread(int argc, VALUE *argv, VALUE io)
     return rb_ensure(io_s_read, (VALUE)&arg, rb_io_close, arg.io);
 }
 
+/*
+ *  call-seq:
+ *     IO.write(name, string, [offset] )   => fixnum
+ *     IO.write(name, string, [offset], open_args )   => fixnum
+ *
+ *  Opens the file, optionally seeks to the given <i>offset</i>, writes
+ *  <i>string</i>, then returns the length written.
+ *  <code>write</code> ensures the file is closed before returning.
+ *  If <i>offset</i> is not given, the file is truncated.  Otherwise,
+ *  it is not truncated.
+ *
+ *  If the last argument is a hash, it specifies option for internal
+ *  open().  The key would be the following.  open_args: is exclusive
+ *  to others.
+ *
+ *   encoding: string or encoding
+ *
+ *    specifies encoding of the read string.  encoding will be ignored
+ *    if length is specified.
+ *
+ *   mode: string
+ *
+ *    specifies mode argument for open().  it should start with "w" or "a" or "r+"
+ *    otherwise it would cause error.
+ *
+ *   perm: fixnum
+ *
+ *    specifies perm argument for open().
+ *
+ *   open_args: array of strings
+ *
+ *    specifies arguments for open() as an array.
+ *
+ *     IO.write("testfile", "0123456789")      #=> "0123456789"
+ *     IO.write("testfile", "0123456789", 20)  #=> "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
+ */
+
+static VALUE
+rb_io_s_write(int argc, VALUE *argv, VALUE io)
+{
+    VALUE offset;
+    struct foreach_arg arg;
+    struct write_arg warg;
+    int mode = O_WRONLY | O_CREAT, mandatory_argc;
+
+    rb_scan_args(argc, argv, "22", NULL, &warg.str, &offset, NULL);
+    if (!NIL_P(offset) && FIXNUM_P(offset)) {
+	mandatory_argc = 3;
+    }
+    else {
+	mode |= O_TRUNC;
+	mandatory_argc = 2;
+    }
+    open_key_args_with_opt(argc, argv, &arg, mandatory_argc, mode, 0666);
+    if (NIL_P(arg.io)) return Qnil;
+    if (!NIL_P(offset) && FIXNUM_P(offset)) {
+	struct seek_arg sarg;
+	int state = 0;
+	sarg.io = arg.io;
+	sarg.offset = offset;
+	sarg.mode = SEEK_SET;
+	rb_protect((VALUE (*)(VALUE))seek_before_access, (VALUE)&sarg, &state);
+	if (state) {
+	    rb_io_close(arg.io);
+	    rb_jump_tag(state);
+	}
+	if (arg.argc == 2) arg.argc = 1;
+    }
+    warg.io = arg.io;
+    return rb_ensure(io_s_write, (VALUE)&warg, rb_io_close, arg.io);
+}
+
+/*
+ *  call-seq:
+ *     IO.binwrite(name, string, [offset] )   => fixnum
+ *
+ *  Opens the file, optionally seeks to the given <i>offset</i>, write
+ *  <i>string</i> then returns the length written.
+ *  <code>binwrite</code> ensures the file is closed before returning.
+ *  The open mode would be "wb:ASCII-8BIT".
+ *  If <i>offset</i> is not given, the file is truncated.  Otherwise,
+ *  it is not truncated.
+ *
+ *     IO.binwrite("testfile", "0123456789")      #=> "0123456789"
+ *     IO.binwrite("testfile", "0123456789", 20)  #=> "This is line one\nThi0123456789two\nThis is line three\nAnd so on...\n"
+ */
+
+static VALUE
+rb_io_s_binwrite(int argc, VALUE *argv, VALUE io)
+{
+    VALUE offset;
+    const char *mode;
+    struct write_arg warg;
+
+    rb_scan_args(argc, argv, "21", NULL, &warg.str, &offset);
+    if (!NIL_P(offset)) {
+	NUM2OFFT(offset);
+	mode = "ab:ASCII-8BIT";
+    }
+    else {
+	mode = "wb:ASCII-8BIT";
+    }
+    FilePathValue(argv[0]);
+    warg.io = rb_io_open(argv[0], rb_str_new_cstr(mode), Qnil, Qnil);
+    if (NIL_P(warg.io)) return Qnil;
+    if (!NIL_P(offset)) {
+	rb_io_seek(warg.io, offset, SEEK_SET);
+    }
+    return rb_ensure(io_s_write, (VALUE)&warg, rb_io_close, warg.io);
+}
+
 struct copy_stream_struct {
     VALUE src;
     VALUE dst;
@@ -9731,6 +9866,8 @@ Init_IO(void)
     rb_define_singleton_method(rb_cIO, "readlines", rb_io_s_readlines, -1);
     rb_define_singleton_method(rb_cIO, "read", rb_io_s_read, -1);
     rb_define_singleton_method(rb_cIO, "binread", rb_io_s_binread, -1);
+    rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, -1);
+    rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, -1);
     rb_define_singleton_method(rb_cIO, "select", rb_f_select, -1);
     rb_define_singleton_method(rb_cIO, "pipe", rb_io_s_pipe, -1);
     rb_define_singleton_method(rb_cIO, "try_convert", rb_io_s_try_convert, 1);
diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb
index 5fc3b13..6ea128a 100644
--- a/test/ruby/test_io.rb
+++ b/test/ruby/test_io.rb
@@ -1512,4 +1512,34 @@ End
     t.close
     assert_raise(IOError) {t.binmode}
   end
+
+  def test_s_write
+    t = Tempfile.new("foo")
+    path = t.path
+    t.close(false)
+    File.write(path, "foo\nbar\nbaz")
+    assert("foo\nbar\nbaz", File.read(path))
+    File.write(path, "FOO", 0)
+    assert("FOO\nbar\nbaz", File.read(path))
+    File.write(path, "BAR")
+    assert("BAR", File.read(path))
+    File.write(path, "\u{3042}", mode: "w", encoding: "EUC-JP")
+    assert("\u{3042}".encode("EUC-JP"), File.read(path, encoding: "EUC-JP"))
+    t.unlink
+  end
+
+  def test_s_binwrite
+    t = Tempfile.new("foo")
+    path = t.path
+    t.close(false)
+    File.binwrite(path, "foo\nbar\nbaz")
+    assert("foo\nbar\nbaz", File.read(path))
+    File.binwrite(path, "FOO", 0)
+    assert("FOO\nbar\nbaz", File.read(path))
+    File.binwrite(path, "BAR")
+    assert("BAR", File.read(path))
+    File.binwrite(path, "\u{3042}")
+    assert("\u{3042}", File.read(path, encoding: "EUC-JP"))
+    t.unlink
+  end
 end

-- 
Yusuke Endoh <mame@tsg.ne.jp>
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081

----------------------------------------
http://redmine.ruby-lang.org

In This Thread