Invoke namespaced rake task in ruby code - ruby

Given some ruby file foo.rb:
require 'rake'
namespace :tmp do
desc "Foo bar baz.."
task :some_task do
puts "running some task..."
end
end
How can I invoke the namespaced task tmp:some_task task in ruby?
I've tried:
require_relative 'foo'
#=> true
Rake::Task[tmp:some_task].invoke
#=> NameError: undefined local variable or method `some_task' for main:Object

You are calling the task incorrectly - pass the name of the task as string:
Rake::Task['tmp:some_task'].invoke

The Accepted answer is correct. But, from rails, to invoke any rake task from Rails. you need to load them first.
require 'rake'
Rails.application.load_tasks
Rake::Task['my_task'].invoke

Related

Rake tast with cli arguments in Sinatra

I have created a rake file in my Sinatra app to create indexes for a Mongodb collection and I am trying to pass the environment parameter in the rake task db:create_indexes.
Here is my db.rake file:
namespace :db do
task :create_indexes, :environment do |t, args|
puts "Environment : #{args}"
unless args[:environment]
puts "Must provide an environment"
exit
end
yaml = YAML.load_file("./config/mongoid.yml")
env_info = yaml[args[:environment]]
unless env_info
puts "Unknown environment"
exit
end
Mongoid.configure do |config|
config.from_hash(env_info)
end
Bin.mongoid:create_indexes
end
end
Also the Rakefile in the root of app contains:
require 'rake'
require 'rubygems'
require 'bundler/setup'
Dir.glob('lib/tasks/*.rake').each { |r| load r}
But whenver I try to run the rake task using the command rake db:create_indexes[development], I get the following error, no matches found: db:create_indexes[development]
Now I am clueless about how to solve this issue.
So the problem was not with the code but the shell I was using.
I use zsh shell in place of bash and it seems zsh require you to escape the brackets: rake my_task\['arg1'\].
Therefore the code works with rake db:create_indexes\['development'\].

How to access members of another class in a different file

I'm using ruby-prolog. I want to run a task to query a fact.
demo.rb:
require 'ruby-prolog'
c = RubyProlog::Core.new
c.instance_eval do
person['name','brian'].fact
person['name','James'].fact
puts 'all the names are: '
p query(person['name', :A])
end
This works great. Now I want to run the query inside of Rake. That is a problem because I don't know how to access person[] from the other file.
Rakefile.rb:
require_relative 'demo.rb'
task :test do |variable|
puts 'all the names are: '
p query(person['name', :A])
end
Error:
all the names are: rake aborted! NameError: undefined local variable
or method `person' for main:Object
I'm hoping this can be solved by passing an object back somehow. I tried accessing c, but it did not work out. Any ideas?
In your demo file, both variables person and c are local variables and will not be accessible from outside of that context. If you require demo.rb into an irb session, the behavior should be the same; neither c nor person will be defined.
A good way of dealing with this in rake tasks is to keep any and all logic out of the rake task itself, and only call out to another object that takes care of the task. For a quick and dirty example, you could alter your code as such:
# demo.rb
require 'ruby-prolog'
class Demo
def self.run_demo
# Existing code:
c = RubyProlog::Core.new
c.instance_eval do
person['name','brian'].fact
person['name','James'].fact
puts 'all the names are: '
p query(person['name', :A])
end
end
end
and
# Rakefile.rb
require_relative 'demo.rb'
task :test do
Demo.run_demo
end

How do I pass args from command line to rake then rspec

I'm trying to pass a couple of variables through the command line to rake to be used in rspec.
From what i gather i can do this to pass args into my rake task:
task :my_task, :arg1, :arg2 do |t, args|
puts "Args were: #{args}"
end
but I'm using rspec so my rake task looks like this:
RSpec::Core::RakeTask.new(:my_task), :arg1, :arg2 do |t, args|
puts args.arg1
puts args.arg2
end
which doesn't work.
also I havent figured out how to pass it to my rspec spec file
How do you call rake?
For your example you have to call:
rake mytask[val1,val2]
I'm not sure about your 2nd code example.
args should be a hash with keys :arg1 and :arg2.
So you may use
puts args[:arg1]
I'm in doubt if args.arg1 will work.
It's been a while since the original question, but I had to solve a similar problem. You don't have to change much of your initial idea:
RSpec::Core::RakeTask.new(:my_task, [:arg1, :arg2]) do |t, args|
puts args.arg1
puts args.arg2
end
Then call it e.g. via:
rake my_task["hello","world"]

Namespaces in Ruby Rake Tasks

Are the following equivalent?
namespace :resque do
task setup: :environment do
end
end
task "resque:setup" => :environment do
end
In short: yes. When running rake resque:setup both of these tasks will be invoked.
Rake will merge these tasks. You can test this by doing the following:
p Rake.application.tasks
Which in this case would return something like
[<Rake::Task resque:setup => [environment]>]
Which is simply an Array holding a single Rake::Task object. You can also check the scope or list of namespaces for a task by doing:
p Rake.application.tasks.first.scope
#=> ["resque"]
If you want to learn a little more on how the internals of Rake work, check out Rake::Task and Rake::TaskManager

How do I run Rake tasks within a Ruby script?

I have a Rakefile with a Rake task that I would normally call from the command line:
rake blog:post Title
I'd like to write a Ruby script that calls that Rake task multiple times, but the only solution I see is shelling out using `` (backticks) or system.
What's the right way to do this?
from timocracy.com:
require 'rake'
def capture_stdout
s = StringIO.new
oldstdout = $stdout
$stdout = s
yield
s.string
ensure
$stdout = oldstdout
end
Rake.application.rake_require 'metric_fetcher', ['../../lib/tasks']
results = capture_stdout {Rake.application['metric_fetcher'].invoke}
This works with Rake version 10.0.3:
require 'rake'
app = Rake.application
app.init
# do this as many times as needed
app.add_import 'some/other/file.rake'
# this loads the Rakefile and other imports
app.load_rakefile
app['sometask'].invoke
As knut said, use reenable if you want to invoke multiple times.
You can use invoke and reenable to execute the task a second time.
Your example call rake blog:post Title seems to have a parameter. This parameter can be used as a parameter in invoke:
Example:
require 'rake'
task 'mytask', :title do |tsk, args|
p "called #{tsk} (#{args[:title]})"
end
Rake.application['mytask'].invoke('one')
Rake.application['mytask'].reenable
Rake.application['mytask'].invoke('two')
Please replace mytask with blog:post and instead the task definition you can require your rakefile.
This solution will write the result to stdout - but you did not mention, that you want to suppress output.
Interesting experiment:
You can call the reenable also inside the task definition. This allows a task to reenable himself.
Example:
require 'rake'
task 'mytask', :title do |tsk, args|
p "called #{tsk} (#{args[:title]})"
tsk.reenable #<-- HERE
end
Rake.application['mytask'].invoke('one')
Rake.application['mytask'].invoke('two')
The result (tested with rake 10.4.2):
"called mytask (one)"
"called mytask (two)"
In a script with Rails loaded (e.g. rails runner script.rb)
def rake(*tasks)
tasks.each do |task|
Rake.application[task].tap(&:invoke).tap(&:reenable)
end
end
rake('db:migrate', 'cache:clear', 'cache:warmup')

Resources