2014-09-03 6 views
0

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

module DSL 
    def update object, *args, &block 
    updated_object = object.send *args 
    # then, some stuff with the updated object and the block 
    end 
end 

следующий код может быть использован, например, как:

include DSL 

# equivalent to: Array.new 3, :foo 
update Array, :new, 3, :foo do 
    # updated object => [:foo, :foo, :foo] 
    # some stuff 
end 

или такие, как:

# equivalent to: [:foo, :foo, :foo].size 
update [:foo, :foo, :foo], :size do 
    # updated object => 3 
    # some stuff 
end 

Но как мы могли обновить содержание этого update метода для того, чтобы обрабатывать блоки, как ч ERE:

[:foo, :bar].select {|a| a == :foo } 

Я думал о преобразовании блока в процедурный, такие как:

update [:foo, :bar], :select, &:foo.method(:==) do 
    # ... 
end 

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

SyntaxError: both block arg and actual block given

Есть ли элегантный способ решить эту проблему?

ответ

1

Я думаю, что вы собираетесь чрезмерно с этим, но в любом случае, вот идея:

Вы могли бы пройти регулярный прок вашего метода update и затем специальная обработка последнего аргумента, который является Proc.

module DSL 
    def update object, *args, &block 
    updated_object = if args.last.is_a? Proc 
     proc = args.pop 
     object.send *args, &proc 
    else 
     object.send *args 
    end 
    yield updated_object 
    end 
end 

extend DSL 

update [:foo, :bar], :select, ->(a) { a == :foo } do |obj| 
    puts "selected object: #{obj}" 
end 

# >> selected object: [:foo] 
+0

Brillante! Большое спасибо, @ sergio-tulentsev! – Sisss

Смежные вопросы