2013-08-29 9 views
5

Próbuję utworzyć prywatne metody pomocnicze dla funkcji modułu bez skutku. Czuję, że jest coś bardzo prostego, czego mi brakuje.Uzyskiwanie dostępu do prywatnych metod z funkcji modułu w Ruby

Updated przykład z bardziej zrozumiały przypadku użycia:

module FancyScorer 
    module_function 

    def score(ary) 
    scores = [] 
    ary.each_slice(2).with_index do |slice, i| 
     scores << 
     case i % 2 
     when 0 
      score_eventh(ary) 
     else 
      score_oddth(ary) 
     end 
    end 
    scores.inject(:+) 
    end 

    private 

    def score_eventh(ary) 
    ary.inject(:+)/(ary.size - 1) 
    end 

    def score_oddth(ary) 
    ary.inject(:*)/(ary.size - 1) 
    end 
end 

FancyScorer.score([1,2,3,4]) 
# => `block in score_curiously': undefined method `score_eventh' 
# for FancyScorer:Module (NoMethodError) 

Uwaga: Metody prywatne powinny pozostać prywatne.

Oto przypadek użycia: istnieje kilka modułów, które zawierają różne techniki oceniania, np. FancyScorer, SimpleScorer, ComplexScorer. Te funkcje są testowane niezależnie, a następnie są używane do utworzenia metody score dla różnych klas. Na przykład:

class A 
    ... 
    def score  
    FancyScorer.score(metrics) + 2*SimpleScorer.score(metrics) 
    end 
end 

class B 
    ... 
    def score 
    0.5*FancyScorer.score(metrics) + 2*SimpleScorer.score(metrics[0,3]) + ComplexScorer.score(metrics) 
    end 
end 

poprzednim przykładzie bez przewidzianego przypadku użycia:

module Party 
    module_function 

    def pooper 
    enjoy 
    end 

    private 

    def enjoy 
    puts "Wahoo!" 
    end 
end 

Party.pooper 
# => NameError: undefined local variable or method `enjoy' for Party:module 
#   from (party): in `pooper` 
+0

Trzeba trochę się problemu [XY] (http://www.perlmonks.org/?node_id=542341) tutaj. Powinieneś wyjaśnić swój faktyczny problem. Nieprawidłowe jest wywoływanie metod bezpośrednio w module. – naomik

+0

Przedstawiony przykład był bardzo wymyślny. Wdrażam wzór promowany przez Corey Hainesa i Gary'ego Bernhardta (co Bernhardt nazywa "funkcjonalnym rdzeniem i imperatywną powłoką"), aw niektórych przypadkach wymagam przestrzeni nazw, aby uniknąć konfliktów. – fny

+0

@faraz Dostałeś teraz? –

Odpowiedz

8

module_function(symbol, ...) → self mówi: -

Tworzy funkcje modułu dla wymienionych metod. Funkcje te mogą być wywoływane z modułem jako odbiornik, i stają się również dostępne jako metody instancji dla klas, które mieszają się w module. Funkcje modułu są kopiami oryginału i dlatego mogą być zmieniane niezależnie. Wersje metody instancji są prywatne. Jeśli używane bez argumentów, później zdefiniowane metody stają się funkcjami modułu.

Musisz upewnić się, że deklarujesz metodę pomocnika jako #private_class_method: private wpływa tylko na metody instancji.

module Party 

    def enjoy 
    puts 'hello' 
    end 

    def pooper 
    enjoy 
    end 

    private_class_method :enjoy 
    module_function :pooper 
end 

Party.pooper # => 'hello' 
Party.enjoy # => private method `enjoy' called for Party:Module (NoMethodError) 

Ponadto, należy być ostrożnym zamawiania dostępności słów kluczowych jak public, private i module_function. Nie nakładają się one, lecz zastępują.

module Party 
    module_function # Module function declarations begin 
    def pooper 
    bar 
    end 
    def bar 
    enjoy 
    end 

    private   # Private declarations begin, module function declarations end 
    module_function # Private declarations end, module function declarations begin 
    def enjoy  # Therefore, this is a module function 
    "Wahoo!" 
    end 
end 

Party.pooper # => "Wahoo!" 
Party.bar # => "Wahoo!" 
Party.enjoy # => "Wahoo!" <-- No longer private 

Uwaga tutaj module_function nadpisuje poprzednią deklarację private.


Oto kilka innych przykładów, kiedy module_function będzie wykonywać swoje zadania, a kiedy nie.

Definicje module_function zatrzymują się, gdy pojawi się inne słowo kluczowe dotyczące dostępności. W tym przykładzie module_function jest przerywane przez public tworząc #pooper metodę instancji publicznej. Używanie private podobnie blokowałoby module_method.

module Party 
    module_function 
    public 
    def pooper 
    "i am pooper" 
    end 
end 

Party.pooper 
# undefined method `pooper' for Party:Module (NoMethodError) 

Teraz, jeśli zamówienie jest zmieniony:

module Party 
    public 
    module_function 
    def pooper 
    "i am pooper" 
    end 
end 

Party.pooper # => "i am pooper" 
+0

Nie wiedziałem nawet o 'Module # module_function', ale nie mogę powiedzieć, że jestem zaskoczony. Jest to działające rozwiązanie, ale wygląda na bardzo zły skład modułów. (ps. Rozumiem, że to nie twoja wina, ponieważ to jest to, o co prosi OP). – naomik

+0

@naomik 'module_function' jest bardzo interesujący ... proszę przeczytaj dokument, możesz zrozumieć, dlaczego jest ta metoda .. Ma wiele smaków .. –

+0

po przeczytaniu dokumentów, jestem teraz bardziej przerażony. 'module_function' wydaje się świetnym sposobem na podzielenie spójności zachowania twojego modułu i dodanie mnóstwa złożoności. Musiałbym mieć nieodparty powód, by uciekać się do używania go. – naomik

2

Jeśli chcesz wywołać metody bezpośrednio na module (np Party.pooper), trzeba zdefiniować metody wykorzystujące self

module Party 
    def self.pooper 
    enjoy 
    end 

    private 

    def self.enjoy 
    puts "wahoo!" 
    end 
end 

Party.pooper #=> wahoo! 

Zasadniczo jednym głównym zadaniem modułów jest ich dodawanie do klasy przy użyciu include lub extend.

module Party 
    def pooper 
    enjoy 
    end 

    private 

    def enjoy 
    puts "wahoo!" 
    end 
end 

Oto przykład extend który pokazuje sposoby moduł dodawane jako metody klasy

class Diaper 
    extend Party 
end 

Diaper.pooper #=> wahoo! 

Oto przykład include który pokazuje sposoby moduł dodawane jako metody np

class Toilet 
    include Party 
end 

t = Toilet.new 
t.pooper #=> wahoo! 
+0

OP chciał zobaczyć o 'module_function' .. Myślę, że idziesz na niewłaściwym torze .. To nie było zadawane .. –

+1

Może, myślę, że jest bardziej prawdopodobne, że OP ma [XY Problem] (http: // www.perlmonks.org/?node_id=542341) i nie rozumie, jak właściwie używać modułów. – naomik

Powiązane problemy