Spis treściKliknij link, aby przejść do wybranego miejsca
Ta treść została automatycznie przetłumaczona z ukraińskiego.
W Ruby moduły są używane do ponownego wykorzystania kodu. Metoda dodawania modułu wpływa na to, gdzie i jak metody z modułu stają się dostępne.
include - dodaje metody jako metody instancji
- Metody modułu stają się dostępne dla wszystkich obiektów klasy.
- Używa się, gdy chce się, aby metody były w instancjach klasy.
module Greetings
def hello
"Cześć!"
end
end
class User
include Greetings
end
u = User.new
u.hello # => "Cześć!"
Metody modułu pojawiają się w łańcuchu przodków klasy (ancestors) po samej klasie, co oznacza, że można je nadpisywać w klasie. Ale przyjrzyjmy się temu dokładniej. W Ruby każda klasa ma łańcuch przodków (ancestors) - kolejność, w jakiej Ruby szuka metod przy wywołaniu na obiekcie.
module Greetings
def hello
"Cześć z modułu"
end
end
class User
include Greetings
def hello
"Cześć z klasy"
end
end
p User.ancestors
# => [User, Greetings, Object, Kernel, BasicObject]
Kiedy robisz include Greetings, Ruby wstawia moduł po klasie w łańcuchu przodków. Albo jeśli łatwiej zapamiętać - nad klasą.
To oznacza, że metody klasy przesłaniają metody modułu, jeśli mają te same nazwy.
u = User.new u.hello # => "Cześć z klasy"
Ruby najpierw szuka metody w samej klasie (User). Następnie, jeśli nie znajdzie, sprawdza moduły w łańcuchu (Greetings), a potem przodków (Object, Kernel).
extend - dodaje metody jako metody klasy
- Metody modułu stają się dostępne bezpośrednio na klasie, a nie na instancjach.
- Wygodne do dodawania "metod klasowych" bez jawnego self.method.
module Tools
def info
"Metoda klasowa!"
end
end
class User
extend Tools
end
User.info # => "Metoda klasowa!"
User.new.info # => NoMethodError
Faktycznie Ruby dodaje metody do singleton class obiektu (klasa sama w sobie - obiekt).
prepend - dodaje metody przed klasą w łańcuchu przodków
- Metody modułu pojawiają się przed klasą w łańcuchu przodków.
- To oznacza, że metody modułu mogą nadpisywać metody klasy.
module Greetings
def hello
"Cześć z modułu"
end
end
class User
prepend Greetings
def hello
"Cześć z klasy"
end
end
p User.ancestors
# => [Greetings, User, Object, Kernel, BasicObject]
Kluczowy punkt: Greetings stoi przed klasą User.
Ruby szuka metod w kolejności, którą pokazuje ancestors.
Dlatego gdy wywołujesz u.hello, Ruby najpierw widzi metodę w module Greetings, a potem w klasie User.
u = User.new u.hello # => "Cześć z modułu"
Użycie super w module
Jeśli w module wywołasz super, Ruby przejdzie dalszym łańcuchem przodków i wykona metodę klasy:
module Greetings
def hello
super + " i moduł"
end
end
class User
prepend Greetings
def hello
"Cześć z klasy"
end
end
u = User.new
u.hello # => "Cześć z klasy i moduł"
Dlaczego tak?
- Ruby wywołuje hello w module Greetings (bo jest pierwszy w ancestors).
- Tam jest super. Ruby szuka następnej metody w łańcuchu przodków, czyli w klasie User.
- Metoda klasy zwraca "Cześć z klasy", a następnie dodaje " i moduł".
Krótko mówiąc
include -> metody modułu stają się metodami instancji klasy, moduł po klasie w łańcuchu przodków.
extend -> metody modułu stają się metodami klasy lub konkretnego obiektu (singleton class).
prepend -> metody modułu stają się metodami instancji, ale przed klasą w łańcuchu przodków, co oznacza, że mają priorytet nad metodami klasy.
Ten post nie ma jeszcze żadnych dodatków od autora.