From 6d6fdf947c8c0ce0d562c42d7daad12330c76499 Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Tue, 7 Aug 2012 00:08:22 +0900
Subject: [PATCH 01/10] string.c: change String#bytes to return array

---
 string.c |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/string.c b/string.c
index 26463b9..db26ebe 100644
--- a/string.c
+++ b/string.c
@@ -6238,6 +6238,17 @@ struct tr {
     return str;
 }
 
+static VALUE
+rb_str_bytes(VALUE str)
+{
+    long i;
+    VALUE ary = rb_ary_new();
+
+    for (i=0; i<RSTRING_LEN(str); i++) {
+	rb_ary_push(ary, INT2FIX(RSTRING_PTR(str)[i] & 0xff));
+    }
+    return ary;
+}
 
 /*
  *  call-seq:
@@ -7916,7 +7927,7 @@ struct tr {
     rb_define_method(rb_cString, "oct", rb_str_oct, 0);
     rb_define_method(rb_cString, "split", rb_str_split_m, -1);
     rb_define_method(rb_cString, "lines", rb_str_each_line, -1);
-    rb_define_method(rb_cString, "bytes", rb_str_each_byte, 0);
+    rb_define_method(rb_cString, "bytes", rb_str_bytes, 0);
     rb_define_method(rb_cString, "chars", rb_str_each_char, 0);
     rb_define_method(rb_cString, "codepoints", rb_str_each_codepoint, 0);
     rb_define_method(rb_cString, "reverse", rb_str_reverse, 0);
-- 
1.7.10


From 800b65798b625644621e473d544b897e25e1dc6e Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Tue, 7 Aug 2012 21:36:05 +0900
Subject: [PATCH 02/10] Refactor rb_str_each_byte and rb_str_bytes

Add test
---
 string.c                 |   39 ++++++++++++++++++++++++++++-----------
 test/ruby/test_string.rb |   12 ++++++++++++
 2 files changed, 40 insertions(+), 11 deletions(-)

diff --git a/string.c b/string.c
index db26ebe..971286c 100644
--- a/string.c
+++ b/string.c
@@ -6227,27 +6227,44 @@ struct tr {
  */
 
 static VALUE
-rb_str_each_byte(VALUE str)
+rb_str_enumerate_bytes(VALUE str, VALUE return_enumerator_p)
 {
     long i;
+    VALUE ary, yieldp;
+
+    if (return_enumerator_p) {
+	RETURN_ENUMERATOR(str, 0, 0);
+    }
+
+    if (rb_block_given_p()) {
+	yieldp = Qtrue;
+    }
+    else {
+	yieldp = Qfalse;
+	ary = rb_ary_new2(RSTRING_LEN(str));
+    }
 
-    RETURN_ENUMERATOR(str, 0, 0);
     for (i=0; i<RSTRING_LEN(str); i++) {
-	rb_yield(INT2FIX(RSTRING_PTR(str)[i] & 0xff));
+	if (yieldp) {
+	    rb_yield(INT2FIX(RSTRING_PTR(str)[i] & 0xff));
+	}
+	else {
+	    rb_ary_push(ary, INT2FIX(RSTRING_PTR(str)[i] & 0xff));
+	}
     }
-    return str;
+    return ary;
 }
 
 static VALUE
-rb_str_bytes(VALUE str)
+rb_str_each_byte(VALUE str)
 {
-    long i;
-    VALUE ary = rb_ary_new();
+    return rb_str_enumerate_bytes(str, Qtrue);
+}
 
