Как создать псевдоним метода класса в модуле?
Я использую 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.
- Где я должен положить файл, связанный с расширением ядра Ruby
Module
учебный класс? Может быть в Ruby on Railslib
каталог? - Как правильно "расширить"
Module
класс в файле расширения ядра? - Это правильный путь? То есть, например, я должен "расширить" другой класс (
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"