Ruby oferă o construcție numităModule
care este un fel de clasă subțire. La început, Ruby devs s-ar putea uita la module ca un „sertar junk” de cod, care este doar aruncat în jurul și utilizate pentru a organiza fișiere, dar există o metodă de această nebunie. Clasa RubyClass
moștenește de laModule
și adaugă lucruri precum instanțierea, proprietățile etc. – toate lucrurile pe care în mod normal credeți că le-ar avea o clasă. Deoarece Module
este literalmente un strămoș alClass
, aceasta înseamnă că modulele pot fi tratate ca clase în anumite moduri.
cel mai important pentru a înțelege este modul în care funcționează lanțul strămoș Rubin. Ca toate limbile OOP, Ruby acceptă moștenirea. Când moștenești dintr-o clasă, superclasa este adăugată lanțului tău strămoș. Puteți vizualiza strămoșii oricărei clase apelând ancestors
pe ea:
class Foo < BarendFoo.ancestors#=>
după cum sa menționat, puteți găsi Module
în matrice Class.ancestors
.
cândinclude
un modul în clasa dvs., modulul este adăugat la lanțul strămoș al clasei dvs. – la fel ca o clasă. Acest lucru face include
doar o formă de moștenire, nu există nimic special în acest sens.
module Barendclass Foo include BarendFoo.ancestors#=>
toate metodele dinBar
sunt adăugate laFoo
ca metode de instanță. Deoarece bara este în lanț, puteți apela chiar super
de la acesta pentru a apela metode deasupra acestuia în lanț, indiferent dacă sunt definite pe Module sau clase.
class Baz def hello p 'world' endendmodule Bar def hello p 'hello' super endendclass Foo < Baz include BarendFoo.new.hello#=> hello world
chiar dacăBar
este un modul,super
încă apelează lanțul și astfelBaz#hello
se mai numește. Este demn de remarcat faptul că Bar
se adaugă lanțului strămoș în fața Baz. Atunci când un modul este inclus, acesta este întotdeauna adăugat direct pe partea de sus a acesteia, inclusiv clasa. Acest lucru poate deveni confuz atunci când adăugați mai multe module, deoarece acestea sunt incluse în ordinea ” inversă:
class Foo include A include BendFoo.ancestors#=>
cândA
este inclus, acesta este introdus direct deasupraFoo
. Dar când B
este inclus, este introdus și direct deasupra Foo
, deci ajunge să aterizeze înainte de A
.
include vs extinde
include
este destul de ușor de înțeles, se adaugă metodele modulului ca metode de instanță pentru a include clasa. Vă puteți gândi la extend
făcând același lucru, dar adăugând în schimb metodele ca metode de clasă.
module Bar def hello p 'hello' endendclass Foo extend BarendFoo.hello # no .new!# => 'hello'
prepend
pe lângă includerea/extinderea, Ruby 2.0+ adaugă metodaprepend
prepend
este similar cu include
, dar în schimb introduce modulul înainte de clasa inclusiv în lanțul de moștenire.
class Foo include Bar prepend BazendFoo.ancestors#=>
în Ruby puteți redeschide orice clasă și redefini metodele de pe ea-nu pare util să înlocuiți metodele pe o clasă folosind un modul prepended, spre deosebire de redefinirea lor. Undeprepend
vine la îndemână este atunci când mai aveți nevoie de implementarea inițială a metodei, deoarece modulele prefabricate pot suprascrie metodele, dar încă folosescsuper
pentru a apela implementarea inițială.