RubyRedGrapefruit
RubyRedGrapefruit

Reputation: 12214

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 Rake task.

Upvotes: 54

Views: 18274

Answers (4)

armchairdj
armchairdj

Reputation: 1070

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!

Upvotes: 1

Kamil Sarna
Kamil Sarna

Reputation: 6281

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

Upvotes: 10

Jon Cairns
Jon Cairns

Reputation: 11951

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

Upvotes: 5

ricaurte
ricaurte

Reputation: 1436

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?

Upvotes: 108

Related Questions