We will learn today to cook with objects. We will start with creating a list of all objects of a pizzeria.
Because with objects oriented programming you want your code to work like a pizzeria.
- Waiter: You talk to the waiter. He takes your order, serves the food, checks if you want anything else and eventually you can pay the bill.
- Kitchen: In the kitchen the food is prepared.
- Dish: A dish is a collection of ingredients prepared in a certain order.
- Menu: A collection of recipes with available ingredients
- Ingredients: Part of a recipe.
- Stock: Amount of ingredients available
- Storageroom: Holds the stock
Lets start by setting up the project:
- open your terminal
- create a new directory
- go into the directory
- initialize a new git repository
git init
[01] As a guest. I want to be greeted by the waiter when I enter the pizzeria. So that I feel like I am welcome.
Tasks:
- create a waiter
- add a method to the waiter to greet a guest
- create a pizzeria
- require the waiter in the pizzeria
- make a instance of the waiter in the pizzeria
- call the greeting method
- test if it all works
- save your progress
- Create a file
waiter.rb
- Create a class in this new file. We create a class like:
class Waiter
end
- add a method
greet_guest
- the method should print a greeting
class Waiter
def greet_guest
p "Good day. Welcome to our lovely restaurant"
end
end
- create a file
pizzeria.rb
- at the top of
pizzeria.rb
addrequire './waiter'
to include the file.
A instance is when we create a object from a class. You can create a object by calling the constructor method, new
, and by default it takes no arguments.
- Create a new instance of
Waiter
and assign it to a variablew = Waiter.new
- Call a method on a object by placing it after a dot. Like
object.method
. So to call thegreet_guest
method on the object stored inw
you can callw.greet_guest
- Open the terminal
- Run the pizzeria class with ruby
ruby pizzeria.rb
- Should display:
"Good day. Welcome to our lovely restaurant"
- Open the terminal
- Add all the files in your project to git
git add .
- Commit the files to your local git
git commit -m 'greetings'
Tasks:
- Create a method for the waiter to serve_guests.
- The serve_guests method should print a list of options for the guests
- A guest should be able to choose from the options by their number.
- After a choice is made, the waiter can take action
- Call the serve_guest method from the pizzeria
- Test if it all works
- save your progress
def serve_guest
end
Add a small menu to the body of the serve_guest
method. For example
p "How can I be of service?"
p "1. Would you like to order a pizza?"
p "2. Would you like to leave?"
Call the gets
method at the bottom of the serve_guest method and cast it to a integer
choice = gets.chomp.to_i
- create a method to handle the input of the
gets
method. When we create a method that needs input from another method, you have to add this data to its arguments list.
def take_order(order_number)
end
- call the
take_order
method instead of assigning the result of gets to a variable
take_order(gets.chomp.to_i)
- if the choice is 1 or 2 or none of these, give appropriate response. To easily do this we can use a case statement. Add the following content to the take_order function.
case order_number
when 1
p "Let me get the menu"
when 2
p "Thank you for your visit"
else
p "I really don't understand"
end
- on the waiter object stored in the
w
variable, call theserve_guest
method.
w.serve_guest
- Open the terminal
- Run the pizzeria class with ruby
ruby pizzeria.rb
- Should display:
"Good day. Welcome to our lovely restaurant"`
"How can I be of service?"
"1. Would you like to order a pizza?"
"2. Would you like to leave?"
- Wait for input
- Exit
- Open the terminal
- Add all the files in your project to git
git add .
- Commit the files to your local git
git commit -m 'choices'
A menu is a combination of dishes.
Tasks:
- create a class for menu
- create a class for dish
- add a initialize method to the menu to create a array of dishes
- add a initialize method to the dish
- create a array of dishes calling its constructor with a name
- let the waiter know about the menu
- let the waiter tell guests the contents of the menu
- test your progress
- Improve the display of dishes
- test your progress
- Save your progress
- Create a file
menu.rb
- Create a class in this new file
class Menu
end
###2. create a class for dish
- Create a file
dish.rb
- Create a class in this new file
class Dish
end
###3. add a initialize method to the menu to create a array of dishes
When a object is constructed, its initialize method is called. So when you call Menu.new to create a object of the menu class, it searches for the initialize method in the Menu class.
- Add the initialize method to the Menu class
def initialize
end
- Inside the initialize method of Menu we are going create the following dishes. Margherita, Napoletana, Peperoni
###4. Add a initialize method to the dish
- To create a
Dish
with a name, you can use the initialize method again. Add a initialize method (constructor) to theDish
class that takes adish_name
as a argument.
def initialize(dish_name)
end
- Assign the argument of the constructor to a instance variable
@name
def initialize(dish_name)
@name = dish_name
end
A instance variable is available to all methods of a class instance (object). Unlike a normal variable which is only available inside the method where it was created.
###5. Create a array of dishes calling its constructor with a name
- require the file containing the dish class inside the file containing the menu class
require './dish'
- create a array inside the initialize method of the Menu class and assign it to a instance variable
@menu = []
- create instances of the dish class and add them to the variable holding the array
@menu << Dish.new("Margherita")
@menu << Dish.new("Napoletana")
@menu << Dish.new("Peperoni")
###6. let the waiter know about the menu
- require the file containing the menu in the pizzeria file.
require './menu'
- Create a instance of the menu class by calling its constructor.
menu = Menu.new
- Add a constructor method to the waiter class that takes a argument for menu.
- Assign the argument to a instance variable.
def initialize(menu)
@menu = menu
end
- Change the call to the constructor of Waiter in Pizzeria to receive a menu.
w = Waiter.new(menu)
###7. let the waiter tell guests the contents of the menu
- define a method in the
Menu
class to return the value of the instance variable.
def contents
@menu
end
- create a
list_menu
method in theWaiter
class to list all the dishes
def list_menu
@menu.contents.each do |dish|
p "#{dish}"
end
end
- call the
list_menu
method in the case statement
def take_order(order_number)
case order_number
when 1
"Let me get the menu"
list_menu
###8. test your progress
- Open the terminal
- Run the pizzeria class with ruby
ruby pizzeria.rb
- Should display:
"Good day. Welcome to our lovely restaurant"
"How can I be of service?"
"1. Would you like to order a pizza?"
"2. Would you like to leave?"
- Choose 1
- Should display:
"#<Dish:0x007ff25b058048>"
"#<Dish:0x007ff25b058160>"
"#<Dish:0x007ff25b058ae8>"
###9. Improve the display of dishes
- add a method to dish to return its name
def name
@name
end
- In the loop printing the dishes, call the
name
method to display the name
def list_menu
@menu.contents.each do |recipe|
p "#{recipe.name}"
end
end
###10. test your program
- Open the terminal
- Run the pizzeria class with ruby
ruby pizzeria.rb
- Should display:
"Good day. Welcome to our lovely restaurant"
"How can I be of service?"
"1. Would you like to order a pizza?"
"2. Would you like to leave?"
- Choose 1
- Should display:
"Margherita"
"Napoletana"
"Peperoni"
- Open the terminal
- Add all the files in your project to git
git add .
- Commit the files to your local git
git commit -m 'choices'
[04] As a waiter. I would like to be able to order a item from the kitchen. So that the guests stop bothering me
Tasks:
- add a number to a dish
- allow the ordering of food by this number
- call the order food after the menu was listed and supply the number of the dish
- add a kitchen class
- add a method to kitchen so it can receive orders of dishes
- let the waiter know about the kitchen
- let the kitchen know about the order
- test your progress
- save your progress
def list_menu
@menu.contents.each_with_index do |dish, index|
p "#{index}. #{dish.name}"
end
end
def order_food(choice)
dish = @menu.contents[ choice ]
end
this method will assign a dish object to the dish variable.
"Let me get the menu"
list_menu
order_food(gets.chomp.to_i)
- Create a file
kitchen.rb
- Create a class in this new file
class Kitchen
end
def order(dish)
p "KITCHEN: Order received for #{dish.name}"
end
- In the
pizzeria.rb
file add a require for the file containing the kitchen - Create a new instance of the
Kitchen
class and assign it to a variable
kitchen = Kitchen.new
- Add the option to
Waiter
to receive a kitchen in its initializer method. Assign this argument to a instance variable
def initialize(menu, kitchen)
@menu = menu
@kitchen = kitchen
end
- Add the variable kitchen to the initialization of the
Waiter
class.
w = Waiter.new(menu, kitchen)
- In the
order_food
method of the Waiter class add a call to the order method of the Kitchen
def order_food(choice)
dish = @menu.contents[ choice ]
@kitchen.order(dish)
end
- Open the terminal
- Run the pizzeria class with ruby
ruby pizzeria.rb
- Should display:
"Good day. Welcome to our lovely restaurant"
"How can I be of service?"
"1. Would you like to order a pizza?"
"2. Would you like to leave?"
- Choose 1
- Should display:
"0. Margherita"
"1. Napoletana"
"2. Peperoni"
- Choose 2
- Should display
"KITCHEN: Order received for Peperoni"
- Open the terminal
- Add all the files in your project to git
git add .
- Commit the files to your local git
git commit -m 'choices'
[05] As a cook. I would like to know which ingredients I have to use and which amounts. So that the dishes taste nice
Tasks:
- create a class for Ingredient
- ingredients can have a name and amount
- add constants for the ingredient names
- When creating a dish, add ingredients
- print a list of ingredients and their amount
- let the waiter know about the kitchen
- let the kitchen know about the order
- test your progress
- save your progress
- Create a file
ingredient.rb
- Create a class in this new file
def initialize(name, amount)
@name = name
@amount = amount
end
class Ingredient
TOMATO = "Tomato"
DOUGH = "Dough"
MOZZARELLA = "Mozzarella"
ANCHOVIES = "Anchovies"
PEPERONI = "Peperoni"
def initialize(name, amount)
@name = name
@amount = amount
end
end
Constants are used to prevent misspelling.
- Add a ingredients list to the initializer of the Dish class
def initialize(name, ingredients)
@name = name
@ingredients = ingredients
end
- In the menu, where the dishes are initialized, also add ingredients
@menu << Dish.new("Margherita", [
Ingredient.new(Ingredient::TOMATO, 3),
Ingredient.new(Ingredient::DOUGH, 0.25),
Ingredient.new(Ingredient::MOZZARELLA, 0.2)
])
@menu << Dish.new("Napoletana", [
Ingredient.new(Ingredient::TOMATO, 3),
Ingredient.new(Ingredient::DOUGH, 0.25),
Ingredient.new(Ingredient::MOZZARELLA, 0.2),
Ingredient.new(Ingredient::ANCHOVIES, 0.05)
])
@menu << Dish.new("Peperoni",[
Ingredient.new(Ingredient::TOMATO, 3),
Ingredient.new(Ingredient::DOUGH, 0.25),
Ingredient.new(Ingredient::MOZZARELLA, 0.2),
Ingredient.new(Ingredient::PEPERONI, 0.1)
])
- Create a method on the Dish class to return the value in the ingredients instance variable
def ingredients
@ingredients
end
- Create a method for the Ingredient class to return the value in the name instance variable and a method for the amount variable
def name
@name
end
def amount
@amount
end
- Improve the order method of the Kitchen class to print a list of ingredients for the dish
def order(dish)
p "KITCHEN: Order received for #{dish.name}"
p "Im gonna need some:"
dish.ingredients.each do |ingredient|
p "#{ingredient.amount} - #{ingredient.name}"
end
end
- Open the terminal
- Run the pizzeria class with ruby
ruby pizzeria.rb
- Should display:
"Good day. Welcome to our lovely restaurant"
"How can I be of service?"
"1. Would you like to order a pizza?"
"2. Would you like to leave?"
- Choose 1
- Should display:
"0. Margherita"
"1. Napoletana"
"2. Peperoni"
- Choose 1
- Should display
"KITCHEN: Order received for Napoletana"
"Im gonna need some:"
"3 - Tomato"
"0.25 - Dough"
"0.2 - Mozzarella"
"0.05 - Anchovies"
- Open the terminal
- Add all the files in your project to git
git add .
- Commit the files to your local git
git commit -m 'choices'
[06] As a waiter. I would like to know if a dish can still be ordered. So that I don't try sell unavailable dishes.
Add a storage and check before a order can be placed. When a dish is prepared, update the stock.
- Create a file
storage.rb
- Create a class in this new file
def initialize
@items = [
Ingredient.new(Ingredient::TOMATO, 8),
Ingredient.new(Ingredient::DOUGH, 2),
Ingredient.new(Ingredient::MOZZARELLA, 1),
Ingredient.new(Ingredient::PEPERONI, 0.3)
]
end
def use(amount)
@amount -= amount
end
- Create a fetch method that takes a list of ingredients as a argument and checks them out of the storage
def fetch(ingredients)
ingredients.each do |ingredient|
item = @items.detect{|item| item.name == ingredient.name}
item.use ingredient.amount
end
end
- require the file which is declaring the storage class in kitchen
require './storage'
class Kitchen
- add a initializer method to the kitchen and create a instance of storage
def initialize
@storage = Storage.new
end
5. Call the fetch method when a order is placed. Add it to the bottom of the order method of Kitchen
@storage.fetch(dish.ingredients)
def order_food(choice)
dish = @menu.contents[ choice ]
if @kitchen.order(dish)
p "Dish is on its way"
else
p "Sorry this dish is not available"
end
end
The kitchen has the order method which tries to fetch items from the storage. Make it return false if there is no item in the storage
def fetch(ingredients)
ingredients.each do |ingredient|
item = @items.detect{|item| item.name == ingredient.name}
if item
item.use ingredient.amount
else
return false
end
end
end
- Open the terminal
- Run the pizzeria class with ruby
ruby pizzeria.rb
- Should display:
"Good day. Welcome to our lovely restaurant"
"How can I be of service?"
"1. Would you like to order a pizza?"
"2. Would you like to leave?"
- Choose 1
- Should display:
"0. Margherita"
"1. Napoletana"
"2. Peperoni"
- Choose 1
- Should display
"KITCHEN: Order received for Napoletana"
"Im gonna need some:"
"3 - Tomato"
"0.25 - Dough"
"0.2 - Mozzarella"
"0.05 - Anchovies"
"Sorry this dish is not available"
- Open the terminal
- Add all the files in your project to git
git add .
- Commit the files to your local git
git commit -m 'choices'
[07] As a waiter. I would like to keep track of the items that a customer orders. So that I can present the bill afterwards.
- create a instance variable in the initializer and assign a empty array to it
def add(item)
@items << item
end
- require the file containing the check class in the waiter class file
- add a instance variable to the waiter initialize method
@check = Check.new
- call the add method on @check if food can be ordered
@check.add(dish)
[08] As a guest. I would like to keep ordering food until there is no stock left or I have had enough. So that I have a good time
- add a boolean to the waiter class as a instance variable
@serving
. Add it to the initializer and give it the value oftrue
- create a method for waiter which returns the value of the boolean
def serving?
return @serving
end
while(w.serving?) do
w.serve_guest
end
- in the method
take_order
of Waiter. Set @serving to false if a guest wants to leave.
- add a price to the arguments of the initializer of the dish class
- assign the price to a instance variable
- create a method to return the value of the instance variable
- in the menu class initializer, add a price for each of the three dishes
- create a method on the check class that loops over all items
- create a local variable sum for this method
- for each dish in the item loop, add the price to the sum
- return the value of sum
- let the waiter call this method and tell the value after saying "Thank you for your visit"