Di più sui Metodi

Finora abbiamo visto un certo numero di metodi diversi, puts e gets e così via (Flash Quiz: Elenca tutti i metodi visti finora. Ce ne sono ben dieci; la risposta è più sotto.) ma ancora non abbiamo discusso davvero di cosa i metodi siano. Sappiamo quello che fanno, ma non sappiamo cosa sono.

Ma veramente, questo è quello che sono: cose che fanno qualcosa. Se gli oggetti (come le stringhe, i numeri interi e i float) possono essere considerati i"sostantivi" del linguaggio Ruby, allora i metodi sono i suoi "verbi". E, proprio come in Italiano, non può esserci un verbo senza un sostantivo (seppur talvolta sottinteso) che faccia da soggetto e/o da complemento oggetto per quel verbo. [NdT: si pensi ad esempio all'imperativo "lavati!" il soggetto sottinteso sei tu (soggetto) che devi lavare te stesso (complemento oggetto).] Per esempio, il "ticchettare" non è qualcosa che accade in sé; un orologio (da polso o comunque di qualche tipo) deve farlo. In italiano diremmo: "L'orologio emette un ticchettìo", oppure "L'orologio ticchetta". In Rubi diremmo orologio.ticchetta (assumendo che orologio sia un oggetto Ruby, ovviamente). I programmatori direbbero che stiamo "chiamando il metodo ticchetta dell'oggetto orologio".

Allora, hai provato a risolvere il quiz? Bene, Sono sicuro che hai ricordato i metodi puts, gets, e chomp, dal momento che li abbiamo appena visti. Probabilmente hai elencato anche i nostri metodi di conversione, to_i, to_f, e to_s. Ma hai beccato anche gli altri quattro? Perché non si tratta di altro che dei nostri vecchi compagni di aritmetica +, -, *, e /!

Come dicevo, proprio come ogni verbo ha bisogno di un soggetto, ogni metodo ha bisogno di un oggetto. Di solito è facile individuare quale oggetto sta eseguendo il metodo: è ciò che compare appena prima del punto, come nel nostro esempio orologio.ticchetta, o in 101.to_s. Qualche volta, tuttavia, non è così ovvio; come per i metodi aritmetici. Come si scopre, 55 è in realtà solo una scorciatoia per scrivere 5.+ 5. Per esempio:

puts 'ciao '.+ 'mondo'
puts (10.* 9).+ 9
ciao mondo
99

Non è molto gradevole, quindi non li scriveremo in questo modo; tuttavia è importante capire cosa stia davvero accadendo. (Sul mio computer, mi restituisce anche un warning, cioè un messaggio di avvertimento): warning: parenthesize argument(s) for future version. Pur eseguendo il codice correttamente, mi sta dicendo che sta avendo difficoltà a capire cosa intendo, e di utilizzare delle parentesi in futuro.) Questo ci dà anche una più profonda comprensione del perché possiamo scrivere 'maiale'*5 ma non 5*'maiale': 'maiale'*5 sta dicendo alla stringa 'maiale' di fare la moltiplicazione, mentre 5*'maiale' sta dicendo di fare la moltiplicazione al numero intero 5. 'maiale' sa come fare 5 copie di sé stesso e sommarle tutte assieme; mentre 5 se la vedrà decisamente peggio nel cercare di fare 'maiale' copie di sé stesso e sommarle assieme...

Ovviamente, ci rimangono ancora da spiegare puts e gets. Dove sono i loro oggetti che li eseguono? In Italiano si può talvolta omettere il sostantivo; per esempio se un furfante grida "Muori!", il sostantivo implicito che fa da soggetto è il furfante stesso, mentre il sostantivo implicito che fa da complemento oggetto è il poveretto a cui sta gridando. In Ruby, se dico puts 'essere o non essere', quello che davvero sto dicendo è self.puts 'essere o non essere'. Ma cos'è self? E' una variabile speciale che punta sempre all'oggetto nel quale ti trovi in quel momento. Ok, ancora non sappiamo come essere in un oggetto ma, finché non lo scopriamo, possiamo capire subito che ci troveremo sempre all'interno di un grande oggetto che è... tutto il programma! E, fortuna nostra, il programma ha alcuni metodi suoi, come puts and gets. Guarda questo:

