hungry 0.0.1
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.
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/Gemfile +13 -0
- data/Guardfile +11 -0
- data/Rakefile +1 -0
- data/hungry.gemspec +26 -0
- data/lib/hungry.rb +37 -0
- data/lib/hungry/city.rb +7 -0
- data/lib/hungry/collection.rb +65 -0
- data/lib/hungry/collection/pagination.rb +71 -0
- data/lib/hungry/country.rb +7 -0
- data/lib/hungry/geolocation.rb +63 -0
- data/lib/hungry/location.rb +23 -0
- data/lib/hungry/region.rb +7 -0
- data/lib/hungry/resource.rb +93 -0
- data/lib/hungry/review.rb +19 -0
- data/lib/hungry/site.rb +22 -0
- data/lib/hungry/tag.rb +21 -0
- data/lib/hungry/util.rb +26 -0
- data/lib/hungry/venue.rb +57 -0
- data/lib/hungry/venue/collection.rb +37 -0
- data/lib/support/presence.rb +20 -0
- data/lib/support/symbolize_keys.rb +16 -0
- data/spec/hungry/geolocation_spec.rb +122 -0
- data/spec/hungry/util_spec.rb +54 -0
- data/spec/spec_helper.rb +9 -0
- metadata +138 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
require 'rb-readline'
|
|
2
|
+
|
|
3
|
+
guard 'bundler' do
|
|
4
|
+
watch('Gemfile')
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
guard 'rspec', version: 2, cli: '--format Fuubar --colour' do
|
|
8
|
+
watch(%r{^spec/.+_spec\.rb})
|
|
9
|
+
watch(%r{^lib/(.+)\.rb}) { |m| "spec/#{m[1]}_spec.rb" }
|
|
10
|
+
watch('spec/spec_helper.rb') { "spec" }
|
|
11
|
+
end
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/hungry.gemspec
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
|
3
|
+
require 'hungry'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'hungry'
|
|
7
|
+
s.version = Hungry::VERSION
|
|
8
|
+
s.authors = ['Tom-Eric Gerritsen']
|
|
9
|
+
s.email = ['tomeric@eet.nu']
|
|
10
|
+
s.homepage = 'http://github.com/eet-nu/hungry'
|
|
11
|
+
s.summary = %q{An interface to the Eet.nu API.}
|
|
12
|
+
s.description = %q{An interface to the Eet.nu API.}
|
|
13
|
+
|
|
14
|
+
s.files = `git ls-files`.split("\n")
|
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
17
|
+
s.require_paths = ['lib']
|
|
18
|
+
|
|
19
|
+
# specify any dependencies here:
|
|
20
|
+
s.add_dependency 'httparty'
|
|
21
|
+
s.add_dependency 'rack'
|
|
22
|
+
|
|
23
|
+
# specify any development dependencies here:
|
|
24
|
+
s.add_development_dependency 'rspec'
|
|
25
|
+
s.add_development_dependency 'fakeweb'
|
|
26
|
+
end
|
data/lib/hungry.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
$LOAD_PATH << File.expand_path('..', __FILE__)
|
|
2
|
+
|
|
3
|
+
require 'support/presence'
|
|
4
|
+
require 'support/symbolize_keys'
|
|
5
|
+
|
|
6
|
+
module Hungry
|
|
7
|
+
VERSION = '0.0.1'
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
attr_accessor :api_url
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
self.api_url = 'http://api.eet.nu/'
|
|
14
|
+
|
|
15
|
+
### LIBRARY:
|
|
16
|
+
|
|
17
|
+
autoload :City, 'hungry/city'
|
|
18
|
+
autoload :Collection, 'hungry/collection'
|
|
19
|
+
autoload :Country, 'hungry/country'
|
|
20
|
+
autoload :Geolocation, 'hungry/geolocation'
|
|
21
|
+
autoload :Location, 'hungry/location'
|
|
22
|
+
autoload :Region, 'hungry/region'
|
|
23
|
+
autoload :Resource, 'hungry/resource'
|
|
24
|
+
autoload :Review, 'hungry/review'
|
|
25
|
+
autoload :Site, 'hungry/site'
|
|
26
|
+
autoload :Tag, 'hungry/tag'
|
|
27
|
+
autoload :Util, 'hungry/util'
|
|
28
|
+
autoload :Venue, 'hungry/venue'
|
|
29
|
+
|
|
30
|
+
### EXCEPTIONS:
|
|
31
|
+
|
|
32
|
+
# Exception raised when a geolocation is required, but it is not given:
|
|
33
|
+
class GeolocationNotGiven < StandardError; end
|
|
34
|
+
|
|
35
|
+
# Exception raised when an endpoint is not specified for a resource:
|
|
36
|
+
class EndpointNotSpecified < StandardError; end
|
|
37
|
+
end
|
data/lib/hungry/city.rb
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
require 'httparty'
|
|
2
|
+
require 'cgi'
|
|
3
|
+
|
|
4
|
+
module Hungry
|
|
5
|
+
class Collection
|
|
6
|
+
include Enumerable
|
|
7
|
+
include HTTParty
|
|
8
|
+
|
|
9
|
+
autoload :Pagination, 'hungry/collection/pagination'
|
|
10
|
+
|
|
11
|
+
attr_reader :klass, :endpoint, :criteria
|
|
12
|
+
|
|
13
|
+
### CLASS METHODS:
|
|
14
|
+
|
|
15
|
+
def self.get(*args)
|
|
16
|
+
puts "[Collection]: GET #{args.map(&:inspect).join(', ')}"
|
|
17
|
+
self.base_uri Hungry.api_url
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
### INSTANCE METHODS:
|
|
22
|
+
|
|
23
|
+
def initialize(klass, endpoint, criteria = {})
|
|
24
|
+
@klass = klass
|
|
25
|
+
@endpoint = endpoint
|
|
26
|
+
@criteria = criteria.symbolize_keys
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def from_url(url)
|
|
30
|
+
uri = URI.parse(url)
|
|
31
|
+
options = Util.params_from_uri(uri) || klass.default_criteria
|
|
32
|
+
|
|
33
|
+
self.class.new(klass, uri.path, options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def all(new_criteria = {})
|
|
37
|
+
self.class.new(klass, endpoint, criteria.merge(new_criteria))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def count(*args)
|
|
41
|
+
if args.present?
|
|
42
|
+
super
|
|
43
|
+
else
|
|
44
|
+
response['results'].count
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def each(&block)
|
|
49
|
+
response['results'].each do |result|
|
|
50
|
+
yield klass.new(result)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def response
|
|
57
|
+
raise NoEndpointSpecified unless endpoint
|
|
58
|
+
|
|
59
|
+
@response ||= begin
|
|
60
|
+
uri = Util.uri_with_params(endpoint, criteria)
|
|
61
|
+
self.class.get uri
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Hungry
|
|
2
|
+
class Collection
|
|
3
|
+
module Pagination
|
|
4
|
+
class NotPaginatedError < StandardError; end
|
|
5
|
+
|
|
6
|
+
def paginate(page, options = {})
|
|
7
|
+
all options.merge(page: page)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def paginated?
|
|
11
|
+
pagination.present?
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def per_page
|
|
15
|
+
if paginated?
|
|
16
|
+
pagination['per_page'].to_i
|
|
17
|
+
else
|
|
18
|
+
response['results'].length
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def total_entries
|
|
23
|
+
if paginated?
|
|
24
|
+
pagination['total_entries'].to_i
|
|
25
|
+
else
|
|
26
|
+
response['results'].length
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def total_pages
|
|
31
|
+
if paginated?
|
|
32
|
+
pagination['total_pages'].to_i
|
|
33
|
+
else
|
|
34
|
+
1
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def current_page
|
|
39
|
+
if paginated?
|
|
40
|
+
pagination['current_page'].to_i
|
|
41
|
+
else
|
|
42
|
+
1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def previous_page
|
|
47
|
+
current_page - 1 if paginated? && current_page > 1
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def next_page
|
|
51
|
+
current_page + 1 if paginated? && current_page < total_pages
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def previous
|
|
55
|
+
raise NotPaginatedError unless paginated?
|
|
56
|
+
all page: previous_page if previous_page
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def next
|
|
60
|
+
raise NotPaginatedError unless paginated?
|
|
61
|
+
all page: next_page if next_page
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def pagination
|
|
67
|
+
response['pagination']
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
module Hungry
|
|
2
|
+
class Geolocation
|
|
3
|
+
attr_accessor :latitude, :longitude
|
|
4
|
+
|
|
5
|
+
def self.parse(input)
|
|
6
|
+
# input is already a Geolocation, so we can return it early:
|
|
7
|
+
return input if input.is_a?(self)
|
|
8
|
+
|
|
9
|
+
if input.respond_to?(:geolocation)
|
|
10
|
+
# input has a geolocation attribute, so try to use that one first:
|
|
11
|
+
geolocation = parse(input.geolocation)
|
|
12
|
+
return geolocation if geolocation
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
coordinates = []
|
|
16
|
+
|
|
17
|
+
if input.respond_to?(:latitude) && input.respond_to?(:longitude)
|
|
18
|
+
# input has latitude and longitude attributes, so use those:
|
|
19
|
+
coordinates = [input.latitude, input.longitude]
|
|
20
|
+
|
|
21
|
+
elsif input.respond_to?(:lat) && input.respond_to?(:lng)
|
|
22
|
+
# input has lat and lng attributes, so use those:
|
|
23
|
+
coordinates = [input.lat, input.lng]
|
|
24
|
+
|
|
25
|
+
elsif input.respond_to?(:match)
|
|
26
|
+
# Example: "50.8469397,5.6927505"
|
|
27
|
+
#
|
|
28
|
+
# input is a String, so we can use a regular expression to extract
|
|
29
|
+
# latitude and longitude:
|
|
30
|
+
if match = input.match(/^(?<latitude>[0-9\.]+),\s?(?<longitude>[0-9\.]+)$/)
|
|
31
|
+
coordinates = [match[:latitude], match[:longitude]]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
elsif input.respond_to?(:keys)
|
|
35
|
+
# Example: { latitude: 50.8469397, longitude: 5.6927505 }
|
|
36
|
+
#
|
|
37
|
+
# input is a Hash, so we can extract values with the keys:
|
|
38
|
+
coordinates = [input[:latitude] || input[:lat], input[:longitude] || input[:lng]]
|
|
39
|
+
|
|
40
|
+
elsif input.respond_to?(:[])
|
|
41
|
+
# Example: [50.8469397, 5.6927505]
|
|
42
|
+
#
|
|
43
|
+
# input is an Array, so we need the first and second value:
|
|
44
|
+
coordinates = input[0], input[1]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
coordinates = coordinates.map(&:presence).compact
|
|
48
|
+
|
|
49
|
+
if coordinates.length == 2 && coordinates.all? { |coordinate| Util.is_numeric?(coordinate) }
|
|
50
|
+
new(*coordinates)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def initialize(latitude, longitude)
|
|
55
|
+
self.latitude = latitude.to_f
|
|
56
|
+
self.longitude = longitude.to_f
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def to_s
|
|
60
|
+
[latitude, longitude].join(',')
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module Hungry
|
|
2
|
+
class Location < Resource
|
|
3
|
+
|
|
4
|
+
self.endpoint = '/locations'
|
|
5
|
+
|
|
6
|
+
### ATTRIBUTES:
|
|
7
|
+
|
|
8
|
+
### Location:
|
|
9
|
+
attr_accessor :id, :name, :type, :url, :geolocation,
|
|
10
|
+
|
|
11
|
+
### Utility:
|
|
12
|
+
:resources, :counters
|
|
13
|
+
|
|
14
|
+
### RESOURCES:
|
|
15
|
+
|
|
16
|
+
has_many :venues, Venue
|
|
17
|
+
|
|
18
|
+
has_many :nearby_venues, Venue
|
|
19
|
+
|
|
20
|
+
has_many :tags, Tag
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
require 'httparty'
|
|
2
|
+
|
|
3
|
+
module Hungry
|
|
4
|
+
class Resource
|
|
5
|
+
include HTTParty
|
|
6
|
+
|
|
7
|
+
attr_accessor :attributes
|
|
8
|
+
|
|
9
|
+
### CLASS METHODS:
|
|
10
|
+
|
|
11
|
+
def self.get(*args)
|
|
12
|
+
puts "[Resource]: GET #{args.map(&:inspect).join(', ')}"
|
|
13
|
+
self.base_uri Hungry.api_url
|
|
14
|
+
super
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.belongs_to(resource, klass = Resource)
|
|
18
|
+
define_method resource do
|
|
19
|
+
if url = resources[resource]
|
|
20
|
+
attributes = self.class.get url
|
|
21
|
+
klass.new(attributes)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.has_many(resource, klass = Resource)
|
|
27
|
+
define_method resource do
|
|
28
|
+
if url = resources[resource]
|
|
29
|
+
klass.collection.from_url(url)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
include Enumerable
|
|
36
|
+
|
|
37
|
+
attr_writer :endpoint
|
|
38
|
+
attr_writer :default_criteria
|
|
39
|
+
|
|
40
|
+
def endpoint
|
|
41
|
+
@endpoint || (superclass.respond_to?(:endpoint) ? superclass.endpoint : nil)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def default_criteria
|
|
45
|
+
if @default_criteria.respond_to?(:call)
|
|
46
|
+
@default_criteria.call
|
|
47
|
+
else
|
|
48
|
+
@default_criteria || {}
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def collection
|
|
53
|
+
Collection.new(self, endpoint, default_criteria)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def find(id)
|
|
57
|
+
raise NoEndpointSpecified unless endpoint
|
|
58
|
+
|
|
59
|
+
response = get "#{endpoint}/#{id}"
|
|
60
|
+
|
|
61
|
+
if response.code == 200
|
|
62
|
+
new(response)
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def all(criteria = {})
|
|
67
|
+
collection.all(criteria)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def each(&block)
|
|
71
|
+
all.each(&block)
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
### INSTANCE METHODS:
|
|
76
|
+
|
|
77
|
+
def initialize(new_attributes = {})
|
|
78
|
+
self.attributes = {}
|
|
79
|
+
|
|
80
|
+
new_attributes.each do |key, value|
|
|
81
|
+
if value.respond_to?(:symbolize_keys)
|
|
82
|
+
value = value.symbolize_keys
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
attributes[key] = value
|
|
86
|
+
|
|
87
|
+
if respond_to?("#{key}=")
|
|
88
|
+
send("#{key}=", value)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'httparty'
|
|
2
|
+
|
|
3
|
+
module Hungry
|
|
4
|
+
class Review < Resource
|
|
5
|
+
|
|
6
|
+
### ATTRIBUTES:
|
|
7
|
+
|
|
8
|
+
### Review:
|
|
9
|
+
attr_accessor :id, :body, :rating, :scores, :author,
|
|
10
|
+
|
|
11
|
+
### Utility:
|
|
12
|
+
:created_at, :updated_at
|
|
13
|
+
|
|
14
|
+
### RESOURCES:
|
|
15
|
+
|
|
16
|
+
belongs_to :venue, Venue
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
end
|
data/lib/hungry/site.rb
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Hungry
|
|
2
|
+
class Site < Resource
|
|
3
|
+
|
|
4
|
+
self.endpoint = '/sites'
|
|
5
|
+
|
|
6
|
+
### ATTRIBUTES:
|
|
7
|
+
|
|
8
|
+
### Preview:
|
|
9
|
+
attr_accessor :id, :name, :title, :subtitle, :identifier, :default, :locale,
|
|
10
|
+
:url, :timezone, :country, :applications,
|
|
11
|
+
|
|
12
|
+
### Utility:
|
|
13
|
+
:resources, :counters
|
|
14
|
+
|
|
15
|
+
### FINDERS:
|
|
16
|
+
|
|
17
|
+
def self.with_hostname(hostname)
|
|
18
|
+
collection.all(hostname: hostname).first
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/hungry/tag.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Hungry
|
|
2
|
+
class Tag < Resource
|
|
3
|
+
|
|
4
|
+
self.endpoint = '/tags'
|
|
5
|
+
|
|
6
|
+
### ATTRIBUTES:
|
|
7
|
+
|
|
8
|
+
### Tag:
|
|
9
|
+
attr_accessor :id, :name, :context,
|
|
10
|
+
|
|
11
|
+
### Utility:
|
|
12
|
+
:resources, :counters
|
|
13
|
+
|
|
14
|
+
### RESOURCES:
|
|
15
|
+
|
|
16
|
+
has_many :venues, Venue
|
|
17
|
+
|
|
18
|
+
has_many :tags, Tag
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/hungry/util.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require 'cgi'
|
|
2
|
+
require 'rack/utils'
|
|
3
|
+
|
|
4
|
+
module Hungry
|
|
5
|
+
module Util
|
|
6
|
+
extend self
|
|
7
|
+
|
|
8
|
+
def params_from_uri(uri)
|
|
9
|
+
uri = URI.parse(uri) unless uri.is_a?(URI)
|
|
10
|
+
Rack::Utils.parse_query(uri.query) if uri.query.present?
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def uri_with_params(uri, params = {})
|
|
14
|
+
params = params.map { |k,v| "#{k}=#{CGI.escape(v.to_s)}" }
|
|
15
|
+
.join('&')
|
|
16
|
+
.presence
|
|
17
|
+
|
|
18
|
+
[uri, params].compact
|
|
19
|
+
.join('?')
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def is_numeric?(value)
|
|
23
|
+
value.to_s =~ /^[+-]?[\d]+(\.[\d]+){0,1}$/
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/hungry/venue.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
module Hungry
|
|
2
|
+
class Venue < Resource
|
|
3
|
+
autoload :Collection, 'hungry/venue/collection'
|
|
4
|
+
|
|
5
|
+
self.endpoint = '/venues'
|
|
6
|
+
|
|
7
|
+
### RESOURCES:
|
|
8
|
+
|
|
9
|
+
has_many :reviews, Review
|
|
10
|
+
|
|
11
|
+
belongs_to :country, Country
|
|
12
|
+
|
|
13
|
+
belongs_to :region, Region
|
|
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
|
|
30
|
+
|
|
31
|
+
### FINDERS:
|
|
32
|
+
|
|
33
|
+
def self.collection
|
|
34
|
+
Collection.new(self, endpoint, default_criteria)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def self.search(query)
|
|
38
|
+
collection.search(query)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.nearby(geolocation, options = {})
|
|
42
|
+
collection.nearby(geolocation, options)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.tagged_with(*tags)
|
|
46
|
+
collection.tagged_with(*tags)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.sort_by(sortable)
|
|
50
|
+
collection.sort_by(sortable)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.paginate(page, options = {})
|
|
54
|
+
collection.paginate(page, options)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Hungry
|
|
2
|
+
class Venue
|
|
3
|
+
class Collection < Hungry::Collection
|
|
4
|
+
include Pagination
|
|
5
|
+
|
|
6
|
+
def search(query)
|
|
7
|
+
all query: query
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def nearby(location, options = {})
|
|
11
|
+
options[:geolocation] = Geolocation.parse(location)
|
|
12
|
+
options[:sort_by] ||= 'distance'
|
|
13
|
+
|
|
14
|
+
all options
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def tagged_with(*tags)
|
|
18
|
+
all tags: (current_tags + tags.flatten).compact.join(',')
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def sort_by(subject)
|
|
22
|
+
all sort_by: subject
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def current_tags
|
|
28
|
+
if criteria[:tags].is_a?(String)
|
|
29
|
+
criteria[:tags].gsub(/\s+/, '')
|
|
30
|
+
.split(',')
|
|
31
|
+
else
|
|
32
|
+
criteria[:tags] || []
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
begin
|
|
2
|
+
# Add support for Object#presence:
|
|
3
|
+
require 'active_support/core_ext/object/blank'
|
|
4
|
+
|
|
5
|
+
rescue LoadError => e
|
|
6
|
+
Object.class_eval do
|
|
7
|
+
unless respond_to?(:present?)
|
|
8
|
+
def present?
|
|
9
|
+
!!presence
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
unless respond_to?(:presence)
|
|
14
|
+
def presence
|
|
15
|
+
return nil if respond_to?(:empty?) ? empty? : !self
|
|
16
|
+
self
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
begin
|
|
2
|
+
# Add support for Hash#symbolize_keys:
|
|
3
|
+
require 'active_support/core_ext/hash/keys'
|
|
4
|
+
|
|
5
|
+
rescue LoadError => e
|
|
6
|
+
Hash.class_eval do
|
|
7
|
+
unless respond_to?(:symbolize_keys)
|
|
8
|
+
def symbolize_keys
|
|
9
|
+
inject({}) do |options, (key, value)|
|
|
10
|
+
options[(key.to_sym rescue key) || key] = value
|
|
11
|
+
options
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Hungry::Geolocation do
|
|
4
|
+
let(:geo) { Hungry::Geolocation.new(50.8469397, 5.6927505) }
|
|
5
|
+
|
|
6
|
+
describe '.parse' do
|
|
7
|
+
context 'with a Geolocation' do
|
|
8
|
+
it 'returns the given Geolocation' do
|
|
9
|
+
Hungry::Geolocation.parse(geo).should == geo
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
context 'with an Object' do
|
|
14
|
+
it 'returns a Geolocation object for objects with a latitude and longitude' do
|
|
15
|
+
object = Class.new do
|
|
16
|
+
def latitude; 50.8469397; end
|
|
17
|
+
def longitude; 5.6927505; end
|
|
18
|
+
end.new
|
|
19
|
+
|
|
20
|
+
geo = Hungry::Geolocation.parse(object)
|
|
21
|
+
geo.latitude.should == 50.8469397
|
|
22
|
+
geo.longitude.should == 5.6927505
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'returns a Geolocation object for objects with a lat and lng' do
|
|
26
|
+
object = Class.new do
|
|
27
|
+
def lat; 50.8469397; end
|
|
28
|
+
def lng; 5.6927505; end
|
|
29
|
+
end.new
|
|
30
|
+
|
|
31
|
+
geo = Hungry::Geolocation.parse(object)
|
|
32
|
+
geo.latitude.should == 50.8469397
|
|
33
|
+
geo.longitude.should == 5.6927505
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'returns a Geolocation object for objects that have a valid geolocation' do
|
|
37
|
+
object = Class.new do
|
|
38
|
+
def geolocation; Hungry::Geolocation.new(50.8469397, 5.6927505); end
|
|
39
|
+
end.new
|
|
40
|
+
|
|
41
|
+
geo = Hungry::Geolocation.parse(object)
|
|
42
|
+
geo.latitude.should == 50.8469397
|
|
43
|
+
geo.longitude.should == 5.6927505
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it 'returns nil for objects without geo information' do
|
|
47
|
+
geo = Hungry::Geolocation.parse(Object.new)
|
|
48
|
+
geo.should be_nil
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it 'returns nil for objects that have an invalid geolocation' do
|
|
52
|
+
object = Class.new do
|
|
53
|
+
def geolocation; "just a string"; end
|
|
54
|
+
end.new
|
|
55
|
+
|
|
56
|
+
geo = Hungry::Geolocation.parse(object)
|
|
57
|
+
geo.should be_nil
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context 'with a String' do
|
|
62
|
+
it 'returns a Geolocation object' do
|
|
63
|
+
geo = Hungry::Geolocation.parse('50.8469397,5.6927505')
|
|
64
|
+
geo.latitude.should == 50.8469397
|
|
65
|
+
geo.longitude.should == 5.6927505
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it 'returns nil if the string can not be parsed' do
|
|
69
|
+
geo = Hungry::Geolocation.parse('not-a,geolocation')
|
|
70
|
+
geo.should be_nil
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
context 'with an Array' do
|
|
75
|
+
it 'returns a Geolocation object' do
|
|
76
|
+
geo = Hungry::Geolocation.parse([50.8469397, 5.6927505])
|
|
77
|
+
geo.latitude.should == 50.8469397
|
|
78
|
+
geo.longitude.should == 5.6927505
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
it 'returns nil if the array can not be parsed' do
|
|
82
|
+
geo = Hungry::Geolocation.parse(['not a', 'geolocation'])
|
|
83
|
+
geo.should be_nil
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
context 'with a Hash' do
|
|
88
|
+
it 'returns a Geolocation object' do
|
|
89
|
+
geo = Hungry::Geolocation.parse(latitude: 50.8469397, longitude: 5.6927505)
|
|
90
|
+
geo.latitude.should == 50.8469397
|
|
91
|
+
geo.longitude.should == 5.6927505
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'supports abbreviated keys' do
|
|
95
|
+
geo = Hungry::Geolocation.parse(lat: 50.8469397, lng: 5.6927505)
|
|
96
|
+
geo.latitude.should == 50.8469397
|
|
97
|
+
geo.longitude.should == 5.6927505
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
it 'returns nil if the hash can not be parsed' do
|
|
101
|
+
geo = Hungry::Geolocation.parse(a: 'b', c: 'd')
|
|
102
|
+
geo.should be_nil
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe '#initialize' do
|
|
108
|
+
it 'sets latitude' do
|
|
109
|
+
geo.latitude.should == 50.8469397
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'sets longitude' do
|
|
113
|
+
geo.longitude.should == 5.6927505
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
describe '#to_s' do
|
|
118
|
+
it 'joins latitude and longitude with a ","' do
|
|
119
|
+
geo.to_s.should == "50.8469397,5.6927505"
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Hungry::Util do
|
|
4
|
+
describe '#params_from_uri' do
|
|
5
|
+
it 'returns a hash representing the params in the given URL' do
|
|
6
|
+
hash = Hungry::Util.params_from_uri 'http://www.google.com/search?q=ruby&lang=en'
|
|
7
|
+
hash.should == { 'q' => 'ruby', 'lang' => 'en' }
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe '#uri_with_params' do
|
|
12
|
+
it 'returns a clean URL if there no hash is given' do
|
|
13
|
+
url = Hungry::Util.uri_with_params('http://www.google.com/')
|
|
14
|
+
url.should == 'http://www.google.com/'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'returns an URL with params representing the given hash' do
|
|
18
|
+
url = Hungry::Util.uri_with_params('http://www.google.com/search', 'q' => 'ruby', 'lang' => 'en')
|
|
19
|
+
url.should == 'http://www.google.com/search?q=ruby&lang=en'
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
describe '#is_numeric?' do
|
|
24
|
+
it 'returns true for integers' do
|
|
25
|
+
Hungry::Util.is_numeric?(100).should be_true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it 'returns true for floats' do
|
|
29
|
+
Hungry::Util.is_numeric?(10.0).should be_true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'returns true for integers in strings' do
|
|
33
|
+
Hungry::Util.is_numeric?('100').should be_true
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it 'returns true for floats in strings' do
|
|
37
|
+
Hungry::Util.is_numeric?('10.0').should be_true
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it 'returns true for negative integers in strings' do
|
|
41
|
+
Hungry::Util.is_numeric?('-100').should be_true
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'returns true for negative floats in strings' do
|
|
45
|
+
Hungry::Util.is_numeric?('-10.0').should be_true
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it 'returns false for non numeric values' do
|
|
49
|
+
Hungry::Util.is_numeric?('abc').should be_false
|
|
50
|
+
Hungry::Util.is_numeric?('1a3').should be_false
|
|
51
|
+
Hungry::Util.is_numeric?('1.0.0').should be_false
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: hungry
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Tom-Eric Gerritsen
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-02-04 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: httparty
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
- !ruby/object:Gem::Dependency
|
|
31
|
+
name: rack
|
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
|
33
|
+
none: false
|
|
34
|
+
requirements:
|
|
35
|
+
- - ! '>='
|
|
36
|
+
- !ruby/object:Gem::Version
|
|
37
|
+
version: '0'
|
|
38
|
+
type: :runtime
|
|
39
|
+
prerelease: false
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
none: false
|
|
42
|
+
requirements:
|
|
43
|
+
- - ! '>='
|
|
44
|
+
- !ruby/object:Gem::Version
|
|
45
|
+
version: '0'
|
|
46
|
+
- !ruby/object:Gem::Dependency
|
|
47
|
+
name: rspec
|
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
type: :development
|
|
55
|
+
prerelease: false
|
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
57
|
+
none: false
|
|
58
|
+
requirements:
|
|
59
|
+
- - ! '>='
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
- !ruby/object:Gem::Dependency
|
|
63
|
+
name: fakeweb
|
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
|
65
|
+
none: false
|
|
66
|
+
requirements:
|
|
67
|
+
- - ! '>='
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '0'
|
|
70
|
+
type: :development
|
|
71
|
+
prerelease: false
|
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
73
|
+
none: false
|
|
74
|
+
requirements:
|
|
75
|
+
- - ! '>='
|
|
76
|
+
- !ruby/object:Gem::Version
|
|
77
|
+
version: '0'
|
|
78
|
+
description: An interface to the Eet.nu API.
|
|
79
|
+
email:
|
|
80
|
+
- tomeric@eet.nu
|
|
81
|
+
executables: []
|
|
82
|
+
extensions: []
|
|
83
|
+
extra_rdoc_files: []
|
|
84
|
+
files:
|
|
85
|
+
- .gitignore
|
|
86
|
+
- .rspec
|
|
87
|
+
- Gemfile
|
|
88
|
+
- Guardfile
|
|
89
|
+
- Rakefile
|
|
90
|
+
- hungry.gemspec
|
|
91
|
+
- lib/hungry.rb
|
|
92
|
+
- lib/hungry/city.rb
|
|
93
|
+
- lib/hungry/collection.rb
|
|
94
|
+
- lib/hungry/collection/pagination.rb
|
|
95
|
+
- lib/hungry/country.rb
|
|
96
|
+
- lib/hungry/geolocation.rb
|
|
97
|
+
- lib/hungry/location.rb
|
|
98
|
+
- lib/hungry/region.rb
|
|
99
|
+
- lib/hungry/resource.rb
|
|
100
|
+
- lib/hungry/review.rb
|
|
101
|
+
- lib/hungry/site.rb
|
|
102
|
+
- lib/hungry/tag.rb
|
|
103
|
+
- lib/hungry/util.rb
|
|
104
|
+
- lib/hungry/venue.rb
|
|
105
|
+
- lib/hungry/venue/collection.rb
|
|
106
|
+
- lib/support/presence.rb
|
|
107
|
+
- lib/support/symbolize_keys.rb
|
|
108
|
+
- spec/hungry/geolocation_spec.rb
|
|
109
|
+
- spec/hungry/util_spec.rb
|
|
110
|
+
- spec/spec_helper.rb
|
|
111
|
+
homepage: http://github.com/eet-nu/hungry
|
|
112
|
+
licenses: []
|
|
113
|
+
post_install_message:
|
|
114
|
+
rdoc_options: []
|
|
115
|
+
require_paths:
|
|
116
|
+
- lib
|
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
118
|
+
none: false
|
|
119
|
+
requirements:
|
|
120
|
+
- - ! '>='
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: '0'
|
|
123
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
124
|
+
none: false
|
|
125
|
+
requirements:
|
|
126
|
+
- - ! '>='
|
|
127
|
+
- !ruby/object:Gem::Version
|
|
128
|
+
version: '0'
|
|
129
|
+
requirements: []
|
|
130
|
+
rubyforge_project:
|
|
131
|
+
rubygems_version: 1.8.24
|
|
132
|
+
signing_key:
|
|
133
|
+
specification_version: 3
|
|
134
|
+
summary: An interface to the Eet.nu API.
|
|
135
|
+
test_files:
|
|
136
|
+
- spec/hungry/geolocation_spec.rb
|
|
137
|
+
- spec/hungry/util_spec.rb
|
|
138
|
+
- spec/spec_helper.rb
|