如何在未知类型的对象上的对象实例上使用define_method?

时间:2013-01-16 18:59:59

标签: ruby-on-rails ruby mocking metaprogramming

所以,我有点想做类似于rspec / mocha的mock,但只针对两个对象,而不是所有对象。这就是我到目前为止所做的:

def mock(obj, method_to_mock, value)
    obj.class << obj do
        define_method(method_to_mock) do
            return value
        end
    end
end

我有想法从这篇文章中写出来:https://stackoverflow.com/a/185969/356849

那么我可以做以下事情:

mock(self.instantiated, :sections, sections)

它将使用我的Section对象数组self.instantiated覆盖我在sections的{​​{1}}中存储的对象。

我这样做的原因是因为我存储了一个对象的序列化和加密版本,我希望能够解密和反序列化该对象,然后恢复所有关系,这样我可以在我的视图中查看该对象,就像从数据库中读取它一样。但这并不重要,大部分都已完成。

所以,我希望能够做到这一点:

sections

显然,我在mock(<Instance of object>, :<method of object that is going to be overridden, to avoid db access>, <the stuff to return when the overridden method is invoked)行上收到错误:

obj.class << obj do

想法?


更新

将第二行更改为NoMethodError: undefined method `obj' for #<MyObject::Encrypted:0x7f190eebcd18> ,现在无限循环。

class << obj

2 个答案:

答案 0 :(得分:2)

def mock(obj, method_to_mock, value=nil)
  obj.define_singleton_method(method_to_mock) do value end
end  

答案 1 :(得分:1)

obj.class << obj do毫无意义。

你可能想说的是

def mock(obj, method_to_mock, value)
  (class << obj; self; end).class_eval do
    define_method(method_to_mock) do
      return value
    end
  end
end

(class << obj; self; end).class_eval语法打开返回该单例类的obj单例类,然后在该单例类上调用class_eval传递该块。

在您的语法中,obj.class:class消息发送给obj作为接收者,该接收者返回对obj的类(不是其单例类)的引用,然后您尝试调用它<<方法将评估obj do...end的结果作为arg传递。由于obj不是self(MyObject :: Encrypted:0x7f190eebcd1)的方法,因此会得到NoM​​ethodError。

在现代红宝石中,您可以使用singleton_class方法,而不是说相对神秘的(class << obj; self; end)来获取单例类:obj.singleton_class.class_eval do ... end