Vendor Everything — err.the_blog (original) (raw)

Adding Depended Sees

Alright, alright, let’s see how we’d vendor the test-spec gem. First, the vendor directory:
$ ls -1 vendor/
bin
data
gems
plugins
rails
We obviously added a few directories, namely gems, data, and bin. The rails and plugins directories should be familiar, one hopes.
Let’s focus on the the vendor/gems directory:
$ ls -1 vendor/gems/
RedCloth-3.0.4
RubyInline-3.6.2
crypt-1.1.4
image_science-1.1.1
memcache-client-1.3.0
session-2.4.0
sphinx-0.9.7-rc2
We’ll cd in there and then use the handy gem unpack command to, erm, unpack the contents of our test-spec gem:
$ gem unpack test-spec
Unpacked gem: 'test-spec-0.3.0'
Cool. Now we need to dive into our config/environment.rb file to ensure Rails knows to look in vendor/gems/test-spec-0.3.0/lib when we try to require ‘test/spec’. It’s easier than you think.
Add this to your Rails::Initializer.run block:
config.load_paths += Dir["#{RAILS_ROOT}/vendor/gems/**"].map do |dir|
File.directory?(lib = "#{dir}/lib") ? lib : dir
end
Now all the libraries in vendor/gems will automatically be included in your load path, complete with a lib check for libraries like RubyInline and crypt (which don’t come with lib directories).
Want to only include some libraries in a specific environment? Maybe you don’t want RubyInline or image_science in development mode. Put this under the above snippet o’ code:
if %w(development test).include? RAILS_ENV
config.load_paths.delete_if { |f| f =~ /RubyInline|image_science/ }
end
Good to go.
It should be noted that this trick will not auto-require the gems for you. You still need to do that in your config file, or in your gems, or wherever. Maybe with a line like %w(crypt/blowfish redcloth).each { |f| require f } in your config/environment.rb if it pleases you.

Other Approaches

For one, Dr Nic has something cool: this patch. It lets you run tasks from within vendor/gems right from your RAILS_ROOT. Nifty. He’s also got his gemsonrails plugin which is a similar (but different) approach than we illustrate here.
Jay Fields has his own method for autoloading gems in vendor. Worth a look, and a listen.
Classic Railer topfunky, back in the day, rolled a rake task to scratch the same itch.
Then there’s this thread on Rails-Core about adding some kinda gemy-ness to Core which, unfortunately, hasn’t yet transpired. The gem in question, the one to metaly manage other gems, lives in technoweenie’s repository.
I even do this (for better or worse) with cache_fu, btw. I am starting to really like not being dependent on the environment.

All Set!

The goal here is simple: always get everyone, especially your production environment, on the same page. You don’t want to guess at which gems everyone does and does not have. Right.
There’s another point lurking subtlety in the background: once all your gems are under version control, you can (probably) get your app up and running at any point of its existence without fuss. You can also see, quite easily, which versions of what gems you were using when. A real history.