2013-01-16 52 views
1

所以,我很想做類似於rspec/mocha的mock,但只適用於兩個對象,而不是全部。這是我到目前爲止有:如何對未知類型的對象上的對象實例使用define_method?

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對象sections覆蓋我已存儲在self.instantiatedsections中的對象。

我之所以這樣做,是因爲我存儲了一個對象的序列化和加密版本,我希望能夠解密和反序列化對象,然後還原所有關係,例如我可以在我的視圖中查看該對象,就好像它正在從數據庫中讀取一樣。但這並不重要,大部分工作已經完成。

所以,我希望能夠做到這一點:

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> 

想法?


UPDATE

改變第二行class << obj現在無限循環。

from /home/me/.rvm/gems/[email protected]/gems/activerecord-2.3.15/lib/active_record/connection_adapters/abstract/connection_pool.rb:351:in `retrieve_connection_pool' 
from /home/me/.rvm/gems/[email protected]/gems/activerecord-2.3.15/lib/active_record/connection_adapters/abstract/connection_pool.rb:351:in `retrieve_connection_pool' 
from /home/me/.rvm/gems/[email protected]/gems/activerecord-2.3.15/lib/active_record/connection_adapters/abstract/connection_pool.rb:325:in `retrieve_connection' 
from /home/me/.rvm/gems/[email protected]/gems/activerecord-2.3.15/lib/active_record/connection_adapters/abstract/connection_specification.rb:123:in `retrieve_connection' 
from /home/me/.rvm/gems/[email protected]/gems/activerecord-2.3.15/lib/active_record/connection_adapters/abstract/connection_specification.rb:115:in `connection' 
from /home/me/.rvm/gems/[email protected]/gems/activerecord-2.3.15/lib/active_record/base.rb:1305:in `columns' 
from /home/me/.rvm/gems/[email protected]/gems/activerecord-2.3.15/lib/active_record/base.rb:1318:in `column_names' 
from /home/me/.rvm/gems/[email protected]/gems/searchlogic-2.4.28/lib/searchlogic/named_scopes/ordering.rb:35:in `ordering_condition_details' 
from /home/me/.rvm/gems/[email protected]/gems/searchlogic-2.4.28/lib/searchlogic/named_scopes/ordering.rb:26:in `method_missing' 
from /home/me/.rvm/gems/[email protected]/gems/searchlogic-2.4.28/lib/searchlogic/named_scopes/or_conditions.rb:28:in `method_missing' 
from /home/me/.rvm/gems/[email protected]/gems/activerecord-2.3.15/lib/active_record/base.rb:2002:in `method_missing_without_paginate' 
from /home/me/.rvm/gems/[email protected]/gems/will_paginate-2.3.16/lib/will_paginate/finder.rb:170:in `method_missing_without_attr_encrypted' 
from /home/me/.rvm/gems/[email protected]/bundler/gems/attr_encrypted-a4b25f01d137/lib/attr_encrypted/adapters/active_record.rb:50:in `method_missing' 
from /home/me/Work/GravityLabs/project/app/models/proposal/encrypted.rb:119:in `mock' 
from /home/me/Work/GravityLabs/project/app/models/proposal/encrypted.rb:79:in `instantiate' 
from /home/me/Work/GravityLabs/project/app/models/proposal/encrypted.rb:58:in `each' 
from /home/me/Work/GravityLabs/project/app/models/proposal/encrypted.rb:58:in `instantiate' 
+1

'類<< self'是一種特殊的表達進入自我的單身類。嘗試'class << obj'。 'class'是一個關鍵字,而不是一個方法。 – BernardK

+0

現在我已經這樣做了,它無限循環。 O操作。o我的猜測是現在它爲每個'obj'的實例定義了新的方法,而不僅僅是一個。 : - \ – NullVoxPopuli

回答

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。

在現代的紅寶石,而不是說比較神祕,(class << obj; self; end)獲得單例類,你可以使用singleton_class方法,像這樣:obj.singleton_class.class_eval do ... end

+0

感謝您的解釋!每個對象都有單獨類嗎?我記得我java時代的單身人士只是一個只能實例化一次的類。 – NullVoxPopuli

+1

在ruby中,每個對象都有一個單例類,有時也稱爲元類或特徵類。 ruby單例類本質上是一個匿名類,插入到對象和其基類之間的祖先鏈中。我們稱之爲「類方法」的東西實際上是一個類的單例方法(記住類只是ruby中的對象)。 [更充分的解釋](http://www.devalot.com/articles/2008/09/ruby-singleton)這與[Singleton]不一樣(http://en.wikipedia.org/wiki/ Singleton_pattern),它是一個只能有一個實例的對象。 – dbenhur

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

哎呀!應該提到我使用紅寶石1.8.7/rails 2.3.15。 – NullVoxPopuli

相關問題