2014-04-03 108 views
4

我正在嘗試編寫一個通用模塊來將method_missing模式應用於一些Rails模型的動態方法創建。這些模型有類方法和實例方法。雖然我可以寫一個模塊相當直截了當的任一類情況:覆蓋類和實例方法的method_missing?

module ClassVersion 
    extend ActiveSupport::Concern 

    module ClassMethods 
     def method_missing(meth, *args, &block) 
     if meth.to_s =~ /^(.+)_async$/ 
      Async::handle_async self, $1, *args, &block 
     else 
      super meth, *args, &block 
     end 
     end 

     # Logic for this method MUST match that of the detection in method_missing 
     def respond_to_missing?(method_name, include_private = false) 
     Async::async?(method_name) || super 
     end 
    end 
    end 

或實例情況:

module InstanceVersion 
    extend ActiveSupport::Concern 

    def method_missing(meth, *args, &block) 
     if meth.to_s =~ /^(.+)_async$/ 
     Async::handle_async self, $1, *args, &block 
     else 
     super meth, *args, &block 
     end 
    end 

    # Logic for this method MUST match that of the detection in method_missing 
    def respond_to_missing?(method_name, include_private = false) 
     Async::async?(method_name) || super 
    end 
    end 

...我似乎無法支持這兩種情況下在同一個班。有沒有更好的方法來覆蓋method_missing,這樣兩種情況都被支持?我on Rails的3.2 ....

回答

6

什麼你正在努力實現是非常簡單的,並在同一時間不同尋常。 ActiveSupport::Concern給你定義嵌套ClassMethods模塊的可能性,該模塊擴展了included模塊鉤子的基類。通常這很方便,因爲你不想用相同的方法來擴充類和它的實例。

你需要做的是停止使用ActiveSupport::Concernincluded鉤滿足您的特定需求:

module AsyncModule 
    def method_missing(meth, *args, &block) 
    if meth.to_s =~ /^(.+)_async$/ 
     Async::handle_async self, $1, *args, &block 
    else 
     super meth, *args, &block 
    end 
    end 

    # Logic for this method MUST match that of the detection in method_missing 
    def respond_to_missing?(method_name, include_private = false) 
    Async::async?(method_name) || super 
    end 

    private 

    def self.included(base) 
    base.extend self 
    end 
end 
+0

古樸典雅。謝謝! –

+0

似乎關鍵是:如果通過模塊向類中添加'method_missing',則還必須爲模塊提供'respond_to_missing?',否則'method_missing'不會生效。 –

0

你試過以下

module ClassAndInstanceVersion 
    extend ActiveSupport::Concern 

    def method_missing(meth, *args, &block) 
     self.class.method_missing(meth, *args, &block) 
    end 

    def respond_to_missing?(method_name, include_private = false) 
     self.class.respond_to_missing?(method_name, include_private) 
    end 

    module ClassMethods 
     def method_missing(meth, *args, &block) 
     if meth.to_s =~ /^(.+)_async$/ 
      Async::handle_async self, $1, *args, &block 
     else 
      super meth, *args, &block 
     end 
     end 

     # Logic for this method MUST match that of the detection in method_missing 
     def respond_to_missing?(method_name, include_private = false) 
     Async::async?(method_name) || super 
     end 
    end 
    end