2012-05-30 46 views
0

清潔方式有在Ruby創建一個閉合使得定義的方法具有訪問可變m一個更容易和/或更具有可讀性方式?定義的方法,而不lambda表達式

我在這裏有一個輕微的「問題」lambda

很多時候,我動態定義具有訪問一個局部變量的方法:

例如:

class Comparison 

    def income 
    123 
    end 

    def sales 
    42342 
    end 

    # and a dozen of other methods 

    # Generate xxx_after_tax for each method 
    instance_methods(false).each do |m| 
    lambda { 
     define_method("#{m}_after_tax") do 
     send(m) * 0.9 
     end 
    }.call 
    end 
end 
+1

你確定lambda是必需的嗎?沒有它,關閉應該可以正常工作。 – tokland

+2

他不需要lambda)),這看起來很有趣,創建lambda並立即調用它。 Lambda只是一個匿名函數。 –

+0

是的。 Lambda需要訪問方法定義中的'm'變量。 –

回答

5
class Comparison 

    def income 
    123 
    end 

    def sales 
    42342 
    end 

    # and a dozen of other methods 

    # Generate xxx_after_tax for each method 
    instance_methods(false).each do |m| 

    define_method("#{m}_after_tax") do 
     send(m) * 0.9 
    end 

    end 
end 
+0

你不能這樣做,因爲你將無法訪問實現中的變量'm'。 –

+0

你嘗試過嗎?它的工作原理...並在這裏使用lambda是過度殺毒,因爲你沒有將變量傳遞給lambda,並沒有任何意義))。 define_method它只是一個你在迭代器中調用的函數,所以參數可以包含迭代器範圍內的任何變量 –

+0

@DmytriiNagirniak這是正確的答案,我的答案中有一個最小的測試用例,你可以自己嘗試。 – Gareth

1
instance_methods(false).each do |m| 
    class_eval <<-ERUBY, __FILE__, __LINE__ 
     def #{m}_after_tax 
     #{m} * 0.9 
     end 
    ERUBY 
    end 
0

您可以使用method_missing的是這樣的:

def method_missing(name, *args, &block) 
    if name.to_s.match /^([a-z_]+)_after_tax$/ 
    send($1) 
    else 
    super 
    end 
end 

我希望這可以幫助。

+0

完全沒有必要使用method_missing。它使事情變得複雜。你還必須實現respond_to?和相關。這絕對是overkil在這裏。 –

+0

你能詳細說明爲什麼我必須實現respond_to? – moritz

+0

http://technicalpickles.com/posts/using-method_missing-and-respond_to-to-create-dynamic-methods/ –

2

正如尤里指出的那樣,lambda是多餘的,您可以通過運行此示例來查看。

#!/usr/bin/env ruby -w 

class Foo 
    [:foo, :bar].each do |m| 
    define_method("#{m}_dynamic") do 
     "Called #{m}" 
    end 
    end 
end 

p Foo.new.foo_dynamiC# => "Called foo" 
3

常規方法的定義都沒有關閉,但在這裏,你是一個塊調用define_method和塊關閉。這應該足夠了:

instance_methods(false).each do |m| 
    define_method :"#{m}_after_tax" do 
    send(m) * 0.9 
    end 
end 
+0

我認爲我給了壞榜樣。所以如果我要從方法定義方法,我需要創建一個閉包(使用lambda或block)?對? –

+0

@Dmytrii,如果您需要捕獲給定上下文中可用的局部變量,則必須創建閉包。這裏的問題是你正在創建兩個:'lambda'和提供給'define_method'的塊。前者是不必要的。 –