Poking around the Capistrano gem binary,
I've recently been trying to get an understanding of how Rubygems lets us 'require' external code libraries by looking at a typical gem binary, because wasn't too clear to me how everything worked under the hood, and when I've tried to modify existing gems, I've been left scratching my head, generally unable to progress beyond having nice ideas.
I've written commented the living daylights out the 'cap' command on my system, to help me understand how it works:
#!/Users/chrisadams/.rvm/rubies/ruby-1.8.7-p249/bin/ruby
#
# This file was generated by RubyGems.
#
# The application 'capistrano' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0"
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
version = $1
ARGV.shift
end
gem 'capistrano', version
load Gem.bin_path('capistrano', 'cap', version)
Lets look at the various parts in more detail, shall we?
require 'rubygems'
We use this to make previously downloaded gems accessible by name, instead of having to provide the full path to each ruby file.
version = ">= 0"
Here we're listing the minumum version needed for this the capistrano gem to work
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
version = $1
ARGV.shift
end
This checks the for any version numbers passed in, then removes it from the array that the 'cap' command would normally proces when working out what you want to do.
gem 'capistrano', version
The 'gem' method is like using a 'require statement for a rubygem', but lets us be version specific, in case changes to a codebase on a version bump break functionality. Capistrano's API has changed a few times, and great chunks of the DSL it uses have been deprecated, so this check is worthwhile:
load Gem.bin_path('capistrano', 'cap', version)
This is the path that really gets the ball rolling. The 'bin_path' method executes a binary in the gem named with the first parameter (in this case, capistrano). The second parameter lets us specify which binary should be used in the gem, in case the name of the binary, 'cap' isn't the same as the name of the code library , 'capistrano'. This lets us store multiple binaries on the rubygem without too much fear of clashes in the namespace.
This should have helped demystify each line in a common ruby based binary command - in the next post, I'll touch on how Capistrano can be called from the command line, or inside a script, by instantiating config objects that control how the program is run when you're not directly calling it from a terminal.