如何使用alias_method

时间:2016-02-13 08:39:55

标签: ruby metaprogramming

我最近一直在阅读Metaprogrammin Ruby第二版,在第5章结束时,他们提供了一些小测验

  

您的任务是更改Fixnum课程,以便1+1的答案变为3,而不是2

我理解教科书中的解决方案没有太大麻烦(他们直接重新开放Fixnum课程)。但我想尽可能地尝试将方法隔离到独立的Module。如下所示。

但是在下面运行会导致新定义的+内的无限lop。你能指出这段代码有什么问题吗?提前谢谢。

module PlusOneMore
  def self.prepended(base)
    base.class_eval{
      alias_method :original_plus, :+
    }
  end
  def +(n)
    original_plus(n).original_plus(1)
  end
end

Fixnum.class_eval do
  prepend PlusOneMore
end

puts 1.+(1)

2 个答案:

答案 0 :(得分:5)

问题是,当执行prepended挂钩时,您的覆盖已经已经发生。即当您运行alias_method :original_plus, :+时,+已指向您的覆盖。

您需要确保在 alias_method来电之后定义新方法或使用其他方法。

module Foo
  def self.included(klass)
    klass.class_eval do 
      alias_method :original_plus, :+
      define_method(:+) do |n|
        original_plus(n).original_plus(1)
      end
    end
  end
end

Fixnum.include(Foo)

puts 1.+(1)
# => 3

您还可以将prependsupersucc

一起使用
module Foo
  def +(n)
    super(n.succ)
  end
end

Fixnum.prepend(Foo)

puts 1.+(1)
# => 3

答案 1 :(得分:2)

您也可以使用Ruby refinements来达到类似的效果。

module Foo
  refine Fixnum do 
    alias_method :original_plus, :+
    def +(n)
      (self.original_plus(n)).next
    end
  end
end

using Foo

puts 1 + 1
#=> 3