-    for (i=0; i<RSTRING_LEN(str); i++) {
-	rb_ary_push(ary, INT2FIX(RSTRING_PTR(str)[i] & 0xff));
-    }
-    return ary;
+static VALUE
+rb_str_bytes(VALUE str)
+{
+    return rb_str_enumerate_bytes(str, Qfalse);
 }
 
 /*
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 47f349c..a3a3511 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -625,6 +625,18 @@ def test_each_byte
     assert_equal(65, res[0])
     assert_equal(66, res[1])
     assert_equal(67, res[2])
+
+    assert_equal 65, S("ABC").each_byte.next
+  end
+
+  def test_bytes
+    res = []
+    S("ABC").bytes {|x| res << x }
+    assert_equal(65, res[0])
+    assert_equal(66, res[1])
+    assert_equal(67, res[2])
+
+    assert_equal [65, 66, 67], S("ABC").bytes
   end
 
   def test_each_line
-- 
1.7.10


From 7c5996572b858b6d74a7d6abc3c5f325e757a7b0 Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Wed, 8 Aug 2012 00:18:39 +0900
Subject: [PATCH 03/10] Fixed return values

---
 string.c                 |    7 ++++++-
 test/ruby/test_string.rb |    6 ++++--
 2 files changed, 10 insertions(+), 3 deletions(-)

diff --git a/string.c b/string.c
index 971286c..1a92147 100644
--- a/string.c
+++ b/string.c
@@ -6252,7 +6252,12 @@ struct tr {
 	    rb_ary_push(ary, INT2FIX(RSTRING_PTR(str)[i] & 0xff));
 	}
     }
-    return ary;
+    if (yieldp) {
+	return str;
+    }
+    else {
+	return ary;
+    }
 }
 
 static VALUE
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index a3a3511..a269c0c 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -621,7 +621,8 @@ def test_each
 
   def test_each_byte
     res = []
-    S("ABC").each_byte {|x| res << x }
+    s = S("ABC")
+    assert_equal s.object_id, s.each_byte {|x| res << x }.object_id
     assert_equal(65, res[0])
     assert_equal(66, res[1])
     assert_equal(67, res[2])
@@ -631,7 +632,8 @@ def test_each_byte
 
   def test_bytes
     res = []
-    S("ABC").bytes {|x| res << x }
+    s = S("ABC")
+    assert_equal s.object_id, s.bytes {|x| res << x }.object_id
     assert_equal(65, res[0])
     assert_equal(66, res[1])
     assert_equal(67, res[2])
-- 
1.7.10


From a3ef427ff74d9b128d9b852a8bf69f97c3063801 Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Wed, 8 Aug 2012 11:01:03 +0900
Subject: [PATCH 04/10] Change #chars to return array

---
 string.c                 |   50 ++++++++++++++++++++++++++++++++++++++++------
 test/ruby/test_string.rb |   22 ++++++++++++++++++++
 2 files changed, 66 insertions(+), 6 deletions(-)

diff --git a/string.c b/string.c
index 1a92147..3a40857 100644
--- a/string.c
+++ b/string.c
@@ -6291,14 +6291,25 @@ struct tr {
  */
 
 static VALUE
