[ruby-core:96399] [Ruby master Feature#16441] Enumerable#take_while_after

[email protected]
Newsgroups gmane.comp.lang.ruby.core
Message-ID <redmine.journal-83324.20191222052126.4470843739d791a2@ruby-lang.org>
Issue #16441 has been updated by sawa (Tsuyoshi Sawada).


Not necessarily against the proposal, but just to note. For the second example, I would do:

```ruby
'7+38/6'.split(/(\D+)/) # => ["7", "+", "38", "/", "6"]
```

----------------------------------------
Feature #16441: Enumerable#take_while_after
https://bugs.ruby-lang.org/issues/16441#change-83324

* Author: zverok (Victor Shepelev)
* Status: Open
* Priority: Normal
* Assignee: 
* Target version: 
----------------------------------------
The method is just like `#take_while`, but also includes the item where condition became true.

Examples of usefulness:

```ruby
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:

```ruby
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:

```ruby
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`):

```ruby
str.each_line(chomp: true).drop_while { _1 != '<<' }.slice_after { _1 == '>>' }.first
# => ["<<", "1", "2", "3", ">>"]
```

With proposed method:

```ruby
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](https://bugs.ruby-lang.org/issues/14781)):

```ruby
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



-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:[email protected]?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.