2012-03-05 9 views
21

che sto facendo la classe SaaS Stanford, cercando di fare parte 5 this assignmentRubino - Utilizzando class_eval per definire metodi

Sto avendo un momento davvero difficile afferrare questo concetto, questo è quello che ho cercato di fare:

class Class 
    def attr_accessor_with_history(attr_name) 
    attr_name = attr_name.to_s 
    attr_reader attr_name 
    attr_reader attr_name + '_history' 
    class_eval %Q'{def #{attr_name}(a);#{attr_name}_history.push(a) ; end;}' 
    end 
end 

probabilmente sto facendo un sacco di cose sbagliate, a leggere metaprogrammazione The Book Of capitolo Ruby e io ancora non capisco, qualcuno può aiutarmi a comprendere questo?

+0

Funziona davvero? In caso contrario, qual è il problema? Non sono proprio sicuro di cosa la domanda stia chiedendo qui! –

+0

dare un'occhiata a http://stackoverflow.com/questions/9658724/ruby-metaprogramming-class-eval/9658775#9658775 è la stessa domanda di compiti a casa –

+2

Sì, e alla data che ho chiesto prima: P – 8vius

risposta

40

Questo è stato divertente !!!

class Class 
    def attr_accessor_with_history(attr_name) 
     attr_name = attr_name.to_s # make sure it's a string 
     attr_reader attr_name 
     attr_reader attr_name+"_history" 
     class_eval %Q" 
      def #{attr_name}=(value) 
       if !defined? @#{attr_name}_history 
        @#{attr_name}_history = [@#{attr_name}] 
       end 
       @#{attr_name} = value 
       @#{attr_name}_history << value 
      end 
     " 
    end 
end 

class Foo 
    attr_accessor_with_history :bar 
end 

class Foo2 
    attr_accessor_with_history :bar 
    def initialize() 
     @bar = 'init' 
    end 
end 

f = Foo.new 
f.bar = 1 
f.bar = nil 
f.bar = '2' 
f.bar = [1,nil,'2',:three] 
f.bar = :three 
puts "First bar:", f.bar.inspect, f.bar_history.inspect 
puts "Correct?", f.bar_history == [f.class.new.bar, 1, nil, '2', [1,nil,'2',:three], :three] ? "yes" : "no" 
old_bar_history = f.bar_history.inspect 

f2 = Foo2.new 
f2.bar = 'baz' 
f2.bar = f2 
puts "\nSecond bar:", f2.bar.inspect, f2.bar_history.inspect 
puts "Correct?", f2.bar_history == [f2.class.new.bar, 'baz', f2] ? "yes" : "no" 

puts "\nIs the old f.bar intact?", f.bar_history.inspect == old_bar_history ? "yes" : "no" 

Nota che l'unico motivo è necessario utilizzare corde con class_eval è così che è possibile fare riferimento al valoredi attr_name quando si definisce il setter personalizzato. Altrimenti normalmente si passerebbe un blocco a class_eval.

+0

Grazie molto: D – 8vius

+9

Spiega i concetti! Non dare solo la risposta! Stai davvero ferendo più persone che aiutando. –

+0

Cosa fa questa sezione? def # {attr_name} = (valore). Intendo cosa stiamo definendo qui? – dbalakirev

6

Per quanto riguarda ciò che hai fatto, in realtà sei al culmine della soluzione. È solo che #{attr_name}_history non esiste nel tuo codice. Sarà necessario creare una variabile di istanza e impostarla su zero se non esiste. Quello che hai già dovrebbe gestire la spinta nell'array se esiste.

Ci sono diversi modi per farlo. Un modo è if defined? @#{attr_name}_history DoStuffHere

0

È necessario notare che #{attr_name}_history è una variabile di istanza, in modo da utilizzare @ prima, come @pippo nella classe sotto

def #{attr_name}=value, #{attr_name}= è il nome del metodo, è value parametro, uguale def func parameter

def #{attr_name}=value 
    (!defined? @#{attr_name}_history) ? @#{attr_name}_history = [nil, value] : @#{attr_name}_history << value 
end 
Problemi correlati