ruby-core@ruby-lang.org archive (unofficial mirror)
 help / color / mirror / Atom feed
* [ruby-core:96385] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
@ 2019-12-21 13:22 ` zverok.offline
  2019-12-21 14:01 ` [ruby-core:96387] " nobu
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: zverok.offline @ 2019-12-21 13:22 UTC (permalink / raw)
  To: ruby-core

Issue #16441 has been reported by zverok (Victor Shepelev).

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

* 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:
p 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...
p str.each_line(chomp: true).drop_while { _1 != '<<' }.take_while { _1 != '>>' }
# => ["<<", "1", "2", "3"] -- the last line is lost.

# So, Enumerable leaves us with this (which is harder to read, due to additional `.first`):
p str.each_line(chomp: true).drop_while { _1 != '<<' }.slice_after { _1 == '>>' }.first
# => ["<<", "1", "2", "3", ">>"]

# With proposed method:
p 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')
p Enumerator.produce { scanner.scan(%r{\d+|[-+*/]}) }.take_while { !scanner.eos? } # expresses meaning, but loses last element
# => ["7", "+", "38", "/"]
p Enumerator.generate { scanner.scan(%r{\d+|[-+*/]}) }.slice_after { scanner.eos? }.first # slice_after {}.first again
# => ["7", "+", "38", "/", "6"]
p 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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:96387] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
  2019-12-21 13:22 ` [ruby-core:96385] [Ruby master Feature#16441] Enumerable#take_while_after zverok.offline
@ 2019-12-21 14:01 ` nobu
  2019-12-21 16:12 ` [ruby-core:96391] " shevegen
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: nobu @ 2019-12-21 14:01 UTC (permalink / raw)
  To: ruby-core

Issue #16441 has been updated by nobu (Nobuyoshi Nakada).


Flip-flop is the winner!!!

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

* 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:
p 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...
p str.each_line(chomp: true).drop_while { _1 != '<<' }.take_while { _1 != '>>' }
# => ["<<", "1", "2", "3"] -- the last line is lost.

# So, Enumerable leaves us with this (which is harder to read, due to additional `.first`):
p str.each_line(chomp: true).drop_while { _1 != '<<' }.slice_after { _1 == '>>' }.first
# => ["<<", "1", "2", "3", ">>"]

# With proposed method:
p 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')
p Enumerator.produce { scanner.scan(%r{\d+|[-+*/]}) }.take_while { !scanner.eos? } # expresses meaning, but loses last element
# => ["7", "+", "38", "/"]
p Enumerator.generate { scanner.scan(%r{\d+|[-+*/]}) }.slice_after { scanner.eos? }.first # slice_after {}.first again
# => ["7", "+", "38", "/", "6"]
p 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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:96391] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
  2019-12-21 13:22 ` [ruby-core:96385] [Ruby master Feature#16441] Enumerable#take_while_after zverok.offline
  2019-12-21 14:01 ` [ruby-core:96387] " nobu
@ 2019-12-21 16:12 ` shevegen
  2019-12-22  5:21 ` [ruby-core:96399] " sawadatsuyoshi
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: shevegen @ 2019-12-21 16:12 UTC (permalink / raw)
  To: ruby-core

Issue #16441 has been updated by shevegen (Robert A. Heiler).


This is of course only my personal opinion, but I believe that long
names can be somewhat problematic. Now I myself use really very
long method names, but for ruby as a "basic building block", I think
the shorter the method name, the better (usually that is).

So we have methods such as:

    .size
    .keys
    .uniq

And we have some methods with two words:

    .each_pair
    .take_while

And so forth.

I believe that the net benefit of methods becomes lesser the more words
have to be used - which I mean in general, primarily, not solely confined
to the name here.

I think three words are quite unwieldy. It also feels a bit strange since
this is almost as if you could do a method-chain, like:

    .take_while_after
    .take.while.after

Reminds me a bit of rspec.

Of course it depends a lot on how someone uses ruby, which "style" is to
be preferred, but for me personally, I much prefer the shorter, simpler
variant whenever that would be possible. It is a bit comparable to 
"yield_self" versus "then" - if the question is solely between these two
names, then the name "then" is IMO better, because it is easier to use.

I don't have a good alternative name either, but I am also not sure if there
can be a much simpler name IF the thought behind the suggestion is to 
combine so many different method calls in one go.

Perhaps we could have two variants of ruby, one for the simple minds, and
one for the uber gurus that may find haskell too easy. ;-)

> The idea is the same as with flip-flops .. vs ...

Well, the difference here is a single (!) character.

I think you are a bit afar from that difference. I also already find
.take_while a peculiar name ...

By the way, another small point to note is that in the method chain,
"while" appears twice. That seems a bit odd to me too.


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

* 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:
p 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...
p str.each_line(chomp: true).drop_while { _1 != '<<' }.take_while { _1 != '>>' }
# => ["<<", "1", "2", "3"] -- the last line is lost.

# So, Enumerable leaves us with this (which is harder to read, due to additional `.first`):
p str.each_line(chomp: true).drop_while { _1 != '<<' }.slice_after { _1 == '>>' }.first
# => ["<<", "1", "2", "3", ">>"]

# With proposed method:
p 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')
p Enumerator.produce { scanner.scan(%r{\d+|[-+*/]}) }.take_while { !scanner.eos? } # expresses meaning, but loses last element
# => ["7", "+", "38", "/"]
p Enumerator.generate { scanner.scan(%r{\d+|[-+*/]}) }.slice_after { scanner.eos? }.first # slice_after {}.first again
# => ["7", "+", "38", "/", "6"]
p 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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:96399] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
                   ` (2 preceding siblings ...)
  2019-12-21 16:12 ` [ruby-core:96391] " shevegen
@ 2019-12-22  5:21 ` sawadatsuyoshi
  2019-12-22  5:46 ` [ruby-core:96401] " sawadatsuyoshi
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: sawadatsuyoshi @ 2019-12-22  5:21 UTC (permalink / raw)
  To: ruby-core

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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:96401] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
                   ` (3 preceding siblings ...)
  2019-12-22  5:21 ` [ruby-core:96399] " sawadatsuyoshi
@ 2019-12-22  5:46 ` sawadatsuyoshi
  2019-12-26 22:32 ` [ruby-core:96505] " daniel
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: sawadatsuyoshi @ 2019-12-22  5:46 UTC (permalink / raw)
  To: ruby-core

Issue #16441 has been updated by sawa (Tsuyoshi Sawada).


I think a better name would be `take_after`. And from symmetry, you should also be proposing a counterpart for `drop_*`, which I would name `drop_after`.

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

* 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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:96505] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
                   ` (4 preceding siblings ...)
  2019-12-22  5:46 ` [ruby-core:96401] " sawadatsuyoshi
@ 2019-12-26 22:32 ` daniel
  2019-12-26 23:13 ` [ruby-core:96506] " sawadatsuyoshi
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: daniel @ 2019-12-26 22:32 UTC (permalink / raw)
  To: ruby-core

Issue #16441 has been updated by Dan0042 (Daniel DeLorme).


`take_while_after` is rather unwieldy, so in terms of naming maybe I can suggest:

```ruby
str.each_line(chomp: true).take_from{ _1 == '<<' }.take_upto{ _1 == '>>' }
```

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

* 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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:96506] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
                   ` (5 preceding siblings ...)
  2019-12-26 22:32 ` [ruby-core:96505] " daniel
@ 2019-12-26 23:13 ` sawadatsuyoshi
  2020-01-14  3:24 ` [ruby-core:96831] " mame
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 10+ messages in thread
From: sawadatsuyoshi @ 2019-12-26 23:13 UTC (permalink / raw)
  To: ruby-core

Issue #16441 has been updated by sawa (Tsuyoshi Sawada).


Dan0042 (Daniel DeLorme) wrote:
> `take_while_after` is rather unwieldy, so in terms of naming maybe I can suggest:
> 
> ```ruby
> str.each_line(chomp: true).take_from{ _1 == '<<' }.take_upto{ _1 == '>>' }
> ```

Such methods are the same as the cases 6 an 7 in my proposal #16446.

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

* 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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:96831] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
                   ` (6 preceding siblings ...)
  2019-12-26 23:13 ` [ruby-core:96506] " sawadatsuyoshi
@ 2020-01-14  3:24 ` mame
  2020-01-14  5:05 ` [ruby-core:96834] " akr
  2020-01-16  6:53 ` [ruby-core:96892] " matz
  9 siblings, 0 replies; 10+ messages in thread
From: mame @ 2020-01-14  3:24 UTC (permalink / raw)
  To: ruby-core

Issue #16441 has been updated by mame (Yusuke Endoh).


@akr What do you think?

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

* 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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:96834] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
                   ` (7 preceding siblings ...)
  2020-01-14  3:24 ` [ruby-core:96831] " mame
