Pointless One

Nice Rakefile

Last few days I’ve been writing ebuilds for some gems. There are a lot of problems with packed gems and many of them was discussed before. I want to talk about only one of them - evil Rakefiles.

Here’s example of evil Rakefile:

require 'rake'
require 'spec'
require 'cucumber'

require 'cucumber/rake/task'
require 'spec/rake/spectask'

spec_files = Rake::FileList["spec/**/*_spec.rb"]

desc "Run specs"
Spec::Rake::SpecTask.new do |t|
  t.spec_files = spec_files
  t.spec_opts = ["-c"]
end

Cucumber::Rake::Task.new(:features) do |t|
  t.cucumber_opts = "features --format progress"
end

task :default => [:spec, :features]

You see those requires at the top? It means that you can not even list available tasks if you don’t have rspec and cucumber installed.

Here’s the approach I propose. Write a stubs for tasks so that people could list tasks and run tasks without forcing them to install unnecessary stuff.

Like this:

require 'rake'

desc "Run specs"
task :spec do
  unless Rake.application.lookup('real_spec')
    require 'spec'
    require 'spec/rake/spectask'

    spec_files = Rake::FileList["spec/**/*_spec.rb"]

    Spec::Rake::SpecTask.new(:real_spec) do |t|
      t.spec_files = spec_files
      t.spec_opts = ["-c"]
    end
  end
  Rake.application['real_spec'].invoke
end

desc "Run features"
task :features do
  unless Rake.application.lookup('real_features')
    require 'cucumber'
    require 'cucumber/rake/task'

    Cucumber::Rake::Task.new(:real_features) do |t|
      t.cucumber_opts = "features --format progress"
    end
  end
  Rake.application['real_features'].invoke
end

task :default => [:spec, :features]

This Rakfile postpones requiring stuff until it’s really needed and so creating needed tasks and calling them. Yes this is a bit longer than previous variant but it also much nicer. Note, this is rather small Rakefile and it already depends on two gems I’ve seen Rakefiles that pull half a dozen gems for tests and about the same for docs. And each of those gems has their own dependencies. So I have to install a whole bunch of gems to just see the list of available tasks or run a task that is not related to tests or docs.

Be nice.