用类扩展控制器

时间:2014-07-15 23:20:10

标签: ruby-on-rails rspec

创建自定义匹配器以测试某些局部变量:

RSpec::Matchers.define :set_the_local_variable do |variable|    
    match do |actual|
        @actual = controller.binding.local_variable_get(variable)
        @actual == @expected
    end

    failure_message do |actual|
        "set '#{@actual}' equal to #{@expected}. However, it did not: \n '#{@actual.inspect}' \n '#{@expected.inspect}'"
    end

    failure_message_when_negated do |actual|
        "set '#{@actual}' not equal to #{@expected}. However, it did: \n '#{@actual.inspect}' \n '#{@expected.inspect}'"
    end

    description do
        "set the instance '#{@actual}' to equal '#{expected}'"
    end

    def to(expected)
        @expected = expected
        self
    end
end

然而,这一行:

 controller.binding.local_variable_get(variable)

给了我这个错误:

private method `binding' called for #<StaticController:0x00000104b5a108>

我如何解决这个问题? binding.local_variable_get在irb中工作正常:

2.1.1 :001 > foo = 'bar'
 => "bar" 
2.1.1 :002 > binding.local_variable_get(:foo)
 => "bar"

有人能解释一下这里发生了什么吗?我理解类,实例和继承以及私有类方法,但我不确定如何使其工作。

我想找出包含绑定的类,并在匹配块中使用该类扩展控制器?那样的东西?

1 个答案:

答案 0 :(得分:1)

binding的文档说:

  

返回一个Binding对象,描述变量和方法绑定   在通话点

(强调补充)

在IRB中尝试:

> self
main
> binding
=> #<Binding:0x007fa89a8be670>
> self.binding
NoMethodError: private method `binding' called for main:Object

您当然可以直接发送消息:

> self.send(:binding)
=> #<Binding:0x007fa89a890b30>

但这与输入binding相同。

您在IRB中键入的内容是在顶级main方法的上下文中完成的。执行controller.binding时,您将在RSpec为您创建的测试控制器实例上调用该方法。但是,上下文是RSpec示例实例,而不是控制器实例,它(可能是?)不是您想要的。

实际上这完全是学术性的:在测试时进入实例并检查局部变量的值是不明智的。如果您非常想要这样做,那么恕我直言就表明需要进行一些重构。