5. Još malo o metodama

Imali smo, do ovog momenta, priliku vidjeti nekoliko metoda, -puts- i –gets- i tako dalje (Nagradno pitanje: možete li pobrojati sve metode s kojima smo se do sada upoznali? Ima ih deset; a odgovor koje su – slijedi.), ali nismo puno govorili o tome šta su zapravo metode. Znamo šta one rade, ali ne znam još uvijek šta one zapravo jesu.

Ustvari to i jeste njihova suština – da rade koješta u programima koje pišemo. Ako u Ruby kao jeziku objekte (kao što su strings, integers, floats) predstavimo kao imenice, onda su metode vrlo slične glagolima. Baš kao i u jeziku, ne možete imati glagol, a da nemate određenu imenicu koja će ga izvršiti (radnju). Na primjer, „kucanje“ nije nešto što se jednostavno dešava; moraćemo imati sat koji to radi. U jeziku bismo mogli reći da „sat kuca“. Kad bi tu situaciju trebalo prevesti u Ruby, onda bismo naveli u kodu clock.tick (pretpostavljajući da je clock objekat u Ruby). Programeri bi najvjerovatnije rekli da su pozvali metodu tick, objekta clock ili . . . „nad objektom clock smo pozvali metodu tick“.

Jeste li odgovorili na nagradno pitanje? Dobro. Siguran sam da ste se sjetili metoda –puts-, -gets- i –chomp-, iz razloga što smo ih nedavno naučili i ponovili mnogo puta. Garant ste se sjetili i metoda za pretvorbu -to_i-, -to_s-, -to_f-. Međutim, jeste li uspjeli dokučiti koje su preostale četiri? Ma haj'te, pa to nije ništa drugo nego naši dobri stari drugovi [+], [-], [*] i [/] – matematički operatori.

Kao što sam već rekao, svaki glagol treba svoju imenicu, pa tako i svaki objekt treba neku metodu. Obično je vrlo lahko reći koji objekat izvršava metodu; to je onaj koji stoji ispred tačke, kao u našem primjeru clock.tick, ili na primjer 101.to_s. Ponekad, međutim, nije sve tako očito; kao što je slučaj sa aritmetičkim metodama. Kako to i izgleda, napisati 5 + 5 je samo kraći način od pisanja 5.+ 5; na primjer

puts 'hello '.+ 'world'

puts (10.* 9).+ 9

Ispis:

hello world

99

Ovako postaviti aritmetičke metode nije baš najljepše, tako da ih mi nikad nećemo pisati u ovom obliku; važno je, međutim, razumjeti šta se ustvari događa. (Na mom računaru, došlo mi je i upozorenje „parenthesize argument(s) for future versions“ – „argumente ubuduće stavi u zagrade“! Iako je pokrenuo moj program bez problema, računar me je ipak upozorio da ne zna šta sam želio reći ovim kodom i tražio je od mene da u budućnosti manje koristim zagrade.)

Ovaj nam primjer takođe objašnjava zašto možemo pomnožiti žabu peticom, ali ne možemo peticu pomnožiti žabom. 'žaba' * 5, govori 'žabi' da učini množenje, a 5 * 'žaba' govori petici da to učini. 'žaba' zna kako da napravi pet svojih kopija i da ih doda jedne drugima; međutim, petica će ipak imati daleko više problema praveći 'žaba' svojih kopija i onda ih dodati jedne drugima.

Naravno, ostaje nam štošta objasniti što se metoda –puts- i –gets- tiče. Gdje su njihovi objekti (ispred)? U jeziku koji govorimo, kao što i sami znate, ponekad možemo izostaviti imenicu; na primjer ako VILLAIN govori „Umri!“, imenica na koju se ukazuje na onoga na koga se on dere. U Ruby, ako ja kažem - puts 'to be or not to be' – to ustvari znači –self.puts 'to be or not to be'.– Šta je pa sad self? Self je specijalna varijabla/promjenjiva koja pokazuje na onaj objekat u kome se nalazite. Još uvijek mi ne znamo šta znači biti u objektu, ali dok ne spoznamo, treba reći da ćemo uvijek biti u jednom velikom objektu koji je... sam program koji smo napisali je objekat! Sreća naša, sam program ima svoje metode, kao što su –puts- i –gets-. Vidi ovo:

