使用`alias`关键字扩充方法

时间:2018-04-28 17:23:52

标签: ruby

通过The Ruby programming language阅读后,我找到了使用alias关键字来扩充方法的示例。

def hello                      # A nice simple method
  puts 'Hello world'           # Suppose we want to augment it...
end

alias original_hello hello     # Give the method a backup name

def hello                      # Now we define a new method with the old name
  puts "Your attention please" # That does some stuff
  original_hello               # Then calls the original method
  puts "This has been a test"  # Then does some more stuff
end

确实original hello保留旧行为,即使重新定义了它所引用的方法之后也是如此。

但是,在我看来,这个例子几乎没有说明这种技术的真正好处。不能以传统的方式实现(例如通过提供块)?那为什么要用这个成语呢?当使用alias进行扩充真的有意义时,任何人都可以提供来自现实世界的示例吗?

2 个答案:

答案 0 :(得分:5)

Rails代码充满了这些。想象一下原始hello方法不属于您的代码库。在第三方库的某处,在类do_stuff(stuff)上声明了Stuffer方法。

你想要例如调试这个方法。你重新打开这个类,定义一个别名,然后瞧瞧:

class Stuffer
  alias original_do_stuff do_stuff
  def do_stuff(stuff)
    puts stuff.inspect
    original_do_stuff(stuff)
  end
end

现在所有代码,包括您可能甚至不知道的原始第三方代码,都会打印出传递给do_stuff每次调用的参数。

现实生活中的例子(不要在家里和学校里试试这个:)

class String
  alias _inspect inspect
  def inspect
    puts "I am a string: “#{_inspect}”"
  end
end
"abc".inspect
#⇒ I am a string: “"abc"”

答案 1 :(得分:4)

  

当使用alias进行扩充真的有意义时,任何人都能提供来自现实世界的示例吗?

不是真的。今天,你会这样做(例如取自@mudasobwa's answer):

module WeirdInspectRefinement
  module WeirdInspectExtension
    def inspect
      "I am a string: “#{super}”"
    end
  end

  refine String do
    prepend WeirdInspectExtension
  end
end

using WeirdInspectRefinement

p 'abc'.inspect
#⇒ 'I am a string: “"abc"”'

但即使在Module#prependRefinements存在之前,也没有理由使用alias来保留未使用的方法来污染命名空间,Rails abandoned it quite a while ago

class String
  old_inspect = instance_method(:inspect)

  define_method(:inspect) do
    "I am a string: “#{old_inspect.bind(self).()}”"
  end
end

'abc'.inspect
#⇒ 'I am a string: “"abc"”'