2015-07-08 3 views
2

Я создаю файл с драгоценными камнями Ruby, который имеет различные исполняемые требования сторонних разработчиков (некоторые рубиновые инструменты, которые камень будет использовать через системные вызовы).Как читать спецификации gem-файла из extconf.rb?

Перечень требований задаются с помощью gemspec списка информативного requirements, и я была поставлена ​​задачей создания набора вверх, где этот список требования проверяются во время установки - по существу преобразования requirements списка от того, информативного, чтобы быть авторитетным.

Мой первоначальный подход заключается в использовании extensions, как в шаблоне extconf.rb, для запуска некоторого рубинового кода во время установки, который будет проверять список требований и не выполнить установку, если эти требования не выполняются.

Так что мой текущая реализация использует ext/Rakefile, который читает gemspec файл, используя жестко запрограммированный путь, разбирает список requirements, используя пользовательский (но прямо-вперед и простой) синтаксис и запустить несколько простых тестов на требуемых исполняемых файлов.

Я бы очень хотел отказать в зависимости от знания пути к файлу gemspec, поэтому я могу повторно использовать код модульным способом для других проектов.

Для завершения (и в надежде, что это будет полезно для кого-то), вот мой код, в котором используется режим «Rakefile» Gem::Ext::Builder, чтобы запустить какой-то произвольный код.

require 'rubygems' 
require 'mkmf' 

def verify_requirement(reqspec) 
    exe, version_spec, version_regex = reqspec.split(/\s*,\s*/,3) 

    exe = $1 if exe =~ /\[([^\]]+)\]/ # support human readable alias for executable name 

    abort "Missing required executable #{exe}!" unless find_executable(exe) 
    return unless version_speC# no version is specified, so executable existing is good enough 

    version = %x|#{exe} --version 2>&1|.chomp 
    version = %x|#{exe} -version 2>&1|.chomp unless $?.success? 
    abort "Error checking for version of #{exe}: (#{$?.exitstatus}) #{version}" unless $?.success? 

    if version_regex 
    abort "Version test '#{version_regex}' failed to match '#{version}'!" unless version =~ /#{version_regex}/m 
    abort "Version test '#{version_regex}' failed to generate a version number!" unless $1 
    version = $1 
    end 

    abort "Failed to locate a valid version number for #{exe}, found '#{version}'" unless version =~ /^[0-9\.]+/ 
    abort "Insufficient version '#{version}' for #{exe} - requires #{version_spec}" unless Gem::Dependency.new(exe, version_spec).match? exe, version 
end 

task :default do 
    gemspec = File.absolute_path('../my.gemspec') 
    Gem::Specification::load(gemspec).requirements.each do |req| 
    verify_requirement(req) 
    end 
end 

Этот код требует, чтобы requirements использует любой из этих синтаксисов:

  • exe-file[, <semantic-version-spec>[, <version-garabbing-regex>]]
  • alias '[' exe-file ']'[, <semantic-version-spec>[, <version-garabbing-regex>]]

Например:

spec.requirements << 'sox' 
spec.requirements << 'ffmpeg, >= 2.5, ffmpeg version ([\d\.]+)' 
spec.requirements << 'ImageMagick [convert], >= 6.7.5, ImageMagick ([\d\.]+)' 

ответ

0

Класс Gem::Specification может использоваться для загрузки и анализа gemspec. Я использую следующий код в ext/Rakefile для выполнения задач на основе файла gemspec:

task :default do 
    gemspec = File.absolute_path('../gemname.gemspec') 
    Gem::Specification::load(gemspec).requirements.each do |req| 
    verify_requirement(req) 
    end 
end