-rb_str_each_char(VALUE str)
+rb_str_enumerate_chars(VALUE str, VALUE return_enumerator_p)
 {
     VALUE orig = str;
     long i, len, n;
     const char *ptr;
     rb_encoding *enc;
+    VALUE ary, yieldp;
 
-    RETURN_ENUMERATOR(str, 0, 0);
+    if (return_enumerator_p) {
+	RETURN_ENUMERATOR(str, 0, 0);
+    }
+
+    if (rb_block_given_p()) {
+	yieldp = Qtrue;
+    }
+    else {
+	yieldp = Qfalse;
+	ary = rb_ary_new();
+    }
     str = rb_str_new4(str);
     ptr = RSTRING_PTR(str);
     len = RSTRING_LEN(str);
@@ -6308,16 +6319,43 @@ struct tr {
       case ENC_CODERANGE_7BIT:
 	for (i = 0; i < len; i += n) {
 	    n = rb_enc_fast_mbclen(ptr + i, ptr + len, enc);
-	    rb_yield(rb_str_subseq(str, i, n));
+	    if (yieldp) {
+		rb_yield(rb_str_subseq(str, i, n));
+	    }
+	    else {
+		rb_ary_push(ary, rb_str_subseq(str, i, n));
+	    }
 	}
 	break;
       default:
 	for (i = 0; i < len; i += n) {
 	    n = rb_enc_mbclen(ptr + i, ptr + len, enc);
-	    rb_yield(rb_str_subseq(str, i, n));
+	    if (yieldp) {
+		rb_yield(rb_str_subseq(str, i, n));
+	    }
+	    else {
+		rb_ary_push(ary, rb_str_subseq(str, i, n));
+	    }
 	}
     }
-    return orig;
+    if (yieldp) {
+	return orig;
+    }
+    else {
+	return ary;
+    }
+}
+
+static VALUE
+rb_str_each_char(VALUE str)
+{
+    return rb_str_enumerate_chars(str, Qtrue);
+}
+
+static VALUE
+rb_str_chars(VALUE str)
+{
+    return rb_str_enumerate_chars(str, Qfalse);
 }
 
 /*
@@ -7950,7 +7988,7 @@ struct tr {
     rb_define_method(rb_cString, "split", rb_str_split_m, -1);
     rb_define_method(rb_cString, "lines", rb_str_each_line, -1);
     rb_define_method(rb_cString, "bytes", rb_str_bytes, 0);
-    rb_define_method(rb_cString, "chars", rb_str_each_char, 0);
+    rb_define_method(rb_cString, "chars", rb_str_chars, 0);
     rb_define_method(rb_cString, "codepoints", rb_str_each_codepoint, 0);
     rb_define_method(rb_cString, "reverse", rb_str_reverse, 0);
     rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0);
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index a269c0c..f263edc 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -641,6 +641,28 @@ def test_bytes
     assert_equal [65, 66, 67], S("ABC").bytes
   end
 
+  def test_each_char
+    res = []
+    s = S("ABC")
+    assert_equal s.object_id, s.each_char {|x| res << x }.object_id
+    assert_equal("A", res[0])
+    assert_equal("B", res[1])
+    assert_equal("C", res[2])
+
+    assert_equal "A", S("ABC").each_char.next
+  end
+
+  def test_chars
+    res = []
+    s = S("ABC")
+    assert_equal s.object_id, s.chars {|x| res << x }.object_id
+    assert_equal("A", res[0])
+    assert_equal("B", res[1])
+    assert_equal("C", res[2])
+
+    assert_equal ["A", "B", "C"], S("ABC").chars
+  end
+
   def test_each_line
     save = $/
     $/ = "\n"
-- 
1.7.10


From afcff52b2dec6d784720133ff1ac96316d756339 Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Thu, 9 Aug 2012 11:59:53 +0900
Subject: [PATCH 05/10] Changed #codepoints to return array

---
 string.c                 |   72 ++++++++++++++++++++++++++++++++++------------
 test/ruby/test_string.rb |   28 ++++++++++++++++++
 2 files changed, 82 insertions(+), 18 deletions(-)

diff --git a/string.c b/string.c
index 3a40857..5d721a3 100644
--- a/string.c
+++ b/string.c
@@ -6358,6 +6358,53 @@ struct tr {
     return rb_str_enumerate_chars(str, Qfalse);
 }
 
+static VALUE
+rb_str_enumerate_codepoints(VALUE str, VALUE return_enumerator_p)
+{
+    VALUE orig = str;
+    int n;
+    unsigned int c;
+    const char *ptr, *end;
+    rb_encoding *enc;
+    VALUE ary, yieldp;
+
+    if (single_byte_optimizable(str))
+	return rb_str_enumerate_bytes(str, return_enumerator_p);
+
+    if (return_enumerator_p) {
+	RETURN_ENUMERATOR(str, 0, 0);
+    }
+
+    if (rb_block_given_p()) {
+	yieldp = Qtrue;
+    }
+    else {
+	yieldp = Qfalse;
+	ary = rb_ary_new();
+    }
+
+    str = rb_str_new4(str);
+    ptr = RSTRING_PTR(str);
+    end = RSTRING_END(str);
+    enc = STR_ENC_GET(str);
+    while (ptr < end) {
+	c = rb_enc_codepoint_len(ptr, end, &n, enc);
+	if (yieldp) {
+	    rb_yield(UINT2NUM(c));
+	}
+	else {
+	    rb_ary_push(ary, UINT2NUM(c));
+	}
+	ptr += n;
+    }
+    if (yieldp) {
+	return orig;
+    }
+    else {
+	return ary;
+    }
+}
+
 /*
  *  call-seq:
  *     str.codepoints {|integer| block }        -> str
@@ -6382,24 +6429,13 @@ struct tr {
 static VALUE
 rb_str_each_codepoint(VALUE str)
 {
-    VALUE orig = str;
-    int n;
-    unsigned int c;
-    const char *ptr, *end;
-    rb_encoding *enc;
+    return rb_str_enumerate_codepoints(str, Qtrue);
+}
 
-    if (single_byte_optimizable(str)) return rb_str_each_byte(str);
-    RETURN_ENUMERATOR(str, 0, 0);
-    str = rb_str_new4(str);
-    ptr = RSTRING_PTR(str);
-    end = RSTRING_END(str);
-    enc = STR_ENC_GET(str);
-    while (ptr < end) {
-	c = rb_enc_codepoint_len(ptr, end, &n, enc);
-	rb_yield(UINT2NUM(c));
-	ptr += n;
-    }
-    return orig;
+static VALUE
+rb_str_codepoints(VALUE str)
+{
+    return rb_str_enumerate_codepoints(str, Qfalse);
 }
 
 static long
@@ -7989,7 +8025,7 @@ struct tr {
     rb_define_method(rb_cString, "lines", rb_str_each_line, -1);
     rb_define_method(rb_cString, "bytes", rb_str_bytes, 0);
     rb_define_method(rb_cString, "chars", rb_str_chars, 0);
-    rb_define_method(rb_cString, "codepoints", rb_str_each_codepoint, 0);
+    rb_define_method(rb_cString, "codepoints", rb_str_codepoints, 0);
     rb_define_method(rb_cString, "reverse", rb_str_reverse, 0);
     rb_define_method(rb_cString, "reverse!", rb_str_reverse_bang, 0);
     rb_define_method(rb_cString, "concat", rb_str_concat, 1);
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index f263edc..5c89db3 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -663,6 +663,34 @@ def test_chars
     assert_equal ["A", "B", "C"], S("ABC").chars
   end
 
+  def test_each_codepoint
+    # Single byte optimization
+    assert_equal 65, S("ABC").each_codepoint.next
+
+    res = []
+    s = S("\u3042\u3044\u3046")
+    assert_equal s.object_id, s.each_codepoint {|x| res << x }.object_id
+    assert_equal(0x3042, res[0])
+    assert_equal(0x3044, res[1])
+    assert_equal(0x3046, res[2])
+
+    assert_equal 0x3042, S("\u3042\u3044\u3046").each_codepoint.next
+  end
+
+  def test_codepoints
+    # Single byte optimization
+    assert_equal [65, 66, 67], S("ABC").codepoints
+
+    res = []
+    s = S("\u3042\u3044\u3046")
+    assert_equal s.object_id, s.codepoints {|x| res << x }.object_id
+    assert_equal(0x3042, res[0])
+    assert_equal(0x3044, res[1])
+    assert_equal(0x3046, res[2])
+
+    assert_equal [0x3042, 0x3044, 0x3046], S("\u3042\u3044\u3046").codepoints
+  end
+
   def test_each_line
     save = $/
     $/ = "\n"
-- 
1.7.10


From f75e6230a729b387f1347fca922d8e45718888ed Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Thu, 9 Aug 2012 12:03:17 +0900
Subject: [PATCH 06/10] Moved comments just before the implementation

---
 string.c |   72 ++++++++++++++++++++++++++++++++------------------------------
 1 file changed, 37 insertions(+), 35 deletions(-)

diff --git a/string.c b/string.c
index 5d721a3..163654c 100644
--- a/string.c
+++ b/string.c
@@ -6208,24 +6208,6 @@ struct tr {
 }
 
 
-/*
- *  call-seq:
- *     str.bytes {|fixnum| block }        -> str
- *     str.bytes                          -> an_enumerator
- *
- *     str.each_byte {|fixnum| block }    -> str
- *     str.each_byte                      -> an_enumerator
- *
- *  Passes each byte in <i>str</i> to the given block, or returns
- *  an enumerator if no block is given.
- *
- *     "hello".each_byte {|c| print c, ' ' }
- *
- *  <em>produces:</em>
- *
- *     104 101 108 108 111
- */
-
 static VALUE
 rb_str_enumerate_bytes(VALUE str, VALUE return_enumerator_p)
 {
@@ -6260,6 +6242,24 @@ struct tr {
     }
 }
 
