Я знаю, что есть команда для добавления драгоценного камня в Gemfile: bundle add GEMNAME
, но есть ли аналогичная команда для добавления зависимости в gemspec?
Есть что-то вроде bundle add rails --gemspec
?
Есть ли команда, которая добавляет эту строку в gemspec?:
spec.add_dependency 'GEMNAME', 'GEMVERSION'
🤔 А знаете ли вы, что...
Ruby поддерживает различные парадигмы программирования, включая функциональное программирование.
Я думаю, что ответ «нет». По крайней мере, не с помощью «стандартных» инструментов Ruby; Возможно, кто-то создал для него CLI, но я не могу его найти.
Я почти никогда не использовал команду bundle add
. Я ожидаю, что в большинстве случаев использования это лишь немного быстрее, чем редактирование Gemfile
и запуск bundle
, с дополнительным недостатком, заключающимся в том, что вам нужно запомнить эту специальную команду (и, вероятно, еще проверить, что она внесла правильные изменения в Gemfile
!).
Возможно, было бы полезно, если бы я добавлял одну и ту же зависимость к дюжине проектов или чему-то еще, но для меня это не «обычная» задача.
Точно так же я не могу себе представить сценарий, в котором использование CLI для обновления gemspec
будет действительно полезным. Неужели так же быстро, если не быстрее, просто открыть gemspec
и отредактировать его напрямую?
Вот почему (насколько я могу найти?) не существует популярного инструмента для автоматизации этого процесса.
Кстати, команда bundle gem <gemname>
очень полезна при создании нового драгоценного камня, поскольку она автоматизирует большое количество шаблонного кода для запуска новой библиотеки, аналогично запуску rails new <app-name>
.
Ваш вопрос предполагает, что Gem::Specification, хранящийся в файле .gemspec, должен содержать тот же уровень информации о зависимостях, что и Gemfile, анализируемый Bundler. Обычно это не так, и, вероятно, именно поэтому отсутствует поддержка, которую вы хотите.
Вы правы, в настоящее время такой поддержки нет. Тем не менее, я привожу примеры переноса минимального набора зависимостей из Gemfile в вашу Gem::Specification, а также некоторую пищу для размышлений о том, как и зачем сохранять в Gemfile столько управления зависимостями, сколько это разумно для вашего конкретного пакета или библиотеки.
Я не видел опции CLI, похожей на Bundle-add на сайте RubyGems Command Reference для добавления строк непосредственно в файл .gemspec из командной строки, но синтаксис драгоценных камней в gemspec очень похож если только вы не используете более продвинутый синтаксис от Bundler.
Однако различия для простейших случаев тривиальны, и, вероятно, поэтому они не поддерживаются. Ниже я привожу несколько примеров того, как их конвертировать с помощью sed или текстового редактора.
Кроме того, любой драгоценный камень, который, скорее всего, будет включен в виде библиотеки, а не исполняемого файла, технически может не нуждаться в определенных зависимостях времени выполнения. Возможно, будет достаточно (хотя это не обязательно лучшая практика) включить в ваш .gemspec только зависимости разработки, а остальное оставить Bundler и Gemfile.
.gemspec на самом деле предназначен для информационного характера, но его можно использовать для создания драгоценных камней без Bundler, если вам не нужны расширенные функции Bundler. Bundler также может включить .gemspec в свой Gemfile для использования во время разрешения зависимостей, но обратное неверно.
Основное различие в спецификациях заключается в том, что Bundler Gemfile поддерживает гораздо больше функций (например, группировку) и может использовать более продвинутые спецификации, чем файл .gemspec. Некоторыми примерами этого являются определение нестандартных операторов require в Gemfile или использование Install_if
; это то, с чем Bundler может справиться, а стандартный .gemspec - нет.
Однако в более простых случаях использования синтаксис спецификации двух форматов файлов достаточно эквивалентен, и вы можете использовать sed или текстовый редактор, чтобы внести незначительные изменения, необходимые для переноса файлов из вашего Gemfile в ваш Gem::Specification.
В несложных случаях можно сделать что-то вроде этого:
Gemfile
в .gemspec
.gem
, чтобы она соответствовала синтаксису Gem::Specification.
В vim: :%s/^gem/spec.add_dependency/
для общих зависимостей.
Вы можете сделать то же самое из командной строки с помощью GNU sed:
# for items in your global group
sed -ri "s/^gem/spec.add_dependency/" .gemspec
# for items your Gemfile's development group
sed -ri "s/^gem/spec.add_development_dependency/" .gemspec
# for items in your various runtime groups
sed -ri "s/^gem/spec.add_runtime_dependency/" .gemspec
Примечание. #add_dependentness прагматично является синонимом #add_runtime_dependentency, но в большей степени раскрывает намерения. Вы можете использовать любой из них, в зависимости от ваших семантических намерений, но он ничем не отличается от Бандлера.
Поскольку драгоценный камень обычно определяет свои собственные операторы require в файле gem_name/lib/gem_name.rb, отсутствие сложности в файле .gemspec редко является реальной проблемой. В таких случаях, перечислив зависимости разработки в Gem::Specification, а затем полагаясь на свой Gemfile или Gemfile.lock (были споры о включении или исключении Gemfile.lock из библиотек, но большинство людей в настоящее время, похоже, включают его), тогда вы может рассматривать .gemspec как информационный и позволить Bundler управлять реальными зависимостями, группами, условиями и другими причудливыми вещами перед сборкой и отправкой драгоценного камня.
По моему личному опыту, обычно лучше всего сохранять спецификации .gemspec как можно более простыми, поскольку Bundler является распространенной частью экосистемы и гораздо более мощным. Лучшая практика или нет, но я часто создаю библиотеки, в которых мои минимальные ожидания определены в:
# foo.gemspec
spec.add_dependency "bundler"
spec.add_development_dependency "standardrb"
# Gemfile
gemspec
group :development, :test do
gem "standard", "~> 1.36"
end
В этом примере я сообщаю RubyGems, что некоторая версия Bundler является основной зависимостью и что для разработки потребуется Standardrb (мета-гем для стандартного гема). Я мог бы указать ограничение для Bundler, если мне нужно, но обычно я этого не делаю, особенно в библиотеках, а стандартному Rb оно на самом деле не нужно, потому что вместо этого я добавлю все необходимые ограничения для стандартного драгоценного камня или других конкретных зависимостей в Gemfile. .
Между тем, в Gemfile метод gemspec
извлекает Standardrb и его зависимости, а группы :development и :test включают как сам стандартный драгоценный камень, так и его зависимости. Я делаю это, потому что Gem::Specification#add_development_dependentity назначается только одной группе (обычно :development, но настраивается в Bundler), тогда как сам Bundler может добавлять элементы в несколько групп или список групп.
Спецификация Standard внутри группы ограничивает Standard до второстепенной семантической версии, которую я определил (например, 1.36
). Затем распознаватель Bundler обрабатывает зависимости и для этой конкретной версии Standard!
Обычно гораздо удобнее делать подобные вещи в Bundler, чем в Gem::Specification, но ваш опыт и вариант использования могут отличаться. Тем не менее, это разумный шаблон, который не только решает вашу проблему, убирая лишний вес в вашем файле .gemspec и упрощая определение минимально необходимых метаданных о зависимостях вашего драгоценного камня, но также предоставляет в ваше распоряжение всю мощь Bundler при необходимости. стоимость наличия Gem::Specification, которая не точна.
Чтобы разобраться во всем этом, обратите внимание, что в основном репозитории RubyGems вы найдете множество драгоценных камней, версии которых Gem::Specification указаны как >=0
или которые просто перечисляют их зависимости во время выполнения или разработки. Например, в RSpec 3.13.0 перечислены только три зависимости времени выполнения:
rspec-core ~> 3.13.0
rspec-expectations ~> 3.13.0
rspec-mocks ~> 3.13.0
и необходимая версия Ruby >= 0
. Это может быть или не быть идеальным, но перечисление в Gem::Specification только зависимостей времени выполнения или разработки является на удивление распространенным явлением. Помимо метаданных о самом драгоценном камне, Bundler предлагает больше опций конфигурации и, возможно, более мощные возможности разрешения зависимостей, поэтому часто выгодно указывать в Gem::Specification как можно меньше о зависимостях драгоценного камня, а все остальное оставить Gemfile Bundler.