Могу ли я передать блок, который сам ожидает блок instance_exec в ruby?

Я ожидаю код

foo=proc{puts "foo"}

instance_exec(1,2,3,&foo) do |*args , &block|
  puts *args
  block.call
  puts "bar"
end

выводить

1
2
3
foo
bar

Но получил ошибку

both block arg and actual block given

Могу ли я передать блок, который сам ожидает блок instance_exec в ruby?


person benjaminchanming    schedule 12.03.2013    source источник


Ответы (2)


&foo пытается передать foo как блок instance_exec, а вы уже передаете явный блок. Отсутствие амперсанда отправляет foo так же, как и любой другой аргумент (за исключением того, что это экземпляр Proc). Итак, попробуйте это вместо этого:

instance_exec(1,2,3,foo) do |*args, block|
  puts *args
  block.call
  puts "bar"
end

Это также означает, что вы можете сделать что-то вроде:

bar = proc{ |*args, block|
  puts *args
  block.call
  puts "bar"
}

instance_exec(1,2,3,foo,&bar)

И получить тот же результат.

Дополнительная информация на странице Разница между блоком и блоком в Ruby

person Mladen Jablanović    schedule 12.03.2013
comment
К сожалению, это не сработает для моего случая. Я пытаюсь прозрачно обернуть существующий процесс таким образом, чтобы я мог отслеживать время его выполнения. Поскольку у меня нет контроля над подписью процесса, который я оборачиваю, я не могу использовать этот метод. В целом, хотя это кажется хорошим обходным путем. - person Ajedi32; 12.05.2015

Я опоздал на эту вечеринку примерно на 3 года, но решил поделиться подходом, позволяющим относиться к внутреннему блоку как к настоящему блоку, а не как к простому старому аргументу.

Лучший известный мне способ сделать это — создать объект, который будет действовать как контекст привязки, и определить внешний блок как метод. Итак, если я перепишу исходный пример следующим образом без вызова instance_exec...

inner_proc = proc { puts "inner" }
outer_proc = proc { |*args, &inner_block|
  puts *args
  inner_block.call
  puts "bar"
}

Мы можем определить outer_proc как метод объекта.

scope_object = Object.new
scope_object.define_singleton_method :bound_proc, &outer_proc

Теперь вы можете вызывать scope_object.bound_proc вместо вызова instance_exec выше.

scope_object.bound_proc 1, 2, 3, &inner_proc

Ты получишь:

1
2
3
inner
bar

К сожалению, вы получите LocalJumpError, если попытаетесь выполнить yield внутри outer_proc, а не inner_block.call, я не совсем понимаю, почему. Если у кого-то есть такой ответ, мне было бы интересно.

person Erick J    schedule 17.11.2016