Mniej oczywiste części Ruby - Klasy

Poniżej wklejam treść posta z mojego bloga, który można znaleźć pod adresem www.benol.pl - tutaj ten pseudo-artykuł ma szansę znaleźć czytelników :slight_smile:

Jeżeli ktoś zajmuje się Ruby na poważnie to z pewnością wie jak “działają” klasy w tym języku, ale może trafi się ktoś, kto znajdzie w tym poście coś nowego. Otóż podstawową sprawą jest zrozumienie faktu, że klasy są to obiekty typu Class, na ogół przypisane do stałych, ale nie zawsze:

String.class # => Class Napis = String "cokolwiek".is_a? Napis # => true
Klasy można również przypisywać do zmiennych:

moj_typ = (rand > 0.5) ? Array : String kontener = moj_typ.new kontener << "foobar"
Z bliżej nieznanych nikomu przyczyn w Ruby można też nadpisywać stałe (sic!), więc można zrobić na przykład tak:

String = Array "cokolwiek".is_a? String # => false
Wypada zauważyć, że “zepsucie” tak kluczowej klasy jak String najprawdopodobniej bardzo szybko doprowadzi do DUŻEGO błędu :smiley:

Wypada też omówić tzw. class methods w Ruby. Jak zapewne wam wiadomo, w Ruby możne definiować metody dla konkretnego obiektu:

obj = Array.new def obj.foo; "foo"; end obj.foo # => "foo"
Jako że klasy też są obiektami (typu Class) można zdefiniować metody dla owych obiektów, które w takim wypadku stają się class methods (metodami statycznymi) odpowiedniej klasy:

def Array.to_s "tablica" end [1,2,3].to_s # => "tablica"
Można taką metodę zdefiniować gdziekolwiek, ale kod jest czytelniejszy kiedy robi się to wewnątrz definicji klasy (można wtedy użyć skrótu self):

def MojTyp def self.bar "bar" end end MojTyp.bar #=> "bar"
To tyle - co nieco o różnych metodach monkey-patching czyli zmienianiu działania istniejących klas, następnym razem :slight_smile:

[oki@michal2~]$lynx -dump http://www.benol.pl

REFRESH(8 sec): [1]http://home.pl

Obsługę techniczną [2]domeny zapewnia [3]home.pl - największy w Polsce
rejestrator domen i dostawca profesjonalnych rozwiązań hostingowych.

Copyright © 1997-2007 [4]home.pl. All Rights Reserved.
Kontakt: [5]info@home.pl, 0801 445555, 091 4325555

References

Visible links

  1. http://home.pl/
  2. http://home.pl/
  3. http://home.pl/
  4. http://home.pl/
  5. mailto:info@home.pl

Hidden links:
6. http://home.pl/
[oki@michal2~]$

Ciekawe, ciekawe, w railsach pisales? :>

pociagne temat… wie moze ktos jak zrobic rzutowanie w gore ?
zwykle to wyglada tak:

Personel extends Osoba{}

Osoba t = new Osoba();
r = (Personel) t;

z gory dzieki

A po co miałbyś to robić?

Według mojej wiedzy w Ruby nie da się odzyskać metod “przesłoniętych” przez klasę dziedziczącą po bazowej (chyba że zostawiła ona aliasy). Poza tym w Ruby nie sprawdza się typów, więc rzutowanie na ogół nie jest potrzebne.

He, he. Troche juz nie jestem w temacie, ale w javie tez nie widze w tym zadnego sensu. Raczej programuje sie do interfejsow aby latwo podmienic w razie potrzeby implementacje (np. List - LinkedList na ArrayList). Polimorfizm powinien wystarczyc ale explicit Downcasting czasami moze sie przydac. Upcasting zazwyczaj przebiega automatycznie i nie powinno sie na sile z tym kombinowac. Dobieranie sie do przeslonietych metod superimplementacji imho przeczy idei dziedziczenia - jak mam SamochodSportowy extends Samochod i wywolam dodajGazu to dlaczego ma mi sie zachowywac jak ‘zwykly’ Samochod :slight_smile:

W ruby to moze wygladac tak (za benolem http://benol.pl/2007/09/06/mniej-oczywiste-czesci-ruby-monkey-patching/)

irb(main):026:0> class Osoba; def hey; "Osoba"; end; end => nil irb(main):027:0> class Personel < Osoba; def hey; "Personel"; end; end => nil irb(main):028:0> p = Personel.new => #<Personel:0xb7a044cc> irb(main):029:0> p.hey => "Personel" irb(main):030:0> p.class.send(:define_method, :hey) { || super } => #<Proc:0xb79fa0e4@(irb):30> irb(main):031:0> p.hey => "Osoba"
Dobrze jest zachowac i przywrocic po uzyciu oryginalna met. z Personel, czyli np.

irb(main):044:0> hey = p.method :hey irb(main):053:0> p.class.send(:define_method, :hey, hey)
Ale jak wspomnialem nie widze ku temu zadnych zastosowan.

Z tym “super” to oczywiście masz rację - zupełnie o tym nie pomyślałem, jako że “super” zawsze kojarzyło mi się z konstruktorami. Problem polega na tym, że jeżeli metoda hey wywołuje jakąkolwiek inną metodę, która została przeciążona w klasie pochodnej, to wywołana zostanie wersja przeciążona (co w przypadku konstruktorów ma sens). Krótko mówiąc próbując robić takie sztuczki sam prosisz się o kłopoty :smiley: