Статьи

Code Safari: настройка капибары

Добро пожаловать в 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 для конфигурации, он работает так же?
  • Машинист использует совершенно другую технику, чтобы разрешить конфигурацию с блоком без выдачи параметра. Выясните, как это работает.

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