gowalla 0.1.4 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,7 @@
1
1
  require 'hashie'
2
- require 'httparty'
2
+ require 'faraday'
3
+ require 'multi_json'
4
+ require 'oauth2'
3
5
 
4
6
  directory = File.expand_path(File.dirname(__FILE__))
5
7
 
@@ -7,6 +9,8 @@ Hash.send :include, Hashie::HashExtensions
7
9
 
8
10
  module Gowalla
9
11
 
12
+ VERSION = "0.2.0".freeze
13
+
10
14
  # config/initializers/gowalla.rb (for instance)
11
15
  #
12
16
  # Gowalla.configure do |config|
@@ -27,6 +31,7 @@ module Gowalla
27
31
  attr_accessor :api_key
28
32
  attr_accessor :username
29
33
  attr_accessor :password
34
+ attr_accessor :api_secret
30
35
  end
31
36
 
32
37
  end
@@ -1,134 +1,181 @@
1
+ require 'forwardable'
2
+
1
3
  module Gowalla
2
-
3
4
  class Client
4
- include HTTParty
5
- format :json
6
- base_uri "http://api.gowalla.com"
7
- headers({'Accept' => 'application/json', "User-Agent" => 'Ruby gem'})
5
+ extend Forwardable
6
+
7
+ attr_reader :username, :api_key, :api_secret
8
8
 
9
- attr_reader :username
9
+ def_delegators :oauth_client, :web_server, :authorize_url, :access_token_url
10
10
 
11
11
  def initialize(options={})
12
- api_key = options[:api_key] || Gowalla.api_key
12
+ @api_key = options[:api_key] || Gowalla.api_key
13
+ @api_secret = options[:api_secret] || Gowalla.api_secret
13
14
  @username = options[:username] || Gowalla.username
15
+ @access_token = options[:access_token]
14
16
  password = options[:password] || Gowalla.password
15
- self.class.basic_auth(@username, password) unless @username.nil?
16
- self.class.headers({'X-Gowalla-API-Key' => api_key }) unless api_key.nil?
17
- end
18
-
19
- def user(user_id=self.username)
20
- mashup(self.class.get("/users/#{user_id}"))
21
- end
22
-
23
- def events(user_id=self.username)
24
- mashup(self.class.get("/users/#{user_id}/events")).activity
25
- end
26
-
27
- def friends_events
28
- mashup(self.class.get("/visits/recent")).activity
29
- end
30
-
31
- def friend_requests(user_id=self.username)
32
- mashup(self.class.get("/users/#{user_id}/friend_requests")).friends_needing_approval
33
- end
34
-
35
- def friends(user_id=self.username)
36
- mashup(self.class.get("/users/#{user_id}/friends")).friends
37
- end
38
-
39
- def items(user_id=self.username)
40
- mashup(self.class.get("/users/#{user_id}/items")).items
41
- end
42
-
43
- def missing_items(user_id=self.username)
44
- mashup(self.class.get("/users/#{user_id}/items/missing")).items
45
- end
46
-
47
- def vaulted_items(user_id=self.username)
48
- mashup(self.class.get("/users/#{user_id}/items/vault")).items
49
- end
50
-
17
+ connection.basic_auth(@username, password) unless @api_secret
18
+ end
19
+
20
+ # Retrieve information about a specific user
21
+ #
22
+ # @param [String] user_id (authenticated basic auth user) User ID (screen name)
23
+ # @return [Hashie::Mash] User info
24
+ def user(user_id=nil)
25
+ user_id ||= username
26
+ handle_response(connection.get("/users/#{user_id}"))
27
+ end
28
+
29
+ # Retrieve information about a specific item
30
+ #
31
+ # @param [Integer] id Item ID
32
+ # @return [Hashie::Mash] item info
51
33
  def item(id)
