Forum: Ruby-core [Feature #1081] add File::write() convenience method

Posted by Suraj Kurapati (Guest)
on 2009-01-31 21:47
(Received via mailing list)
Feature #1081: add File::write() convenience method
http://redmine.ruby-lang.org/issues/show/1081

Author: Suraj Kurapati
Status: Open, Priority: Normal
Category: core, Target version: 1.9.2

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

Currently, it is easier to read whole files than to write them:

  # reading a whole file --- less effort
  text = File::read('foo.txt')

  # writing a whole file --- more effort
  File::open('foo.txt', 'wb') {|f| f.write 'ruby!' }

This imbalance can be corrected by adding a File::write method,
such as the following, to the core Ruby API:

  class File
    def self.write path, data, mode = 'wb'
      open(path, mode) {|f| f.write data }
    end
  end

Thanks for your consideration.
Posted by Roger Pack (Guest)
on 2009-01-31 23:12
(Received via mailing list)
> Feature #1081: add File::write() convenience method

I don't mean to push too hard, but I would also really like this
function within Ruby stdlib.  Please?  I would be happy to help with a
patch for it or what not.
Thanks.
-=r
Posted by Yukihiro Matsumoto (Guest)
on 2009-02-02 07:28
(Received via mailing list)
Hi,

In message "Re: [ruby-core:21701] [Feature #1081] add File::write() 
convenience method"
    on Sun, 1 Feb 2009 05:46:57 +0900, Suraj Kurapati 
<redmine@ruby-lang.org> writes:

|Please add a File::write() convenience method to the core Ruby API.
|
|Currently, it is easier to read whole files than to write them:
|
|  # reading a whole file --- less effort
|  text = File::read('foo.txt')
|
|  # writing a whole file --- more effort
|  File::open('foo.txt', 'wb') {|f| f.write 'ruby!' }

open() has following API

  open(path, mode="r", mode=0, opthash=nil)

write() has

  IO#write(string)

What do you think proper API for combined File.open?

  File::write(path, string, mode, opt)

or

  File::write(string, path, mode, opt)

or whatever?  The latter would conflict with some in-house definition
of File::write.

              matz.
Posted by Kornelius Kalnbach (Guest)
on 2009-02-02 08:19
(Received via mailing list)
Yukihiro Matsumoto wrote:
> What do you think proper API for combined File.open?
> 
> File::write(path, string, mode, opt)
> 
> or
> 
> File::write(string, path, mode, opt)
we badly need keyword arguments.

[murphy]
Posted by Suraj Kurapati (Guest)
on 2009-02-03 05:09
(Received via mailing list)
Issue #1081 has been updated by Suraj Kurapati.


Hi,

Sorry for my late response.

Matz wrote:
> What do you think proper API for combined File.open?
> 
>   File::write(path, string, mode, opt)

I prefer this order of parameters because it feels natural:

  File::open('hello.txt', 'r').read()
  File::read('hello.txt')

  File::open('hello.txt', 'w').write('hello')
  File::write('hello.txt', 'hello')

In addition, the Facets library also perfers this order:

http://facets.rubyforge.org/doc/api/core/classes/File.html#M000241

> or
> 
>   File::write(string, path, mode, opt)
> 
> The latter would conflict with some in-house definition of File::write.

Then, to minimize disruption, let us avoid this latter order of 
parameters.

Thanks for your consideration.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Roger Pack (Guest)
on 2009-04-01 18:06
(Received via mailing list)
Issue #1081 has been updated by Roger Pack.


> What do you think proper API for combined File.open?
> 
>   File::write(path, string, mode, opt)

I also prefer this first way.
File.write('hello.txt', 'some stuff')

and default to mode 'wb' for all platforms
Thanks for looking into this.  It would be quite useful.

----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Suraj Kurapati (Guest)
on 2009-09-21 20:26
(Received via mailing list)
Issue #1081 has been updated by Suraj Kurapati.


To summarize Roger's comment, we prefer this API:

  File::write(path, string, mode='wb', opt={})

Thanks for your consideration.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by xiong ai (Guest)
on 2009-09-28 11:40
(Received via mailing list)
Issue #1081 has been updated by xiong ai.


File::write(path, string, mode='wb', opt={})
+1
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Roger Pack (Guest)
on 2009-11-23 21:32
(Received via mailing list)
Issue #1081 has been updated by Roger Pack.


Hmm.
On second thought perhaps on windows it should be

File::write(path, string, mode='w', opt={})

And there should be

File::binwrite(path, string, mode='wb', opt={})

for consistency with 1.9's existing File::read and File::binread

Thoughts?
-r

----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Suraj Kurapati (Guest)
on 2010-01-02 20:57
(Received via mailing list)
Issue #1081 has been updated by Suraj Kurapati.


That seems reasonable Roger.  I agree:

File::write(path, string, mode='w', opt={})
File::binwrite(path, string, mode='wb', opt={})
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Yusuke Endoh (Guest)
on 2010-02-28 10:18
(Received via mailing list)
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
Posted by Yusuke Endoh (Guest)
on 2010-03-03 18:48
(Received via mailing list)
Issue #1081 has been updated by Yusuke Endoh.


Hi,

Yusuke Endoh wrote:
> 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
>
*snip*
>
> I'll commit the patch if anyone says objection.


Sorry, I have misunderstood matz had already approved the feature in
[ruby-core:21732].  But I realized he just discussed API design.

I have not commit it yet.  Matz, may I commit my patch?

--
Yusuke Endoh <mame@tsg.ne.jp>
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Yukihiro Matsumoto (Guest)
on 2010-03-04 02:31
(Received via mailing list)
Hi,

In message "Re: [ruby-core:28450] [Feature #1081] add File::write() 
convenience method"
    on Thu, 4 Mar 2010 02:48:14 +0900, Yusuke Endoh 
<redmine@ruby-lang.org> writes:

|I have not commit it yet.  Matz, may I commit my patch?

Go ahead.

              matz.
Posted by Yusuke ENDOH (Guest)
on 2010-03-04 14:59
(Received via mailing list)
Hi,

2010/3/4 Yukihiro Matsumoto <matz@ruby-lang.org>:
> In message "Re: [ruby-core:28450] [Feature #1081] add File::write() convenience method"
>    on Thu, 4 Mar 2010 02:48:14 +0900, Yusuke Endoh <redmine@ruby-lang.org> writes:
>
> |I have not commit it yet.  Matz, may I commit my patch?
>
> Go ahead.

Thank you!  Done.
Posted by Yusuke Endoh (Guest)
on 2010-03-04 15:02
(Received via mailing list)
Issue #1081 has been updated by Yusuke Endoh.

Status changed from Open to Closed
% Done changed from 0 to 100

This issue was solved with changeset r26816.
Suraj, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.

----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Run Paint Run Run (Guest)
on 2010-03-05 15:24
(Received via mailing list)
Is it intended that the length of the leading nulls are not included
in the return value? I assumed the second line in the example below
would return 3.

  >> File.delete('/tmp/glark') #=> 1
  >> File.write('/tmp/glark','s',2) #=> 1
  >> File.read('/tmp/glark') #=> "\u0000\u0000s"
Posted by Yusuke ENDOH (Guest)
on 2010-03-05 16:03
(Received via mailing list)
Hi,

2010/3/5 Run Paint Run Run <runrun@runpaint.org>:
> Is it intended that the length of the leading nulls are not included
> in the return value? I assumed the second line in the example below
> would return 3.
>
>  >> File.delete('/tmp/glark') #=> 1
>  >> File.write('/tmp/glark','s',2) #=> 1
>  >> File.read('/tmp/glark') #=> "\u0000\u0000s"


Intended.  It currently returns the length actually written.  The
\u0000s are padded by seek, not write.

Consider the situation where there is /tmp/glark whose size is more
than 2:

 >> File.read('/tmp/glark') #=> "foo"
 >> File.write('/tmp/glark', "s", 2) #=> 1
 >> File.read('/tmp/glark') #=> "fos"

In this case, it is natural (for me) to return 1.

But I'm happy to change the spec if you guys want.
Posted by Run Paint Run Run (Guest)
on 2010-03-05 21:34
(Received via mailing list)
> \u0000s are padded by seek, not write.
OK, just wanted to check. As for #binwrite, I'm also assuming that, at
least on Linux, it's intentionally ignoring the offset, treating it
instead as merely a cue to append.

>> File.delete('/tmp/offset') #=> 1
>> File.write('/tmp/offset','ruby') #=> 4
>> File.write('/tmp/offset','ruby',2) #=> 4
>> File.size('/tmp/offset') #=> 6
Posted by Yusuke ENDOH (Guest)
on 2010-03-06 02:16
(Received via mailing list)
Hi,

2010/3/6 Run Paint Run Run <runrun@runpaint.org>:
>>> File.binwrite('/tmp/offset','ruby') #=> 4
>>> File.binwrite('/tmp/offset','ruby',2) #=> 4
>>> File.size('/tmp/offset') #=> 8

No, it is never intended :-(
Fixed.  Thanks.

# I had used assert instead of assert_equal in the test...
Posted by Run Paint Run Run (Guest)
on 2010-03-06 04:02
(Received via mailing list)
Teamwork. :-)

The only other inconsistency I found is how offsets are handled for
non-existent paths.

    >> File.delete('/tmp/offset') #=> 1
    >> File.binwrite('/tmp/offset','string',2)
    Errno::ENOENT: No such file or directory - /tmp/offset
  from (irb):6:in `binwrite'
  from (irb):6
  from /usr/local/bin/irb:12:in `<main>'
    >> File.write('/tmp/offset','string',2) #=> 6
    >> File.read('/tmp/offset') #=> "\u0000\u0000string"

     >> File.delete('/tmp/offset') #=> 1
     >> File.binwrite('/tmp/offset','string',-2)
     Errno::ENOENT: No such file or directory - /tmp/offset
  from (irb):14:in `binwrite'
  from (irb):14
  from /usr/local/bin/irb:12:in `<main>'
     >> File.write('/tmp/offset','string',-2)
     Errno::EINVAL: Invalid argument - /tmp/offset
  from (irb):16:in `write'
  from (irb):16
  from /usr/local/bin/irb:12:in `<main>'
Posted by Yusuke ENDOH (Guest)
on 2010-03-06 04:49
(Received via mailing list)
2010/3/6 Run Paint Run Run <runrun@runpaint.org>:
> The only other inconsistency I found is how offsets are handled for
> non-existent paths.

Grr, I hate IO.

In addition, I noticed we cannot specify permission with the current
File#binwrite.

I'll consider for some time.
Posted by Yusuke ENDOH (Guest)
on 2010-03-06 06:03
(Received via mailing list)
Hi,

2010/3/6 Yusuke ENDOH <mame@tsg.ne.jp>:
> 2010/3/6 Run Paint Run Run <runrun@runpaint.org>:
>> The only other inconsistency I found is how offsets are handled for
>> non-existent paths.
>
> Grr, I hate IO.
>
> In addition, I noticed we cannot specify permission with the current
> File#binwrite.
>
> I'll consider for some time.


I give up.  I have already reverted and deleted the two methods.

I wrote the patch because I thought closing the ticket encourages 1.9.2
release.
But it seems to take some time to make the feature stable, and I became
afraid that it may delay the release.  It is never the effect I 
expected.

I think refactoring io.c is needed to implement the feature.
open argument is easy to use, but difficult for me to implement :-(
Posted by Run Paint Run Run (Guest)
on 2010-03-06 15:58
(Received via mailing list)
> I give up.  I have already reverted and deleted the two methods.
>
> I wrote the patch because I thought closing the ticket encourages 1.9.2
> release.
> But it seems to take some time to make the feature stable, and I became
> afraid that it may delay the release.  It is never the effect I expected.
>
> I think refactoring io.c is needed to implement the feature.
> open argument is easy to use, but difficult for me to implement :-(

Why don't we just start simple? Add IO.write and IO.binwrite that take
exactly two arguments--a path and a string--and truncate the file and
write to it the string. That covers the common use case which inspired
this ticket, and allows the optional arguments to be added later
without breaking compatibility.
Posted by Run Paint Run Run (Guest)
on 2010-03-06 18:33
(Received via mailing list)
Issue #1081 has been updated by Run Paint Run Run.

File 0001-io.c-io_s_write-io_s_binwrite-Re-add-IO.write-binwri.patch 
added

For example, with the usual caveat that I don't speak C, the attached 
patch passes the following RubySpec: http://goo.gl/RcAW (the two methods 
are treated as aliases because I haven't looked at testing binmode under 
Linux). I suspect that if it was rewritten by somebody who knew what 
they were doing it would satisfy the original reporter and simplify the 
common idiom of "File.open('/tmp/glark','w'){|f| f << 'string'}". If 
more functionality is desired, IO.open can be used or another ticket can 
be opened.
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Nobuyoshi Nakada (nobu)
on 2010-03-06 19:45
(Received via mailing list)
Hi,

At Sun, 7 Mar 2010 02:32:56 +0900,
Run Paint Run Run wrote in [ruby-core:28536]:
> File 0001-io.c-io_s_write-io_s_binwrite-Re-add-IO.write-binwri.patch added

It's broken, and will cause segfault or similar.

+static VALUE
+rb_io_s_write(int argc, VALUE path, VALUE str, VALUE io)

+static VALUE
+rb_io_s_binwrite(int argc, VALUE path, VALUE str, VALUE io)

+    rb_define_singleton_method(rb_cIO, "write", rb_io_s_write, 2);
+    rb_define_singleton_method(rb_cIO, "binwrite", rb_io_s_binwrite, 
2);
Posted by Yusuke ENDOH (Guest)
on 2010-03-08 16:23
(Received via mailing list)
Hi,

2010/3/6 Run Paint Run Run <runrun@runpaint.org>:
> Why don't we just start simple?
Because there are already complex File.read/binread.
It is confusing to make File.write/binwrite inconsistent with them.


> That covers the common use case which inspired
> this ticket, and allows the optional arguments to be added later
> without breaking compatibility.

There is no reason to rush into 1.9.2.
Posted by Kazuo Ishii (Guest)
on 2010-03-08 17:17
(Received via mailing list)
2010/3/8, Yusuke ENDOH <mame@tsg.ne.jp>:
>>> I think refactoring io.c is needed to implement the feature.
>> without breaking compatibility.
>
> There is no reason to rush into 1.9.2.
>
> --
> Yusuke ENDOH <mame@tsg.ne.jp>
>
>


--
Kazuo Ishii, Ph.D.
Bioinformatics Specialist
Division of Hematology/Oncology,
Northwestern University Feinberg School of Medicine,
303 E. Superior Street, Lurie 5-129, Chicago, IL 60611, USA,
Phone; 1-312-503-1186
Intelligent BIO-IT International, freeparis2@gmail.com
Posted by Suraj Kurapati (Guest)
on 2010-03-15 02:42
(Received via mailing list)
Issue #1081 has been updated by Suraj Kurapati.


Hi,

Is this issue solved?  Or was the patch[1] removed from Ruby?

Sorry for asking these (perhaps self-evident) questions;
I really don't understand the discussion succeeding [1].

Thanks for your consideration.

[1]: http://redmine.ruby-lang.org/issues/show/1081#note-13
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Yusuke ENDOH (Guest)
on 2010-03-15 16:52
(Received via mailing list)
Hi,

2010/3/15 Suraj Kurapati <redmine@ruby-lang.org>:
> Is this issue solved? ?Or was the patch[1] removed from Ruby?

Removed.  [ruby-core:28530]

I thought it is difficult (for me) to make the feature stable by the
deadline.
I will not disagree with a patch that anyone writes, if it passes Run
Paint's corner cases.  [ruby-core:28517] [ruby-core:28528]
Posted by Roger Pack (Guest)
on 2010-04-28 20:43
(Received via mailing list)
Issue #1081 has been updated by Roger Pack.

File new.diff added

I was unable to reproduce the odd behavior observed previously by Run 
Paint Run.

Here is the original diff plus some test cases that cover the corner 
cases (they don't appear to fail--maybe something else has been fixed 
since then, allowing things to work right now?)
Maybe somebody can point out a failing test case to me?

Thanks.

 ./ruby  test/ruby/test_io.rb
Loaded suite test/ruby/test_io
Started
...........................................................................................
Finished in 0.687023 seconds.

91 tests, 358 assertions, 0 failures, 0 errors, 0 skips

Test run options: --seed 26858
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Nobuyoshi Nakada (nobu)
on 2010-04-29 05:22
(Received via mailing list)
Hi,

At Thu, 29 Apr 2010 03:42:57 +0900,
Roger Pack wrote in [ruby-core:29861]:
> Here is the original diff plus some test cases that cover the
> corner cases (they don't appear to fail--maybe something else
> has been fixed since then, allowing things to work right
> now?)
> Maybe somebody can point out a failing test case to me?

It's sorry that your tests have no meanings at all, except for
assert_raise.  You should use assert_equal instead of mere
assert.
Posted by Roger Pack (Guest)
on 2010-04-29 19:33
(Received via mailing list)
Issue #1081 has been updated by Roger Pack.

File latest.diff added

Sorry for the poor tests.
Fixing the tests revealed that there were some bugs in binwrite.

The attached (new) patch fixes the tests and code.  The tests pass on 
windows and linux (and I think are accurate).
Feel free to refactor it as desired.

(as a note, windows currently fails some other tests in test_io.rb 
http://gist.github.com/383867).

Thanks.
-rp
----------------------------------------
http://redmine.ruby-lang.org/issues/show/1081
Posted by Roger Pack (Guest)
on 2010-11-01 15:37
(Received via mailing list)
Issue #1081 has been updated by Roger Pack.


Any chance of getting this committed at all? (File#write)?
Thanks!
Posted by Benoit Daloze (Guest)
on 2010-11-01 23:28
(Received via mailing list)
On 1 November 2010 15:37, Roger Pack <redmine@ruby-lang.org> wrote:
> Issue #1081 has been updated by Roger Pack.
>
>
> Any chance of getting this committed at all? (File#write)?
> Thanks!

I want to show my wish to back up this, it is definitely worth it.

Is there any issue left ?
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.