hungry 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +0 -1
- data/.rspec +1 -1
- data/.ruby-version +1 -0
- data/.travis.yml +19 -0
- data/Gemfile +7 -1
- data/Gemfile.lock +104 -0
- data/Rakefile +14 -0
- data/hungry.gemspec +0 -5
- data/lib/hungry.rb +20 -8
- data/lib/hungry/collection.rb +43 -9
- data/lib/hungry/collection/pagination.rb +17 -0
- data/lib/hungry/geolocation.rb +22 -2
- data/lib/hungry/location.rb +13 -8
- data/lib/hungry/menu.rb +53 -0
- data/lib/hungry/menu/category.rb +22 -0
- data/lib/hungry/menu/dish.rb +22 -0
- data/lib/hungry/menu/option.rb +9 -0
- data/lib/hungry/resource.rb +80 -12
- data/lib/hungry/response.rb +17 -0
- data/lib/hungry/review.rb +6 -6
- data/lib/hungry/site.rb +20 -6
- data/lib/hungry/tag.rb +6 -7
- data/lib/hungry/user.rb +77 -0
- data/lib/hungry/util.rb +44 -4
- data/lib/hungry/venue.rb +39 -18
- data/lib/hungry/venue/collection.rb +9 -0
- data/spec/hungry/geolocation_spec.rb +43 -43
- data/spec/hungry/util_spec.rb +18 -18
- data/spec/spec_helper.rb +0 -1
- metadata +20 -63
@@ -0,0 +1,22 @@
|
|
1
|
+
module Hungry
|
2
|
+
class Menu
|
3
|
+
class Category < Resource
|
4
|
+
|
5
|
+
attr_accessor :id, :name, :dishes, :menu
|
6
|
+
|
7
|
+
def dishes
|
8
|
+
@dishes ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def dishes=(new_dishes)
|
12
|
+
@dishes = new_dishes.map do |attributes|
|
13
|
+
dish = Menu::Dish.new(attributes)
|
14
|
+
dish.category = self
|
15
|
+
dish.data_source = data_source
|
16
|
+
dish
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Hungry
|
2
|
+
class Menu
|
3
|
+
class Dish < Resource
|
4
|
+
|
5
|
+
attr_accessor :name, :price, :description, :options, :photos, :category
|
6
|
+
|
7
|
+
def options
|
8
|
+
@options ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def options=(new_options)
|
12
|
+
@options = new_options.map do |attributes|
|
13
|
+
option = Menu::Option.new(attributes)
|
14
|
+
option.dish = self
|
15
|
+
option.data_source = data_source
|
16
|
+
option
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/hungry/resource.rb
CHANGED
@@ -1,32 +1,69 @@
|
|
1
|
-
require 'httparty'
|
1
|
+
require 'httparty' unless defined? HTTParty
|
2
2
|
|
3
3
|
module Hungry
|
4
4
|
class Resource
|
5
5
|
include HTTParty
|
6
6
|
|
7
|
-
attr_accessor :attributes
|
7
|
+
attr_accessor :attributes, :resources, :data_source
|
8
8
|
|
9
9
|
### CLASS METHODS:
|
10
10
|
|
11
11
|
def self.get(*args)
|
12
|
-
puts "[Resource]: GET #{args.map(&:inspect).join(', ')}"
|
13
12
|
self.base_uri Hungry.api_url
|
14
13
|
super
|
15
14
|
end
|
16
15
|
|
17
|
-
def self.belongs_to(resource, klass = Resource)
|
16
|
+
def self.belongs_to(resource, klass = 'Resource')
|
18
17
|
define_method resource do
|
19
|
-
|
20
|
-
|
21
|
-
klass.
|
18
|
+
@belongs_to ||= {}
|
19
|
+
@belongs_to[resource] ||= begin
|
20
|
+
klass = Kernel.const_get(klass) if klass.is_a?(String)
|
21
|
+
|
22
|
+
if attributes[resource].present?
|
23
|
+
resource = klass.new attributes[resource]
|
24
|
+
resource.data_source = data_source
|
25
|
+
resource
|
26
|
+
elsif url = resources[resource]
|
27
|
+
attributes = self.class.get url
|
28
|
+
resource = klass.new attributes
|
29
|
+
resource.data_source = url
|
30
|
+
resource
|
31
|
+
end
|
22
32
|
end
|
23
33
|
end
|
24
34
|
end
|
25
35
|
|
26
|
-
def self.has_many(resource, klass = Resource)
|
36
|
+
def self.has_many(resource, klass = 'Resource')
|
27
37
|
define_method resource do
|
28
|
-
|
29
|
-
|
38
|
+
@has_many ||= {}
|
39
|
+
@has_many[resource] ||= begin
|
40
|
+
klass = Kernel.const_get(klass) if klass.is_a?(String)
|
41
|
+
|
42
|
+
if url = resources[resource]
|
43
|
+
collection = klass.collection.from_url(url)
|
44
|
+
|
45
|
+
if attributes[resource].present?
|
46
|
+
collection.results = attributes[resource]
|
47
|
+
end
|
48
|
+
|
49
|
+
collection
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.lazy_load(*attributes)
|
56
|
+
attributes.each do |attribute|
|
57
|
+
alias_method "#{attribute}_without_lazy_load".to_sym, attribute
|
58
|
+
define_method attribute do
|
59
|
+
result = send "#{attribute}_without_lazy_load".to_sym
|
60
|
+
|
61
|
+
if !result.present? && (canonical_data_source != data_source && canonical_data_source.present?)
|
62
|
+
reload
|
63
|
+
send "#{attribute}_without_lazy_load".to_sym
|
64
|
+
else
|
65
|
+
result
|
66
|
+
end
|
30
67
|
end
|
31
68
|
end
|
32
69
|
end
|
@@ -56,13 +93,23 @@ module Hungry
|
|
56
93
|
def find(id)
|
57
94
|
raise NoEndpointSpecified unless endpoint
|
58
95
|
|
59
|
-
|
96
|
+
uri = "#{endpoint}/#{id}"
|
97
|
+
|
98
|
+
Util.log "GET: #{uri}"
|
99
|
+
response = get uri
|
60
100
|
|
61
101
|
if response.code == 200
|
62
|
-
|
102
|
+
attributes = Util.parse_json(response.body)
|
103
|
+
resource = new(attributes)
|
104
|
+
resource.data_source = uri
|
105
|
+
resource
|
63
106
|
end
|
64
107
|
end
|
65
108
|
|
109
|
+
def first(n = 1)
|
110
|
+
collection.first(n)
|
111
|
+
end
|
112
|
+
|
66
113
|
def all(criteria = {})
|
67
114
|
collection.all(criteria)
|
68
115
|
end
|
@@ -89,5 +136,26 @@ module Hungry
|
|
89
136
|
end
|
90
137
|
end
|
91
138
|
end
|
139
|
+
|
140
|
+
def canonical_data_source
|
141
|
+
resources && resources[:self]
|
142
|
+
end
|
143
|
+
|
144
|
+
def reload
|
145
|
+
resource = self.class.find id
|
146
|
+
|
147
|
+
if resource
|
148
|
+
self.data_source = resource.data_source
|
149
|
+
initialize resource.attributes
|
150
|
+
else
|
151
|
+
self.data_source = nil
|
152
|
+
initialize Hash[*attributes.keys.map { |key| [key, nil] }]
|
153
|
+
end
|
154
|
+
|
155
|
+
@has_many = {}
|
156
|
+
@belongs_to = {}
|
157
|
+
|
158
|
+
self
|
159
|
+
end
|
92
160
|
end
|
93
161
|
end
|
data/lib/hungry/review.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
-
require 'httparty'
|
2
|
-
|
3
1
|
module Hungry
|
4
2
|
class Review < Resource
|
5
3
|
|
4
|
+
### RESOURCES:
|
5
|
+
|
6
|
+
belongs_to :venue, 'Hungry::Venue'
|
7
|
+
|
8
|
+
has_many :responses, 'Hungry::Response'
|
9
|
+
|
6
10
|
### ATTRIBUTES:
|
7
11
|
|
8
12
|
### Review:
|
@@ -11,9 +15,5 @@ module Hungry
|
|
11
15
|
### Utility:
|
12
16
|
:created_at, :updated_at
|
13
17
|
|
14
|
-
### RESOURCES:
|
15
|
-
|
16
|
-
belongs_to :venue, Venue
|
17
|
-
|
18
18
|
end
|
19
19
|
end
|
data/lib/hungry/site.rb
CHANGED
@@ -3,19 +3,33 @@ module Hungry
|
|
3
3
|
|
4
4
|
self.endpoint = '/sites'
|
5
5
|
|
6
|
+
### FINDERS:
|
7
|
+
|
8
|
+
def self.with_hostname(hostname)
|
9
|
+
collection.all(hostname: hostname).first
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.for_country(country)
|
13
|
+
collection.all(country: country.id).first
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.default_site
|
17
|
+
collection.all(default: true).first
|
18
|
+
end
|
19
|
+
|
20
|
+
|
6
21
|
### ATTRIBUTES:
|
7
22
|
|
8
23
|
### Preview:
|
9
24
|
attr_accessor :id, :name, :title, :subtitle, :identifier, :default, :locale,
|
10
|
-
:url, :timezone, :country, :applications,
|
25
|
+
:url, :email, :support_email, :timezone, :country, :applications,
|
11
26
|
|
12
27
|
### Utility:
|
13
|
-
:resources,
|
28
|
+
:resources, :counters
|
14
29
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
collection.all(hostname: hostname).first
|
30
|
+
def hostname
|
31
|
+
uri = URI.parse(url) rescue nil
|
32
|
+
uri && uri.hostname
|
19
33
|
end
|
20
34
|
|
21
35
|
end
|
data/lib/hungry/tag.rb
CHANGED
@@ -3,6 +3,12 @@ module Hungry
|
|
3
3
|
|
4
4
|
self.endpoint = '/tags'
|
5
5
|
|
6
|
+
### RESOURCES:
|
7
|
+
|
8
|
+
has_many :venues, 'Hungry::Venue'
|
9
|
+
|
10
|
+
has_many :tags, 'Hungry::Tag'
|
11
|
+
|
6
12
|
### ATTRIBUTES:
|
7
13
|
|
8
14
|
### Tag:
|
@@ -10,12 +16,5 @@ module Hungry
|
|
10
16
|
|
11
17
|
### Utility:
|
12
18
|
:resources, :counters
|
13
|
-
|
14
|
-
### RESOURCES:
|
15
|
-
|
16
|
-
has_many :venues, Venue
|
17
|
-
|
18
|
-
has_many :tags, Tag
|
19
|
-
|
20
19
|
end
|
21
20
|
end
|
data/lib/hungry/user.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
module Hungry
|
2
|
+
class User < Resource
|
3
|
+
|
4
|
+
self.endpoint = '/users'
|
5
|
+
|
6
|
+
### ASSOCIATIONS:
|
7
|
+
|
8
|
+
has_many :reviews, 'Hungry::Review'
|
9
|
+
|
10
|
+
### FINDERS:
|
11
|
+
|
12
|
+
def self.with_ip(ip_address)
|
13
|
+
collection.all(ip: ip_address)
|
14
|
+
end
|
15
|
+
|
16
|
+
### CLASS METHODS:
|
17
|
+
|
18
|
+
def self.authenticate_with_persistence_token(persistence_token)
|
19
|
+
result = authenticate_via_api 'Cookie' => "persistence_token=#{persistence_token}"
|
20
|
+
return false unless result.present?
|
21
|
+
|
22
|
+
from_json(result)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.authenticate_with_perishable_token(perishable_token)
|
26
|
+
result = authenticate_via_api query: "perishable_token=#{perishable_token}"
|
27
|
+
return false unless result.present?
|
28
|
+
|
29
|
+
from_json(result)
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.from_json(json)
|
33
|
+
new Util.parse_json(json)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.authenticate_via_api(options = {})
|
37
|
+
options = {
|
38
|
+
path: '/account.json',
|
39
|
+
query: nil
|
40
|
+
}.merge(options)
|
41
|
+
|
42
|
+
url = URI.parse(Hungry.api_url)
|
43
|
+
url.path = options.delete(:path)
|
44
|
+
url.query = options.delete(:query)
|
45
|
+
|
46
|
+
http = Net::HTTP.new(url.host, url.port)
|
47
|
+
if url.scheme == 'https'
|
48
|
+
http.use_ssl = true
|
49
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
50
|
+
end
|
51
|
+
|
52
|
+
request = Net::HTTP::Get.new(url.request_uri, options)
|
53
|
+
response = http.request request
|
54
|
+
|
55
|
+
if response.code.to_i == 200
|
56
|
+
response.body
|
57
|
+
else
|
58
|
+
false
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
### ATTRIBUTES:
|
63
|
+
|
64
|
+
### Preview:
|
65
|
+
attr_accessor :id, :name, :avatar, :slug, :profile_url, :score, :bio,
|
66
|
+
:location, :email,
|
67
|
+
|
68
|
+
### FULL:
|
69
|
+
:gender, :birth_date, :website_url, :persistence_token,
|
70
|
+
:single_access_token, :maintainer_of, :connections,
|
71
|
+
:device_tokens, :admin,
|
72
|
+
|
73
|
+
### Utility:
|
74
|
+
:resources, :counters, :created_at, :updated_at, :activated_at
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
data/lib/hungry/util.rb
CHANGED
@@ -1,13 +1,23 @@
|
|
1
|
-
require 'cgi'
|
2
|
-
require 'rack/utils'
|
1
|
+
require 'cgi' unless defined?(CGI)
|
3
2
|
|
4
3
|
module Hungry
|
5
4
|
module Util
|
6
5
|
extend self
|
7
6
|
|
7
|
+
def log(message, type = :info)
|
8
|
+
if Hungry.logger
|
9
|
+
message = "[Hungry] #{message}"
|
10
|
+
Hungry.logger.send(type, message)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def parse_json(json)
|
15
|
+
Hungry.json_parser.call(json)
|
16
|
+
end
|
17
|
+
|
8
18
|
def params_from_uri(uri)
|
9
19
|
uri = URI.parse(uri) unless uri.is_a?(URI)
|
10
|
-
|
20
|
+
parse_query(uri.query) if uri.query.present?
|
11
21
|
end
|
12
22
|
|
13
23
|
def uri_with_params(uri, params = {})
|
@@ -20,7 +30,37 @@ module Hungry
|
|
20
30
|
end
|
21
31
|
|
22
32
|
def is_numeric?(value)
|
23
|
-
value.to_s =~ /^[+-]?[\d]+(\.[\d]+){0,1}$/
|
33
|
+
!!(value.to_s =~ /^[+-]?[\d]+(\.[\d]+){0,1}$/)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# Copied from rack/utils:
|
39
|
+
def unescape(s, encoding = Encoding::UTF_8)
|
40
|
+
URI.decode_www_form_component(s, encoding)
|
41
|
+
end
|
42
|
+
|
43
|
+
def parse_query(qs, d = nil, &unescaper)
|
44
|
+
unescaper ||= method(:unescape)
|
45
|
+
|
46
|
+
params = {}
|
47
|
+
|
48
|
+
(qs || '').split(d ? /[#{d}] */ : /[&;] */n).each do |p|
|
49
|
+
next if p.empty?
|
50
|
+
k, v = p.split('=', 2).map(&unescaper)
|
51
|
+
|
52
|
+
if cur = params[k]
|
53
|
+
if cur.class == Array
|
54
|
+
params[k] << v
|
55
|
+
else
|
56
|
+
params[k] = [cur, v]
|
57
|
+
end
|
58
|
+
else
|
59
|
+
params[k] = v
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
params
|
24
64
|
end
|
25
65
|
end
|
26
66
|
end
|
data/lib/hungry/venue.rb
CHANGED
@@ -6,27 +6,13 @@ module Hungry
|
|
6
6
|
|
7
7
|
### RESOURCES:
|
8
8
|
|
9
|
-
has_many :reviews, Review
|
9
|
+
has_many :reviews, 'Hungry::Review'
|
10
10
|
|
11
|
-
belongs_to :country, Country
|
11
|
+
belongs_to :country, 'Hungry::Country'
|
12
12
|
|
13
|
-
belongs_to :region, Region
|
13
|
+
belongs_to :region, 'Hungry::Region'
|
14
14
|
|
15
|
-
belongs_to :city, City
|
16
|
-
|
17
|
-
### ATTRIBUTES:
|
18
|
-
|
19
|
-
### Preview:
|
20
|
-
attr_accessor :id, :name, :category, :telephone, :fax, :website_url,
|
21
|
-
:tagline, :rating, :url, :address, :geolocation, :relevance,
|
22
|
-
:distance, :plan,
|
23
|
-
|
24
|
-
### Full:
|
25
|
-
:reachability, :staff, :prices, :capacity, :description,
|
26
|
-
:tags, :menus, :images, :maintainers, :awards, :opening_hours,
|
27
|
-
|
28
|
-
### Utility:
|
29
|
-
:resources, :counters, :created_at, :updated_at
|
15
|
+
belongs_to :city, 'Hungry::City'
|
30
16
|
|
31
17
|
### FINDERS:
|
32
18
|
|
@@ -50,8 +36,43 @@ module Hungry
|
|
50
36
|
collection.sort_by(sortable)
|
51
37
|
end
|
52
38
|
|
39
|
+
def self.maintainable_by(user_or_id)
|
40
|
+
collection.maintainable_by(user_or_id)
|
41
|
+
end
|
42
|
+
|
53
43
|
def self.paginate(page, options = {})
|
54
44
|
collection.paginate(page, options)
|
55
45
|
end
|
46
|
+
|
47
|
+
### ATTRIBUTES:
|
48
|
+
|
49
|
+
### Preview:
|
50
|
+
attr_accessor :id, :name, :category, :telephone, :fax, :website_url,
|
51
|
+
:tagline, :rating, :url, :address, :geolocation,
|
52
|
+
:currency_symbol, :relevance, :distance, :plan,
|
53
|
+
|
54
|
+
### Full:
|
55
|
+
:reachability, :staff, :prices, :capacity, :description,
|
56
|
+
:tags, :menus, :images, :maintainers, :awards, :opening_hours,
|
57
|
+
:holidays,
|
58
|
+
|
59
|
+
### Utility:
|
60
|
+
:counters, :created_at, :updated_at, :status
|
61
|
+
|
62
|
+
lazy_load :tags, :menus, :maintainers, :opening_hours, :holidays
|
63
|
+
|
64
|
+
def geolocation=(new_coordinates)
|
65
|
+
@geolocation = Geolocation.parse(new_coordinates).tap do |geo|
|
66
|
+
attributes[:geolocation] = geo
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def menus=(new_menus)
|
71
|
+
@menus = new_menus.map do |attributes|
|
72
|
+
menu = Menu.new(attributes)
|
73
|
+
menu.data_source = data_source
|
74
|
+
menu
|
75
|
+
end
|
76
|
+
end
|
56
77
|
end
|
57
78
|
end
|