Je fais la SaaS Stanford, en essayant de faire la partie 5 de cette affectation
J'ai vraiment du mal à saisir ce concept, voici ce que j'ai tenté de faire:
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
Je fais probablement toutes sortes de choses mauvaises, lisez le chapitre du livre de Ruby sur la métaprogrammation et je ne comprends toujours pas, est-ce que quelqu'un peut m'aider à comprendre cela?
C'était amusant!!!
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"
Notez que la seule raison pour laquelle vous devez utiliser des chaînes avec class_eval est que vous pouvez vous référer au value de attr_name
lors de la définition du programme de définition personnalisé. Sinon, on passerait normalement un bloc à class_eval
.
En ce qui concerne ce que vous avez fait, vous êtes sur le point de connaître la solution. C'est juste que #{attr_name}_history
n'existe pas dans votre code. Vous devrez créer une variable d'instance et la définir sur nil si elle n'existe pas. Ce que vous avez déjà devrait gérer l’introduction dans le tableau s’il existe.
Il y a plusieurs façons de le faire. Une façon est if defined? @#{attr_name}_history DoStuffHere
Vous devez remarquer que #{attr_name}_history
est une variable d'instance, utilisez donc @ before, comme @foo dans la classe ci-dessous.
def #{attr_name}=value
, #{attr_name}=
est le nom de la méthode, value
est le paramètre, identique à def func parameter
def #{attr_name}=value
(!defined? @#{attr_name}_history) ? @#{attr_name}_history = [nil, value] : @#{attr_name}_history << value
end