@ 2020-01-14  5:05 ` akr
  2020-01-16  6:53 ` [ruby-core:96892] " matz
  9 siblings, 0 replies; 10+ messages in thread
From: akr @ 2020-01-14  5:05 UTC (permalink / raw)
  To: ruby-core

Issue #16441 has been updated by akr (Akira Tanaka).


mame (Yusuke Endoh) wrote:
> @akr What do you think?

I'm neutral with this feature.
I don't like the name, take_while_after, though.

I feel that it's better to consider the method name in wider view, like [Feature #16446].


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

* 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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [ruby-core:96892] [Ruby master Feature#16441] Enumerable#take_while_after
       [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
                   ` (8 preceding siblings ...)
  2020-01-14  5:05 ` [ruby-core:96834] " akr
@ 2020-01-16  6:53 ` matz
  9 siblings, 0 replies; 10+ messages in thread
From: matz @ 2020-01-16  6:53 UTC (permalink / raw)
  To: ruby-core

Issue #16441 has been updated by matz (Yukihiro Matsumoto).

Status changed from Open to Rejected

I don't see the real-world usage of `take_while_after`. Use `take_while` with proper condition.

Matz.


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

* Author: zverok (Victor Shepelev)
* Status: Rejected
* 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/

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2020-01-16  6:53 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <redmine.issue-16441.20191221132215@ruby-lang.org>
2019-12-21 13:22 ` [ruby-core:96385] [Ruby master Feature#16441] Enumerable#take_while_after zverok.offline
2019-12-21 14:01 ` [ruby-core:96387] " nobu
2019-12-21 16:12 ` [ruby-core:96391] " shevegen
2019-12-22  5:21 ` [ruby-core:96399] " sawadatsuyoshi
2019-12-22  5:46 ` [ruby-core:96401] " sawadatsuyoshi
2019-12-26 22:32 ` [ruby-core:96505] " daniel
2019-12-26 23:13 ` [ruby-core:96506] " sawadatsuyoshi
2020-01-14  3:24 ` [ruby-core:96831] " mame
2020-01-14  5:05 ` [ruby-core:96834] " akr
2020-01-16  6:53 ` [ruby-core:96892] " matz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).