2012-03-05 3 views
21
내가의 제 5 부 일을하려고, SaaS는 스탠포드 클래스를하고 있어요

을 정의 할 수 class_eval 사용 this assignment루비 - 방법

나는이 개념을 파악 정말 힘든 시간을 보내고있어

, 이것은 내가 시도 한 것입니다 아마 잘못된 모든 일을하고 있어요

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 

, 메타 프로그래밍에 루비 장의 책을 읽고 난 아직도 이해가 안가, 누군가가 나이 이해 도움이 될 수 있습니다합니까?

+0

실제로 작동합니까? 그렇지 않다면 무엇이 문제입니까? 그 질문이 여기서 무엇을 요구하는지 확실하지 않습니다! –

+0

http://stackoverflow.com/questions/9658724/ruby-metaprogramming-class-eval/9658775#9658775 같은 숙제에 관한 질문입니다. –

+2

예, 제가 처음에 물어 본 날짜 : P – 8vius

답변

40

재미있었습니다! 사용자 정의 세터를 정의 할 때 attr_name을 참조 할 수 있도록 class_eval와 문자열을 사용하는 데 필요한 유일한 이유입니다

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" 

참고. 그렇지 않으면 일반적으로 블록을 class_eval으로 전달합니다.

+0

감사합니다. 대단히 : D – 8vius

+9

개념을 설명하십시오! 답을주지 마라. 도와주는 것보다 더 많은 사람들을 아프게합니다. –

+0

이 섹션의 기능은 무엇입니까? def # {attr_name} = (값). 우리가 실제로 여기서 정의하고있는 것은 무엇입니까? – dbalakirev

6

당신이 해왔 던 것과 관련하여 당신은 실제로 솔루션의 첨단에 있습니다. 코드에 #{attr_name}_history이 존재하지 않는 것입니다. 인스턴스 변수를 작성하고 존재하지 않는 경우이를 nil로 설정해야합니다. 존재하는 경우 이미 배열로 밀어 넣는 것을 처리해야합니다.

여러 가지 방법이 있습니다. 한 가지 방법은 당신이 #{attr_name}_history는 인스턴스 변수 것을 알 수 있으므로

def #{attr_name}=value 아래의 클래스 @foo처럼 전 @ 사용해야합니다 if defined? @#{attr_name}_history DoStuffHere

0

이며, #{attr_name}= 메소드 이름이, valuedef func parameter

같은 매개 변수입니다
def #{attr_name}=value 
    (!defined? @#{attr_name}_history) ? @#{attr_name}_history = [nil, value] : @#{attr_name}_history << value 
end