Spis treściKliknij link, aby przejść do wybranego miejsca
Ta treść została automatycznie przetłumaczona z ukraińskiego.
W module Ruby można organizować kod, ale czasami trzeba, aby metoda była dostępna zarówno dla instancji modułu, jak i bezpośrednio z modułu (jak funkcja). W tym celu używa się module_function.
Jak działa module_function
- Uczynia metodę prywatną dla instancji modułu (przeczytaj tutaj o private).
- Dodaje także "modułową kopię" metody, którą można wywołać bez tworzenia obiektu.
module MathHelper
def square(x)
x * x
end
module_function :square
end
Teraz można wywołać metodę bezpośrednio przez moduł:
MathHelper.square(5) # => 25
Lub używać jej wewnątrz innych metod modułu (jak prywatnej):
module MathHelper
def cube(x)
square(x) * x
end
module_function :cube
end
MathHelper.cube(3) # => 27
Cecha
Prywatna dla instancji modułu:
include MathHelper square(5) # => NoMethodError (bo square stał się prywatny)
Odpowiednia dla narzędzi
module_function często używa się w "statycznych narzędziach", aby nie tworzyć obiektu modułu do wywołania funkcji.
Krótko mówiąc:
- module_function czyni metodę jednocześnie:
- Prywatną dla instancji (poprzez include)
- Dostępną jako funkcję przez moduł
MathHelper.square(5) # działa include MathHelper square(5) # błąd
To wygodne dla modułów, które mają zestaw narzędzi, jak w standardowych bibliotekach Ruby (Math, Enumerable na przykład).
Ale jeśli zwrócisz uwagę na punkt - prywatna dla instancji (poprzez include), możesz zapytać, co z extend i prepend (o tych metodach pisałem tutaj)?
- Metoda modułu staje się prywatna dla instancji i dostępna przez sam moduł.
- Wywołanie przez include nie działa bezpośrednio (metoda jest prywatna).
- Wywołanie przez extend działa jak metoda klasowa.
- Wywołanie przez prepend nie działa na obiekcie (metoda jest prywatna).
Wciąż trudno zrozumieć? Przyjrzyjmy się temu bardziej szczegółowo:
module_function robi dwie rzeczy jednocześnie:
-
Prywatna dla instancji
- Jeśli dołączasz moduł (include) lub robisz prepend, metoda staje się prywatna dla wszystkich obiektów, co oznacza, że nie możesz jej wywołać po prostu tak: obj.method - będzie błąd.
- Ruby tak robi, aby nie można było przypadkowo wywołać tej metody na instancji.
-
Dostępna przez sam moduł
- Ruby tworzy kopię metody na poziomie modułu.
- Dlatego można wywołać: ModuleName.method - działa to jak "funkcja statyczna".
Prosty przykład:
module Utils
def greet
"Hello"
end
module_function :greet
end
# Przez moduł można
Utils.greet # => "Hello"
# Przez include — nie można, bo prywatna
include Utils
greet # => błąd NoMethodError
- Dlaczego extend działa? extend dodaje metody modułu do singleton class klasy lub obiektu. Tam metoda jest wywoływana przez klasę/obiekt, a nie przez instancję, więc działa.
- Dlaczego prepend nie działa? prepend wstawia metodę w łańcuch przodków, ale oryginalna metoda pozostaje prywatna -> obiekt nie może jej wywołać bezpośrednio.
Ten post nie ma jeszcze żadnych dodatków od autora.