nation_builder 0.0.6 → 0.0.13

Sign up to get free protection for your applications and to get access to all the features.
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