iCantBelieveIMadeAVariableNameThisLongJustToPointToA3 = 3

puts iCantBelieveIMadeAVariableNameThisLongJustToPointToA3

self.puts iCantBelieveIMadeAVariableNameThisLongJustToPointToA3

Ispis:

3

3

Ako niste upratili baš sve kako treba, nema veze. Važno iz svega zaključiti da je svaka metoda izvršena od strane nekog objekta, čak i ako nema tačke ispred objekta. Ukoliko ste shvatili, onda smo spremni da idemo dalje.

Zanimljive metode namijenjene znakovima (string)

Haj'te da naučimo par zanimljivih metoda koje tretiraju znakove (stringove). Ne morate ih sve učiti napamet; jednostavno pogledajte ovu stranicu ponovo ako ih zaboravite. Namjera mi je pokazati vam samo jedan dio onoga što možete učiniti sa znakovima (stringovima). Da budem iskren, ni ja sam ne mogu upamtiti polovinu metoda koje tretiraju string – ali nema veze, jer postoje izvrsne reference na internetu, izlistane i sa detaljnim objašnjenjima o njihovoj primjeni. (Uputit ću vas na linkove na kojima ćete naći liste metoda.) Uistinu, ja i ne želim da znam sve te metode; to nekako dođe kao znati sve riječi iz riječnika. Mogu govoriti engleski solidno i bez poznavanja sve do jedne riječi koja je napisana u riječniku...uostalom to je poenta riječnika...zar ne? Ono što mi u njemu ne znamo je njegova poenta, inače nam ne bi trebao.

Dakle, prva metoda na koju ćemo obratiti pažnju je –reverse-, metoda kojia će nam dati obrnuti redoslijed znakova u nekom stringu.

var1 = 'stop'

var2 = 'stressed'

var3 = 'Can you pronounce this sentence backwards?'

puts var1.reverse

puts var2.reverse

puts var3.reverse

puts var1

puts var2

puts var3

Ispis:

pots

desserts

?sdrawkcab ecnetnes siht ecnuonorp uoy naC

stop

stressed

Can you pronounce this sentence backwards?

Kao što i sami možete vidjeti, -reverse- ne „izvrće” izvorni string, nego pravi novu „rikverc” verziju istog. Iz tog razloga var1 ostaje 'stop' čak i nakon što smo pozvali metodu –reverse- nad njom. U nizu metoda je i metoda –lenght-, koja nam govori koliko znakova (uključujući i razmake, prazne prostore) ima određeni string:

puts 'What is your full name?'

name = gets.chomp

puts 'Did you know there are ' + name.length + ' characters in your name, ' + name + '?'

Ispis:

What is your full name?

Christopher David Pine

#<TypeError: can't convert Fixnum into String>

Uh! Uh! Nešto je izgleda krenulo po zlu, a desilo se nakon linije name = gets.chomp... Možete li uočiti gdje u čemu je problem? Pokušajte otkriti?

Problem je nastao sa metodom –length- : ona kao rezultat daje broj, a ono što mi želimo je string. Ništa lakše, jednostavno ćemo na čitav izraz nabaciti metodu -to_s-

( i prekrstit' prste [/] držat' fige ):

puts 'What is your full name?'

name = gets.chomp

puts 'Did you know there are ' + name.length.to_s + ' characters in your name, ' + name + '?'

Ispis:

What is your full name?

Christopher David Pine

Did you know there are 22 characters in your name, Christopher David Pine?

Ma nemoj mi reći,…toliko slova u mom imenu,…nisam znao.

