Rake prepare gem

I'm using rake to create a gem, but I have some questions.

Before creating a gem in Rake i would like to copy some files to
a different directory and then create the package.

I tried something like this:

task :gem => [:prepare_gem]

task :prepare_gem do
    # do stuff here
    gem_task.gem_spec.files = files.to_a
end

But the problem is that the prepare_gem is executed AFTER the gem
task. Is this normal?

···

--
Roeland

Roeland Moors said:

I'm using rake to create a gem, but I have some questions.

Great!

Before creating a gem in Rake i would like to copy some files to
a different directory and then create the package.

I tried something like this:

task :gem => [:prepare_gem]

task :prepare_gem do
    # do stuff here
    gem_task.gem_spec.files = files.to_a
end

But the problem is that the prepare_gem is executed AFTER the gem
task. Is this normal?

Actually, yes. First the explain why, and then the fix ...

Rake invokes a task, it will first invoke all the dependencies (aka
prerequisites) of that task before it executes the actions (the do/end
block) of that task. So you are guaranteed that the actions of a task
will execute only after the actions of all its all dependencies are
executed. You have no guarantee that the dependencies will be executed in
any particular order.

When debugging problems like this, the -P option on rake is your friend.
Here is the output for your rakefile (non-relevant portions elided).

  rake gem
      pkg/demo-0.0.0.gem
      prepare_gem
  rake pkg/demo-0.0.0.gem
      pkg
      a
      b
  rake prepare_gem

(NOTE: I created a package named 'demo' with version 0.0.0 and it depends
on two files named 'a' and 'b'. I don't know what you were using.)

We can see that the :gem task depends upon the "pkg/demo-0.0.0.gem" file
task which is where the gem file is actually created. Since :gem depends
on "pkg/demo-0.0.0.gem", the gem file will be built before the :gem
actions are executed. Also the actions of :prepare_gem will be executed
before :gem's actions. But since :prepare_gem and "pkg/demo-0.0.0.gem"
are sibling dependents of :gem, their order is not specified, hence the
gem is built before the :prepare_gem actions are performed.

The Fix

···

-------

You need to specify that :prepare_gem is a dependency of
"pkg/demo-0.0.0.gem" instead of :gem. To to this, add the following line
to your Rakefile ...

  file "pkg/demo-0.0.0.gem" => [:prepare_gem]

Now, the proper dependencies are declared and prepare_gem is guaranteed to
execute before the gem file is built.

The answer to almost any problem with Rake dependencies is to correctly
declare the real dependencies in the project.

An aside: It is tempting to just move the "task :gem => [:prepare_gem]"
task before the creation of the gem package task. This makes sure that
:prepare_gem comes first in the list of dependencies for :gem. And this
works because all other things being equal, rake will execute
dependencies in the order discovered. However, this is very fragile.
Other dependencies can easily override the "in order rule".

--
-- Jim Weirich jim@weirichhouse.org http://onestepback.org
-----------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)

Thanks a lot for the detailed information.

···

On Thu, Aug 26, 2004 at 12:53:29AM +0900, Jim Weirich wrote:

Roeland Moors said:
> I'm using rake to create a gem, but I have some questions.

Great!

> Before creating a gem in Rake i would like to copy some files to
> a different directory and then create the package.
>
> I tried something like this:
>
> task :gem => [:prepare_gem]
>
> task :prepare_gem do
> # do stuff here
> gem_task.gem_spec.files = files.to_a
> end
>
> But the problem is that the prepare_gem is executed AFTER the gem
> task. Is this normal?

Actually, yes. First the explain why, and then the fix ...
[snip]

--
Roeland