# encoding: utf-8
nonPossoCredereDiAvereUnaVariabileCosìLungaSoloPerPuntareAlNumero3 = 3
puts nonPossoCredereDiAvereUnaVariabileCosìLungaSoloPerPuntareAlNumero3
self.puts nonPossoCredereDiAvereUnaVariabileCosìLungaSoloPerPuntareAlNumero3
3
3

Se non sei riuscito a seguire proprio tutto fin qui, è OK. La cosa più importante da capire è che ogni metodo viene sempre eseguito da qualche oggetto, anche se non c'è un punto a separarli o se l'oggetto è sottinteso. Se hai capito bene questo, allora sei pronto a proseguire.

Estrosi Metodi delle Stringhe

Impariamo un po' di divertenti metodi delle stringhe. Non devi impararli tutti a memoria; puoi consultare questa pagina ancora se te li dimentichi. Voglio solo mostrarti una piccola parte di ciò che possono fare le stringhe. In realtà, io stesso non ricordo nemmeno la metà dei metodi delle stringhe — ma va bene così, perché sono facilmente reperibili su internet ottimi elenchi in cui tutti i metodi sono nominati e spiegati. (Ti mostrerò dove trovarli alla fine di questo tutorial). Davvero, io nemmeno voglio conoscerli tutti; sarebbe un po' come ricordare ogni parola nel dizionario. Posso parlare Italiano benissimo pur non conoscendone ogni singola parola... è non è proprio questa la vera ragione d'essere del dizionario? Far sì che tu non debba ricordarti tutto quello che c'è scritto dentro?

Dunque, il nostro primo metodo è reverse (inverti), che restituisce una versione della stringa al contrario:

var1 = 'stop'
var2 = 'stressed'
var3 = 'Puoi leggere al contrario questa frase?'

puts var1.reverse
puts var2.reverse
puts var3.reverse
puts var1
puts var2
puts var3
pots
desserts
?esarf atseuq oirartnoc la ereggel iouP
stop
stressed
Puoi leggere al contrario questa frase?

Come puoi notare, reverse non inverte la stringa originale, ne crea una nuova versione invertita. E' per questo che var1 punta sempre a 'stop' anche dopo che abbiamo chiamato il metodo reverse su var1.

Un altro metodo delle stringhe è length (lunghezza), che ci restituisce il numero di caratteri (spazi inclusi) nella stringa:

# encoding: utf-8
puts 'Qual è il tuo nome completo?'
name = gets.chomp
puts 'Lo sapevi che ci sono ' + name.length + ' caratteri nel tuo nome, ' + name + '?'
Qual è il tuo nome completo?
Duccio Domenico Antonio Armenise
#<TypeError: can't convert Fixnum into String>

