Чи існує псевдонім_метод для методу класу?


10

Розглянемо наступний клас:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
end

Це не проблема, і ви можете телефонувати Foo.new.a_new_inst_methodбез жодної проблеми.

Мені б хотілося мати метод класу на кшталт Foo.add_widget(*items)і псевдонім його, щоб я міг зробити щось на кшталт:

Foo.add_widget 'item1'
Foo.add_widgets 'item2', 'item3'

Таким чином, він має "рубіновий стиль", 1.minuteі 2.minutesтому я хочу псевдоніми Foo.add_widgetтак називати Foo.add_widgetsдзвінки точно таким же методом. Я знаю, що міг би це обернути, але я відчуваю, що я маю змогу зробити це чистіше.

Розгляньте мою спробу спробувати щось подібне:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method
  alias_method :a_new_class_method, :a_class_method
end

Однак я отримую таку помилку:

NameError (undefined method `a_class_method' for class `Foo')

І тому схоже, що це не працює для методів класу. Як мені це робити?

Відповіді:


9

alias_methodпсевдонім інстанцій метод приймача. Методи класу - це фактичні методи екземплярів, визначені для однокласного класу класу.

class MyClass
  def self.a
    "Hello World!"
  end
end

method_1 = MyClass.method(:a).unbind
method_2 = MyClass.singleton_class.instance_method(:a)

method_1 == method_2
#=> true

Для отримання псевдоніму екземплярного методу, визначеного в класі Singleton, ви можете відкрити його за допомогою class << objectсинтаксису.

class << MyClass
  alias_method :b, :a
end

MyClass.b
#=> "Hello World!"

Або ви можете звернутися до нього безпосередньо, використовуючи singleton_classметод.

MyClass.singleton_class.alias_method :c, :a

MyClass.c
#=> "Hello World!"

Якщо ви все ще знаходитесь в контексті класу, selfбуде посилатися на клас. Отже, вище можна також записати як:

class MyClass
  class << self
    def a
      "Hello World!"
    end
    alias_method :b, :a
  end
end

Або

class MyClass
  def self.a
    "Hello World!"
  end
  singleton_class.alias_method :c, :a
end

Або поєднання двох.


5

Ви можете alias_methodперетворити методи класу та їх виклики в окремий модуль і включити цей модуль у свій клас за допомогою extend:

class Foo
  def an_inst_method
    'instance method'
  end
  alias_method :a_new_inst_method, :an_inst_method

  module ClassMethods
    def a_class_method
      'class method'
    end
    alias_method :a_new_class_method, :a_class_method
  end

  extend ClassMethods
end

Гей! Я забув про extend ClassMethodsрішення. +1
aarona

4

Важливо зрозуміти, що у Ruby не існує такого поняття, як метод класу .

Метод класу насправді є лише однотонним методом. У класових методах немає нічого особливого. У кожному об'єкті можуть бути одинакові методи. Ми просто називаємо їх "методами класу", коли об'єкт є тим, Classщо "однотонний метод екземпляра Class" занадто довгий і громіздкий.

Зачекайте! Я сказав "метод одиночки"?

Ще одна важлива річ, яку потрібно зрозуміти, це те, що в Рубі не існує такого поняття, як синглтон .

Метод синглтон - це просто звичайний нудний старий метод екземпляра класу синглтон. Немає нічого особливого в однотонних методах. Вони просто методи екземпляра, як і будь-який інший метод.

Насправді, у Рубі є лише методи екземпляра. Ні функцій, ні конструкторів, ні статичних методів, ні методів класів, ні функцій модулів, ні однотонних методів.

Питання не в тому, "це метод класу, це метод однотонний", а в тому, "в якому модулі визначений цей метод?"

"Методи Singleton" - це дійсні методи, визначені в класі Singleton. Синтаксис доступу до класу синглтон fooє

class << foo
end

Існує також метод, Object#singleton_classякий повертає однотонний клас об'єкта.

Чому я так агресивно замислююся про те, що кожен метод є методом екземпляра, а методи класу не існують? Тому що це означає, що об’єктна модель Рубі набагато простіша, ніж люди думають, що це! Зрештою, у вашому запитанні ви вже показуєте, що знаєте як псевдоніми примірників методів, але ви говорите, що не знаєте, як псевдоніми методів класу. Але це неправильно! Ви робите знаєте , як методи класу псевдонім, бо вони просто методи екземпляра . Якби ви цього навчали належним чином, вам ніколи не потрібно було б ставити це питання!

Як тільки ви зрозумієте, що кожен метод є методом екземпляра і що те, що ми називаємо "однотонними методами" - це лише методи екземпляра класу синглтон, рішення стає зрозумілим:

singleton_class.alias_method :a_new_class_method, :a_class_method

Зауважте: коли я писав вище, що "не існує такого поняття, як X", я мав на увазі, що " в рубінській мові немає такого поняття, як X ". Це не означає, що ці концепції не існують у спільноті Рубі .

Ми регулярно говоримо про "методи одиночного типу" та "методи класу", просто тому, що це простіше, ніж говорити про "методи екземпляра класу синглтон" або "методи екземпляра класу синглтон" об'єкта, який, як буває, є екземпляром Classкласу ". Є навіть такі методи , як Object#define_singleton_method, Object#singleton_method, Object#singleton_methods, Module#private_class_method, Module#public_class_method, і Module#module_functionв основний бібліотеці Ruby. Але завжди важливо пам’ятати, що це не мовні поняття. Це поняття спільноти, які існують лише в наших головах та в назвах деяких бібліотечних методів.


2

Добре, схоже, я можу зробити щось подібне, і це спрацює:

class Foo
  def an_inst_method
    'instance method'
  end

  def self.a_class_method
    'class method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    alias_method :a_new_class_method, :a_class_method
  end
end

Foo.a_class_method # => "class method" 
Foo.a_new_class_method # => "class method"

Якщо у когось є якась корисна інформація про мову Ruby і хотів би надати вичерпну відповідь, я дам вам +1.


1
Коли ви class << selfпотім alias_method :a_new_class_method, :a_class_methodви дійсно зателефонувати alias_methodпо одноплідних класу Foo. Ще один спосіб написання цього: singleton_class.alias_method :a_new_class_method, :a_class_methodв контексті класу.
3limin4t0r

Що ще ви хочете від відповіді? Я маю на увазі, це, мабуть, найчистіше рішення.
Дейв Ньютон

@ 3limin4t0r, якщо ти зробиш цю відповідь, я поставив це +1. Дякуємо за цю додаткову інформацію.
aarona

@DaveNewton ви маєте рацію, але тому що я також маю філософію, що якщо хтось може надати якусь більш змістовну інформацію про проблему, навіть якщо це побічно вирішує проблему, я думаю, що це також повинно бути винагородженим.
aarona

2

alias_methodпрацює над екземпляром, тому вам потрібно заглибитись на один рівень глибше і оперувати Classекземпляром або метакласом класу . У Рубі є дика об’єктна модель, яка може бути своєрідною руйнуванням мозку, але вона також дає тону сили:

class Foo
  def an_inst_method
    'instance method'
  end

  alias_method :a_new_inst_method, :an_inst_method

  class << self
    def a_class_method
      'class method'
    end

    alias_method :a_new_class_method, :a_class_method
  end
end

Я працював з рубіном в контексті рейок близько десяти років, але лише нещодавно почав глибоко занурюватися в об'єктну модель. Є так багато класних речей!
aarona
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.