Добро пожаловать в Code Safari.
Capybara предоставляет Ruby DSL для взаимодействия с веб-страницами. Обычно он используется для тестирования приложений на основе Rack (таких как Ruby on Rails или Sinatra), но может использоваться автономно для управления любым веб-сайтом.
Я заметил синтаксис конфигурации Capybara — довольно распространенную идиому в мире библиотек ruby - и был заинтригован тем, как это работает.
Capybara.configure do |config| config.default_wait_time = 2 end
Давай выясним! Возьмите исходный код Capybara, чтобы мы могли начать писать.
git clone https://github.com/jnicklas/capybara.git
Прежде всего, давайте попробуем найти интересующий нас код конфигурации. Поиск имени метода обычно является хорошим началом.
$ ack configure lib lib/capybara.rb 25: # Capybara.configure do |config| 46: def configure 166:Capybara.configure do |config|
(ack — более хороший grep — см. документацию для получения дополнительной информации)
Джек-пот! Мы нашли метод, который мы использовали после первого захода. Откройте этот файл, чтобы найти определение метода.
# lib/capybara:46 def configure yield self end
Любопытно: yield
устанавливает для себя configure
блока configure
в self
, но что такое self
в этом контексте? Возможно, вам удастся выяснить это после сканирования остальной части файла, но мы также можем начать использовать гибкость ruby, просто перейдя и выполнив код с помощью irb
. Вы можете использовать флаг -I
чтобы добавить каталог к пути загрузки, гарантируя, что мы сможем запросить файл, который мы просматриваем, а не другую версию, которая может существовать где-то еще в нашей системе.
# In cloned capybara directory $ irb -Ilib irb> require 'capybara' => true irb> Capybara.configure {|config| puts config.inspect } Capybara => nil irb> Capybara.configure {|config| puts config.class.inspect } Module => nil
Здесь мы видим, что self
на самом деле является модулем Capybara
. Это интересно: обычно мы думаем о self
как о ссылке на экземпляр класса, но в этом случае это фактический объект класса . Это означает, что следующие две строки эквивалентны:
Capybara.default_wait_time = 2 Capybara.configure {|config| config.default_wait_time = 2 }
configure
обеспечивает некоторый уровень абстракции, не позволяя напрямую устанавливать средства доступа к модулю, что позволяет Capybara потенциально реорганизовать способ сохранения предпочтений в будущем.
Как этот механизм работает, становится все яснее, но все еще остаются некоторые вопросы без ответа. Как configure
была определена для модуля, и как были определены атрибуты модуля? Ответ лежит немного дальше по файлу, где мы видим следующую схему:
# lib/capybara.rb, trimmed to size module Capybara class << self attr_accessor :default_wait_time def configure self end end end
Волшебство здесь — это class << self
, который фактически говорит: «все, что находится внутри, принадлежит классу, а не экземплярам класса». (Это на самом деле немного более тонко, чем это, но это определение на данный момент достаточно хорошо). Традиционно attr_accessor
это используется для определения атрибутов экземпляра, таких как:
class Person attr_accessor :name end p = Person.new p.name = 'Don' p.name # => 'Don'
Из кода Capybara мы можем видеть, что на самом деле мы можем использовать его для определения атрибутов в любом экземпляре, даже в таких странных, как Module
.
Рассмотрение
Читая исходный код Capybara, чтобы узнать, как реализован блок конфигурации, мы изучили два метода:
- Сдача объекта застройщика
- Определение методов доступа в
Module
Мы можем использовать эти знания для создания нашей аналогичной системы конфигурации.
module MyApp class << self attr_accessor :special_number def configure yield self end end end MyApp.configure do |config| config.special_number = 42 end puts "The special number is #{MyApp.special_number}."
Чтобы попрактиковаться в чтении кода, вот несколько других исследовательских задач, которые вы можете попробовать:
- RSpec использует похожий DSL для конфигурации, он работает так же?
- Машинист использует совершенно другую технику, чтобы разрешить конфигурацию с блоком без выдачи параметра. Выясните, как это работает.
Дайте нам знать, как вы идете в комментариях. Настройтесь на следующую неделю для более захватывающих приключений в джунглях кода.