grubber 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 +17 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +22 -0
- data/README.md +125 -0
- data/Rakefile +1 -0
- data/bin/grubber +5 -0
- data/grubber.gemspec +26 -0
- data/lib/grubber.rb +12 -0
- data/lib/grubber/client.rb +47 -0
- data/lib/grubber/command.rb +52 -0
- data/lib/grubber/config.rb +70 -0
- data/lib/grubber/presenter.rb +34 -0
- data/lib/grubber/restaurant.rb +47 -0
- data/lib/grubber/store.rb +85 -0
- data/lib/grubber/version.rb +3 -0
- metadata +132 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Matthew Werner
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
# Grubber
|
2
|
+
|
3
|
+
Grubber helps you find a place to eat neaby.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Simply:
|
8
|
+
|
9
|
+
$ gem install grubber
|
10
|
+
|
11
|
+
## API Access
|
12
|
+
|
13
|
+
Grubber uses the Yelp API to find nearby places. To use
|
14
|
+
grubber you must get yourself Yelp API access. You
|
15
|
+
can do so at: [http://www.yelp.com/developers](http://www.yelp.com/developers)
|
16
|
+
|
17
|
+
Once you have your tokens, run `grubber auth`. This will
|
18
|
+
prompt you for your credentials and get you the rest of the way.
|
19
|
+
|
20
|
+
## Location Services
|
21
|
+
|
22
|
+
Grubber uses CoreLocation to find out where you're geographically operating.
|
23
|
+
It will request permission once and then cache your location. Grubber will automatically
|
24
|
+
find your coordinates when needed if you haven't previously located yourself.
|
25
|
+
|
26
|
+
#### Granting Permission
|
27
|
+
|
28
|
+
CoreLocation requires you grant ruby permission to use Location Services. You should
|
29
|
+
be prompted for permission once, and don't have to worry about it again.
|
30
|
+
|
31
|
+
#### Revoking Permission
|
32
|
+
|
33
|
+
To revoke previously granted permissions, you can uncheck ruby in:
|
34
|
+
|
35
|
+
System Preferences > Security & Privacy > Privacy > Location Services
|
36
|
+
|
37
|
+
#### Updating your location
|
38
|
+
|
39
|
+
You can request grubber to update its cached location by calling `locate`:
|
40
|
+
|
41
|
+
$ grubber locate
|
42
|
+
Updated coordinates to: 37.782487810714265, -122.40982359190473
|
43
|
+
|
44
|
+
*Developers Note: No stalkers please*
|
45
|
+
|
46
|
+
## Usage
|
47
|
+
|
48
|
+
Grubber has two primary commands:
|
49
|
+
|
50
|
+
### List
|
51
|
+
|
52
|
+
Grubber can list a bunch of nearby restaurants. Each entry has
|
53
|
+
the name, rating, address, category, phone and url.
|
54
|
+
|
55
|
+
**Protip:** If using iTerm, you can cmd+click on a url to open in your default browser
|
56
|
+
|
57
|
+
$ grubber list
|
58
|
+
|
59
|
+
Split Pea Seduction ★ ★ ★ ★ ☆
|
60
|
+
138 6th St
|
61
|
+
[Sandwiches] +1-415-551-2223
|
62
|
+
http://www.yelp.com/biz/split-pea-seduction-san-francisco
|
63
|
+
|
64
|
+
Miss SaiGon ★ ★ ★ ★ ☆
|
65
|
+
100 6th St
|
66
|
+
[Vietnamese] +1-415-522-0332
|
67
|
+
http://www.yelp.com/biz/miss-saigon-san-francisco-2
|
68
|
+
|
69
|
+
Punjab Kabab House ★ ★ ★ ☆ ☆
|
70
|
+
101 Eddy St
|
71
|
+
[Indian] +1-415-447-7499
|
72
|
+
http://www.yelp.com/biz/punjab-kabab-house-san-francisco
|
73
|
+
|
74
|
+
Cafe Venue ★ ★ ★ ☆ ☆
|
75
|
+
67 5th St
|
76
|
+
[Coffee & Tea] +1-415-546-1144
|
77
|
+
http://www.yelp.com/biz/cafe-venue-san-francisco-7
|
78
|
+
|
79
|
+
...
|
80
|
+
|
81
|
+
### Pick
|
82
|
+
|
83
|
+
Grubber can just go ahead and pick a nearby restaurant for you
|
84
|
+
to avoid you having to think about exactly where you want to go.
|
85
|
+
Pick returns all the same fields as list.
|
86
|
+
|
87
|
+
$ grubber pick
|
88
|
+
|
89
|
+
Tu Lan ★ ★ ★ ★ ☆
|
90
|
+
8 6th St
|
91
|
+
[Vietnamese] +1-415-626-0927
|
92
|
+
http://www.yelp.com/biz/tu-lan-san-francisco-2
|
93
|
+
|
94
|
+
### The CLI
|
95
|
+
|
96
|
+
grubber help [TASK] # Describe available tasks or one specific task
|
97
|
+
grubber auth # Enter your Yelp API credentials
|
98
|
+
grubber list # List available nearby restaurants
|
99
|
+
grubber locate # Refresh your grubber's known coordinates
|
100
|
+
grubber pick # Pick a restaurant nearby
|
101
|
+
|
102
|
+
## Troubleshooting
|
103
|
+
|
104
|
+
_**When I run call locate twice in a row, it just hangs. wtf**_
|
105
|
+
|
106
|
+
If you request a new location from CoreLocation too quickly, the command
|
107
|
+
will simply hang. Unfortunately this pertains to [a problem]((https://github.com/evanphx/lost/pull/2) with the awesome ruby wrapper [lost](https://github.com/evanphx/lost) that [evanphx](https://github.com/evanphx) has written. Grubber will cache your location, so it shouldn't be a problem. Just don't move around so fast.
|
108
|
+
|
109
|
+
## The future
|
110
|
+
|
111
|
+
I would like to add a few features to grubber. Such as:
|
112
|
+
|
113
|
+
- Testing
|
114
|
+
- Preferred tags/categories of food
|
115
|
+
- CLI for search terms
|
116
|
+
- Price range
|
117
|
+
- Maximum distance
|
118
|
+
|
119
|
+
## Contributing
|
120
|
+
|
121
|
+
1. Fork it
|
122
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
123
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
124
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
125
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/grubber
ADDED
data/grubber.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'grubber/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "grubber"
|
8
|
+
gem.version = Grubber::VERSION
|
9
|
+
gem.authors = ["Matthew Werner"]
|
10
|
+
gem.email = ["matthew@culini.com"]
|
11
|
+
gem.description = %q{Grubber uses the Yelp API to find nearby restaurants to eat at}
|
12
|
+
gem.summary = %q{Grubber helps you decide where to eat}
|
13
|
+
gem.homepage = ""
|
14
|
+
gem.license = 'MIT'
|
15
|
+
|
16
|
+
gem.add_runtime_dependency 'oauth'
|
17
|
+
gem.add_runtime_dependency 'thor'
|
18
|
+
gem.add_runtime_dependency 'lost'
|
19
|
+
|
20
|
+
gem.add_development_dependency 'rake'
|
21
|
+
|
22
|
+
gem.files = `git ls-files`.split($/)
|
23
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
24
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
25
|
+
gem.require_paths = ["lib"]
|
26
|
+
end
|
data/lib/grubber.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "grubber/version"
|
2
|
+
|
3
|
+
module Grubber
|
4
|
+
autoload :Client, 'grubber/client'
|
5
|
+
autoload :Command, 'grubber/command'
|
6
|
+
autoload :Config, 'grubber/config'
|
7
|
+
autoload :Store, 'grubber/store'
|
8
|
+
autoload :Presenter, 'grubber/presenter'
|
9
|
+
autoload :Restaurant, 'grubber/restaurant'
|
10
|
+
|
11
|
+
CONFIG = Config.load
|
12
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'oauth'
|
2
|
+
require 'json'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Grubber
|
6
|
+
class Client
|
7
|
+
|
8
|
+
HOST = 'api.yelp.com'
|
9
|
+
attr_accessor :consumer_key, :consumer_secret, :token_key, :token_secret
|
10
|
+
|
11
|
+
def search(term, opts={})
|
12
|
+
lat, lng = *Grubber::CONFIG.coordinates
|
13
|
+
yelp = connection
|
14
|
+
return [] if yelp.nil?
|
15
|
+
|
16
|
+
response = yelp.get("/v2/search?term=#{term}&ll=#{lat},#{lng}")
|
17
|
+
Restaurant.parse(response.body)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def connection
|
23
|
+
return @connection if defined?(@connection)
|
24
|
+
ckey, csec, tkey, tsec = credentials
|
25
|
+
|
26
|
+
oauth = OAuth::Consumer.new(ckey, csec, {:site => "http://#{HOST}"})
|
27
|
+
@connection = OAuth::AccessToken.new(oauth, tkey, tsec)
|
28
|
+
end
|
29
|
+
|
30
|
+
def credentials
|
31
|
+
config = Grubber::CONFIG
|
32
|
+
unless config.has_auth?
|
33
|
+
puts "\nYou are missing Yelp API Credentials"
|
34
|
+
puts "Add your credentials using `grubber auth`"
|
35
|
+
return nil
|
36
|
+
end
|
37
|
+
|
38
|
+
return [
|
39
|
+
config.consumer_key,
|
40
|
+
config.consumer_secret,
|
41
|
+
config.token_key,
|
42
|
+
config.token_secret
|
43
|
+
]
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module Grubber
|
4
|
+
class Command < Thor
|
5
|
+
include Thor::Actions
|
6
|
+
|
7
|
+
desc "pick", "Select one restaurant nearby"
|
8
|
+
def pick
|
9
|
+
Presenter.new( Restaurant.random ).present
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "list", "List available nearby restaurants"
|
13
|
+
def list
|
14
|
+
Presenter.new( Restaurant.all ).present
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'locate', "Refresh your grubber's known coordinates"
|
18
|
+
def locate
|
19
|
+
lat, lng = Grubber::Config.update_location
|
20
|
+
say "Updated coordinates to: #{lat}, #{lng}", :green
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'auth', 'Enter your Yelp API credentials'
|
24
|
+
def auth
|
25
|
+
config = Grubber::Config.load
|
26
|
+
|
27
|
+
say("\nGrubber requires Yelp API v2 credentials")
|
28
|
+
say("To learn more go to: http://www.yelp.com/developers")
|
29
|
+
if config.has_auth?
|
30
|
+
say("\nYelp authentication already set:")
|
31
|
+
say("Consumer Key: #{config.consumer_key}")
|
32
|
+
say("Consumer Secret: #{config.consumer_secret}\n")
|
33
|
+
say("Token Key: #{config.token_key}\n")
|
34
|
+
say("Token Sec: #{config.token_secret}\n")
|
35
|
+
overwrite = ask('Overwrite? (y,n)')
|
36
|
+
return unless overwrite.downcase == 'y'
|
37
|
+
end
|
38
|
+
|
39
|
+
c_key = ask("\nConsumer Key: ")
|
40
|
+
c_sec = ask('Consumer Secret: ')
|
41
|
+
t_key = ask('Token Key: ')
|
42
|
+
t_sec = ask('Token Sec: ')
|
43
|
+
|
44
|
+
if Grubber::Config.update_auth(c_key, c_sec, t_key, t_sec)
|
45
|
+
say("Complete!", :green)
|
46
|
+
else
|
47
|
+
say("Failed", :red)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'lost'
|
2
|
+
|
3
|
+
module Grubber
|
4
|
+
class Config
|
5
|
+
|
6
|
+
attr_accessor :store, :lat, :lng, :credentials
|
7
|
+
|
8
|
+
def initialize(opts={})
|
9
|
+
@store = Grubber::Store.load[:grubber]
|
10
|
+
|
11
|
+
location = store[:location]
|
12
|
+
@lat = location[:lat]
|
13
|
+
@lng = location[:lng]
|
14
|
+
|
15
|
+
@credentials = store[:credentials]
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.load
|
20
|
+
new
|
21
|
+
end
|
22
|
+
|
23
|
+
def coordinates
|
24
|
+
[lat, lng]
|
25
|
+
end
|
26
|
+
|
27
|
+
def has_auth?
|
28
|
+
!self.credentials.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
# consumer_key, consumer_secret
|
32
|
+
# token_key, token_secret
|
33
|
+
%w(consumer token).each do |type|
|
34
|
+
%w(key secret).each do |obj|
|
35
|
+
auth_attr = "#{type}_#{obj}".to_sym
|
36
|
+
define_method(auth_attr) do
|
37
|
+
return '' unless has_auth?
|
38
|
+
credentials[auth_attr] || ''
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.update_auth(ckey, csec, tkey, tsec)
|
44
|
+
[ckey, csec, tkey, tsec].each do |k|
|
45
|
+
return nil if k.nil? || k == ''
|
46
|
+
end
|
47
|
+
|
48
|
+
Grubber::Store.update({
|
49
|
+
credentials: {
|
50
|
+
consumer_key: ckey,
|
51
|
+
consumer_secret: csec,
|
52
|
+
token_key: tkey,
|
53
|
+
token_secret: tsec
|
54
|
+
}
|
55
|
+
})
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.update_location
|
59
|
+
lat, lng = *Lost.current_position
|
60
|
+
Grubber::Store.update({
|
61
|
+
location: {
|
62
|
+
lat: lat,
|
63
|
+
lng: lng
|
64
|
+
}
|
65
|
+
})
|
66
|
+
return [lat, lng]
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
# encoding: utf-8
|
3
|
+
|
4
|
+
module Grubber
|
5
|
+
class Presenter
|
6
|
+
|
7
|
+
attr_accessor :restaurants
|
8
|
+
|
9
|
+
def initialize(restaurants)
|
10
|
+
@restaurants = [*restaurants]
|
11
|
+
end
|
12
|
+
|
13
|
+
def present
|
14
|
+
return nil if empty?
|
15
|
+
|
16
|
+
restaurants.each do |r|
|
17
|
+
puts "\n#{r.name} #{stars(r.rating)}"
|
18
|
+
puts r.address
|
19
|
+
puts "[#{r.category}] #{r.phone}"
|
20
|
+
puts r.url
|
21
|
+
end
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def stars(rating)
|
26
|
+
(" ★" * rating) + (" ☆" * (5 - rating))
|
27
|
+
end
|
28
|
+
|
29
|
+
def empty?
|
30
|
+
self.restaurants.empty?
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Grubber
|
2
|
+
class Restaurant
|
3
|
+
|
4
|
+
ATTRIBUTES = [:name, :description, :categories, :rating, :url, :display_phone, :location, :reviews].freeze
|
5
|
+
attr_accessor *ATTRIBUTES
|
6
|
+
|
7
|
+
alias_method :phone, :display_phone
|
8
|
+
|
9
|
+
def initialize(opts={})
|
10
|
+
opts.each_pair do |k,v|
|
11
|
+
self.instance_variable_set("@#{k}", v)
|
12
|
+
end
|
13
|
+
yield self
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.all(opts={})
|
17
|
+
q = opts[:term] || 'lunch'
|
18
|
+
Client.new.search(q)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.random(opts={})
|
22
|
+
all(opts).sample
|
23
|
+
end
|
24
|
+
|
25
|
+
def address
|
26
|
+
location['display_address'].first
|
27
|
+
end
|
28
|
+
|
29
|
+
def category
|
30
|
+
cat = categories.first
|
31
|
+
cat.is_a?(Array) ? cat.first : cat
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.parse(body)
|
35
|
+
JSON.parse(body)['businesses'].collect do |r|
|
36
|
+
Restaurant.new do |n|
|
37
|
+
ATTRIBUTES.map(&:to_s).each do |a|
|
38
|
+
value = r[a]
|
39
|
+
value = value.to_i if a == 'rating'
|
40
|
+
n.send("#{a}=", value)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'lost'
|
3
|
+
|
4
|
+
module Grubber
|
5
|
+
class Store
|
6
|
+
|
7
|
+
attr_accessor :path, :content
|
8
|
+
|
9
|
+
DEFAULT_PATH = "/Users/#{`whoami`.strip}/.grubber"
|
10
|
+
|
11
|
+
def initialize(opts={})
|
12
|
+
@path = opts[:path] || DEFAULT_PATH
|
13
|
+
|
14
|
+
setup
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.load
|
18
|
+
client = new
|
19
|
+
|
20
|
+
data = client.read
|
21
|
+
return data unless data.nil?
|
22
|
+
|
23
|
+
client.reset
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.update(data)
|
27
|
+
return unless data.is_a?(Hash)
|
28
|
+
|
29
|
+
client = new
|
30
|
+
client.content[:grubber].merge!(data)
|
31
|
+
client.write
|
32
|
+
data
|
33
|
+
end
|
34
|
+
|
35
|
+
def setup
|
36
|
+
return reload if File.exist?(path)
|
37
|
+
|
38
|
+
reset
|
39
|
+
end
|
40
|
+
|
41
|
+
def read
|
42
|
+
begin
|
43
|
+
yml = YAML.load_file(path)
|
44
|
+
rescue TypeError => e
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
|
48
|
+
return nil unless yml
|
49
|
+
|
50
|
+
yml
|
51
|
+
end
|
52
|
+
|
53
|
+
def reload
|
54
|
+
@content = read
|
55
|
+
end
|
56
|
+
|
57
|
+
def write
|
58
|
+
File.open(path, 'w'){|f| f.write(content.to_yaml) }
|
59
|
+
end
|
60
|
+
|
61
|
+
def reset
|
62
|
+
File.open(path, 'w') do |f|
|
63
|
+
f.write(base_config.to_yaml)
|
64
|
+
end
|
65
|
+
|
66
|
+
reload
|
67
|
+
end
|
68
|
+
|
69
|
+
def base_config
|
70
|
+
lat, lng = *Lost.current_position
|
71
|
+
current_time = Time.now.to_i
|
72
|
+
|
73
|
+
{
|
74
|
+
grubber: {
|
75
|
+
location: {
|
76
|
+
lat: lat,
|
77
|
+
lng: lng
|
78
|
+
},
|
79
|
+
created_at: current_time
|
80
|
+
}
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
metadata
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: grubber
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Matthew Werner
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-19 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: oauth
|
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: thor
|
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: lost
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
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: rake
|
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: Grubber uses the Yelp API to find nearby restaurants to eat at
|
79
|
+
email:
|
80
|
+
- matthew@culini.com
|
81
|
+
executables:
|
82
|
+
- grubber
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- Gemfile
|
88
|
+
- LICENSE.txt
|
89
|
+
- README.md
|
90
|
+
- Rakefile
|
91
|
+
- bin/grubber
|
92
|
+
- grubber.gemspec
|
93
|
+
- lib/grubber.rb
|
94
|
+
- lib/grubber/client.rb
|
95
|
+
- lib/grubber/command.rb
|
96
|
+
- lib/grubber/config.rb
|
97
|
+
- lib/grubber/presenter.rb
|
98
|
+
- lib/grubber/restaurant.rb
|
99
|
+
- lib/grubber/store.rb
|
100
|
+
- lib/grubber/version.rb
|
101
|
+
homepage: ''
|
102
|
+
licenses:
|
103
|
+
- MIT
|
104
|
+
post_install_message:
|
105
|
+
rdoc_options: []
|
106
|
+
require_paths:
|
107
|
+
- lib
|
108
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
+
none: false
|
110
|
+
requirements:
|
111
|
+
- - ! '>='
|
112
|
+
- !ruby/object:Gem::Version
|
113
|
+
version: '0'
|
114
|
+
segments:
|
115
|
+
- 0
|
116
|
+
hash: -3855025966836421654
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
segments:
|
124
|
+
- 0
|
125
|
+
hash: -3855025966836421654
|
126
|
+
requirements: []
|
127
|
+
rubyforge_project:
|
128
|
+
rubygems_version: 1.8.24
|
129
|
+
signing_key:
|
130
|
+
specification_version: 3
|
131
|
+
summary: Grubber helps you decide where to eat
|
132
|
+
test_files: []
|