Часто перед программистом становится необходимость создания второго имени для метода — псевдонима метода. Создание псевдонима может нам понадобится, например если мы хотим переопределить метод, но при этом данный метод нам так же необходим. Для этих задач Ruby предоставляет нам такие инструменты, как alias и alias_method. Псевдоним — это не просто другое имя, это полная, точная копия метода, которой дано новое имя, благодаря чему мы можем изменить один метод (оригинал) не боясь, что это как-то отразится на другом (псевдониме — копии). Давайте рассмотрим пример использования alias:
def my_method(a,b) puts a+b end alias :mymeth : my_method my_method(2,3) #=> 5 mymeth(1,4) #=> 5
Теперь, когда мы создали копию нашего метода, мы можем переопределить метод с оригинальным названием my_method:
def my_method (a,b) puts a**b end my_method(2,3) #=> 8 mymeth(2,3) #=> 5
Люди не имеющие практики программирования могут не понимать зачем необходимо такое вот переопределение методов. Чтобы развеять их сомнения в необходимости синонимов, поделюсь лично своим примером использования. Допустим, у меня есть класс, который определяет атрибуты и методы блоков отработки залежи полезного ископаемого, объект этого класса — модель блока в котором проводятся горные работы. В этом классе содержится следующий метод:
def ore (arg=:w) result = ... case arg when :p; result = ... when :v; result = ... when :vw; result = ... end result end
Данный метод высчитывает и возвращает некоторые параметры руды: % от общего запаса, который нам удалось изъять из блока, удельный вес добытой руды, ее объем и общий вес добытой руды. Поскольку я разделяю логику и представление, я создаю новый класс, который отвечает за представление данных, в нем метод ore уже не возвращает значение, а печатает его. Это удобнее, чем писать: puts ore :w и т.д.. Метод для печати значения выглядит следующим образом:
alias :r_ore :ore def ore (arg=:w) result = "ВЕС РУДЫ: #{ore :w}" case arg when :p; result = "ПРОЦЕНТ ИЗВЛЕЧЕННОЙ РУДЫ: #{r_ore :p}" when :v; result = "ОБЪЕМ ИЗВЛЕЧЕННОЙ РУДЫ: #{r_ore :v}" when :vw; result = "ОБЪЕМНЫЙ ВЕС ДОБЫТОЙ РУДЫ: #{r_ore :vw}" end puts result end
Теперь понятны выгоды использования alias?
alias_metod я никогда не пользовал и считал, что это просто синоним для alias, но когда начал писать статью, решил все таки проверить так ли это. Вот к каким выводам я пришел:
class Cls def initialize (a=5, b=10) @a = a @b = b end # alias def sum @a + @b end alias :old_sum :sum def sum puts @a + @b end #alias_method def div @a / @b.to_f end alias_method :old_div, :div def div puts @a / @b.to_f end end Cls.new.sum puts Cls.new.old_sum Cls.new.div puts Cls.new.old_div #Выходит, что alias и alias_method эквивалентны? - Нет! def my_method (a = 10, b = 20) a + b end alias_method :mymeth, :my_method #=> undefined method `alias_method' for main:Object (NoMethodError) alias mymeth my_method puts mymeth puts my_method
Из этого следует, что alias_method не работает вне контекста какого-нибудь класса.
В чем еще разница? — alias это ключевое слово языка Ruby, а alias_method — метод класса Module. Из этого следует, что методу alias_method имена методов следует передавать в виде строк или символов, которые разделены запятой. Ключевому слову alias можно просто передавать имена методов (в том смысле, что они могут представляться не как символы и строки, а просто вы вводите имена методов и все, даже не разделяя их запятыми).
class MyClass end MyClass.instance_eval {alias c class} puts MyClass.new.c # undefined method `c' for # (NoMethodError) MyClass.instance_eval {alias_method :cl, :class} puts MyClass.new.cl#=> MyClass #Оппа! alias не работает в контексте объекта, а alias_method работает! MyClass.class_eval {alias c class} puts MyClass.new.c #=> MyClass MyClass.class_eval {alias_method :cls, :class} puts MyClass.new.cls #=> MyClass
Я нашел это различие, но не могу понять какую из этого можно взять пользу. Далее я начал гуглить и нашел действительно полезный комментарий в котором было описано еще одно различие:
class Parent def self.redef alias redef_method my_method end def self.redef_m alias_method :redef_method, :my_method end def my_method puts "Parent" end end class Child1 < Parent def my_method puts "Child" end redef() end class Child2 < Parent def my_method puts "Child" end redef_m() end Child1.new.redef_method #=> Parent Child2.new.redef_method #=> Child
В этом уже можно найти какой-нибудь смысл, однако я не видел, чтобы кто-то этим пользовался. Исходя из того, что я вообще мало чего видел, это нельзя считать каким-либо показателем того, что пользоваться этой особенностью нельзя.
Если вы что-то знаете о различиях в alias и alias_method отпишитесь пожалуйста в комментариях.
Ваши комментарии — лучший мотиватор для написания новых постов!