2012-07-18 15 views
39

Yakutta, modül işlevlerinin burada gösterildiği gibi module_function'u kullanarak modülde karıştırma olmadan kullanılabilir olduğunu anlıyorum. Bunun nasıl faydalı olduğunu görebiliyorum, böylece modülde karıştırma olmadan fonksiyonu kullanabilirsiniz.ruby ​​module_function vs modülü dahil

module MyModule 
    def do_something 
    puts "hello world" 
    end 
    module_function :do_something 
end 

Sorglum, neden bu iki yolun her ikisini de tanımladığınıza sahip olmak isteyebilirsiniz.

Neden sadece

def MyModule.do_something 

YA durumlarda ne tür yılında

def do_something 

o karışık olması kullanılabilir işlevi olması veya statik bir yöntem olarak kullanılabilir faydalı olacaktır sahip ?

cevap

35

Enumerable'u düşünün.

Bu, bir modülde ne zaman eklemeniz gerektiğine dair mükemmel bir örnektir. Sınıfınız #each'u tanımlarsa, bir modül ekleyerek (#map, #select, vb.) Çok fazla iyilik elde edersiniz. Modülleri miks olarak kullandığım tek durum budur - modül, modülde dahil ettiğiniz sınıfta tanımlanan birkaç yöntem açısından işlevsellik sağlar. Bunun genel olarak tek durum olması gerektiğini söyleyebilirim. "Statik" yöntemleri tanımlayan gelince

, daha iyi bir yaklaşım olacaktır:

module MyModule 
    def self.do_something 
    end 
end 

Gerçekten #module_function aramaya gerek yoktur. Bence sadece tuhaf eski şeyler.

module MyModule 
    extend self 

    def do_something 
    end 
end 

... ama aynı zamanda bir yere modülü dahil etmek istiyorsanız iyi çalışmaz:

Hatta yapabilirsiniz. Ruby meta programlamasının inceliklerini öğrenene kadar bundan kaçınmanızı öneriyorum.

Son olarak, sadece yaparsanız:

def do_something 
end 

... küresel bir fonksiyonu olarak sona olmayacak, ama Object özel bir yöntem olarak (hayır fonksiyonlar, Ruby sadece yöntem vardır). İki olumsuz taraf var. İlk olarak, ad boşluğuna sahip değilsiniz - aynı ada sahip başka bir işlev tanımlarsanız, daha sonra değerlendirdiğiniz kişi budur. İkincisi, #method_missing açısından uygulanan bir işlevselliğe sahipseniz, Object'da özel bir yönteme sahip olmak onu gölgeleyecektir. Ve son olarak, Object yama maymunvari kötü iş :) olduğunu

DÜZENLEME:

module_functionprivate benzer bir şekilde kullanılabilir:

module Something 
    def foo 
    puts 'foo' 
    end 

    module_function 

    def bar 
    puts 'bar' 
    end 
end 

Bu şekilde, Something.bar çağırabilir, ancak Something.foo değil. Bu çağrıdan sonra module_function'a başka herhangi bir yöntem tanımlarsanız, bunlar karıştırılmadan da kullanılabilirlerdi.

İki nedenden dolayı beğenmiyorum.İlk olarak, hem karışık hem de "statik" yöntemlere sahip olan modüller biraz tehlikeli geliyor. Geçerli davalar olabilir, ama o kadar sık ​​olmayacak. Dediğim gibi, bir modülü bir ad alanı olarak kullanmayı veya karıştırmayı tercih ediyorum, ancak ikisini de değil. Bu örnekte bar,İkinci olarak, bu örnekte Something'da bulunan sınıflar/modüller için kullanılabilir. Yöntemin, self'u kullandığı ve karıştırılmasının gerekip gerekmediği ve karıştırılmasının gerekmediğinden emin olamadığımdan emin değilim.

module_function'u kullanmadan kullanmayı düşünüyorum. Yöntemin adı ile çok daha sık kullanılır. Aynı şey private ve protected için geçerlidir.

+0

Açıklama için teşekkürler. Neden bir modülde karıştırmak istediğinizi anlıyorum, bu soru modül_fonksiyonunu gerçekte ne zaman kullanabileceğinizi sorguluyordu. Gerçekten kullanabileceğin zaman var mı? –

+2

Bu son örnekte 'module_function' ile bir daha yakalama daha var:" foo "nun" private "işlevi" bar "içinden erişilemiyor, çünkü" foo "o zaman bir örnek metodu ('self' içermiyor) ve sadece bu modül bir sınıfta karıştırıldığında çağrılabilir. Sadece isim verme amaçları için bağımsız bir modül olduğunda imkansız. Peki ikisine nasıl sahip olunur? Modül sadece ad-boşluk kullanımı ve bazı uygulama yardımcı işlevlerini dış dünyadan gizlemek için kullanılır, ancak bunların arabirim yöntemleriyle çağrılmasına izin verir misiniz? – SasQ

12

Bir Ruby kütüphanesinin dahili durumu (fazla) kullanmayan işlevler sunması iyi bir yoldur. Yani (örneğin) bir sin işlevini sunmak istiyorsanız ve "global" (Object) ad alanını kirletmek istemiyorsanız, onu bir sabit (Math) altında sınıf yöntemi olarak tanımlayabilirsiniz. Bununla birlikte, matematiksel bir uygulama yazmak isteyen bir uygulama geliştiricisi, her iki satıra da sin gerekebilir. Yöntem aynı zamanda bir yöntem ise, yalnızca Math (veya My::Awesome::Nested::Library) modülünü ekleyebilir ve artık doğrudan sin (stdlib örneği) olarak adlandırılabilir.

Kitaplığı, kullanıcıları için daha rahat bir hale getirmekle ilgilidir. Kütüphanenizin işlevselliğini en üst düzeyde istiyorlarsa, kendileri seçebilirler.

Bu arada, module_function gibi benzer bir işlevsellik kullanarak aşağıdakileri gerçekleştirebilirsiniz: extend self (modülün ilk satırında). Zihnime göre, daha iyi görünüyor ve anlamak için işleri biraz daha netleştiriyor.

Güncelleme:this blog article. Eğer bir çalışma örneği inceleyelim kronik gem kontrol etmek istiyorsanız

+3

[ruby styleguide] (https://github.com/bbatsov/ruby-style-guide#classes--modules) '' module_function'' '' '' 'self'' uzatma '' tercih eder. – zhon

+3

İşaretçi için teşekkürler. Yine de buna katılmıyorum. 'module_function' yeni başlayanlar için daha dostça olabilir, ancak ciddi Ruby yapan herkes 'kendini genişlet' versiyonunu okuyabilmeli ve anlayabilmelidir. 'kendini uzat' daha az soyutlamadır.Ruby'nin temel araç setini kullanırken, “module_function” Ruby'den önemli işlevler kaybetmeden kaldırılabilir. –

+0

Sebeplerinizi verdiğiniz için teşekkür ederiz. Bu Q/A'yı okumadan önce, 'self.method'' ve' 'class << self'' kullanıyorum. – zhon