When creating methods that yield
, sometimes we want it to return an Enumerator
if no block is given. The recommended way is basically return to_enum(:name_of_method, [args]) unless block_given?
. However, it's a pain to have to type that for every method that does this. Ruby being ruby, I decided to create a make_enum
method, similar to attr_accessor
, which does this for me:
class Module # Put this in a mixin, but for the purposes of this experiment, it's in Module
def make_enum *args
args.each do |name|
old_method = instance_method(name)
define_method(name) do |*args, &block|
next to_enum(name, *args) unless block
old_method.bind(self).call(*args, &block)
end
end
end
end
Now I can use it like so:
class Test
def test
yield 1
yield 2
end
make_enum :test
end
t = Test.new
t.test { |n| puts n }
# 1
# 2
t.test.to_a #=> [1, 2]
And it works! But it doesn't work if make_enum
is before the method definition.
How can I get this method to work before defining a method, so that the following works? Perhaps I need to make use of method_added
?
class Test
make_enum :test
def test
yield 1
yield 2
end
end
I don't know if it's a bad idea for it to be before the method, but my reason for thinking that it would be nice to do that is that it better matches the way we use attr_accessor
and the like.
Whereas attr_
methods create instance methods newly, your make_enum
modifies an existing method, which is rather similar to protected
, private
, and public
methods. Note that these visibility methods are used either in the form:
protected
def foo; ... end
or
protected def foo; ... end
or
def foo; ... end
protected :foo
The latter two ways are already available with your make_enum
. Especially, the second form is already possible (which Stefan also notes in the comment). You can do:
make_enum def test; ... end
If you want to do the first form, you should try to implement that in your make_enum
definition.