1.4.1.1. fejezet, Stringek, számok, osztályok és objektumok
A Ruby-ban programozás egyszerű. Nem típusos, kis/nagybetű megkülönböztető (myvar és myVar között van különbség), gets az egyszerű szöveg bevitelre, print, puts (sortörést tesz a string végére) az egyszerű kiírásra való.
print( 'Enter your name: ' ) name = gets() puts( "Hello #{name}" )
Nincs változó deklaráció, vagy tipus megadás. A gets után a zárójel kirakása nem kötelező, habár megkönnyíti a különbségtételt változó és metódushívás között.
Stringek és beágyazott kiértékelés
Az utolsó parancsnál puts( "Hello #{name}" )
a name változó beágyazódik, értékét a stringbe írja ki. Ez a #{} kifejezés a macskaköröm ("") jelek között kiértékeli a benne megadott kifejezést, ami lehet összetett is. Pl.:
puts( "\n\t#{(1 + 2) * 3}\nGoodbye" )
A szimpla idézőjelek ('') közé írva nincs ilyen kiértékelés. A macskakörmök közt a \n és \t is működik, sortörést és tabulátorjelet tesz a stringbe.
Számok
Az alábbiakban áfát számolunk, és megismerkedünk a to_f string metódussal
#!/usr/bin/ruby # Ez egy megjegyzes taxrate = 0.175 print "Enter price (ex tax): " s = gets subtotal = s.to_f tax = subtotal * taxrate # Ez is egy megjegyzés. puts "Tax on $#{subtotal} is $#{tax}, so grand total is $#{subtotal+tax}"
A string objektum metódusa a to_f, amivel törtszámmá alakítunk egy stringet. Ha nem megy az átváltás, 0.0-t kapunk. pl.: “Hello world”.to_f értékét. A program elejére egy megjegyzés került az értelmező elérhetőségével, majd a következő sorba egy egyszerű kommentár. A # jel után bárhova egy sornyi megjegyzés írható. Az alábbi pedig egy többsoros megjegyzés:
=begin
This is a
multiline
comment
=end
Kifejezés kiértékelése, if..then
taxrate = 0.175 print "Enter price (ex tax): " s = gets subtotal = s.to_f if (subtotal < 0.0) then subtotal = 0.0 end tax = subtotal * taxrate puts "Tax on $#{subtotal} is $#{tax}, so grand total is $#{subtotal+tax}"
Ha ez if feltételben megadott kifejezés igaz, lefut a következmény blokk (subtotal = 0.0). A then kulcsszót akkor kötelező kiírni, ha egy sorban van a feltétel a következmény blokkal. Tehát:
if (subtotal < 0.0) then subtotal = 0.0 end
Ezzel egy-két sorral rövidebb a kód, de az áttekinthetősége rovására. Ugyanis ha a következmény részben több kifejezést zsúfolunk, pontosvesszővel (;) kell elválasztanunk azokat egymástól. Az if után az end viszont nem opcionális.
Lokális és globális változók
A subtotal, tax és taxrate változók, kisbetűvel kezdődnek, ezért lokális változók (main), $ jelöli a globális változókat. Pl.:
localvar = "hello" $globalvar = "goodbye" def amethod localvar = 10 puts( localvar ) puts( $globalvar ) end def anotherMethod localvar = 500 $globalvar = "bonjour" puts( localvar ) puts( $globalvar ) end amethod puts anotherMethod puts amethod puts puts( localvar ) puts( $globalvar )
Eredménye:
10 goodbye 500 bonjour 10 bonjour hello bonjour
Osztályok és objektumok
Most ahelyett, hogy belemennénk a részletekbe a procedurális nyelveknél megszokott kifejezések értelmezésében, úgy mint az típusok, iteráció, modulok, gyorsan tegyünk egy pillantást az osztályok és objektumok világába. Az osztály a lenyomata egy objektumnak. Definiálja a tulajdonságait, adat tagjait, a metódusain keresztül a viselkedését. Az osztályból készíthetők aztán a példányok. Így egy Macska osztályból lehet több cica objektum, mint mirmur, kandurbandi és micike. A metódus olyan mint egy függvény vagy eljárás, csak az osztályban definiáljuk, és a példányok tulajdonságain lehet dolgozni ezekkel.
Az olyan OOP nyelvek igen elterjedtek, mint a C++, C#, Object Pascal, Java, stb. A Ruby megszállottan objektum orientált. Amíg nem programoztál Smalltalk vagy Eiffel nyelveken, amik még inkább azok. Még az operátorok, mint a + és - műveletek is azok.
x = 1 + 2
Itt a + jel metódusa a Fixnum objektumnak (Integer), és az = jel itt a kivétel, amin nem egy metódus, hanem egy beépített izé (ez nem a legjobb meghatározása, nem meghatározott valami).
Most nézzük, hogyan definiálja a Ruby az osztályokat. Készítsünk egy kutya osztályt
class Dog def set_name( aName ) @myname = aName end end
Itt észrevehető, hogy az osztály definíció a class kulcsszóval kezdődik (kisbetűvel). Az osztálynév nagybetűvel kezdődik, és egy set_name metódusnév is van a def kulcsszó mögött. Zárójelbe mögötte a metódus argumentuma, majd a metódus blokk, amiben egy @ jel után az objektum myname tulajdonságának adunk értéket
Példány változók, avagy objektum tulajdonságok
Nem szükséges elő-deklarálni az objektum tulajdonságokat. Lehet egy metóduson belül is az új változó, mint az előző set_name metódusban. Példányosítani az osztályt a new metódussal lehet. Most készítsünk két kutyát, és ne feledjük, hogy az osztály nagybetűs, a példány változó kisbetűs.
mydog = Dog.new yourdog = Dog.new
Ebben a pillanatban a két kutyának nincsen neve. Szóval a következő lépésként nevezzük el őket.
mydog.set_name( 'Fido' ) yourdog.set_name( 'Bonzo' )
Az egységbe zárás elve szerint a belső tulajdonságokat nem lehet kívülről elérni, módosítani vagy lekérdezni, csak kívülről hívható metóduson keresztül. Ezért írjunk a kutya osztályhoz egy lekérdező metódust is.
def get_name return @myname end
A return kulcsszó itt nem szükségszerű. Ha elhagyjuk, a Ruby a blokkok végén az utoljára kiadott kifejezéssel dolgozik. Most, hogy van kutya osztályunk, adjunk hozzá még egy metódust, a talk formájában. Az így létrehozott osztályunk a következő:
class Dog def set_name( aName ) @myname = aName end def get_name return @myname end def talk return 'woof!' end end
Mostmár a létrehozott kutyánknak tudunk nevet adni, és szóra bírhatjuk.
mydog = Dog.new mydog.set_name( 'Fido' ) puts(mydog.get_name) puts(mydog.talk)
Nos, van egy kutya és egy macska osztályunk. Annyi különbséggel, hogy a kutya azt mondja woof!, a macska pedig hogy miaow.
class Cat def set_name( aName ) @myname = aName end def get_name return @myname end def talk return 'miaow!' end end
Készítsünk néhány példányt belőlük
# --- Create instances (objects) of the Dog and Cat classes mydog = Dog.new yourdog = Dog.new mycat = Cat.new yourcat = Cat.new someotherdog = Dog.new # --- Name them mydog.set_name( 'Fido' ) yourdog.set_name( 'Bonzo' ) mycat.set_name( 'Tiddles' ) yourcat.set_name( 'Flossy' ) # --- Get their names and display them # Dogs puts(mydog.get_name) puts(yourdog.get_name) # hmmm, but what happens here if the dog has no name? puts(someotherdog.get_name) # Cats puts(mycat.get_name) puts(yourcat.get_name) # --- Ask them to talk puts(mydog.talk) puts(yourdog.talk) puts(mycat.talk) puts(yourcat.talk)
Hoppá, úgy tűnik a someotherdog kutyának nem adtunk nevet. Hogy ne forduljon ilyen elő többet, erre nézünk később megoldást.
Üzenetek, metódusok és többalakúság (polimorfizmus)
A mintaprogram egyébként hasonlít egy klasszikus Smalltalk demóra, ami megmutatja hogy az azonos üzenetre (talk) hogyan válaszolhatnak különbözőképp az objektumok (mint pl. a macska és a kutya). Ezt nevezik polimorfizmusnak az OOP nyelvek.
Apropó! Kódrészek a Ruby-ban nem csak úgy léteznek, vagy futnak. Van egy main objektum, ami egységbe zárja a kódrészeket, és ez az objektum az első és utolsó, ami létrejön és felszámolódik a programrészek futása során. Próbáljuk csak ki a következőket:
puts self puts self.class
Eredmény:
main Object
Az előbbi program a kutya és macska osztállyal elég sok ismétlést tartalmaz. Elég lenne egy állat osztály (Animal), aminek lenne egy név beállítás és lekérdezés metódusa, és ezt egészítené ki két osztály, a kutya (Dog) és a macska (Cat), ami tud beszélni (talk). Ezt valósítjuk meg a második fejezetben.
Konstruktorok, a new és az initialize
Tanulmányozzuk a következő osztályokat és viselkedésüket
class Thing def set_name( aName ) @name = aName end def get_name return @name end end class Treasure def initialize( aName, aDescription ) @name = aName @description = aDescription end def to_s # override default to_s method "The #{@name} Treasure is #{@description}\n" end end thing1 = Thing.new thing1.set_name( "A lovely Thing" ) puts thing1.get_name t1 = Treasure.new("Sword", "an Elvish weapon forged of gold") t2 = Treasure.new("Ring", "a magic ring of great power") puts t1.to_s puts t2.to_s # Az inspect metódus, ami betekintést enged az objektumba puts "Inspecting 1st treasure: #{t1.inspect}"
Van itt egy új metódus, az initialize, ami két argumentumot kap: @name és @description (név és leírás). Mikor egy osztálynak van initialize metódusa, a new példányosítás után ez fog lefutni. Ez azért jó, mert több objektum létrehozásakor nem kell minden tulajdonságnak értéket adni, hanem az initialize metódusban kaphatnak alapértelmezett értéket, másrészt pedig nem lesz sose olyan tulajdonsága az objektumoknak, ami ne kapna értéket (itt utaltam a someotherdog kérdéses nevére). Végül pedig felülírtuk a to_s metódust, amivel string formába alakítható egy objektum. A to_s metódusnév nem véletlen, ugyanis az összes ősosztálya a kincs osztálynak (Treasure) ezzel alakítja magát string formára. Azzal, hogy definiáltuk, felülírtuk a viselkedését a leszármazott osztályokban.
Objektumok megfigyelése
Láttuk, hogyan lehet betekinteni az osztályokba. A t1.inspect metódus teszi ember számára olvashatóvá a t1 objektumot.
#<Treasure:0x28962f8 @description="an Elvish weapon forged of gold", @name="Sword">
Ugyanezt érhetjük el a p() metódussal.
p( anobject )
Többek közt ezekről, és ezek részleteiről lesz szó a következő fejezetekben.
- A hozzászóláshoz be kell jelentkezni