2017-04-07 143 views
1

我正在創建一個類(例如,Bar),以便通過另一個類的方法(比如說,Foo#bar)返回一個對象,幾乎是MatchData對象由Regexp#match返回。Ruby - 如何在沒有.new的情況下創建MatchData對象?

但類MatchData沒有.new

我知道我不需要模仿MatchData的實現,但我想了解它,並知道如何做到這一點,當我發現它很有趣。假設我不希望客戶創建Bar對象,除非通過調用Foo#bar

問題:

  1. 內部,如何MatchData對象,而無需創建.new
  2. 我該如何實現它(模仿MatchData或不)?

回答

3

MatchData.new方法正在explicitly undefined

rb_cMatch = rb_define_class("MatchData", rb_cObject); 
rb_define_alloc_func(rb_cMatch, match_alloc); 
rb_undef_method(CLASS_OF(rb_cMatch), "new"); // <- here 

您可以通過undef_method做相同的純Ruby:

class Bar 
    class << self 
    undef_method :new 
    end 

    def initialize 
    @bar = '123' # <- for demonstration purposes 
    end 
end 

試圖調用Bar.new現在將產生一個錯誤:

Bar.new #=> undefined method `new' for Bar:Class (NoMethodError) 

要沒有new方法創建一個新的實例,就可以調用手動allocate(也許initialize,太):

bar = Bar.allocate  #=> #<Bar:0x007f9eba047cd8> 
Bar.send(:initialize) #=> "123" 
bar     #=> #<Bar:0x007fd8e0847658 @bar="123"> 

send是必要的,因爲initialize是私有的)

+0

很多,您可以通過使類私人做的核心類由於各種原因違反了規則。有時候,他們爲自己的特殊而走出困境令人非常痛心。 – tadman

+0

@tadman違反規則? – Stefan

+0

你知道,無法初始化的對象,它們基本上是其他進程的神奇副產品。和Fixnum一樣,這不是你可以調用'Fixnum.new'的地方,因爲在內部,整數實際上只是對象。 – tadman

1

讓我先說你不應該。即使它不是公共接口,也不願意限制用戶做他們想做的事情。更習慣的方法是使它更加明確,它不是公共接口的一部分。

class RegexMockery 
    class MatchDataMockery 
    def initialize(whatever) 
     puts "I'm being created #{whatever}" 
    end 

    def [](_) 
     '42' 
    end 
    end 
    private_constant :MatchDataMockery 

    def match(string) 
    MatchDataMockery.new(string) 
    end 
end 

match_result = RegexMockery.new.match('foo') 
    # I'm being created foo 
    # => #<RegexMockery::MatchDataMockery:0x007fe990de2ed0> 

match_result[0] # => '42' 

RegexMockery::MatchDataMockery # !> NameError: private constant RegexMockery::MatchDataMockery referenced 

但如果你堅持以人恨你,保存方法,民主基金,並調用它,只要你想創建實例:

class Foo 
    def initialize(whatever) 
    puts "Now you see me #{whatever}" 
    end 

    def brag 
    puts "I can create Foos and you can't!!!1!!" 
    end 
end 

class Bar 
    foos_new = Foo.method(:new) 
    Foo.singleton_class.send :undef_method, :new 

    define_method(:sorcery) do 
    foos_new.call('bar').brag 
    end 
end 

Bar.new.sorcery 
    # Now you see me bar 
    # I can create Foos and you can't!!!1!! 

Foo.new # !> NoMethodError: undefined method `new' for Foo:Class 
+0

我真的很討厭'整數'。和「浮動」,這是最糟糕的。更不用說'方法'和'編碼'。哦,還有那雙邪惡的雙胞胎,'TrueClass'和'FalseClass' :-) – Stefan

+0

@Stefan,對吧?它是可怕的。給我們'#新'或者讓我們死!嚴肅地說,那裏只是內部的噱頭。對於用戶創建的類,沒有人應該這樣做。 – ndn

+0

如果核心類沒問題,應該允許用戶定義的類,不是嗎?一個匿名或無價值的'Integer'實例會有點奇怪。 – Stefan

相關問題