52
- mashup(self.class.get("/items/#{id}"))
53
- end
54
-
55
- def pins(user_id=self.username)
56
- mashup(self.class.get("/users/#{user_id}/pins"))
57
- end
58
-
34
+ handle_response(connection.get("/items/#{id}"))
35
+ end
36
+
37
+ # Retrieve a list of the stamps the user has collected
38
+ #
39
+ # @param [String] user_id (authenticated basic auth user) User ID (screen name)
40
+ # @param [Integer] limit (20) limit per page
41
+ # @return [Hashie::Mash] stamps info
59
42
  def stamps(user_id=self.username, limit=20)
60
- mashup(self.class.get("/users/#{user_id}/stamps", :query => {:limit => limit})).stamps
43
+ response = connection.get do |req|
44
+ req.url "/users/#{user_id}/stamps", :limit => limit
45
+ end
46
+ handle_response(response).stamps
61
47
  end
62
-
48
+
49
+ # Retrieve a list of spots the user has visited most often
50
+ #
51
+ # @param [String] user_id (authenticated basic auth user) User ID (screen name)
52
+ # @return [Hashie::Mash] item info
63
53
  def top_spots(user_id=self.username)
64
- mashup(self.class.get("/users/#{user_id}/top_spots")).top_spots
54
+ handle_response(connection.get("/users/#{user_id}/top_spots")).top_spots
65
55
  end
66
-
67
- def visited_spots(user_id=self.username)
68
- mashup(self.class.get("/users/#{user_id}/visited_spots"))
69
- end
70
-
56
+
57
+ # Retrieve information about a specific trip
58
+ #
59
+ # @param [Integer] trip_id Trip ID
60
+ # @return [Hashie::Mash] trip info
71
61
  def trip(trip_id)
72
- mashup(self.class.get("/trips/#{trip_id}"))
62
+ handle_response(connection.get("/trips/#{trip_id}"))
73
63
  end
74
64
 
65
+ # Retrieve information about a specific spot
66
+ #
67
+ # @param [Integer] spot_id Spot ID
68
+ # @return [Hashie::Mash] Spot info
75
69
  def spot(spot_id)
76
- mashup(self.class.get("/spots/#{spot_id}"))
70
+ handle_response(connection.get("/spots/#{spot_id}"))
77
71
  end
78
72
 
73
+ # Retrieve a list of check-ins at a particular spot. Shows only the activity that is visible to a given user.
74
+ #
75
+ # @param [Integer] spot_id Spot ID
76
+ # @return [Hashie::Mash] Spot info
79
77
  def spot_events(spot_id)
80
- mashup(self.class.get("/spots/#{spot_id}/events")).activity
78
+ handle_response(connection.get("/spots/#{spot_id}/events")).activity
81
79
  end
82
80
 
81
+ # Retrieve a list of items available at a particular spot
82
+ #
83
+ # @param [Integer] spot_id Spot ID
84
+ # @return [Hashie::Mash] Spot info
83
85
  def spot_items(spot_id)
84
- mashup(self.class.get("/spots/#{spot_id}/items")).items
86
+ handle_response(connection.get("/spots/#{spot_id}/items")).items
85
87
  end
86
88
 
89
+ # Retrieve a list of spots within a specified distance of a location
90
+ #
91
+ # @option options [Float] :latitude Latitude of search location
92
+ # @option options [Float] :longitude Longitude of search location
93
+ # @option options [Integer] :radius Search radius (in meters)
94
+ # @return [Hashie::Mash] spots info
87
95
  def list_spots(options={})
88
96
  query = format_geo_options(options)
89
- mashup(self.class.get("/spots", :query => query)).spots
90
- end
91
-
92
- def featured_spots(options={})
93
- list_spots(options.merge(:featured => 1))
94
- end
95
-
96
- def bookmarked_spots(options={})
97
- list_spots(options.merge(:bookmarked => 1))
97
+ response = connection.get do |req|
98
+ req.url "/spots", query
99
+ end
100
+ handle_response(response).spots
98
101
  end
99
102
 
103
+ # List of trips
104
+ #
105
+ # @return [<Hashie::Mash>] trip info
100
106
  def trips(options={})
101
107
  if user_id = options.delete(:user_id)
