Search code examples
rake

How To Process Inputs and Outputs in Separate Directories in Rake?


I am trying to convert Haml files to HTML files using Rake, so that if the Haml files have not changed, I do not re-generate existing HTML.

However, I do not want my input files, output files, and Rakefile all smushed into one directory. Instead, I want my input files to be in src/ and my output files to be in build/output/. So, I want to start with:

Rakefile
src/
  slides.haml

and I want to end with:

Rakefile
src/
  slides.haml
build/
  output/
    slides.html

I have tried several bits of Rake code, with no luck.

First, I tried the caveman approach, hard-coding the precise files I am trying:

task "build/output/slides.html" => "src/slides.haml" do
  touch task.name
end

task :slides => "src/slides.haml"
task :default => "slides"

Running rake --trace results in:

** Invoke default (first_time)
** Invoke slides (first_time)
** Invoke src/slides.haml (first_time, not_needed)
** Execute slides
** Execute default

The directory is not built, and I do not have an empty build/output/slides.html file.

Ideally, I'd prefer a rule-and-FileList approach, using stuff like this SO answer or this "Rake cheatshet" entry. However, I tried a few variations on that theme, and I get the same results, suggesting that I have something more profoundly messed up. I have trimmed my Rakefile back to the caveman approach, just to try to grok what's going on here.

Why is Rake not recognizing my "build/output/slides.html" task? Is there some magic to using subdirectories (input or output) in Rake?


Solution

  • I was missing that file tasks use file instead of task, and that there is a directory task as well.

    The working version of the caveman approach is:

    namespace :build do
      directory "build/output"
    
      file "build/output/slides.html" => ["build/output", "src/slides.haml"] do |t|
        touch t.name
      end
    
      task :all => "build/output/slides.html"
    end
    
    task :default => ['build:all']