Object#enumerate
This is a small (exactly 1 method) gem to showcase my proposal to core Ruby.
Discussion log from developers meeting:
Naruse: interesting proposal
Akr: adding method to Object sounds too radical to me.
Usa: I think there is a chance if this is a method of Enumerable.
Shyouhei: my feeling is this should start as a gem.
So, considering Shyouhei's last remark, I am providing this gem for interested parties to experiment.
I still strongly believe the method should be a part of language core, so the gem is made as a proof-of-concept, to make experimentation with an idea simple.
Synopsys
Object#enumerate takes a block and returns an instance of infinite Enumerator, where each next element is made by applying the block to the previous.
Examples of usage
Object#enumerate can provide idiomatic replacement for a lot of while and loop constructs, the same way each replaces for.
require 'object_enumerate'
# Most idiomatic "infinite sequence" possible:
p 1.enumerate(&:succ).take(5)
# => [1, 2, 3, 4, 5]
# Easy Fibonacci
p [0, 1].enumerate { |f0, f1| [f1, f0 + f1] }.take(10).map(&:first)
#=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
# Find next Tuesday
require 'date'
Date.today.enumerate(&:succ).detect { |d| d.wday == 2 }
# => #<Date: 2018-05-22 ((2458261j,0s,0n),+0s,2299161j)>
# Tree navigation
# ---------------
require 'nokogiri'
require 'open-uri'
# Find some element on page, then make list of all parents
p Nokogiri::HTML(open('https://www.ruby-lang.org/en/'))
.at('a:contains("Ruby 2.2.10 Released")')
.enumerate(&:parent)
.take_while { |node| node.respond_to?(:parent) }
.map(&:name)
# => ["a", "h3", "div", "div", "div", "div", "div", "div", "body", "html"]
# Pagination
# ----------
require 'octokit'
Octokit.stargazers('rails/rails')
# ^ this method returned just an array, but have set `.last_response` to full response, with data
# and pagination. So now we can do this:
p Octokit.last_response
.enumerate { |response| response.rels[:next].get } # pagination: `get` fetches next Response
.first(3) # take just 3 pages of stargazers
.flat_map(&:data) # `data` is parsed response content (stargazers themselves)
.map { |h| h[:login] }
# => ["wycats", "brynary", "macournoyer", "topfunky", "tomtt", "jamesgolick", ...
Alternative synopsys
Not implemented in the gem, just provided for a sake of core language proposal.
Enumerable.enumerate(1, &:succ)
Enumerable(1, &:succ)
Enumerator.from(1, &:succ)
I personally don't believe any of those look clear enough, so, however risky adding new method to Object could look, I'd vote for it.