[NdT: nella versione originale l'autore ha usato "Christopher David Pine"]

Uh-oh! Qualcosa è andato storto, e sembra che sia accaduto appena dopo la linea name = gets.chomp... Riesci a vedere dov'è e in cosa consiste il problema?

Il problema riguarda il metodo length: ci restituisce un numero (un "fixnum", cioè un intero), mentre a noi serve una stringa. Sembra semplice, proviamo semplicemente a chiamare un to_s (e a incrociare le dita):

# encoding: utf-8
puts 'Qual è il tuo nome completo?'
name = gets.chomp
puts 'Lo sapevi che ci sono ' + name.length.to_s + ' caratteri nel tuo nome, ' + name + '?'
Qual è il tuo nome completo?
Duccio Domenico Antonio Armenise
Lo sapevi che ci sono 32 caratteri nel tuo nome, Duccio Domenico Antonio Armenise?

No, non lo sapevo. NB: è il numero di caratteri nel mio nome, non il numero di lettere (contale se non ci credi). Immagino che potremmo scrivere un programma che chieda il nostro nome, il secondo nome e il nostro cognome individualmente, per poi sommare tutte le lunghezze assieme... hey, perché non lo scrivi tu?
Procedi pure, io aspetto.

L'hai fatto? Bene! E' piacevole programmare, non è vero? Fra qualche capitolo in più, ti stupirai di cosa sarai in grado di fare!

Ci sono anche alcuni metodi in grado di cambiare il carattere (maiuscolo e minuscolo) della tua stringa. upcase (maiuscolo) cambia ogni lettera minuscola con la sua maiuscola, e downcase (minuscolo) cambia ogni lettera maiuscola con la sua minuscola. swapcase scambia il tipo di ciascuna lettera (le maiuscole diventano minuscole e viceversa), e infine, capitalize (capitalizza) si comporta come downcase, ma in più cambia il primo carattere, se è una lettera, sempre in maiuscolo (NdT: è un metodo tipicamente utilizzato per stampare nomi propri che richiedono la prima lettera maiuscola).

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

Tutto piuttosto semplice. Come puoi notare dalla linea puts ' a'.capitalize, il metodo capitalize effettivamente capitalizza solo il primo carattere, non la prima lettera. Inoltre, come si è visto prima, durante tutte queste chiamate di metodo, lettere rimane invariata. Non intendo insistere su questo punto, ma è importante da capire. Ci sono alcuni metodi che , cambiano gli oggetti associati, ma ancora non ne abbiamo visti, e non ne vedremo ancora per un po'.

Gli ultimi simpatici metodi delle stringhe che vedremo servono per la formattazione visuale. Il primo, center, aggiunge degli spazi all'inizio e alla fine della stringa per renderla centrata. Tuttavia, proprio come occorre dire a puts cosa vogliamo che stampi, e a + cosa deve sommare, occorre dire a center l'ampiezza delle stringhe che intendiamo centrare. Quindi se volessi centrare le linee di un poema, farei in questo modo:

# encoding: utf-8
ampiezzaLinea = 50
puts(                                'Vecchia Madre Enza'.center(ampiezzaLinea))
puts(                         'Seduta nella sua credenza'.center(ampiezzaLinea))
puts(               'Mangiando cardi e certosa di Pavia,'.center(ampiezzaLinea))
puts(                            'Quando arrivò un ragno'.center(ampiezzaLinea))
puts(                  'Che si siedette sul suo calcagno'.center(ampiezzaLinea))
puts('E il suo cane da pantofole, spaventato scappò via.'.center(ampiezzaLinea))
Vecchia Madre Enza
Seduta nella sua credenza
Mangiando cardi e certosa di Pavia,
Quando arrivò un ragno
Che si siedette sul suo calcagno
E il suo cane porta scarpe, spaventato scappò via.

Hmmm... Non credo che quella filastrocca facesse proprio così [NdT: l'originale è "Old Mother Hubbard" che è una filastrocca tipica della lingua inglese], ma sono troppo pigro per andare a controllare. (Inoltre volevo allineare la parte coi vari .center ampiezzaLinea, così ho aggiunto quegli spazi extra prima delle stringhe. Ma questo solo perché penso che il codice sia più carino così. I programmatori spesso provano forti sentimenti rispetto a cosa è più grazioso in un programma, e spesso su questo genere di punti sono in disaccordo. Più programmerai, più arriverai a uno stile tutto tuo). A proposito dell'essere pigri, la pigrizia non è sempre una brutta cosa in informatica. Per esempio, hai notato come ho salvato la larghezza del poema nella variabile ampiezzaLinea? In questo modo, qualora volessi cambiare la larghezza del poema per renderlo più largo, dovrei cambiare solo la primissima linea del programma, invece di dover cambiare ogni linea che effettua la centratura (provaci subito!). Con un programma molto lungo, questo approccio permette di risparmiare tantissimo tempo. Questo tipo di pigrizia, quando applicata alla programmazione, diventa proprio una virtù.

Quindi, a proposito del centrare... avrai notato che il risultato non poi così bello se comparato a quello che si otterrebbe con un programma di videoscrittura avanzato (tipo Word). Se davvero volessi una centratura perfetta (e magari un font più bello), allora avresti dovuto usare un programma di videoscrittura! Ruby è uno strumento strepitoso, ma nessuno strumento è il miglior strumento per ogni lavoro.

Gli altri due metodi per formattare le stringhe sono ljust e rjust, che stanno per left justify (allineato a sinistra) e right justify (allineato a destra). Sono simili a center, a eccezione del fatto che spaziano la stringa solo sul lato destro e sinistro rispettivamente. Vediamoli tutti e tre in azione:

ampiezzaLinea = 40
str = '--> testo <--'
puts str.ljust  ampiezzaLinea
puts str.center ampiezzaLinea
puts str.rjust  ampiezzaLinea
puts str.ljust(ampiezzaLinea/2) + str.rjust(ampiezzaLinea/2)
--> text <--
              --> text <--
                            --> text <--
--> text <--                --> text <--

Un Po' di Cose da Provare

  • Scrivi un programma "Capo Cattivo". Dovrebbe chiederti bruscamente quello che vuoi. Poi, qualunque sia la risposta, il Capo Cattivo dovrebbe gridartela indietro e quindi licenziarti. Per esempio, se rispondi Voglio un aumento., dovrebbe risponderti gridando CHEDDIAVOLO MI SIGNIFICA "VOGLIO UN AUMENTO."?!?  SEI LICENZIATO!!
  • Ed eccoti qualcosa da fare per giocare ancora un po' coi vari center, ljust, e rjust: Scrivi un programma che visualizzi un Indice che appaia così:
                Indice

Capitolo 1:  I Numeri                          page 1
Capitolo 2:  Le Lettere                       page 72
capitolo 3:  Variabili e Assegnamenti        page 118

Le soluzioni a tutti gli esercizi proposti sono disponibili nel Manuale delle Soluzioni.

Alta Matematica

(Questa sezione è del tutto facoltativa. Si presuppone un discreto livello di conoscenza della matematica. Se non sei interessato, puoi andare dritto al capitolo Controllo del Flusso senza nessun problema. Tuttavia una rapida occhiata alla sezione Numeri Casuali potrebbe tornare utile).

Il numero di metodi aritmetici non è nemmeno paragonabile al numero di metodi delle stringhe (quest'ultimi sono molti di più). Qui vedremo i restanti metodi aritmetici, un generatore di numeri casuali, e l'oggetto Math coi suoi metodi trigonometrici e trascendentali.

Più Aritmetica

Gli altri due metodi aritmetici sono ** (elevamento a potenza) e % (modulo). Quindi se vuoi dire "cinque al quadrato" (o "il quadrato di cinque") in Ruby lo scriveresti come 5**2. Puoi anche usare i float (numeri in virgola mobile) come esponenti, quindi se vuoi la "radice quadrata di cinque", puoi scrivere 5**0.5. Il metodo modulo ti restituisce il resto della divisione per un altro numero. Per esempio, se divido 7 per 3 ottengo 2 col resto di 1. Vediamo come funziona in un programma:

# encoding: utf-8
puts 5**2
puts 5**0.5
puts 7/3
puts 7%3
puts 365%7
25
2.23606797749979
2
1
1

Da quell'ultima linea apprendiamo che un anno (non bisestile) ha un certo numero di settimane, più un giorno. Quindi se il tuo compleanno quest'anno cade di Martedì, il prossimo anno cadrà di Mercoledì. Anche col metodo modulo puoi usare dei float ma, nel caso, si comporta nell'unico modo sensato... te lo lascio scoprire da solo.

C'è solo un ultimo metodo da menzionare prima di passare al generatore di numeri casuali: abs. Restituisce semplicemente il valore assoluto (absolute) di un numero:

puts((5-2).abs)
puts((2-5).abs)
3
3

Numeri Casuali (Random)

Ruby dispone di un simpatico generatore di numeri casuali. Il metodo per ottenere un numero scelto casualmente è rand (NdT: in inglese "casuale" si dice "random"). Se chiami rand da solo, otterrai un float maggiore o uguale a 0.0 e minore di 1.0. Se invece passi a rand un intero (5 per esempio), ti restituirà un intero maggiore o uguale di 0 e minore di 5 (vale a dire cinque numero possibili, da 0 a 4).

Vediamo rand in azione.

# encoding: utf-8
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('Il meteorologo ha detto che c\'è al '+rand(101).to_s+'% possibilità di pioggia,')
puts('ma non ci si può mai fidare dei meteorologi.')
0.866769322351658
0.155609260113273
0.208355946789083
61
46
92
0
0
0
22982477508131860231954108773887523861600693989518495699862
Il meteorologo ha detto che c'è al 47% possibilità di pioggia,
ma non ci si può mai fidare dei meteorologi.

Nota bene che ho usato rand(101) per ottenere numero da 0 a 100, e che rand(1) restituisce sempre 0. Il non capire il range di possibili valori restituiti è alla base dei peggiori errori che ho visto commettere con rand; anche da programmatori professionisti; anche in prodotti finiti che si possono acquistare sul mercato. Ho persino avuto un lettore CD che, se impostato su "Random Play" ("Riproduzione Casuale"), riproduceva qualsiasi canzone tranne l'ultima... (Mi chiedo, cosa sarebbe accaduto se vi avessi inserito un CD con una sola canzone?)

Alle volte potresti volere che rand restituisca gli stessi numeri casuali nella stessa sequenza in due diverse esecuzioni del tuo programma. (Per esempio, una volta per creare mondi generati casualmente per un gioco del computer stavo usando numeri generati casualmente. Se trovavo un mondo che mi piaceva, magari ci volevo giocare nuovamente, o mandarlo a un amico). Al fine di riuscirci, devi impostare il seme (seed), e puoi farlo con metodo srand (NdT: "seeded random", cioè "numero casuale con seme"). Così:

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

Che farà la stessa cosa ogni volta che sarà "seminato" con lo stesso numero o seme (in questo caso 1776). Se vuoi ottenere numeri diversi (come accadrebbe se non hai mai usato srand), allora chiama semplicemente srand 0. Questo lo semina con un numero davvero strano, usando (fra le altre cose) il tempo corrente sul tuo computer, preciso al millisecondo.

L'Oggetto Math

Infine diamo un'occhiata all'oggetto Math. Potremmo anche saltarci subito dentro:

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)
3.14159265358979
2.71828182845905
0.5
1.0
2.0
1.61803398874989

La prima cosa che hai notato è stata probabilmente la notazione "::". Spiegare l'operatore di scopo (o "scope operator") che è ciò di cui si tratta, è proprio aldilà del, ehm... scopo di questo tutorial. Il gioco di parole non era voluto. Giuro. Basti sapere che puoi usare Math::PI proprio come ti aspetteresti.

Come puoi vedere, Math contiene tutte le cose che ti aspetteresti di trovare in una decente calcolatrice scientifica. E, come al solito, i float vanno molto vicino all'essere la risposta giusta.

E adesso... seguiamo il flusso!

Vorrai mica perderti altri articoli come questo?
Iscriviti per riceverne altri!

Scritto da

Duccio

Duccio Armenise

Corsidia Founder

Aiuto solo i migliori Maestri a trovare i loro prossimi Studenti. Come? Così! :)

Bio - uCV

Per

Corsidia logo

I tuoi prossimi Studenti ti stanno già cercando, tu ci sei?

Materie

Trova un altro corso