ruby metaprogramming class-eval

Ruby-Usando class_eval para definir métodos



metaprogramming class-eval (3)

¡¡¡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 por la que necesita usar cadenas con class_eval es para poder consultar el valor de attr_name al definir el attr_name personalizado. De lo contrario, normalmente se pasaría un bloque a class_eval .

Estoy haciendo la clase de SaaS Stanford, tratando de hacer la Parte 5 de esta tarea

Me está costando mucho entender este concepto, esto es lo que he intentado hacer:

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, lea el capítulo sobre la metaprogramación del Libro de Ruby y todavía no lo entiendo, ¿puede alguien ayudarme a comprender esto?


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

Hay varias maneras de hacer eso. Una forma es if defined? @#{attr_name}_history DoStuffHere if defined? @#{attr_name}_history DoStuffHere


Debes notar que #{attr_name}_history es una variable de instancia, así que usa @ antes, como @foo en la clase a continuación

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

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