2010-12-08 6 views
6

메소드가있는 클래스와 그 메소드가없는 클래스를 정의하려고 시도하고 있으며, 후자의 클래스의 객체가 이전 클래스의 인스턴스에서 메소드를 '학습'할 수있게하려고합니다.서로 다른 Ruby 클래스간에 싱글 톤 메소드를 복사하는 방법은 무엇입니까?

내 시도 (Ruby 1.9.2) - 람다 바인딩에서 'self'의 값을 변경하려고 시도 할 때 (줄 바꿈으로 "BREAKS!") 중단됩니다.

당신이 이것을 해결하는 방법을 찾을 수 있다면 - 나는 알아 내서 매료 될 것입니다.

class Skill 

    attr_accessor :name 
    attr_accessor :technique 

    def initialize(name, &technique_proc) 
    @name = name 
    @technique = lambda(&proc) 
    end 

end 

class Person 

    attr_accessor :name 

    def initialize(name) 
    @name = name 
    end 

    def method_missing(m, *args) 
    "#{@name} the #{self.class}: I don't know how to #{m}" 
    end 

    def learn_skill(skill) 
    puts "#{@name} the #{self.class} is learning skill: #{skill.name}" 
    actual_self = self 
    eval "self = #{actual_self}", skill.technique.binding ####### BREAKS! 
    define_singleton_method skill.name.to_sym, skill.technique 
    end 

    def teach_skill(skill_name) 
    skill = nil 
    if self.respond_to?(skill_name) 
     puts "#{@name} the #{self.class} is teaching skill: #{skill_name}" 
     skill_method = self.method(skill_name.to_sym) 
     skill_proc = skill_method.to_proc 
     skill_lambda = lambda(&skill_proc) 
     skill = Skill.new(skill_name, &skill_lambda) 
    end 
    skill 
    end 

end 

class Teacher < Person 

    def speak(sentence) 
    "#{@name} the #{self.class} is now saying \"#{sentence}\"!" 
    end 

    def jump(number_of_feet) 
    "#{name} the #{self.class} is now jumping #{number_of_feet} high!" 
    end 

end 

miss_mollyflop = Teacher.new("Miss Mollyflop") 
little_billey = Person.new("Little Billy") 

puts miss_mollyflop.speak("Good morning, children!") 
puts little_billey.speak("Good morning, Miss Mollyflop!") 

speak_skill = miss_mollyflop.teach_skill("speak") 
little_billey.learn_skill(speak_skill) 

puts little_billey.speak("Good morning, Miss Mollyflop!") 

이의 출력은 다음과 같습니다

Miss Mollyflop the Teacher is now saying "Good morning, children!"! 
Little Billy the Person: I don't know how to speak 
Miss Mollyflop the Teacher is teaching skill: speak 
Little Billy the Person is learning skill: speak 
test.rb:27:in `eval': (eval):1: Can't change the value of self (SyntaxError) 
self = #<Person:0x1482270> 
    ^
(eval):1: syntax error, unexpected $end 
self = #<Person:0x1482270> 
         ^
     from test.rb:27:in `learn_skill' 
     from test.rb:64:in `<main>' 
+1

코드를 올바르게 포맷 할 수 있습니까? – Theo

+1

'self'는 직접 변경할 수 없으며 읽기 전용입니다. –

+0

코드 포맷이 고정되어 있습니다 (무료). 다음 번에는 코드 또는 출력을 강조 표시 한 다음 "101010"버튼을 클릭하여 코드 형식을 지정할 수 있습니다. –

답변

0

사용 Object2module : gem install object2module

require 'object2module' 

o = Object.new 
def o.speak 
    puts "hello from o" 
end 

m = Object.new 
m.gen_extend o 

m.speak #=> "hello from o" 
+0

Object2module을 체크 아웃했는데 정말 재미있어 보입니다. 나는 근원을 공부하는 것을 즐긴다. Ruby는 계속해서 더 많은 매혹적인 레이어를 제공합니다! 문서에서 다른 클래스의 싱글 톤을 선택적으로 '가르치기', 다른 싱글 톤의 특정 메서드를 사용할 수 있는지 여부를 알 수 없었습니다. 그렇지 않은 경우 - 코드를 조정하는 방법에 대한 의견이 있습니까? 고맙습니다. 답변 : btw : – Anthony

+0

출처 : https://github.com/banister/object2module – horseyguy

0

당신이 가능성이 다른 하나 개의 클래스에서 방법을 통해 복사 할 경우,하지만 만약 방법 메소드가 실제로 바인드 된 객체에없는 원래 객체의 상태를 수정하는 상태를 수정합니다 (이는 메소드가 실제로 m의 Proc wrapper 대신에 실제로 복사되지 않기 때문입니다). ethod는 메소드로 새 객체에 바인딩됩니다.

a = Object.new 
def a.hello 
    puts "hello world from a" 
end 

b = Object.new 
b.define_singleton_method(:hello, &a.method(:hello)) 
b.hello #=> "hello world from a"