Skip to content

Instantly share code, notes, and snippets.

@arthur-littm
Created October 19, 2020 17:07
Show Gist options
  • Save arthur-littm/6d52e3f84d9831ab028def0646fdbed9 to your computer and use it in GitHub Desktop.
Save arthur-littm/6d52e3f84d9831ab028def0646fdbed9 to your computer and use it in GitHub Desktop.
require_relative 'cookbook' # You need to create this file!
require_relative 'controller' # You need to create this file!
require_relative 'router'
csv_file = File.join(__dir__, 'recipes.csv')
cookbook = Cookbook.new(csv_file)
controller = Controller.new(cookbook)
router = Router.new(controller)
# Start the app
router.run
require 'open-uri'
require 'nokogiri'
require_relative 'recipe'
require_relative 'view'
class Controller
def initialize(cookbook)
@view = View.new
@cookbook = cookbook
end
def create
# ask user for recipe info
name = @view.ask_user_for_recipe('name')
description = @view.ask_user_for_recipe('description')
prep_time = @view.ask_user_for_recipe('prep time')
# create a recipe
new_recipe = Recipe.new(name, description, prep_time)
#store new recipe in cookbook
@cookbook.add_recipe(new_recipe)
end
def list
# ask cookbook for all recipes
all_recipes = @cookbook.all
# give the recipes to the view to display
@view.list_recipes(all_recipes)
end
def destroy
# ask user which recipe to destroy
index = @view.which_recipe_to_delete
# ask the cookbook to remove that recipe from the list
@cookbook.delete_recipe(index)
end
def import_from_web
# PSEUDO CODE
# 1. ask the user for a keyword to search
keyword = @view.ask_for_keyword
# 2. display the results in a list with numbers
# 2a. Open the web page and parse the page with Nokogiri
url = "https://www.allrecipes.com/search/results/?wt=#{keyword}"
html_file = open(url).read
html_doc = Nokogiri::HTML(html_file)
array_of_recipe_instances = []
html_doc.search('.fixed-recipe-card').first(5).each do |element|
name = element.search('.fixed-recipe-card__h3').text.strip
description = element.search('.fixed-recipe-card__description').text.strip
next_url = element.search('a').attribute('href').value
new_html_file = open(next_url).read
new_html_doc = Nokogiri::HTML(new_html_file)
prep_time = new_html_doc.search('.recipe-meta-item .recipe-meta-item-body').first.text.strip
# get the link of each recipe page
# open that page
# on that page search for prep time
array_of_recipe_instances << Recipe.new(name, description, prep_time)
end
# 2b. Inspect the website to understand what CLASSES we will look for
# 2c. Put the results in an array
# 2d. display the results
# -> array to the view
@view.list_recipes(array_of_recipe_instances)
# 3. Ask the user which one they would like to import
# -> Asking for a number!
index = @view.ask_for_index
recipe = array_of_recipe_instances[index]
# 4. Save the recipe into the cookbook (and the csv)
@cookbook.add_recipe(recipe)
end
end
require 'csv'
class Cookbook
def initialize(csv_file_path)
@csv_file_path = csv_file_path
@recipes = [] # An array of `Recipe` instances
CSV.foreach(csv_file_path) do |row|
@recipes << Recipe.new(row[0], row[1], row[2])
end
end
def add_recipe(recipe)
@recipes << recipe
save_csv
end
def all
@recipes
end
def delete_recipe(index)
@recipes.delete_at(index)
save_csv
end
private
def save_csv
CSV.open(@csv_file_path, 'wb') do |csv_file|
@recipes.each do |recipe|
csv_file << [recipe.name, recipe.description, recipe.prep_time]
end
end
end
end
class Recipe
# STATE:
# name + description (both are strings)
attr_reader :name, :description, :prep_time
def initialize(name, description, prep_time)
@name = name
@description = description
@prep_time = prep_time
end
# def name
# @name
# end
# def description
# @description
# end
end
# pesto_pasta = Recipe.new('Pesto Pasta', 'Delicious pasta')
# puts "Recipe name: #{pesto_pasta.name} Recipe description: #{pesto_pasta.description}"
pasta good 1hr
class Router
def initialize(controller)
@controller = controller
@running = true
end
def run
puts "Welcome to the Cookbook!"
puts " -- "
while @running
display_tasks
action = gets.chomp.to_i
print `clear`
route_action(action)
end
end
private
def route_action(action)
case action
when 1 then @controller.list
when 2 then @controller.create
when 3 then @controller.destroy
when 4 then @controller.import_from_web
when 5 then stop
else
puts "Please press 1, 2, 3 or 4"
end
end
def stop
@running = false
end
def display_tasks
puts ""
puts "What do you want to do next?"
puts "1 - List all recipes"
puts "2 - Create a new recipe"
puts "3 - Destroy a recipe"
puts "4 - Import from the web"
puts "5 - Stop and exit the program"
end
end
class View
def ask_user_for_recipe(attribute)
puts "What is the #{attribute} of your recipe?"
print '> '
return gets.chomp
end
def list_recipes(recipes) # <- array of `Recipe` instances!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
recipes.each_with_index do |recipe, index|
puts "#{index + 1}. #{recipe.name} : #{recipe.description} (#{recipe.prep_time})"
end
end
def which_recipe_to_delete
puts 'Which recipe number would you like to delete?'
print '> '
return gets.chomp.to_i - 1 # remember to subtract one. Recipe number 1
# is really recipe at index 0 in our cookbook!
end
def ask_for_keyword
puts "What's the keyword?"
return gets.chomp
end
def ask_for_index
puts "What's the index?"
return gets.chomp.to_i - 1
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment