Manuale Semplice Ruby
Manuale Semplice Ruby
Manuale Semplice Ruby
Introduzione a Ruby
Tesina
Corso di laurea in
Ingegneria Informatica
Anno Accademico 2009 2010
Indice
Indice 1
Introduzione 3
1. Caratteristiche generali di Ruby 5
2. Guida rapida 7
0. Come iniziare 8
1. I numeri 10
2. Le lettere 12
3. Variabili e assegnazioni 15
4. Mescoliamoli insieme 17
5. Qualcosaltro sui metodi 21
6. Controllo del flusso 27
7. Array e iteratori 34
8. Scrivere metodi propri 37
9. Le classi 50
10. Blocchi e procedure 59
3. Uso di Ruby per creare una documentazione html 67
4. Bibliografia 77
Matz ha fuso insieme parti dei suoi linguaggi di programmazione preferiti (Perl,
Smalltalk, Eiffel, Ada e Lisp) per creare un nuovo linguaggio in grado di
bilanciare programmazione funzionale con programmazione imperativa.
In molti linguaggi, i numeri e gli altri tipi primitivi non sono oggetti, ma Ruby,
seguendo lesempio di Smalltalk, d metodi e variabili di istanza a tutti i suoi
tipi. Questo rende pi facile lutilizzo di Ruby, dal momento che tutte le regole
applicabili agli oggetti si applicano, di fatto, allintero linguaggio.
Il testo utilizzato come base riferimento alla versione 1.8.4 di Ruby; attualmente
si giunti alla release 1.9.1 del programma (il changelog della versione 1.9.1 lo
si pu trovare qui: http://svn.ruby-lang.org/repos/ruby/tags/v1_9_1_0/NEWS),
ma per le caratteristiche base, a livello di codice, non vi sono grandi differenze.
La versione 1.9.1 una nuova versione di Ruby moderna, pi veloce, con
sintassi pi chiara e con supporto multilingua. Uno dei grandi difetti delle
versioni precedenti di Ruby era la lentezza. Per questo motivo, a partire da
questa versione, Ruby integra YARV (Yet another Ruby VM), una virtual
machine per linterprete che lavora producendo un byte code del file sorgente ed
interpretandolo; questa nuova tecnica unita ad altri miglioramenti ha fatto si che
i tempi di interpretazione siano notevolmente ridotti, rendendo pi performante
lesecuzione.
Questa stessa guida verr poi utilizzata come file di partenza, in formato txt, per
la conversione attraverso codice Ruby in file html.
0. Come iniziare
Quando si programma un computer, necessario parlare in un linguaggio che il computer
capisca: un linguaggio di programmazione. Ci sono decine e decine di linguaggi differenti, e
molti di questi sono eccellenti. In questa guida viene trattato il linguaggio di programmazione
Ruby.
Quando scriviamo qualcosa nel linguaggio umano, ci che viene scritto lo chiamiamo testo.
Quando scriviamo qualcosa in un linguaggio di programmazione, questo viene invece
chiamato codice. Ho inserito molti esempi di codice Ruby nella guida, la maggior parte dei
quali sono programmi completi che potete eseguire sul vostro computer. Per rendere la lettura
del codice pi immediata ho colorato differentemente le varie parti (per esempio, i numeri
sono sempre in verde). Tutto ci che si dovr digitare sar in un rettangolo bianco e
tutto ci che il programma stamper sar in un rettangolo blu.
Per poter programmare dobbiamo poter scrivere programmi ed eseguirli. Per fare questo c
bisogno di un editor di testi e di una linea di comando.
Il programma di installazione di Ruby installa anche un bel editor di testi chiamato SciTE
(Scintilla Text Editor). Per far colorare il proprio codice alla stessa maniera degli esempi di
questa guida, scarichiamo i seguenti file e copiamoli nella cartella di SciTE
(c:/ruby/scite se non stata modificata la sua locazione):
Sarebbe inoltre una buona idea quella di creare una cartella dove conservare tutti i propri
programmi. Assicuriamoci quando salviamo un programma di farlo in questa cartella.
Per ottenere la linea di comando, selezioniamo Prompt dei comandi dalla cartella Accessori
del menu avvio. Quindi spostiamoci nella cartella dove conserviamo i nostri programmi.
Per poter programmare abbiamo bisogno di poter scrivere programmi ed eseguirli. Per fare
questo c bisogno di un editor di testi e di una linea di comando.
Come editor di testi possiamo utilizzare qualunque editor al quale si familiari o con i quali
ci si trova bene. Se si utilizza TextEdit, comunque, assicuriamoci di salvare i programmi nel
formato di solo testo altrimenti i programmi non funzioneranno! Altri editor sono emacs, vi e
pico, tutti accessibili dalla linea di comando.
Altrimenti potremo installarlo in modo tale che solo il nostro utente potr utilizzarlo.
Spostiamo il file scaricato in una directory temporanea, tipo $HOME/tmp. Se il nome del file
ruby-1.8.7-p72.tar.gz, possibile estrarlo digitando tar zxvf ruby-1.8.7-
p72.tar.gz. Spostiamoci nella directory appena creata (in questo esempio, cd ruby-
1.8.7-p72).
1. I numeri
Ora che sappiamo tutto sulla configurazione siamo pronti per scrivere un programma!
Apriamo il nostro editor preferito e scriviamo la seguente riga:
puts 1+2
Introduzione a puts
puts scrive semplicemente sullo schermo quello che viene dopo di lui.
puts 3
Interi e decimali
In molti linguaggi di programmazione (e Ruby non fa eccezione) i numeri senza virgola sono
chiamati interi, e quelli con la virgola sono in genere chiamati decimali o numeri a virgola
mobile.
In pratica, molti programmi non usano i decimali, ma solo numeri interi. (Dopo tutto, nessuno
vuole leggere 7.4 email, o navigare 1.8 pagine, oppure ascoltare 5.24 delle proprie canzoni
preferite...). I decimali sono usati in ambiti accademici (esperimenti di fisica e simili) e per la
grafica 3D. Anche molti programmi che hanno a che fare con i soldi usano interi, tengono
semplicemente il conto del numero dei centesimi!
Semplice Aritmetica
Finora abbiamo ottenuto tutte le funzionalit di una semplice calcolatrice. (Le calcolatrici
usano sempre i decimali, quindi se vogliamo che il nostro computer si comporti come una
calcolatrice dobbiamo usare anche noi i decimali). Per laddizione e la sottrazione usiamo + e
- come gi detto. Per la moltiplicazione usiamo * e per la divisione /. Molte tastiere hanno
questi tasti nel tastierino numerico a destra.
Proviamo ora ad aggiungere qualcosa al nostro programma calc.rb. Scriviamo quanto segue
ed eseguiamo.
puts 1.0 + 2.0
puts 2.0 * 3.0
puts 5.0 - 8.0
puts 9.0 / 2.0
Otterremo questo:
3.0
6.0
-3.0
4.5
(Gli spazi nel programma non sono importanti; rendono solo il codice facile da leggere.)
Bene, finora nessuna grande sorpresa. Proviamo adesso con gli interi:
puts 1+2
puts 2*3
puts 5-8
puts 9/2
Uh... tranne lultimo! Quando si fa aritmetica con gli interi bisogna aspettarsi risposte intere.
Quando il computer non pu ricavare la risposta esatta non pu far altro che arrotondare.
Forse vi starete chiedendo a cosa serve la divisione tra numeri interi. Bene, immaginiamo di
andare a vedere un film e di avere solo 9 dollari. Qui a Padova si pu vedere un film al Lux
con 2 euro. Quanti film possiamo vedere? 9/2... 4 film. In questo caso di sicuro 4.5 non la
risposta giusta: non ci verr fatto vedere mezzo film e non si potr entrare solo per met per
vedere un film intero... alcune cose semplicemente sono indivisibili.
Sperimentate adesso per conto vostro con qualche programma! Per scrivere espressioni pi
complesse si possono usare le parentesi. Ad esempio:
puts 5 * (12-8) + -15
puts 98 + (59872 / (13*8)) * -52
5
-29802
Una volta finito di giocare e sperimentare con i numeri, andremo a dare unocchiata alle
lettere.
2. Le lettere
E cos adesso sappiamo tutto sui numeri, ma cosa sappiamo sulle lettere? e sulle parole? e sul
testo?
In un programma un gruppo di lettere detto stringa. (Potete pensare a delle lettere stampate
tenute insieme su uno striscione). Le stringhe saranno colorate di rosso per distinguerle
facilmente allinterno del codice. Ecco alcune stringhe:
'Ciao.'
'Ruby rocks.'
'5 il mio numero preferito... il tuo?'
Si pu notare che le stringhe possono contenere punteggiatura, cifre, simboli... oltre alle
lettere. Lultima stringa non contiene niente; perci la chiameremo stringa vuota.
Prima abbiamo usato puts per stampare dei numeri; adesso proveremo con alcune stringhe:
puts 'Ciao Mondo!'
puts ''
puts 'Addio.'
Ciao Mondo!
Addio.
Oops! Ho dimenticato di mettere uno spazio tra 'Mi piace' e 'la torta di mele'.
Gli spazi in genere non contano, ma hanno importanza allinterno delle stringhe. ( vero
quello che si dice: i computer non fanno quello che vorremmo che loro facessero, ma fanno
solo quello che gli si dice di fare.) Riproviamo ancora:
puts 'Mi piace ' + 'la torta di mele.'
puts 'Mi piace' + ' la torta di mele.'
24
1212
12 + 12
10
22222
2 * 5
Problemi
A questo punto potreste aver provato alcune cose che non funzionano. Se cos non stato
eccone alcune:
puts '12' + 12
puts '2' * '5'
You're swell!
Dato che il backslash non fa lescape della lettera 'g', ma fa lescape di s stesso, le ultime
due stringhe sono identiche: nel codice sembrano differenti ma per il computer sono la stessa
stringa.
3. Variabili e assegnazioni
Finora ogni volta che abbiamo usato puts con una stringa o con un numero, ci che abbiamo
stampato poi scomparso. Quello che intendo dire che se volevamo stampare qualcosa due
volte, avremmo dovuto scriverla due volte:
puts '...puoi dirlo ancora...'
puts '...puoi dirlo ancora...'
Sarebbe carino poterlo digitare una sola volta e poi... memorizzarlo da qualche parte.
Naturalmente possiamo farlo.
Per memorizzare la stringa nella memoria del nostro computer, bisogna dare un nome alla
stringa. I programmatori spesso chiamano questa operazione assegnazione e chiamano i nomi
variabili. La variabile pu essere costituita da una sequenza di lettere e numeri, ma il primo
carattere deve essere una lettera minuscola. Proviamo nuovamente questo programma, questa
Ogni volta che il programma fa unoperazione con myString, in realt la fa con '...puoi
dirlo ancora...'. Si pu pensare che la variabile myString punti alla stringa
'...puoi dirlo ancora...'. Ecco un esempio un po pi interessante:
Inoltre, allo stesso modo di come si assegna un oggetto ad una variabile, possibile
riassegnare un oggetto differente a quella variabile (ecco perch le chiamiamo variabili:
perch ci a cui puntano pu variare).
compositore = 'Mozart'
puts compositore + ' era "il massimo" ai suoi tempi.'
compositore = 'Beethoven'
puts 'Ma personalmente preferisco ' + compositore + '.'
Naturalmente le variabili possono puntare a ogni tipo di oggetto, non solo alle stringhe:
var = 'solo un\'altra ' + 'stringa'
puts var
var = 5 * (1+2)
puts var
Infatti le variabili possono puntare a quasi qualsiasi cosa eccetto altre variabili. Allora cosa
succede se ci proviamo?
var1 = 8
var2 = var1
puts var1
puts ''
var1 = 'otto'
puts var1
puts var2
8
8
otto
8
Come prima cosa, quando abbiamo provato a far puntare var2 a var1, la variabile ha
davvero puntato a 8 (proprio come var1). Dopodich abbiamo fatto puntare var1 a
'otto', ma dato che var2 in realt non ha mai veramente puntato var1, la variabile ha
continuato a puntare 8.
4. Mescoliamoli insieme
Finora abbiamo visto alcuni differenti tipi di oggetti (numeri e lettere), e abbiamo creato delle
variabili che puntano ad essi; la prossima cosa che faremo sar quella di prenderli e di metterli
insieme.
Abbiamo visto che se vogliamo far stampare 25 al nostro programma, il seguente programma
non va bene, poich non si possono sommare numeri e stringhe:
var1 = 2
var2 = '5'
Parte del problema sta nel fatto che il computer non sa se vogliamo ottenere 7 (2 + 5)
oppure 25 ('2' + '5').
Prima di poterli sommare abbiamo bisogno di rappresentare var1 come stringa oppure var2
come intero.
Conversioni
Per ottenere la versione stringa di un oggetto, basta aggiungere .to_s dopo di esso:
var1 = 2
var2 = '5'
puts var1.to_s + var2
Allo stesso modo, to_i ci fornisce loggetto sotto forma di intero, e to_f ci d invece la
versione decimale. Vediamo un po pi da vicino cosa fanno (e cosa non fanno) questi tre
metodi:
var1 = 2
var2 = '5'
25
7
Si pu notare che anche dopo aver convertito var1 in stringa chiamando to_s, questi punta
sempre a 2 e mai a '2'. A meno che non sia esplicitamente riassegnato var1 (il che richiede
il segno =), questo punter a 2 per tutta la durata del programma.
15.0
99.999
99
5
0
0.0
stringy
3
E ancora, seguono alcuni esempi di... insolite stringhe convertite in numeri. to_i ignora la
prima cosa che non capisce, e anche il resto della stringa da quel punto in poi. Cos la prima
stringa convertita in 5, ma le altre, che iniziano con una lettera, sono ignorate
completamente... e il computer mostra solo uno zero.
20
20
20
Perch in tutti e tre i casi viene stampata la stessa cosa? Bene, sugli ultimi due nessuna
stranezza, poich 20.to_s '20'. Ma per quanto riguarda il primo, il 20 intero? A questo
proposito, che cosa significa scrivere lintero 20? Quando scriviamo un 2 e poi uno 0 su un
pezzo di carta, noi stiamo scrivendo una stringa, non un intero. Lintero 20 il numero di dita
delle mani e dei piedi che io ho; non un 2 seguito da uno 0.
Bene, qui c il grande segreto di puts: prima di provare a scrivere un oggetto puts utilizza
to_s per ottenere loggetto sotto forma di stringa. Infatti, la s in puts sta per stringa; puts
dunque significa put string.
Questo potrebbe sembrare non molto entusiasmante adesso, ma in Ruby ci sono tantissimi tipi
di oggetti (impareremo anche come crearne di nostri!), ed divertente sapere cosa accade
quando tentiamo di usare puts su un oggetto veramente molto strano, come ad esempio
unimmagine di nostra nonna, o un file musicale o qualcosaltro. Ma questo lo vedremo
dopo...
Nel frattempo, vediamo alcuni metodi che ci permetteranno di scrivere ogni genere di
programma...
Da noi! Dalla nostra tastiera ovviamente. Poich la nostra tastiera produce solo stringhe, tutto
funziona a meraviglia. Quello che accade che gets se ne sta in attesa di leggere quello che
scriviamo fino a che non premiamo il tasto Enter. Proviamo:
puts gets
Ciao!
Ciao!
A questo punto siamo pronti per fare un programma interattivo! Scriveremo il nostro nome e
il programma ci saluter:
puts 'Ciao, come ti chiami?'
nome = gets
puts 'Ti chiami ' + nome + '? Che bel nome!'
puts 'Piacere di conoscerti, ' + nome + '. :)'
Molto meglio! Notate che nome sta puntando a gets.chomp, quindi non dovremo pi fare
nome.chomp, poich nome gi chompato.
Scrivere un programma che chiede ad una persona il suo numero preferito. Quindi il
programma aggiunge uno al numero e lo suggerisce come un migliore e pi grande
numero preferito. (Abbiate molto tatto a tale proposito.)
Ecco cosa sono effettivamente: cose che fanno cose. Se gli oggetti (come stringhe, interi, e
decimali) sono i nomi nel linguaggio Ruby, allora i metodi sono come i verbi. E, proprio
come nella lingua italiana, non si possono avere verbi senza un nome che li esegue. Ad
esempio, il ticchettio non qualcosa che semplicemente accade; un orologio (o una sveglia o
qualcosa di simile) lo produce. In italiano diremmo, Lorologio ticchetta. In Ruby
potremmo scrivere orologio.ticchetta (ovviamente assumendo che orologio un
oggetto Ruby). I programmatori potrebbero dire che abbiamo chiamato il metodo
ticchetta di orologio, oppure che chiamiamo ticchetta su orologio.
Come dicevo, cos come ogni verbo ha bisogno di un sostantivo, allo stesso modo ogni
metodo ha bisogno di un oggetto. Solitamente semplice dire quale oggetto sta eseguendo il
metodo: quello che viene prima del punto, come nel nostro esempio
orologio.ticchetta, oppure 101.to_s. A volte, comunque, non cos scontato;
come succede per i metodi aritmetici. Risulta che 5 + 5 solo un modo breve di scrivere
5.+ 5. Ad esempio:
hello world
99
Non molto gradevole, quindi non scriveremo mai in questo modo; comunque, limportante
capire cosa successo veramente. (Sulla mia macchina, che restituisce anche un warning:
warning: parenthesize argument(s) for future version. Il codice viene
eseguito correttamente, ma vengo avvertito che sta avendo problemi a capire cosa voglio dire,
e mi invita ad usare pi parentesi in futuro.) Questo ci permette di capire anche perch
possiamo scrivere 'pig'*5 ma non possiamo scrivere 5*'pig': 'pig'*5 sta dicendo a
'pig' di moltiplicarsi, mentre 5*'pig' sta dicendo a 5 di moltiplicarsi. 'pig' sa come
fare 5 copie di se stesso e sommarle tutte insieme; invece 5 potrebbe avere molta pi
difficolt a fare 'pig' copie di se stesso e a sommarle insieme.
E, naturalmente, ci sono puts e gets da spiegare. Dove sono i loro oggetti? In italiano, si
pu qualche volta sottintendere il nome; ad esempio, se un furfante urla Crepa!, il nome
implicito colui a cui sta urlando contro. In Ruby, se dico puts 'essere o non
essere', in realt sto dicendo self.puts 'essere o non essere'. Dunque cos'
self? una variabile speciale che punta alloggetto che la contiene. Non sappiamo ancora
cosa vuol dire essere contenuto un oggetto, ma fino a che non usciamo, sappiamo di essere
sempre in un grande oggetto che ... l'intero programma! E per nostra fortuna il programma ha
alcuni suoi propri metodi, come puts e gets. Date uno sguardo a questo:
3
3
La cosa importante da capire da tutto questo che ogni metodo viene eseguito da qualche
oggetto, anche se non c il punto.
var1 = 'roma'
var2 = 'enoteca'
var3 = 'Puoi pronunciare questa frase al contrario?'
puts var1.reverse
puts var2.reverse
puts var3.reverse
puts var1
puts var2
puts var3
amor
acetone
?oirartnoc la esarf atseuq eraicnunorp iouP
roma
enoteca
Puoi pronunciare questa frase al contrario?
Come si pu vedere, reverse non inverte la stringa originale; ma ne fa solo una copia
inversa. Ecco perch var1 vale ancora 'roma' anche dopo aver chiamato reverse su
var1.
Un altro metodo sulle stringhe length, che ci dice il numero dei caratteri (spazi inclusi)
nella stringa:
puts 'Dimmi il tuo nome completo...'
nome = gets.chomp
puts 'Sai che ci sono ' + nome.length + ' caratteri nel tuo nome, ' +
nome + '?'
Qualcosa andata storta, e sembra che sia accaduto qualcosa dopo la riga name =
gets.chomp... Avete riconosciuto il problema? Provate a trovarlo.
Nota: quello il numero di caratteri del mio nome, non il numero di lettere.
Ci sono anche alcuni metodi che cambiano il case (maiuscolo e minuscolo) delle stringhe.
upcase cambia ogni lettera minuscola in maiuscola, e downcase cambia le maiuscole in
minuscole. swapcase scambia il case di ogni lettera della stringa, e infine, capitalize
come downcase, con la differenza che cambia solo il primo carattere in maiuscolo (se una
lettera).
lettere = 'aAbBcCdDeE'
puts lettere.upcase
puts lettere.downcase
puts lettere.swapcase
puts lettere.capitalize
puts ' a'.capitalize
puts lettere
AABBCCDDEE
aabbccddee
AaBbCcDdEe
Aabbccddee
a
aAbBcCdDeE
Come si pu vedere, dalla riga puts ' a'.capitalize, il metodo capitalize rende
maiuscolo il primo carattere, non la prima lettera. E anche, come abbiamo visto prima, nel
chiamare questi metodi, la variabile lettere rimane immutata.
Gli ultimi metodi che vedremo servono a formattare le stringhe. Il primo, center, aggiunge
degli spazi allinizio e alla fine della stringa al fine di centrarla. Ricapitolando, a puts va
detto cosa si vuole stampare, a + cosa si vuole aggiungere, a center in che modo vogliamo
che la nostra stringa sia centrata. Quindi se vogliamo centrare le righe di una poesia dobbiamo
fare cos:
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))
Gli altri due metodi di formattazione per le stringhe sono ljust e rjust, che servono per
giustificare a sinistra e a destra. Sono simili a quello per il centro, tranne che riempiono la
stringa con degli spazi sulla destra e sulla sinistra rispettivamente. Diamo unocchiata a tutti e
tre in azione:
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)
Un po di aritmetica
Gli altri due metodi aritmetici sono ** (elevamento a potenza) e % (modulo). Per dire
Cinque al quadrato in Ruby, si pu scrivere come 5**2. inoltre possibile utilizzare i
decimali per la potenza, quindi se si desidera la radice quadrata di cinque si pu scrivere
5**0.5. Il modulo invece restituisce il resto della divisione per un numero. Se per esempio
dividiamo 7 per 3, otteniamo 2 con resto 1. Vediamolo in un programma:
25
2.23606797749979
2
1
1
Infine prima di passare a parlare dei numeri casuali c un metodo che va menzionato: abs.
D semplicemente il valore assoluto di un numero.
puts((5-2).abs)
puts((2-5).abs)
3
3
Numeri casuali
Ruby dotato di un generatore di numeri casuali molto carino. Il metodo per ottenere un
numero scelto a caso rand. Se si chiama rand si ottiene un decimale maggiore o uguale a
0.0 e minore di 1. Se si d rand ad un intero (5 per esempio), si otterr un intero maggiore
o uguale a 0 e minore di 5 (quindi cinque possibili numeri, da 0 a 4).
0.422119163813049
0.510323219568254
0.11000613088893
71
71
31
0
0
Notate che ho usato rand(101) per ottenere numeri tra 0 e 100, e che rand(1)
restituisce sempre 0. Non considerare lintervallo dei valori di ritorno lerrore pi grande
che ho visto fare dalla gente con rand; anche programmatori professionisti e anche in prodotti
finiti acquistabili. Avevo anche un lettore cd che se impostato su riproduzione casuale
faceva ascoltare tutte le canzoni ma non lultima (mi chiedo cosa sarebbe successo se
avessi messo un cd con ununica canzone?)
Si potrebbe inoltre volere che rand ritornasse gli stessi numeri casuali nella stessa sequenza
su due segmenti diversi di codice (per esempio, una volta stavo usando un generatore di
numeri casuali per creare un mondo generato casualmente per un videogioco, e se ho trovato
un mondo che mi piace particolarmente, potrei volerci giocare di nuovo o inviarlo ad un
amico). Per fare questo necessario impostare un seed, utilizzando srand:
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))
24
35
36
58
70
24
35
36
58
70
Dar sempre lo stesso risultato ogni volta che si imposta il seed con lo stesso numero. Se si
vogliono ottenere di nuovo numeri differenti (come quando non abbiamo usato srand), basta
chiamare srand 0. Questo imposta il seed con un numero davvero strano, usando lora del
computer, fino ai millisecondi.
3.14159265358979
2.71828182845905
0.5
1.0
2.0
1.61803398874989
La prima cosa che avrete notato probabilmente la notazione ::. Spiegare cosa sia al di
fuori dello scopo di questa guida sufficiente sapere che si pu usare Math::PI, proprio
come ci si aspetterebbe di usare.
Come potete vedere, Math ha tutte le caratteristiche che ci si aspetta da una calcolatrice
scientifica decente. E come sempre, i numeri decimali sono molto vicini allessere la risposta
esatta.
Metodi di confronto
Per vedere se un oggetto maggiore o minore di un altro, usiamo i metodi > e <, come qui:
puts 1 > 2
puts 1 < 2
false
true
Nessun problema. Allo stesso modo possiamo trovare se un oggetto maggiore o uguale (o
minore uguale) di un altro con i metodi >= e <=
true
false
Infine possiamo vedere se due oggetti sono uguali o no usando == (che significa sono
uguali?) e != (che significa sono diversi?). importante non confondere = con ==. =
serve a dire ad una variabile di puntare ad un oggetto (assegnazione) e == per porre la
domanda questi due oggetti sono uguali?.
puts 1 == 1
puts 2 != 1
true
true
Ovviamente possiamo anche confrontare le stringhe, che vengono confrontate secondo il loro
ordine lessicografico, che praticamente significa il loro ordine nel dizionario. cane viene
prima di gatto nel dizionario, cos:
puts 'cane' < 'gatto'
true
C un problema per: il modo con cui i computer fanno le cose, ovvero ordinano le lettere
maiuscole prima di quelle minuscole (questo il modo con cui memorizzano le lettere nei
caratteri, per esempio: prima tutte le lettere maiuscole, poi tutte quelle minuscole). Questo
significa che 'Zoo' verr prima di 'ape', quindi se vogliamo capire quale parola venga
veramente prima in un dizionario, assicuriamoci di usare downcase (o upcase o
capitalize) in entrambe le parole prima di provare a confrontarle.
Unultima nota prima di passare alle istruzioni condizionali: i metodi di confronto non
restituiscono le stringhe 'true' e 'false', ma gli oggetti speciali true e false
(ovviamente true.to_s ci dar 'true', motivo per cui puts stampa 'true'). true e
false saranno usati per tutto il tempo nel
Istruzioni condizionali
Si tratta di un concetto semplice ma potente:
puts 'Ciao, come ti chiami?'
nome = gets.chomp
puts 'Ciao, ' + nome + '.'
if name == 'Lucia'
puts 'Che bel nome!'
end
Se ci che viene dopo lif true, allora eseguiamo il codice tra lif e lend; se invece
false no.
Il codice tra if e true rientrato perch cos pi semplice tenerne traccia. Potrebbe non
sembrare molto daiuto in questo semplice programma, ma quando le cose saranno pi
complesse, far una grande differenza.
Spesso ci serve un programma che faccia una cosa se lespressione true e unaltra se
false. Questo ci che fa lelse:
un po come un bivio nel codice: eseguiamo la parte di codice per chi ha nome ==
'Luca' oppure (else) seguiamo laltra parte?
if nome == nome.capitalize
puts 'Prego si sieda, ' + nome + '.'
else
if reply.downcase == 'si'
puts 'Hmmph! Bene, si sieda!'
else
puts 'SE NE VADA!!'
end
end
Bene, oppure
Salve, e benvenuto al 7th Grade English.
Io sono la Signora Gabbard. Come si chiama?
Marco
Prego si sieda, Marco.
A volte potrebbe essere difficile cercare di capire dove vanno tutti gli if, gli else e gli
end. Cos quello che faccio io scrivere subito lend quando scrivo lif. Cos mentre stavo
scrivendo il programma sopra, questo come appariva:
puts 'Salve, e benvenuto al 7th Grade English.'
puts 'Io sono la Signora Gabbard. Come si chiama?'
nome = gets.chomp
if nome == nome.capitalize
else
end
Quindi lho riempito con dei commenti, pezzi di codice che il computer ignorer:
puts 'Salve, e benvenuto al 7th Grade English.'
puts 'Io sono la Signora Gabbard. Come si chiama?'
nome = gets.chomp
if nome == nome.capitalize
# civile
else
# si arrabbia
end
Quando diciamo a un computer di fare qualcosa ripetutamente, dobbiamo anche dire quando
fermarsi. I computer non si annoiano, cos se non gli diciamo quando fermarsi, non lo fanno e
basta. Dobbiamo essere sicuri che ci non accada dicendo al computer di ripetere certe parti
di programma mentre (while) una certa condizione vera. Funziona in modo molto simile
allif:
command = ''
Ciao?
Ciao?
Salve!
Salve!
Piacere di conoscerti.
Piacere di conoscerti.
Oh... che dolce!
Oh... che dolce!
bye
Torna presto!
E questo un ciclo. (Avrete notato la riga bianca allinizio delloutput; data dal primo
puts, prima del primo gets.)
I cicli ci permettono di fare tutte cose interessanti, come son sicuro potete immaginare.
Tuttavia possono anche causare problemi se si commettono errori. Che cosa succede se il
computer viene intrappolato in un loop infinito? In questo caso basta premere Ctrl + C.
Un po di logica
Diamo ancora unocchiata al nostro primo programma sulle istruzioni condizionali. Cosa
succede se mia moglie torna a casa, vede il programma, lo prova, e non le dice che ha un bel
nome? Non vorrei ferirle i sentimenti (o dormire sul divano), cos riscriviamolo:
puts 'Ciao, come ti chiami?'
nome = gets.chomp
puts 'Ciao, ' + nome + '.'
if name == 'Lucia'
puts 'Che bel nome!'
Bene, funziona ma non proprio un bel programma. Perch no? Bene, la regola migliore
che io abbia mai imparato nella programmazione DRY: Dont Repeat Yourself (non
ripetere), e probabilmente potrei scrivere un libretto sul perch sia una buona regola. Nel
nostro caso abbiamo ripetuto la riga puts 'Che bel nome!'. Perch questo un grosso
problema? Ebbene, cosa succede se commetto un errore di ortografia quando ho riscritto?
Cosa succede se voglio cambiare aggettivo in entrambe le righe? Io sono pigro, ricordate?
Fondamentalmente, se voglio che il programma faccia la stessa cosa quando riceve 'Lucia'
o 'Maria', allora dovrebbe realmente fare la stessa cosa:
puts 'Ciao, come ti chiami?'
nome = gets.chomp
puts 'Ciao, ' + nome + '.'
if (name == 'Lucia' or name == 'Maria')
puts 'Che bel nome!'
end
Molto meglio. Per farlo funzionare, ho usato or. Gli altri operatori logici sono and e not.
sempre una buona idea usare le parentesi quando lavoriamo con loro. Vediamo come
funzionano:
ioSonoChris = true
ioSonoBiondo = false
miPiaceMangiare = true
mangioSassi = false
true
false
false
false
true
true
true
false
true
false
Lunico di questi che pu colpirvi or. Spesso infatti usiamo o per dire uno o laltro, ma
non entrambi. Il computer usa or per dire uno o laltro, o entrambi, un altro modo di dire
sarebbe almeno uno di questi vero.
Estendere il programma Nonna Sorda: che cosa succede se la nonna non vuole che te ne
vai? Quando si dice CIAO, pu far finta di non sentire. Cambia il programma precedente
in modo da doverle urlare CIAO tre volte in riga. Assicurati di provare il programma: se
dici CIAO per tre volte, ma non in una riga, dovrai rimanere a parlare con la nonna.
Anni bisestili. Scrivere un programma dove, richiesto un anno di inizio e uno di fine,
puts tutti gli anni bisestili nel mezzo (inclusi loro, se sono bisestili). Gli anni bisestili
sono anni divisibili per quattro (come il 1984 e il 2004). Tuttavia, gli anni divisibili per
100 non sono anni bisestili (ad esempio 1800 e 1900), a meno che non siano divisibili per
400 (come il 1600 e il 2000).
Un array solo una lista nel computer. Ogni cella nella lista si comporta come una variabile:
si pu vedere a quale oggetto un particolare slot punti a si pu farlo puntare ad un oggetto
diverso. Diamo uno sguardo ad alcuni array:
[]
[5]
['Salve', 'Arrivederci']
Prima abbiamo un array vuoto, poi un array contenente un solo numero, poi un array
contenente due stringhe. Dopo abbiamo una semplice assegnazione, poi un array contenente
tre oggetti, lultimo dei quali larray [true, false]. Ricorda, le variabili non sono
oggetti, dunque il nostro ultimo array punta realmente ad un decimale, una stringa e un array.
Anche se facessimo puntare gusto a qualcosaltro larray non cambierebbe.
Per aiutarci a trovare un particolare oggetto in un array, ogni cella un numero indice. I
programmatori iniziano a contare da zero, cos la prima cella in un array la cella zero. Ecco
come abbiamo i riferimenti agli oggetti in un array:
nomi = ['Ada', 'Bianca', 'Carla']
puts nomi
puts nomi[0]
puts nomi[1]
puts nomi[2]
puts nomi[3] # Questo fuori dei limiti.
Ada
Bianca
Carla
Ada
Bianca
Carla
nil
Infine abbiamo provato puts nomi[3], giusto per vedere cosa sarebbe successo. Vi
aspettavate un errore? A volte, quando fate una domanda, la domanda non ha senso (o almeno
per il computer), questo quando si verifica un errore. talvolta, tuttavia, si pu porre una
domanda e ottenere come risposta nulla. Cosa c nella cella 3? Nulla. Qual nomi[3]?
nil: il modo di Ruby per dire nulla. nil un oggetto speciale che praticamente significa
nessun altro oggetto.
Il metodo each
each ci permette di fare qualcosa (qualsiasi cosa) per ciascun (each) oggetto al quale punta
larray. Quindi, se vogliamo dire qualcosa di carino su ciascuna lingua nellarray sottostante,
facciamo cos:
languages = ['English', 'German', 'Ruby']
languages.each do |lang|
puts 'I love ' + lang + '!'
puts 'Tu no?'
end
I love English!
Tu no?
I love German!
Tu no?
I love Ruby!
Tu no?
E sentiamo sul C++!
...
Bene, siamo stati in grado di andare in ogni oggetto dellarray senza usare alcun numero, che
decisamente piacevole. Tradotto sarebbe: per ogni (each) oggetto in languages, punta la
variabile lang alloggetto e poi fai (do) quello che ti dico, fino a che non arrivi alla fine
(end).
Potreste pensare un po come i cicli che abbiamo imparato prima. S, simile. Una
differenza importante che il metodo each proprio questo: un metodo. while e end
Metodi come each che si comportano come i cicli sono spesso chiamati iteratori.
Una cosa da sottolineare sugli iteratori che sono sempre seguiti da doend. while e if
non hanno mai un do vicino a loro; usiamo do solo con gli iteratori.
Hip-Hip-Hooray!
Hip-Hip-Hooray!
Hip-Hip-Hooray!
In primo luogo diamo unocchiata a to_s e a join. join funziona in modo simile a to_s,
tranne per il fatto che aggiunge una stringa tra gli oggetti dellarray. Vediamo:
foods = ['carciofo', 'brioche', 'caramello']
puts foods
puts
puts foods.to_s
puts
puts foods.join(', ')
puts
puts foods.join(' :) ') + ' 8)'
200.times do
puts []
end
carciofo
brioche
caramello
Guardiamo ora push, pop e last. I metodi push e pop sono come opposti, come + e -.
push aggiunge un oggetto alla fine dellarray, e pop rimuove lultimo oggetto dallarray
(mostrando quale ). last simile a pop in quanto mostra la fine dellarray, per
lasciandolo invariato. push e pop modificano effettivamente larray:
stanze = []
stanze.push 'cucina'
stanze.push 'camera da letto'
puts stanze[0]
puts stanze.last
puts stanze.length
puts stanze.pop
puts stanze
puts stanze.length
cucina
camera da letto
2
camera da letto
cucina
1
Provare a scrivere il programma di cui sopra senza utilizzare il metodo sort. Una gran
parte della programmazione risolvere problemi, cos fate pi pratica possibile!
Riscrivere il programma della Tabella di Contenuti (dal capitolo sui metodi). Iniziare il
programma con un array che contiene tutte le informazioni della Tabella dei Contenuti
(nome del capitolo, numeri di pagina, ecc.). Poi stampare le informazioni dallarray
formattando per bene la Tabella dei Contenuti.
goodAnswer = false
while (not goodAnswer)
puts 'Ti piacciono i tacos?'
answer = gets.chomp.downcase
if (answer == 'si' or answer == 'no')
goodAnswer = true
else
puts 'Per piacere rispondi con "si" or "no".'
end
end
goodAnswer = false
while (not goodAnswer)
puts 'Ti piacciono i burritos?'
answer = gets.chomp.downcase
if (answer == 'si' or answer == 'no')
goodAnswer = true
else
puts 'Per piacere rispondi con "si" or "no".'
end
end
goodAnswer = false
while (not goodAnswer)
puts 'Ti piacciono i sopapillas?'
answer = gets.chomp.downcase
if (answer == 'si' or answer == 'no')
goodAnswer = true
else
puts 'Per piacere rispondi con "si" or "no".'
end
end
puts
puts 'Conclusione:'
puts 'Grazie per avermi concesso del tuo tempo per aiutarmi'
puts 'con questo esperimento. In realta\' questo esperimento'
puts 'non ha nulla a che fare con il cibo messicano.'
puts 'E\' un esperimento sul fare la pipi\' a letto.'
puts 'Il cibo messicano serviva solo per far abbassare la'
puts 'guardia nella speranza di avere risposte piu\' spontanee.'
puts 'Grazie ancora.'
puts
puts wetsBed
Ti piacciono i tacos?
si
Ti piacciono i burritos?
si
Ti fai la pipi' a letto?
assolutamente no
Per piacere rispondi con "si" or "no".
Ti fai la pipi' a letto?
Conclusione:
Grazie per avermi concesso del tuo tempo per aiutarmi
con questo esperimento. In realta' questo esperimento
non ha nulla a che fare con il cibo messicano.
E' un esperimento sul fare la pipi' a letto.
Il cibo messicano serviva solo per far abbassare la
guardia nella speranza di avere risposte piu' spontanee.
Grazie ancora.
false
Questo era un carino e lungo programma, con molte ripetizioni (tutte le sezioni di codice sulle
domande sul cibo messicano erano identiche e quella sulla pip a letto era differente solo di
poco). Le ripetizioni non sono una cosa buona. Non possiamo per metterle in un unico
grande ciclo o iteratore, perch a volte ci sono cose che vogliamo vengano fatte tra due
domande. In situazioni come queste la soluzione migliore scrivere un metodo. Ecco come:
def scriviMoo
puts 'mooooooo...'
end
Uh il nostro programma non ha scritto mooo. Perch no? Perch non gli abbiamo detto di
farlo. Gli abbiamo detto come farlo, ma non ancora di farlo! Proviamo di nuovo:
def scriviMoo
puts 'mooooooo...'
end
scriviMoo
scriviMoo
puts 'coin-coin'
scriviMoo
scriviMoo
mooooooo...
mooooooo...
coin-coin
mooooooo...
mooooooo...
Molto meglio. Abbiamo definito (def) il metodo scriviMoo (il nome dei metodi, come per
le variabili, inizia con la lettera minuscola; eccezioni sono ad esempio + e ==). Ma i metodi
non devono essere sempre associati con gli oggetti? Beh, s, e in questo caso (come con puts
scriviMoo 3
puts 'oink-oink'
scriviMoo # Questo dar un errore perch manca il parametro
mooooooo...mooooooo...mooooooo...
oink-oink
#<ArgumentError: wrong number of arguments (0 for 1)>
numberOfMoos una variabile che punta al parametro che viene passato. Lo dir unaltra
volta: numberOfMoos una variabile che punta al parametro che viene passato. Cos se
scrivo scriviMoo 3, il parametro 3 e la variabile numberOfMoos punta a 3.
Se gli oggetti in Ruby sono come i nomi e i metodi sono come i verbi, allora potete pensare ai
parametri come agli avverbi (come con scriviMoo, dove il parametro ci dice come) o a
qualcosa come un complemento oggetto (come con puts).
Variabili locali
Nel programma seguente ci sono due variabili:
def doubleThis num
numTimes2 = num*2
puts num.to_s+' per due fa '+numTimes2.to_s
end
doubleThis 44
44 per due fa 88
doubleThis 44
puts numTimes2.to_s
44 per due fa 88
#<NameError: undefined local variable or method `numTimes2' for
#<StringIO:0x82ba924>>
Variabile locale non definita In effetti abbiamo definito quella variabile locale, ma non
locale dove abbiamo provato ad usarla, locale al metodo.
Ci sono due variabili chiamate var in questo piccolo programma: una allinterno di
littlePest, e una fuori. Quando abbiamo chiamato littlePest var, in realt gli
abbiamo passato la stringa da var allaltra, cos entrambe puntavano alla stessa stringa. Poi
littlePest ha puntato la sua var locale a nil, senza far nulla alla var fuori del metodo.
Valori di ritorno
Avrete notato che alcuni metodi vi restituiscono qualcosa quando vengono chiamati. Per
esempio, gets restituisce una stringa (la stringa che avete scritto) e il metodo + in 5 + 3
(che in realt sarebbe 5. + (3)) restituisce 8. I metodi aritmetici per i numeri restituiscono
numeri e quelli per le stringhe restituiscono stringhe.
importante capire la differenza tra i metodi che restituiscono un valore dove il metodo
stato chiamato, e i metodi che stampano informazioni sullo schermo, coma fa puts. Notate
che 5 + 3 restituisce 8, non stampa 8.
Simone Ranzato Introduzione a Ruby Pagina 42
Allora che cosa restituisce puts? Non ce ne siamo mai interessati, ma guardiamo ora:
returnVal = puts 'puts restituisce questo:'
puts returnVal
Il primo puts restituisce nil; il secondo, anche se non abbiamo prove, fa lo stesso. Ogni
metodo deve restituire qualcosa, anche se si tratta solo di nil.
Il valore di ritorno di un metodo semplicemente lultima riga del metodo. Nel caso di
scriviMoo, significa che ritorna puts 'mooooooo...'*numberOfMoos, che
appunto nil dato che puts ritorna sempre nil. Se vogliamo che tutti i nostri metodi
restituiscano la stringa 'yellow submarine' dobbiamo allora mettere questa alla fine:
def scriviMoo numberOfMoos
puts 'mooooooo...'*numberOfMoos
'yellow submarine'
end
x = scriviMoo 2
puts x
mooooooo...mooooooo...
yellow submarine
numberOfMoos una variabile che punta al parametro che viene passato. Lo dir unaltra
volta:
def ask question
goodAnswer = false
while (not goodAnswer)
puts question
reply = gets.chomp.downcase
puts
puts 'Grazie mille...'
puts
puts wetsBed
Ciao, e grazie...
Ti piacciono i tacos?
si
Ti piacciono i burritos?
no
Fai la pipi' a letto?
no
Ti piacciono i chimichangas?
si
Ti piacciono i sopapillas?
si
Ti piacciono i tamales?
no
Solo qualche altra domanda...
Ti piace bere l'horchata?
si
Ti piacciono i flautas?
no
Grazie mille...
false
Nota: Questo metodo utilizza la parola chiave return per uscire prima da un metodo e
introduce una nuova opzione di scelta: elsif. Dovrebbe essere chiaro nel contesto come
funzionano.
# "left" is how much of the number we still have left to write out.
# "write" is the part we are writing out right now.
# write and left... get it? :)
left = number
write = left/100 # How many hundreds left to write out?
left = left - write*100 # Subtract off those hundreds.
if write > 0
return 'one hundred'
end
if write > 0
if write == 1 # Uh-oh...
# Since we can't write "tenty-two" instead of "twelve",
# we have to make a special exception for these.
if left == 0
numString = numString + 'ten'
elsif left == 1
numString = numString + 'eleven'
elsif left == 2
numString = numString + 'twelve'
elsif left == 3
numString = numString + 'thirteen'
elsif left == 4
numString = numString + 'fourteen'
elsif left == 5
numString = numString + 'fifteen'
elsif left == 6
numString = numString + 'sixteen'
elsif left == 7
numString = numString + 'seventeen'
elsif left == 8
numString = numString + 'eighteen'
elsif left == 9
numString = numString + 'nineteen'
end
# Since we took care of the digit in the ones place already,
# we have nothing left to write.
left = 0
if left > 0
numString = numString + '-'
end
end
if write > 0
if write == 1
numString = numString + 'one'
elsif write == 2
numString = numString + 'two'
elsif write == 3
numString = numString + 'three'
elsif write == 4
numString = numString + 'four'
elsif write == 5
numString = numString + 'five'
elsif write == 6
numString = numString + 'six'
elsif write == 7
numString = numString + 'seven'
elsif write == 8
numString = numString + 'eight'
elsif write == 9
numString = numString + 'nine'
end
end
if numString == ''
# The only way "numString" could be empty is if
# "number" is 0.
return 'zero'
end
puts englishNumber( 0)
puts englishNumber( 9)
puts englishNumber( 10)
puts englishNumber( 11)
puts englishNumber( 17)
puts englishNumber( 32)
puts englishNumber( 88)
puts englishNumber( 99)
puts englishNumber(100)
zero
nine
ten
eleven
seventeen
thirty-two
eighty-eight
ninety-nine
one hundred
# "left" is how much of the number we still have left to write out.
# "write" is the part we are writing out right now.
# write and left... get it? :)
left = number
write = left/100 # How many hundreds left to write out?
left = left - write*100 # Subtract off those hundreds.
if left > 0
# So we don't write 'two hundredfifty-one'...
numString = numString + ' '
end
end
if write > 0
if ((write == 1) and (left > 0))
# Since we can't write "tenty-two" instead of "twelve",
# we have to make a special exception for these.
numString = numString + teenagers[left-1]
# The "-1" is because teenagers[3] is 'fourteen', not 'thirteen'.
if left > 0
# So we don't write 'sixtyfour'...
numString = numString + '-'
end
end
if write > 0
numString = numString + onesPlace[write-1]
# The "-1" is because onesPlace[3] is 'four', not 'three'.
end
puts englishNumber( 0)
puts englishNumber( 9)
puts englishNumber( 10)
puts englishNumber( 11)
puts englishNumber( 17)
puts englishNumber( 32)
puts englishNumber( 88)
puts englishNumber( 99)
puts englishNumber(100)
puts englishNumber(101)
puts englishNumber(234)
puts englishNumber(3211)
puts englishNumber(999999)
puts englishNumber(1000000000000)
zero
nine
ten
eleven
seventeen
thirty-two
eighty-eight
ninety-nine
one hundred
one hundred one
two hundred thirty-four
thirty-two hundred eleven
ninety-nine hundred ninety-nine hundred ninety-nine
one hundred hundred hundred hundred hundred hundred
Molto meglio. Funziona anche con numeri grandi, anche se non proprio cos bene come si
potrebbe sperare. Per esempio, penso che 'one trillion' sarebbe un bel valore di
ritorno per lultimo numero o anche 'one million million' (anche se tutti e tre sono
corretti).
a = 12345
b = hello
c = Wed Dec 27 12:24:36 GMT 2006
Dato che gli array e le stringhe possono essere creati usando rispettivamente [...] e
'...', raramente useremo new per crearli. (Bench questo non sia evidente dallesempio,
String.new crea una stringa vuota, e Array.new crea un array vuoto.) Infine, i numeri
rappresentano uneccezione: non possibile creare un intero con Integer.new. Bisogna
scrivere lintero direttamente.
La classe Time
Dunque che roba la classe Time? Gli oggetti Time rappresentano momenti di tempo.
possibile aggiungere (o sottrarre) numeri al (o dal) tempo per ottenere nuovi tempi:
aggiungendo 1.5 si ha un nuovo tempo con un secondo e mezzo in pi:
time = Time.new # The moment you got this web page.
time2 = time + 60 # One minute later.
puts time
puts time2
possibile anche creare un tempo che rappresenta uno specifico momento usando
Time.mktime:
puts Time.mktime(2000, 1, 1)
puts Time.mktime(1976, 8, 3, 10, 11)
Buon compleanno! Chiedete ad una persona in che anno, mese e giorno nata. Calcolate
quanti anni ha e dategli un bel ceffone per ogni compleanno.
La classe Hash
Unaltra utile classe Hash. Un hash una specie di array: ha un mucchio di posti che
possono puntare a diversi oggetti. Negli array i posti sono allineati in una riga e sono tutti
numerati (partendo da zero). In un hash i posti non sono allineati (sono ammucchiati tutti
insieme), ed possibile usare qualsiasi oggetto per fare riferimento ad essi. una buona idea
usare gli hash quando si vuole tenere traccia di un sacco di cose che non si adattano bene a
stare in una lista ordinata. Ad esempio i colori utilizzati per le diverse parti del codice in
questo documento:
colorArray = [] # come Array.new
colorHash = {} # come Hash.new
colorArray[0] = 'red'
colorArray[1] = 'green'
colorArray[2] = 'blue'
colorHash['strings'] = 'red'
colorHash['numbers'] = 'green'
colorHash['keywords'] = 'blue'
colorArray.each do |color|
puts color
end
colorHash.each do |codeType, color|
puts codeType + ': ' + color
end
red
green
blue
strings: red
keywords: blue
numbers: green
Sebbene le persone usino delle stringhe per identificare le posizioni negli hash, si pu anche
usare qualsiasi tipo di oggetti, anche array o altri hash (sebbene non mi venga in mente nessun
buon motivo per farlo...):
weirdHash = Hash.new
weirdHash[12] = 'monkeys'
weirdHash[[]] = 'emptiness'
weirdHash[Time.new] = 'no time like the present'
Hash e array vanno utilizzati per cose differenti; spetta a voi decidere quale scelta la
migliore per il particolare problema.
Estendere le classi
Alla fine dellultimo capitolo, avete scritto un metodo per ottenete la parola corrispondente ad
un numero intero. Non era un metodo per gli interi; era solo un metodo generico. Non sarebbe
bello poter scrivere qualcosa tipo 22.to_eng invece di englishNumber 22? Ecco come
farlo:
class Integer
def to_eng
if self == 5
english = 'five'
else
english = 'fifty-eight'
end
english
end
end
five
fifty-eight
Abbiamo definito un metodo per i numeri interi saltando per un momento nella classe
Integer, definito il metodo l dentro, e poi saltando fuori di nuovo. Ora tutti gli interi hanno
questo (un po incompleto) metodo. In realt, se ad esempio non ci piacesse il funzionamento
del metodo to_s potremmo anche pensare di ridefinirlo in qualche altro modo... ma non
una buona idea! meglio lasciare i vecchi metodi in pace e farne di nuovi quando si deve fare
qualcosa di nuovo.
Creare le classi
Abbiamo visto un gran numero di diverse classe di oggetti. Comunque semplice arrivare a
tipi di oggetti che Ruby non ha. Fortunatamente creare nuove classi semplice come
modificare quelle gi esistenti. Diciamo di voler creare dei dadi in Ruby. Ecco come si
potrebbe rendere la classe Dado:
class Dado
def lancio
1 + rand(6)
end
end
# ...e lanciamoli.
dadi.each do |dado|
puts dado.lancio
end
1
3
Possiamo definire tutti i tipi di metodi per i nostri oggetti... ma manca qualcosa. Lavorare con
questi oggetti ci fa un po lavorare come con la programmazione prima di aver imparato
qualcosa sulle variabili. Guardate i nostri dadi, per esempio. Possiamo lanciarli, e ogni volta
ci danno un numero diverso. Ma se decidiamo di tenere traccia di quel numero, dobbiamo
creare una variabile che punti a quel numero. Sembra che ogni dado deve avere un numero, e
che lanciando il dado deve cambiare il numero. Se noi teniamo traccia del dado, non
dobbiamo anche tenere traccia del numero che sta mostrando.
Tuttavia, se si tenta di memorizzare il numero che abbiamo lanciato in una variabile (locale)
in lancio, verr persa appena lancio finito. Abbiamo bisogno di memorizzare il
numero in un tipo diverso di variabile:
Variabili distanza
Normalmente quando vogliamo parlare di una stringa, noi lo chiamano semplicemente una
stringa. Tuttavia, potremmo anche chiamare un oggetto stringa. A volte i programmatori
potrebbero chiamare unistanza della classe String, ma questa solo un altro modo (e un
po prolisso) di dire stringa. Unistanza di una classe solo un oggetto di quella classe.
def lancio
@numberShowing = 1 + rand(6)
end
def risultato
@numberShowing
end
end
dadi = Dado.new
dadi.lancio
puts dadi.risultato
puts dadi.risultato
dadi.lancio
puts dadi.risultato
puts dadi.risultato
4
4
6
6
Quindi lancio lancia i dadi e risultato ci dice il numero che viene visualizzato.
Tuttavia, proviamo a guardare ci che mostra prima di aver lanciato i dadi (prima di aver
impostato @numberShowing)?
class Dado
def lancio
@numberShowing = 1 + rand(6)
end
def risultato
@numberShowing
end
end
nil
Hmmm...bene, almeno non ci ha dato un errore. In realt in questo caso non ha senso per un
dado essere lanciato, o comunque nil starebbe a significare questo. Sarebbe bello se
class Dado
def initialize
# Lancer solamente il dado, tuttavia volendo
# avrebbe potuto fare qualcosa di diverso,
# come impostare il dado con 6 risultati.
lancio
end
def lancio
@numberShowing = 1 + rand(6)
end
def risultato
@numberShowing
end
end
puts Dado.new.risultato
Quando viene creato un oggetto, il suo metodo initialize (se definito) viene sempre
chiamato.
Ora lunica cosa che potrebbe mancare un modo per impostare quale lato di un dado
mostrare... perch non scrivete un metodo imbroglione che fa proprio questo! Tornate
quando avete finito (e quando avete prova che funziona, ovviamente). Assicuratevi che
qualcuno non possa impostare il dado che mostra una settima faccia!
Facciamo un altro esempio. Diciamo che vogliamo fare un semplice animale domestico
virtuale, un cucciolo di drago. Come la maggior parte dei cuccioli, dovrebbe essere in grado
di mangiare, dormire, e di fare la cacca, il che significa che dovremo essere in grado di dargli
da mangiare, metterlo a letto, e portarlo a passeggio. Internamente, il nostro drago avr
bisogno di tenere traccia se affamato, stanco, o deve andare, ma non saremo in grado di
vedere quando interagiamo con il nostro drago, cos come non si pu chiedere a un bambino
umano Hai fame?. Faremo anche aggiungere qualche modo divertente per poter interagire
con il nostro cucciolo di drago, e quando nato gli daremo un nome (qualunque cosa si passa
nel metodo new passata nel metodo initialize per voi). Bene, diamo unocchiata:
class Dragon
def feed
puts 'You feed ' + @name + '.'
@stuffInBelly = 10
passageOfTime
end
def walk
puts 'You walk ' + @name + '.'
@stuffInIntestine = 0
passageOfTime
end
def putToBed
puts 'You put ' + @name + ' to bed.'
@asleep = true
3.times do
if @asleep
passageOfTime
end
if @asleep
puts @name + ' snores, filling the room with smoke.'
end
end
if @asleep
@asleep = false
puts @name + ' wakes up slowly.'
end
end
def toss
puts 'You toss ' + @name + ' up into the air.'
puts 'He giggles, which singes your eyebrows.'
passageOfTime
end
def rock
puts 'You rock ' + @name + ' gently.'
@asleep = true
puts 'He briefly dozes off...'
passageOfTime
if @asleep
@asleep = false
puts '...but wakes when you stop.'
end
end
private
def hungry?
# Method names can end with "?".
# Usually, we only do this if the method
# returns true or false, like this:
@stuffInBelly <= 2
end
def poopy?
@stuffInIntestine >= 8
end
def passageOfTime
if @stuffInBelly > 0
# Move food from belly to intestine.
@stuffInBelly = @stuffInBelly - 1
@stuffInIntestine = @stuffInIntestine + 1
else # Our dragon is starving!
if @asleep
@asleep = false
puts 'He wakes up suddenly!'
end
puts @name + ' is starving! In desperation, he ate YOU!'
exit # This quits the program.
end
if @stuffInIntestine >= 10
@stuffInIntestine = 0
puts 'Whoops! ' + @name + ' had an accident...'
end
if hungry?
if @asleep
@asleep = false
puts 'He wakes up suddenly!'
end
puts @name + '\'s stomach grumbles...'
end
if poopy?
if @asleep
@asleep = false
puts 'He wakes up suddenly!'
end
puts @name + ' does the potty dance...'
end
end
end
Norbert is born.
You feed Norbert.
You toss Norbert up into the air.
He giggles, which singes your eyebrows.
You walk Norbert.
You put Norbert to bed.
Norbert snores, filling the room with smoke.
Norbert snores, filling the room with smoke.
Norbert snores, filling the room with smoke.
Norbert wakes up slowly.
You rock Norbert gently.
He briefly dozes off...
...but wakes when you stop.
You put Norbert to bed.
He wakes up suddenly!
Norbert's stomach grumbles...
You put Norbert to bed.
He wakes up suddenly!
Norbert's stomach grumbles...
You put Norbert to bed.
He wakes up suddenly!
Norbert's stomach grumbles...
Norbert does the potty dance...
You put Norbert to bed.
He wakes up suddenly!
Norbert is starving! In desperation, he ate YOU!
Abbiamo visto un paio di cose nuove in questo esempio. Il primo semplice: exit termina il
programma l e subito. La seconda la parola private che abbiamo messo nel mezzo della
definizione della nostra classe. Avrei potuto farne a meno, ma ho voluto rispettare lidea che
certi metodi sono cose che potete fare a un drago, e altri che semplicemente accadono
allinterno. Si pu pensare a questi come sotto il cofano: a meno che non siate un
meccanico di automobili, tutto ci che avete realmente bisogno di sapere il pedale del gas, il
pedale del freno, e il volante. Un programmatore potrebbe chiamarli linterfaccia pubblica per
la vostra auto. Come il vostro airbag sa quando aprirsi, interno alla macchina; l'utente medio
(autista) non ha bisogno di sapere di questo.
Allinterno di un oggetto auto, per, servirebbero molte altre cose per funzionare, a partire da
una velocit, una direzione e una posizione (al massimo di base). Questi attributi verrebbero
modificati premendo sui pedali dellacceleratore o del freno e girando la ruote, naturalmente,
ma lutente non sarebbe in grado di impostare la posizione direttamente. Potrebbe essere utile
anche tenere traccia di slittamenti o danni, e cos via. Queste sarebbero tutte interne
alloggetto automobile.
toast.call
toast.call
toast.call
Cheers!
Cheers!
Cheers!
Cos ho creato un proc (che credo sia labbreviazione di procedura, ma di gran lunga pi
importante, fa rima con block) che ha tenuto il blocco di codice, poi ho chiamato (call) il
proc tre volte. Come potete vedere, un po come un metodo.
In realt, ancora pi simile ai metodi che vi ho mostrato, perch i blocchi possono assumere
i parametri:
doYouLike = Proc.new do |aGoodThing|
puts 'I *really* like '+aGoodThing+'!'
end
doYouLike.call 'chocolate'
doYouLike.call 'ruby'
Ma allora, perch non usare semplicemente i metodi? Beh, perch ci sono alcune cose che non
si possono fare con i metodi. In particolare, non possibile passare metodi in altri metodi (ma
si possono passare proc nei metodi), e i metodi non possono ritornare altri metodi (ma
possono tornare proc). Tutto ci semplicemente perch i proc sono oggetti, i metodi no.
sayHello = Proc.new do
puts 'hello'
end
doSelfImportantly sayHello
doSelfImportantly sayGoodbye
Forse non sembra particolarmente favolosa... ma cos. fin troppo comune nella
programmazione avere dei requisiti severi su cosa si deve fare. Se si desidera salvare un file,
per esempio, dovete aprire il file, scrivere le informazioni che si desidera avere, e quindi
chiudere il file. Se vi dimenticate di chiudere il file, pu verificarsi qualche problema. Ma
ogni volta che si desidera salvare o caricare un file, bisogna fare la stessa cosa: aprire il file,
fare ci che si vuole veramente fare, quindi chiudere il file. noioso e facile da dimenticare.
In Ruby, salvare (o caricare) file funziona in modo simile al codice di cui sopra, in modo che
non ci si deve preoccupare di nulla, se non ci che si desidera salvare (o caricare).
Si possono anche scrivere metodi che determinano quante volte, o anche se, chiamare un
proc:
def maybeDo someProc
if rand(2) == 0
someProc.call
end
end
wink = Proc.new do
puts '<wink>'
end
glance = Proc.new do
puts '<glance>'
end
maybeDo wink
maybeDo glance
twiceDo wink
twiceDo glance
<glance>
Questi sono alcuni degli usi pi comuni di proc che ci permettono di fare cose che
semplicemente non avrebbe potuto fare con metodi da solo.
Prima di procedere, diamo unocchiata a un ultimo esempio. Finora i proc che abbiamo
passato sono stati molto simili gli uni agli altri. Questa volta sar molto diverso, in modo da
poter vedere quanto un metodo dipende dai proc passati in esso. Il nostro metodo ricever
qualche oggetto e un proc, e chiamer il proc su tale oggetto. Se il proc ritorna false, termina;
altrimenti chiamiamo il proc con loggetto restituito. Continuiamo a farlo fino a che il proc
non restituisce false (che era meglio farlo alla fine, o il programma andr in crash). Il metodo
restituisce lultimo valore non-false restituito dal proc.
def doUntilFalse firstInput, someProc
input = firstInput
output = firstInput
while output
input = output
output = someProc.call input
end
input
end
[25, 16, 9, 4, 1, 0]
I'm writing this at 3:00 am; someone knock me out!
Il metodo inspect molto simile a to_s, salvo che la stringa che restituisce tenta di
mostrare il codice Ruby per costruire loggetto che gli avete passato. Qui ci mostra lintero
array restituito dalla nostra prima chiamata a doUntilFalse.
In questo esempio, compose prende due proc e restituisce una nuova proc che, quando viene
chiamato, chiama il primo proc e passa il suo risultato al secondo.
def compose proc1, proc2
Proc.new do |x|
proc2.call(proc1.call(x))
end
end
puts doubleThenSquare.call(5)
puts squareThenDouble.call(5)
100
50
Si noti che la chiamata a proc1 deve essere allinterno delle parentesi per proc2 in modo
che venga fatta prima.
def eachEven(&wasABlock_nowAProc)
isEven = true # We start with "true" because arrays start with 0,
# which is even.
end
Quindi, per passare in un blocco a eachEven, tutto quello che abbiamo dovuto fare stato
mettere il blocco dopo il metodo. In questo modo potete passare un blocco in qualsiasi
metodo, anche se molti metodi ignoreranno il blocco. Affinch il vostro metodo non ignori il
blocco, ma lo prenda e lo trasformi in un proc, inserite il nome del proc alla fine della lista di
parametri del vostro metodo, preceduto da una e commerciale (&). Questa parte un po pi
difficile, ma non troppo, e dovete fare ci solo una volta (quando si definisce il metodo). Poi
possibile utilizzare il metodo pi e pi volte, proprio come i metodi che ricevono blocchi,
come each e times (ricordate 5.times do...?).
Se siete un po confusi, ricordate che cosa dovrebbe fare eachEven: chiamare il blocco che
stato passato con ogni altro elemento dellarray. Una volta che lavete scritto e funziona,
non c bisogno di pensare che cosa sta realmente facendo sotto il cofano; in effetti, questo
esattamente il motivo per cui scriviamo metodi come questo: cos non dobbiamo poi pensare a
come funzionano di nuovo. Li usiamo e basta.
Proviamo a scrivere un metodo che misuri quanto tempo impiegano diverse sezioni di un
programma (conosciuto come profiling del codice): quindi prenderemo il tempo prima e dopo
lesecuzione di un pezzo di codice, e ne calcoleremo la differenza.
def profile descriptionOfBlock, &block
startTime = Time.now
25000.times do
number = number + number
end
1000000.times do
number = number + 1
end
end
7526 digits
25000 doublings: 0.186667 seconds
count to a million: 0.506593 seconds
Con questo piccolo metodo, possiamo facilmente calcolare la durata di qualsiasi sezione di
qualsiasi programma; abbiamo appena messo il codice in un blocco e inviato in profile.
Cosa potrebbe essere pi semplice? Nella maggior parte dei linguaggi, avremmo dovuto
aggiungere in modo esplicito il codice di temporizzazione intorno ad ogni sezione che si
vuole misurare.
Program Logger. Scrivere un metodo chiamato log, che prende una stringa di
descrizione di un blocco e, naturalmente, un blocco. Simile a doSelfImportantly,
dovrebbe scrivere (puts) una stringa dicendo che ha iniziato il blocco, e unaltra stringa
alla fine dicendo che ha finito il blocco, e dicendo anche cosa ha restituito il blocco.
Provare il metodo con linvio di un blocco di codice. Allinterno del blocco, mettere
Una volta installato Shoes, vediamo che cosa si trova allinterno della cartella
/Shoes/:
Questo invece il metodo che praticamente genera i file html, sempre da shoes.rb:
def self.manual_as format, *args
require 'shoes/search'
require 'shoes/help'
case format
when :shoes
Shoes.app(:width => 720, :height => 640, &Shoes::Help)
else
extend Shoes::Manual
man = self
dir, = args
FileUtils.mkdir_p File.join(dir, 'static')
FileUtils.cp "static/shoes-icon.png", "#{dir}/static"
%w[manual.css code_highlighter.js code_highlighter_ruby.js].
each { |x| FileUtils.cp "static/#{x}", "#{dir}/static" }
html_bits = proc do
proc do |sym, text|
case sym when :intro
div.intro { p { self << man.manual_p(text, dir) } }
docn = 1
docs.each do |title1, opt1|
subsect = opt1['sections'].map { |x,| x }
menu = sections.map do |x|
[x, (subsect if x == title1)]
end
docn += 1
end
end
end
end
end
end
end
end
end.to_html
end
end
end
Ecco dunque che una volta sistemata opportunamente la guida realizzata, con le
convenzioni richieste per la realizzazione dei file html, e modificando un po di
percorsi dal codice sopra riportato, lanciando
dal Promp dei Comandi si crea la cartella (nominata manuale e situata in c:\)
con i file della guida in html:
= titolo =
== capitolo ==
Va inoltre indicato che alcuni caratteri speciali, come le lettere accentate, non
vengono riconosciuti.
0. Come iniziare
1. I numeri
2. Le lettere
4. Mescoliamoli insieme
7. Array e iteratori
9. Le classi
== 0. Come iniziare ==
Come iniziare
http://www.ruby-lang.org/it/