Make Rake Task from Gem Available Everywhere

Including rake tasks in gems

On Rails 3, you do this via Railties. Here's the code to do it for a gem I just made:

class BackupTask < Rails::Railtie
rake_tasks do
Dir[File.join(File.dirname(__FILE__),'tasks/*.rake')].each { |f| load f }
end
end

So you basically create a class that inherits from Rails::Railtie, then within that class you have a rake_tasks block that loads the relevant files. You must load instead of require if you want to use a .rake extension.

I found that I need to specify the full path to Dir (hence the File.join gymnastics). If I just wanted to list the file explicitly then I could get away with just saying load 'tasks/foo.rake' because the /lib dir of my gem was in the load path.

Can a Rake task be documented with a multiline usage accessible from command line?

I came here with the same problem: I added a parameter with a default value to task, and wanted to document that in enough detail to make sure that folks knew they could pass their own value.

I found that if I made the string longer, it would print the entire string, wrapping it to the next line, which looks terrible. But if I passed a multiline string, the -T output would only print the string up to the end of the first line.

It turns out, this behavior is intentional:

https://ruby.github.io/rake/Rake/DSL.html#method-i-desc

Descriptions are shown with rake -T (up to the first sentence)
and rake -D (the entire description).

Given your example above, rake -D (or rake --describe) should do the trick:

$ rake -T
rake idle[option,token] # Do nothing, even when arguments are provided

$ rake -D
rake idle[option,token]
Do nothing, even when arguments are provided.
Usage:
rake 'users:idle["something", "anotherthing"]'
rake 'users:idle[, "anotherthing"]' # something is ignored anyway
rake users:idle # do nothing tersely

Determining whether gem was called as Rake task

Rake is only defined in rake context.

So, you could simply go something like that :

if defined? Rake
# rake specific stuff
else
# non rake stuff
end

Edit :

While this will work perfectly with rails s, there's a problem with zeus on development environment : zeus will require rake.

If this is a problem, if think you can take advantage of Rake.application, which sets an instance variable when a rake task is executed.

I've tested this in a zeus s context :

> Rake.instance_variable_defined? :@application
false

And in a rake <task> context :

> Rake.instance_variable_defined? :@application
true

So, a complete solution would be :

if defined?( Rake ) and Rake.instance_variable_defined?( :@application )
# rake specific stuff
else
# non rake stuff
end

Is it possible to include a module in rake tasks without polluting the global scope?

Here's what worked for me:

module MyRakeHelpers
def helper
puts 'foo'
end
end

module MyRakeTasks
extend Rake::DSL
extend MyRakeHelpers

task :some_task do
helper
end
end

In short, you can use the Rake DSL in a different scope by including (or extending) Rake::DSL. From the source:

DSL is a module that provides #task, #desc, #namespace, etc. Use this when you'd like to use rake outside the top level scope. For a Rakefile you run from the command line this module is automatically included.

task uses Rake::Task#define_task under the hood, which you could also use to write your own DSL.

Thanks to How To Build Custom Rake Tasks; The Right Way for the tip about define_task.

Rubymotion, adding interface builder: running a rake task from gem gives Don't know how to build task 'ib'

Make sure to require 'ib' inside the Rakefile, either with Bundler or manually for each gem.

And if you use Bundler, you might need to remove the begin/catch guard, because it will silence all import related errors.



Related Topics



Leave a reply



Submit