Stripe API открывает метакласс? Или просто определяет метод класса?

#ruby

#ruby

Вопрос:

Я читаю Stripe API и вижу это:

 module Stripe

  ...

  class << self
    attr_accessor :stripe_account, :api_key, :api_base, :verify_ssl_certs, :api_version, :connect_base, :uploads_base,
                  :open_timeout, :read_timeout

    attr_reader :max_network_retry_delay, :initial_network_retry_delay
  end
  

Что там происходит? Я пытался прочитать блог Иегуды Каца об этом, но некоторые его части неясны, например:

Что происходит в двух примерах, которые он предоставляет?

Оказывается, что все эти странные правила сводятся к одной концепции: контроль над self в данной части кода. Давайте вернемся назад и взглянем на некоторые фрагменты, которые мы рассмотрели ранее:

 class Person     
   def name
      "Matz" 
   end

  self.name #=> "Person" 
end   
  

Здесь мы добавляем метод name
в класс Person . Как только мы скажем class Person , self до конца
блока — это сам Person класс.

 Person.class_eval do     
   def name
       "Matz"
   end

   self.name #=> "Person"
end 
  

Здесь мы делаем то же
самое: добавляем метод name к экземплярам Person класса. В
этом случае class_eval устанавливается значение self для Person до конца
блока. Все это совершенно прямолинейно при работе с
классами, но не менее прямолинейно и при работе с
метаклассами:

Почему Иегуда продолжает писать:

self.name #=> "Person"

Ответ №1:

В Ruby нет такого понятия, как «метод класса». Все методы являются методами экземпляра. Дело в том, что экземпляры разные.

Stripe является экземпляром class Module и Person является экземпляром class Class .

Итак, в вашем первом примере ( Stripe ) есть определение attr_accessor s, доступное для object Stripe .

Таким образом, вы сможете читать и записывать Stripe атрибуты s:

 Stripe.api_key = :some_key
Stripe.api_key
#=> :some_key
  

В то время как следующий определяет метод, доступный экземплярам класса Person

 Person.class_eval do
  def name
    "Matz"
  end
end
  

Вы могли бы определить метод экземпляра, доступный для Person класса с помощью using instance_eval , который оценивал код в контексте получателя:

 Person.instance_eval do
  def name
    "Matz"
  end
end
Person.name # this is what they sometimes called  "a class method", which I don't like personally
#=> 'Matz'
  

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

Комментарии:

1. @Jwan622 потому что это контекст Person . Как я уже сказал, это всегда вопрос self . Внутри тела класса вы находитесь в контексте этого класса, что означает, что self указывает на сам класс. Это то же самое, как если бы вы писали Person.name вне определения класса

2. name похоже, это встроенная функция.

3. @Jwan622 вот документы для name метода