Как создать псевдоним метода класса в модуле?

Я использую Ruby v1.9.2 и гем Ruby on Rails v3.2.2. У меня был следующий модуль

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. Где я должен положить файл, связанный с расширением ядра Ruby Module учебный класс? Может быть в Ruby on Rails lib каталог?
  2. Как правильно "расширить" Module класс в файле расширения ядра?
  3. Это правильный путь? То есть, например, я должен "расширить" другой класс (Object, BasicObject, Kernel,...) скорее, чем Module? или мне вообще следует избегать реализации упомянутого расширения ядра?

Но, что более важно, есть ли функция Ruby, которая делает то, что я пытаюсь сделать, чтобы мне не пришлось расширять его классы?

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, и вам будет хорошо...

Я нашел ответ на этом сайте: 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

Принятый ответ сбивал с толку и не работал.

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"
Другие вопросы по тегам