如何在 ruby 中创建具有给定绑定的块?
我正在尝试编写一个接受哈希作为参数的 assert_difference
版本,这样
assert_difference 'thing1', 1 do
assert_difference ['thing2a', 'thing2b'], 2 do
assert_difference 'thing3', -3 do
# some triple-indented code
end
end
end
我就可以编写
assert_difference 'thing1' => 1, ['thing2a', 'thing2b'] => 2, 'thing3' => 3 do
# some single-indented code
end
我已经得到的内容,而
def assert_difference_with_hash_support(expression, difference = 1, message = nil, &block)
if expression.is_a? Hash
expression.each do |expr, diff|
block = lambda do
assert_difference_without_hash_support expr, diff, &block
end
end
block.call
else
assert_difference_without_hash_support(expression, difference, message, &block)
end
end
alias_method_chain :assert_difference, :hash_support
不是编写,但这不起作用,因为assert_difference 使用计算表达式时块的绑定。我想做的是使用原始绑定创建一个新块 - 类似这样:
b = block.send :binding
expression.each do |expr, diff|
block = lambda(b) do
assert_difference_without_hash_support expr, diff, &block
end
end
block.call
但我还没有看到使用当前绑定以外的任何内容创建新块的方法。如何创建具有给定绑定的块?
I'm trying to write a version of assert_difference
that will accept a hash as an argument, so that instead of writing
assert_difference 'thing1', 1 do
assert_difference ['thing2a', 'thing2b'], 2 do
assert_difference 'thing3', -3 do
# some triple-indented code
end
end
end
I can write
assert_difference 'thing1' => 1, ['thing2a', 'thing2b'] => 2, 'thing3' => 3 do
# some single-indented code
end
I've got as far as
def assert_difference_with_hash_support(expression, difference = 1, message = nil, &block)
if expression.is_a? Hash
expression.each do |expr, diff|
block = lambda do
assert_difference_without_hash_support expr, diff, &block
end
end
block.call
else
assert_difference_without_hash_support(expression, difference, message, &block)
end
end
alias_method_chain :assert_difference, :hash_support
but this doesn't work because assert_difference uses the binding of the block when it evaluates the expression. What I'd like to do is to create a new block with the original binding - something like so:
b = block.send :binding
expression.each do |expr, diff|
block = lambda(b) do
assert_difference_without_hash_support expr, diff, &block
end
end
block.call
but I haven't seen a way of creating a new block with anything other than the current binding. How do I create a block with a given binding?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
也许我错过了一些东西,但我认为你正在尝试使用 ruby 的非常复杂的功能,而它们对于解决你的问题是不必要的。
我的解决方案是:
当然它缺少别名,但这不是重点。
编辑:
当使用自定义绑定创建块时,答案是:不。但是您可以使用不同的绑定调用代码块,可以使用
binding
方法捕获,也可以仅通过提供与其相关的绑定的对象。您可以使用
eval
来实现此目的(它接受 Binding 对象作为第二个参数),也可以使用更好的instance_eval
、class_eval
、instance_exec< /code> 和
class_exec
。您可以从 Jay Fields 的想法博客条目。Maybe I am missing something, but I think you are trying to use very complicated features of ruby, while they are unnecessary for solving your problem.
My solution would be:
Of course it is missing aliasing, but that's not the point.
EDIT:
As of creating blocks with custom bindings the answer is: no. But you can call chunks of code with different binding, either caught with
binding
method, or just by providing object that has binding related with it.You can either use
eval
for this purpose (it accepts Binding object as a second argument) or betterinstance_eval
,class_eval
,instance_exec
andclass_exec
. You can start your digging at Jay Fields' Thoughts blog entry.