Module: Nuggets::Ruby

Extended by:
Ruby
Included in:
Ruby
Defined in:
lib/nuggets/ruby.rb

Overview

Heavily based on Phusion Passenger’s PlatformInfo module; see their code.

– Phusion Passenger - www.modrails.com/ Copyright © 2010 Phusion

“Phusion Passenger” is a trademark of Hongli Lai & Ninh Bui.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. ++

Constant Summary collapse

CONFIG =
::RbConfig::CONFIG
GEM_HOME =
gem_home
RUBY_ENGINE =
defined?(::RUBY_ENGINE) ? ::RUBY_ENGINE : 'ruby'
OSX_RUBY_RE =
%r{\A/System/Library/Frameworks/Ruby.framework/Versions/.*?/usr/bin/ruby\Z}
UPDATE_RVM =

:nodoc:

%q{Please update RVM by running 'rvm update --head && rvm reload && rvm repair all'.}

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#ruby_commandObject

Returns correct command for invoking the current Ruby interpreter. In case of RVM this function will return the path to the RVM wrapper script that executes the current Ruby interpreter in the currently active gem set.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/nuggets/ruby.rb', line 76

def ruby_command
  return @ruby_command if defined?(@ruby_command)

  return @ruby_command = ruby_executable unless rvm?

  if name = rvm_ruby_string and dir = rvm_path
    if ::File.exist?(filename = ::File.join(dir, 'wrappers', name, 'ruby'))
      # Old wrapper scripts reference $HOME which causes
      # things to blow up when run by a different user.
      return @ruby_command = filename unless ::File.read(filename).include?('$HOME')
    end

    abort 'Your RVM wrapper scripts are too old. ' << UPDATE_RVM
  end

  # Something's wrong with the user's RVM installation.
  # Raise an error so that the user knows this instead of
  # having things fail randomly later on.
  # 'name' is guaranteed to be non-nil because rvm_ruby_string
  # already raises an exception on error.
  abort 'Your RVM installation appears to be broken: the RVM path cannot be found. ' <<
        'Please fix your RVM installation or contact the RVM developers for support.'
end

#ruby_executableObject

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.



105
106
107
108
109
110
# File 'lib/nuggets/ruby.rb', line 105

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

#rvm_pathObject

If the current Ruby interpreter is managed by RVM, returns the directory in which RVM places its working files. Otherwise returns nil.



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/nuggets/ruby.rb', line 132

def rvm_path
  return @rvm_path if defined?(@rvm_path)

  return @rvm_path = nil unless rvm?

  [::ENV['rvm_path'], '~/.rvm', '/usr/local/rvm'].compact.each { |path|
    path = ::File.expand_path(path)
    return @rvm_path = path if ::File.directory?(path)
  }

  # Failure to locate the RVM path is probably caused by the
  # user customizing $rvm_path. Older RVM versions don't
  # export $rvm_path, making us unable to detect its value.
  abort 'Unable to locate the RVM path. Your RVM ' <<
        'installation is probably too old. ' << UPDATE_RVM
end

#rvm_ruby_stringObject

If the current Ruby interpreter is managed by RVM, returns the RVM name which identifies the current Ruby interpreter plus the currently active gemset, e.g. something like this: “ruby-1.9.2-p0@mygemset”

Returns nil otherwise.



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/nuggets/ruby.rb', line 157

def rvm_ruby_string
  return @rvm_ruby_string if defined?(@rvm_ruby_string)

  return @rvm_ruby_string = nil unless rvm?

  # RVM used to export the necessary information through
  # environment variables, but doesn't always do that anymore
  # in the latest versions in order to fight env var pollution.
  # Scanning $LOAD_PATH seems to be the only way to obtain
  # the information.

  # Getting the RVM name of the Ruby interpreter ("ruby-1.9.2")
  # isn't so hard, we can extract it from the #ruby_executable
  # string. Getting the gemset name is a bit harder, so let's
  # try various strategies...

  # $GEM_HOME usually contains the gem set name.
  return @rvm_ruby_string = ::File.basename(GEM_HOME) if GEM_HOME && GEM_HOME.include?('rvm/gems/')

  # User somehow managed to nuke $GEM_HOME. Extract info from $LOAD_PATH.
  $LOAD_PATH.each { |path| return @rvm_ruby_string = $1 if path =~ %r{^.*rvm/gems/([^/]+)} }

  # On Ruby 1.9, $LOAD_PATH does not contain any gem paths until
  # at least one gem has been required so the above can fail.
  # We're out of options now, we can't detect the gem set.
  # Raise an exception so that the user knows what's going on
  # instead of having things fail in obscure ways later.
  abort 'Unable to autodetect the currently active RVM gem set ' <<
        "name. Please contact this program's author for support."
end

Instance Method Details

#command_for_ruby_tool(name) ⇒ Object

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.

If it’s not a Ruby program then it’s probably a wrapper script as is the case with e.g. RVM (~/.rvm/wrappers).



234
235
236
237
# File 'lib/nuggets/ruby.rb', line 234

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) ⇒ Object

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.



206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/nuggets/ruby.rb', line 206

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}")
      return result if result
    }
  }

  nil
end

#ruby_options_to_argv(args, ruby_command = ruby_command) ⇒ Object



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/nuggets/ruby.rb', line 255

def ruby_options_to_argv(args, ruby_command = ruby_command)
  argv = [ruby_command]

  args.pop.each { |key, val|
    opt = "-#{key.to_s[0, 1]}"

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

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

#ruby_sudo_commandObject

Returns either ‘sudo’ or ‘rvmsudo’ depending on whether the current Ruby interpreter is managed by RVM.



192
193
194
# File 'lib/nuggets/ruby.rb', line 192

def ruby_sudo_command
  "#{'rvm' if rvm?}sudo"
end

#ruby_supports_fork?Boolean

Returns whether the Ruby interpreter supports process forking.



115
116
117
118
119
120
121
122
# File 'lib/nuggets/ruby.rb', line 115

def ruby_supports_fork?
  # MRI >= 1.9.2's respond_to? returns false
  # for methods that are not implemented.
  ::Process.respond_to?(:fork) &&
  RUBY_ENGINE != 'jruby'     &&
  RUBY_ENGINE != 'macruby'   &&
  CONFIG['target_os'] !~ /mswin|windows|mingw/
end

#rvm?Boolean

Returns whether the current Ruby interpreter is managed by RVM.



125
126
127
# File 'lib/nuggets/ruby.rb', line 125

def rvm?
  CONFIG['bindir'] =~ %r{/\.?rvm/}
end