2016-09-02 1 views
2

Я хотел бы сгенерировать proc, который при вызове возвращает последовательные значения для любого Enumerable. Другими словами:Как сгенерировать proc для возврата последовательных записей в хеш, преобразованный?

a_proc = generate_proc([:a, :b, :c]) 
a_proc.call # => :a 
a_proc.call # => :b 

т.д.

В идеале, я бы хотел, чтобы перевести его, прежде чем вернуться, тоже, так что это может привыкнуть как:

a_proc = generate_proc([:a, :b, :c ]) { |e| "Element: #{e.inspect}" } 
a_proc.call # => "Element: :a" 
a_proc.call # => "Element: :b" 
a_proc.call # => "Element: :c" 
+1

Почему нужно быть 'proc'? Является ли класс, метод или лямбда опцией? – spickermann

+0

Призыв API (который я не контролирую) требует, увы. –

+0

Можете ли вы рассказать об этом? Похоже на проблему [xy] (http://meta.stackexchange.com/a/66378/284887). – spickermann

ответ

0

И это именно то, что вы просите:

def generate_proc(list, &transform) 
    enum = list.to_enum 
    if transform 
    proc { transform[enum.next] } 
    else 
    proc { enum.next } 
    end 
end 
+0

Возможно, было бы более эффективно возвращать одну из двух разных процедур, в зависимости от того, есть или нет трансформация, а не выполнение проверки внутри proc. – mwp

+0

True ... отредактировано. – michau

+0

Вы также можете вернуть дескриптор существующего метода 'Enumerator # send' (вместо того, чтобы обернуть его в другой Proc) с помощью' enum.method (: next) 'вместо' proc {enum.next} '. :-) – mwp

4

Это не совсем что вы просите, но я думаю, что он может удовлетворить ваши потребности:

an_enum = [:a, :b, :c].each 

p an_enum.next # => :a 
p an_enum.next # => :b 

И:

an_enum = [:a, :b, :c].map { |e| "Element: #{e.inspect}" }.each 
# or, if you want to defer calling the block... 
an_enum = [:a, :b, :c].lazy.map { |e| "Element: #{e.inspect}" } 

p an_enum.next # => Element: :a 
p an_enum.next # => Element: :b 
p an_enum.next # => Element: :c 

Для получения дополнительной информации посетите Enumerator и Enumerator::Lazy.

+0

Это удобно, спасибо. К сожалению, мне нужно somethign, которое отвечает на #call, но то, что –

+0

пригодится позже. –

+0

@ EricSchwartz Возможно, это слишком крамольно, но просто для удовольствия: 'def an_enum.call; self.next end' – mwp

1
def generate_proc x, &postproc 
    myobj = Fiber.new { x.each { |v| Fiber.yield v }} 

    postproc ? ->() { postproc.call myobj.resume } : 
      ->() {    myobj.resume } 
end 
Смежные вопросы