My_define_method

Salve ragazzi, studiando meta-programming in Ruby mi sono riproposto di
scrivere un metodo, my_define_method(), che emuli Module#define_method o
che grosso modo, si comporti in maniera simile. ho pensato al seguente
snippet:

class Module

def my_define_method method_name, &block
self.class_eval(“def #{method_name} *args; #{ block.call() }; end;
end;”)
end

end

Il mio problema è : come faccio dentro #{block.call( … ) a riferirmi
ad
*args ?

Client code:

AClass.my_define_method “metodo” do |x,y,z|
puts “Numeri : #{x},#{y},#{z}”
end

obj = AClass.new
obj.metodo 1,2,3

self.class_eval("def #{method_name} *args; #{ block.call() }; end;
Cos stai usando come corpo della funzione il valore di ritorno
della Proc, non funzioner.

Il mio problema : come faccio dentro #{block.call( … ) a riferirmi
ad
*args ?

args un Array, per utilizzarlo come elenco di argomenti per una
funzione ti serve nuovamente l’asterisco. Esempio:

def print_numbers(a, b, c)
puts “#{a} #{b} #{c}”
end

print_numbers(1, 2, 3) # stampa 1 2 3
numbers = [1, 2, 3]
print_numbers(numbers) # ArgumentError: wrong number of arguments (1 for
3)
print_numbers(*numbers) # stampa 1 2 3

2011/8/23 Vogon P. [email protected]:

Salve ragazzi, studiando meta-programming in Ruby mi sono riproposto di
scrivere un metodo, my_define_method(), che emuli Module#define_method o
che grosso modo, si comporti in maniera simile. ho pensato al seguente
snippet:

class Module

def my_define_method method_name, &block
self.class_eval(“def #{method_name} *args; #{ block.call() }; end;
end;”)
end

end

non puoi farlo cos: block.call eseguita nello scope di
my_define_method, mentre args nello scope del metodo che stai
definendo.
Non ti do la soluzione che mi viene in mente ma se leggi sotto ti do
qualche hint. Fatto base: non credo possa funzionare usando class_eval
con una stringa come argomento :slight_smile:

s
p
o
i
l
e
r

in assenza di define_method o di Proc#to_source a occhio l’unica
cosa che puoi fare pensare a come funziona l’invocazione di un
metodo (ignorando l’ereditariet): c’ un nome (riferimento), del
codice e una tabella che ti fa andare da uno all’altro, che locale
per ogni classe. Ti tocca riprodurtelo in “userland”, un po’ come se
volessi riscriverti “eval”[0].

[0] che ok, se consideri ripper & co lo puoi pure fare ma penso esuli
dalla discussione


twitter: @riffraff
blog (en, it): www.riffraff.info riffraff.blogsome.com
work: cascaad.com www.circleme.com