2012-03-05 8 views
21

que estoy haciendo la clase SaaS Stanford, tratando de hacer la parte 5 de this assignmentRuby - El uso de class_eval para definir métodos

Estoy teniendo un momento muy difícil comprender este concepto, esto es lo que he intentado do:

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 

probablemente estoy haciendo todo tipo de cosas mal, leer el libro de capítulo Ruby on metaprogramming y todavía no lo consigue, puede que alguien me ayude a comprender esto?

+0

¿Esto realmente funciona? Si no, ¿cuál es el problema? ¡No estoy seguro de lo que la pregunta está pidiendo aquí! –

+0

eche un vistazo a http://stackoverflow.com/questions/9658724/ruby-metaprogramming-class-eval/9658775#9658775 es la misma pregunta de la tarea –

+2

Sí, y para la fecha en que lo pregunté primero: P – 8vius

Respuesta

40

Esto fue divertido!

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" 

Tenga en cuenta que la única razón es necesario utilizar cadenas con class_eval es por lo que se puede hacer referencia al valor de attr_name la hora de definir el colocador personalizado. De lo contrario, uno normalmente pasaría un bloque al class_eval.

+0

Gracias mucho: D – 8vius

+9

¡Explique los conceptos! ¡No solo dé la respuesta! Estás realmente lastimando a más personas que ayudando. –

+0

¿Qué hace esta sección? def # {attr_name} = (valor). Quiero decir, ¿qué estamos definiendo aquí? – dbalakirev

6

Con respecto a lo que has hecho, estás en la cúspide de la solución. Es solo que #{attr_name}_history no existe en su código. Tendrá que crear una variable de instancia y establecerla en cero si no existe. Lo que ya debe manejar empujando en la matriz, si existe.

Hay varias formas de hacerlo. Una forma es if defined? @#{attr_name}_history DoStuffHere

0

Debe notar que #{attr_name}_history es una variable de instancia, a fin de utilizar @ antes, como @foo de clase inferior a

def #{attr_name}=value, #{attr_name}= es el nombre del método, es value parámetro, mismo que def func parameter

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