2010-12-08 5 views
6

Ich versuche, eine Klasse mit Methoden zu definieren, und eine Klasse, die diese Methoden fehlt, und dann einem Objekt der letzteren Klasse zu erlauben, die Methoden von einer Instanz der früheren Klasse zu "lernen".Wie kopieren wir Singleton-Methoden zwischen verschiedenen Ruby-Klassen?

Dies ist mein Versuch (Ruby 1.9.2) - es bricht (in der Zeile kommentierte "Breaks!"), Wenn ich versuche, den Wert von "Selbst" in der Lambda-Bindung zu ändern.

Wenn Sie herausfinden können, wie Sie das lösen - würde mich das faszinieren.

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

Der Ausgang dieses ist:

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

Konnten Sie sich bemühen, Ihren Code richtig zu formatieren? – Theo

+1

Sie können "self" nicht direkt ändern, es ist schreibgeschützt. –

+0

Ich habe den Code formatiert (kostenlos). Beim nächsten Mal können Sie den Code oder die Ausgabe markieren und dann auf die Schaltfläche "101010" klicken, um sie als Code zu formatieren. –

Antwort

0

Mit 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

Ich habe das Objekt2Module ausgecheckt und das sieht wirklich interessant aus; Ich werde es genießen, die Quelle zu studieren; es scheint, dass Ruby immer mehr Faszinationsebenen liefert! Ich konnte aus der Dokumentation nicht ersehen, ob wir den Edelstein dazu verwenden können, Singles aus einer anderen Klasse, bestimmte Methoden aus einem anderen Singleton, selektiv zu "lehren". Wenn nicht - haben Sie irgendwelche Gedanken darüber, wie der Code dafür angepasst werden könnte? Vielen Dank für Ihre Antwort, btw :) – Anthony

+0

Quelle ist hier: https://github.com/banister/object2module – horseyguy

0

Wenn Sie über Methoden von einer Klasse in eine andere kopieren möchten es möglich ist, aber wenn das Verfahren Ändert den Zustand, in dem der Status für das ursprüngliche Objekt geändert wird, nicht für das Objekt, an das die Methode anschließend gebunden wird (weil die Methode nicht wirklich kopiert wird, sondern eine Proc-Wrapper des m ethod ist an das neue Objekt als Methode gebunden):

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" 
Verwandte Themen