nation_builder 0.0.6 → 0.0.13

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: 4e5da2ccce139f8e49b386b72018157e0f5d4d1a
4
- data.tar.gz: 62663da2e7aecc665b36d1950a26df7949bfbc6a
3
+ metadata.gz: 25e0b4c18cbdd3d11d1864be214b148239174bf4
4
+ data.tar.gz: a2d3d92444675969ed3ac20df264bb161f1aa8f0
5
5
  SHA512:
6
- metadata.gz: 801be53fd22a2e9fd90aacbc5369e6c27bec40bdd9d243f5a9d0e43f82706943c6b176caece51917908355aa97605e5bd17253ea68187e8b56488759ac162181
7
- data.tar.gz: 8c1fc92e0f1df84b200e2bac16d0deceb0c592ab7508008140c87ce320520bc3372a229b9c92083947f9fe4ea69dcb1cf9a059f284c0927659017c8d8d96a60f
6
+ metadata.gz: 3c9ac4a580ad47ce00259b97774da67bc686aed5245eb9b9e619571cd69545cfdef53d17226567ef7cd31063cd5ad42e4b7941bd74d57be95e44490587ac5fb8
7
+ data.tar.gz: e194f687bf3b7fce973e7a81f8a7ce6f625f85c31e22a78eb1f6a8ef54fbfd70ac3f812b1ce501a97093cfba7f8288d4d5ca7e4902f2ac30f5f830a21c328e41
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.0.0-p247
1
+ 2.3.4
data/.travis.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  language: ruby
2
2
  rvm:
3
- - 1.9.3
3
+ - 2.2.4
data/Gemfile CHANGED
@@ -1,14 +1,14 @@
1
- source "http://rubygems.org"
1
+ source 'http://rubygems.org'
2
2
 
3
- # NationBuilder puts error messages in a different location.
3
+ # NationBuilder puts error messages in a different location.
4
4
  gem 'oauth2', git: 'https://github.com/controlshift/oauth2.git'
5
5
  gem 'json'
6
+ gem 'activesupport', '>3.0.0'
6
7
 
7
8
  group :development do
8
9
  gem 'webmock'
9
- gem 'pry'
10
- gem 'pry-debugger'
11
- gem "rspec"
12
- gem "bundler"
13
- gem "jeweler", "~> 1.8.7"
10
+ gem 'byebug'
11
+ gem 'rspec'
12
+ gem 'bundler'
13
+ gem "juwelier"
14
14
  end
data/Gemfile.lock CHANGED
@@ -1,93 +1,108 @@
1
1
  GIT
2
2
  remote: https://github.com/controlshift/oauth2.git
3
- revision: 7e60e15878e503f80c8708f5c2cca5d17664fc61
3
+ revision: 1dbcdd2bff439cfab188220accc02b39c6bae5ba
4
4
  specs:
5
- oauth2 (0.9.2)
6
- faraday (~> 0.8)
7
- jwt (~> 0.1.4)
8
- multi_json (~> 1.0)
5
+ oauth2 (1.3.0)
6
+ faraday (>= 0.8, < 0.11)
7
+ jwt (~> 1.0)
8
+ multi_json (~> 1.3)
9
9
  multi_xml (~> 0.5)
10
- rack (~> 1.2)
10
+ rack (>= 1.2, < 3)
11
11
 
12
12
  GEM
13
13
  remote: http://rubygems.org/
14
14
  specs:
15
- addressable (2.3.5)
16
- builder (3.2.2)
17
- coderay (1.0.9)
18
- columnize (0.3.6)
19
- crack (0.4.1)
20
- safe_yaml (~> 0.9.0)
21
- debugger (1.6.1)
22
- columnize (>= 0.3.1)
23
- debugger-linecache (~> 1.2.0)
24
- debugger-ruby_core_source (~> 1.2.3)
25
- debugger-linecache (1.2.0)
26
- debugger-ruby_core_source (1.2.3)
27
- diff-lcs (1.2.4)
28
- faraday (0.8.8)
29
- multipart-post (~> 1.2.0)
30
- git (1.2.6)
31
- github_api (0.10.1)
32
- addressable
33
- faraday (~> 0.8.1)
34
- hashie (>= 1.2)
35
- multi_json (~> 1.4)
36
- nokogiri (~> 1.5.2)
37
- oauth2
38
- hashie (2.0.5)
39
- highline (1.6.20)
40
- jeweler (1.8.8)
15
+ activesupport (5.1.2)
16
+ concurrent-ruby (~> 1.0, >= 1.0.2)
17
+ i18n (~> 0.7)
18
+ minitest (~> 5.1)
19
+ tzinfo (~> 1.1)
20
+ addressable (2.4.0)
21
+ builder (3.2.3)
22
+ byebug (9.0.6)
23
+ concurrent-ruby (1.0.5)
24
+ crack (0.4.3)
25
+ safe_yaml (~> 1.0.0)
26
+ descendants_tracker (0.0.4)
27
+ thread_safe (~> 0.3, >= 0.3.1)
28
+ diff-lcs (1.3)
29
+ faraday (0.9.2)
30
+ multipart-post (>= 1.2, < 3)
31
+ git (1.3.0)
32
+ github_api (0.17.0)
33
+ addressable (~> 2.4.0)
34
+ descendants_tracker (~> 0.0.4)
35
+ faraday (~> 0.8, < 0.10)
36
+ hashie (>= 3.4)
37
+ mime-types (>= 1.16, < 3.0)
38
+ oauth2 (~> 1.0)
39
+ hashdiff (0.3.4)
40
+ hashie (3.5.6)
41
+ highline (1.7.8)
42
+ i18n (0.8.6)
43
+ json (2.1.0)
44
+ juwelier (2.4.7)
41
45
  builder
