2012-03-05 30 views
21
ben 5. kısmını yapmaya çalışıyor, SaaS Stanford sınıfını yapıyorum

tanımlamak için class_eval kullanma this assignmentYakut - yöntemleri

Ben bu kavramı kavrama gerçekten zorlanıyorum

, bu şimdiye denediğimizi budur muhtemelen yanlış her türlü şeyi yapıyorum

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 

, metaprogramlama üzerinde Yakut bölüm Kitabı okumak ve hala alamadım, birisi bana bunu idrak yardımcı olabilir: do?

+0

Bu gerçekten çalışıyor mu? Değilse, sorun nedir? Sorunun burada sorduğundan emin değilim! –

+0

http://stackoverflow.com/questions/9658724/ruby-metaprogramming-class-eval/9658775#9658775 adresinde aynı ödev sorusu var –

+2

Evet ve ilk sorduğum tarihe kadar: P – 8vius

cevap

40

Bu eğlenceli oldu! özel ayarlayıcı tanımlarken attr_name ait değerine atıfta böylece class_eval dizelerle kullanmaya gerek tek nedeni olduğunu

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" 

Not. Aksi halde normalde bir blok class_eval'a geçer.

+0

Teşekkür ederim Çok fazla: D – 8vius

+9

Kavramları açıklayın! Sadece cevabı vermeyin! Gerçekten yardım etmekten çok insanı incitiyorsun. –

+0

Bu bölüm ne yapıyor? def # {attr_name} = (değer). Yani aslında burada neyi tanımlarız? – dbalakirev

6

Yaptıklarınızla ilgili olarak, aslında çözümün zirvesindeydiniz. Sadece #{attr_name}_history kodunuzda mevcut değil. Bir örnek değişkeni oluşturmanız ve mevcut değilse sıfırlamaya ayarlamanız gerekecektir. Halihazırda var ise, diziye itmeyi başarabilirsiniz.

Bunu yapmanın birkaç yolu vardır. Tek yönlü Sen #{attr_name}_history bir örnek değişken olduğunu fark, bu yüzden

def #{attr_name}=value aşağıda sınıfta @foo gibi önce @ kullanmalıdır if defined? @#{attr_name}_history DoStuffHere

0

olduğunu #{attr_name}= yöntem adıdır valuedef func parameter

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