在别名中包装继承的方法

时间:2013-12-25 02:38:12

标签: ruby inheritance methods

我希望通过继承基类来提供一致的接口。但是该基类的某些方法我想用其他功能包装。

假设每个子类都有一个eat方法:

class ClassyAnimal

  def self.inherited(base)
    base.class_eval do
      alias :eat_without_napkin :eat
      alias :eat :eat_with_napkin 
    end
  end

  def eat_with_napkin
    begin
      eat_without_napkin
    rescue FoodOutOfMouthError
      puts 'phew!'
    end
  end

  def eat
    raise 'Please implement the #eat method.'
  end
end

class ClassyWalrus < ClassyAnimal

  def eat
    puts 'Eating Cronuts.'
    raise FoodOutOfMouthError.new('Damn these tusks!')
    puts 'Finishing my meal.'
  end
end

class FoodOutOfMouthError < StandardError; end

现在我希望ClassyWalrus.new.eat输出以下内容:

Eating Cronuts.
phew!

不幸的是,我们得到以下信息:

Eating Cronuts.
FoodOutOfMouthError: Damn these tusks!

在继承时,因此在alias时,#eat被定义为ClassyAnimal中的一个而不是ClassyWalrus中的一个。别名#eat然后被子类覆盖,并且包装丢失。

可以做些什么?

2 个答案:

答案 0 :(得分:1)

尝试以下代码添加。

课程ClassyAnimal中的

  def eat_with_napkin
    begin
      yield
    rescue FoodOutOfMouthError
      puts 'phew!'
    end
  end
课程ClassyWalrus中的

  def eat
    puts 'Eating Cronuts.'
    superclass.eat do
      raise FoodOutOfMouthError.new('Damn these tusks!')
    end
    puts 'Finishing my meal.'
  end

答案 1 :(得分:0)

我想到的一种可能性,我相信ActionMailer是如何做到的,是将子方法定义为实例变量,但是在类本身上调用它。

这不是我正在寻找的,所以我不接受这个答案,只是为了记录它。

class ClassyAnimal
  def self.eat
    if instance_methods.include? :eat
      begin
        self.new.eat
      rescue FoodOutOfMouthError
        puts 'phew!'
      end
    end
  end
end

class ClassyWalrus < ClassyAnimal

  def eat
    puts 'Eating Cronuts.'
    raise FoodOutOfMouthError.new('Damn these tusks!')
    puts 'Finishing my meal.'
  end
end

class FoodOutOfMouthError < StandardError; end

将被称为:

ClassyWalrus.eat
# outputs => Eating Cronuts.
# outputs => phew!