2010-12-08 9 views
6

Estoy intentando definir una clase con métodos, y una clase que carece de esos métodos, y luego permitir que un objeto de la última clase 'aprenda' los métodos de una instancia de la clase anterior.¿Cómo se copian los métodos singleton entre diferentes clases de Ruby?

Este es mi intento (Ruby 1.9.2) - se rompe (en la línea comentada "BREAKS!") Cuando intento cambiar el valor de 'self' en el enlace lambda.

Si puede encontrar la manera de resolver esto, me fascinaría descubrirlo.

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 salida de este es:

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

¿Podría hacer un esfuerzo para formatear su código correctamente? – Theo

+1

No puede cambiar 'self' directamente, es de solo lectura. –

+0

He corregido el formato del código (sin cargo). Para la próxima vez, puede resaltar el código o la salida y luego hacer clic en el botón "101010" para formatearlo como código. –

Respuesta

0

Usando 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

Revisé el Object2module y eso se ve realmente interesante; Disfrutaré estudiando la fuente; ¡parece que Ruby proporciona continuamente más capas de fascinación! No podría decir a partir de la documentación si podemos usar la gema para 'enseñar' selectivamente singletons de otra clase, métodos específicos de otro singleton. Si no, ¿tiene alguna idea sobre cómo se puede ajustar el código para hacer esto? Muchas gracias por su respuesta, por cierto :) – Anthony

+0

fuente está aquí: https://github.com/banister/object2module – horseyguy

0

Si desea copiar a través de métodos de una clase a otra que es posible, pero si el método modifica el estado que modificará el estado en el objeto original, no en el objeto al que el método se enlaza posteriormente (esto se debe a que el método no se ha copiado en realidad en lugar de un envoltorio Proc del m ethod está vinculado al nuevo objeto como un método):

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" 
Cuestiones relacionadas