angellist_api 1.0.5 → 1.0.6
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/CHANGELOG.md +8 -0
- data/lib/angellist_api/client/activity_feeds.rb +7 -0
- data/lib/angellist_api/client/follows.rb +19 -8
- data/lib/angellist_api/client/messages.rb +2 -1
- data/lib/angellist_api/client/paths.rb +1 -0
- data/lib/angellist_api/client/press.rb +1 -0
- data/lib/angellist_api/client/reviews.rb +1 -0
- data/lib/angellist_api/client/tags.rb +9 -4
- data/lib/angellist_api/client/users.rb +2 -0
- data/lib/angellist_api/error.rb +10 -6
- data/lib/angellist_api/error/too_many_requests.rb +26 -0
- data/lib/angellist_api/response/raise_client_error.rb +7 -4
- data/lib/angellist_api/version.rb +1 -1
- data/spec/fixtures/cassettes/errors/forbidden.yml +53 -0
- data/spec/fixtures/cassettes/errors/too_many_requests.yml +53 -0
- data/spec/integration/errors_spec.rb +24 -0
- data/spec/support/http_headers.rb +8 -0
- data/spec/unit/lib/angellist_api/client/follows_spec.rb +12 -4
- data/spec/unit/lib/angellist_api/client/tags_spec.rb +6 -2
- data/spec/unit/lib/angellist_api/error_spec.rb +92 -83
- metadata +13 -5
- data/lib/angellist_api/error/enhance_your_calm.rb +0 -13
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
## Master
|
2
2
|
|
3
|
+
## 1.0.6 - 14 April, 2013
|
4
|
+
|
5
|
+
- Properly raise a `TooManyRequests` error when a 403 contains a JSON error
|
6
|
+
object indicating rate limit overage (`EnhanceYourCalm` error aliased for
|
7
|
+
backwards compatibility) ([Ches Martin])
|
8
|
+
- Add missing options parameters for passing pagination params to endpoints that
|
9
|
+
support them ([Ches Martin])
|
10
|
+
|
3
11
|
## 1.0.5 - 27 March, 2013
|
4
12
|
|
5
13
|
- Fix inability to pass direction param for startup_roles ([Ches Martin])
|
@@ -11,11 +11,18 @@ module AngellistApi
|
|
11
11
|
# paginated and ordered by most recent story first.
|
12
12
|
#
|
13
13
|
# @requires_authentication Optional
|
14
|
+
# @paginated By explicit timestamp cursor
|
14
15
|
#
|
15
16
|
# @param options [Hash] A customizable set of options.
|
16
17
|
# @option options [Integer] :personalized If set to 1 and a user is
|
17
18
|
# authenticated, only activity from the authenticated user's social graph
|
18
19
|
# is returned.
|
20
|
+
# @option options [Integer] :since If a Unix timestamp is passed in via
|
21
|
+
# this parameter, only activity since that timestamp will be returned. A
|
22
|
+
# maximum of 25 items will be returned, starting with the oldest item. A
|
23
|
+
# cursor variable is also returned, which is the timestamp of the last
|
24
|
+
# item. You may call /feed again with since set to this value to get the
|
25
|
+
# next page of activity.
|
19
26
|
#
|
20
27
|
# @example
|
21
28
|
# AngellistApi.get_feed
|
@@ -38,6 +38,7 @@ module AngellistApi
|
|
38
38
|
# follow ids, such as those from the activity feed.
|
39
39
|
#
|
40
40
|
# @requires_authentication Optional
|
41
|
+
# @paginated No
|
41
42
|
#
|
42
43
|
# @param ids [Array] IDs of the follows to fetch.
|
43
44
|
#
|
@@ -52,26 +53,30 @@ module AngellistApi
|
|
52
53
|
# follower first.
|
53
54
|
#
|
54
55
|
# @requires_authentication No
|
56
|
+
# @paginated Yes
|
55
57
|
#
|
56
58
|
# @param [Integer] id The id of the given user.
|
59
|
+
# @param [Hash] options A customizable set of options.
|
57
60
|
#
|
58
61
|
# @example Get followers of user with ID 12345.
|
59
62
|
# AngellistApi.get_user_followers(12345)
|
60
|
-
def get_user_followers(id)
|
61
|
-
get("1/users/#{id}/followers")
|
63
|
+
def get_user_followers(id, options={})
|
64
|
+
get("1/users/#{id}/followers", options)
|
62
65
|
end
|
63
66
|
|
64
67
|
# Return the ids of the given user's followers, paginated and ordered by
|
65
68
|
# most recent follower first.
|
66
69
|
#
|
67
70
|
# @requires_authentication No
|
71
|
+
# @paginated Yes
|
68
72
|
#
|
69
73
|
# @param [Integer] id The id of the given user.
|
74
|
+
# @param [Hash] options A customizable set of options.
|
70
75
|
#
|
71
76
|
# @example Get IDs of the followers of user with ID 12345.
|
72
77
|
# AngellistApi.get_user_follower_ids(12345)
|
73
|
-
def get_user_follower_ids(id)
|
74
|
-
get("1/users/#{id}/followers/ids")
|
78
|
+
def get_user_follower_ids(id, options={})
|
79
|
+
get("1/users/#{id}/followers/ids", options)
|
75
80
|
end
|
76
81
|
|
77
82
|
# Return objects that the given user is following, paginated and ordered
|
@@ -79,6 +84,7 @@ module AngellistApi
|
|
79
84
|
# class of objects to return.
|
80
85
|
#
|
81
86
|
# @requires_authentication Optional
|
87
|
+
# @paginated Yes
|
82
88
|
#
|
83
89
|
# @param [Integer] id The id of the given user.
|
84
90
|
# @param [Hash] options A customizable set of options.
|
@@ -96,6 +102,7 @@ module AngellistApi
|
|
96
102
|
# /users/:id/followers/ids.
|
97
103
|
#
|
98
104
|
# @requires_authentication Optional
|
105
|
+
# @paginated Yes
|
99
106
|
#
|
100
107
|
# @param [Integer] id The id of the given user.
|
101
108
|
# @param [Hash] options A customizable set of options.
|
@@ -111,26 +118,30 @@ module AngellistApi
|
|
111
118
|
# recent follower first. Responds like GET /users/:id/followers.
|
112
119
|
#
|
113
120
|
# @requires_authentication Optional
|
121
|
+
# @paginated Yes
|
114
122
|
#
|
115
123
|
# @param [Integer] id The id of the given startup.
|
124
|
+
# @param [Hash] options A customizable set of options.
|
116
125
|
#
|
117
126
|
# @example Get followers of startup with ID 1234.
|
118
127
|
# AngellistApi.get_startup_followers(1234)
|
119
|
-
def get_startup_followers(id)
|
120
|
-
get("1/startups/#{id}/followers")
|
128
|
+
def get_startup_followers(id, options={})
|
129
|
+
get("1/startups/#{id}/followers", options)
|
121
130
|
end
|
122
131
|
|
123
132
|
# Returns the ids of the given startup's followers, paginated and ordered
|
124
133
|
# by most recent follower first. Responds like GET /users/:id/followers.
|
125
134
|
#
|
126
135
|
# @requires_authentication Optional
|
136
|
+
# @paginated Yes
|
127
137
|
#
|
128
138
|
# @param [Integer] id The id of the given user.
|
139
|
+
# @param [Hash] options A customizable set of options.
|
129
140
|
#
|
130
141
|
# @example Get IDs of followers of startup with ID 1234.
|
131
142
|
# AngellistApi.get_startup_follower_ids(1234)
|
132
|
-
def get_startup_follower_ids(id)
|
133
|
-
get("1/startups/#{id}/followers/ids")
|
143
|
+
def get_startup_follower_ids(id, options={})
|
144
|
+
get("1/startups/#{id}/followers/ids", options)
|
134
145
|
end
|
135
146
|
end
|
136
147
|
end
|
@@ -8,7 +8,8 @@ module AngellistApi
|
|
8
8
|
# Returns threads that the authenticated user is involved in. A "thread"
|
9
9
|
# is a conversation between two users, where each message is tagged with
|
10
10
|
# the same thread_id. If the authenticated user has any unread messages
|
11
|
-
#in the thread, the viewed attribute will be false. Requires scope
|
11
|
+
# in the thread, the viewed attribute will be false. Requires scope
|
12
|
+
# "message".
|
12
13
|
#
|
13
14
|
# @requires_authentication Yes
|
14
15
|
# @paginated Yes
|
@@ -13,6 +13,7 @@ module AngellistApi
|
|
13
13
|
# - do not use user_ids and startup_ids at the same time
|
14
14
|
#
|
15
15
|
# @requires_authentication Yes
|
16
|
+
# @paginated No
|
16
17
|
#
|
17
18
|
# @param options [Hash] A customizable set of options.
|
18
19
|
# @option options [Array<Integer>] :user_ids Show paths between you and
|
@@ -9,6 +9,7 @@ module AngellistApi
|
|
9
9
|
# Also returns the total count of positive reviews.
|
10
10
|
#
|
11
11
|
# @requires_authentication Optional
|
12
|
+
# @paginated Yes
|
12
13
|
#
|
13
14
|
# @param [Hash] options A customizable set of options.
|
14
15
|
# @option options [Integer] :user_id user_id of the desired user. If none
|
@@ -21,28 +21,32 @@ module AngellistApi
|
|
21
21
|
# descending.
|
22
22
|
#
|
23
23
|
# @requires_authentication No
|
24
|
+
# @paginated Yes
|
24
25
|
#
|
25
26
|
# @param [Integer] id The id of the desired tag. Currently only works for
|
26
27
|
# tags of type MarketTag or LocationTag.
|
28
|
+
# @param [Hash] options A customizable set of options.
|
27
29
|
#
|
28
30
|
# @example Get children of a tag.
|
29
31
|
# AngellistApi.get_tag_children(1654)
|
30
|
-
def get_tag_children(id)
|
31
|
-
get("1/tags/#{id}/children")
|
32
|
+
def get_tag_children(id, options={})
|
33
|
+
get("1/tags/#{id}/children", options)
|
32
34
|
end
|
33
35
|
|
34
36
|
# Returns parents of the given tag. For more details, see the
|
35
37
|
# documentation for GET /tags/:id/children.
|
36
38
|
#
|
37
39
|
# @requires_authentication No
|
40
|
+
# @paginated Yes
|
38
41
|
#
|
39
42
|
# @param [Integer] id The id of the desired tag. Currently only works for
|
40
43
|
# tags of type MarketTag or LocationTag.
|
44
|
+
# @param [Hash] options A customizable set of options.
|
41
45
|
#
|
42
46
|
# @example Get parents of a tag.
|
43
47
|
# AngellistApi.get_tag_parents(1654)
|
44
|
-
def get_tag_parents(id)
|
45
|
-
get("1/tags/#{id}/parents")
|
48
|
+
def get_tag_parents(id, options={})
|
49
|
+
get("1/tags/#{id}/parents", options)
|
46
50
|
end
|
47
51
|
|
48
52
|
# Returns startups that are tagged with the given tag or a child of the
|
@@ -50,6 +54,7 @@ module AngellistApi
|
|
50
54
|
# parameter.
|
51
55
|
#
|
52
56
|
# @requires_authentication Optional
|
57
|
+
# @paginated Yes
|
53
58
|
#
|
54
59
|
# @param [Hash] options A customizable set of options.
|
55
60
|
# @option options [String] :order May be one of popularity, asc or desc.
|
@@ -19,6 +19,7 @@ module AngellistApi
|
|
19
19
|
# Get information for a batch of up to 50 users given a list of user IDs.
|
20
20
|
#
|
21
21
|
# @requires_authentication No
|
22
|
+
# @pagination No
|
22
23
|
#
|
23
24
|
# @param [Array] ids IDs of the users to fetch.
|
24
25
|
#
|
@@ -32,6 +33,7 @@ module AngellistApi
|
|
32
33
|
# Search for a user given a URL slug. Responds like GET /users/:id.
|
33
34
|
#
|
34
35
|
# @requires_authentication No
|
36
|
+
# @pagination No
|
35
37
|
#
|
36
38
|
# @param [Hash] options A customizable set of options.
|
37
39
|
# @option options [String] :slug The URL slug of the desired user.
|
data/lib/angellist_api/error.rb
CHANGED
@@ -8,29 +8,33 @@ module AngellistApi
|
|
8
8
|
# @param [String] message
|
9
9
|
# @param [Hash] http_headers
|
10
10
|
# @return [AngellistApi::Error]
|
11
|
-
def initialize(message, http_headers)
|
12
|
-
@http_headers =
|
11
|
+
def initialize(message, http_headers={})
|
12
|
+
@http_headers = http_headers
|
13
13
|
super message
|
14
14
|
end
|
15
15
|
|
16
16
|
# @return [Time]
|
17
17
|
def ratelimit_reset
|
18
|
-
|
18
|
+
reset = http_headers['x-ratelimit-reset']
|
19
|
+
Time.at(reset.to_i) if reset
|
19
20
|
end
|
20
21
|
|
21
22
|
# @return [Integer]
|
22
23
|
def ratelimit_limit
|
23
|
-
|
24
|
+
limit = http_headers['x-ratelimit-limit']
|
25
|
+
limit.to_i if limit
|
24
26
|
end
|
25
27
|
|
26
28
|
# @return [Integer]
|
27
29
|
def ratelimit_remaining
|
28
|
-
|
30
|
+
remaining = http_headers['x-ratelimit-remaining']
|
31
|
+
remaining.to_i if remaining
|
29
32
|
end
|
30
33
|
|
31
34
|
# @return [Integer]
|
32
35
|
def retry_after
|
33
|
-
[(ratelimit_reset - Time.now).ceil, 0].max
|
36
|
+
[(ratelimit_reset - Time.now).ceil, 0].max if ratelimit_reset
|
34
37
|
end
|
35
38
|
end
|
36
39
|
end
|
40
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'angellist_api/error'
|
2
|
+
|
3
|
+
module AngellistApi
|
4
|
+
# Raised when AngellistApi returns the HTTP status code 403 with "over_limit"
|
5
|
+
# in the response.
|
6
|
+
#
|
7
|
+
# @note We've inquired with the AngelList API team about using a 429 status
|
8
|
+
# in the future.
|
9
|
+
class Error
|
10
|
+
class TooManyRequests < AngellistApi::Error
|
11
|
+
# The number of seconds your application should wait before requesting data
|
12
|
+
# from the API again.
|
13
|
+
#
|
14
|
+
# This may not be supported by AngelList currently but is suggested in RFC
|
15
|
+
# 6585 for the 429 status code.
|
16
|
+
def retry_after
|
17
|
+
retry_after = http_headers['retry-after']
|
18
|
+
retry_after.to_i if retry_after
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# Backwards compatability
|
23
|
+
EnhanceYourCalm = TooManyRequests
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'faraday'
|
2
2
|
require 'angellist_api/error/bad_request'
|
3
|
-
require 'angellist_api/error/
|
3
|
+
require 'angellist_api/error/too_many_requests'
|
4
4
|
require 'angellist_api/error/forbidden'
|
5
5
|
require 'angellist_api/error/not_acceptable'
|
6
6
|
require 'angellist_api/error/not_found'
|
@@ -16,13 +16,15 @@ module AngellistApi
|
|
16
16
|
when 401
|
17
17
|
raise AngellistApi::Error::Unauthorized.new(error_message(env), env[:response_headers])
|
18
18
|
when 403
|
19
|
-
|
19
|
+
if env[:body]['error'] == 'over_limit'
|
20
|
+
raise AngellistApi::Error::TooManyRequests.new(error_message(env), env[:response_headers])
|
21
|
+
else
|
22
|
+
raise AngellistApi::Error::Forbidden.new(error_message(env), env[:response_headers])
|
23
|
+
end
|
20
24
|
when 404
|
21
25
|
raise AngellistApi::Error::NotFound.new(error_message(env), env[:response_headers])
|
22
26
|
when 406
|
23
27
|
raise AngellistApi::Error::NotAcceptable.new(error_message(env), env[:response_headers])
|
24
|
-
when 420
|
25
|
-
raise AngellistApi::Error::EnhanceYourCalm.new(error_message(env), env[:response_headers])
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
@@ -49,3 +51,4 @@ module AngellistApi
|
|
49
51
|
end
|
50
52
|
end
|
51
53
|
end
|
54
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://api.angel.co/1/me
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- application/json
|
12
|
+
User-Agent:
|
13
|
+
- AngellistApi Ruby Gem 1.0.5
|
14
|
+
Authorization:
|
15
|
+
- Bearer <ANGELLIST_ACCESS_TOKEN>
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 403
|
19
|
+
message: !!null
|
20
|
+
headers:
|
21
|
+
server:
|
22
|
+
- nginx/1.0.6
|
23
|
+
date:
|
24
|
+
- Sun, 14 Apr 2013 06:45:44 GMT
|
25
|
+
content-type:
|
26
|
+
- application/json; charset=utf-8
|
27
|
+
transfer-encoding:
|
28
|
+
- chunked
|
29
|
+
connection:
|
30
|
+
- close
|
31
|
+
vary:
|
32
|
+
- Accept-Encoding, Accept-Encoding
|
33
|
+
status:
|
34
|
+
- '403'
|
35
|
+
x-ratelimit-limit:
|
36
|
+
- '2000'
|
37
|
+
x-ratelimit-remaining:
|
38
|
+
- '2000'
|
39
|
+
x-thanks:
|
40
|
+
- For using AngelList. Rock on.
|
41
|
+
x-runtime:
|
42
|
+
- '35'
|
43
|
+
etag:
|
44
|
+
- ! '"0c13384ccaf0ae7c9e1ff289e0070619"'
|
45
|
+
cache-control:
|
46
|
+
- private, max-age=0, must-revalidate
|
47
|
+
body:
|
48
|
+
encoding: ASCII-8BIT
|
49
|
+
string: ! '{"error":"forbidden","error_description":""}'
|
50
|
+
http_version: !!null
|
51
|
+
recorded_at: Sun, 14 Apr 2013 06:45:44 GMT
|
52
|
+
recorded_with: VCR 2.4.0
|
53
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://api.angel.co/1/me
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept:
|
11
|
+
- application/json
|
12
|
+
User-Agent:
|
13
|
+
- AngellistApi Ruby Gem 1.0.5
|
14
|
+
Authorization:
|
15
|
+
- Bearer <ANGELLIST_ACCESS_TOKEN>
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 403
|
19
|
+
message: !!null
|
20
|
+
headers:
|
21
|
+
server:
|
22
|
+
- nginx/1.0.6
|
23
|
+
date:
|
24
|
+
- Sun, 14 Apr 2013 06:45:44 GMT
|
25
|
+
content-type:
|
26
|
+
- application/json; charset=utf-8
|
27
|
+
transfer-encoding:
|
28
|
+
- chunked
|
29
|
+
connection:
|
30
|
+
- close
|
31
|
+
vary:
|
32
|
+
- Accept-Encoding, Accept-Encoding
|
33
|
+
status:
|
34
|
+
- '403'
|
35
|
+
x-ratelimit-limit:
|
36
|
+
- '2000'
|
37
|
+
x-ratelimit-remaining:
|
38
|
+
- '0'
|
39
|
+
x-thanks:
|
40
|
+
- For using AngelList. Rock on.
|
41
|
+
x-runtime:
|
42
|
+
- '35'
|
43
|
+
etag:
|
44
|
+
- ! '"0c13384ccaf0ae7c9e1ff289e0070619"'
|
45
|
+
cache-control:
|
46
|
+
- private, max-age=0, must-revalidate
|
47
|
+
body:
|
48
|
+
encoding: ASCII-8BIT
|
49
|
+
string: ! '{"error":"over_limit","error_description":"You are currently over your rate limit."}'
|
50
|
+
http_version: !!null
|
51
|
+
recorded_at: Sun, 14 Apr 2013 06:45:44 GMT
|
52
|
+
recorded_with: VCR 2.4.0
|
53
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Errors' do
|
4
|
+
let(:client) { AngellistApi::Client.new }
|
5
|
+
|
6
|
+
describe AngellistApi::Error::TooManyRequests do
|
7
|
+
context 'when response is an over rate limit error',
|
8
|
+
:vcr => { :cassette_name => 'errors/too_many_requests' } do
|
9
|
+
|
10
|
+
it 'is raised' do
|
11
|
+
expect { client.me }.to raise_error described_class
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'when response is some other 403 Forbidden error',
|
16
|
+
:vcr => { :cassette_name => 'errors/forbidden' } do
|
17
|
+
|
18
|
+
it 'is not raised' do
|
19
|
+
expect { client.me }.to raise_error AngellistApi::Error::Forbidden
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -32,7 +32,9 @@ describe AngellistApi::Client::Follows do
|
|
32
32
|
describe "#get_user_followers" do
|
33
33
|
it "gets 1/users/<id>/followers" do
|
34
34
|
id = "123"
|
35
|
-
client.should_receive(:get).
|
35
|
+
client.should_receive(:get).
|
36
|
+
with("1/users/#{id}/followers", {}).
|
37
|
+
and_return("success")
|
36
38
|
client.get_user_followers(id).should == "success"
|
37
39
|
end
|
38
40
|
end
|
@@ -40,7 +42,9 @@ describe AngellistApi::Client::Follows do
|
|
40
42
|
describe "#get_user_follower_ids" do
|
41
43
|
it "gets 1/users/<id>/followers/ids" do
|
42
44
|
id = "123"
|
43
|
-
client.should_receive(:get).
|
45
|
+
client.should_receive(:get).
|
46
|
+
with("1/users/#{id}/followers/ids", {}).
|
47
|
+
and_return("success")
|
44
48
|
client.get_user_follower_ids(id).should == "success"
|
45
49
|
end
|
46
50
|
end
|
@@ -66,7 +70,9 @@ describe AngellistApi::Client::Follows do
|
|
66
70
|
describe "#get_startup_followers" do
|
67
71
|
it "gets 1/startups/<id>/followers" do
|
68
72
|
id = "123"
|
69
|
-
client.should_receive(:get).
|
73
|
+
client.should_receive(:get).
|
74
|
+
with("1/startups/#{id}/followers", {}).
|
75
|
+
and_return("success")
|
70
76
|
client.get_startup_followers(id).should == "success"
|
71
77
|
end
|
72
78
|
end
|
@@ -74,7 +80,9 @@ describe AngellistApi::Client::Follows do
|
|
74
80
|
describe "#get_startup_follower_ids" do
|
75
81
|
it "gets 1/startups/<id>/followers/ids" do
|
76
82
|
id = "123"
|
77
|
-
client.should_receive(:get).
|
83
|
+
client.should_receive(:get).
|
84
|
+
with("1/startups/#{id}/followers/ids", {}).
|
85
|
+
and_return("success")
|
78
86
|
client.get_startup_follower_ids(id).should == "success"
|
79
87
|
end
|
80
88
|
end
|
@@ -14,7 +14,9 @@ describe AngellistApi::Client::Tags do
|
|
14
14
|
describe "#get_tag_children" do
|
15
15
|
it "gets 1/tags/<id>/children" do
|
16
16
|
id = "123"
|
17
|
-
client.should_receive(:get).
|
17
|
+
client.should_receive(:get).
|
18
|
+
with("1/tags/#{id}/children", {}).
|
19
|
+
and_return("success")
|
18
20
|
client.get_tag_children(id).should == "success"
|
19
21
|
end
|
20
22
|
end
|
@@ -22,7 +24,9 @@ describe AngellistApi::Client::Tags do
|
|
22
24
|
describe "#get_tag_parents" do
|
23
25
|
it "gets 1/tags/<id>/parents" do
|
24
26
|
id = "123"
|
25
|
-
client.should_receive(:get).
|
27
|
+
client.should_receive(:get).
|
28
|
+
with("1/tags/#{id}/parents", {}).
|
29
|
+
and_return("success")
|
26
30
|
client.get_tag_parents(id).should == "success"
|
27
31
|
end
|
28
32
|
end
|
@@ -1,124 +1,133 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe AngellistApi::Error do
|
4
|
+
include HttpHeaders
|
4
5
|
|
5
|
-
describe
|
6
|
-
|
7
|
-
|
8
|
-
expect { AngellistApi::Error.new(nil, :header => "data") }.to_not raise_error
|
9
|
-
end
|
10
|
-
|
11
|
-
it "builds an error with the given message" do
|
12
|
-
error = AngellistApi::Error.new("bad data", :header => 'data')
|
13
|
-
error.message.should == "bad data"
|
14
|
-
end
|
6
|
+
describe '#new' do
|
7
|
+
specify 'message parameter can be nil' do
|
8
|
+
expect { AngellistApi::Error.new(nil, :header => 'data') }.to_not raise_error
|
15
9
|
end
|
16
10
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
it "raises an exception if the params cant be converted to a hash" do
|
23
|
-
expect { AngellistApi::Error.new("some message", "header") }.to raise_error(ArgumentError, "odd number of arguments for Hash")
|
24
|
-
end
|
11
|
+
it 'builds an error with the given message' do
|
12
|
+
error = AngellistApi::Error.new('bad data', :header => 'data')
|
13
|
+
error.message.should == 'bad data'
|
14
|
+
end
|
25
15
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
16
|
+
it 'sets http_headers attribute' do
|
17
|
+
error = AngellistApi::Error.new('some message', :some => 'value')
|
18
|
+
error.http_headers.should == { :some => 'value' }
|
30
19
|
end
|
31
20
|
end
|
32
21
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
22
|
+
# NOTE: AngelList doesn't actually support this yet...
|
23
|
+
describe '#ratelimit_reset' do
|
24
|
+
subject { described_class.new('message', headers).ratelimit_reset }
|
25
|
+
|
26
|
+
context 'with X-RateLimit-Reset header set' do
|
27
|
+
let(:unixtime) { Time.now.to_i }
|
28
|
+
let(:headers) { headerize('X-RateLimit-Reset' => unixtime) }
|
40
29
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
error.ratelimit_reset.should == Time.at(time)
|
30
|
+
it 'returns the time of reset' do
|
31
|
+
subject.should == Time.at(unixtime)
|
32
|
+
end
|
45
33
|
end
|
46
34
|
|
47
|
-
|
48
|
-
|
49
|
-
|
35
|
+
context 'with X-RateLimit-Reset unset' do
|
36
|
+
let(:headers) { headerize({}) }
|
37
|
+
it { should be_nil }
|
50
38
|
end
|
51
39
|
end
|
52
40
|
|
53
|
-
describe
|
54
|
-
|
55
|
-
error = AngellistApi::Error.new("message", {'x-ratelimit-limit' => 500, 'X-RateLimit-Limit' => 400})
|
56
|
-
error.ratelimit_limit.should == 500
|
57
|
-
end
|
41
|
+
describe '#ratelimit_limit' do
|
42
|
+
subject { described_class.new('message', headers).ratelimit_limit }
|
58
43
|
|
59
|
-
|
60
|
-
|
61
|
-
|
44
|
+
context 'with X-RateLimit-Limit header set' do
|
45
|
+
let(:limit) { '1000' }
|
46
|
+
let(:headers) { headerize('X-RateLimit-Limit' => limit) }
|
47
|
+
|
48
|
+
it 'returns the limit as an integer' do
|
49
|
+
subject.should eq 1000
|
50
|
+
end
|
62
51
|
end
|
63
52
|
|
64
|
-
|
65
|
-
|
66
|
-
|
53
|
+
context 'with X-RateLimit-Limit unset' do
|
54
|
+
let(:headers) { headerize({}) }
|
55
|
+
it { should be_nil }
|
67
56
|
end
|
68
57
|
end
|
69
58
|
|
70
|
-
describe
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
59
|
+
describe '#ratelimit_remaining' do
|
60
|
+
subject { described_class.new('message', headers).ratelimit_remaining }
|
61
|
+
|
62
|
+
context 'with X-RateLimit-Remaining header set' do
|
63
|
+
let(:remaining) { '22' }
|
64
|
+
let(:headers) { headerize('X-RateLimit-Remaining' => remaining) }
|
75
65
|
|
76
|
-
|
77
|
-
|
78
|
-
|
66
|
+
it 'returns remaining request count as an integer' do
|
67
|
+
subject.should eq 22
|
68
|
+
end
|
79
69
|
end
|
80
70
|
|
81
|
-
|
82
|
-
|
83
|
-
|
71
|
+
context 'with X-RateLimit-Remaining unset' do
|
72
|
+
let(:headers) { headerize({}) }
|
73
|
+
it { should be_nil }
|
84
74
|
end
|
85
75
|
end
|
86
76
|
|
87
|
-
|
88
|
-
|
89
|
-
|
77
|
+
# NOTE: AngelList doesn't actually support this yet...
|
78
|
+
describe '#retry_after' do
|
79
|
+
subject { described_class.new('message', headerize({})).retry_after }
|
80
|
+
let(:now) { Time.now }
|
81
|
+
|
82
|
+
before { Timecop.freeze(now) }
|
83
|
+
after { Timecop.return }
|
90
84
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
85
|
+
context 'when limit reset time is known' do
|
86
|
+
let(:reset_at) { now + 3600 }
|
87
|
+
|
88
|
+
before do
|
89
|
+
described_class.any_instance.stub(:ratelimit_reset).and_return(reset_at)
|
96
90
|
end
|
97
91
|
|
98
|
-
it
|
99
|
-
|
100
|
-
error.should_receive(:ratelimit_reset) { Time.now - 3600 }
|
101
|
-
error.retry_after.should == 0
|
102
|
-
end
|
92
|
+
it 'gives time in seconds until it is acceptable to make another call' do
|
93
|
+
subject.should eq reset_at - now
|
103
94
|
end
|
104
95
|
end
|
105
96
|
|
106
|
-
context
|
107
|
-
it
|
108
|
-
|
109
|
-
error.retry_after.should == 12
|
110
|
-
end
|
97
|
+
context 'when limit reset time is not known' do
|
98
|
+
it { should be_nil }
|
99
|
+
end
|
111
100
|
|
112
|
-
|
113
|
-
|
114
|
-
error.retry_after.should == 16
|
115
|
-
end
|
101
|
+
context 'when limit reset time is past' do
|
102
|
+
let(:reset_at) { now - 3600 }
|
116
103
|
|
117
|
-
|
118
|
-
|
119
|
-
error.retry_after.should == 0
|
104
|
+
before do
|
105
|
+
described_class.any_instance.stub(:ratelimit_reset).and_return(reset_at)
|
120
106
|
end
|
107
|
+
|
108
|
+
it { should be_zero }
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
# NOTE: AngelList doesn't actually support this yet...
|
114
|
+
describe AngellistApi::Error::TooManyRequests do
|
115
|
+
include HttpHeaders
|
116
|
+
|
117
|
+
subject { described_class.new('message', headers).retry_after }
|
118
|
+
|
119
|
+
context 'with Retry-After header set' do
|
120
|
+
let(:wait) { '12' }
|
121
|
+
let(:headers) { headerize('Retry-After' => wait) }
|
122
|
+
|
123
|
+
it 'returns the seconds to wait until retrying' do
|
124
|
+
subject.should == 12
|
121
125
|
end
|
122
126
|
end
|
127
|
+
|
128
|
+
context 'with Retry-After unset' do
|
129
|
+
let(:headers) { headerize({}) }
|
130
|
+
it { should be_nil }
|
131
|
+
end
|
123
132
|
end
|
124
133
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: angellist_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2013-
|
13
|
+
date: 2013-04-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: hashie
|
@@ -203,12 +203,12 @@ files:
|
|
203
203
|
- lib/angellist_api/core_ext/hash.rb
|
204
204
|
- lib/angellist_api/error/bad_gateway.rb
|
205
205
|
- lib/angellist_api/error/bad_request.rb
|
206
|
-
- lib/angellist_api/error/enhance_your_calm.rb
|
207
206
|
- lib/angellist_api/error/forbidden.rb
|
208
207
|
- lib/angellist_api/error/internal_server_error.rb
|
209
208
|
- lib/angellist_api/error/not_acceptable.rb
|
210
209
|
- lib/angellist_api/error/not_found.rb
|
211
210
|
- lib/angellist_api/error/service_unavailable.rb
|
211
|
+
- lib/angellist_api/error/too_many_requests.rb
|
212
212
|
- lib/angellist_api/error/unauthorized.rb
|
213
213
|
- lib/angellist_api/error.rb
|
214
214
|
- lib/angellist_api/request/angellist_api_oauth.rb
|
@@ -224,6 +224,8 @@ files:
|
|
224
224
|
- README.md
|
225
225
|
- CHANGELOG.md
|
226
226
|
- spec/fixtures/cassettes/activity_feeds.yml
|
227
|
+
- spec/fixtures/cassettes/errors/forbidden.yml
|
228
|
+
- spec/fixtures/cassettes/errors/too_many_requests.yml
|
227
229
|
- spec/fixtures/cassettes/follows.yml
|
228
230
|
- spec/fixtures/cassettes/jobs.yml
|
229
231
|
- spec/fixtures/cassettes/messages.yml
|
@@ -237,6 +239,7 @@ files:
|
|
237
239
|
- spec/fixtures/cassettes/tags.yml
|
238
240
|
- spec/fixtures/cassettes/users.yml
|
239
241
|
- spec/integration/activity_feeds_spec.rb
|
242
|
+
- spec/integration/errors_spec.rb
|
240
243
|
- spec/integration/follows_spec.rb
|
241
244
|
- spec/integration/jobs_spec.rb
|
242
245
|
- spec/integration/messages_spec.rb
|
@@ -251,6 +254,7 @@ files:
|
|
251
254
|
- spec/integration/users_spec.rb
|
252
255
|
- spec/spec_helper.rb
|
253
256
|
- spec/support/authentication.rb
|
257
|
+
- spec/support/http_headers.rb
|
254
258
|
- spec/support/vcr.rb
|
255
259
|
- spec/unit/lib/angellist_api/api_spec.rb
|
256
260
|
- spec/unit/lib/angellist_api/authentication_spec.rb
|
@@ -285,7 +289,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
285
289
|
version: '0'
|
286
290
|
segments:
|
287
291
|
- 0
|
288
|
-
hash:
|
292
|
+
hash: 74367016323838857
|
289
293
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
290
294
|
none: false
|
291
295
|
requirements:
|
@@ -294,7 +298,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
294
298
|
version: '0'
|
295
299
|
segments:
|
296
300
|
- 0
|
297
|
-
hash:
|
301
|
+
hash: 74367016323838857
|
298
302
|
requirements: []
|
299
303
|
rubyforge_project:
|
300
304
|
rubygems_version: 1.8.25
|
@@ -303,6 +307,8 @@ specification_version: 3
|
|
303
307
|
summary: Ruby wrapper for the Angellist API.
|
304
308
|
test_files:
|
305
309
|
- spec/fixtures/cassettes/activity_feeds.yml
|
310
|
+
- spec/fixtures/cassettes/errors/forbidden.yml
|
311
|
+
- spec/fixtures/cassettes/errors/too_many_requests.yml
|
306
312
|
- spec/fixtures/cassettes/follows.yml
|
307
313
|
- spec/fixtures/cassettes/jobs.yml
|
308
314
|
- spec/fixtures/cassettes/messages.yml
|
@@ -316,6 +322,7 @@ test_files:
|
|
316
322
|
- spec/fixtures/cassettes/tags.yml
|
317
323
|
- spec/fixtures/cassettes/users.yml
|
318
324
|
- spec/integration/activity_feeds_spec.rb
|
325
|
+
- spec/integration/errors_spec.rb
|
319
326
|
- spec/integration/follows_spec.rb
|
320
327
|
- spec/integration/jobs_spec.rb
|
321
328
|
- spec/integration/messages_spec.rb
|
@@ -330,6 +337,7 @@ test_files:
|
|
330
337
|
- spec/integration/users_spec.rb
|
331
338
|
- spec/spec_helper.rb
|
332
339
|
- spec/support/authentication.rb
|
340
|
+
- spec/support/http_headers.rb
|
333
341
|
- spec/support/vcr.rb
|
334
342
|
- spec/unit/lib/angellist_api/api_spec.rb
|
335
343
|
- spec/unit/lib/angellist_api/authentication_spec.rb
|
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'angellist_api/error'
|
2
|
-
|
3
|
-
module AngellistApi
|
4
|
-
# Raised when AngellistApi returns the HTTP status code 420
|
5
|
-
class Error::EnhanceYourCalm < AngellistApi::Error
|
6
|
-
# The number of seconds your application should wait before requesting date
|
7
|
-
# from the API again
|
8
|
-
def retry_after
|
9
|
-
@http_headers.values_at('retry-after', 'Retry-After').detect {|value| value }.to_i
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|