Как мы копируем одноэлементные методы между различными классами Ruby? - PullRequest
6 голосов
/ 08 декабря 2010

Я пытаюсь определить класс с помощью методов, а класс не имеет этих методов, а затем позволяю объекту последнего класса «изучать» методы из экземпляра первого класса.

Это моя попытка (Ruby 1.9.2) - она ​​ломается (в строке с комментарием «BREAKS!»), Когда я пытаюсь изменить значение «self» в лямбда-привязке.

Если вы можете решить, как решить эту проблему - я был бы рад узнать.

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>'

Ответы [ 2 ]

0 голосов
/ 09 декабря 2010

Если вы хотите скопировать методы из одного класса в другой, это возможно, но если метод изменяет состояние, он изменит состояние исходного объекта, а не объекта, с которым впоследствии будет связан метод (это потому, что метод не 'вместо этого на самом деле выполняется копирование в другую обертку метода Proc, привязанного к новому объекту как к методу):

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"
0 голосов
/ 09 декабря 2010

Использование 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"
...