Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed spec 1.9: String#lines #1330

Merged
merged 1 commit into from Oct 22, 2011
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
108 changes: 108 additions & 0 deletions kernel/common/string18.rb
Expand Up @@ -567,4 +567,112 @@ def <<(other)
append(other) append(other)
end end
alias_method :concat, :<< alias_method :concat, :<<

# Splits <i>self</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 on
# <code>\n</code> characters, except that multiple successive newlines are
# appended together.
#
# print "Example one\n"
# "hello\nworld".each { |s| p s }
# print "Example two\n"
# "hello\nworld".each('l') { |s| p s }
# print "Example three\n"
# "hello\n\n\nworld".each('') { |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"
def each_line(sep=$/)
return to_enum(:each_line, sep) unless block_given?

# weird edge case.
if sep.nil?
yield self
return self
end

sep = StringValue(sep)

pos = 0

size = @num_bytes
orig_data = @data

# If the separator is empty, we're actually in paragraph mode. This
# is used so infrequently, we'll handle it completely separately from
# normal line breaking.
if sep.empty?
sep = "\n\n"
pat_size = 2

while pos < size
nxt = find_string(sep, pos)
break unless nxt

while @data[nxt] == 10 and nxt < @num_bytes
nxt += 1
end

match_size = nxt - pos

# string ends with \n's
break if pos == @num_bytes

str = substring(pos, match_size)
yield str unless str.empty?

# detect mutation within the block
if !@data.equal?(orig_data) or @num_bytes != size
raise RuntimeError, "string modified while iterating"
end

pos = nxt
end

# No more separates, but we need to grab the last part still.
fin = substring(pos, @num_bytes - pos)
yield fin if fin and !fin.empty?

else

# This is the normal case.
pat_size = sep.size

while pos < size
nxt = find_string(sep, pos)
break unless nxt

match_size = nxt - pos
str = substring(pos, match_size + pat_size)
yield str unless str.empty?

# detect mutation within the block
if !@data.equal?(orig_data) or @num_bytes != size
raise RuntimeError, "string modified while iterating"
end

pos = nxt + pat_size
end

# No more separates, but we need to grab the last part still.
fin = substring(pos, @num_bytes - pos)
yield fin unless fin.empty?
end

self
end

alias_method :lines, :each_line
end end
103 changes: 103 additions & 0 deletions kernel/common/string19.rb
Expand Up @@ -645,4 +645,107 @@ def chr
end end
end end


# Splits <i>self</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 on
# <code>\n</code> characters, except that multiple successive newlines are
# appended together.
#
# print "Example one\n"
# "hello\nworld".each { |s| p s }
# print "Example two\n"
# "hello\nworld".each('l') { |s| p s }
# print "Example three\n"
# "hello\n\n\nworld".each('') { |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"
def each_line(sep=$/)
return to_enum(:each_line, sep) unless block_given?

# weird edge case.
if sep.nil?
yield self
return self
end

sep = StringValue(sep)

pos = 0

size = @num_bytes
orig_data = @data

# If the separator is empty, we're actually in paragraph mode. This
# is used so infrequently, we'll handle it completely separately from
# normal line breaking.
if sep.empty?
sep = "\n\n"
pat_size = 2

while pos < size
nxt = find_string(sep, pos)
break unless nxt

while @data[nxt] == 10 and nxt < @num_bytes
nxt += 1
end

match_size = nxt - pos

# string ends with \n's
break if pos == @num_bytes

str = substring(pos, match_size)
yield str unless str.empty?

# detect mutation within the block
if !@data.equal?(orig_data) or @num_bytes != size
raise RuntimeError, "string modified while iterating"
end

pos = nxt
end

# No more separates, but we need to grab the last part still.
fin = substring(pos, @num_bytes - pos)
yield fin if fin and !fin.empty?

else

# This is the normal case.
pat_size = sep.size
unmodified_self = clone

while pos < size
nxt = unmodified_self.find_string(sep, pos)
break unless nxt

match_size = nxt - pos
str = unmodified_self.substring(pos, match_size + pat_size)
yield str unless str.empty?

pos = nxt + pat_size
end

# No more separates, but we need to grab the last part still.
fin = unmodified_self.substring(pos, @num_bytes - pos)
yield fin unless fin.empty?
end

self
end

alias_method :lines, :each_line
end end
1 change: 0 additions & 1 deletion spec/tags/19/ruby/core/string/lines_tags.txt
@@ -1 +0,0 @@
fails:String#lines does not care if the string is modified while substituting