nationbuilder-rb 1.1.0 → 1.2.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 478eaf49468a14664586855b0105a5c0781b9e82
4
- data.tar.gz: be6334a496d0b620c74c357515fb026224935594
3
+ metadata.gz: 7f736fe98de0df24dd6a2e38b3d7013ec6d49245
4
+ data.tar.gz: fca4e68a8753f003ba0f6815abcf74e9d16c8e7d
5
5
  SHA512:
6
- metadata.gz: d3f42b168b4b0ce526e17ef7462c1666e27e57b05822c005e3f97fd5ca4832041de1884a3c6cbd11656bf89d1d02d874fd66e5dd57ceb533d9efbc057b7f6652
7
- data.tar.gz: a1b4b4fef2cad1592d178c50cc91f385e69b1b9828c7037bdbb963020afb5469129b4ed1f3e23c4f9f98d383ccab76b564d20ec1bf06c0d3daa85efc3fd03c69
6
+ metadata.gz: 25aec085a33bab04ce580aa96d6f650893a5d603f87caa46f4b910401559b3d66bc161d71bb56370b9bada6a20be5d11b0f4759a587b9edcc3d6c252eb6f2d8f
7
+ data.tar.gz: a958baba40eaefda72a00248ef5d3ada11d9b751763de3a97ad17ef068fe6a21220f7eafdf74007ffca41c105f9bad5fa4a463f15ca1a708fa1a67921708e080
data/CHANGELOG.md CHANGED
@@ -1,2 +1,6 @@
1
+ # 1.2.0
2
+ - Native exception types
3
+ - [#9] Exponential backoff when encountering rate limit
4
+
1
5
  # 1.1.0
2
6
  - [#6] Pagination class for iterating through paginated sets
data/Gemfile CHANGED
@@ -3,9 +3,9 @@ source 'http://rubygems.org'
3
3
  gem 'httpclient', '~> 2.4.0'
4
4
 
5
5
  group :development do
6
- gem 'jeweler', '~> 2.0.1'
7
- gem 'rspec', '~> 2.8.0'
8
- gem 'simplecov', '~> 0.8.2'
9
- gem 'vcr', '~> 2.9.2'
10
- gem 'webmock', '~> 1.18.0'
6
+ gem 'jeweler', '~> 2.0'
7
+ gem 'rspec', '~> 3.2'
8
+ gem 'simplecov', '~> 0.8'
9
+ gem 'vcr', '~> 2.9'
10
+ gem 'webmock', '~> 1.18'
11
11
  end
data/Gemfile.lock CHANGED
@@ -1,26 +1,26 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- addressable (2.3.6)
4
+ addressable (2.3.7)
5
5
  builder (3.2.2)
6
6
  crack (0.4.2)
7
7
  safe_yaml (~> 1.0.0)
8
8
  descendants_tracker (0.0.4)
9
9
  thread_safe (~> 0.3, >= 0.3.1)
10
- diff-lcs (1.1.3)
10
+ diff-lcs (1.2.5)
11
11
  docile (1.1.5)
12
- faraday (0.9.0)
12
+ faraday (0.9.1)
13
13
  multipart-post (>= 1.2, < 3)
14
- git (1.2.7)
15
- github_api (0.11.3)
14
+ git (1.2.9.1)
15
+ github_api (0.12.3)
16
16
  addressable (~> 2.3)
17
- descendants_tracker (~> 0.0.1)
17
+ descendants_tracker (~> 0.0.4)
18
18
  faraday (~> 0.8, < 0.10)
19
- hashie (>= 1.2)
19
+ hashie (>= 3.3)
20
20
  multi_json (>= 1.7.5, < 2.0)
21
- nokogiri (~> 1.6.0)
21
+ nokogiri (~> 1.6.3)
22
22
  oauth2
23
- hashie (3.1.0)
23
+ hashie (3.4.0)
24
24
  highline (1.6.21)
25
25
  httpclient (2.4.0)
26
26
  jeweler (2.0.1)
@@ -32,41 +32,46 @@ GEM
32
32
  nokogiri (>= 1.5.10)
33
33
  rake
34
34
  rdoc
35
- json (1.8.1)
36
- jwt (1.0.0)
37
- mini_portile (0.6.0)
35
+ json (1.8.2)
36
+ jwt (1.2.1)
37
+ mini_portile (0.6.2)
38
38
  multi_json (1.10.1)
39
39
  multi_xml (0.5.5)
40
40
  multipart-post (2.0.0)
41
- nokogiri (1.6.2.1)
42
- mini_portile (= 0.6.0)
43
- oauth2 (0.9.4)
41
+ nokogiri (1.6.6.2)
42
+ mini_portile (~> 0.6.0)
43
+ oauth2 (1.0.0)
44
44
  faraday (>= 0.8, < 0.10)
45
45
  jwt (~> 1.0)
46
46
  multi_json (~> 1.3)
47
47
  multi_xml (~> 0.5)
48
48
  rack (~> 1.2)
49
- rack (1.5.2)
50
- rake (10.3.2)
51
- rdoc (4.1.1)
49
+ rack (1.6.0)
50
+ rake (10.4.2)
51
+ rdoc (4.2.0)
52
52
  json (~> 1.4)
53
- rspec (2.8.0)
54
- rspec-core (~> 2.8.0)
55
- rspec-expectations (~> 2.8.0)
56
- rspec-mocks (~> 2.8.0)
57
- rspec-core (2.8.0)
58
- rspec-expectations (2.8.0)
59
- diff-lcs (~> 1.1.2)
60
- rspec-mocks (2.8.0)
61
- safe_yaml (1.0.3)
62
- simplecov (0.8.2)
53
+ rspec (3.2.0)
54
+ rspec-core (~> 3.2.0)
55
+ rspec-expectations (~> 3.2.0)
56
+ rspec-mocks (~> 3.2.0)
57
+ rspec-core (3.2.0)
58
+ rspec-support (~> 3.2.0)
59
+ rspec-expectations (3.2.0)
60
+ diff-lcs (>= 1.2.0, < 2.0)
61
+ rspec-support (~> 3.2.0)
62
+ rspec-mocks (3.2.0)
63
+ diff-lcs (>= 1.2.0, < 2.0)
64
+ rspec-support (~> 3.2.0)
65
+ rspec-support (3.2.1)
66
+ safe_yaml (1.0.4)
67
+ simplecov (0.9.1)
63
68
  docile (~> 1.1.0)
64
- multi_json
69
+ multi_json (~> 1.0)
65
70
  simplecov-html (~> 0.8.0)
66
71
  simplecov-html (0.8.0)
67
72
  thread_safe (0.3.4)
68
- vcr (2.9.2)
69
- webmock (1.18.0)
73
+ vcr (2.9.3)
74
+ webmock (1.20.4)
70
75
  addressable (>= 2.3.6)
71
76
  crack (>= 0.3.2)
72
77
 
@@ -75,8 +80,8 @@ PLATFORMS
75
80
 
76
81
  DEPENDENCIES
77
82
  httpclient (~> 2.4.0)
78
- jeweler (~> 2.0.1)
79
- rspec (~> 2.8.0)
80
- simplecov (~> 0.8.2)
81
- vcr (~> 2.9.2)
82
- webmock (~> 1.18.0)
83
+ jeweler (~> 2.0)
84
+ rspec (~> 3.2)
85
+ simplecov (~> 0.8)
86
+ vcr (~> 2.9)
87
+ webmock (~> 1.18)
data/README.md CHANGED
@@ -30,9 +30,13 @@ Then, create a client by specifying the name of your nation and
30
30
  your API token:
31
31
 
32
32
  ```ruby
33
- client = NationBuilder::Client.new('my_nation_name', 'my_api_token')
33
+ client = NationBuilder::Client.new('my_nation_name', 'my_api_token', retries: 8)
34
34
  ```
35
35
 
36
+ The `retries` parameter specifies the maximum number of retries to attempt
37
+ when the client is rate limited. This uses an exponential backoff strategy.
38
+ The default is `8`.
39
+
36
40
  ## Calling the API
37
41
 
38
42
  The primary method for calling the NationBuilder API in
@@ -81,7 +85,7 @@ page1 = paginated
81
85
  page2 = page1.next
82
86
  page3 = page2.next
83
87
  ```
84
- Methods `#next` and `#prev` return the results of the next or previous page of results, nil if none. `#next?` and `#prev?` return the path to the next or prev page, or nil if none. The results of a page can be accessed through `.body` - in the above example, `page1.body` returns the same hash as `response`.
88
+ Methods `#next` and `#prev` return the results of the next or previous page of results, nil if none. `#next?` and `#prev?` return the path to the next or prev page, or nil if none. The results of a page can be accessed through `.body` - in the above example, `page1.body` returns the same hash as `response`.
85
89
 
86
90
  ## Documentation
87
91
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.0
1
+ 1.2.0
data/lib/nationbuilder.rb CHANGED
@@ -12,3 +12,4 @@ require 'nationbuilder/parameter'
12
12
  require 'nationbuilder/url'
13
13
  require 'nationbuilder/spec_parser'
14
14
  require 'nationbuilder/paginator'
15
+ require 'nationbuilder/errors'
@@ -1,10 +1,16 @@
1
1
  class NationBuilder::Client
2
2
 
3
- def initialize(nation_name, api_key, base_url = 'https://:nation_name.nationbuilder.com')
3
+ def initialize(nation_name, api_key, opts = {})
4
4
  @nation_name = nation_name
5
5
  @api_key = api_key
6
- @base_url = base_url
7
6
  @name_to_endpoint = {}
7
+ @base_url = opts[:base_url] || 'https://:nation_name.nationbuilder.com'
8
+ @retries = opts[:retries] || 8
9
+
10
+ if @retries < 1
11
+ raise 'A positive number of retries must be specified'
12
+ end
13
+
8
14
  parsed_endpoints.each do |endpoint|
9
15
  @name_to_endpoint[endpoint.name] = endpoint
10
16
  end
@@ -31,6 +37,8 @@ class NationBuilder::Client
31
37
  @base_url.gsub(':nation_name', @nation_name)
32
38
  end
33
39
 
40
+ RETRY_DELAY = 0.1 # seconds
41
+
34
42
  def raw_call(path, method, body = {}, args = {})
35
43
  url = NationBuilder::URL.new(base_url).generate_url(path, args)
36
44
 
@@ -51,8 +59,7 @@ class NationBuilder::Client
51
59
  request_args[:body] = JSON(body)
52
60
  end
53
61
 
54
- set_response(HTTPClient.send(method, url, request_args))
55
- return parse_response_body(response)
62
+ perform_request_with_retries(method, url, request_args)
56
63
  end
57
64
 
58
65
  def call(endpoint_name, method_name, args={})
@@ -64,22 +71,52 @@ class NationBuilder::Client
64
71
  return raw_call(method.uri, method.http_method, nonmethod_args, args)
65
72
  end
66
73
 
74
+ def perform_request_with_retries(method, url, request_args)
75
+ raw_response = HTTPClient.send(method, url, request_args)
76
+ parsed_response = nil
77
+
78
+ @retries.times do |i|
79
+ begin
80
+ parsed_response = parse_response_body(raw_response)
81
+ rescue NationBuilder::RateLimitedError
82
+ Kernel.sleep(RETRY_DELAY * 2**i)
83
+ rescue => e
84
+ raise e
85
+ else
86
+ break
87
+ end
88
+ end
89
+
90
+ set_response(raw_response)
91
+ parsed_response
92
+ end
93
+
67
94
  def set_response(value)
68
95
  Thread.current[:nationbuilder_rb_response] = value
69
96
  end
70
97
 
98
+ # This getter is used for fetching the raw response
71
99
  def response
72
100
  Thread.current[:nationbuilder_rb_response]
73
101
  end
74
102
 
75
- class ServerResponseError < StandardError; end
103
+ def classify_response_error(response)
104
+ case
105
+ when response.code == 429
106
+ return NationBuilder::RateLimitedError.new(response.body)
107
+ when response.code.to_s.start_with?('4')
108
+ return NationBuilder::ClientError.new(response.body)
109
+ when response.code.to_s.start_with?('5')
110
+ return NationBuilder::ServerError.new(response.body)
111
+ end
112
+ end
76
113
 
77
114
  def parse_response_body(response)
78
- success = response.code.to_s.start_with?('2')
115
+ error = classify_response_error(response)
116
+ raise error if error
79
117
 
80
118
  if response.header['Content-Type'].first != 'application/json'
81
- return {} if success
82
- raise ServerResponseError.new("Non-JSON content-type for server response: #{response.body}")
119
+ return nil
83
120
  end
84
121
 
85
122
  body = response.body.strip
@@ -0,0 +1,6 @@
1
+ module NationBuilder
2
+ class BaseError < StandardError; end
3
+ class ServerError < BaseError; end
4
+ class ClientError < BaseError; end
5
+ class RateLimitedError < ClientError; end
6
+ end
@@ -2,16 +2,16 @@
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
3
  # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: nationbuilder-rb 1.1.0 ruby lib
5
+ # stub: nationbuilder-rb 1.2.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "nationbuilder-rb"
9
- s.version = "1.1.0"
9
+ s.version = "1.2.0"
10
10
 
11
11
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
12
  s.require_paths = ["lib"]
13
13
  s.authors = ["David Huie"]
14
- s.date = "2015-02-10"
14
+ s.date = "2015-02-17"
15
15
  s.description = "A Ruby client to the NationBuilder API"
16
16
  s.email = "david@nationbuilder.com"
17
17
  s.executables = ["nbdoc"]
@@ -37,6 +37,7 @@ Gem::Specification.new do |s|
37
37
  "lib/nationbuilder/api_spec.json",
38
38
  "lib/nationbuilder/client.rb",
39
39
  "lib/nationbuilder/endpoint.rb",
40
+ "lib/nationbuilder/errors.rb",
40
41
  "lib/nationbuilder/method.rb",
41
42
  "lib/nationbuilder/paginator.rb",
42
43
  "lib/nationbuilder/parameter.rb",
@@ -62,26 +63,26 @@ Gem::Specification.new do |s|
62
63
 
63
64
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
64
65
  s.add_runtime_dependency(%q<httpclient>, ["~> 2.4.0"])
65
- s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
66
- s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
67
- s.add_development_dependency(%q<simplecov>, ["~> 0.8.2"])
68
- s.add_development_dependency(%q<vcr>, ["~> 2.9.2"])
69
- s.add_development_dependency(%q<webmock>, ["~> 1.18.0"])
66
+ s.add_development_dependency(%q<jeweler>, ["~> 2.0"])
67
+ s.add_development_dependency(%q<rspec>, ["~> 3.2"])
68
+ s.add_development_dependency(%q<simplecov>, ["~> 0.8"])
69
+ s.add_development_dependency(%q<vcr>, ["~> 2.9"])
70
+ s.add_development_dependency(%q<webmock>, ["~> 1.18"])
70
71
  else
71
72
  s.add_dependency(%q<httpclient>, ["~> 2.4.0"])
72
- s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
73
- s.add_dependency(%q<rspec>, ["~> 2.8.0"])
74
- s.add_dependency(%q<simplecov>, ["~> 0.8.2"])
75
- s.add_dependency(%q<vcr>, ["~> 2.9.2"])
76
- s.add_dependency(%q<webmock>, ["~> 1.18.0"])
73
+ s.add_dependency(%q<jeweler>, ["~> 2.0"])
74
+ s.add_dependency(%q<rspec>, ["~> 3.2"])
75
+ s.add_dependency(%q<simplecov>, ["~> 0.8"])
76
+ s.add_dependency(%q<vcr>, ["~> 2.9"])
77
+ s.add_dependency(%q<webmock>, ["~> 1.18"])
77
78
  end
78
79
  else
79
80
  s.add_dependency(%q<httpclient>, ["~> 2.4.0"])
80
- s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
81
- s.add_dependency(%q<rspec>, ["~> 2.8.0"])
82
- s.add_dependency(%q<simplecov>, ["~> 0.8.2"])
83
- s.add_dependency(%q<vcr>, ["~> 2.9.2"])
84
- s.add_dependency(%q<webmock>, ["~> 1.18.0"])
81
+ s.add_dependency(%q<jeweler>, ["~> 2.0"])
82
+ s.add_dependency(%q<rspec>, ["~> 3.2"])
83
+ s.add_dependency(%q<simplecov>, ["~> 0.8"])
84
+ s.add_dependency(%q<vcr>, ["~> 2.9"])
85
+ s.add_dependency(%q<webmock>, ["~> 1.18"])
85
86
  end
86
87
  end
87
88
 
@@ -17,7 +17,7 @@ http_interactions:
17
17
  - application/json
18
18
  response:
19
19
  status:
20
- code: 409
20
+ code: 200
21
21
  message: Conflict
22
22
  headers:
23
23
  Server:
@@ -76,6 +76,6 @@ http_interactions:
76
76
  LOS ANGELES\",\"closed_invoices_amount_in_cents\":null,\"closed_invoices_count\":null,\"contact_status_id\":null,\"contact_status_name\":null,\"could_vote_status\":null,\"demo\":\"\",\"donations_amount_in_cents\":0,\"donations_amount_this_cycle_in_cents\":0,\"donations_count\":0,\"donations_count_this_cycle\":0,\"donations_pledged_amount_in_cents\":0,\"donations_raised_amount_in_cents\":0,\"donations_raised_amount_this_cycle_in_cents\":0,\"donations_raised_count\":0,\"donations_raised_count_this_cycle\":0,\"donations_to_raise_amount_in_cents\":0,\"email1\":\"bob@example.com\",\"email1_is_bad\":false,\"email2\":null,\"email2_is_bad\":false,\"email3\":null,\"email3_is_bad\":false,\"email4\":null,\"email4_is_bad\":false,\"ethnicity\":\"\",\"facebook_address\":null,\"facebook_profile_url\":null,\"facebook_updated_at\":null,\"facebook_username\":null,\"fax_number\":\"\",\"federal_donotcall\":false,\"first_donated_at\":null,\"first_fundraised_at\":null,\"first_invoice_at\":null,\"first_prospect_at\":null,\"first_recruited_at\":null,\"first_supporter_at\":\"2014-04-24T10:27:34-07:00\",\"first_volunteer_at\":\"2014-09-02T13:10:28-07:00\",\"full_name\":\"Bob
77
77
  Smith\",\"home_address\":null,\"import_id\":null,\"inferred_party\":\"\",\"inferred_support_level\":null,\"invoice_payments_amount_in_cents\":null,\"invoice_payments_referred_amount_in_cents\":null,\"invoices_amount_in_cents\":null,\"invoices_count\":null,\"is_deceased\":false,\"is_donor\":false,\"is_fundraiser\":false,\"is_ignore_donation_limits\":false,\"is_leaderboardable\":true,\"is_mobile_bad\":false,\"is_possible_duplicate\":false,\"is_profile_private\":false,\"is_profile_searchable\":true,\"is_prospect\":false,\"is_supporter\":true,\"is_survey_question_private\":false,\"language\":\"\",\"last_call_id\":null,\"last_contacted_at\":null,\"last_contacted_by\":null,\"last_donated_at\":null,\"last_fundraised_at\":null,\"last_invoice_at\":null,\"last_rule_violation_at\":null,\"legal_name\":null,\"locale\":\"\",\"mailing_address\":null,\"marital_status\":\"\",\"media_market_name\":null,\"meetup_address\":null,\"membership_expires_at\":null,\"membership_level_name\":null,\"membership_started_at\":null,\"middle_name\":null,\"mobile_normalized\":null,\"nbec_precinct_code\":null,\"note_updated_at\":null,\"outstanding_invoices_amount_in_cents\":null,\"outstanding_invoices_count\":null,\"overdue_invoices_count\":null,\"page_slug\":\"ticket_page\",\"parent\":null,\"parent_id\":null,\"party_member\":false,\"phone_normalized\":\"2135551234\",\"phone_time\":\"\",\"precinct_code\":null,\"precinct_name\":null,\"prefix\":null,\"previous_party\":\"\",\"primary_email_id\":1,\"priority_level\":null,\"priority_level_changed_at\":null,\"profile_content\":null,\"profile_content_html\":null,\"profile_headline\":null,\"received_capital_amount_in_cents\":17700,\"recruiter\":null,\"recruits_count\":0,\"registered_address\":null,\"registered_at\":null,\"religion\":\"\",\"rule_violations_count\":0,\"spent_capital_amount_in_cents\":1000,\"submitted_address\":\"\",\"subnations\":[],\"suffix\":null,\"support_level_changed_at\":null,\"support_probability_score\":null,\"turnout_probability_score\":null,\"twitter_address\":null,\"twitter_description\":null,\"twitter_followers_count\":null,\"twitter_friends_count\":null,\"twitter_location\":null,\"twitter_login\":null,\"twitter_updated_at\":null,\"twitter_website\":null,\"unsubscribed_at\":null,\"user_submitted_address\":{\"address1\":\"488
78
78
  S Hill St\",\"address2\":null,\"address3\":null,\"city\":\"Los Angeles\",\"state\":\"CA\",\"country_code\":\"US\",\"zip\":\"90013\",\"lat\":\"34.0490467\",\"lng\":\"-118.2515224\"},\"username\":\"randomeveguy\",\"warnings_count\":0,\"website\":null,\"work_address\":null,\"bag_preference\":null,\"do_you_drive_a_fork_lift\":null,\"have_you_ever_been_contacted_by_a_union_representative_before_\":null,\"have_you_been_involved_in_an_election_campaign_before_\":null,\"sub_branch\":null,\"sams_custom_field\":null,\"mrow\":null,\"received_an_email\":null,\"brett_petition_mc\":null,\"headshot_url\":null,\"university\":null,\"membership_number\":null},\"precinct\":null}"
79
- http_version:
79
+ http_version:
80
80
  recorded_at: Thu, 05 Feb 2015 05:54:33 GMT
81
81
  recorded_with: VCR 2.9.2
@@ -4,13 +4,14 @@ describe NationBuilder::Client do
4
4
 
5
5
  let(:client) do
6
6
  NationBuilder::Client.new('organizeralexandreschmitt',
7
- '53920a524356034a065515a37650df2bd295971975d5742b9daa50eb8c7404d5')
7
+ '53920a524356034a065515a37650df2bd295971975d5742b9daa50eb8c7404d5',
8
+ retries: 2)
8
9
  end
9
10
 
10
11
  describe '#endpoints' do
11
12
 
12
13
  it 'should contain all defined endpoints' do
13
- client.endpoints.sort.should eq([
14
+ expect(client.endpoints.sort).to eq([
14
15
  :basic_pages,
15
16
  :blog_posts,
16
17
  :blogs,
@@ -38,7 +39,7 @@ describe NationBuilder::Client do
38
39
  describe '#base_url' do
39
40
 
40
41
  it 'should contain the nation slug' do
41
- client.base_url.should eq('https://organizeralexandreschmitt.nationbuilder.com')
42
+ expect(client.base_url).to eq('https://organizeralexandreschmitt.nationbuilder.com')
42
43
  end
43
44
  end
44
45
 
@@ -48,7 +49,7 @@ describe NationBuilder::Client do
48
49
  VCR.use_cassette('parametered_get') do
49
50
  response = client.call(:basic_pages, :index, site_slug: 'organizeralexandreschmitt')
50
51
  response['results'].each do |result|
51
- result['site_slug'].should eq('organizeralexandreschmitt')
52
+ expect(result['site_slug']).to eq('organizeralexandreschmitt')
52
53
  end
53
54
  end
54
55
  end
@@ -66,7 +67,7 @@ describe NationBuilder::Client do
66
67
  client.call(:people, :create, params)
67
68
  end
68
69
 
69
- response['person']['first_name'].should eq('Bob')
70
+ expect(response['person']['first_name']).to eq('Bob')
70
71
  end
71
72
 
72
73
  it 'should handle a DELETE' do
@@ -78,7 +79,51 @@ describe NationBuilder::Client do
78
79
  client.call(:people, :destroy, params)
79
80
  end
80
81
 
81
- response.should eq({})
82
+ expect(response).to eq(nil)
83
+ end
84
+ end
85
+
86
+ describe '#classify_response_error' do
87
+ it 'should account for rate limits' do
88
+ response = double(code: 429, body: 'rate limiting')
89
+ expect(client.classify_response_error(response).class).
90
+ to eq(NationBuilder::RateLimitedError)
91
+ end
92
+ it 'should account for client errors' do
93
+ response = double(code: 404, body: '404ing')
94
+ expect(client.classify_response_error(response).class).
95
+ to eq(NationBuilder::ClientError)
96
+ end
97
+ it 'should account for client errors' do
98
+ response = double(code: 500, body: '500ing')
99
+ expect(client.classify_response_error(response).class).
100
+ to eq(NationBuilder::ServerError)
101
+ end
102
+ end
103
+
104
+ describe '#perform_request_with_retries' do
105
+ before do
106
+ expect(HTTPClient).to receive(:send)
107
+ end
108
+
109
+ it 'should raise non-rate limiting execeptions' do
110
+ expect(client).to receive(:parse_response_body) { raise StandardError.new('boom') }
111
+ expect do
112
+ client.perform_request_with_retries(nil, nil, nil)
113
+ end.to raise_error
114
+ end
115
+
116
+ it 'should return a response if the rate limit is eventually dropped' do
117
+ expect(Kernel).to receive(:sleep).twice
118
+ allow(client).to receive(:parse_response_body) do
119
+ @count ||= 0
120
+ if @count != 2
121
+ raise NationBuilder::RateLimitedError.new
122
+ end
123
+ end
124
+ expect do
125
+ client.perform_request_with_retries(nil, nil, nil)
126
+ end.to_not raise_error
82
127
  end
83
128
  end
84
129
  end
@@ -19,26 +19,26 @@ describe Paginator do
19
19
  end
20
20
 
21
21
  it 'should check for next and prev page link' do
22
- @page1.next?.should_not be_nil
23
- @page1.prev?.should be_nil
22
+ expect(@page1.next?).to_not be_nil
23
+ expect(@page1.prev?).to be_nil
24
24
  end
25
25
 
26
26
  it 'should return next page' do
27
27
  VCR.use_cassette('paginated_get_page2') do
28
28
  page2 = @page1.next
29
- page2.body.should_not eq(@page1.body)
29
+ expect(page2.body).to_not eq(@page1.body)
30
30
  end
31
31
  end
32
32
 
33
33
  it 'should return additional pages' do
34
34
  VCR.use_cassette('paginated_get_page3') do
35
35
  page3 = @page2.next
36
- page3.body.should_not eq(@page2.body)
36
+ expect(page3.body).to_not eq(@page2.body)
37
37
  end
38
38
  end
39
39
 
40
40
  it 'should return nil if no prev page' do
41
- @page1.prev.should be_nil
41
+ expect(@page1.prev).to be_nil
42
42
  end
43
43
  end
44
- end
44
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nationbuilder-rb
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Huie
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-10 00:00:00.000000000 Z
11
+ date: 2015-02-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httpclient
@@ -30,70 +30,70 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 2.0.1
33
+ version: '2.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 2.0.1
40
+ version: '2.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: 2.8.0
47
+ version: '3.2'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: 2.8.0
54
+ version: '3.2'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: simplecov
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 0.8.2
61
+ version: '0.8'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 0.8.2
68
+ version: '0.8'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: vcr
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: 2.9.2
75
+ version: '2.9'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: 2.9.2
82
+ version: '2.9'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: webmock
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: 1.18.0
89
+ version: '1.18'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: 1.18.0
96
+ version: '1.18'
97
97
  description: A Ruby client to the NationBuilder API
98
98
  email: david@nationbuilder.com
99
99
  executables:
@@ -120,6 +120,7 @@ files:
120
120
  - lib/nationbuilder/api_spec.json
121
121
  - lib/nationbuilder/client.rb
122
122
  - lib/nationbuilder/endpoint.rb
123
+ - lib/nationbuilder/errors.rb
123
124
  - lib/nationbuilder/method.rb
124
125
  - lib/nationbuilder/paginator.rb
125
126
  - lib/nationbuilder/parameter.rb