42
- bundler (~> 1.0)
43
- git (>= 1.2.5)
44
- github_api (= 0.10.1)
45
- highline (>= 1.6.15)
46
- nokogiri (= 1.5.10)
46
+ bundler
47
+ git
48
+ github_api
49
+ highline
50
+ kamelcase (~> 0)
51
+ nokogiri
52
+ psych
47
53
  rake
48
54
  rdoc
49
- json (1.8.1)
50
- jwt (0.1.8)
51
- multi_json (>= 1.5)
52
- method_source (0.8.2)
53
- multi_json (1.8.2)
54
- multi_xml (0.5.5)
55
- multipart-post (1.2.0)
56
- nokogiri (1.5.10)
57
- pry (0.9.12.2)
58
- coderay (~> 1.0.5)
59
- method_source (~> 0.8)
60
- slop (~> 3.4)
61
- pry-debugger (0.2.2)
62
- debugger (~> 1.3)
63
- pry (~> 0.9.10)
64
- rack (1.5.2)
65
- rake (10.1.0)
66
- rdoc (4.0.1)
67
- json (~> 1.4)
68
- rspec (2.14.1)
69
- rspec-core (~> 2.14.0)
70
- rspec-expectations (~> 2.14.0)
71
- rspec-mocks (~> 2.14.0)
72
- rspec-core (2.14.5)
73
- rspec-expectations (2.14.2)
74
- diff-lcs (>= 1.1.3, < 2.0)
75
- rspec-mocks (2.14.3)
76
- safe_yaml (0.9.7)
77
- slop (3.4.6)
78
- webmock (1.13.0)
79
- addressable (>= 2.2.7)
55
+ semver2
56
+ jwt (1.5.6)
57
+ kamelcase (0.0.1)
58
+ semver2 (~> 3)
59
+ mime-types (2.99.3)
60
+ mini_portile2 (2.2.0)
61
+ minitest (5.10.2)
62
+ multi_json (1.12.1)
63
+ multi_xml (0.6.0)
64
+ multipart-post (2.0.0)
65
+ nokogiri (1.8.0)
66
+ mini_portile2 (~> 2.2.0)
67
+ psych (2.2.4)
68
+ rack (2.0.3)
69
+ rake (12.0.0)
70
+ rdoc (5.1.0)
71
+ rspec (3.6.0)
72
+ rspec-core (~> 3.6.0)
73
+ rspec-expectations (~> 3.6.0)
74
+ rspec-mocks (~> 3.6.0)
75
+ rspec-core (3.6.0)
76
+ rspec-support (~> 3.6.0)
77
+ rspec-expectations (3.6.0)
78
+ diff-lcs (>= 1.2.0, < 2.0)
79
+ rspec-support (~> 3.6.0)
80
+ rspec-mocks (3.6.0)
81
+ diff-lcs (>= 1.2.0, < 2.0)
82
+ rspec-support (~> 3.6.0)
83
+ rspec-support (3.6.0)
84
+ safe_yaml (1.0.4)
85
+ semver2 (3.4.2)
86
+ thread_safe (0.3.6)
87
+ tzinfo (1.2.3)
88
+ thread_safe (~> 0.1)
89
+ webmock (3.0.1)
90
+ addressable (>= 2.3.6)
80
91
  crack (>= 0.3.2)
92
+ hashdiff
81
93
 
82
94
  PLATFORMS
83
95
  ruby
84
96
 
85
97
  DEPENDENCIES
98
+ activesupport (> 3.0.0)
86
99
  bundler
87
- jeweler (~> 1.8.7)
100
+ byebug
88
101
  json
102
+ juwelier
89
103
  oauth2!
90
- pry
91
- pry-debugger
92
104
  rspec
93
105
  webmock
