2010-12-08 44 views
6

J'essaie de définir une classe avec des méthodes, et une classe qui manque de ces méthodes, puis permettant à un objet de cette dernière classe d '«apprendre» les méthodes à partir d'une instance de la première classe.Comment copier des méthodes singleton entre différentes classes Ruby?

Ceci est ma tentative (Ruby 1.9.2) - il casse (à la ligne commentée "BREAKS!") Quand j'essaie de changer la valeur de 'self' dans la liaison lambda.

Si vous pouvez résoudre ce problème, je serais ravi de le découvrir.

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!") 

La sortie de c'est:

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

Pourriez-vous faire un effort pour formater correctement votre code? – Theo

+1

Vous ne pouvez pas changer 'self' directement, c'est en lecture seule. –

+0

J'ai corrigé le formatage du code (sans frais). Pour la prochaine fois, vous pouvez mettre en évidence le code ou la sortie, puis cliquez sur le bouton "101010" pour le formater en code. –

Répondre

0

En utilisant 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

J'ai vérifié le Object2module et cela a l'air vraiment intéressant; j'apprécierai étudier la source; il semble que Ruby fournit continuellement plus de couches de fascination! Je ne pouvais pas dire à partir de la documentation si nous pouvions utiliser la gemme pour «enseigner» sélectivement des singletons d'une autre classe, des méthodes spécifiques d'un autre singleton. Si non, avez-vous des idées sur la façon dont le code pourrait être ajusté pour faire cela? Merci beaucoup pour votre réponse, btw :) – Anthony

+0

source est ici: https://github.com/banister/object2module – horseyguy

0

Si vous souhaitez copier dans les méthodes d'une classe à une autre, il est possible, mais si la méthode modifie l'état il va modifier l'état sur l'objet d'origine pas sur l'objet auquel la méthode est liée par la suite (parce que la méthode n'est pas vraiment copiée à la place à la place d'une enveloppe Proc de la m ethod est lié au nouvel objet en tant que méthode):

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"