diff --git a/README.md b/README.md index dbcb154e43..0bb87737a8 100644 --- a/README.md +++ b/README.md @@ -1,83 +1,51 @@ -Takeaway Challenge -================== -``` - _________ - r== | | - _ // | M.A. | )))) - |_)//(''''': | | - // \_____:_____.-------D ))))) - // | === | / \ - .:'//. \ \=| \ / .:'':./ ))))) - :' // ': \ \ ''..'--:'-.. ': - '. '' .' \:.....:--'.-'' .' - ':..:' ':..:' +# FAKE-AWAY - ``` +This is Gawain Hewitt's weekend challenge for Makers Academy week 2, the takeaway challenge. -Instructions -------- -* Feel free to use google, your notes, books, etc. but work on your own -* If you refer to the solution of another coach or student, please put a link to that in your README -* If you have a partial solution, **still check in a partial solution** -* You must submit a pull request to this repo with your code by 9am Monday morning +[Process Followed](#process-followed) -Task ------ +[Instructions For Use](#instructions-for-use) -* Fork this repo -* Run the command 'bundle' in the project directory to ensure you have all the gems -* Write a Takeaway program with the following user stories: +[Things I enjoyed](#things-i-enjoyed) -``` -As a customer -So that I can check if I want to order something -I would like to see a list of dishes with prices +[Things I struggled with](#things-i-struggled-with) -As a customer -So that I can order the meal I want -I would like to be able to select some number of several available dishes -As a customer -So that I can verify that my order is correct -I would like to check that the total I have been given matches the sum of the various dishes in my order -As a customer -So that I am reassured that my order will be delivered on time -I would like to receive a text such as "Thank you! Your order was placed and will be delivered before 18:52" after I have ordered -``` -* Hints on functionality to implement: - * Ensure you have a list of dishes with prices - * The text should state that the order was placed successfully and that it will be delivered 1 hour from now, e.g. "Thank you! Your order was placed and will be delivered before 18:52". - * The text sending functionality should be implemented using Twilio API. You'll need to register for it. It’s free. - * Use the twilio-ruby gem to access the API - * Use the Gemfile to manage your gems - * Make sure that your Takeaway is thoroughly tested and that you use mocks and/or stubs, as necessary to not to send texts when your tests are run - * However, if your Takeaway is loaded into IRB and the order is placed, the text should actually be sent - * Note that you can only send texts in the same country as you have your account. I.e. if you have a UK account you can only send to UK numbers. -* Advanced! (have a go if you're feeling adventurous): - * Implement the ability to place orders via text message. -* A free account on Twilio will only allow you to send texts to "verified" numbers. Use your mobile phone number, don't worry about the customer's mobile phone. +### Process Followed -> :warning: **WARNING:** think twice before you push your **mobile number** or **Twilio API Key** to a public space like GitHub :eyes: -> -> :key: Now is a great time to think about security and how you can keep your private information secret. You might want to explore environment variables. -* Finally submit a pull request before Monday at 9am with your solution or partial solution. However much or little amount of code you wrote please please please submit a pull request before Monday at 9am -In code review we'll be hoping to see: -* All tests passing -* High [Test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) (>95% is good) -* The code is elegant: every class has a clear responsibility, methods are short etc. -Reviewers will potentially be using this [code review rubric](docs/review.md). Referring to this rubric in advance will make the challenge somewhat easier. You should be the judge of how much challenge you want this at this moment. -Notes on Test Coverage ------------------- -You can see your [test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) when you run your tests. + + + + + + +### Instructions For Use + + + +### Things I enjoyed + +The challenge of writing tests for puts and user input. + +Trying to keep my tests discreet in each class. + +### Things I struggled with + +The sheer amount of work when writing tests for puts and user input. + +Stubbing a test to check totals on #confirm_order in class Takeaway + +Why a heredoc wouldn't work in my "it should display menu" test + diff --git a/diagramming_takewaway.odt b/diagramming_takewaway.odt new file mode 100644 index 0000000000..58ac364295 Binary files /dev/null and b/diagramming_takewaway.odt differ diff --git a/instructions.md b/instructions.md new file mode 100644 index 0000000000..dbcb154e43 --- /dev/null +++ b/instructions.md @@ -0,0 +1,83 @@ +Takeaway Challenge +================== +``` + _________ + r== | | + _ // | M.A. | )))) + |_)//(''''': | | + // \_____:_____.-------D ))))) + // | === | / \ + .:'//. \ \=| \ / .:'':./ ))))) + :' // ': \ \ ''..'--:'-.. ': + '. '' .' \:.....:--'.-'' .' + ':..:' ':..:' + + ``` + +Instructions +------- + +* Feel free to use google, your notes, books, etc. but work on your own +* If you refer to the solution of another coach or student, please put a link to that in your README +* If you have a partial solution, **still check in a partial solution** +* You must submit a pull request to this repo with your code by 9am Monday morning + +Task +----- + +* Fork this repo +* Run the command 'bundle' in the project directory to ensure you have all the gems +* Write a Takeaway program with the following user stories: + +``` +As a customer +So that I can check if I want to order something +I would like to see a list of dishes with prices + +As a customer +So that I can order the meal I want +I would like to be able to select some number of several available dishes + +As a customer +So that I can verify that my order is correct +I would like to check that the total I have been given matches the sum of the various dishes in my order + +As a customer +So that I am reassured that my order will be delivered on time +I would like to receive a text such as "Thank you! Your order was placed and will be delivered before 18:52" after I have ordered +``` + +* Hints on functionality to implement: + * Ensure you have a list of dishes with prices + * The text should state that the order was placed successfully and that it will be delivered 1 hour from now, e.g. "Thank you! Your order was placed and will be delivered before 18:52". + * The text sending functionality should be implemented using Twilio API. You'll need to register for it. It’s free. + * Use the twilio-ruby gem to access the API + * Use the Gemfile to manage your gems + * Make sure that your Takeaway is thoroughly tested and that you use mocks and/or stubs, as necessary to not to send texts when your tests are run + * However, if your Takeaway is loaded into IRB and the order is placed, the text should actually be sent + * Note that you can only send texts in the same country as you have your account. I.e. if you have a UK account you can only send to UK numbers. + +* Advanced! (have a go if you're feeling adventurous): + * Implement the ability to place orders via text message. + +* A free account on Twilio will only allow you to send texts to "verified" numbers. Use your mobile phone number, don't worry about the customer's mobile phone. + +> :warning: **WARNING:** think twice before you push your **mobile number** or **Twilio API Key** to a public space like GitHub :eyes: +> +> :key: Now is a great time to think about security and how you can keep your private information secret. You might want to explore environment variables. + +* Finally submit a pull request before Monday at 9am with your solution or partial solution. However much or little amount of code you wrote please please please submit a pull request before Monday at 9am + + +In code review we'll be hoping to see: + +* All tests passing +* High [Test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) (>95% is good) +* The code is elegant: every class has a clear responsibility, methods are short etc. + +Reviewers will potentially be using this [code review rubric](docs/review.md). Referring to this rubric in advance will make the challenge somewhat easier. You should be the judge of how much challenge you want this at this moment. + +Notes on Test Coverage +------------------ + +You can see your [test coverage](https://github.com/makersacademy/course/blob/main/pills/test_coverage.md) when you run your tests. diff --git a/lib/menu.rb b/lib/menu.rb new file mode 100644 index 0000000000..dd5f4e2966 --- /dev/null +++ b/lib/menu.rb @@ -0,0 +1,37 @@ +class Menu + + def initialize(input: $stdin, output: $stdout) + @input = input + @output = output + @dishes = [{ food: :Chips, price: 1 }, + { food: :Tofu, price: 2 }, { food: :Broccoli, price: 1 }, + { food: :Ice_cream, price: 2 }] + end + + def show + @dishes.each_with_index do |item, index| + @output.puts "#{index + 1}. #{item[:food]} - £#{item[:price]}" + end + end + + def check(dish) + the_dish = dish.to_sym + @dishes.each do |dish| + if the_dish == dish[:food] + return true + end + end + return false + end + + def price(dish) + the_dish = dish.to_sym + @dishes.each do |dish| + if the_dish == dish[:food] + return dish[:price] + end + end + return false + end + +end diff --git a/lib/takeaway.rb b/lib/takeaway.rb new file mode 100644 index 0000000000..2224e5c449 --- /dev/null +++ b/lib/takeaway.rb @@ -0,0 +1,67 @@ +require './lib/menu' + +class Takeaway + attr_reader :menu, :summary + + def initialize(input: $stdin, output: $stdout) + @input = input + @output = output + @menu = Menu.new + @dishes = [] + @summary = [] + @total = 0 + end + + def show_menu + @menu.show + end + + def order + loop do + dish = ask_for_order + return confirm_order if dish == "" + if menu.check(dish) + quantity = ask_for_quantity + log_order(dish, quantity) + else + clarify_order + end + end + end + + def confirm_order + @summary.each do |dish| + @output.puts "#{dish[:quantity]} order of #{dish[:food]} at £#{menu.price(dish[:food])} each" + @total += menu.price(dish[:food]) + end + @output.puts "Total order is £#{@total}" + end + + private + + + def ask_for_order + @output.puts <<~ORDER + Please type each dish you require followed by return. + When you have finished your order press return twice. + ORDER + dish = @input.gets.chomp + end + + def clarify_order + @output.puts "Sorry, we don't have that dish - perhaps you've made a spelling mistake?" + end + + def ask_for_quantity + @output.puts "how many do you want?" + quantity = @input.gets.to_i + end + + def log_order(dish, quantity) + order_item = {} + order_item[:food] = dish + order_item[:quantity] = quantity + @summary << order_item + end + +end diff --git a/spec/feature_test_spec.rb b/spec/feature_test_spec.rb new file mode 100644 index 0000000000..25c23df74b --- /dev/null +++ b/spec/feature_test_spec.rb @@ -0,0 +1,32 @@ +require 'takeaway' + +describe 'Featuretest' do + context '#order' do + it 'will ask again if item mispelt' do + output = place_order_with_input("Brocoli", "Broccoli") + + expect(output).to eq <<~OUTPUT + Please type each dish you require followed by return. + When you have finished your order press return twice. + Sorry, we don't have that dish - perhaps you've made a spelling mistake? + Please type each dish you require followed by return. + When you have finished your order press return twice. + how many do you want? + Please type each dish you require followed by return. + When you have finished your order press return twice. + 0 order of Broccoli at £1 each + Total order is £1 + OUTPUT + end + end + + def place_order_with_input(*order) + input = StringIO.new(order.join("\n") + "\n" + "\n" + "\n") + output = StringIO.new + + takeaway = Takeaway.new(input: input, output: output) + takeaway.order + + output.string + end +end diff --git a/spec/menu_spec.rb b/spec/menu_spec.rb new file mode 100644 index 0000000000..06223cdf18 --- /dev/null +++ b/spec/menu_spec.rb @@ -0,0 +1,35 @@ +require 'menu' + +describe Menu do + + context '#show' do + it 'should display menu' do + # output = <<~MENU + # 1. Chips - £1 + # 2. Tofu - £2 + # 3. Broccoli - £1 + # 4. Ice_cream - £2 + # MENU + # expect { subject.show }.to output(output).to_stdout + + expect { subject.show }.to output("1. Chips - £1\n2. Tofu - £2\n3. Broccoli - £1\n4. Ice_cream - £2\n").to_stdout + end + end + + context '#check' do + it 'dish against menu and return false' do + wrong_spelling = "Brocoli" + expect(subject.check(wrong_spelling)).to eq false + end + it 'dish against menu and return true' do + right_spelling = "Broccoli" + expect(subject.check(right_spelling)).to eq true + end + end + + context '#price' do + it 'returns the price of an item' do + expect(subject.price("Broccoli")).to eq 1 + end + end +end diff --git a/spec/takeaway_spec.rb b/spec/takeaway_spec.rb new file mode 100644 index 0000000000..32cb644012 --- /dev/null +++ b/spec/takeaway_spec.rb @@ -0,0 +1,96 @@ +require 'takeaway' +require 'stringio' + +describe Takeaway do + + context '#show menu' do + it 'should call #show from class instance of Menu' do + expect(subject.menu).to receive(:show) + subject.show_menu + end + end + + context '#order' do + it 'can ask for one order from menu and return summary and total' do + output = place_order_with_input_and_return_output("Broccoli") + + expect(output).to eq <<~OUTPUT + Please type each dish you require followed by return. + When you have finished your order press return twice. + how many do you want? + Please type each dish you require followed by return. + When you have finished your order press return twice. + 0 order of Broccoli at £1 each + Total order is £1 + OUTPUT + end + it 'can ask for three orders from menu and return summary and total' do + output = place_order_with_input_and_return_output("Broccoli", 2, "Chips", 1, "Ice_cream", 1) + + expect(output).to eq <<~OUTPUT + Please type each dish you require followed by return. + When you have finished your order press return twice. + how many do you want? + Please type each dish you require followed by return. + When you have finished your order press return twice. + how many do you want? + Please type each dish you require followed by return. + When you have finished your order press return twice. + how many do you want? + Please type each dish you require followed by return. + When you have finished your order press return twice. + 2 order of Broccoli at £1 each + 1 order of Chips at £1 each + 1 order of Ice_cream at £1 each + Total order is £3 + OUTPUT + end + it 'stores an order of one dish' do + takeaway = place_order_with_input_and_return_class("Chips", 1) + expect(takeaway.summary).to eq([{ food: "Chips", quantity: 1 }]) + end + it 'stores an order of four dishes' do + takeaway = place_order_with_input_and_return_class("Chips", 1, "Broccoli", 3, "Tofu", 1, "Ice_cream", 4) + expect(takeaway.summary).to eq([{ food: "Chips", quantity: 1 }, + { food: "Broccoli", quantity: 3 }, { food: "Tofu", quantity: 1 }, + { food: "Ice_cream", quantity: 4 }]) + end + end + + context '#confirm order' do + it 'confirms order' do + output = StringIO.new + takeaway = Takeaway.new(output: output) + takeaway.confirm_order + expect(output.string).to eq "Total order is £0\n" + end + end + + def place_order_with_input_and_return_output(*order) + input = StringIO.new(order.join("\n") + "\n" + "\n" + "\n") + output = StringIO.new + test_price = 1 + + takeaway = Takeaway.new(input: input, output: output) + allow(takeaway.menu).to receive(:check).and_return(true) + allow(takeaway.menu).to receive(:price).and_return(test_price) + takeaway.order + + output.string + end + + def place_order_with_input_and_return_class(*order) + input = StringIO.new(order.join("\n") + "\n" + "\n" + "\n") + output = StringIO.new + test_price = 1 + + takeaway = Takeaway.new(input: input, output: output) + allow(takeaway.menu).to receive(:check).and_return(true) + allow(takeaway.menu).to receive(:price).and_return(test_price) + + takeaway.order + + takeaway + end + +end