From: "zverok (Victor Shepelev)" Date: 2021-09-16T14:15:56+00:00 Subject: [ruby-core:105305] [Ruby master Feature#18136] take_while_after Issue #18136 has been updated by zverok (Victor Shepelev). @mame > In other words, your use case examples looked not so frequent to make it built-in. Soooo... Let me summarize :) In defense of the idea, I provided: 1. **Two** big domains: API clients with pagination ("stop after current page"), and working with tokenized sequences ("stop after breaking token"), both well inside Ruby's intended usage; 2. A few additional cases from *production* codebases (choosing dates with inclusion; navigating trees) 3. Explanation how in some cases there is no way to rewrite code with different Enumerable methods (lazy), and in other cases rewritten code is much less clear (`slice_after{}.first`); so realistically, people tend to switch back to just `each` with `break`, or `while` etc. (which, I believe, is against the best practices) The answer from the core team is "(empirically,) not *all* API clients use this kind of pagination, therefore the case is not frequent *enough*, therefore we can't have `take_while_after`/`drop_after` (despite already having several kinds of `slice_`, `chunk_`, `take_` and `drop_`)". Is that what you are saying? Is there a way to show the case is frequent *enough*? Should I provide links to public APIs of popular services which require this approach? If so, how many should be enough? Should I provide more diverse examples (besides two big domains and some additional cases)? How many? How diverse? Should I just stop bothering the core team? :) ---------------------------------------- Feature #18136: take_while_after https://bugs.ruby-lang.org/issues/18136#change-93715 * Author: zverok (Victor Shepelev) * Status: Open * Priority: Normal ---------------------------------------- Sorry, I already tried that once (#16441) but I failed to produce the persuasive example. So I am back with a couple of them, much simpler and clear than my initial. **The proposal itself:** Have `take_while_after` which behaves like `take_while` but also includes the last element (first where the condition failed). Reason: there are a lot of cases where "the last good item" in enumeration is the distinctive one (one where enumeration should stop, but the item is still good. **Example 1:** Take pages from paginated API, the last page will have less items than the rest (and that's how we know it is the last): ```ruby (0..).lazy .map { |offset| get_page(offset, limit) } .take_while_after { |response| response.count == limit } # the last will have, say, 10 items, but should still be included! .map { process response somehow } ``` **Example 2:** Same as above, but "we should continue pagination" is specified with a separate data key "can_continue": ```ruby (0..).lazy .map { |offset| get_page(offset, limit) } .take_while_after { |response| response['can_continue'] } # the last will have can_continue=false, but still has data .map { process response somehow } ``` **Exampe 3:** Taking a sentence from a list of tokens like this: ```ruby tokens = [ {text: 'Ruby', type: :word}, {text: 'is', type: :word}, {text: 'cool', type: :word}, {text: '.', type: :punctuation, ends_sentence: true}, {text: 'Rust', type: :word}, # ... ] sentence = tokens.take_while_after { !_1[:ends_sentence] } ``` (I can get more if it is necessary!) Neither of those can be solved by "Using `take_while` with proper condition.", as @matz suggested here: https://bugs.ruby-lang.org/issues/16441#note-9 I typically solve it by `slice_after { condition }.first`, but that's a) uglier and b) greedy when we are working with lazy enumerator (so for API examples, all paginated pages would be fetched at once, and only then processed). Another consideration in #16441 was an unfortunate naming. I am leaving it to discussion, though I tend to like `#take_upto` from #16446. -- https://bugs.ruby-lang.org/ Unsubscribe: