2012-11-26 42 views
0

我正在創建一個支持API網絡的庫。該庫的中心目前是每個API客戶端子類的Client類。由於我是編寫我所有API的人,所以他們都會以類似的方式運行(通過access_token等進行安寧的授權)。有沒有辦法將Ruby類初始化僅限制到一個子類?

不像其他ruby API客戶端庫(Twitter's等),不應該直接實例化客戶端類。這是因爲該庫不限於單個API。相反,每個API客戶端都將繼承客戶端類。我的問題如下:

有沒有辦法要求Ruby類只通過子類初始化?

此外,在閱讀this question我決定在這裏一個班級比mixin更好。

對於那些想代碼,這裏有一個例子:

class A 
    def initialize(options = {}) 
     #what goes on in here doesn't really matter for the purpose of this question 
     #I just don't want it to be initialized directly 
     options.each do |k,v| 
      instance_variable_set("@#{k}",v) unless v.nil? 
     end 
    end 
end 

class B < A 
    attr_accessor :class_specific_opt 
    def initialize(options = {}) 
     @class_specific_opt = "val" unless options[:class_specific_opt].nil? 
     super(options) 
    end 
end 

有什麼想法?

+0

如果你做'B.new',那麼將調用'B#initialize',它將調用'A#initialize'。 '#初始化'不會被直接調用,除非你做'A.new'。它有什麼問題? – sawa

+0

問題是,有人仍然可以理論上調用A#初始化 –

+0

'initialize'是一種私有方法。你不能用接收器調用它。 – sawa

回答

1

你可以做這樣的事情:

class A 
    def self.initialize_allowed? 
    raise "You cannot initialize instances of this class." 
    end 

    def self.allow_initialize 
    class << self 
     def initialize_allowed? 
     true 
     end 
    end 
    end 

    def initialize(options = {}) 
    self.class.initialize_allowed? 
    options.each do |k,v| 
     instance_variable_set("@#{k}", v) 
    end 
    end 
end 

調用A.new提高拋出一個RuntimeError和暫停initialize方法。然後您可以通過調用allow initialize來覆蓋子類中的initialized_allowed?方法。 (也許這是矯枉過正,但我​​認爲allow_initialize是很容易,def self.initialize_allowed?;end閱讀):

class B < A 
    allow_initialize 
end 

B.new #=> #<B:0x00000102837d10> 
1

如果您不想A.new被調用,簡單地做:

class <<A 
    undef :new 
end 

然後,你會不能夠把它叫做:

A.new #=> NoMethodError: undefined method `new' for A:Class 
0

添加

private_class_method :new 

A類和

public_class_method :new 

類B.

0

我認爲最好的辦法是使新方法private。這正是紅寶石Singleton模塊的功能。 Singleton Module Documentation

class A 
    private_class_method :new 
end 

class B < A 
    public_class_method :new 
end