2014-02-25 82 views
1

我試圖爲模型創建一個關注點,但這是一個基本的Ruby方法查找問題,而不是Rails問題本身。從模塊中的調度表中查找紅寶石方法

我希望能夠通過選擇基於值的某些特徵的格式化方法來提供格式化值的功能。在下面的抽象示例中,如果要格式化的值的值爲:attribute且值爲:a_characteristic,我想調用foo格式化程序。特別是,我想要一個調度表,我可以從特徵映射到格式化函數。

這裏是我的嘗試:

module FormatConcern 
    FORMATTERS = { 
    a_characteristic: ->(v){foo v} 
    } 

    def format(v) 
    FORMATTERS[v[:attribute]].call(v) 
    end 

    def foo(v) 
    "A value with #{v[:foo]}" 
    end 
end 

class ModelWithConcern 
    include FormatConcern 
end 

test_value = {attribute: :a_characteristic, 
       foo: "bar"} 
m = ModelWithConcern.new 
puts "formatted value: #{m.format(test_value)}" 

當我執行這段代碼中,foo方法查找失敗:

$ ruby concern_test.rb 
concern_test.rb:3:in `block in <module:FormatConcern>': undefined method `foo' for FormatConcern:Module (NoMethodError) 
from concern_test.rb:7:in `call' 
from concern_test.rb:7:in `format' 
from concern_test.rb:22:in `<main>' 

我想我明白紅寶石如何查找方法名在一類,但顯然我不太瞭解它!我如何從我的調度表中的lambda函數引用foo方法?

回答

1

你的問題是塊是詞彙綁定。由於塊是在模塊的上下文中定義的,塊中的self指的是模塊。最直接的方法是在格式化程序塊中調用一個被調用者參數。

module FormatConcern 
    FORMATTERS = { 
    a_characteristic: ->(obj, v){obj.foo v} 
    } 

    def format(v) 
    FORMATTERS[v[:attribute]].call(self, v) 
    end 

    def foo(v) 
    "A value with #{v[:foo]}" 
    end 
end 

另一個解決辦法是instance_exec塊,而不是調用它:

module FormatConcern 
    FORMATTERS = { 
    a_characteristic: ->(v){foo v} 
    } 

    def format(v) 
    instance_exec(v, &FORMATTERS[v[:attribute]]) 
    end 

    def foo(v) 
    "A value with #{v[:foo]}" 
    end 
end 
0

製作FOO一個類的方法與.self

def self.foo(v) 
    "A value with #{v[:foo]}" 
    end