106
+
107
+ BUNDLED WITH
108
+ 1.15.2
data/README.md CHANGED
@@ -12,6 +12,7 @@ client = NationBuilder.new(hostname: 'whatever.nationbuilder.com', client_id: 'i
12
12
  client.people.create('person' => {'first_name' => 'George', 'last_name' => 'Washington', 'email' => 'george@washington.com'})
13
13
  client.people.match('email' => 'george@washington.com) # either a person hash or nil.
14
14
  client.people.list # returns people in nation
15
+ client.tags.list # all tags.
15
16
  ```
16
17
 
17
18
  ### Contributing
data/Rakefile CHANGED
@@ -11,9 +11,9 @@ rescue Bundler::BundlerError => e
11
11
  end
12
12
  require 'rake'
13
13
 
14
- require 'jeweler'
15
- Jeweler::Tasks.new do |gem|
16
- # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
14
+ require 'juwelier'
15
+ Juwelier::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://guides.rubygems.org/specification-reference/ for more options
17
17
  gem.name = "nation_builder"
18
18
  gem.homepage = "http://github.com/controlshift/nation_builder"
19
19
  gem.license = "MIT"
@@ -23,7 +23,7 @@ Jeweler::Tasks.new do |gem|
23
23
  gem.authors = ["Nathan Woodhull", "Dan Schneiderman"]
24
24
  # dependencies defined in Gemfile
25
25
  end
26
- Jeweler::RubygemsDotOrgTasks.new
26
+ Juwelier::RubygemsDotOrgTasks.new
27
27
 
28
28
  require 'rspec/core'
29
29
  require 'rspec/core/rake_task'
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.0.6
1
+ 0.0.13
@@ -0,0 +1,10 @@
1
+ module NationBuilder
2
+ module Actions
3
+ module Create
4
+ def create params
5
+ body = JSON.generate(params)
6
+ JSON.parse(client.post(base_path, body: body).response.env[:body])
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,9 @@
1
+ module NationBuilder
2
+ module Actions
3
+ module List
4
+ def list
5
+ JSON.parse(client.get(base_path).response.env[:body])
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module NationBuilder
2
+ module Actions
3
+ module Show
4
+ def show(person_id)
5
+ JSON.parse(client.get("#{base_path}/#{person_id}").response.env[:body])
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ module NationBuilder
2
+ module Actions
3
+ module Update
4
+
5
+ def update id, params
6
+ body = JSON.generate(params)
7
+ JSON.parse(client.put("#{base_path}/#{id}", body: body).response.env[:body])
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -1,44 +1,104 @@
1
1
  module NationBuilder
2
+ class RateLimitedError < StandardError
3
+ def initialize(oauth2_response)
4
+ message = "NationBuilder rate limit error. Current values:\n"
5
+ message << "Limit: #{oauth2_response.headers["x-ratelimit-limit"]}\n"
6
+ message << "Remaining: #{oauth2_response.headers["x-ratelimit-remaining"]}\n"
7
+ message << "Reset: #{Time.at(oauth2_response.headers["x-ratelimit-reset"].try(:to_i) || 0)}\n"
8
+ message << "Body: #{oauth2_response.body}"
9
+ super(message)
10
+ end
11
+ end
12
+
2
13
  class Client
3
- attr_accessor :token, :client_secret, :client_id, :username, :password, :hostname
4
-
14
+ attr_accessor :client, :token, :client_secret, :client_id, :username, :password, :hostname, :instrumentation, :logger
15
+
5
16
  def initialize(args = {})
6
17
  args.each do |key, value|
7
18
  self.send("#{key}=".intern, value)
8
19
  end
9
- self.token = setup_client
20
+ if username.present? && password.present?
21
+ self.client = setup_client_from_password
22
+ elsif token.present?
23
+ self.client = setup_client_from_token
24
+ end
10
25
  end
11
-
26
+
12
27
  def people
13
28
  NationBuilder::People.new(self)
14
29
  end
15
-
30
+
31
+ def tags
32
+ NationBuilder::Tags.new(self)
33
+ end
34
+
16
35
  def get(path, opts={})
17
- self.token.get "#{base_uri}#{path}", opts.merge(headers: headers)
36
+ instrumented_request(:get, path, opts)
18
37
  end
19
-
38
+
20
39
  def post(path, opts={})
21
- self.token.post "#{base_uri}#{path}", opts.merge(headers: headers)
40
+ instrumented_request(:post, path, opts)
22
41
  end
23
42
 
24
43
  def put(path, opts={})
25
- self.token.put "#{base_uri}#{path}", opts.merge(headers: headers)
44
+ instrumented_request(:put, path, opts)
26
45
  end
27
-
46
+
47
+ def delete(path, opts={})
48
+ instrumented_request(:delete, path, opts)
49
+ end
50
+
28
51
  private
29
-
52
+
53
+ def instrumented_request(request_type, path, opts)
54
+ if self.instrumentation
55
+ # Normalize path to remove IDs from it
56
+ normalized_path = path.gsub(/\/\d+\//, '/_/')
57
+ stats = { path: normalized_path, request_type: request_type }
58
+ self.instrumentation.call(stats)
59
+ end
60
+
61
+ begin
62
+ response = self.client.send(request_type, "#{base_uri}#{path}", opts.merge(headers: headers))
63
+ if !logger.nil?
64
+ log_message = <<-MESSAGE
65
+ NationBuilder rate limit headers for #{base_uri}:
66
+ X-RateLimit-Limit: #{response.headers["x-ratelimit-limit"]}
67
+ X-RateLimit-Remaining: #{response.headers['x-ratelimit-remaining']}
68
+ X-RateLimit-Reset: #{Time.at(response.headers["x-ratelimit-reset"].try(:to_i) || 0)}
69
+ MESSAGE
70
+ logger.info(log_message)
71
+ end
72
+ response
73
+ rescue OAuth2::Error => e
74
+ if (!e.code.nil? && e.code.downcase == 'rate_limited') || (e.message =~ /rate_limited/)
75
+ raise RateLimitedError.new(e.response)
76
+ end
77
+
78
+ raise
79
+ end
80
+ end
81
+
82
+ def setup_client_from_password
83
+ setup_client.password.get_token(username, password)
84
+ end
85
+
86
+ def setup_client_from_token
87
+ OAuth2::AccessToken.new(setup_client, token)
88
+ end
89
+
30
90
  def setup_client
31
- client = OAuth2::Client.new(client_id, client_secret, :site => "https://#{hostname}", authorize_url: "https://#{hostname}/oauth/authorize", token_url: "https://#{hostname}/oauth/token" )
32
- client.password.get_token(username, password)
91
+ OAuth2::Client.new(client_id, client_secret, site: "https://#{hostname}", authorize_url: "https://#{hostname}/oauth/authorize", token_url: "https://#{hostname}/oauth/token" )
33
92
  end
34
-
93
+
94
+
35
95
  def headers
36
96
  {
37
97
  'Content-Type' => 'application/json',
38
98
  'Accept' => 'application/json'
39
- }
99
+ }
40
100
  end
41
-
101
+
42
102
  def base_uri
43
103
  "https://#{hostname}/"
44
104
  end
@@ -0,0 +1,19 @@
1
+ module NationBuilder
2
+ module Exceptions
3
+ class ValidationError < StandardError
4
+ attr_accessor :message, :errors, :code
5
+
6
+ def initialize(message, errors, code)
7
+ self.message = message
8
+ self.errors = errors
9
+ self.code = code
10
+ super()
11
+ end
12
+
13
+ def to_s
14
+ "#{super()} \n message: #{message} \n code: #{code} \n errors: #{errors}"
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -1,14 +1,17 @@
1
1
  module NationBuilder
2
- class People
3
- attr_accessor :client
4
-
5
- def initialize(client)
6
- self.client = client
2
+ class People < RemoteController
3
+ include NationBuilder::Actions::Show
4
+ include NationBuilder::Actions::List
5
+ include NationBuilder::Actions::Update
6
+ include NationBuilder::Actions::Create
7
+
8
+ def controller_name
9
+ 'people'
7
10
  end
8
11
 
9
12
  def match(params)
10
13
  begin
11
- JSON.parse(client.get('/api/v1/people/match', params: params).response.env[:body])
14
+ JSON.parse(client.get("#{base_path}/match", params: params).response.env[:body])
12
15
  rescue OAuth2::Error => e
13
16
  if e.response.parsed['code'] == 'no_matches'
14
17
  return nil
@@ -17,29 +20,75 @@ module NationBuilder
17
20
  end
18
21
  end
19
22
  end
20
-
21
- def list
22
- JSON.parse(client.get('/api/v1/people').response.env[:body])
23
+
24
+ def search(params)
25
+ JSON.parse(client.get("#{base_path}/search", params: params).response.env[:body])
23
26
  end
24
-
25
- def create params
27
+
28
+ def create_or_update params
29
+ person = self.match('email' => params['person']['email'])
30
+ if person
31
+ new_person = person['person'].merge(params['person'])
32
+ r = self.update new_person['id'], 'person' => new_person
33
+ {is_new: false, response: r}
34
+ else
35
+ r = self.create params
36
+ {is_new: true, response: r}
37
+ end
38
+ end
39
+
40
+ def match_or_add(params)
41
+ person = self.match('email' => params['person']['email'])
42
+ if person
43
+ r = self.add(params)
44
+ {is_new: false, response: r}
45
+ else
46
+ r = self.add(params)
47
+ {is_new: true, response: r}
48
+ end
49
+ end
50
+
51
+ def push(params)
26
52
  body = JSON.generate(params)
27
- JSON.parse(client.post('/api/v1/people', body: body).response.env[:body])
53
+ JSON.parse(client.put("#{base_path}/push", body: body).response.env[:body])
28
54
  end
29
55
 
30
- def update id, params
56
+ def add(params)
31
57
  body = JSON.generate(params)
32
- JSON.parse(client.put("/api/v1/people/#{id}", body: body).response.env[:body])
58
+ begin
59
+ JSON.parse(client.put("#{base_path}/add", body: body).response.env[:body])
60
+ rescue OAuth2::Error => e
61
+ if e.response.parsed['code'] == 'validation_failed'
62
+ raise NationBuilder::Exceptions::ValidationError.new(e.response.parsed['message'], e.response.parsed['validation_errors'], e.response.parsed['code'])
63
+ else
64
+ raise e
65
+ end
66
+ end
67
+
33
68
  end
34
69
 
35
- def create_or_update params
36
- person = self.match('email' => params['person']['email'])
37
- if(person)
38
- new_person = person['person'].merge(params['person'])
39
- self.update new_person['id'], 'person' => new_person
70
+ def taggings(person_id)
71
+ JSON.parse(client.get(taggings_path(person_id)).response.env[:body])
72
+ end
73
+
74
+ def add_tagging(person_id, tag)
75
+ body = JSON.generate({'tagging' => {'tag' => tag}})
76
+ JSON.parse(client.put(taggings_path(person_id), body: body).response.env[:body])
77
+ end
78
+
79
+ def delete_tagging(person_id, tag)
80
+ response = client.delete("#{taggings_path(person_id)}/#{tag}")
81
+ if response.response.env[:status] == 204
82
+ return true
40
83
  else
41
- self.create params
84
+ return response
42
85
  end
43
86
  end
87
+
88
+ private
89
+
90
+ def taggings_path(person_id)
91
+ "#{base_path}/#{person_id}/taggings"
92
+ end
44
93
  end
45
94
  end
@@ -0,0 +1,22 @@
1
+ module NationBuilder
2
+ class RemoteController
3
+ attr_accessor :client
4
+
5
+ def initialize(client)
6
+ self.client = client
7
+ end
8
+
9
+ def base_uri
10
+ '/api/v1/'
11
+ end
12
+
13
+ def controller_name
14
+ raise 'implement me'
15
+ end
16
+
17
+ def base_path
18
+ base_uri + controller_name
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module NationBuilder
2
+ class Tags < RemoteController
3
+ include NationBuilder::Actions::List
4
+
5
+ def controller_name
6
+ 'tags'
7
+ end
8
+
9
+ def people(tag)
10
+ JSON.parse(client.get(base_path + '/' + tag).response.env[:body])
11
+ end
12
+ end
13
+ end
@@ -1,15 +1,36 @@
1
1
  require 'oauth2'
2
+ require 'active_support/all'
3
+ require 'nation_builder/exceptions/validation_error'
4
+ require 'nation_builder/actions/show'
5
+ require 'nation_builder/actions/list'
6
+ require 'nation_builder/actions/update'
7
+ require 'nation_builder/actions/create'
2
8
  require 'nation_builder/client'
9
+ require 'nation_builder/remote_controller'
10
+ require 'nation_builder/tags'
3
11
  require 'nation_builder/people'
4
12
 
5
- module NationBuilder
13
+
14
+ module NationBuilder
6
15
 
7
16
  class << self
17
+ # Initializes a new NationBuilder client
18
+ #
19
+ # @param [Hash] options the options to make the request with
20
+ # @option options [String] :client_id client ID used for OAuth 2.0 authenticated requests
21
+ # @option options [String] :client_secret secret used for OAuth 2.0 authenticated requests
22
+ # @option options [String] :hostname NationBuilder site hostname, must not include protocol (i.e.: 'http://')
23
+ # @option options [String] :token OAuth2 access token used for perform authenticated calls. Not required if performing authenticated calls with :username and :password
24
+ # @option options [String] :username username used for getting a OAuth 2.0 access token. Not required if performing authenticated calls with :token
25
+ # @option options [String] :password password used for getting a OAuth 2.0 access token. Not required if performing authenticated calls with :token
26
+ # @option options [Proc] :instrumentation block of code to be invoked on every request to NationBuilder. Should receive a single Hash argument that includes :path and :request_type.
27
+ # :path argument is normalized, replacing IDs with '_'
28
+ # @option options [Logger] :logger optional. If provided, rate limit related headers from successful responses will be logged.
8
29
  def new(options = {})
9
30
  NationBuilder::Client.new(options)
10
31
  end
11
-
12
- def method_missing(method, *args)
32
+
33
+ def method_missing(method, *args)
13
34
  return super unless new.respond_to?(method)
14
35
  new.send(method, *args)
15
36
  end
@@ -18,4 +39,4 @@ module NationBuilder
18
39
  new.respond_to?(method, include_private) || super(method, include_private)
19
40
  end
20
41
  end
21
- end
42
+ end
@@ -1,18 +1,19 @@
1
- # Generated by jeweler
1
+ # Generated by juwelier
2
2
  # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
3
+ # Instead, edit Juwelier::Tasks in Rakefile, and run 'rake gemspec'
4
4
  # -*- encoding: utf-8 -*-
5
- # stub: nation_builder 0.0.6 ruby lib
5
+ # stub: nation_builder 0.0.13 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
- s.name = "nation_builder"
9
- s.version = "0.0.6"
8
+ s.name = "nation_builder".freeze
9
+ s.version = "0.0.13"
10
10
 
11
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
- s.authors = ["Nathan Woodhull", "Dan Schneiderman"]
13
- s.date = "2013-10-28"
14
- s.description = "Ruby wrapper for NationBuilder API"
15
- s.email = "nathan@controlshiftlabs.com"
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
12
+ s.require_paths = ["lib".freeze]
13
+ s.authors = ["Nathan Woodhull".freeze, "Dan Schneiderman".freeze]
14
+ s.date = "2017-08-21"
15
+ s.description = "Ruby wrapper for NationBuilder API".freeze
16
+ s.email = "nathan@controlshiftlabs.com".freeze
16
17
  s.extra_rdoc_files = [
17
18
  "LICENSE.txt",
18
19
  "README.md"
@@ -30,8 +31,15 @@ Gem::Specification.new do |s|
30
31
  "Rakefile",
31
32
  "VERSION",
32
33
  "lib/nation_builder.rb",
34
+ "lib/nation_builder/actions/create.rb",
35
+ "lib/nation_builder/actions/list.rb",
36
+ "lib/nation_builder/actions/show.rb",
37
+ "lib/nation_builder/actions/update.rb",
33
38
  "lib/nation_builder/client.rb",
39
+ "lib/nation_builder/exceptions/validation_error.rb",
34
40
  "lib/nation_builder/people.rb",
41
+ "lib/nation_builder/remote_controller.rb",
42
+ "lib/nation_builder/tags.rb",
35
43
  "nation_builder.gemspec",
36
44
  "spec/client_spec.rb",
37
45
  "spec/fixtures/not_found",
@@ -41,43 +49,42 @@ Gem::Specification.new do |s|
41
49
  "spec/people_spec.rb",
42
50
  "spec/spec_helper.rb"
43
51
  ]
44
- s.homepage = "http://github.com/controlshift/nation_builder"
45
- s.licenses = ["MIT"]
46
- s.require_paths = ["lib"]
47
- s.rubygems_version = "2.1.10"
48
- s.summary = "NationBuilder API wrapper"
52
+ s.homepage = "http://github.com/controlshift/nation_builder".freeze
53
+ s.licenses = ["MIT".freeze]
54
+ s.rubygems_version = "2.5.2".freeze
55
+ s.summary = "NationBuilder API wrapper".freeze
49
56
 
50
57
  if s.respond_to? :specification_version then
51
58
  s.specification_version = 4
52
59
 
53
60
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
54
- s.add_runtime_dependency(%q<oauth2>, [">= 0"])
55
- s.add_runtime_dependency(%q<json>, [">= 0"])
56
- s.add_development_dependency(%q<webmock>, [">= 0"])
57
- s.add_development_dependency(%q<pry>, [">= 0"])
58
- s.add_development_dependency(%q<pry-debugger>, [">= 0"])
59
- s.add_development_dependency(%q<rspec>, [">= 0"])
60
- s.add_development_dependency(%q<bundler>, [">= 0"])
61
- s.add_development_dependency(%q<jeweler>, ["~> 1.8.7"])
61
+ s.add_runtime_dependency(%q<oauth2>.freeze, [">= 0"])
62
+ s.add_runtime_dependency(%q<json>.freeze, [">= 0"])
63
+ s.add_runtime_dependency(%q<activesupport>.freeze, ["> 3.0.0"])
64
+ s.add_development_dependency(%q<webmock>.freeze, [">= 0"])
65
+ s.add_development_dependency(%q<byebug>.freeze, [">= 0"])
66
+ s.add_development_dependency(%q<rspec>.freeze, [">= 0"])
67
+ s.add_development_dependency(%q<bundler>.freeze, [">= 0"])
68
+ s.add_development_dependency(%q<juwelier>.freeze, [">= 0"])
62
69
  else
63
- s.add_dependency(%q<oauth2>, [">= 0"])
64
- s.add_dependency(%q<json>, [">= 0"])
65
- s.add_dependency(%q<webmock>, [">= 0"])
66
- s.add_dependency(%q<pry>, [">= 0"])
67
- s.add_dependency(%q<pry-debugger>, [">= 0"])
68
- s.add_dependency(%q<rspec>, [">= 0"])
69
- s.add_dependency(%q<bundler>, [">= 0"])
70
- s.add_dependency(%q<jeweler>, ["~> 1.8.7"])
70
+ s.add_dependency(%q<oauth2>.freeze, [">= 0"])
71
+ s.add_dependency(%q<json>.freeze, [">= 0"])
72
+ s.add_dependency(%q<activesupport>.freeze, ["> 3.0.0"])
73
+ s.add_dependency(%q<webmock>.freeze, [">= 0"])
74
+ s.add_dependency(%q<byebug>.freeze, [">= 0"])
75
+ s.add_dependency(%q<rspec>.freeze, [">= 0"])
76
+ s.add_dependency(%q<bundler>.freeze, [">= 0"])
77
+ s.add_dependency(%q<juwelier>.freeze, [">= 0"])
71
78
  end
72
79
  else
73
- s.add_dependency(%q<oauth2>, [">= 0"])
74
- s.add_dependency(%q<json>, [">= 0"])
75
- s.add_dependency(%q<webmock>, [">= 0"])
76
- s.add_dependency(%q<pry>, [">= 0"])
77
- s.add_dependency(%q<pry-debugger>, [">= 0"])
78
- s.add_dependency(%q<rspec>, [">= 0"])
79
- s.add_dependency(%q<bundler>, [">= 0"])
80
- s.add_dependency(%q<jeweler>, ["~> 1.8.7"])
80
+ s.add_dependency(%q<oauth2>.freeze, [">= 0"])
81
+ s.add_dependency(%q<json>.freeze, [">= 0"])
82
+ s.add_dependency(%q<activesupport>.freeze, ["> 3.0.0"])
83
+ s.add_dependency(%q<webmock>.freeze, [">= 0"])
84
+ s.add_dependency(%q<byebug>.freeze, [">= 0"])
85
+ s.add_dependency(%q<rspec>.freeze, [">= 0"])
86
+ s.add_dependency(%q<bundler>.freeze, [">= 0"])
87
+ s.add_dependency(%q<juwelier>.freeze, [">= 0"])
81
88
  end
82
89
  end
83
90
 
data/spec/client_spec.rb CHANGED
@@ -1,6 +1,113 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- describe 'Client' do
4
- specify { pending 'spec client behavior'}
3
+ describe NationBuilder::Client do
4
+ shared_examples 'request' do
5
+ let(:client) { double }
5
6
 
6
- end
7
+ subject { NationBuilder::Client.new(hostname: 'nationbuilder.com') }
8
+
9
+ before :each do
10
+ expect(subject).to receive(:client).and_return(client)
11
+ end
12
+
13
+ context 'request path does not include ID' do
14
+ let(:request_path) { 'foo/bar' }
15
+
16
+ before :each do
17
+ expect(client).to receive(request_type).with('https://nationbuilder.com/foo/bar', hash_including(headers: subject.send(:headers)))
18
+ end
19
+
20
+ it 'should perform instrumented request if instrumentation set' do
21
+ instrumentation = double
22
+ expect(instrumentation).to receive(:call).with(hash_including(path: request_path, request_type: request_type))
23
+ expect(subject).to receive(:instrumentation).at_least(:once).and_return(instrumentation)
24
+
25
+ subject.send(request_type, request_path)
26
+ end
27
+
28
+ it 'should perform uninstrumented request if instrumentation not set' do
29
+ expect(subject).to receive(:instrumentation).and_return(nil)
30
+
31
+ subject.send(request_type, request_path)
32
+ end
33
+ end
34
+
35
+ context 'request path includes ID' do
36
+ let(:request_path) { 'foo/123/bar' }
37
+
38
+ before :each do
39
+ expect(client).to receive(request_type).with('https://nationbuilder.com/foo/123/bar', hash_including(headers: subject.send(:headers)))
40
+ end
41
+
42
+ it 'should perform instrumented request normalizing path' do
43
+ instrumentation = double
44
+ expect(instrumentation).to receive(:call).with(hash_including(path: 'foo/_/bar', request_type: request_type))
45
+ expect(subject).to receive(:instrumentation).at_least(:once).and_return(instrumentation)
46
+
47
+ subject.send(request_type, request_path)
48
+ end
49
+ end
50
+
51
+ describe 'error handling' do
52
+ let(:error_response) { double(parsed: nil, body: 'This is an error') }
53
+ let(:oauth_exception) { OAuth2::Error.new(error_response) }
54
+
55
+ before :each do
56
+ allow(error_response).to receive(:error=)
57
+ expect(client).to receive(request_type).and_raise(oauth_exception)
58
+ end
59
+
60
+ context 'error code is "rate_limited"' do
61
+ before :each do
62
+ expect(oauth_exception).to receive(:code).at_least(:once).and_return('rate_limited')
63
+ end
64
+
65
+ it 'should raise RateLimitedError' do
66
+ limit_reset = Time.parse('2017-01-01 12:00 +0000')
67
+ allow(error_response).to receive(:headers).and_return({'x-ratelimit-limit' => '100', 'x-ratelimit-remaining' => '0', 'x-ratelimit-reset' => limit_reset.to_i})
68
+
69
+ error_message = "NationBuilder rate limit error. Current values:\nLimit: 100\nRemaining: 0\nReset: #{Time.at(limit_reset.to_i)}\nBody: This is an error"
70
+
71
+ expect { subject.send(request_type, 'foo/bar') }.to raise_error NationBuilder::RateLimitedError, error_message
72
+ end
73
+
74
+ it 'should not fail if "x-ratelimit-reset" header not present' do
75
+ allow(error_response).to receive(:headers).and_return({'x-ratelimit-limit' => '100', 'x-ratelimit-remaining' => '0'})
76
+ error_message = "NationBuilder rate limit error. Current values:\nLimit: 100\nRemaining: 0\nReset: #{Time.at(0)}\nBody: This is an error"
77
+
78
+ expect { subject.send(request_type, 'foo/bar') }.to raise_error NationBuilder::RateLimitedError, error_message
79
+ end
80
+ end
81
+
82
+ context 'error message includes rate_limited but code is nil' do
83
+ before :each do
84
+ allow(oauth_exception).to receive(:code).and_return(nil)
85
+ allow(oauth_exception).to receive(:message).and_return('{"code":"rate_limited","You have been rate limited."}')
86
+ end
87
+
88
+ it 'should raise RateLimitedError' do
89
+ limit_reset = Time.parse('2017-01-01 12:00 +0000')
90
+ allow(error_response).to receive(:headers).and_return({'x-ratelimit-limit' => '100', 'x-ratelimit-remaining' => '0', 'x-ratelimit-reset' => limit_reset.to_i})
91
+
92
+ error_message = "NationBuilder rate limit error. Current values:\nLimit: 100\nRemaining: 0\nReset: #{Time.at(limit_reset.to_i)}\nBody: This is an error"
93
+
94
+ expect { subject.send(request_type, 'foo/bar') }.to raise_error NationBuilder::RateLimitedError, error_message
95
+ end
96
+ end
97
+
98
+ it 'should raise generic exception if code is not "rate_limited"' do
99
+ expect(oauth_exception).to receive(:code).at_least(:once).and_return('another_error')
100
+
101
+ expect { subject.send(request_type, 'foo/bar') }.to raise_error oauth_exception
102
+ end
103
+ end
104
+ end
105
+
106
+ [:get, :post, :put, :delete].each do |request|
107
+ describe "##{request}" do
108
+ it_behaves_like 'request' do
109
+ let(:request_type) { request }
110
+ end
111
+ end
112
+ end
113
+ end
@@ -2,9 +2,9 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
3
  describe NationBuilder do
4
4
  before(:each) do
5
- NationBuilder::Client.any_instance.stub(:setup_client).and_return(true)
5
+ allow_any_instance_of(NationBuilder::Client).to receive(:setup_client).and_return(true)
6
6
  end
7
7
 
8
- specify { subject.should respond_to :people }
9
- specify { subject.new.should be_a(NationBuilder::Client)}
8
+ specify { expect(subject).to respond_to :people }
9
+ specify { expect(subject.new).to be_a(NationBuilder::Client)}
10
10
  end
data/spec/spec_helper.rb CHANGED
@@ -9,10 +9,6 @@ require 'json'
9
9
  # in ./support/ and its subdirectories.
10
10
  Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
11
11
 
12
- RSpec.configure do |config|
13
- config.color_enabled = true
14
- end
15
-
16
12
 
17
13
  RSpec.configure do |config|
18
14
  config.include WebMock::API
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nation_builder
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.13
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Woodhull
@@ -9,120 +9,120 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-10-28 00:00:00.000000000 Z
12
+ date: 2017-08-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: oauth2
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - '>='
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
20
  version: '0'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
- - - '>='
25
+ - - ">="
26
26
  - !ruby/object:Gem::Version
27
27
  version: '0'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: json
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
- - - '>='
32
+ - - ">="
33
33
  - !ruby/object:Gem::Version
34
34
  version: '0'
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
- - - '>='
39
+ - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
42
  - !ruby/object:Gem::Dependency
43
- name: webmock
43
+ name: activesupport
44
44
  requirement: !ruby/object:Gem::Requirement
45
45
  requirements:
46
- - - '>='
46
+ - - ">"
47
47
  - !ruby/object:Gem::Version
48
- version: '0'
49
- type: :development
48
+ version: 3.0.0
49
+ type: :runtime
50
50
  prerelease: false
51
51
  version_requirements: !ruby/object:Gem::Requirement
52
52
  requirements:
53
- - - '>='
53
+ - - ">"
54
54
  - !ruby/object:Gem::Version
55
- version: '0'
55
+ version: 3.0.0
56
56
  - !ruby/object:Gem::Dependency
57
- name: pry
57
+ name: webmock
58
58
  requirement: !ruby/object:Gem::Requirement
59
59
  requirements:
60
- - - '>='
60
+ - - ">="
61
61
  - !ruby/object:Gem::Version
62
62
  version: '0'
63
63
  type: :development
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
- - - '>='
67
+ - - ">="
68
68
  - !ruby/object:Gem::Version
69
69
  version: '0'
70
70
  - !ruby/object:Gem::Dependency
71
- name: pry-debugger
71
+ name: byebug
72
72
  requirement: !ruby/object:Gem::Requirement
73
73
  requirements:
74
- - - '>='
74
+ - - ">="
75
75
  - !ruby/object:Gem::Version
76
76
  version: '0'
77
77
  type: :development
78
78
  prerelease: false
79
79
  version_requirements: !ruby/object:Gem::Requirement
80
80
  requirements:
81
- - - '>='
81
+ - - ">="
82
82
  - !ruby/object:Gem::Version
83
83
  version: '0'
84
84
  - !ruby/object:Gem::Dependency
85
85
  name: rspec
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
- - - '>='
88
+ - - ">="
89
89
  - !ruby/object:Gem::Version
90
90
  version: '0'
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
- - - '>='
95
+ - - ">="
96
96
  - !ruby/object:Gem::Version
97
97
  version: '0'
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: bundler
100
100
  requirement: !ruby/object:Gem::Requirement
101
101
  requirements:
102
- - - '>='
102
+ - - ">="
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  type: :development
106
106
  prerelease: false
107
107
  version_requirements: !ruby/object:Gem::Requirement
108
108
  requirements:
109
- - - '>='
109
+ - - ">="
110
110
  - !ruby/object:Gem::Version
111
111
  version: '0'
112
112
  - !ruby/object:Gem::Dependency
113
- name: jeweler
113
+ name: juwelier
114
114
  requirement: !ruby/object:Gem::Requirement
115
115
  requirements:
116
- - - ~>
116
+ - - ">="
117
117
  - !ruby/object:Gem::Version
118
- version: 1.8.7
118
+ version: '0'
119
119
  type: :development
120
120
  prerelease: false
121
121
  version_requirements: !ruby/object:Gem::Requirement
122
122
  requirements:
123
- - - ~>
123
+ - - ">="
124
124
  - !ruby/object:Gem::Version
125
- version: 1.8.7
125
+ version: '0'
126
126
  description: Ruby wrapper for NationBuilder API
127
127
  email: nathan@controlshiftlabs.com
128
128
  executables: []
@@ -131,11 +131,11 @@ extra_rdoc_files:
131
131
  - LICENSE.txt
132
132
  - README.md
133
133
  files:
134
- - .document
135
- - .rspec
136
- - .ruby-gemset
137
- - .ruby-version
138
- - .travis.yml
134
+ - ".document"
135
+ - ".rspec"
136
+ - ".ruby-gemset"
137
+ - ".ruby-version"
138
+ - ".travis.yml"
139
139
  - Gemfile
140
140
  - Gemfile.lock
141
141
  - LICENSE.txt
@@ -143,8 +143,15 @@ files:
143
143
  - Rakefile
144
144
  - VERSION
145
145
  - lib/nation_builder.rb
146
+ - lib/nation_builder/actions/create.rb
147
+ - lib/nation_builder/actions/list.rb
148
+ - lib/nation_builder/actions/show.rb
149
+ - lib/nation_builder/actions/update.rb
146
150
  - lib/nation_builder/client.rb
151
+ - lib/nation_builder/exceptions/validation_error.rb
147
152
  - lib/nation_builder/people.rb
153
+ - lib/nation_builder/remote_controller.rb
154
+ - lib/nation_builder/tags.rb
148
155
  - nation_builder.gemspec
149
156
  - spec/client_spec.rb
150
157
  - spec/fixtures/not_found
@@ -163,17 +170,17 @@ require_paths:
163
170
  - lib
164
171
  required_ruby_version: !ruby/object:Gem::Requirement
165
172
  requirements:
166
- - - '>='
173
+ - - ">="
167
174
  - !ruby/object:Gem::Version
168
175
  version: '0'
169
176
  required_rubygems_version: !ruby/object:Gem::Requirement
170
177
  requirements:
171
- - - '>='
178
+ - - ">="
172
179
  - !ruby/object:Gem::Version
173
180
  version: '0'
174
181
  requirements: []
175
182
  rubyforge_project:
176
- rubygems_version: 2.1.10
183
+ rubygems_version: 2.5.2
177
184
  signing_key:
178
185
  specification_version: 4
179
186
  summary: NationBuilder API wrapper