How do I use gets on a rake task?
The problem is that Kernel#gets
(which is what you're calling if you just use gets
by itself) assumes you're pulling from a file named by the arguments passed to Rake. That means gets
tries to return the content of a file called [rake-task-here], which almost certainly doesn't exist.
Try STDIN.gets
.
Asking questions in rake tasks
task :input_test do
input = ''
STDOUT.puts "What is the airspeed velocity of a swallow?"
input = STDIN.gets.chomp
raise "bah, humbug!" unless input == "an african or european swallow?"
end
task :blah_blah => :input_test do
end
i think that should work
Accepting user input from the console/command prompt inside a rake task
Rake tasks are stored in the lib/tasks
folder of the Rails application. The rake task's file should end with the .rake
extension; for example: populate.rake
.
Accepting the input is done with STDIN.gets.chomp
instead of gets.chomp
.
namespace :db do
desc "Prints the migrated versions"
task :populate => :environment do
puts "\n Is this what you want to happen? [Y/N]"
answer = STDIN.gets.chomp
puts answer
if answer == "Y"
# your code here
elsif answer == "N"
return false # Abort the rake task
end
end
end
You can run this rake task with: rake db:populate
Get rake task name in initializer
None of the other answers presented here will work unless you stop using Spring, because Spring changes the way rake tasks are called significantly.
When using Spring, the command being run is handed over to the Spring server process using a UNIX socket and unfortunately Spring server reads this socket to get the command and its arguments after initializing the rails environment. Thus, during rails initialization, there seems to be no way of getting the command and its arguments (e.g. the rake task name) when using Spring, as Spring itself does not know yet! Even the after_fork
hook that Spring provides won't help, because it is being also run after rails initialization.
A proof can be seen in the Spring source code. It is the serve
method in which Spring gets the ARGV
of the command being run from the socket, forks itself and runs the command. The relevant parts of the method are these:
def serve(client)
# ... getting standard input / output streams from the client socket
# this is where rails initialization occurs
preload unless preloaded?
# this is where Spring gets the command name and it's ARGV and environment
args, env = JSON.load(client.read(client.gets.to_i)).values_at("args", "env")
command = Spring.command(args.shift)
# ...
# fork and run the command
pid = fork {
# ...
# run the command
ARGV.replace(args)
$0 = command.exec_name
# ...
# run the after_fork hook
invoke_after_fork_callbacks
command.call
}
# ...
end
The rails initializers are run in the preload
method which is run before the command name is read from the socket. The $0
and ARGV
variables are also set after initialization, in the fork
block.
So, unless you monkey-patched Spring significantly (replaced the serve
method with your own, but you'd need to handle working with the socket yourself), you need to stop calling your rake tasks inside the Spring environment. If the rake
command is a binstub in the RAILS_ROOT/bin/
directory, you need to remove the binstub with spring binstup --remove rake
.
Only then, I believe, you can use one of the solutions in the other answers.
How would I force Kernel#gets to use STDIN#gets in a rake task?
(Answered by @the-tin-man in this comment)
There's really very little advantage to be gained in DRYness from forcing Kernel#gets
to read from STDIN
in any context, including Rake. Although it can be done (by modifying $stdin
), it shouldn't be done because it would just be brittle and hacky.
How to pass command line arguments to a rake task
Options and dependencies need to be inside arrays:
namespace :thing do
desc "it does a thing"
task :work, [:option, :foo, :bar] do |task, args|
puts "work", args
end
task :another, [:option, :foo, :bar] do |task, args|
puts "another #{args}"
Rake::Task["thing:work"].invoke(args[:option], args[:foo], args[:bar])
# or splat the args
# Rake::Task["thing:work"].invoke(*args)
end
end
Then
rake thing:work[1,2,3]
=> work: {:option=>"1", :foo=>"2", :bar=>"3"}
rake thing:another[1,2,3]
=> another {:option=>"1", :foo=>"2", :bar=>"3"}
=> work: {:option=>"1", :foo=>"2", :bar=>"3"}
NOTE: variable
task
is the task object, not very helpful unless you know/care about Rake internals.
RAILS NOTE:
If running the task from Rails, it's best to preload the environment by adding
=> [:environment]
which is a way to setup dependent tasks.
task :work, [:option, :foo, :bar] => [:environment] do |task, args|
puts "work", args
end
Related Topics
Rails: Validating Min and Max Length of a String But Allowing It to Be Blank
Xcode - Configure: Error: No Acceptable C Compiler Found in $Path
Rails: How to Write Tests for a Ruby Module
Namespacing Thor Commands in a Standalone Ruby Executable
Passing Param Values to Redirect_To as Querystring in Rails
How to Check If a Gem Is Installed
Conditional Tag Wrapping in Rails/Erb
Switching Between Web and Touch Interfaces on Facebook Login Using Omniauth and Rails 3
Generate a Migration File from Schema.Rb
How to Test a Ruby Application Which Uses Mechanize
How to Controller (Start/Kill) a Background Process (Server App) in Ruby
How to Use an Overridden Constant in an Inheritanced Class
Are Bundle Exec and Require 'Bundler/Setup' Equivalent
Ruby - Adding a Directory to $Load_Path - What Does It Do
Rails: How to Autocomplete Search for Name But Save Id
What Is the Easiest Way I Can Create a 'Beep' Sound from a Ruby Program