Actions
Feature #16441
closedEnumerable#take_while_after
Status:
Rejected
Assignee:
-
Target version:
-
Description
The method is just like #take_while
, but also includes the item where condition became true.
Examples of usefulness:
str = <<DOC
prologue
<<
1
2
3
>>
epilogue
DOC
Imagine we want to take everything starting from <<
to >>
in short and clean Ruby. Surprisingly, our best guess would be infamous flip-flop:
str.each_line(chomp: true).filter_map { _1 if _1 == '<<'.._1 == '>>' }
# => ["<<", "1", "2", "3", ">>"]
Trying to achieve this with Enumerator
, you almost can express it, but the last line is lost:
str.each_line(chomp: true).drop_while { _1 != '<<' }.take_while { _1 != '>>' }
# => ["<<", "1", "2", "3"]
So, Enumerable leaves us with this (which is harder to read, due to additional .first
):
str.each_line(chomp: true).drop_while { _1 != '<<' }.slice_after { _1 == '>>' }.first
# => ["<<", "1", "2", "3", ">>"]
With proposed method:
str.each_line(chomp: true).drop_while { _1 != '<<' }.take_while_after { _1 != '>>' }
# => ["<<", "1", "2", "3", ">>"]
The idea is the same as with flip-flops ..
vs ...
(sometimes we need to include the last element matching the condition, sometimes don't), and while ... end
vs do ... while
. Another example (from Enumerator.produce
proposal):
require 'strscan'
scanner = StringScanner.new('7+38/6')
Enumerator.produce { scanner.scan(%r{\d+|[-+*/]}) }.take_while { !scanner.eos? }
# => ["7", "+", "38", "/"]
Enumerator.generate { scanner.scan(%r{\d+|[-+*/]}) }.slice_after { scanner.eos? }.first
# => ["7", "+", "38", "/", "6"]
Enumerator.produce { scanner.scan(%r{\d+|[-+*/]}) }.take_while_after { !scanner.eos? }
# => ["7", "+", "38", "/", "6"]
PS: Not sure about the name, suggestions are welcome
Actions
Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0