4

I wonder — is it possible to create private helpers for rake tasks, no matter how I try to do it they end up being available in the in the global scope and also are available as methods of any object. For example:

## this is what I need

module MyRakeHelpers
  def helper_1
  end

  def helper_2
  end
end

include RakeHelpers

task :sometask do
  helper_1
  helper_2
end

## And this should not work:

# global scope
helper_1

"a random object".helper_1

class RandomClass
  def foo
    helper_1
  end
end
Dmitry Sokurenko
  • 6,042
  • 4
  • 32
  • 53
  • I pasted this into a Rakefile and ran `rake sometask` and it blew up because helper_1 is undefined – kleaver Jun 20 '16 at 17:03
  • Obviously, as it is a part of the question, if would know how to correctly include the `MyRakeHelpers` into a task I wouldn't ask it :) – Dmitry Sokurenko Jun 20 '16 at 17:05
  • Ok I didn't understand that from the question, I thought all of the above code was somehow working and you wanted to know why – kleaver Jun 20 '16 at 17:11

3 Answers3

5

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.

Max Wallace
  • 3,609
  • 31
  • 42
1

I think you can write your rake task like this:

module MyRakeHelpers
  def helper_1
  end

  def helper_2
  end
end

task :sometask do
  include RakeHelpers
  helper_1
  helper_2
end   
Sean
  • 983
  • 5
  • 13
  • 1
    Nope, that would actually pollute the global namespace, it's just not evident as `include` happens only when the task is called. You can add something like `"just a string".helper_1` into the `:sometask` block and it will work fine, but it should not. And all those helpers become available anywhere in the app once the `include` was called. – Dmitry Sokurenko Jun 20 '16 at 17:20
1

First anwser: Is this what you are looking for?

module MyRakeHelpers
  def self.helper_1
    puts 'helper_1'
  end

  def self.helper_2
    puts 'helper_2'
  end
end

task :sometask do
  MyRakeHelpers.helper_1
  MyRakeHelpers.helper_2
end

Second answer: The only thing I can think of is something like this

module MyRakeHelpers
  def helper_1
    puts 'helper_1'
  end

  def helper_2
    puts 'helper_2'
  end
end

task :sometask do |t|
  t.extend MyRakeHelpers
  t.helper_1
end

But you'll have to add the t everywhere

kleaver
  • 749
  • 8
  • 14
  • you shouldn't have to pollute the interface of the module in order to access the method. If you just include it in the scope of the rake task, instance of calling methods on your module, you achieve the same thing but open yourself up to less code misuse. – Sean Jun 20 '16 at 17:12
  • 1
    Nope, that's an obvious solution, but that's not what I'm looking for, I have a project with hundreds of Rake tasks, and about the same number of global helpers, prefixing each of them with a module name is a bit too cumbersome. – Dmitry Sokurenko Jun 20 '16 at 17:25