whats-for-dinner 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/bin/whats-for-dinner +12 -0
- data/lib/category.rb +37 -0
- data/lib/category_list.rb +13721 -0
- data/lib/command_line_interface.rb +114 -0
- data/lib/restaurant.rb +33 -0
- data/lib/user.rb +17 -0
- data/lib/whats_for_dinner.rb +51 -0
- data/lib/yelp_client.rb +18 -0
- metadata +53 -0
@@ -0,0 +1,114 @@
|
|
1
|
+
class CommandLineInterface
|
2
|
+
|
3
|
+
CATEGORIES = Category.get_category_list
|
4
|
+
|
5
|
+
def run
|
6
|
+
location = get_location
|
7
|
+
users = get_users
|
8
|
+
whats_for_dinner = WhatsForDinner.new(location, users)
|
9
|
+
loop do
|
10
|
+
restaurant = whats_for_dinner.ask
|
11
|
+
make_recommendation(restaurant)
|
12
|
+
break if yes?("Sound good?")
|
13
|
+
end
|
14
|
+
puts "Great! Thanks for using What's For Dinner?, powered by Yelp."
|
15
|
+
end
|
16
|
+
|
17
|
+
def get_location
|
18
|
+
puts "Hi! Where do you want to have dinner tonight?"
|
19
|
+
location = gets.strip
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_users
|
23
|
+
users = []
|
24
|
+
loop do
|
25
|
+
puts "What's your name?"
|
26
|
+
name = gets.strip
|
27
|
+
puts "What are you in the mood for today?"
|
28
|
+
likes = get_preferences(gets)
|
29
|
+
puts "What don't you want to eat?"
|
30
|
+
dislikes = get_preferences(gets)
|
31
|
+
user = User.new(name, likes, dislikes)
|
32
|
+
users << user
|
33
|
+
break unless yes?("Is anyone else joining you?")
|
34
|
+
end
|
35
|
+
users
|
36
|
+
end
|
37
|
+
|
38
|
+
def make_recommendation(restaurant)
|
39
|
+
puts "How about?"
|
40
|
+
puts ""
|
41
|
+
puts restaurant.name
|
42
|
+
puts "#{restaurant.rating} star rating, #{restaurant.review_count} reviews"
|
43
|
+
puts restaurant.categories.map{|category| category.title}.join(", ")
|
44
|
+
puts ""
|
45
|
+
puts restaurant.display_address
|
46
|
+
puts restaurant.display_phone
|
47
|
+
puts ""
|
48
|
+
puts "\"#{restaurant.snippet_text}\""
|
49
|
+
puts ""
|
50
|
+
end
|
51
|
+
|
52
|
+
def get_preferences(input)
|
53
|
+
validated_categories = []
|
54
|
+
if input.strip == ""
|
55
|
+
validated_categories
|
56
|
+
else
|
57
|
+
user_categories = input
|
58
|
+
.split(/[,][ ]*/)
|
59
|
+
.select {|string| !string.include? ","}
|
60
|
+
.map {|string| string.strip}
|
61
|
+
user_categories.each do |user_category|
|
62
|
+
if CATEGORIES.map{|category| category.title.downcase}.include? user_category.downcase
|
63
|
+
validated_categories << user_category.downcase
|
64
|
+
else
|
65
|
+
suggested_categories = suggested_categories(user_category).map{|category| category.title}
|
66
|
+
formatted_categories = format_categories(suggested_categories)
|
67
|
+
puts "I'm sorry, I didn't understand \"#{user_category}\". Did you mean #{formatted_categories}?"
|
68
|
+
recover_category = gets
|
69
|
+
.split(/[,][ ]*/)
|
70
|
+
.select {|string| !string.include? ","}
|
71
|
+
.first
|
72
|
+
get_preferences(recover_category).each {|category| validated_categories << category}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
validated_categories.uniq
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def suggested_categories(input, categories = CATEGORIES, characters = 0)
|
80
|
+
suggestions = categories
|
81
|
+
.select {|category| category.title.downcase[0, characters] == input.downcase[0, characters]}
|
82
|
+
.compact
|
83
|
+
if suggestions.empty? || suggested_categories(input, suggestions, characters + 1).empty?
|
84
|
+
suggestions
|
85
|
+
else
|
86
|
+
suggested_categories(input, suggestions, characters + 1)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def format_categories(array, string = "")
|
91
|
+
head = "\"" + array[0].split.map{|word| word.capitalize}.join(" ") + "\""
|
92
|
+
tail = array[1..-1]
|
93
|
+
if tail.empty?
|
94
|
+
string == ""? head : string + ", or " + head
|
95
|
+
else
|
96
|
+
string = string == ""? head : string + ", " + head
|
97
|
+
format_categories(tail, string)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def yes?(prompt)
|
102
|
+
puts prompt
|
103
|
+
case gets.strip.downcase
|
104
|
+
when "yes"
|
105
|
+
true
|
106
|
+
when "no"
|
107
|
+
false
|
108
|
+
else
|
109
|
+
puts "I'm sorry, I didn't understand you. Please say \"Yes\" or \"No\"."
|
110
|
+
yes?(prompt)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
data/lib/restaurant.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
class Restaurant
|
2
|
+
attr_accessor :id, :is_claimed, :is_closed, :name, :image_url, :url, :mobile_url, :phone, :display_phone, :review_count, :categories, :distance, :rating, :rating_img_url, :rating_img_url_small, :rating_img_url_large, :snippet_text, :snippet_image_url, :address, :display_address, :city, :state_code, :postal_code, :country_code, :cross_streets, :neighborhoods, :latitude, :longitude, :menu_provider, :menu_date_updated, :reservation_url, :eat24_url
|
3
|
+
|
4
|
+
@@all = []
|
5
|
+
|
6
|
+
def initialize(restaurant)
|
7
|
+
location = restaurant.location
|
8
|
+
coordinate = location.coordinate
|
9
|
+
[restaurant, location, coordinate].each do |instance|
|
10
|
+
instance.instance_variables.each do |variable|
|
11
|
+
instance_has = instance.instance_variable_defined?(variable)
|
12
|
+
self_has = self.instance_variables.find(variable)
|
13
|
+
if instance_has && self_has
|
14
|
+
if variable.to_s == "@categories"
|
15
|
+
categories = instance.categories
|
16
|
+
.map {|category| Category.find_by_title(category[0])}
|
17
|
+
.compact
|
18
|
+
@categories = categories
|
19
|
+
categories.each {|category| category.restaurants << self}
|
20
|
+
else
|
21
|
+
self.instance_variable_set(variable, instance.instance_variable_get(variable))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
@@all << self
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.all
|
30
|
+
@@all
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/lib/user.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class User
|
2
|
+
attr_accessor :name, :likes, :dislikes
|
3
|
+
|
4
|
+
@@all = []
|
5
|
+
|
6
|
+
def initialize(name, likes, dislikes)
|
7
|
+
@name = name
|
8
|
+
@likes = likes.map {|title| Category.find_by_title(title)}
|
9
|
+
@dislikes = dislikes.map {|title| Category.find_by_title(title)}
|
10
|
+
@@all << self
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.all
|
14
|
+
@@all
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class WhatsForDinner
|
2
|
+
attr_accessor :location, :users, :yelp_client, :categories, :preferred_categories, :restaurants
|
3
|
+
|
4
|
+
def initialize(location, users)
|
5
|
+
@location = location
|
6
|
+
@users = users
|
7
|
+
@yelp_client = YelpClient.new
|
8
|
+
@categories = Category.all
|
9
|
+
@preferred_categories = []
|
10
|
+
@restaurants = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def ask
|
14
|
+
if self.restaurants.empty?
|
15
|
+
category_filters = get_category_filters
|
16
|
+
self.categories = self.categories - self.preferred_categories
|
17
|
+
params = {category_filter: category_filters}
|
18
|
+
results = yelp_client.search(location, params)
|
19
|
+
self.restaurants = results.map{|result| Restaurant.new(result)}
|
20
|
+
if self.restaurants.empty?
|
21
|
+
ask
|
22
|
+
else
|
23
|
+
recommendation = self.restaurants.first
|
24
|
+
self.restaurants = self.restaurants[1..-1]
|
25
|
+
recommendation
|
26
|
+
end
|
27
|
+
else
|
28
|
+
recommendation = self.restaurants.first
|
29
|
+
self.restaurants = self.restaurants[1..-1]
|
30
|
+
recommendation
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_category_filters
|
35
|
+
categories_with_votes = self.categories.map{|category| [category, 0]}.to_h
|
36
|
+
users.each do |user|
|
37
|
+
user.likes.each do |category|
|
38
|
+
categories_with_votes[category] += 1 if categories_with_votes.has_key?(category)
|
39
|
+
end
|
40
|
+
user.dislikes.each do |category|
|
41
|
+
categories_with_votes[category] -= 100 if categories_with_votes.has_key?(category)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
max_votes = categories_with_votes.values.max
|
45
|
+
self.preferred_categories = categories_with_votes
|
46
|
+
.select {|category, votes| votes == max_votes}
|
47
|
+
.keys
|
48
|
+
self.preferred_categories.map {|category| category.filter}.join(",")
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/yelp_client.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class YelpClient
|
2
|
+
attr_accessor :client
|
3
|
+
|
4
|
+
def initialize
|
5
|
+
@client = Yelp::Client.new
|
6
|
+
client.configure do |config|
|
7
|
+
config.consumer_key = "iet5BTns6urx8_MPMSN9lg"
|
8
|
+
config.consumer_secret = "LUwtv6MjjikYbt7BrHUxJV6oJ0E"
|
9
|
+
config.token = "K3EIm60p2YqhX5H5DOyZoqfFJua3TGCS"
|
10
|
+
config.token_secret = "oVvc-K6pQR31nGvujojMjty07hY"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def search(location, params = {}, locale = {})
|
15
|
+
client.search(location, params, locale).businesses
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
metadata
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: whats-for-dinner
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Adam Fraser
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-09 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A simple gem to help groups find restaurants that optimize their collective
|
14
|
+
preferences.
|
15
|
+
email: adam.fraser@gmail.com
|
16
|
+
executables:
|
17
|
+
- whats-for-dinner
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- bin/whats-for-dinner
|
22
|
+
- lib/category.rb
|
23
|
+
- lib/category_list.rb
|
24
|
+
- lib/command_line_interface.rb
|
25
|
+
- lib/restaurant.rb
|
26
|
+
- lib/user.rb
|
27
|
+
- lib/whats_for_dinner.rb
|
28
|
+
- lib/yelp_client.rb
|
29
|
+
homepage: https://github.com/adamgfraser/whats-for-dinner
|
30
|
+
licenses:
|
31
|
+
- None
|
32
|
+
metadata: {}
|
33
|
+
post_install_message:
|
34
|
+
rdoc_options: []
|
35
|
+
require_paths:
|
36
|
+
- lib
|
37
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
requirements: []
|
48
|
+
rubyforge_project:
|
49
|
+
rubygems_version: 2.4.5.1
|
50
|
+
signing_key:
|
51
|
+
specification_version: 4
|
52
|
+
summary: What's For Dinner?
|
53
|
+
test_files: []
|