Подтвердить что ты не робот

Проверить наличие Ruby Gem

Есть ли способ проверить, установлен ли какой-либо камень в модуле Gem? Из кода ruby, а не путем выполнения 'gem list'...

Чтобы уточнить - я не хочу загружать библиотеку. Я просто хочу проверить, доступно ли это, поэтому все решения rescue LoadError не помогают мне. Также мне все равно, будет ли сам камень работать или нет, только если он установлен.

4b9b3361

Ответ 1

IMHO лучший способ - попытаться загрузить/потребовать GEM и спасти Exception, как уже показал Ray. Это безопасно, чтобы спасти исключение LoadError, потому что оно не было поднято самим GEM, но это стандартное поведение команды require.

Вместо этого вы можете использовать команду gem.

begin
  gem "somegem"
  # with requirements
  gem "somegem", ">=2.0"
rescue Gem::LoadError
  # not installed
end

Команда gem имеет такое же поведение команды require, что и некоторые незначительные отличия. AFAIK, он по-прежнему пытается автозагрузить основной файл GEM.

Копаем в файл rubygems.rb(строка 310) Я нашел следующее выполнение

matches = Gem.source_index.find_name(gem.name, gem.version_requirements)
report_activate_error(gem) if matches.empty?

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

Ответ 2

Там также:

Gem.available?('somegem')

Вы также можете использовать выражения регулярных выражений. Удобно, если я хочу разрешить варианты "rcov" и GitHub, такие как "релевантность-rcov":

Gem.available?(/-?rcov$/)

Ответ 3

Глядя на документацию API Gem, использование Gem:: Specification:: find_all_by_name для проверки доступности gem представляется разумным.

if Gem::Specification::find_all_by_name('gemname').any?
  do stuff
end

find_all_by_name всегда возвращает массив (объектов спецификации), в отличие от find_by_name, который вызывает исключение, если совпадение не найдено.

Ответ 4

Так как Gem.доступен? (argh!), вам нужно снова спасти (double aaargh). Да, find_by_name генерирует исключение, если камень не найден. Таким образом, чтобы быть обратно совместимым со старыми рубигемами, общее решение выглядит следующим образом:

def gem_available?(name)
   Gem::Specification.find_by_name(name)
rescue Gem::LoadError
   false
rescue
   Gem.available?(name)
end

Обратите внимание, что новый метод позволяет вам передать конкретную версию, чтобы увидеть, загружена ли она:

Gem::Specification.find_by_name('rails', '3.0.4')

Ответ 5

Вы можете:

begin
  require "somegem"
rescue LoadError
  # not installed
end

Это, однако, не сообщит вам, был ли модуль установлен через gem или какие-то другие средства.

Ответ 6

Я использую этот код, и он работает плавно.

def gem_available?(gem_name, version = nil)
  version.nil? gem(gem_name) : gem(gem_name, version)
rescue Gem::LoadError
  false
end

Примеры использования

Предположим, что у вас установлена ​​стойка 1.9.1.

puts gem_available?('rack') # => true
puts gem_available?('rack', '>=2') => # false

Ответ 7

Здесь такого не было, но вы также можете передавать нечеткие строки версий в find_by_name и find_all_by_name:

Gem::Specification.find_all_by_name('gemname', '>= 4.0').any?