102
108
  options[:user_url] = "/users/#{user_id}"
103
109
  end
104
110
  query = format_geo_options(options)
105
- mashup(self.class.get("/trips", :query => query)).trips
106
- end
107
-
108
- def featured_trips(options={})
109
- trips(options.merge(:context => 'featured'))
110
- end
111
-
112
- def friends_trips(options={})
113
- trips(options.merge(:context => 'friends'))
111
+ response = connection.get do |req|
112
+ req.url "/trips", query
113
+ end
114
+ handle_response(response).trips
114
115
  end
115
-
116
+
117
+ # Lists all spot categories
118
+ #
119
+ # @return [<Hashie::Mash>] category info
116
120
  def categories
117
- mashup(self.class.get("/categories")).spot_categories
121
+ handle_response(connection.get("/categories")).spot_categories
118
122
  end
119
123
 
124
+ # Retrieve information about a specific category
125
+ #
126
+ # @param [Integer] id Category ID
127
+ # @return [Hashie::Mash] category info
120
128
  def category(id)
121
- mashup(self.class.get("/categories/#{id}"))
129
+ handle_response(connection.get("/categories/#{id}"))
122
130
  end
123
131
 
124
- def checkin(spot_id, options = {})
125
- query = format_geo_options(options)
132
+ # Check for missing access token
133
+ #
134
+ # @return [Boolean] whether or not to redirect to get an access token
135
+ def needs_access?
136
+ @api_secret and @access_token.to_s == ''
137
+ end
138
+
139
+ # Raw HTTP connection, either Faraday::Connection or OAuth2::AccessToken
140
+ #
141
+ # @return [OAuth2::Client]
142
+ def connection
126
143
 
127
- mashup(self.class.post("/checkins", :body => options, :query => { :spot_id => spot_id }))
144
+ if api_secret
145
+ @connection ||= OAuth2::AccessToken.new(oauth_client, @access_token)
146
+ else
147
+ headers = default_headers
148
+ headers['X-Gowalla-API-Key'] = api_key if api_key
149
+ @connection ||= Faraday::Connection.new \
150
+ :url => "http://api.gowalla.com",
151
+ :headers => headers
152
+ end
128
153
  end
129
154
 
155
+ # Provides raw access to the OAuth2 Client
156
+ #
157
+ # @return [OAuth2::Client]
158
+ def oauth_client
159
+ if @oauth_client
160
+ @oauth_client
161
+ else
162
+ conn ||= Faraday::Connection.new \
163
+ :url => "https://api.gowalla.com",
164
+ :headers => default_headers
165
+
166
+ oauth= OAuth2::Client.new(api_key, api_secret, oauth_options = {
167
+ :site => 'https://api.gowalla.com',
168
+ :authorize_url => 'https://gowalla.com/api/oauth/new',
169
+ :access_token_url => 'https://gowalla.com/api/oauth/token'
170
+ })
171
+ oauth.connection = conn
172
+ oauth
173
+ end
174
+ end
175
+
130
176
  private
131
177
 
178
+ # @private
132
179
  def format_geo_options(options={})
133
180
  options[:lat] = "+#{options[:lat]}" if options[:lat].to_i > 0
134
181
  options[:lng] = "+#{options[:lng]}" if options[:lng].to_i > 0
@@ -137,21 +184,33 @@ module Gowalla
137
184
  end
138
185
  options
139
186
  end
140
-
141
- def mashup(response)
142
- case response.code
187
+
188
+ # @private
189
+ def default_headers
190
+ headers = {
191
+ :accept => 'application/json',
192
+ :user_agent => 'Ruby gem'
193
+ }
194
+ end
195
+
196
+ # @private
197
+ def handle_response(response)
198
+ case response.status
143
199
  when 200
144
- if response.is_a?(Hash)
145
- Hashie::Mash.new(response)
200
+ body = response.respond_to?(:body) ? response.body : response
201
+ data = MultiJson.decode(body)
202
+ if data.is_a?(Hash)
203
+ Hashie::Mash.new(data)
146
204
  else
