Ruby poskytuje konstrukt nazvaný Module
což je něco jako tenká Třída. Zpočátku se Ruby devs může dívat na moduly jako na „nevyžádanou zásuvku“ kódu, který je právě hozen a používán k uspořádání souborů, ale k tomuto šílenství existuje metoda. Ruby třídy Class
dědí z Module
a přidává věci jako instance, vlastnosti, atd – všechny ty věci, které by normálně si myslím, že třída bude mít. Protože Module
je doslova předkem Class
, znamená to, že moduly mohou být v některých ohledech považovány za třídy.
nejdůležitější je pochopit, jak funguje řetězec Ruby ancestor. Stejně jako všechny jazyky OOP, Ruby podporuje dědičnost. Když zdědíte z třídy, supertřída se přidá do řetězce předků. Můžete zobrazit předků nějaké třídy voláním ancestors
na to:
class Foo < BarendFoo.ancestors#=>
Jak již bylo zmíněno, můžete najít Module
v poli Class.ancestors
.
když include
modul do vaší třídy, modul je přidán do řetězce předků vaší třídy-stejně jako třída. To dělá include
jen formou dědičnosti, na tom není nic zvláštního.
module Barendclass Foo include BarendFoo.ancestors#=>
Všechny metody v Bar
jsou přidány do Foo
jako metody instance. Protože Bar je v řetězci, můžete dokonce volat super
z něj volat metody nad ním v řetězci, ať už jsou definovány na modulech nebo třídách.
class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world
I když Bar
je modul, super
stále volá do řetězce a tak Baz#hello
je také nazýván. Stojí za zmínku, že Bar
je přidán do řetězce předků před Baz. Je-li součástí modulu, je vždy přidán přímo na vrcholu je včetně třídy. To může být matoucí při přidávání více modulů, protože jsou zahrnuty v „obráceném“ pořadí:
class Foo include A include BendFoo.ancestors#=>
Pokud je zahrnut A
, je vložen přímo nad Foo
. Ale když je zahrnuta B
, je také vložena přímo nad Foo
, takže skončí přistání před A
.
include vs extend
include
je dostatečně snadné pochopit, přidává metody modulu jako metody instance do třídy včetně. Můžete si myslet, že extend
dělá totéž, ale místo toho přidává metody jako metody třídy.
module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'
prepend
kromě include/extend, Ruby 2.0 + přidá metodu prepend
prepend
je podobný include
, ale místo toho vloží modul před třídu including v řetězci dědičnosti.
class Foo include Bar prepend BazendFoo.ancestors#=>
V Ruby můžete re-otevřít všechny třídy a předefinovat metody na to – to nebude zdát užitečné pro přepsání metody třídy pomocí předřazen modul jako protiklad k předefinování. Kde prepend
přijde vhod, je, když budete ještě potřebovat původní implementace metody, protože předřazen moduly mohou přepsat metody, ale stále používat super
volat původní implementaci.