+/*
+ *  call-seq:
+ *     str.bytes {|fixnum| block }        -> str
+ *     str.bytes                          -> an_enumerator
+ *
+ *     str.each_byte {|fixnum| block }    -> str
+ *     str.each_byte                      -> an_enumerator
+ *
+ *  Passes each byte in <i>str</i> to the given block, or returns
+ *  an enumerator if no block is given.
+ *
+ *     "hello".each_byte {|c| print c, ' ' }
+ *
+ *  <em>produces:</em>
+ *
+ *     104 101 108 108 111
+ */
+
 static VALUE
 rb_str_each_byte(VALUE str)
 {
@@ -6272,23 +6272,6 @@ struct tr {
     return rb_str_enumerate_bytes(str, Qfalse);
 }
 
-/*
- *  call-seq:
- *     str.chars {|cstr| block }        -> str
- *     str.chars                        -> an_enumerator
- *
- *     str.each_char {|cstr| block }    -> str
- *     str.each_char                    -> an_enumerator
- *
- *  Passes each character in <i>str</i> to the given block, or returns
- *  an enumerator if no block is given.
- *
- *     "hello".each_char {|c| print c, ' ' }
- *
- *  <em>produces:</em>
- *
- *     h e l l o
- */
 
 static VALUE
 rb_str_enumerate_chars(VALUE str, VALUE return_enumerator_p)
@@ -6346,6 +6329,24 @@ struct tr {
     }
 }
 
