Justin
Justin

Reputation: 25377

Easily create an Enumerator

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.

Upvotes: 3

Views: 147

Answers (1)

sawa
sawa

Reputation: 168249

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.

Upvotes: 3

Related Questions