Napomena: broj koji je program ispisao je ukupan broj znakova u ovom stringu (name), a ne broj slova koje moje ime sadrži (eto prebroj'te ih). Mogli bismo napisati i program koji pita ime, srednje ime, prezime (svako posebno) i onda sabira broj slova svakog od njih...hej! pa zašto to nebiste sami napravili! Hajde, šta čekate!?

Jeste li? Dobro! Fin programčić, zar ne? Nakon par poglavlja poslije ovoga, bićete i sami začuđeni onim što ćete znati da programirate.

Postoji takođe i par metoda koje mogu mijenjati kapitalizaciju slova (malo/veliko slovo) koja se nalaze u nekom od vaših stringova. Metoda –upcase- pretvoriće sva mala slova u velika, a metoda –downcase- sva velika u mala slova. Nadalje, metoda –swapcase- pravi inverziju stringa, jer slova koja su velika pretvara u mala, a ona koja su mala pretvara u velika . . . i konačno –capitalize- je metoda slična metodi –downcase-, s razlikom da na početak stringa stavlja veliko slovo (ako su slova u pitanju).

letters = 'aAbBcCdDeE'

puts letters.upcase

puts letters.downcase

puts letters.swapcase

puts letters.capitalize

puts ' a'.capitalize

puts letters

Ispis:

AABBCCDDEE

aabbccddee

AaBbCcDdEe

Aabbccddee

a

aAbBcCdDeE

To je već standarno, očekivano. Primetićete da u liniji „puts ' a'.capitalize“, metoda –capitalize- samo pretvara u veliko slovo početni znak, ne prvo slovo [ k.p. : koje je u ovo slučaju razmak ]. Takođe, kao što sam to i ranije napominjao, uprkos pozivanju raznih metoda, izvorna slova ostaju nepromijenjena. Nemam namjeru biti dosadan s ponavljanjem, ali je važno da to shvatite. Postoje metode koje mijenjaju objekt koji ih izvršava, ali mi nismo još došli do njih,...i nećemo tako brzo.

Poslijednja od ovih zanimljivih metoda odnosi se na uređivanje izgleda ispisa. Prva od njih, –center-, dodaje razmake na početku i kraju stringa da bi ga postavila u sredinu - centrirala.

Međutim, baš onako kako morate reći metodi –puts- šta želite ispisati, ili metodi [+] šta želite dodati/sabrati, tako i metodi –center- morate reći kolika širina tog razmaka treba da bude.

Dakle, ako bih htio centrirati stihove iz jedne pjesme, učinio bih slijedeće:

lineWidth = 50

puts( 'Old Mother Hubbard'.center(lineWidth))

puts( 'Sat in her cupboard'.center(lineWidth))

puts( 'Eating her curds an whey,'.center(lineWidth))

puts( 'When along came a spider'.center(lineWidth))

puts( 'Which sat down beside her'.center(lineWidth))

puts('And scared her poor shoe dog away.'.center(lineWidth))

Ispis:

Old Mother Hubbard

Sat in her cupboard

Eating her curds an whey,

When along came a spider

Which sat down beside her

And scared her poor shoe dog away.

Hmmm,…nisam siguran koliko je ova rima pogodna, ali mi je lijeno sad voditi računa o tome.

(Htio sam takođe izravnati i dio linije .center lineWidth, te sam zbog toga stavio razmake ispred stringa. Mislio sam da će tako ljepše izgledati. Programeri su vrlo često kritični kad je u pitanju šta je „lijepo na oko“ u programu i često ćete naići na različite stavove. Što više uđete u programiranje, sve više ćete razvijati neki svoj stil.) Kad smo kod lijenosti, u programiranju ona nije uvijek tako loša. Vidite li, na primjer, kako sam ja smjestio dužinu linije u varijablu lineWidth? Kad bih kasnije htio učiniti linije širim, jedino bih morao mijenjati prvu liniju u programu tj. varijablu, a ne svaku vrijednost koja radi centriranje. Ako bi ovo bio neki veći program, onda bi mi ovaj potez uštedio dosta vremena. Ova vrsta lijenosti u programiranju je zaista vrlina.

Kako vam se čini centriranje...primjetićete da nije baš onako lijepo kako to izgleda u nekim uređivačima teksta. Ako je savršeno centriranje ono što želite (i možda malo ljepši font), onda biste jednostavno trebali koristiti neki uređivač teksta! Ruby je sjajan alat, ali nijedan alat nije pravi alat za baš sve poslove.

Preostale metodu su nam –ljust- i –rjust-, koje pozicioniraju tekst na lijevu ili desnu stranu razvlačeći ga cijelom širinom linije. Slični su metodi –center-, osim što pomiču string razmacima nalijevo, odnosno nadesno, respektivno. Hajde da ih vidimo na djelu:

lineWidth = 40

str = '--> text <--'

puts str.ljust lineWidth

puts str.center lineWidth

puts str.rjust lineWidth

puts str.ljust (lineWidth/2) + str.rjust (lineWidth/2)

Ispis:

--> text <--

--> text <--

--> text <--

--> text <-- --> text <--

Par stvarčica za oprobati

    • Napišite program koji će se zvati „Ljuti šef“. Trebao bi vas pitati šta želite. Šta god da mu odgovorite, „Ljuti šef“ bi trebao vikati na vas i onda vas otpustiti. Na primjer, ukoliko napišete „Želim da mi povećate platu.“, on bi vikao: „Želim da mi povećate platu!? To želiš!? E otkaz je ono što ćeš dobiti!“

Evo jednog zadatka koji će omogućiti da se malo poigrate metodama za formatiranje teksta (-center-, -ljust- i –rjust-).

    • Napišite program koji će napraviti sadržaj ovog tutoriala kao što je prikazano u ispisu:

Table of Contents

Chapter 1: Numbers page 1

Chapter 2: Letters page 72

Chapter 3: Variables page 118

Viša matematika

( Naredni dio ovog poglavlja je potpuno neobavezan. Pretpostavlja se za one koji ga žele čitati da imaju solidno znanje iz matematike. Ukoliko niste zainteresovani, možete odmah krenuti dalje, na „Kontrola toka“, bez ikakvih problema. Međutim, bilo bi korisno da makar bacite pogled na dio koji se odnosi na generisanje brojeva metodom slučajnog uzorka, moglo bi vam nekad zatrebati. )

Postoji približno isti broj metoda za brojeve, kao i za string objekte (iako ih ja ne znam sve napamet, kao i prethodne). U ovom kratkom dijelu ćemo sagledati ostatak aritmetičkih metoda, vidjeti kako izgleda generator slučajnih brojeva, Math objekat, sa svojim trigonometrijskim i transcendentalnim metodama.

Više aritmetike

Dvije metode s kojima ćemo započeti ovaj dio su [**] (eksponencija) i [%] (modulus – ostatak nakon dijeljenja). Dakle, ako želite reći Ruby „pet na kvadrat“, onda biste trebali napisati izraz 5 ** 2. U proračunima možete takođe koristiti i float objekte za opis eksponenta na koji podižete brojeve, pa ćete u tom slučaju, ako želite naći kvadratni korijen od pet napisati 5 ** 0.5. Metoda za modulus daje vam rezultat ostatak nakon dijeljenja dva broja. Na primjer, ako dijelim 7 sa 3, onda kao rezultat dobijem 2 i ostatak 1. Da vidimo kako to izgleda u programu:

puts 5**2

puts 5**0.5

puts 7/3

puts 7%3

puts 365%7

Ispis:

25

2.23606797749979

2

1

1

Iz poslijednje linije smo naučili da godina ima prilično veliki broj sedmica, plus jedan dan. Ako je vaš rođendan bio u utorak ove, slijedeće godine bi trebao pasti u srijedu. Sa metodom [%] mogu se takođe koristiti i float objekti. U suštini, radi na jedini mogući osjetljivi način za njega,...ali taj ću dio ostaviti vama, da se malo igrate.

Pomenut ću samo još jednu metodu prije nego pređemo na generator slučajnog broja: -abs-. Ta metoda jednostavno računa apsolutnu vrijednost broja:

puts((5-2).abs)

puts((2-5).abs)

Ispis:

3

3

Slučajni brojevi

Ruby ima prilično zgodan generator slučajnog broja (random). Metoda koja pomaže da se dobije neki slučajni broj je –rand-. Ako pozovete tu metodu bez specifikacije, onda ćete dobiti slučajni float koji će vrijednosno biti smješten ili jednak od 0.0 do 1.0. Međutim, ako metodi –rand- pridružite neki integer (recimo 5), daće vam kao rezultat integer veći ili jednak nuli, a manji od petice (dakle, pet mogućih brojeva, od 0 do 4).

Pogledajmo sada –rand- u akciji. [k.p. Ukoliko na originalnom tutorialu učitate ovu stranicu ponovo, brojevi će se promijeniti svaki put kad ih učitate.] (...pa znali ste da sam sve ove programe, osim što sam ih napisao, pokrenuo/izvršavao na računaru, zar ne?)

puts rand

puts rand

puts rand

puts(rand(100))

puts(rand(100))

puts(rand(100))

puts(rand(1))

puts(rand(1))

puts(rand(1))

puts(rand(99999999999999999999999999999999999999999999999999999999999))

puts('The weatherman said there is a '+rand(101).to_s+'% chance of rain,')

puts('but you can never trust a weatherman.')

Ispis:

0.593474785354615

0.660763674309727

0.422511416882603

78

27

38

0

0

0

91506176963496451620599165354140390470043157669278537593542

The weatherman said there is a 100% chance of rain, but you can never trust a weatherman.

Zamijetit ćete da sam koristio rand(101) da bih dobio za rezultat brojeve između 0 i 100; ali i da će za rand(1) rezultat uvijek biti 0. Nerazumijevanje vrijednosti koje bi se mogle očekivati kao rezultat je jedna od najvećih grješaka koje ljudi prave sa metodom –rand-, pa čak i profesionalni programeri; na nekim proizvodima koji su plasirani na tržište mogu se uočiti takve grješke. Ima sam čak jednom neki CD player, pa kad bih stavio muziku na „random play“ modus, mogao sam preslušati sve pjesme osim posljednje...(pitam se šta bi se desilo da sam imao CD na kome se nalazila samo jedna pjesma?)

Ponekad će biti potrebno da –rand- ispiše iste slučajne brojeve istim redoslijedom na sva različita izvršenja programa. (Na primjer, jednom sam korisito slučajne brojeve da generišem slučajno/spontano mapu za računarsku igru. Ako bih naišao na mapu koja bi mi odgovarala, htio bih je igrati ponovo, ili bih je mogao poslati prijatelju.) Da bismo postigli navedeno, treba postaviti SEED, što se može učiniti deriviranom metodom –srand-. 'vako to se radi:

srand 1776

puts(rand(100))

puts(rand(100))

puts(rand(100))

puts(rand(100))

puts(rand(100))

puts ''

srand 1776

puts(rand(100))

puts(rand(100))

puts(rand(100))

puts(rand(100))

puts(rand(100))

Ispis:

24

35

36

58

70

24

35

36

58

70

Svaki put kad ga SEEDATE istim brojem, program će dati isti rezultat. Ukoliko želite dobiti drukčije brojeve (što bi se desilo da uopšte nismo koristili –srand-) onda jednostavno pozovite srand 0. Ovakav SEED koristi stvarno čudan broj, koji između ostalo može dati i trenutno vrijeme na vašim računarima, do u milisekundu.

„Math“ objekat

Konačno, da vidimo šta je taj „Math“ objekat. Možda je najbolje da odmah uskočim u primjer:

puts(Math::PI)

puts(Math::E)

puts(Math.cos(Math::PI/3))

puts(Math.tan(Math::PI/4))

puts(Math.log(Math::E**2))

puts((1 + Math.sqrt(5))/2)

Ispis:

3.14159265358979

2.71828182845905

0.5

1.0

2.0

1.61803398874989

Prva stvar koju ćete vjerovatno primjetiti je [::] – dupla dvotačka. Objasniti „scope operator” (što je upravo njegov opis) stvarno je izvan, hm…domašaja ovog tutoriala. Nemam namjeru vrijeđati. Kunem se. Ne treba posebno naglašavati da Math::PI daje upravo onaj rezultat koji smo i očekivali.

Kao što vidite, Math objekat radi one stvari koje bismo očekivali od nekog dobrog naučnog kalkulatora/digitrona. Kao i uvijek, float je uglavnom rezultat operacija koje tretira ovaj objekat. Hajde sada, da „tečemo“!

-----------------------------------------------

© 2003-2009 Chris Pine

http://pine.fm/LearnToProgram/