Ruby tarjoaa Konstruktion nimeltä Module
, joka on tavallaan kuin ohut Luokka. Aluksi Ruby devs saattaa tarkastella moduuleja kuin ”roskalaatikkoa” koodia, jota vain heitetään ympäriinsä ja käytetään tiedostojen järjestämiseen, mutta tälle hulluudelle on olemassa menetelmä. Rubiiniluokka Class
perii Module
ja lisää siihen instantiaatiota, ominaisuuksia jne. – kaikkea, mitä luokalla normaalisti luulisi olevan. Koska Module
on sananmukaisesti Class
esi-isä, tämä tarkoittaa, että moduuleja voidaan käsitellä tietyllä tavalla luokkina.
tärkeintä on ymmärtää, miten rubiinin esi-isäketju toimii. Kuten kaikki OOP-kielet, Ruby tukee periytymistä. Kun perii luokalta, superluokka lisätään esi-isien ketjuun. Minkä tahansa luokan esi-isiä voi tarkastella kutsumalla ancestors
sillä:
class Foo < BarendFoo.ancestors#=>
kuten mainittu, Module
array Class.ancestors
.
kun include
moduuli omaan luokkaan, moduuli lisätään oman luokan esi – isäketjuun-aivan kuten luokkakin. Tämä tekee include
vain eräänlaisen perinnön, siinä ei ole mitään erikoista.
module Barendclass Foo include BarendFoo.ancestors#=>
kaikki Bar
lisätään Foo
instanssimenetelmiksi. Koska Bar on ketjussa, voit jopa kutsua super
siitä kutsumenetelmiä sen yläpuolella ketjussa, olivatpa ne määritelty moduuleilla tai luokilla.
class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world
vaikka Bar
on moduuli, super
kutsuu edelleen ketjua ylös ja niin Baz#hello
on myös ns. On syytä huomata, että Bar
lisätään Bazin edessä olevaan kantaketjuun. Kun moduuli on mukana, se lisätään aina suoraan päälle se sisältää luokan. Tämä voi saada sekava lisättäessä useita moduuleja, Koska ne sisältyvät ”Käänteinen” järjestyksessä:
class Foo include A include BendFoo.ancestors#=>
kun A
lasketaan mukaan, se lisätään suoraan Foo
. Mutta kun B
lasketaan mukaan, se lisätään myös suoraan Foo
, joten se päätyy laskuun ennen A
.
include vs extend
include
on riittävän helppo ymmärtää, se lisää moduulin menetelmät instanssimenetelminä sen sisältämään luokkaan. Voi ajatella, että extend
tekisi saman asian, mutta sen sijaan lisäisi menetelmät luokkamenetelmiksi.
module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'
prepend
include/extendin lisäksi Ruby 2.0+ lisää prepend
metodin. prepend
on samankaltainen kuin include
, mutta lisää sen sijaan moduulin perintöketjussa olevan including-luokan eteen.
class Foo include Bar prepend BazendFoo.ancestors#=>
Rubyssa voi avata minkä tahansa luokan uudelleen ja määritellä sen menetelmät uudelleen-ei tunnu hyödylliseltä ohittaa luokan menetelmiä prependoidulla moduulilla sen sijaan, että ne määriteltäisiin uudelleen. Missä prepend
tulee kätevä on silloin, kun tarvitaan vielä menetelmän alkuperäistä toteutusta, koska prependoidut moduulit voivat ohittaa menetelmät, mutta käyttävät silti super
kutsua alkuperäistä toteutusta.