2011-04-16 53 views
4

我知道我可以執行下面的方法添加到String類模塊中的公開課

class String 
    def do_something 
    puts self.size 
    end 
end 

var = "test" 
var.do_something 

,這將返回4

我希望能夠有一個模塊的功能它需要一個字符串,但能夠在這個字符串上調用do_something方法(例如見下文) - 是否有可能?

編輯:不工作

module TestModule 
    class String 
    def do_something 
     puts self.size 
    end 
    end 

    def self.test(str)  
    str.do_something 
    end 
end 

這增加了代碼示例給出了錯誤:undefined method 'do_something' for "hello":String (NoMethodError)

+0

是的。您的代碼完全按照書面形式工作當您在String中定義doSomething時,它在所有範圍內的所有字符串上都可用。 – 2011-04-16 18:33:59

+0

@John Douthat它不工作,我已編輯的問題,以顯示什麼代碼即時運行 – Aly 2011-04-16 18:41:48

+0

你是否只想讓字符串在你的模塊的範圍內具有該功能? – Dogbert 2011-04-16 18:48:09

回答

8

您的代碼寫入的方式是定義一個名爲TestModule :: String的新類。如果要修改內置的Ruby String類,則需要使用完全限定的String名稱(帶「」::「),如果要將該聲明保留在模塊內部。

module TestModule 
    class ::String 
    def do_something 
     puts self.size 
    end 
    end 

    def self.test(str) 
    str.do_something 
    end 
end 

添加「::」告訴紅寶石是你想要的String類不是TestModule的一部分。

這可能吸塵器只是聲明字符串TestModule之外在同一個文件。

如果你不」要想污染全局的String類,只需修改要添加方法的特定String實例即可。

module TestModule 
    def self.test(str) 
    do_somethingify!(str) 
    str.do_something 
    end 

    def self.do_somethingify!(str) 
    unless str.respond_to? :do_something 
     str.instance_eval do 
     def do_something 
      puts size 
     end 
     end 
    end 
    end  
end   
+0

我們不應該使用class_eval嗎?你能評論一下使用instance_eval/class_eval和修改全局類字符串之間的性能差異嗎?無論哪種方式+1和接受的答案 – Aly 2011-04-17 18:07:26

+1

它使用instance_eval,因爲你正在修改一個特定的對象,而不是一個類。你也可以使用'str.define_singleton_method(:do_something){puts size}'。修改全球課程可能會表現更好。您可以使用標準基準庫來衡量差異。 – hallidave 2011-04-18 01:17:58

3

也許這?

​​

編輯由於更改爲這個問題

的變化只是將定義的doSomething之外出TestModule類。

class String 
    def doSomething 
    puts size 
    end 
end 

module TestModule 
    module_function 
    def test(str) 
    str.doSomething 
    end 
end