angellist_api 1.0.5 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -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 "message".
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
@@ -23,3 +23,4 @@ module AngellistApi
23
23
  end
24
24
  end
25
25
  end
26
+
@@ -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.
@@ -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 = Hash[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
- Time.at(@http_headers.values_at('x-ratelimit-reset', 'X-RateLimit-Reset').detect{|value| value}.to_i)
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
- @http_headers.values_at('x-ratelimit-limit', 'X-RateLimit-Limit').detect{|value| value}.to_i
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
- @http_headers.values_at('x-ratelimit-remaining', 'X-RateLimit-Remaining').detect{|value| value}.to_i
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/enhance_your_calm'
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
- raise AngellistApi::Error::Forbidden.new(error_message(env), env[:response_headers])
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
+
@@ -1,4 +1,4 @@
1
1
  module AngellistApi
2
- VERSION = '1.0.5'
2
+ VERSION = '1.0.6'
3
3
  end
4
4
 
@@ -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
+
@@ -0,0 +1,8 @@
1
+ module HttpHeaders
2
+ # Faraday response headers are wrapped with a utility Hash subclass that
3
+ # normalizes case, underscored Symbols, etc.
4
+ def headerize(hash)
5
+ Faraday::Utils::Headers.new(hash)
6
+ end
7
+ end
8
+
@@ -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).with("1/users/#{id}/followers").and_return("success")
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).with("1/users/#{id}/followers/ids").and_return("success")
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).with("1/startups/#{id}/followers").and_return("success")
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).with("1/startups/#{id}/followers/ids").and_return("success")
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).with("1/tags/#{id}/children").and_return("success")
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).with("1/tags/#{id}/parents").and_return("success")
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 "#initialize" do
6
- context "message parameter" do
7
- it "does not raise an error if it is nil" do
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
- context "http_headers parameter" do
18
- it "raises an exception if no http headers are passed" do
19
- expect { AngellistApi::Error.new("some message", nil) }.to raise_error(ArgumentError, "odd number of arguments for Hash")
20
- end
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
- it "is set with the params" do
27
- error = AngellistApi::Error.new("some message", :some => "value")
28
- error.http_headers.should == { :some => "value" }
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
- describe "#ratelimit_reset" do
34
- it "returns the time set as x-rate-limit-reset if it's set" do
35
- time1 = Time.now.to_i
36
- time2 = time1 + 3600
37
- error = AngellistApi::Error.new("message", {'x-ratelimit-reset' => time1, 'X-RateLimit-Reset' => time2})
38
- error.ratelimit_reset.should == Time.at(time1)
39
- end
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
- it "returns the time set as X-RateLimit-Reset if x-rate-limit-reset is empty" do
42
- time = Time.now.to_i
43
- error = AngellistApi::Error.new("message", {'x-ratelimit-reset' => nil, 'X-RateLimit-Reset' => time})
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
- it "returns 0 if both X-RateLimit-Reset or x-rate-limit-reset are not set" do
48
- error = AngellistApi::Error.new("message", {})
49
- error.ratelimit_reset.should == Time.at(0)
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 "#ratelimit_limit" do
54
- it "returns the number set as x-rate-limit-limit if it's set" do
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
- it "returns the number set as X-RateLimit-Limit if x-rate-limit-limit is empty" do
60
- error = AngellistApi::Error.new("message", {'x-ratelimit-limit' => nil, 'X-RateLimit-Limit' => 600})
61
- error.ratelimit_limit.should == 600
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
- it "returns 0 if both X-RateLimit-Limit or x-rate-limit-limit are not set" do
65
- error = AngellistApi::Error.new("message", {})
66
- error.ratelimit_limit.should == 0
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 "#ratelimit_remaining" do
71
- it "returns the number set as x-rate-limit-remaining if it's set" do
72
- error = AngellistApi::Error.new("message", {'x-ratelimit-remaining' => 22, 'X-RateLimit-Remaining' => 23})
73
- error.ratelimit_remaining.should == 22
74
- end
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
- it "returns the number set as X-RateLimit-Remaining if x-rate-limit-remaining is empty" do
77
- error = AngellistApi::Error.new("message", {'x-ratelimit-remaining' => nil, 'X-RateLimit-Remaining' => 32})
78
- error.ratelimit_remaining.should == 32
66
+ it 'returns remaining request count as an integer' do
67
+ subject.should eq 22
68
+ end
79
69
  end
80
70
 
81
- it "returns 0 if both X-RateLimit-Remaining or x-rate-limit-remaining are not set" do
82
- error = AngellistApi::Error.new("message", {})
83
- error.ratelimit_remaining.should == 0
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
- describe "#retry_after" do
88
- context "a normal Error object" do
89
- let(:error) { AngellistApi::Error.new("message", {}) }
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
- it "give you the time in seconds when it is acceptable to make another call" do
92
- Timecop.freeze(Time.now) do
93
- error.should_receive(:ratelimit_reset) { Time.now + 3600 }
94
- error.retry_after.should == 3600
95
- end
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 "return 0 if the ratelimit_reset time is in the past" do
99
- Timecop.freeze(Time.now) do
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 "an EnhanceYourCalm Error object" do
107
- it "return the number of seconds set as retry-after if it's set" do
108
- error = AngellistApi::Error::EnhanceYourCalm.new("message", {'retry-after' => 12, 'Retry-After' => 13})
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
- it "return the number set as Retry-After if retry-after is empty" do
113
- error = AngellistApi::Error::EnhanceYourCalm.new("message", {'retry-after' => nil, 'Retry-After' => 16})
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
- it "return 0 if both Retry-After or retry-after are not set" do
118
- error = AngellistApi::Error::EnhanceYourCalm.new("message", {})
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.5
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-03-27 00:00:00.000000000 Z
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: 704109515206394600
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: 704109515206394600
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
-