Все говорят о Rails одно и то же: «Это волшебство».

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

Со временем я понял, что большая часть того, что я считаю магией в Rails, - это всего лишь несколько умных людей, которые вносят несколько аккуратных, умных и аккуратных хаков в репозиторий Rails. Шутки в сторону! Это все код. Вот и все.

Здесь я пытаюсь раскрыть магию в Rails и посмотреть, как часто используемые функции Rails работают под капотом.

Давайте начнем.

Если вы работали над Rails, я уверен, что вы встречали такие фрагменты кода, как Rails.env.development? или Rails.env.production?.

[1] pry(main)> Rails.env
=> "development"
[2] pry(main)> Rails.env.development?
=> true

Все хорошо. Но здесь происходит что-то странное.

Rails.env возвращает development (строку), но если вы попытаетесь выполнить ‘development’.development? на консоли rails, на самом деле вы получите NoMethodError.

[1] pry(main)> "development".development?
NoMethodError: undefined method `development?' for "development":String

Итак, как все это работает?

Как и большинство функций Rails, это тоже волшебство. Но давайте попробуем понять, как работает эта магия, покопавшись в коде Rails, не так ли?

Нашей первой точкой проверки, очевидно, будет метод env, определенный в модуле Rails. Если вы посмотрите Код Rails, вы увидите определение метода, подобное этому.

Эта функция возвращает значение переменных среды ENV[“RAILS_ENV”] или ENV[“RACK_ENV”] или “development”

Но вот что интересно: эта функция возвращает не объект String, а объект ActiveSupport::StringInquirer.

Итак, давайте погрузимся в класс StringInquirer и посмотрим, что здесь происходит.

Ага! Как и ожидалось, здесь происходит волшебство. Точнее, внутри функции method_missing.

Давайте сделаем шаг назад и проанализируем цепочку событий, которые происходят, когда мы выполняем Rails.env.development

  1. Rails.env возвращает “development”, но это не строковый объект, а объект ActiveSupport::StringInquirer.
  2. Класс ActiveSupport::StringInquirer наследует класс String, поэтому все функции, определенные в String, также будут работать с этим объектом.
  3. Поскольку для класса ActiveSupport::StringInquirer не определен метод development? (или для класса String), он попадает в method_missing.
  4. Здесь происходит волшебство. Здесь он проверяет, заканчивается ли вызываемая функция (в нашем случае development?) на ?. (Строка 9)
  5. Если это так, он проверяет, равна ли строка (в нашем случае development) методу, вызванному для этого объекта, без ? в конце. (Строка 10)

И вуаля! Внезапно все сводится к простому сравнению строк.

Если строки совпадают, возвращается истина.

А волшебство вот в чем:

На самом деле это не String, это объект ActiveSupport::StringInquirer

Практические примеры использования ActiveSupport::StringInquirer

Если ваша строка является объектом этого класса, проверка равенства будет намного проще и чище. Фактически, вы вызываете метод inquiry для любой строки в Rails, и он возвращает объект этого класса.

[9] pry(main)> word = "America".inquiry
=> "America"
[10] pry(main)> word.America?
=> true
[11] pry(main)> word.Russia?
=> false

Теперь вы можете попрощаться с уродливыми сравнениями строк в вашем проекте :)