class Count
def initialize
@count = 0
end
def get
@count
end
def incr(n)
@count = @count + n
end
def Count.test
count = Count.new
count.incr(1)
count.incr(2)
end
end
definisce una class Count. Dentro la class sono definiti
4 metodi. Il primo metodo initialize
def initialize
@count = 0
end
ha uno status particolare.
Sarà chiamato automaticamente alla creazione di un oggetto della
class Count.
Ruby utilizza il prefisso @ per indicare un campo di
un oggetto e il prefisso @@ per indicare un campo statico
di un oggetto. I campi non hanno bisogno di essere dichiarati
(la stesso vale per le variabili locali).
Dunque il metodo initialize mette a zero il campo count.
Il secondo metodo get
def get
@count
end
permette di avere il valore di un campo. Un tale metodo è necessario
in Ruby perché i campi non sono visibili fuori della class.
Questa definizione illustra due aspetti importanti di Ruby.
Primo, Ruby non è tipato. La dichiarazione non ha bisogno di dare il
tipo del valore restituito dal metodo get.
Secondo, tutte le istruzioni di Ruby sono considerate comme delle espressioni.
Dunque il body di un metodo restituisce sempre un valore.
Quindi un modo equivalente di definire lo stesso metodo sarebbe
def get
return @count
end
Il terzo metodo incr
def incr(n)
@count = @count + n
end
permette di incrementare il campo count.
L'assegnazione in Ruby
è un'espressione. Dunque il metodo incr restituisce il nuovo
valore del campo count.
Il quarto metodo Count.test
def Count.test
count = Count.new
count.incr(1)
count.incr(2)
end
definisce un metodo di class (l'equivalente di un metodo statico
in Java). Il body prima definisce una variabile locale
count che inizializza con un nuovo oggetto di tipo
Count. In Ruby, gli oggetti sono creati
chiamando il metodo new.
Dopo l'inizializzazione della variabile count, il codice
chiama due volte il metodo incr. Dunque il valore
restituito è 3.
In Ruby tutti i valori manipolati sono degli oggetti e ci sono solamente chiamate di metodi. Per esempio, l'espressione
1 + 2 * 3è interpretata come
1.plus(2.mult(3))
Una proprietà importante di Ruby è la sua dinamicità. In qualsiasi momento, si può aggiungere un metodo ad una class. La verifica che una chiamata di un metodo è valida è effettuata solamente a tempo di esecuzione. Per esempio, un modo equivalente di definire la class precedente sarebbe
class Count
def initialize
@count = 0
end
def get
@count
end
def incr(n)
@count = @count + n
end
end
class Count
def Count.test
count = Count.new
count.incr(1)
count.incr(2)
end
end
La ridichiarazione della class Count non è considerata
come una ridefinizione ma come un'aggiunta.
Ruby non permette l'overloading dei metodi. Dunque con
il codice seguente
class Count
def initialize
@count = 0
end
def get
@count
end
def incr(n)
@count = @count + n
end
end
class Count
def incr
@count = @count + 1
end
end
La seconda dichiarazione del metodo incr è considerata
come una ridichiarazione. Un oggetto Count avrà in seguito
un solo metodo incr senza parametri.
Come in Java, Ruby permette di estendere
una class per crearne un'altra. Una class può estendere una
sola class.
Per esempio,
class A
def initialize
@a = 0
end
end
class B < A
@@c = 0
def initialize
super()
@b = 0
end
end
crea una estensione B della class A aggiungendo
un campo b ed un campo statico c.
Un meccanismo molto potente di Ruby è la possibilità di passare una chiusura nella chiamata di un metodo. Tale meccanismo permette non solo di passare una funzione come parametro di un metodo ma anche di assicurarsi che l'esecuzione di tale funzione (tramite la parola chiave yield) si farà nel contesto della creazione della funzione. Quindi una chiusura è composta da una funzione e dal suo contesto. Per esempio,
class A
def twice(n)
yield(n)
yield(n+1)
end
def test
a = 0
twice(5) do |m|
a = a + m
end
a
end
end
il metodo test chiama il metodo twice con il parametro
5 e la chiusura parametrizzata da m
do |m| a = a + m endche fa un'assegnazione. Nella dichiariazione del metodo twice il parametro n è passato in modo esplicito, invece la chiusura è passata in modo implicito. Quando il metodo twice eseguirà la chiusura, la variabile locale a di test sarà modificata in conseguenza. Nel nostro caso, il metodo test è equivalente a
def test
a = 0
a = a + 5
a = a + 6
a
end
Quindi la chiamata del metodo test ritornerà sempre 11.
Un'introduzione più completa del linguaggio può essere trovata
all'indirizzo
http://www.rubycentral.com/book.
La base del progetto consiste nell'avere una rappresentazione di un programma Ruby come un oggetto Java. Per esempio, al programma
class A
def initialize
@a = 0
end
end
potrebbe corrispondere l'oggetto
new Programma(
new ClassDef(new ClassName("A"), new ClassName("Object"),
new ClassBody(
new MethodDef(new MethodName("initialize"), new Parameter[]{},
new Body(new Assign(new FieldName("a"), new Int(0)))
)
)
)
)
La base deve permettere
Esempi di programmi che si dovrebbe essere capace di scrivere sono qui. Un esempio d'inizio di implementazione è qui
La base del progetto dovrà obbligatoriamente essere consegnata prima della prova scritta dell'esame.
A partire da questa base, si può completare il progetto realizzando per esempio:
Lo studente dovrebbe seguire le convenzioni di codifica date durante il corso. Per verificare la conformità del progetto, si può usare l'archivio checkstyle.jar. Eseguendo
java -jar checkstyle.jar File.javasi genera un file report che indica la conformità del codice.