6

我正在使用 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起别名。所以,我陈述了以下(不工作)代码:

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 Railslib目录中?
  2. 我应该如何正确“扩展”Module核心扩展文件中的类?
  3. 这是正确的方法吗?也就是说,例如,我应该“扩展”另一个类 ( Object, BasicObject, Kernel, ...) 而不是Module? 或者,我应该完全避免实施上述核心扩展吗?

但是,更重要的是,是否有一个 Ruby 功能可以让我完成我想要完成的工作,这样我就不必扩展它的类?

4

3 回答 3

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_method中实现Object。所以你可以简单地扩展Object类,所以每个类都应该有可用的方法......

Object.extend(MyModule)

把它放在你的 Rails 应用程序的初始化程序中,你应该很高兴......

于 2012-10-16T16:57:16.923 回答
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
于 2013-09-06T21:21:56.173 回答
1

接受的答案令人困惑并且不起作用。

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"
于 2015-03-10T07:42:00.353 回答