Skip to content

Commit

Permalink
Make String#each_line work correctly with paragraph separator and chomp
Browse files Browse the repository at this point in the history
Previously, it was including one newline when chomp was used,
which is inconsistent with IO#each_line behavior. This makes
behavior consistent with IO#each_line, chomping all paragraph
separators (multiple consecutive newlines), but not single
newlines.

Partially Fixes [Bug #18768]
  • Loading branch information
jeremyevans committed Jul 21, 2022
1 parent cdbb9b8 commit 423b41c
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 8 deletions.
9 changes: 7 additions & 2 deletions string.c
Expand Up @@ -8967,14 +8967,18 @@ rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, VALUE ary)
const char *eol = NULL;
subend = subptr;
while (subend < pend) {
long chomp_rslen = 0;
do {
if (rb_enc_ascget(subend, pend, &n, enc) != '\r')
n = 0;
rslen = n + rb_enc_mbclen(subend + n, pend, enc);
if (rb_enc_is_newline(subend + n, pend, enc)) {
if (eol == subend) break;
subend += rslen;
if (subptr) eol = subend;
if (subptr) {
eol = subend;
chomp_rslen = -rslen;
}
}
else {
if (!subptr) subptr = subend;
Expand All @@ -8983,8 +8987,9 @@ rb_str_enumerate_lines(int argc, VALUE *argv, VALUE str, VALUE ary)
rslen = 0;
} while (subend < pend);
if (!subptr) break;
if (rslen == 0) chomp_rslen = 0;
line = rb_str_subseq(str, subptr - ptr,
subend - subptr + (chomp ? 0 : rslen));
subend - subptr + (chomp ? chomp_rslen : rslen));
if (ENUM_ELEM(ary, line)) {
str_mod_check(str, ptr, len);
}
Expand Down
17 changes: 11 additions & 6 deletions test/ruby/test_string.rb
Expand Up @@ -1121,14 +1121,19 @@ def test_each_line_chomp
assert_equal(S("world"), res[1])

res = []
S("hello\n\n\nworld").each_line(S(''), chomp: true) {|x| res << x}
assert_equal(S("hello\n"), res[0])
assert_equal(S("world"), res[1])
S("hello\n\n\nworld\n").each_line(S(''), chomp: true) {|x| res << x}
assert_equal(S("hello"), res[0])
assert_equal(S("world\n"), res[1])

res = []
S("hello\r\n\r\nworld").each_line(S(''), chomp: true) {|x| res << x}
assert_equal(S("hello\r\n"), res[0])
assert_equal(S("world"), res[1])
S("hello\r\n\r\nworld\r\n").each_line(S(''), chomp: true) {|x| res << x}
assert_equal(S("hello"), res[0])
assert_equal(S("world\r\n"), res[1])

res = []
S("hello\r\n\n\nworld").each_line(S(''), chomp: true) {|x| res << x}
assert_equal(S("hello"), res[0])
assert_equal(S("world"), res[1])

res = []
S("hello!world").each_line(S('!'), chomp: true) {|x| res << x}
Expand Down

0 comments on commit 423b41c

Please sign in to comment.