module Nuggets::RubyMixin
Originally based on Phusion Passenger's PlatformInfo module.
Constants
- CONFIG
- GEM_HOME
- OSX_RUBY_RE
- RUBY_ENGINE
- RUBY_PLATFORM
Attributes
Public Class Methods
# File lib/nuggets/ruby_mixin.rb 127 def self.define_ruby_tool(name) 128 class_eval <<-EOT, __FILE__, __LINE__ + 1 129 def #{name} 130 @#{name} ||= locate_ruby_tool('#{name}') 131 end 132 133 attr_writer :#{name} 134 135 def #{name}_command 136 @#{name}_command ||= command_for_ruby_tool('#{name}') 137 end 138 139 attr_writer :#{name}_command 140 EOT 141 end
Public Instance Methods
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 122 def command_for_ruby_tool(name) 123 filename = respond_to?(name) ? send(name) : locate_ruby_tool(name) 124 shebang_command(filename) =~ /ruby/ ? "#{ruby_command} #{filename}" : filename 125 end
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 100 def locate_ruby_tool(name, extensions = ['', CONFIG['EXEEXT']].compact.uniq) 101 # Deduce Ruby's --program-prefix and --program-suffix from its install name 102 # and transform the given input name accordingly. 103 # 104 # "rake" => "jrake", "rake1.8", etc. 105 [name, CONFIG['RUBY_INSTALL_NAME'].sub('ruby', name)].uniq.each { |basename| 106 extensions.each { |ext| 107 result = locate_ruby_tool_by_basename(basename + ext) and return result 108 } 109 } 110 111 nil 112 end
Returns correct command for invoking the current Ruby
interpreter.
# File lib/nuggets/ruby_mixin.rb 72 def ruby_command 73 defined?(@ruby_command) ? @ruby_command : @ruby_command = ruby_executable 74 end
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 81 def ruby_executable 82 @ruby_executable ||= begin 83 dir, name, ext = CONFIG.values_at(*%w[bindir RUBY_INSTALL_NAME EXEEXT]) 84 ::File.join(dir, name + ext).sub(/.*\s.*/m, '"\&"') 85 end 86 end
# File lib/nuggets/ruby_mixin.rb 153 def ruby_options_from_hash(hash, argv = []) 154 hash.each { |key, val| 155 opt = "-#{key.to_s[0, 1]}" 156 157 if val.is_a?(::Array) 158 val.each { |v| argv << opt << v.to_s } 159 elsif opt == '-e' 160 argv << opt << val.to_s 161 elsif val != false 162 argv << "#{opt}#{val unless val == true}" 163 end 164 } 165 166 argv 167 end
# File lib/nuggets/ruby_mixin.rb 145 def ruby_options_to_argv(args, ruby_command = ruby_command()) 146 argv = [ruby_command] 147 148 ruby_options_from_hash(args.pop, argv) if args.last.is_a?(::Hash) 149 150 argv.concat(args.map! { |arg| arg.to_s.strip }) 151 end
Private Instance Methods
# File lib/nuggets/ruby_mixin.rb 197 def executable_filename(dir, name) 198 filename = ::File.join(dir, name) 199 filename if ::File.file?(filename) && ::File.executable?(filename) 200 end
# File lib/nuggets/ruby_mixin.rb 171 def locate_ruby_tool_by_basename(name) 172 # On OS X we must look for Ruby binaries in /usr/bin. 173 # RubyGems puts executables (e.g. 'rake') in there, not in 174 # /System/Libraries/(...)/bin. 175 dir = ::RUBY_PLATFORM =~ /darwin/ && ruby_command =~ OSX_RUBY_RE ? 176 '/usr/bin' : ::File.dirname(ruby_command) 177 178 filename = executable_filename(dir, name) and return filename 179 180 # RubyGems might put binaries in a directory other 181 # than Ruby's bindir. Debian packaged RubyGems and 182 # DebGem packaged RubyGems are the prime examples. 183 filename = executable_filename(::Gem.bindir, name) and return filename 184 185 # Looks like it's not in the RubyGems bindir. Search in $PATH, but 186 # be very careful about this because whatever we find might belong 187 # to a different Ruby interpreter than the current one. 188 ::ENV['PATH'].split(::File::PATH_SEPARATOR).each { |path| 189 if filename = executable_filename(path, name) 190 return filename if shebang_command(filename) == ruby_command 191 end 192 } 193 194 nil 195 end
# File lib/nuggets/ruby_mixin.rb 202 def shebang_command(filename) 203 ::File.foreach(filename) { |line| 204 return $1 if line =~ /\A#!\s*(\S*)/ 205 206 # Allow one extra line for magic comment. 207 break if $. > 1 208 } 209 210 nil 211 end