I am trying to define a class with methods, and a class lacking those methods, and then allowing an object of the latter class to 'learn' the methods from an instance of the former class.
This is my attempt (Ruby 1.9.2) - it breaks (at the line commented "BREAKS!")when I try to change the value of 'self' in the lambda binding.
If you can work out how to solve this - I'd be fascinated to find out.
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!")
The output of this is:
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>'
                If you want to copy across methods from one class to another it's possible, but if the method modifies state it will modify state on the original object not on the object the method is subsequently bound to (this is because the method isn't really copied across instead a Proc wrapper of the method is bound to the new object as a method):
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"
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With