Is it possible to make an interactive Rake task?
I want to run a Rake task that asks the user for input.
I know that I can supply input on the command line, but I want to ask the user if they are sure they want to proceed with a particular action in case they mistyped one of the values supplied to the 开发者_StackOverflow社区Rake task.
Something like this might work
task :action do
STDOUT.puts "I'm acting!"
end
task :check do
STDOUT.puts "Are you sure? (y/n)"
input = STDIN.gets.strip
if input == 'y'
Rake::Task["action"].reenable
Rake::Task["action"].invoke
else
STDOUT.puts "So sorry for the confusion"
end
end
Task reenabling and invoking from How to run Rake tasks from within Rake tasks?
Here's an example without using another task.
task :solve_earth_problems => :environment do
STDOUT.puts "This is risky. Are you sure? (y/n)"
begin
input = STDIN.gets.strip.downcase
end until %w(y n).include?(input)
if input != 'y'
STDOUT.puts "So sorry for the confusion"
return
end
# user accepted, carry on
Humanity.wipe_out!
end
A handy feature for user input is to put it in a do..while
loop, to only continue when a user has supplied valid input. Ruby doesn't explicitly have this construct, but you can achieve the same thing with begin
and until
. That would add to the accepted answer as follows:
task :action do
STDOUT.puts "I'm acting!"
end
task :check do
# Loop until the user supplies a valid option
begin
STDOUT.puts "Are you sure? (y/n)"
input = STDIN.gets.strip.downcase
end until %w(y n).include?(input)
if input == 'y'
Rake::Task["action"].reenable
Rake::Task["action"].invoke
else
# We know at this point that they've explicitly said no,
# rather than fumble the keyboard
STDOUT.puts "So sorry for the confusion"
end
end
You could also wrap this up in a service class so it can be unit-tested and used across your rake tasks:
# frozen_string_literal: true
class RakeConfirmDialog
def initialize(question)
@question = "#{question} (y/n)"
@answer = "".inquiry
end
def confirm!
prompt until (proceed? || abort?)
respond
proceed?
end
private
def prompt
STDOUT.puts @question
@answer = STDIN.gets.strip.downcase.inquiry
end
def respond
STDOUT.puts proceed? ? "Proceeding." : "Aborting."
end
def proceed?
@answer.y?
end
def abort?
@answer.n?
end
end
Then use it like so in your task:
next unless RakeConfirmDialog.new(
"About to close the Hellmouth forever. Are you sure you want 'Buffy the Vampire Slayer' to have a happy ending?"
).confirm!
精彩评论