+/*
+ *  call-seq:
+ *     str.chars {|cstr| block }        -> str
+ *     str.chars                        -> an_enumerator
+ *
+ *     str.each_char {|cstr| block }    -> str
+ *     str.each_char                    -> an_enumerator
+ *
+ *  Passes each character in <i>str</i> to the given block, or returns
+ *  an enumerator if no block is given.
+ *
+ *     "hello".each_char {|c| print c, ' ' }
+ *
+ *  <em>produces:</em>
+ *
+ *     h e l l o
+ */
+
 static VALUE
 rb_str_each_char(VALUE str)
 {
@@ -6358,6 +6359,7 @@ struct tr {
     return rb_str_enumerate_chars(str, Qfalse);
 }
 
+
 static VALUE
 rb_str_enumerate_codepoints(VALUE str, VALUE return_enumerator_p)
 {
-- 
1.7.10


From 42ceea13786c87546a9e50c7db19ea9519c7c620 Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Wed, 15 Aug 2012 19:02:21 +0900
Subject: [PATCH 07/10] Changed lines to return Array

---
 string.c                 |  143 +++++++++++++++++++++++++++++++---------------
 test/ruby/test_string.rb |   19 +++++-
 2 files changed, 113 insertions(+), 49 deletions(-)

diff --git a/string.c b/string.c
index 163654c..ea850a9 100644
--- a/string.c
+++ b/string.c
@@ -6072,45 +6072,8 @@ struct tr {
 }
 
 
-/*
- *  call-seq:
- *     str.each_line(separator=$/) {|substr| block }   -> str
- *     str.each_line(separator=$/)                     -> an_enumerator
- *
- *     str.lines(separator=$/) {|substr| block }       -> str
- *     str.lines(separator=$/)                         -> an_enumerator
- *
- *  Splits <i>str</i> using the supplied parameter as the record separator
- *  (<code>$/</code> by default), passing each substring in turn to the supplied
- *  block. If a zero-length record separator is supplied, the string is split
- *  into paragraphs delimited by multiple successive newlines.
- *
- *  If no block is given, an enumerator is returned instead.
- *
- *     print "Example one\n"
- *     "hello\nworld".each_line {|s| p s}
- *     print "Example two\n"
- *     "hello\nworld".each_line('l') {|s| p s}
- *     print "Example three\n"
- *     "hello\n\n\nworld".each_line('') {|s| p s}
- *
- *  <em>produces:</em>
- *
- *     Example one
- *     "hello\n"
- *     "world"
- *     Example two
- *     "hel"
- *     "l"
- *     "o\nworl"
- *     "d"
- *     Example three
- *     "hello\n\n\n"
- *     "world"
- */
-
 static VALUE
-rb_str_each_line(int argc, VALUE *argv, VALUE str)
+rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, VALUE return_enumerator_p)
 {
     rb_encoding *enc;
     VALUE rs;
@@ -6120,6 +6083,7 @@ struct tr {
     VALUE line;
     int n;
     VALUE orig = str;
+    VALUE ary, yieldp;
 
     if (argc == 0) {
 	rs = rb_rs;
@@ -6127,10 +6091,28 @@ struct tr {
     else {
 	rb_scan_args(argc, argv, "01", &rs);
     }
-    RETURN_ENUMERATOR(str, argc, argv);
+
+    if (return_enumerator_p) {
+	RETURN_ENUMERATOR(str, argc, argv);
+    }
+
+    if (rb_block_given_p()) {
+	yieldp = Qtrue;
+    }
+    else {
+	yieldp = Qfalse;
+	ary = rb_ary_new2(RSTRING_LEN(str));
+    }
+
     if (NIL_P(rs)) {
-	rb_yield(str);
-	return orig;
+	if (yieldp) {
+	    rb_yield(str);
+	    return orig;
+	}
+	else {
+	    rb_ary_push(ary, str);
+	    return ary;
+	}
     }
     str = rb_str_new4(str);
     ptr = p = s = RSTRING_PTR(str);
@@ -6153,7 +6135,12 @@ struct tr {
 	    line = rb_str_new5(str, s, p - s);
 	    OBJ_INFECT(line, str);
 	    rb_enc_cr_str_copy_for_substr(line, str);
-	    rb_yield(line);
+	    if (yieldp) {
+		rb_yield(line);
+	    }
+	    else {
+		rb_ary_push(ary, line);
+	    }
 	    str_mod_check(str, ptr, len);
 	    s = p;
 	}
@@ -6189,7 +6176,12 @@ struct tr {
 	    line = rb_str_new5(str, s, p - s + (rslen ? rslen : n));
 	    OBJ_INFECT(line, str);
 	    rb_enc_cr_str_copy_for_substr(line, str);
-	    rb_yield(line);
+	    if (yieldp) {
+		rb_yield(line);
+	    }
+	    else {
+		rb_ary_push(ary, line);
+	    }
 	    str_mod_check(str, ptr, len);
 	    s = p + (rslen ? rslen : n);
 	}
@@ -6201,10 +6193,69 @@ struct tr {
 	line = rb_str_new5(str, s, pend - s);
 	OBJ_INFECT(line, str);
 	rb_enc_cr_str_copy_for_substr(line, str);
-	rb_yield(line);
+	if (yieldp) {
+	    rb_yield(line);
+	}
+	else {
+	    rb_ary_push(ary, line);
+	}
+    }
+
+    if (yieldp) {
+	return orig;
     }
+    else {
+	return ary;
+    }
+}
+
+/*
+ *  call-seq:
+ *     str.each_line(separator=$/) {|substr| block }   -> str
+ *     str.each_line(separator=$/)                     -> an_enumerator
+ *
+ *     str.lines(separator=$/) {|substr| block }       -> str
+ *     str.lines(separator=$/)                         -> an_enumerator
+ *
+ *  Splits <i>str</i> using the supplied parameter as the record separator
+ *  (<code>$/</code> by default), passing each substring in turn to the supplied
+ *  block. If a zero-length record separator is supplied, the string is split
+ *  into paragraphs delimited by multiple successive newlines.
+ *
+ *  If no block is given, an enumerator is returned instead.
+ *
+ *     print "Example one\n"
+ *     "hello\nworld".each_line {|s| p s}
+ *     print "Example two\n"
+ *     "hello\nworld".each_line('l') {|s| p s}
+ *     print "Example three\n"
+ *     "hello\n\n\nworld".each_line('') {|s| p s}
+ *
+ *  <em>produces:</em>
+ *
+ *     Example one
+ *     "hello\n"
+ *     "world"
+ *     Example two
+ *     "hel"
+ *     "l"
+ *     "o\nworl"
+ *     "d"
+ *     Example three
+ *     "hello\n\n\n"
+ *     "world"
+ */
 
-    return orig;
+static VALUE
+rb_str_each_line(int argc, VALUE *argv, VALUE str)
+{
+    return rb_str_enumerate_lines(argc, argv, str, Qtrue);
+}
+
+static VALUE
+rb_str_lines(int argc, VALUE *argv, VALUE str)
+{
+    return rb_str_enumerate_lines(argc, argv, str, Qfalse);
 }
 
 
@@ -8024,7 +8075,7 @@ struct tr {
     rb_define_method(rb_cString, "hex", rb_str_hex, 0);
     rb_define_method(rb_cString, "oct", rb_str_oct, 0);
     rb_define_method(rb_cString, "split", rb_str_split_m, -1);
-    rb_define_method(rb_cString, "lines", rb_str_each_line, -1);
+    rb_define_method(rb_cString, "lines", rb_str_lines, -1);
     rb_define_method(rb_cString, "bytes", rb_str_bytes, 0);
     rb_define_method(rb_cString, "chars", rb_str_chars, 0);
     rb_define_method(rb_cString, "codepoints", rb_str_codepoints, 0);
diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb
index 5c89db3..e229236 100644
--- a/test/ruby/test_string.rb
+++ b/test/ruby/test_string.rb
@@ -695,19 +695,19 @@ def test_each_line
     save = $/
     $/ = "\n"
     res=[]
-    S("hello\nworld").lines.each {|x| res << x}
+    S("hello\nworld").each_line {|x| res << x}
     assert_equal(S("hello\n"), res[0])
     assert_equal(S("world"),   res[1])
 
     res=[]
-    S("hello\n\n\nworld").lines(S('')).each {|x| res << x}
+    S("hello\n\n\nworld").each_line(S('')) {|x| res << x}
     assert_equal(S("hello\n\n\n"), res[0])
     assert_equal(S("world"),       res[1])
 
     $/ = "!"
 
     res=[]
-    S("hello!world").lines.each {|x| res << x}
+    S("hello!world").each_line {|x| res << x}
     assert_equal(S("hello!"), res[0])
     assert_equal(S("world"),  res[1])
 
@@ -716,6 +716,19 @@ def test_each_line
     s = nil
     "foo\nbar".each_line(nil) {|s2| s = s2 }
     assert_equal("foo\nbar", s)
+
+    assert_equal "hello\n", S("hello\nworld").each_line.next
+    assert_equal "hello\nworld", S("hello\nworld").each_line(nil).next
+  end
+  
+  def test_lines
+    res=[]
+    S("hello\nworld").lines {|x| res << x}
+    assert_equal(S("hello\n"), res[0])
+    assert_equal(S("world"),  res[1])
+
+    assert_equal ["hello\n", "world"], S("hello\nworld").lines
+    assert_equal ["hello\nworld"], S("hello\nworld").lines(nil)
   end
 
   def test_empty?
-- 
1.7.10


From ee111084c170e676b60417e5d220de9f199c9411 Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Wed, 15 Aug 2012 20:34:11 +0900
Subject: [PATCH 08/10] String#lines should use rb_ary_new

---
 string.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/string.c b/string.c
index ea850a9..4841b74 100644
--- a/string.c
+++ b/string.c
@@ -6101,7 +6101,7 @@ struct tr {
     }
     else {
 	yieldp = Qfalse;
-	ary = rb_ary_new2(RSTRING_LEN(str));
+	ary = rb_ary_new();
     }
 
     if (NIL_P(rs)) {
-- 
1.7.10


From 5f5881821bbc2265eedd71908aed70220f21933e Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Wed, 15 Aug 2012 20:40:38 +0900
Subject: [PATCH 09/10] Refactor: moved RETURN_ENUMERATOR inside if

---
 string.c |   30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/string.c b/string.c
index 4841b74..6452814 100644
--- a/string.c
+++ b/string.c
@@ -6092,14 +6092,13 @@ struct tr {
 	rb_scan_args(argc, argv, "01", &rs);
     }
 
-    if (return_enumerator_p) {
-	RETURN_ENUMERATOR(str, argc, argv);
-    }
-
     if (rb_block_given_p()) {
 	yieldp = Qtrue;
     }
     else {
+	if (return_enumerator_p)
+	    RETURN_ENUMERATOR(str, argc, argv);
+
 	yieldp = Qfalse;
 	ary = rb_ary_new();
     }
@@ -6265,14 +6264,13 @@ struct tr {
     long i;
     VALUE ary, yieldp;
 
-    if (return_enumerator_p) {
-	RETURN_ENUMERATOR(str, 0, 0);
-    }
-
     if (rb_block_given_p()) {
 	yieldp = Qtrue;
     }
     else {
+	if (return_enumerator_p)
+	    RETURN_ENUMERATOR(str, 0, 0);
+
 	yieldp = Qfalse;
 	ary = rb_ary_new2(RSTRING_LEN(str));
     }
@@ -6333,17 +6331,17 @@ struct tr {
     rb_encoding *enc;
     VALUE ary, yieldp;
 
-    if (return_enumerator_p) {
-	RETURN_ENUMERATOR(str, 0, 0);
-    }
-
     if (rb_block_given_p()) {
 	yieldp = Qtrue;
     }
     else {
+	if (return_enumerator_p)
+	    RETURN_ENUMERATOR(str, 0, 0);
+
 	yieldp = Qfalse;
 	ary = rb_ary_new();
     }
+
     str = rb_str_new4(str);
     ptr = RSTRING_PTR(str);
     len = RSTRING_LEN(str);
@@ -6424,14 +6422,13 @@ struct tr {
     if (single_byte_optimizable(str))
 	return rb_str_enumerate_bytes(str, return_enumerator_p);
 
-    if (return_enumerator_p) {
-	RETURN_ENUMERATOR(str, 0, 0);
-    }
-
     if (rb_block_given_p()) {
 	yieldp = Qtrue;
     }
     else {
+	if (return_enumerator_p)
+	    RETURN_ENUMERATOR(str, 0, 0);
+
 	yieldp = Qfalse;
 	ary = rb_ary_new();
     }
@@ -6491,6 +6488,7 @@ struct tr {
     return rb_str_enumerate_codepoints(str, Qfalse);
 }
 
+
 static long
 chopped_length(VALUE str)
 {
-- 
1.7.10


From 3496fec038c7102660d9c4a6c88c8bb29b97a5a5 Mon Sep 17 00:00:00 2001
From: Yutaka HARA <yutaka.hara.gmail.com>
Date: Wed, 15 Aug 2012 20:48:52 +0900
Subject: [PATCH 10/10] Fixed documents of lines, chars, bytes, codepoints

---
 string.c |   20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/string.c b/string.c
index 6452814..56b55d6 100644
--- a/string.c
+++ b/string.c
@@ -6210,18 +6210,18 @@ struct tr {
 
 /*
  *  call-seq:
+ *     str.lines(separator=$/) {|substr| block }       -> str
+ *     str.lines(separator=$/)                         -> an_array
+ *
  *     str.each_line(separator=$/) {|substr| block }   -> str
  *     str.each_line(separator=$/)                     -> an_enumerator
  *
- *     str.lines(separator=$/) {|substr| block }       -> str
- *     str.lines(separator=$/)                         -> an_enumerator
- *
  *  Splits <i>str</i> using the supplied parameter as the record separator
  *  (<code>$/</code> by default), passing each substring in turn to the supplied
  *  block. If a zero-length record separator is supplied, the string is split
  *  into paragraphs delimited by multiple successive newlines.
  *
- *  If no block is given, an enumerator is returned instead.
+ *  If no block is given, an array or enumerator is returned instead.
  *
  *     print "Example one\n"
  *     "hello\nworld".each_line {|s| p s}
@@ -6294,13 +6294,13 @@ struct tr {
 /*
  *  call-seq:
  *     str.bytes {|fixnum| block }        -> str
- *     str.bytes                          -> an_enumerator
+ *     str.bytes                          -> an_array
  *
  *     str.each_byte {|fixnum| block }    -> str
  *     str.each_byte                      -> an_enumerator
  *
  *  Passes each byte in <i>str</i> to the given block, or returns
- *  an enumerator if no block is given.
+ *  an array or enumerator if no block is given.
  *
  *     "hello".each_byte {|c| print c, ' ' }
  *
@@ -6381,13 +6381,13 @@ struct tr {
 /*
  *  call-seq:
  *     str.chars {|cstr| block }        -> str
- *     str.chars                        -> an_enumerator
+ *     str.chars                        -> an_array
  *
  *     str.each_char {|cstr| block }    -> str
  *     str.each_char                    -> an_enumerator
  *
  *  Passes each character in <i>str</i> to the given block, or returns
- *  an enumerator if no block is given.
+ *  an array or enumerator if no block is given.
  *
  *     "hello".each_char {|c| print c, ' ' }
  *
@@ -6458,7 +6458,7 @@ struct tr {
 /*
  *  call-seq:
  *     str.codepoints {|integer| block }        -> str
- *     str.codepoints                           -> an_enumerator
+ *     str.codepoints                           -> an_array
  *
  *     str.each_codepoint {|integer| block }    -> str
  *     str.each_codepoint                       -> an_enumerator
@@ -6467,7 +6467,7 @@ struct tr {
  *  also known as a <i>codepoint</i> when applied to Unicode strings to the
  *  given block.
  *
- *  If no block is given, an enumerator is returned instead.
+ *  If no block is given, an array or enumerator is returned instead.
  *
  *     "hello\u0639".each_codepoint {|c| print c, ' ' }
  *
-- 
1.7.10

