Enumerable#lazy
relies on your enumerable providing an #each
method. If your enumerable doesn\'t have an #each
method you can\'t use <
I think you should return a normal Enumerator
using to_enum
:
class Calendar
# ...
def each_from(first)
return to_enum(:each_from, first) unless block_given?
loop do
yield first if include?(first)
first += step
end
end
end
This is what most rubyists would expect. Even though it's an infinite Enumerable
, it is still usable, for example:
Calendar.new.each_from(1.year.from_now).first(10) # => [...first ten dates...]
If they actually need a lazy enumerator, they can call lazy
themselves:
Calendar.new.each_from(1.year.from_now)
.lazy
.map{...}
.take_while{...}
If you really want to return a lazy enumerator, you can call lazy
from you method:
# ...
def each_from(first)
return to_enum(:each_from, first).lazy unless block_given?
#...
I would not recommend it though, since it would be unexpected (IMO), could be an overkill and will be less performant.
Finally, there are a couple of misconceptions in your question:
All methods of Enumerable
assume an each
, not just lazy
.
You can define an each
method that requires a parameter if you like and include Enumerable
. Most methods of Enumerable
won't work, but each_with_index
and a couple of others will forward arguments so these would be usable immediately.
The Enumerator.new
without a block is gone because to_enum
is what one should use. Note that the block form remains. There's also a constructor for Lazy
, but it's meant to start from an existing Enumerable
.
You state that to_enum
never creates a lazy enumerator, but that's not entirely true. Enumerator::Lazy#to_enum
is specialized to return a lazy enumerator. Any user method on Enumerable
that calls to_enum
will keep a lazy enumerator lazy.