如何在 ruby​​ 中创建具有给定绑定的块?

发布于 2024-11-19 05:05:44 字数 1260 浏览 2 评论 0原文

我正在尝试编写一个接受哈希作为参数的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

自演自醉 2024-11-26 05:05:44

也许我错过了一些东西,但我认为你正在尝试使用 ruby​​ 的非常复杂的功能,而它们对于解决你的问题是不必要的。

我的解决方案是:

def assert_hash(hash, &block)
  if hash.length > 1
    assert_difference(*hash.shift) do
      assert_hash(hash, &block)
    end
  else
    assert_difference(*hash.first, &block)
  end
end

当然它缺少别名,但这不是重点。

编辑:

当使用自定义绑定创建块时,答案是:不。但是您可以使用不同的绑定调用代码块,可以使用 binding 方法捕获,也可以仅通过提供与其相关的绑定的对象。

您可以使用 eval 来实现此目的(它接受 Binding 对象作为第二个参数),也可以使用更好的 instance_evalclass_evalinstance_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:

def assert_hash(hash, &block)
  if hash.length > 1
    assert_difference(*hash.shift) do
      assert_hash(hash, &block)
    end
  else
    assert_difference(*hash.first, &block)
  end
end

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 better instance_eval, class_eval, instance_exec and class_exec. You can start your digging at Jay Fields' Thoughts blog entry.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文