class GemX::X

The eXecutable part of this gem

Public Class Methods

parse!(args) click to toggle source
# File lib/gemx.rb, line 74
def self.parse!(args)
  options = new
  options.requirements = Gem::Requirement.new
  opt_parse = OptionParser.new do |opts|
    opts.program_name = 'gemx'
    opts.version = VERSION
    opts.banner = 'Usage: gemx [options --] command'

    opts.on_tail('-v', '--[no-]verbose', 'Run verbosely') do |v|
      options.verbose = v
    end

    opts.on('-g', '--gem=GEM',
            'Run the executable from the given gem') do |g|
      options.gem_name = g
    end

    opts.on('-r', '--requirement REQ',
            'Run the gem with the given requirement') do |r|
      options.requirements.concat [r]
    end

    opts.on('--pre',
            'Allow resolving pre-release versions of the gem') do |_r|
      options.requirements.concat ['>= 0.a']
    end

    opts.on('-c', '--[no-]conservative',
            'Prefer the most recent installed version, ' \
            'rather than the latest version overall') do |c|
      options.conservative = c
    end
  end

  opt_parse.order!(args) do |v|
    # put the non-option back at the front of the list of arguments
    args.unshift(v)

    # stop parsing once we hit the first non-option,
    # so you can call `gemx rails --version` and it prints the rails
    # version rather than gemx's
    break
  end

  abort(opt_parse.help) if args.empty?

  options.executable = args.shift
  options.gem_name ||= options.executable
  options.arguments = args
  options.requirements.requirements.tap(&:uniq).delete(['>=', Gem::Version.new('0')])

  options
end
run!(argv) click to toggle source
# File lib/gemx.rb, line 128
def self.run!(argv)
  parse!(argv).run!
end

Public Instance Methods

activate!() click to toggle source
# File lib/gemx.rb, line 27
def activate!
  gem(gem_name, *requirements)
  Gem.finish_resolve
end
dependency_to_s() click to toggle source
# File lib/gemx.rb, line 32
def dependency_to_s
  if requirements.none?
    gem_name
  else
    "#{gem_name} (#{requirements})"
  end
end
install_if_needed() click to toggle source
# File lib/gemx.rb, line 19
def install_if_needed
  activate!
rescue Gem::MissingSpecError
  warn "#{dependency_to_s} not available locally" if verbose
  install
  activate!
end
load!() click to toggle source
# File lib/gemx.rb, line 40
def load!
  argv = ARGV.clone
  ARGV.replace arguments

  exe = executable

  contains_executable = Gem.loaded_specs.values.select do |spec|
    spec.executables.include?(executable)
  end

  if contains_executable.any? { |s| s.name == executable }
    contains_executable.select! { |s| s.name == executable }
  end

  if contains_executable.empty?
    if (spec = Gem.loaded_specs[executable]) && (exe = spec.executable)
      contains_executable << spec
    else
      abort "Failed to load executable #{executable}," \
            " are you sure the gem #{gem_name} contains it?"
    end
  end

  if contains_executable.size > 1
    abort "Ambiguous which gem `#{executable}` should come from: " \
          "the options are #{contains_executable.map(&:name)}, " \
          'specify one via `-g`'
  end

  load Gem.activate_bin_path(contains_executable.first.name, exe, '>= 0.a')
ensure
  ARGV.replace argv
end
run!() click to toggle source
# File lib/gemx.rb, line 132
def run!
  print_command if verbose
  if conservative
    install_if_needed
  else
    install
    activate!
  end

  load!
end

Private Instance Methods

install() click to toggle source
# File lib/gemx.rb, line 154
def install
  home = Gem.paths.home
  home = File.join(home, 'gemx')
  Gem.use_paths(home, Gem.path + [home])
  with_rubygems_config do
    suppress_always_install do
      Gem.install(gem_name, requirements)
    end
  end
rescue StandardError => e
  abort "Installing #{dependency_to_s} failed:\n#{e.to_s.gsub(/^/, "\t")}"
end
print_command() click to toggle source
suppress_always_install() { || ... } click to toggle source
# File lib/gemx.rb, line 178
def suppress_always_install
  name = :always_install
  cls = ::Gem::Resolver::InstallerSet
  method = cls.instance_method(name)
  cls.define_method(name) { [] }

  begin
    yield
  ensure
    cls.define_method(name, method)
  end
end
with_rubygems_config() { || ... } click to toggle source
# File lib/gemx.rb, line 146
def with_rubygems_config
  verbose_ = Gem.configuration.verbose
  Gem.configuration.verbose = verbose ? 1 : false
  yield
ensure
  Gem.configuration.verbose = verbose_
end