2010-11-09 101 views
2

我正在努力尋找類似於下面示例的代碼(但實際上做了一些有用的工作)。傳遞給def_my_method的塊當然是在類的上下文中創建的,當我想在具有實例方法的實例的上下文中評估它時。我該怎麼做呢?Ruby:將塊傳遞給定義實例方法的類宏

module Formatters 
    # Really useful methods, included in several classes 
    def format_with_stars(str) 
    return "*** #{str} ***" 
    end 
end 

class Test 
    include Formatters 
    STRINGS = ["aa", "bb"] 

    def self.def_my_method(method_name, another_parameter, &format_proc) 
    define_method(method_name) do 
     # In reality, some more complex code here, then... 
     return STRINGS.map(&format_proc) 
    end 
    end 

    def_my_method(:star_strings, "another_parameter") { |str| format_with_stars(str) } 
    # Define other methods 
end 

tt = Test.new 
puts tt.star_strings 
# Throws undefined method `format_with_stars' for Test:Class (NoMethodError) 

回答

3

您可以使用instance_exec在正確的上下文中執行傳遞的塊。不要將&format_proc直接傳遞給map的調用,而是使用實例exec傳遞一個調用它的塊。

事情是這樣的:

def self.def_my_method(method_name, another_parameter, &format_proc) 
    define_method(method_name) do 
    # In reality, some more complex code here, then... 
    return STRINGS.map{|str| instance_exec(str, &format_proc)} 
    end 
end 

這會產生這樣的:

$ ruby tt.rb 
*** aa *** 
*** bb *** 

對我來說(其中tt.rb是我給了該文件的arbitary名),我認爲這是你想要的這個例。

+1

你不需要包裝的proc,你可以做'STRINGS.map {| str | instance_exec(str,&format_proc)}'。 – sepp2k 2010-11-09 18:55:40

+0

@ sepp2k - 哦,是的,這是一個更清晰的方式 - 謝謝。我已將您的建議納入答案。 (任何感興趣的人都可以看看編輯歷史,看看我使用包裝器'lambda'傳遞給'map'的原始想法。) – matt 2010-11-09 19:21:17

+0

instance_exec聽起來很完美,但它不是核心Ruby是它嗎?我的谷歌搜索表明它是在Rails 2中引入的對象的擴展。我簡化的例子是純Ruby,但真正的事情是Rails - 但Rails 1.2!所以我看不到任何方式來使用它。 :-( – 2010-11-11 10:38:21

1
 

... 

class Test 
- include Formatters 
+ extend Formatters 

... 
 

應該做的伎倆。

+0

它適用於我的簡單示例,但只能通過將實例方法更改爲類方法,這絕對不是我在實際代碼中可以執行的操作。 – 2010-11-11 12:09:19