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?
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
puts new_week
new_week.each do |day|
puts day
break if day > Date.civil(2010,4,30)
end
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
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.
Kind regards
robert
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.
Sponsor our Newsletter | Privacy Policy | Terms of Service | Remote Ruby Jobs