В ruby 1.9+ вы можете использовать Enumerator для реализации этого.
def arbitrary(&block)
Enumerator.new do |y|
values = [1,2,3,4]
values.each { |val| y.yield(val) }
end.each(&block)
end
Преимущество этого метода в том, что он работает и для бесконечных потоков:
# block-only version
#
def natural_numbers
0.upto(1/0.0) { |x| yield x }
end
# returning an enumerator when no block is given
#
def natural_numbers(&block)
Enumerator.new do |y|
0.upto(1/0.0) { |x| y.yield(x) }
end.each(&block)
end
Но самый идиоматический способ сделать это - защитить ваш метод с помощью to_enum(your_method_name, your_args)
примерно так:
def arbitrary
return to_enum(:arbitrary) unless block_given?
yield 1
yield 2
yield 3
yield 4
end
Это идиома, которую сами библиотеки ruby core используют в нескольких местах.