From a4f0e5141ad384fb86960f35edf5c0717c465483 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Fri, 24 Nov 2023 13:44:08 +1300 Subject: [PATCH] Add support for passing a block to `IO#readlines` and `IO.readlines`. --- io.c | 19 ++++++++++++++----- spec/ruby/core/io/readlines_spec.rb | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/io.c b/io.c index 590e8d11d7..ca5e27c41f 100644 --- a/io.c +++ b/io.c @@ -4472,15 +4472,24 @@ rb_io_readlines(int argc, VALUE *argv, VALUE io) static VALUE io_readlines(const struct getline_arg *arg, VALUE io) { - VALUE line, ary; + VALUE line; if (arg->limit == 0) rb_raise(rb_eArgError, "invalid limit: 0 for readlines"); - ary = rb_ary_new(); - while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) { - rb_ary_push(ary, line); + + // If a block is provided, yield lines. + if (rb_block_given_p()) { + while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) { + rb_yield(line); + } + return Qnil; + } else { + VALUE ary = rb_ary_new(); + while (!NIL_P(line = rb_io_getline_1(arg->rs, arg->limit, arg->chomp, io))) { + rb_ary_push(ary, line); + } + return ary; } - return ary; } /* diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb index 3a6ff3d0f3..2cf930746c 100644 --- a/spec/ruby/core/io/readlines_spec.rb +++ b/spec/ruby/core/io/readlines_spec.rb @@ -20,6 +20,16 @@ describe "IO#readlines" do -> { @io.readlines }.should raise_error(IOError) end + ruby_version_is "3.3" do + describe "when invoked with a block" do + it "yields each line to the block" do + lines = [] + @io.readlines { |line| lines << line } + lines.should == IOSpecs.lines + end + end + end + describe "when passed no arguments" do before :each do suppress_warning {@sep, $/ = $/, " "} @@ -214,6 +224,14 @@ describe "IO.readlines" do IO.readlines(cmd) }.should complain(/IO process creation with a leading '\|'/) end + + describe "when invoked with a block" do + it "yields each line to the block" do + lines = [] + IO.readlines(@name) { |line| lines << line } + lines.should == IOSpecs.lines + end + end end it_behaves_like :io_readlines, :readlines