A Ruby egy Module
nevű konstrukciót biztosít, amely olyan, mint egy vékony osztály. Először a Ruby devs olyan modulokat nézhet, mint egy kód “szemétfiókja”, amelyet csak a fájlok rendezésére használnak, de van egy módszer erre az őrületre. A Ruby osztályClass
örökli aModule
és hozzáad dolgokat, mint például példányosítás, tulajdonságok, stb – minden dolog, amit általában gondolnánk egy osztály volna. Mivel a Module
szó szerint aClass
őse, ez azt jelenti, hogy a modulok bizonyos szempontból osztályokként kezelhetők.
a legfontosabb megérteni, hogyan működik a Ruby őslánc. Mint minden OOP nyelv, a Ruby is támogatja az öröklést. Amikor egy osztályból örököl, a szuperosztály hozzáadódik az őslánchoz. Bármely osztály őseit megtekintheti a ancestors
hívásával rajta:
class Foo < BarendFoo.ancestors#=>
mint említettük, megtalálható Module
a tömbben Class.ancestors
.
amikor include
egy modult az osztályába, a modul hozzáadódik az osztály ősláncához – akárcsak egy osztály. Ez teszi a include
csak az öröklés egyik formáját, nincs benne semmi különös.
module Barendclass Foo include BarendFoo.ancestors#=>
a Bar
összes metódusa hozzáadódik a Foo
példány metódusként. Mivel a Bar a láncban van, akkor is hívhat super
belőle a fenti módszerek meghívására a láncban, függetlenül attól, hogy modulokon vagy osztályokon vannak-e meghatározva.
class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world
annak ellenére, hogy Bar
egy modul, super
még mindig felhívja a láncot, így Baz#hello
is nevezik. Érdemes megjegyezni, hogy Bar
hozzáadódik a BAZ előtti őslánchoz. Ha egy modult tartalmaz,akkor mindig közvetlenül hozzáadódik az osztályhoz. Ez zavaró lehet több modul hozzáadásakor, mivel ezek “fordított” sorrendben vannak:
class Foo include A include BendFoo.ancestors#=>
Ha a A
tartalmazza, akkor közvetlenül a Foo
fölé kerül. De amikor a B
szerepel, akkor közvetlenül aFoo
fölé is beillesztésre kerül, így végül aA
előtt landol.
include vs extend
include
elég könnyű megérteni, hozzáadja a modul módszereit példány metódusként az osztályhoz. Gondolhat arra, hogy extend
ugyanazt csinálja, hanem a metódusokat osztály metódusként adja hozzá.
module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'
prepend
Az include/extend mellett a Ruby 2.0+ hozzáadja aprepend
módszert. prepend
hasonló a include
– hez, de ehelyett beszúrja a modult az including osztály elé az öröklési láncban.
class Foo include Bar prepend BazendFoo.ancestors#=>
A Ruby-ban bármely osztályt újra megnyithat, és újradefiniálhatja a rajta lévő metódusokat – nem tűnik hasznosnak az osztály metódusainak felülbírálása egy előregyártott modul használatával, szemben az újradefiniálással. Ahol aprepend
akkor hasznos, ha még mindig szüksége van a módszer eredeti megvalósítására, mert az előregyártott modulok felülbírálhatják a módszereket, de továbbra is használjáksuper
az eredeti megvalósítás meghívásához.