2012-09-25 19 views
9

Örnekler değişkenlerini Mixin olarak kullanılmak üzere bir modülde başlatmak için temiz bir yol var mı? - Bu hafif tahriş olduğunu ben her @member düzgün her fonksiyonunda başlatıldı eğer tekrar tekrar kontrol etmek zorundaÖrnek değişkenleri Mixins içinde başlatılıyor

module Example 

    def on(...) 
    @handlers ||= {} 
    # do something with @handlers 
    end 

    def all(...) 
    @all_handlers ||= [] 
    # do something with @all_handlers 
    end 

    def unhandled(...) 
    @unhandled ||= [] 
    # do something with unhandled 
    end 

    def do_something(..) 
    @handlers  ||= {} 
    @unhandled ||= [] 
    @all_handlers ||= [] 

    # potentially do something with any of the 3 above 
    end 

end 

Uyarı: Örneğin, ben şu var. Yazmayı çok isterim:

module Example 

    def initialize 
    @handlers  = {} 
    @unhandled = [] 
    @all_handlers = [] 
    end 

    # or 
    @handlers = {} 
    @unhandled = [] 
    # ... 
end 
Ve tekrar tekrar doğru şekilde başlatıldığından emin olmak zorunda değilsiniz. Ancak, bunu anlatabildiğimden mümkün değil. initialize_me yöntemini Example'a ekleyerek ve genişletilmiş Sınıftan initialize_me'u çağırmanın yanı sıra bunun çevresinde herhangi bir yolu var mı? this example'u gördüm, ancak bunu gerçekleştirmek için hiçbir şeyi Class numaralı adama ekleyemem.

cevap

12
module Example 
    def self.included(base) 
    base.instance_variable_set :@example_ivar, :foo 
    end 
end 

Düzenleme: Bu bir sınıf örneği değişken ayarlama unutmayın. Örnekte örnek değişkenler, modül sınıfla karıştırıldığında oluşturulamaz, çünkü bu örnekler henüz oluşturulmamış. Sen, ancak,

module Example 
    def self.included(base) 
    base.class_exec do 
     def initialize 
     @example_ivar = :foo 
     end 
    end 
    end 
end 

dahil sınıfın initialize yöntemini çağırarak ederken bunu yapmanın bir yolu olabilir .:, mixin içinde örneğin bir initialize yöntemi oluşturabilir (herkes?). Emin değil.

class Foo 
    include Example 

    def initialize 
    @foo = :bar 
    after_initialize 
    end 
end 

module Example 
    def after_initialize 
    @example_ivar = :foo 
    end 
end 
+0

Mükemmel, teşekkürler - Bu konuda bir milyonlarca makale olmasına rağmen neden bir yerde bahsedilen bu yaklaşımı görmediğimi merak ediyorum. –

+0

Ne yazık ki bu işe yaramıyor gibi görünüyor - 'example_ivar' referansı 'nil' olarak geri geliyor. –

+0

Ah, anladım, teşekkürler - ancak bu, eğer sınıf zaten bir "initialize" yöntemi kullanıyorsa sorunlara neden olur, değil mi? –

2

modulesModule#included olarak, kancalar sağlamaktadır: Ama burada bir alternatiftir. Konuyla ilgili ruby ​​dokümanı kontrol etmenizi veya modüllerdeki bazı yardımcıları sağlayan ActiveSupport::Concern'u kullanmanızı öneririm.

+0

'ActiveSupport' kullanmıyorum, ancak beni doğru yönde işaretlediğiniz için teşekkürler. –

+0

rica ederim. – ksol

1

Belki de bu biraz hacky, ancak istenen davranışı elde etmek prepend kullanabilirsiniz:

2.1.1 :011 > A.new 
=> #<A:0x00000101131788 @instance_var=[]> 
+0

Ekleme yerine ekleme kullanmak için herhangi bir olumsuzluk var mı? –

+0

Düşünebildiğim bir dezavantajı, modülün hiyerarşide sınıfın altına yerleştirilmesidir. Normalde, bizim tür hiyerarşimiz 'A Max

+0

tamam :) İyi "hazır" bu konuda oldukça açıklayıcıdır, bu yüzden çözümünüzü beğendim (ve kullandım), teşekkürler! (+ 1'ledi) –

0

Bir olabileceğini düşünüyorum: Burada

module Foo 
    def initialize(*args) 
    @instance_var = [] 
    super 
    end 
end 

class A 
    prepend Foo 
end 

konsolundan çıkışı buna daha basit bir cevap. Modül, normalde yaptığınız gibi değişkenleri başlatan bir başlatıcıya sahip olmalıdır. Modülü içeren sınıfın başlatıcıda, dahil edilen modülde başlatıcıyı çağırmak için super() öğesini çağırın. Bu, Ruby'deki yöntem gönderme kurallarını takip etmektir.

Yansımayla ilgili olarak, modül de dahil olmak üzere sınıfın da başlatılması gereken bir üst sınıfı varsa, bu çok işe yaramaz. Modüldeki başlatıcı, değişken parametre listesini kabul etmeli ve bunu üst sınıfa geçirmelidir. Yine de keşfetmek için iyi bir cadde gibi görünüyor.

İlgili konular