Implement `ask' recipe keyword

This commit is contained in:
Thibault Jouan 2013-12-22 23:54:19 +00:00
parent 70109615c8
commit 7e062e06a1
7 changed files with 114 additions and 1 deletions

View File

@ -0,0 +1,22 @@
Feature: `ask' recipe keyword
Scenario: prompts user with a list of choices on standard output
Given a recipe with:
"""
task :ask_letter do
letter = ask 'Which letter?', %w[A B]
echo letter
end
"""
When I execute the recipe interactively
And I type "1"
Then the output must contain:
"""
Which letter?
0: A
1: B
Choice:
B
"""
And the exit status must be 0

View File

@ -10,3 +10,7 @@ When(/^I successfully execute the recipe$/) do
step 'I execute the recipe'
assert_exit_status(0)
end
When(/^I execute the recipe interactively$/) do
run_interactive('producer recipe.rb')
end

View File

@ -14,6 +14,7 @@ require 'producer/core/condition'
require 'producer/core/condition/dsl'
require 'producer/core/env'
require 'producer/core/errors'
require 'producer/core/prompter'
require 'producer/core/recipe'
require 'producer/core/recipe/dsl'
require 'producer/core/remote'

View File

@ -0,0 +1,21 @@
module Producer
module Core
class Prompter
attr_reader :input, :output
def initialize(input, output)
@input = input
@output = output
end
def prompt(question, choices)
cs = choices.each_with_index.inject('') do |m, (c, i)|
m += "#{i}: #{c}\n"
end
output.puts "#{question}\n#{cs}Choice:"
choice = input.gets
choices[choice.to_i]
end
end
end
end

View File

@ -32,6 +32,10 @@ module Producer
@condition = Condition.evaluate(@env, &block) if block
@condition
end
def ask(question, choices, prompter: Prompter)
prompter.new(env.input, env.output).prompt(question, choices)
end
end
end
end

View File

@ -0,0 +1,41 @@
require 'spec_helper'
module Producer::Core
describe Prompter do
let(:input) { StringIO.new }
let(:output) { StringIO.new }
let(:env) { Env.new(input: input, output: output) }
subject(:prompter) { Prompter.new(input, output) }
describe '#initialize' do
it 'assigns the given input' do
expect(prompter.input).to be input
end
it 'assigns the given output' do
expect(prompter.output).to be output
end
end
describe '#prompt' do
let(:question) { 'Which letter?' }
let(:choices) { %w[A B] }
it 'prompts choices' do
prompter.prompt question, choices
expect(output.string).to eq <<-eoh.gsub /^\s+\|/, ''
|#{question}
|0: A
|1: B
|Choice:
eoh
end
it 'returns value for entry chosen by user' do
input.puts '1'
input.rewind
expect(prompter.prompt question, choices).to eq 'B'
end
end
end
end

View File

@ -3,7 +3,7 @@ require 'spec_helper'
module Producer::Core
describe Task::DSL do
let(:block) { proc {} }
let(:env) { double 'env' }
let(:env) { Env.new }
subject(:dsl) { Task::DSL.new(env, &block) }
%w[echo sh file_write].each do |action|
@ -82,5 +82,25 @@ module Producer::Core
end
end
end
describe '#ask' do
let(:question) { 'Which letter?' }
let(:choices) { %w[A B] }
let(:prompter_class) { double('prompter class').as_null_object }
subject(:ask) { dsl.ask question, choices,
prompter: prompter_class }
it 'builds a prompter' do
expect(prompter_class).to receive(:new).with(env.input, env.output)
ask
end
it 'prompts and returns the choice' do
prompter = double 'prompter'
allow(prompter_class).to receive(:new) { prompter }
allow(prompter).to receive(:prompt) { :choice }
expect(ask).to eq :choice
end
end
end
end