147
- if response.first.is_a?(Hash)
148
- response.map{|item| Hashie::Mash.new(item)}
205
+ if data.first.is_a?(Hash)
206
+ data.map{|item| Hashie::Mash.new(item)}
149
207
  else
150
- response
208
+ data
151
209
  end
152
210
  end
153
211
  end
154
212
  end
213
+
155
214
 
156
215
  end
157
216
 
@@ -0,0 +1,168 @@
1
+ require 'helper'
2
+
3
+ class GowallaTest < Test::Unit::TestCase
4
+
5
+ context "When using the Gowalla API" do
6
+ setup do
7
+ @client = Gowalla::Client.new(:username => 'pengwynn', :password => '0U812', :api_key => 'gowallawallabingbang')
8
+ end
9
+
10
+ context "and working with Spots" do
11
+ should "Retrieve a list of spots within a specified distance of a location" do
12
+ stub_get("http://pengwynn:0U812@api.gowalla.com/spots?lat=%2B33.237593417&lng=-96.960559033&radius=50", "spots.json")
13
+ spots = @client.list_spots(:lat => 33.237593417, :lng => -96.960559033, :radius => 50)
14
+ spots.first.name.should == 'Gnomb Bar'
15
+ spots.first.radius_meters.should == 50
16
+ end
17
+
18
+ should "Retrieve a list of spots within a specified bounds" do
19
+ stub_get("http://pengwynn:0U812@api.gowalla.com/spots?sw=%2839.25565142103586%2C%20-8.717308044433594%29&nw=%2839.31411296530539%2C%20-8.490715026855469%29", "spots.json")
20
+ spots = @client.list_spots(:sw => "(39.25565142103586, -8.717308044433594)", :nw => "(39.31411296530539, -8.490715026855469)")
21
+ spots.first.name.should == 'Gnomb Bar'
22
+ end
23
+
24
+ should "Retrieve information about a specific spot" do
25
+ stub_get('http://pengwynn:0U812@api.gowalla.com/spots/18568', 'spot.json')
26
+ spot = @client.spot(18568)
27
+ spot.name.should == "Wahoo's"
28
+ spot.twitter_username.should == 'Wahoos512'
29
+ spot.spot_categories.first.name.should == 'Mexican'
30
+ end
31
+
32
+ should "retrieve a list of check-ins at a particular spot. Shows only the activity that is visible to a given user" do
33
+ stub_get('http://pengwynn:0U812@api.gowalla.com/spots/452593/events', 'events.json')
34
+ events = @client.spot_events(452593)
35
+ events.first[:type].should == 'checkin'
36
+ events.first.user.last_name.should == 'Mack'
37
+ end
38
+
39
+ should "retrieve a list of items available at a particular spot" do
40
+ stub_get('http://pengwynn:0U812@api.gowalla.com/spots/18568/items', 'items.json')
41
+ items = @client.spot_items(18568)
42
+ items.first.issue_number.should == 27868
43
+ items.first.name.should == 'Bowl of Noodles'
44
+ end
45
+
46
+ should "lists all spot categories" do
47
+ stub_get("http://pengwynn:0U812@api.gowalla.com/categories", "categories.json")
48
+ categories = @client.categories
49
+ categories.size.should == 9
50
+ categories.first.name.should == 'Architecture & Buildings'
51
+ categories.first.description.should == 'Bridge, Corporate, Home, Church, etc.'
52
+ categories.first.spot_categories.size.should == 15
53
+ categories.first.spot_categories.first.name.should == 'Bridge'
54
+ end
55
+
56
+ should "retrieve information about a specific category" do
57
+ stub_get("http://pengwynn:0U812@api.gowalla.com/categories/1", "category.json")
58
+ category = @client.category(1)
59
+ category.name.should == 'Coffee Shop'
60
+ end
61
+ end
62
+
63
+ context "and working with Users" do
64
+
65
+ should "retrieve information about a specific user" do
66
+ stub_get('http://pengwynn:0U812@api.gowalla.com/users/sco', 'user.json')
67
+ user = @client.user('sco')
68
+ user.bio.should == "CTO & co-founder of Gowalla. Ruby/Cocoa/JavaScript developer. Game designer. Author. Indoorsman."
69
+ user.stamps_count.should == 506
70
+ end
71
+
72
+ should "retrieve a list of the stamps the user has collected" do
73
+ stub_get('http://pengwynn:0U812@api.gowalla.com/users/1707/stamps?limit=20', 'stamps.json')
74
+ stamps = @client.stamps(1707)
75
+ stamps.size.should == 20
76
+ stamps.first.spot.name.should == "Muck-N-Dave's Texas BBQ"
77
+ stamps.first.spot.address.locality.should == 'Austin'
78
+ end
79
+
80
+ should "retrieve a list of spots the user has visited most often" do
81
+ stub_get('http://pengwynn:0U812@api.gowalla.com/users/1707/top_spots', 'top_spots.json')
82
+ top_spots = @client.top_spots(1707)
83
+ top_spots.size.should == 10
84
+ top_spots.first.name.should == 'Juan Pelota Cafe'
85
+ top_spots.first.user_checkins_count.should == 30
86
+ end
87
+
88
+ end
89
+
90
+ context "and working with Items" do
91
+ should "retrieve information about a specific item" do
92
+ stub_get('http://pengwynn:0U812@api.gowalla.com/items/607583', 'item.json')
93
+ item = @client.item(607583)
94
+ item.issue_number.should == 13998
95
+ item.name.should == 'Sweets'
96
+ item.determiner.should == 'some'
97
+ end
98
+ end
99
+
100
+ context "and working with Trips" do
101
+ should "retrieve a list of trips" do
102
+ stub_get('http://pengwynn:0U812@api.gowalla.com/trips', 'trips.json')
103
+ trips = @client.trips
104
+ trips.first.name.should == 'London Pub Crawl'
105
+ trips.first.spots.first.url.should == '/spots/164009'
106
+ end
107
+
108
+ should "retrieve information about a specific trip" do
109
+ stub_get('http://pengwynn:0U812@api.gowalla.com/trips/1', 'trip.json')
110
+ trip = @client.trip(1)
111
+ trip.creator.last_name.should == 'Gowalla'
112
+ trip.map_bounds.east.should == -63.457031
113
+ end
114
+ end
115
+
116
+ end
117
+
118
+ context "when using basic auth" do
119
+ should "configure api_key, username, and password for easy access" do
120
+
121
+ Gowalla.configure do |config|
122
+ config.api_key = 'api_key'
123
+ config.api_secret = nil
124
+ config.username = 'username'
125
+ config.password = 'password'
126
+ end
127
+
128
+ @client = Gowalla::Client.new
129
+
130
+ stub_get('http://username:password@api.gowalla.com/trips', 'trips.json')
131
+ trips = @client.trips
132
+
133
+ @client.username.should == 'username'
134
+ end
135
+ end
136
+
137
+ context "when using OAuth2" do
138
+
139
+ setup do
140
+ Gowalla.configure do |config|
141
+ config.api_key = 'api_key'
142
+ config.api_secret = 'api_secret'
143
+ end
144
+
145
+ @client = Gowalla::Client.new
146
+ end
147
+
148
+ should "confiure api_key, api_secret" do
149
+ @client.api_secret.should == 'api_secret'
150
+ @client.oauth_client.id.should == 'api_key'
151
+ end
152
+
153
+ should "create an OAuth2 client" do
154
+ @client.oauth_client.class.to_s.should == "OAuth2::Client"
155
+ end
156
+
157
+ should "create an OAuth2 connection" do
158
+ @client.connection.class.to_s.should == "OAuth2::AccessToken"
159
+ end
160
+
161
+ should "indicate if it needs an access_token" do
162
+ @client.needs_access?.should == true
163
+ end
164
+
165
+ end
166
+
167
+
168
+ end