>> puts 5.class FixnumCome vedete, e’ possibile effettuare una introspezione dell’oggetto
5, chiedendogli quale sia la sua classe. avremmo anche potuto chiedergli quale e’
la sua superclasse:
>> 5.class.superclass >> Integer >> 5.class.superclass.superclass => Numeric >> 5.class.superclass.superclass.superclass => ObjectOppure sapere quali siano i suoi metodi:
>> puts 5.methods.sort % & * ** +...e cosi’ via la lista e’ piuttosto lunga. Come potremmo fare per ridurla ?, Beh, alcuni metodi di reflection sono piu’ specifici. Infatti, abbiamo a disposizione:
- protected_methods
- instance_methods
- public_instance_methods
- private_methods
- public_methods
- protected_instance_methods
- methods
- private_instance_methods
- singleton_methods
Ovviamente alcuni di questi metodi sono disponibili solo per Classi e non per oggetti qualunque (si tratta di quelli in cui e’ presente la parola instance).
In piu’, questi metodi accettano un parametro opzionale, se e’false verrannpo esclusi dall’elenco i metodi non definiti nella clase attuale. Anche questo sembra difficile ma non lo e’:
>> class C >> def met >> end >> end => nil >> C.new.public_methods => ["dup", "hash", "private_methods", "nil?", "tainted?", "class", "singleton_me thods", "=~", "__send__", "untaint", "instance_eval", "extend", "kind_of?", "obj ect_id", "instance_variable_get", "inspect", "frozen?", "taint", "id", "public_m ethods", "respond_to?", "equal?", "to_a", "clone", "method", "protected_methods" , "freeze", "instance_variable_set", "type", "is_a?", "methods", "==", "send", " met", "instance_of?", "===", "instance_variables", "__id__", "eql?", "to_s", "di splay"] >> C.new.public_methods false => ["met"]Ovviamente la reflection non si limita alla scoperta dei metodi. Possiamo ad esempio scoprire quali variabili sono state definite:
- local_variables()
- global_variables()
- instance_variables()
ci restituiscono degli array contenente i nomi delle variabili. In piu’:
- instance_variable_get(nome)
- instance_variable_set(nome,valore)
permettono di leggere e modificare delle variabili specifiche. Per fare riferimento a variabile possiamo usare un simbolo o una stringa, indifferentemente.
Ovviamente abbiamo a disposizione anche:
- const_get(nome)
- const_set(nome,valore)
- constants che fanno per le costanti quello che gli altri metodi fanno per le variabili.
Questi metodi possono sembrare poco utili, ma sono invece fondamentali. Anzitutto permettono di manipolare un programma in maniera molto dinamica e semplice, e poi permettono di evitare tutta una serie di problemi relativi ad eval().
eval() e’, nella maggior parte dei casi, il male.
Ma in altri linguaggi sarete costretti ad usare quella, se volete avere il valore di una variabile partendo dal nome.
In ruby, per fortuna, potete evitarlo.
Il vero mostro della reflection e’, comunque, il modulo ObjectSpace