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
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

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
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
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
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
ruby_command() click to toggle source

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
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
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
ruby_options_from_hash(hash, argv = []) click to toggle source
    # 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
ruby_options_to_argv(args, ruby_command = ruby_command()) click to toggle source
    # 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

executable_filename(dir, name) click to toggle source
    # 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
locate_ruby_tool_by_basename(name) click to toggle source
    # 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
shebang_command(filename) click to toggle source
    # 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