Псевдоним класса в Ruby

Я разрабатываю новое приложение Rails на основе аналогичного существующего. В моем старом приложении у меня есть класс Coupon, который очень похож на Ticket в моем новом приложении. Я хочу повторно использовать весь код в Coupon, но с новым именем класса.

Поскольку рефакторинг в Rails громоздок, мне интересно, есть ли способ создать псевдоним для класса в Ruby (аналогично псевдониму для атрибутов и методов).


person AdamNYC    schedule 17.10.2011    source источник
comment
Как насчет наследства? Примерно так: класс Купон ‹ Билет; конец   -  person WarHog    schedule 17.10.2011


Ответы (5)


Классы не имеют имен в Ruby. Это просто объекты, присвоенные переменным, как и любой другой объект. Если вы хотите обратиться к классу через другую переменную, назначьте его другой переменной:

Foo = String
person Jörg W Mittag    schedule 17.10.2011
comment
Йорг, спасибо за эту жемчужину: это совершенно очевидно, но я никогда раньше об этом не задумывался! - person p4010; 17.10.2011
comment
Спасибо, Йорг. Вполне логичное, но неожиданное решение. :) - person AdamNYC; 18.10.2011
comment
Это не переменная. Это константа (все идентификаторы, начинающиеся с заглавной буквы, являются константами). - person Hauleth; 04.11.2013
comment
Это действительно не очень хороший вариант, потому что, если String изменится, Foo не будет... Foo не указывает на String, он клонирует его. - person boulder_ruby; 26.06.2014
comment
@boulder_ruby: о чем ты говоришь? Foo = []; Bar = Foo; Foo << 1; p Bar # [1] - person Jörg W Mittag; 26.06.2014
comment
Это может быть просто вещь рельсов или даже суеверие с моей стороны. Я только что провел этот тест и получил аналогичные результаты. class Demo; def hey; puts "text1"; end; end;; Test = Demo;; class Demo; def hey; puts "text 2"; end; end;;Demo.new.hey #=> "text 2" - person boulder_ruby; 26.06.2014
comment
Да здравствует Руби. - person Cyril Duchon-Doris; 12.01.2017
comment
Из rails console я попытался запустить Foo, что выдало ошибку NameError: uninitialized constant Foo. Если я запускаю String, а затем Foo, все работает. - person RAJ; 14.03.2019

в файле купон.rb:

class Coupon 
  #...
end

# add this line of code to make alias for class names
# option1. if you haven't defined a "Ticket" class: 
Ticket = Coupon   

# option2. if Ticket has been defined, you have to redefine it: 
Object.send :remove_const, "Ticket"
const_set "Ticket", Coupon

«Любая ссылка, начинающаяся с заглавной буквы, включая имена классов и модулей, является константой» -- ‹‹ метапрограммирование ruby>>, стр. 38, раздел констант

person Siwei    schedule 20.02.2012

Любой, кто приходит сюда, ищет, как создать псевдоним класса модели рельсов, чтобы иметь новое имя:

Я смог просто выполнить Foo = Bar, но мне пришлось поместить Foo в собственный файл модели, чтобы не получить ошибку неинициализированной константы. например

# models/foo.rb
Foo = Bar

Также вы можете столкнуться со странностями, пытаясь использовать псевдоним в ассоциациях, таких как has_many, has_one и т. д. Я обнаружил, что обычно вы можете обойти их, используя корневое пространство имен (или подходящее пространство имен, в зависимости от того, как структурированы ваши модели), чтобы убедиться, что Rails попытка автозагрузки правильной константы:

has_many :foo, class_name: '::Foo'
person Mark G.    schedule 16.03.2015

Вы должны быть осторожны с этим, потому что, если ваш класс претерпевает какое-либо изменение состояния (добавление функций, изменение констант, переменных класса и т. д.), состояние, в котором находился ваш класс, когда был создан экземпляр псевдонима, изменится. не отражают обновленные изменения в вашем классе.

Чтобы избежать запястного канала без ущерба для удобочитаемости, вы можете хранить лямбду в объекте псевдонима, а не в фактическом классе. Конечно, лямбда содержит класс, но это гарантирует, что ваш псевдоним будет вызывать последнюю версию вашего класса.

Я поместил это в свой инициализатор supermanpatches.rb rails (внутри config/initializers/)

LAP = lambda { LosAngelesParcel }

Теперь вы можете вызвать это, используя LAP[], и будет загружена только что созданная версия вашего класса. (Позволяя создавать экземпляры, например, по l = LAP[].new)

запускается один раз при загрузке rails, а затем распространяется через ваше приложение, вызываемое где угодно, как глобальная переменная, но, так сказать, "только для чтения".

person boulder_ruby    schedule 03.11.2013
comment
Это неправильный конец класса А; В= А; A.class_eval do def foo puts(test); конец конец; B.foo' Это напечатает тест, потому что и A, и B ссылаются на один и тот же объект в памяти. также B.object_id равен A.object_id Так что вам не нужно использовать лямбда - person Moustafa Samir; 05.03.2015
comment
Я уже обновил его, используя A.class_eval выше, есть ли другой способ обновить его? - person Moustafa Samir; 05.03.2015
comment
Если вы обновляете методы своих классов, которые вы делаете -- это не верно для старого доброго Ruby. Имеются в виду Rails и его способность перезагружать измененные классы во время разработки? - person Wayne Conrad; 01.07.2015

Я согласен с warhog, более или менее, но я бы подклассифицировал билет из вашего купонного класса — таким образом, если вам нужно выполнить какую-либо обработку данных, вы можете поместить код в свой класс билета.

person chrispanda    schedule 17.10.2011
comment
Подкласс означает отношения IS-A. Я чувствую, что если это не верно в проблемной области, мы не должны делать это в программном обеспечении. - person Wand Maker; 01.07.2013