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

Я использую 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.

Где я должен положить файл, связанный с расширением ядра RubyModule класс? Может быть, в Ruby on Railslib каталог?Как правильно «расширить»Module класс в файле расширения ядра?Это правильный путь? То есть, например, я должен «расширить» другой класс (Object, BasicObject, Kernel, ...) скорее, чемModule? или мне вообще не следует реализовывать упомянутое расширение ядра?

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

Ответы на вопрос(3)

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"
Решение Вопроса

Вы могли бы использовать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, и вам будет хорошо ...

 Backo16 окт. 2012 г., 19:44
Я еще не тестировал ваш код, но с его помощью мне нужно расширить все классы / модули, где мне нужно будет запуститьalias_class_method метод. Это неэффективно (так как я могу сделать то же самое с Ruby Metaprogramming) и не DRYed?
 Vapire16 окт. 2012 г., 19:48
Я обновил свой ответ.
 Backo16 окт. 2012 г., 20:38
У меня все еще есть некоторые сомнения в «достоинстве» - «усилии» вашего подхода: могу ли / должен ли я использовать подход «открытого класса» для достижения того, что я хотел бы сделать?Почему нет?
 eruve26 июн. 2013 г., 06:56
+1, потому что после того, как я попробовал много гугл-примеров (возможно, устаревших?), Это тот, который работал для меня по крайней мере3.times{ puts "thanks!" } (Рубин-2.0.0-P195)
 Vapire16 окт. 2012 г., 21:11
Ну, я не могу ответить на этот вопрос, потому что вы не сказали, для чего именно это нужно ... Если вам нужен подход «открытого класса», чтобы выполнить то, что вы должны сделать, то другого пути не будет Боюсь, так как простой alias_method работает только с методами экземпляра. Но вопрос для меня: зачем вам псевдонимы методов класса? Какой конкретный случай? Я всегда придерживаюсь самого узкого подхода, то есть, если мне нужно определенное поведение для работы во всем дереве классов, используйте верхний класс, если 2 дочерних дерева во всем дереве, используют базовые классы 2 дочерних деревьев ...

Ваш ответ на вопрос