How to create an infinite enumerable of Times?

I want to be able to have an object extend Enumerable in Ruby to be an
infinite list of Mondays (for example).

So it would yield: March 29, April 5, April 12… etc

How can I implement this in Ruby?

On Wednesday 24 March 2010 10:35:16 pm Alex B. wrote:

infinite list of Mondays (for example).

So it would yield: March 29, April 5, April 12… etc

How can I implement this in Ruby?

First learn to implement Enumerable, then it should be obvious. All you
need
to do is define a #each method. So, for example, here’s an
implementation of
all numbers:

class PositiveIntegers
include Enumerable
def each
i = 1
while true
yield i
i += 1
end
end
end

If you can figure out how to do a similar loop for Mondays, you can do
that.

Keep in mind that this kind of thing isn’t nearly as cool in practice as
you
might like – for one, a lot of the reasons you’d want an enumerable are
not
going to work well. For example, calling .map{…}.each is probably
going to
result in an infinite loop, as map returns an array.

I would probably do it like this:

module Foo
def self.positive_integers
return enum_for(:positive_integers) unless block_given?
i = 1
while true
yield i
i += 1
end
end
end

So that means you could do this:

Foo.positive_integers { … }

Or, that enum_for means you could also do this:

Foo.positive_integers.each { … }

On Mar 24, 2010, at 11:35 PM, Alex B. wrote:

I want to be able to have an object extend Enumerable in Ruby to be an
infinite list of Mondays (for example).

So it would yield: March 29, April 5, April 12… etc

How can I implement this in Ruby?

Posted via http://www.ruby-forum.com/.

require ‘date’
class Mondays
include Enumerable

def initialize(starting=Date.today)
@monday = starting
@monday += 1 until @monday.wday == 1
end

def succ
@monday += 7
end

def each
place = @monday.dup
loop do
yield place
place += 7
end
end
end

new_week = Mondays.new

=> #<Mondays:0x357938 @monday=#<Date: 4910569/2,0,2299161>>

puts new_week

#Mondays:0x357938

=> nil

new_week.each do |day|
puts day
break if day > Date.civil(2010,4,30)
end

2010-03-29

2010-04-05

2010-04-12

2010-04-19

2010-04-26

2010-05-03

=> nil

But don’t try to call #to_a on that new_week object or you’ll find out
that an infinite sequence takes quite a long time to iterate.

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

So far I’ve come up with:

module LazyEnumerable
extend Enumerable

def select(&block)
lazily_enumerate { |enum, value| enum.yield(value) if
block.call(value) }
end

def map(&block)
lazily_enumerate {|enum, value| enum.yield(block.call(value))}
end

def collect(&block)
map(&block)
end

private

def lazily_enumerate(&block)
Enumerator.new do |enum|
self.each do |value|
block.call(enum, value)
end
end
end
end

class LazyInfiniteDays
include LazyEnumerable

attr_reader :day

def self.day_of_week
dow = { :sundays => 0, :mondays => 1, :tuesdays => 2, :wednesdays =>
3, :thursdays => 4, :fridays => 5, :saturdays => 6, :sundays => 7 }
dow.default = -10
dow
end

DAY_OF_WEEK = day_of_week()

def advance_to_midnight_of_next_specified_day(day_sym)
year = DateTime.now.year
month = DateTime.now.month
day_of_month = DateTime.now.day
output_day = DateTime.civil(year, month, day_of_month)
output_day += 1 until output_day.wday == DAY_OF_WEEK[day_sym]
output_day
end

def initialize(day_sym)
@day = advance_to_midnight_of_next_specified_day(day_sym)
end

def each
day = @day.dup
while true
yield day
day += 7
end
end

def ==(other)
return false unless other.kind_of? LazyInfiniteDays
@day.wday == other.day.wday
end
end

Thanks guys, great stuff.

In reply to the first poster, I have a lazy_select, and lazy_map like
this:

module Enumerable
def lazy_select(&block)
Enumerator.new do |enum|
self.each do |value|
enum.yield(value) if block.call(value)
end
end
end

def lazy_map(&block)
Enumerator.new do |enum|
self.each do |value|
enum.yield(block.call(value))
end
end
end
end

2010/3/25 Rob B. [email protected]:

require ‘date’
end
IMHO you are abusing #succ here since it is intended to return the
next element of the same class. Either you make it return self
which I would also consider not too safe because the instance does not
change or you change the design and move it to another class.

Here’s my generic solution.

http://gist.github.com/343387

Kind regards

robert

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs