I’ve been running local special need gem servers as well as a gem server for beta versions of Ruport and support code (namely plugins). I got tired of manually wget’ing the gems I needed and their dependencies, so with a little help from mechanize and archive_tar_external, my friend Dinko and I came up with this quick (pretty messy) hack.

require 'rubygems'
require 'archive/tar_external'
require 'mechanize'
require 'fileutils'
include FileUtils
include Archive

module RFDownloader

  def populate(archive)
    mkdir ".rf_downloader"
    cd ".rf_downloader"

    yield

    Tar::External.new( "../#{archive}.tar",
                       "*.gem", "gzip")
    cd ".."
  end

  def get(pattern,options={})
    link = "http://rubyforge.org/projects/#{options[:project]}"
    agent = WWW::Mechanize.new
    page = agent.get(link)
    page.links.find { |l| l.text[/File/] }.click
    link = agent.page.links.find { |l| l.text[pattern] }
    link.click.save_as(link.text)
  end

  def fetch(opts,&block)
    populate(opts[:archive]) do
      module_eval &block
    end
  end

  module_function :fetch, :populate, :get

end

With this, we were able to grab automatically a tarball filled with all the gems needed to run Ruport 0.9.0 with a tiny little script:

require "lib/rf_downloader"

RFDownloader.fetch(:archive => "ruport_deps") do
  get /fastercsv.*gem/,          :project => "fastercsv"
  get /pdf-writer.*gem/,         :project => "ruby-pdf"
  get /color-tools.*gem/,        :project => "ruby-pdf"
  get /transaction-simple.*gem/, :project => "trans-simple"
  get /RedCloth.*gem/,           :project => "redcloth"
  get /hoe.*gem/,                :project => "seattlerb"
  get /rubyforge.*gem/,          :project => "codeforpeople"
  get /mailfactory.*gem/,        :project => "mailfactory"
  get /mime-types.*gem/,         :project => "mime-types"
  get /scruffy.*gem/,            :project => "scruffy"
  get /build.*gem/,              :project => "builder"
  get /gem_plugin.*gem/,         :project => "mongrel"
end

Elegant? Nope! A way to be lazy and quickly snapshot the newest versions of a number of gems, you bet ya. Maybe someone will see this and build a nice little library that does this ‘the right way’ :)

UPDATE: Thanks to Aaron Patterson for helping me get rid of the wget call