0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Bundler появился в Ruby значительно позже RubyGems. Из-за этого устройство библиотек (гемов) и проектов немного отличается. В этом уроке мы немного заглянем внутрь гемов, чтобы понять принципы их работы. Изучим команду bundle gem, которая создает структуру для нового гема и которая, с небольшими модификациями, подходит для своих проектов. Она в себя уже включает настроенный линтер, тесты и интеграцию с Github Actions.</p>
1
<p>Bundler появился в Ruby значительно позже RubyGems. Из-за этого устройство библиотек (гемов) и проектов немного отличается. В этом уроке мы немного заглянем внутрь гемов, чтобы понять принципы их работы. Изучим команду bundle gem, которая создает структуру для нового гема и которая, с небольшими модификациями, подходит для своих проектов. Она в себя уже включает настроенный линтер, тесты и интеграцию с Github Actions.</p>
2
<p>Для работы прикладных проектов в Ruby ничего кроме Bundler не нужно. Достаточно создать<em>Gemfile</em>, указать зависимости и подключить Bundler в своем коде. Дальше можно не отвлекаться и писать прикладной код.</p>
2
<p>Для работы прикладных проектов в Ruby ничего кроме Bundler не нужно. Достаточно создать<em>Gemfile</em>, указать зависимости и подключить Bundler в своем коде. Дальше можно не отвлекаться и писать прикладной код.</p>
3
<p>Для гемов все чуть сложнее. У гемов есть метаданные, например, версия, имя, описание и т.п. У гемов есть зависимости, которые должны учитываться RubyGems при установке. Для всего этого нужен специальный файл, называемый спецификацией гема. Кроме того, у гемов есть определенные соглашения по организации кода, которые важны для удобной работы c require.</p>
3
<p>Для гемов все чуть сложнее. У гемов есть метаданные, например, версия, имя, описание и т.п. У гемов есть зависимости, которые должны учитываться RubyGems при установке. Для всего этого нужен специальный файл, называемый спецификацией гема. Кроме того, у гемов есть определенные соглашения по организации кода, которые важны для удобной работы c require.</p>
4
<p>Гем можно создать полностью руками, но лучше воспользоваться готовой командой bundle gem, которая сделает все сама. Ниже мы пройдемся по всем этапам создания гема и изучим организацию кода внутри. Все это поможет понять работу Ruby и научит эффективно организовывать разработку как гемов, так и своих проектов.</p>
4
<p>Гем можно создать полностью руками, но лучше воспользоваться готовой командой bundle gem, которая сделает все сама. Ниже мы пройдемся по всем этапам создания гема и изучим организацию кода внутри. Все это поможет понять работу Ruby и научит эффективно организовывать разработку как гемов, так и своих проектов.</p>
5
<h2>bundle gem</h2>
5
<h2>bundle gem</h2>
6
<p>Начнем с генерации. Для этого запустим команду bundle gem, которая задаст несколько вопросов и затем создаст директорию с названием гема и нужными файлами внутри.</p>
6
<p>Начнем с генерации. Для этого запустим команду bundle gem, которая задаст несколько вопросов и затем создаст директорию с названием гема и нужными файлами внутри.</p>
7
<h2>Спецификация</h2>
7
<h2>Спецификация</h2>
8
<p>Спецификация гема описывается Ruby кодом. Внутри нее что-то уже заполнено автоматически, но есть места где стоит<em>TODO</em>. Их нужно заполнить, иначе с кодом не получится работать, он начнет просить заполнения.</p>
8
<p>Спецификация гема описывается Ruby кодом. Внутри нее что-то уже заполнено автоматически, но есть места где стоит<em>TODO</em>. Их нужно заполнить, иначе с кодом не получится работать, он начнет просить заполнения.</p>
9
<p>Для работы с гемом нужно сделать две вещи:</p>
9
<p>Для работы с гемом нужно сделать две вещи:</p>
10
<ol><li>Заполнить<em>summary</em>и<em>description</em>. Для простоты просто сотрите<em>TODO</em>.</li>
10
<ol><li>Заполнить<em>summary</em>и<em>description</em>. Для простоты просто сотрите<em>TODO</em>.</li>
11
<li>Все остальные<em>TODO</em>закомментировать включая<em>homepage_uri</em>, который ссылается на<em>homepage</em></li>
11
<li>Все остальные<em>TODO</em>закомментировать включая<em>homepage_uri</em>, который ссылается на<em>homepage</em></li>
12
</ol><h2>Зависимости</h2>
12
</ol><h2>Зависимости</h2>
13
<p>RubyGems в своей работе опирается только на спецификацию гема. Сюда входят и зависимости. То есть все что нужно для работы гема, должно быть указано в gemspec-файле:</p>
13
<p>RubyGems в своей работе опирается только на спецификацию гема. Сюда входят и зависимости. То есть все что нужно для работы гема, должно быть указано в gemspec-файле:</p>
14
<p>Здесь же указывались и зависимости для разработки, но с появлением Bundler это изменилось. Все зависимости, необходимые во время разработки и тестирования, переехали в Gemfile.</p>
14
<p>Здесь же указывались и зависимости для разработки, но с появлением Bundler это изменилось. Все зависимости, необходимые во время разработки и тестирования, переехали в Gemfile.</p>
15
<p>И чтобы не дублировать зависимости самого гема, в Bundler добавили функцию gemspec (в примере выше), которая подтягивает рантайм-зависимости из спецификации в Gemfile.</p>
15
<p>И чтобы не дублировать зависимости самого гема, в Bundler добавили функцию gemspec (в примере выше), которая подтягивает рантайм-зависимости из спецификации в Gemfile.</p>
16
<p>Следующий шаг в разработке гема - установка зависимостей. Для этого выполняется команда bin/setup:</p>
16
<p>Следующий шаг в разработке гема - установка зависимостей. Для этого выполняется команда bin/setup:</p>
17
<p>После установки зависимостей можно начинать разрабатывать, запускать линтер, тесты и другие команды. Начнем с линтера. У Rubocop есть свой исполняемый файл<em>rubocop</em>. Каким образом его запустить? Правильный способ через команду<em>bundle exec</em>. Эта команда запускает исполняемые файлы из зависимостей текущего проекта игнорируя глобально установленные программы.</p>
17
<p>После установки зависимостей можно начинать разрабатывать, запускать линтер, тесты и другие команды. Начнем с линтера. У Rubocop есть свой исполняемый файл<em>rubocop</em>. Каким образом его запустить? Правильный способ через команду<em>bundle exec</em>. Эта команда запускает исполняемые файлы из зависимостей текущего проекта игнорируя глобально установленные программы.</p>
18
<p>Точно так же запускаются любые другие утилиты, которые устанавливаются как зависимости в проект.</p>
18
<p>Точно так же запускаются любые другие утилиты, которые устанавливаются как зависимости в проект.</p>
19
<h2>Rake</h2>
19
<h2>Rake</h2>
20
<p>Еще один важный элемент экосистемы Ruby - Rake. Rake это Ruby + Make, фреймворк для описания и запуска разнообразных задач связанных с проектом. Список доступных задач можно посмотреть через утилиту rake:</p>
20
<p>Еще один важный элемент экосистемы Ruby - Rake. Rake это Ruby + Make, фреймворк для описания и запуска разнообразных задач связанных с проектом. Список доступных задач можно посмотреть через утилиту rake:</p>
21
<p>Эти задачи не встроены в rake, они добавлены, во время генерации гема, в файл<em>Rakefile</em>.</p>
21
<p>Эти задачи не встроены в rake, они добавлены, во время генерации гема, в файл<em>Rakefile</em>.</p>
22
<p>Часть задач подгружается из гемов, но некоторые описаны прямо здесь, например запуск тестов. Rubocop тоже присутствует здесь, то есть линтер можно запускать и так:</p>
22
<p>Часть задач подгружается из гемов, но некоторые описаны прямо здесь, например запуск тестов. Rubocop тоже присутствует здесь, то есть линтер можно запускать и так:</p>
23
<p>Rake важная часть экосистемы Ruby. Практически ни один проект не обходится без него. Например, в Rails из коробки идет несколько десятков таких команд. Плюс всегда можно написать свои.</p>
23
<p>Rake важная часть экосистемы Ruby. Практически ни один проект не обходится без него. Например, в Rails из коробки идет несколько десятков таких команд. Плюс всегда можно написать свои.</p>
24
<h2>Структура проекта</h2>
24
<h2>Структура проекта</h2>
25
<p>Код гема находится в директории<em>lib</em>и организован определенным образом:</p>
25
<p>Код гема находится в директории<em>lib</em>и организован определенным образом:</p>
26
<p>Внутри<em>lib</em>лежит Ruby-файл и директория по имени гема. Ruby-файл hexletgem.rb содержит входной модуль в гем, в нашем случае он называется Hexletgem:</p>
26
<p>Внутри<em>lib</em>лежит Ruby-файл и директория по имени гема. Ruby-файл hexletgem.rb содержит входной модуль в гем, в нашем случае он называется Hexletgem:</p>
27
<p>Именно через этот модуль пользователи гема будут получать доступ к его содержимому. Это важное соглашение, которое позволяет интуитивным образом понимать, как можно взаимодействовать с гемом после его включения в проект:</p>
27
<p>Именно через этот модуль пользователи гема будут получать доступ к его содержимому. Это важное соглашение, которое позволяет интуитивным образом понимать, как можно взаимодействовать с гемом после его включения в проект:</p>
28
<p>Директория<em>lib/hexletgem</em>содержит файл<em>version.rb</em>в котором указана версия гема:</p>
28
<p>Директория<em>lib/hexletgem</em>содержит файл<em>version.rb</em>в котором указана версия гема:</p>
29
<p>Все остальные файлы с кодом располагают рядом с этим файлом, внутри директории<em>hexletgem</em>и ее поддиректориях.</p>
29
<p>Все остальные файлы с кодом располагают рядом с этим файлом, внутри директории<em>hexletgem</em>и ее поддиректориях.</p>
30
<h2>Превращение гема в проект</h2>
30
<h2>Превращение гема в проект</h2>
31
<p>Генерация гема создает удобную структуру не только для разработки гемов, но и для прикладных проектов. Для готовности нужно сделать два шага:</p>
31
<p>Генерация гема создает удобную структуру не только для разработки гемов, но и для прикладных проектов. Для готовности нужно сделать два шага:</p>
32
<ol><li>Удалить файл с версией</li>
32
<ol><li>Удалить файл с версией</li>
33
<li>Удалить<em>gemspec</em>-файл</li>
33
<li>Удалить<em>gemspec</em>-файл</li>
34
</ol>
34
</ol>