module Nuggets::RubyMixin

Originally based on Phusion Passenger's PlatformInfo module.

Constants

CONFIG
GEM_HOME
OSX_RUBY_RE
RUBY_ENGINE
RUBY_PLATFORM

Attributes

ruby_command[W]
ruby_executable[W]

Public Class Methods

define_ruby_tool(name) click to toggle source
# File lib/nuggets/ruby_mixin.rb, line 127
    def self.define_ruby_tool(name)
      class_eval "        def #{name}
          @#{name} ||= locate_ruby_tool('#{name}')
        end

        attr_writer :#{name}

        def #{name}_command
          @#{name}_command ||= command_for_ruby_tool('#{name}')
        end

        attr_writer :#{name}_command
", __FILE__, __LINE__ + 1
    end

Public Instance Methods

command_for_ruby_tool(name) click to toggle source

Returns the correct command string for invoking the name executable that belongs to the current Ruby interpreter. Returns nil if the command is not found.

If the command executable is a Ruby program, then we need to run it in the correct Ruby interpreter just in case the command doesn't have the correct shebang line; we don't want a totally different Ruby than the current one to be invoked.

# File lib/nuggets/ruby_mixin.rb, line 122
def command_for_ruby_tool(name)
  filename = respond_to?(name) ? send(name) : locate_ruby_tool(name)
  shebang_command(filename) =~ /ruby/ ? "#{ruby_command} #{filename}" : filename
end
locate_ruby_tool(name, extensions = ['', CONFIG['EXEEXT']].compact.uniq) click to toggle source

Locates a Ruby tool command name, e.g. 'gem', 'rake', 'bundle', etc. Instead of naively looking in $PATH, this function uses a variety of search heuristics to find the command that's really associated with the current Ruby interpreter. It should never locate a command that's actually associated with a different Ruby interpreter.

NOTE: The return value may not be the actual correct invocation for the tool. Use #command_for_ruby_tool for that.

Returns nil when nothing's found.

# File lib/nuggets/ruby_mixin.rb, line 100
def locate_ruby_tool(name, extensions = ['', CONFIG['EXEEXT']].compact.uniq)
  # Deduce Ruby's --program-prefix and --program-suffix from its install name
  # and transform the given input name accordingly.
  #
  #   "rake" => "jrake", "rake1.8", etc.
  [name, CONFIG['RUBY_INSTALL_NAME'].sub('ruby', name)].uniq.each { |basename|
    extensions.each { |ext|
      result = locate_ruby_tool_by_basename(basename + ext) and return result
    }
  }

  nil
end
ruby_command() click to toggle source

Returns correct command for invoking the current Ruby interpreter.

# File lib/nuggets/ruby_mixin.rb, line 72
def ruby_command
  defined?(@ruby_command) ? @ruby_command : @ruby_command = ruby_executable
end
ruby_executable() click to toggle source

Returns the full path to the current Ruby interpreter's executable file. This might not be the actual correct command to use for invoking the Ruby interpreter; use #ruby_command instead.

# File lib/nuggets/ruby_mixin.rb, line 81
def ruby_executable
  @ruby_executable ||= begin
    dir, name, ext = CONFIG.values_at(*%w[bindir RUBY_INSTALL_NAME EXEEXT])
    ::File.join(dir, name + ext).sub(/.*\s.*/m, '"\&"')
  end
end
ruby_options_from_hash(hash, argv = []) click to toggle source
# File lib/nuggets/ruby_mixin.rb, line 153
def ruby_options_from_hash(hash, argv = [])
  hash.each { |key, val|
    opt = "-#{key.to_s[0, 1]}"

    if val.is_a?(::Array)
      val.each { |v| argv << opt << v.to_s }
    elsif opt == '-e'
      argv << opt << val.to_s
    elsif val != false
      argv << "#{opt}#{val unless val == true}"
    end
  }

  argv
end
ruby_options_to_argv(args, ruby_command = ruby_command()) click to toggle source
# File lib/nuggets/ruby_mixin.rb, line 145
def ruby_options_to_argv(args, ruby_command = ruby_command())
  argv = [ruby_command]

  ruby_options_from_hash(args.pop, argv) if args.last.is_a?(::Hash)

  argv.concat(args.map! { |arg| arg.to_s.strip })
end

Private Instance Methods

executable_filename(dir, name) click to toggle source
# File lib/nuggets/ruby_mixin.rb, line 197
def executable_filename(dir, name)
  filename = ::File.join(dir, name)
  filename if ::File.file?(filename) && ::File.executable?(filename)
end
locate_ruby_tool_by_basename(name) click to toggle source
# File lib/nuggets/ruby_mixin.rb, line 171
def locate_ruby_tool_by_basename(name)
  # On OS X we must look for Ruby binaries in /usr/bin.
  # RubyGems puts executables (e.g. 'rake') in there, not in
  # /System/Libraries/(...)/bin.
  dir = ::RUBY_PLATFORM =~ /darwin/ && ruby_command =~ OSX_RUBY_RE ?
    '/usr/bin' : ::File.dirname(ruby_command)

  filename = executable_filename(dir, name) and return filename

  # RubyGems might put binaries in a directory other
  # than Ruby's bindir. Debian packaged RubyGems and
  # DebGem packaged RubyGems are the prime examples.
  filename = executable_filename(::Gem.bindir, name) and return filename

  # Looks like it's not in the RubyGems bindir. Search in $PATH, but
  # be very careful about this because whatever we find might belong
  # to a different Ruby interpreter than the current one.
  ::ENV['PATH'].split(::File::PATH_SEPARATOR).each { |path|
    if filename = executable_filename(path, name)
      return filename if shebang_command(filename) == ruby_command
    end
  }

  nil
end
shebang_command(filename) click to toggle source
# File lib/nuggets/ruby_mixin.rb, line 202
def shebang_command(filename)
  ::File.foreach(filename) { |line|
    return $1 if line =~ /\A#!\s*(\S*)/

    # Allow one extra line for magic comment.
    break if $. > 1
  }

  nil
end