8

How can I return some value from a Rake task in ruby.

Sample code:

namespace tasks
    task task1: :environment do |task|
      log = "Running task"
      puts log
      log << "Done"
      return log # suggest how to do this
    end
end

I am running the rake task as: Rake::Task['tasks:task1'].invoke. How can I get the return value in a variable as follows:

result = Rake::Task['tasks:task1'].invoke
Rajesh Paul
  • 6,793
  • 6
  • 40
  • 57
  • Looking through the source code for `rake` this appears to be not possible. Ultimately the return value for a rake task is determined from `Task#execute` which has a `nil` return value. You can take a look here. https://github.com/ruby/rake/blob/master/lib/rake/task.rb#L270 – Eli Sadoff May 23 '20 at 02:53
  • Instead of calling other task result, in task1 I set `result = 'something'` and in task2 I can read the variable. Consider I created `result` variable outside task scopes, something like `result = nil` before any namespace/task. This is, assuming you want a task result in other task. – Juan José Ramírez Jan 23 '21 at 23:45
  • In the past I have resorted to storing a flag somewhere either in a database table or in a txt file that can be read back in when needed – jamesc Aug 25 '23 at 13:57

5 Answers5

1

Assuming you want the task result in other task:


config = ''

task :load_config do
  config = 'some config' # this could be reading from a file or API
end

# this tasks depends on the other
task use_config: [:load_config] do
  puts config
end

Then:

$ bundle exec rake use_config
some config
0

Try aborting with an error message and catching that.

Depending on what you're trying to return, you could try aborting the task with an error message, which would be "catchable" from where you invoked the task. You could then see what the error message was.

Your Task

namespace :tasks
  task task1: :environment do |task|
    log = "Running task... "
    puts log
    log << "Done!"
    abort( log )
  end
end

Running Your Task

begin
  Rake::Task[ "tasks:task1" ].invoke
rescue SystemExit => exit
  puts exit.message #=> "Running task... Done!" 
end

It's not exactly elegant but depending on what you're trying to return it could handle your needs.

Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
0

Call the Rake's action directly.

Using @vigo's example because it's simple.

task :return_a_value do
  '123'
end
result = Rake::Task['return_a_value'].actions.first.call

puts result #=> "123"

I found this out by digging through the various methods of the Rake Task in the console and this appeared to work without having to run the task twice, like @vido's answer.

However, the only caveat I've found is that I couldn't figure out how to pass arguments to the Rake Task using this method. Using .call( "myargument" ) didn't work. If you can figure out how to do this, I'd be grateful if you shared it. Thanks!

Update: Figured it out.

After a little more experimentation, I figured out how to use this method while passing arguments to the Rake Task. You just have to pass a Hash of the arguments as the second parameter and nil as the first, like so:

task :return_a_value, :mystring do
  mystring
end
result = Rake::Task['return_a_value'].actions.first.call( nil, { mystring: "hellow there" } )

puts result #=> "hellow there"

It has the added benefit of naming the parameters you pass to the Rake Task, which is a nice bonus.


Versions

  • Rails: 7.0.7
  • Ruby: 3.2.2
Joshua Pinter
  • 45,245
  • 23
  • 243
  • 245
-1

You can exit a rake task with a code and then check that with $?

But perhaps rake might not really the right tool for this job.

Stuart Mclean
  • 407
  • 6
  • 7
-1
task :return_a_value do
  '123'
end

task :hello do
  result = Rake::Task['return_a_value'].invoke.first.call
  puts result
end

now call:

$ rake hello
123
vigo
  • 298
  • 3
  • 8
  • 2
    this runs task `return_a_value` twice. You can check this if you add a print before the return – Juan José Ramírez Jan 22 '21 at 18:34
  • if you add more prints, you'll see more executions. thats why .invoke.first (from an array) important. when you inject print statement, it will be another statement to run. try with double print lines. such as print 'a' (new line) print 'b' (new line) and '123' – vigo Jan 23 '21 at 10:35
  • `invoke` will run the task and store it in an array, and `first.call` will run the task one more time – Juan José Ramírez Jan 23 '21 at 23:42
  • they are all proc in the array. any suggestions? @JuanJoséRamírez – vigo Jan 25 '21 at 04:37