logi sisse meist KKK

Seletades kuulajatele Ruby klasside ehitust, metaprogrammeerimist jmt, tekkis endalgi küsimus järgneva koodilõigu kohta, mida kohe ei suutnud ära vastata:

class A
  def self.m1
    puts "M1"
  end

  class << self
    def m2
      puts "M2"
    end

    def self.m3
      puts "M3"
    end
  end
end

Küsimus: kuidas kutsuda välja meetod m3?

A.m1           # => m1
A.m2           # => m2
A.m3           # => NoMethodError: undefined method `m3' for A:Class
A.class.m3     # => NoMethodError: undefined method `m3' for Class:Class

Vihjeks niipalju, et maagia peitub Ruby operaatoris <<.

PS. tegemist kah nuputamisülesandega, mis mulle lihtsalt põnev tundus, kuid mille vastust ma ise juba (nüüdseks) tean.

küsitud May 11 '11 at 13:09

Laas's gravatar image

Laas
413

silt muudetud Aug 03 '11 at 13:33

dig's gravatar image

dig
17415

Tundub, et vastustega just ei kiirustata. ;-) Enne kui vastuse lisan, annan veel ühe vihje: meetod 'm3' lisati Class objekti A Singleton klassile instantsimeetodiks. Nüüd küsimus, kuidas sellele Singleton klassile ligi pääseda?

(May 12 '11 at 15:32) Laas

Kuna vastust ei laekunud, siis pean ilmselt ise ära vastama. Vastus ise on lühike, enamus on lihtsalt pikem selgitus, kuidas ja miks.

Lühem variant on:

class << A; m3; end
# => M3

Pikem variant, mis natuke ka selgitab, miks see töötab:

singleton_class = class << A; self; end
singleton_class.m3
# => M3

Suusõnaliselt: meetod 'm3' defineeriti klassi A singleton klassi singleton klassi.

Seletus: kogu Ruby maailm koosneb objektidest. Ka klassid ise on objektid (instantsid klassist Class). Ükski objekt pole kunagi suletud ja alati on võimalik neile täiendusi juurde teha. Kasvõi ühele ainukesele instantsile meetodit lisada:

a = A.new
def a.m4
  # ...
end

Selline meetodi definitsioon tekitab uue meetodi punktiga viidatud objekti a_ sisse. Samast klassist tehtud teistele objektidele see välja ei paista. Siinkohal on hea tähele panna, et teistest keeltest tuntud _klassimeetodeid kui selliseid Rubys ei ole. Tühja kohta täidab meetodi definitsioon def self.m1, mis defineerib hoopis instantsimeetodi objektile self, mis sel hetkel (klassi defineerimise ajal) viitab klassi objektile endale, defineerides seega meetodi m1 klassi enda kui objekti "sisse", ilma, et see teistele klassidele (objektidele klassist Class) välja paistaks.

Kuidas on aga võimalik, et üks meetod kuulub vaid ühele instantsile, mitte kõigile sama klassi objektidele? Ruby keeles on see lahendatud anonüümsete singleton klassidega (mitte segi ajada Singleton mustriga) - vajaduse tekkimisel lisatakse objektile uus ananüümne ülemklass, mis on ise alamklass algsest klassist. Nimi tuleneb sarnaselt Singleton mustrile asjaolust, et sellest klassist luuakse vaid üks objekt. Klasside põlvnemine visuaalselt:

a  < SingletonClass1 < A
a2 < SingletonClass2 < A

Kõik laiendavad meetodid lisataksegi selle singleton klassi definitsiooni, nii et need saavad sellest klassist loodud ühe objekti osaks, kuid ei kuulu algse klassi A definitsiooni, seega ei paista välja teistele sama klassi objektidele.

Kõik järgnevalt toodud koodiread avavad või tekitavad singleton klassi ning defineerivad meetodi selle klassi kirjelduses. Huvitav on märgata, et mitmed neist leiavad kasutust igapäevaselt, ilma, et singleton klasside olemasolu üldse oleks vaja teada:

# otsene meetodi definitsioon ühele objektile
def a.m4
end

# mooduliga laiendamine
a.extend(M)

# objekti piires koodi käivitamine, mis defineerib meetodi
a.instance_eval("def m5; end")

# avab märgendist '<<' paremale jääva objekti singleton klassi
# ja defineerib selle sisse meetodi
class << a
  def m6
  end
end

Küsimuses kasutatigi just seda viimast konstruktsiooni 'class << a', kus avati objekti 'self' singleton klass.

Lõpuks siis küsimuse kood kommenteeritud kujul:

class A
  # klassi A definitsioon, 'self' on objekt klassist Class, nimega A
  # Avame objekti 'self' singleton klassi
  class << self
    # Singleton klassi definitsioon, 'self' on anonüümne objekt klassist Class
    # objekti A ülemklass

    # laiendame seda objekti meetodiga 'm3', mis defineeritakse 
    # järjekordses anonüümses signleton klassis, eelmise singletoni ülemklassis
    def self.m3
    end
  end
end

Graafiliselt väljendudes:

A < SC   < SC'   < Class
    m1     m3
    m2
link

vastatud May 16 '11 at 12:42

Laas's gravatar image

Laas
413

Sinu vastus
toggle preview

Jälgi seda küsimust

By Email:

Once you sign in you will be able to subscribe for any updates here

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *italic* or __italic__
  • **bold** or __bold__
  • link:[tekst](http://url.com/ "pealkiri")
  • pilt?![alt tekst](/path/img.jpg "pealkiri")
  • nummerdatud nimekiri: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • basic HTML tags are also supported

Pinu tööpakkumised

kõik pakkumised »

Sildid:

×7
×5
×2

küsitud: May 11 '11 at 13:09

nähtud: 818 korda

viimati uuendatud: Aug 03 '11 at 13:33

Litsents: Creative Commons Attribution License | Kontakt: info@pinu.ee