From: Alex Baranosky on
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/.

From: David Masover on
On Wednesday 24 March 2010 10:35:16 pm Alex Baranosky 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 { ... }

From: Rob Biedenharn on

On Mar 24, 2010, at 11:35 PM, Alex Baranosky 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 Biedenharn http://agileconsultingllc.com
Rob(a)AgileConsultingLLC.com


From: Alex Baranosky on
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
--
Posted via http://www.ruby-forum.com/.

From: Alex Baranosky on
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
--
Posted via http://www.ruby-forum.com/.