From 7e062e06a1d175a331c88bd723c76aa42b8409a6 Mon Sep 17 00:00:00 2001 From: Thibault Jouan Date: Sun, 22 Dec 2013 23:54:19 +0000 Subject: [PATCH] Implement `ask' recipe keyword --- features/recipes/ask.feature | 22 ++++++++++++++++ features/steps/recipe_steps.rb | 4 +++ lib/producer/core.rb | 1 + lib/producer/core/prompter.rb | 21 +++++++++++++++ lib/producer/core/task/dsl.rb | 4 +++ spec/producer/core/prompter_spec.rb | 41 +++++++++++++++++++++++++++++ spec/producer/core/task/dsl_spec.rb | 22 +++++++++++++++- 7 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 features/recipes/ask.feature create mode 100644 lib/producer/core/prompter.rb create mode 100644 spec/producer/core/prompter_spec.rb diff --git a/features/recipes/ask.feature b/features/recipes/ask.feature new file mode 100644 index 0000000..4b5c889 --- /dev/null +++ b/features/recipes/ask.feature @@ -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 diff --git a/features/steps/recipe_steps.rb b/features/steps/recipe_steps.rb index 30b693c..32b5810 100644 --- a/features/steps/recipe_steps.rb +++ b/features/steps/recipe_steps.rb @@ -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 diff --git a/lib/producer/core.rb b/lib/producer/core.rb index 6ec3b16..99ea0fb 100644 --- a/lib/producer/core.rb +++ b/lib/producer/core.rb @@ -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' diff --git a/lib/producer/core/prompter.rb b/lib/producer/core/prompter.rb new file mode 100644 index 0000000..6cbb7a5 --- /dev/null +++ b/lib/producer/core/prompter.rb @@ -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 diff --git a/lib/producer/core/task/dsl.rb b/lib/producer/core/task/dsl.rb index d4e5721..fc02a2e 100644 --- a/lib/producer/core/task/dsl.rb +++ b/lib/producer/core/task/dsl.rb @@ -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 diff --git a/spec/producer/core/prompter_spec.rb b/spec/producer/core/prompter_spec.rb new file mode 100644 index 0000000..cda76ed --- /dev/null +++ b/spec/producer/core/prompter_spec.rb @@ -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 diff --git a/spec/producer/core/task/dsl_spec.rb b/spec/producer/core/task/dsl_spec.rb index 0d8b89b..0f22950 100644 --- a/spec/producer/core/task/dsl_spec.rb +++ b/spec/producer/core/task/dsl_spec.rb @@ -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