# Questo è un commento# In Ruby, (quasi) tutto è un oggetto.# Questo include i numeri...3.class#=> Integer# ...stringhe..."Hello".class#=> String# ...e anche i metodi!"Hello".method(:class).class#=> Method# Qualche operazione aritmetica di base1+1#=> 28-1#=> 710*2#=> 2035/5#=> 72**5#=> 325%3#=> 2# Bitwise operators3&5#=> 13|5#=> 73^5#=> 6# L'aritmetica è solo zucchero sintattico# per chiamare il metodo di un oggetto1.+(3)#=> 410.*5#=> 50100.methods.include?(:/)#=> true# I valori speciali sono oggettinil# equivalente a null in altri linguaggitrue# verofalse# falsonil.class#=> NilClasstrue.class#=> TrueClassfalse.class#=> FalseClass# Uguaglianza1==1#=> true2==1#=> false# Disuguaglianza1!=1#=> false2!=1#=> true# nil è l'unico valore, oltre a false, che è considerato 'falso'!!nil#=> false!!false#=> false!!0#=> true!!""#=> true# Altri confronti1<10#=> true1>10#=> false2<=2#=> true2>=2#=> true# Operatori di confronto combinati (ritorna '1' quando il primo argomento è più# grande, '-1' quando il secondo argomento è più grande, altrimenti '0')1<=>10#=> -110<=>1#=> 11<=>1#=> 0# Operatori logicitrue&&false#=> falsetrue||false#=> true# Ci sono versioni alternative degli operatori logici con meno precedenza.# Sono usati come costrutti per il controllo di flusso per concatenare# insieme statement finché uno di essi ritorna true o false.# `do_something_else` chiamato solo se `do_something` ha successo.do_something()anddo_something_else()# `log_error` è chiamato solo se `do_something` fallisce.do_something()orlog_error()# Interpolazione di stringheplaceholder='usare l\'interpolazione di stringhe'"Per #{placeholder} si usano stringhe con i doppi apici"#=> "Per usare l'interpolazione di stringhe si usano stringhe con i doppi apici"# E' possibile combinare le stringhe usando `+`, ma non con gli altri tipi'hello '+'world'#=> "hello world"'hello '+3#=> TypeError: can't convert Fixnum into String'hello '+3.to_s#=> "hello 3""hello #{3}"#=> "hello 3"# ...oppure combinare stringhe e operatori'ciao '*3#=> "ciao ciao ciao "# ...oppure aggiungere alla stringa'ciao'<<' mondo'#=> "ciao mondo"# Per stampare a schermo e andare a capoputs"Sto stampando!"#=> Sto stampando!#=> nil# Per stampare a schermo senza andare a capoprint"Sto stampando!"#=> Sto stampando! => nil# Variabilix=25#=> 25x#=> 25# Notare che l'assegnamento ritorna il valore assegnato.# Questo significa che è possibile effettuare assegnamenti multipli:x=y=10#=> 10x#=> 10y#=> 10# Per convenzione si usa lo snake_case per i nomi delle variabilisnake_case=true# Usare nomi delle variabili descrittivipath_to_project_root='/buon/nome/'m='/nome/scadente/'# I simboli sono immutabili, costanti riusabili rappresentati internamente da# un valore intero. Sono spesso usati al posto delle stringhe per comunicare# specifici e significativi valori.:pendente.class#=> Symbolstato=:pendentestato==:pendente#=> truestato=='pendente'#=> falsestato==:approvato#=> false# Le stringhe possono essere convertite in simboli e viceversa:status.to_s#=> "pendente""argon".to_sym#=> :argon# Arrays# Questo è un arrayarray=[1,2,3,4,5]#=> [1, 2, 3, 4, 5]# Gli array possono contenere diversi tipi di elementi[1,'hello',false]#=> [1, "hello", false]# Gli array possono essere indicizzati# Dall'inizio...array[0]#=> 1array.first#=> 1array[12]#=> nil# ...o dalla fine...array[-1]#=> 5array.last#=> 5# With a start index and length# ...o con un indice di inzio e la lunghezza...array[2,3]#=> [3, 4, 5]# ...oppure con un intervallo.array[1..3]#=> [2, 3, 4]# Invertire l'ordine degli elementi di un arraya=[1,2,3]a.reverse!#=> [3,2,1]# Come per l'aritmetica, l'accesso tramite [var]# è solo zucchero sintattico# per chiamare il metodo '[]'' di un oggettoarray.[]0#=> 1array.[]12#=> nil# Si può aggiungere un elemento all'array cosìarray<<6#=> [1, 2, 3, 4, 5, 6]# oppure cosìarray.push(6)#=> [1, 2, 3, 4, 5, 6]# Controllare se un elemento esiste in un arrayarray.include?(1)#=> true# Hash è un dizionario con coppie di chiave e valore# Un hash è denotato da parentesi graffe:hash={'colore'=>'verde','numero'=>5}hash.keys#=> ['colore', 'numero']# E' possibile accedere all'hash tramite chiave:hash['colore']#=> 'verde'hash['numero']#=> 5# Accedere all'hash con una chiave che non esiste ritorna nil:hash['nothing here']#=> nil# Quando si usano simboli come chiavi di un hash, si possono utilizzare# queste sintassi:hash={:defcon=>3,:action=>true}hash.keys#=> [:defcon, :action]# oppurehash={defcon:3,action:true}hash.keys#=> [:defcon, :action]# Controllare l'esistenza di una chiave o di un valore in un hashnew_hash.key?(:defcon)#=> truenew_hash.value?(3)#=> true# Suggerimento: sia gli array che gli hash sono enumerabili!# Entrambi possiedono metodi utili come each, map, count e altri.# Strutture di controllo#Condizionaliiftrue'if statement'elsiffalse'else if, opzionale'else'else, opzionale'end#Cicli# In Ruby, i tradizionali cicli `for` non sono molto comuni. Questi semplici# cicli, invece, sono implementati con un enumerable, usando `each`:(1..5).eachdo|contatore|puts"iterazione #{contatore}"end# Esso è equivalente a questo ciclo, il quale è inusuale da vedere in Ruby:forcontatorein1..5puts"iterazione #{contatore}"end# Il costrutto `do |variable| ... end` è chiamato 'blocco'. I blocchi# sono simili alle lambda, funzioni anonime o closure che si trovano in altri# linguaggi di programmazione. Essi possono essere passati come oggetti,# chiamati o allegati come metodi.# # Il metodo 'each' di un intervallo (range) esegue il blocco una volta# per ogni elemento dell'intervallo.# Al blocco è passato un contatore come parametro.# E' possibile inglobare il blocco fra le parentesi graffe(1..5).each{|contatore|puts"iterazione #{contatore}"}# Il contenuto delle strutture dati può essere iterato usando "each".array.eachdo|elemento|puts"#{elemento} è parte dell'array"endhash.eachdo|chiave,valore|puts"#{chiave} è #{valore}"end# If you still need an index you can use 'each_with_index' and define an index# variable# Se comunque si vuole un indice, si può usare "each_with_index" e definire# una variabile che contiene l'indicearray.each_with_indexdo|elemento,indice|puts"#{elemento} è il numero #{index} nell'array"endcontatore=1whilecontatore<=5doputs"iterazione #{contatore}"contatore+=1end#=> iterazione 1#=> iterazione 2#=> iterazione 3#=> iterazione 4#=> iterazione 5# Esistono in Ruby ulteriori funzioni per fare i cicli,# come per esempio 'map', 'reduce', 'inject' e altri.# Nel caso di 'map', esso prende l'array sul quale si sta iterando, esegue# le istruzioni definite nel blocco, e ritorna un array completamente nuovo.array=[1,2,3,4,5]doubled=array.mapdo|elemento|elemento*2endputsdoubled#=> [2,4,6,8,10]putsarray#=> [1,2,3,4,5]# Costrutto "case"grade='B'casegradewhen'A'puts'Way to go kiddo'when'B'puts'Better luck next time'when'C'puts'You can do better'when'D'puts'Scraping through'when'F'puts'You failed!'elseputs'Alternative grading system, eh?'end#=> "Better luck next time"# 'case' può usare anche gli intervalligrade=82casegradewhen90..100puts'Hooray!'when80...90puts'OK job'elseputs'You failed!'end#=> "OK job"# Gestione delle eccezionibegin# codice che può sollevare un eccezioneraiseNoMemoryError,'Esaurita la memoria.'rescueNoMemoryError=>exception_variableputs'NoMemoryError è stato sollevato.',exception_variablerescueRuntimeError=>other_exception_variableputs'RuntimeError è stato sollvato.'elseputs'Questo viene eseguito se nessuna eccezione è stata sollevata.'ensureputs'Questo codice viene sempre eseguito a prescindere.'end# Metodidefdouble(x)x*2end# Metodi (e blocchi) ritornano implicitamente il valore dell'ultima istruzionedouble(2)#=> 4# Le parentesi sono opzionali dove l'interpolazione è inequivocabiledouble3#=> 6doubledouble3#=> 12defsum(x,y)x+yend# Gli argomenit dei metodi sono separati dalla virgolasum3,4#=> 7sumsum(3,4),5#=> 12# yield# Tutti i metodi hanno un implicito e opzionale parametro del blocco.# Esso può essere chiamato con la parola chiave 'yield'.defsurroundputs'{'yieldputs'}'endsurround{puts'hello world'}# {# hello world# }# I blocchi possono essere convertiti in 'proc', il quale racchiude il blocco# e gli permette di essere passato ad un altro metodo, legato ad uno scope# differente o modificato. Questo è molto comune nella lista parametri del# metodo, dove è frequente vedere il parametro '&block' in coda. Esso accetta# il blocco, se ne è stato passato uno, e lo converte in un 'Proc'.# Qui la denominazione è una convenzione; funzionerebbe anche con '&ananas'.defguests(&block)block.class#=> Procblock.call(4)end# Il metodo 'call' del Proc è simile allo 'yield' quando è presente un blocco.# Gli argomenti passati a 'call' sono inoltrati al blocco come argomenti:guests{|n|"You have #{n} guests."}# => "You have 4 guests."# L'operatore splat ("*") converte una lista di argomenti in un arraydefguests(*array)array.each{|guest|putsguest}end# Destrutturazione# Ruby destruttura automaticamente gli array in assegnamento# a variabili multiple:a,b,c=[1,2,3]a#=> 1b#=> 2c#=> 3# In alcuni casi si usa l'operatore splat ("*") per destrutturare# un array in una lista.classifica_concorrenti=["John","Sally","Dingus","Moe","Marcy"]defmigliore(primo,secondo,terzo)puts"I vincitori sono #{primo}, #{secondo}, e #{terzo}."endmigliore*classifica_concorrenti.first(3)#=> I vincitori sono John, Sally, e Dingus.# The splat operator can also be used in parameters:defmigliore(primo,secondo,terzo,*altri)puts"I vincitori sono #{primo}, #{secondo}, e #{terzo}."puts"C'erano altri #{altri.count} partecipanti."endmigliore*classifica_concorrenti#=> I vincitori sono John, Sally, e Dingus.#=> C'erano altri 2 partecipanti.# Per convenzione, tutti i metodi che ritornano un booleano terminano# con un punto interrogativo5.even?#=> false5.odd?#=> true# Per convenzione, se il nome di un metodo termina con un punto esclamativo,# esso esegue qualcosa di distruttivo. Molti metodi hanno una versione con '!'# per effettuare una modifiche, e una versione senza '!' che ritorna# una versione modificata.nome_azienda="Dunder Mifflin"nome_azienda.upcase#=> "DUNDER MIFFLIN"nome_azienda#=> "Dunder Mifflin"# Questa volta modifichiamo nome_aziendanome_azienda.upcase!#=> "DUNDER MIFFLIN"nome_azienda#=> "DUNDER MIFFLIN"# Classi# Definire una classe con la parola chiave classclassUmano# Una variabile di classe. E' condivisa da tutte le istance di questa classe.@@specie='H. sapiens'# Inizializzatore di basedefinitialize(nome,eta=0)# Assegna il valore dell'argomento alla variabile dell'istanza "nome"@nome=nome# Se l'età non è fornita, verrà assegnato il valore di default indicato# nella lista degli argomenti@eta=etaend# Metodo setter di basedefnome=(nome)@nome=nomeend# Metodo getter di basedefnome@nomeend# Le funzionalità di cui sopra posso essere incapsulate usando# il metodo attr_accessor come segueattr_accessor:nome# Getter/setter possono anche essere creati individualmenteattr_reader:nomeattr_writer:nome# Un metodo della classe usa 'self' per distinguersi dai metodi dell'istanza.# Può essere richimato solo dalla classe, non dall'istanza.defself.say(msg)putsmsgenddefspecie@@specieendend# Instanziare una classejim=Umano.new('Jim Halpert')dwight=Umano.new('Dwight K. Schrute')# Chiamiamo qualche metodojim.specie#=> "H. sapiens"jim.nome#=> "Jim Halpert"jim.nome="Jim Halpert II"#=> "Jim Halpert II"jim.nome#=> "Jim Halpert II"dwight.specie#=> "H. sapiens"dwight.nome#=> "Dwight K. Schrute"# Chiamare un metodo della classeUmano.say('Ciao')#=> "Ciao"# La visibilità della variabile (variable's scope) è determinata dal modo# in cui le viene assegnato il nome.# Variabili che iniziano con $ hanno uno scope globale$var="Sono una variabile globale"defined?$var#=> "global-variable"# Variabili che inziano con @ hanno a livello dell'istanza@var="Sono una variabile dell'istanza"defined?@var#=> "instance-variable"# Variabili che iniziano con @@ hanno una visibilità a livello della classe@@var="Sono una variabile della classe"defined?@@var#=> "class variable"# Variabili che iniziano con una lettera maiuscola sono costantiVar="Sono una costante"defined?Var#=> "constant"# Anche una classe è un oggetto in ruby. Quindi la classe può avere# una variabile dell'istanza. Le variabili della classe sono condivise# fra la classe e tutti i suoi discendenti.# Classe baseclassUmano@@foo=0defself.foo@@fooenddefself.foo=(value)@@foo=valueendend# Classe derivataclassLavoratore<UmanoendUmano.foo#=> 0Lavoratore.foo#=> 0Umano.foo=2#=> 2Lavoratore.foo#=> 2# La variabile dell'istanza della classe non è condivisa dai discendenti.classUmano@bar=0defself.bar@barenddefself.bar=(value)@bar=valueendendclassDottore<UmanoendUmano.bar#=> 0Dottore.bar#=> nilmoduleEsempioModulodeffoo'foo'endend# Includere moduli vincola i suoi metodi all'istanza della classe.# Estendere moduli vincola i suoi metodi alla classe stessa.classPersonaincludeEsempioModuloendclassLibroextendEsempioModuloendPersona.foo#=> NoMethodError: undefined method `foo' for Person:ClassPersona.new.foo#=> 'foo'Libro.foo#=> 'foo'Libro.new.foo#=> NoMethodError: undefined method `foo'# Callbacks sono eseguiti quand si include o estende un modulomoduleConcernExampledefself.included(base)base.extend(ClassMethods)base.send(:include,InstanceMethods)endmoduleClassMethodsdefbar'bar'endendmoduleInstanceMethodsdefqux'qux'endendendclassSomethingincludeConcernExampleendSomething.bar#=> 'bar'Something.qux#=> NoMethodError: undefined method `qux'Something.new.bar#=> NoMethodError: undefined method `bar'Something.new.qux#=> 'qux'