Ruby giver en konstruktion kaldet a Module
som er lidt som en tynd klasse. I første omgang kan Ruby devs se på moduler som en” junk skuffe ” af kode, der bare smides rundt og bruges til at organisere filer, men der er en metode til denne vanvid. Ruby-klassen Class
arver fra Module
og tilføjer ting som instantiation, egenskaber osv. – alle ting, du normalt ville tro, at en klasse ville have. Fordi Module
er bogstaveligt talt en forfader til Class
, betyder det, at moduler kan behandles som klasser på nogle måder.
det vigtigste at forstå er, hvordan Ruby ancestor-kæden fungerer. Som alle OOP-sprog understøtter Ruby arv. Når du arver fra en klasse, tilføjes superklassen til din forfædrekæde. Du kan se forfædrene til enhver klasse ved at ringe ancestors
på den:
class Foo < BarendFoo.ancestors#=>
Som nævnt kan du findeModule
i arrayetClass.ancestors
.
Når du include
et modul i din klasse, tilføjes modulet til din klasses forfædrekæde – ligesom en klasse. Dette gør include
bare en form for arv, der er ikke noget særligt ved det.
module Barendclass Foo include BarendFoo.ancestors#=>
alle metoderne i Bar
tilføjes til Foo
som instansmetoder. Fordi Bar er i kæden, kan du endda ringe super
fra det for at kalde metoder over det i kæden, uanset om de er defineret på moduler eller klasser.
class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world
selvomBar
er et modul,super
kalder stadig kæden og såBaz#hello
kaldes også. Det er værd at bemærke, at Bar
tilføjes til forfædrekæden foran base. Når et modul er inkluderet, tilføjes det altid direkte oven på det inklusive klasse. Dette kan blive forvirrende, når du tilføjer flere moduler, da de er inkluderet i” omvendt ” rækkefølge:
class Foo include A include BendFoo.ancestors#=>
NårA
er inkluderet, indsættes den direkte overFoo
. Men når B
er inkluderet, indsættes den også direkte over Foo
, så det ender med at lande før A
.
Inkluder vs Udvid
include
er let nok at forstå, det tilføjer modulets metoder som instansmetoder til det inklusive klasse. Du kan tænke på extend
gør det samme, men i stedet tilføjer metoderne som klassemetoder.
module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'
prepend
ud over at inkludere/udvide tilføjer Ruby 2.0+prepend
metode. prepend
ligner include
, men indsætter i stedet modulet før den inkluderende klasse i arvskæden.
class Foo include Bar prepend BazendFoo.ancestors#=>
i Ruby kan du genåbne enhver klasse og omdefinere metoderne på den-det synes ikke nyttigt at tilsidesætte metoder på en klasse ved hjælp af et forudindstillet modul i modsætning til at omdefinere dem. Hvor prepend
kommer godt med, er, når du stadig har brug for den oprindelige implementering af metoden, fordi forudindstillede moduler kan tilsidesætte metoder, men stadig bruger super
for at kalde den oprindelige implementering.