如何在模块中对类方法进行别名?

时间:2012-10-16 15:03:19

标签: ruby-on-rails ruby metaprogramming core extending

我正在使用Ruby v1.9.2和Ruby on Rails v3.2.2 gem。我有以下模块

module MyModule
  extend ActiveSupport::Concern

  included do
    def self.my_method(arg1, arg2)
      ...
    end
  end
end

我希望为类方法 my_method添加别名。所以,我说了以下( not working )代码:

module MyModule
  extend ActiveSupport::Concern

  included do
    def self.my_method(arg1, arg2)
      ...
    end

    # Note: the following code doesn't work (it raises "NameError: undefined
    # local variable or method `new_name' for #<Class:0x00000101412b00>").
    def self.alias_class_method(new_name, old_name)
      class << self
        alias_method new_name, old_name
      end
    end

    alias_class_method :my_new_method, :my_method
  end
end

换句话说,我想在某处扩展Module课程,以便在整个alias_class_method中添加MyModule方法。但是,我想在所有Ruby on Rails应用程序中使工作可用

  1. 我应该把文件放在Module类的Ruby核心扩展名中?也许在Ruby on Rails lib目录?
  2. 我应该如何正确地“扩展”核心扩展文件中的Module类?
  3. 这是正确的方法吗?也就是说,例如,我应该“扩展”另一个类(ObjectBasicObjectKernel,...)而不是Module?或者,我是否应该完全避免实施上述核心扩展?
  4. 但是,更重要,是否有一个Ruby功能可以实现我想要完成的功能,这样我就不必扩展它的类了?

3 个答案:

答案 0 :(得分:3)

您可以使用define_singleton_method将旧方法换成新名称,如下所示:

module MyModule
  def alias_class_method(new_name, old_name)
    define_singleton_method(new_name) { old_name }
  end
end

class MyClass
  def my_method
    puts "my method"
  end
end

MyClass.extend(MyModule)
MyClass.alias_class_method(:my_new_method, :my_method)
MyClass.my_new_method     # => "my method"

回答你的评论,你不必手动扩展每一堂课。 define_singleton_methodObject类中实现。所以你可以简单地扩展Object类,所以每个类都应该有可用的方法......

Object.extend(MyModule)

将它放在Rails应用程序的初始化程序中,你应该好好去......

答案 1 :(得分:1)

我在这个网站上找到了答案:http://engineering.lonelyplanet.com/2012/12/09/monitoring-our-applications-ruby-methods/

解决方案是将class_eval与块一起使用。这样就可以使用封闭范围内的变量。

module Alias

  def trigger
    @trigger = true
  end

  def method_added(name)
    if @trigger
      @trigger = false
      with_x = "#{name}_with_x"
      without_x = "#{name}_without_x"
      define_method(with_x) do
        "#{send(without_x)} with x"
      end
      alias_method without_x, name
      alias_method name, with_x
    end
  end

  def singleton_method_added(name)
    if @trigger
      @trigger = false
      with_x = "#{name}_with_x"
      without_x = "#{name}_without_x"
      define_singleton_method(with_x) do
        "singleton #{send(without_x)} with x"
      end
      singleton_class.class_eval do
        alias_method without_x, name
        alias_method name, with_x
      end
    end
  end

end

class TestAlias

  extend Alias

  trigger
  def self.foo
    'foo'
  end

  trigger
  def bar
    'bar'
  end

end

TestAlias.foo # => 'singleton foo with x'
TestAlias.new.bar # => 'bar with x'

如果您没有singleton_class,那么您应该升级您的Ruby版本。如果那是不可能的,你可以这样做:

class Object
  def singleton_class
    class << self
      self
    end
  end
end

答案 2 :(得分:0)

接受的答案令人困惑,但没有奏效。

class Module
  def alias_class_method(new_name, old_name)
    define_singleton_method(new_name, singleton_method(old_name))
  end
end

module MyModule
  def self.my_method
    'my method'
  end
end

MyModule.alias_class_method(:my_new_method, :my_method)
MyModule.my_new_method # => "my_method"