nationbuilder-rb 0.0.1

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.
@@ -0,0 +1,97 @@
1
+ class NationBuilder::Client
2
+
3
+ def initialize(nation_name, api_key)
4
+ @nation_name = nation_name
5
+ @api_key = api_key
6
+ @name_to_endpoint = {}
7
+ parsed_endpoints.each do |endpoint|
8
+ @name_to_endpoint[endpoint.name] = endpoint
9
+ end
10
+ end
11
+
12
+ def parsed_endpoints
13
+ NationBuilder::SpecParser
14
+ .parse(File.join(File.dirname(__FILE__), 'api_spec.json'))
15
+ end
16
+
17
+ def [](endpoint)
18
+ @name_to_endpoint[endpoint]
19
+ end
20
+
21
+ def endpoints
22
+ @name_to_endpoint.keys
23
+ end
24
+
25
+ def base_url
26
+ @base_url ||=
27
+ NationBuilder::URL_TEMPLATE.gsub(':nation_name', @nation_name)
28
+ end
29
+
30
+ def call(endpoint_name, method_name, args={})
31
+ endpoint = self[endpoint_name]
32
+ method = endpoint[method_name]
33
+ nonmethod_args = method.nonmethod_args(args)
34
+ method_args = method.method_args(args)
35
+ method.validate_args(method_args)
36
+ url = NationBuilder.generate_url(base_url, method.uri, method_args)
37
+
38
+ request_args = {
39
+ header: {
40
+ 'Accept' => 'application/json',
41
+ 'Content-Type' => 'application/json'
42
+ }
43
+ }
44
+
45
+ if method.http_method == :get
46
+ request_args[:query] = nonmethod_args
47
+ request_args[:query][:access_token] = @api_key
48
+ else
49
+ nonmethod_args[:access_token] = @api_key
50
+ request_args[:body] = JSON(nonmethod_args)
51
+ end
52
+
53
+ response = HTTPClient.send(method.http_method, url, request_args)
54
+ return parse_response_body(response)
55
+ end
56
+
57
+ class ServerResponseError < StandardError; end
58
+
59
+ def parse_response_body(response)
60
+ success = response.code.to_s.start_with?('2')
61
+
62
+ if response.header['Content-Type'].first != 'application/json'
63
+ return {} if success
64
+ raise ServerResponseError.new("Non-JSON content-type for server response: #{response.body}")
65
+ end
66
+
67
+ body = response.body.strip
68
+ return {} if body.length == 0
69
+ return JSON.parse(body)
70
+ end
71
+
72
+ def print_all_descriptions
73
+ endpoints.each do |endpoint_name|
74
+ self.print_description(endpoint_name)
75
+ puts
76
+ end
77
+ end
78
+
79
+ def print_description(endpoint_name)
80
+ endpoint_str = "Endpoint: #{endpoint_name}"
81
+ puts "=" * endpoint_str.length
82
+ puts endpoint_str
83
+ puts "=" * endpoint_str.length
84
+
85
+ self[endpoint_name.to_sym].methods.each do |method_name|
86
+ puts
87
+ method = self[endpoint_name][method_name]
88
+ puts " Method: #{method_name.inspect}"
89
+ puts " Description: #{method.description}"
90
+ required_params = method.parameters.map { |p| p.inspect }
91
+ if required_params.any?
92
+ puts " Required parameters: #{required_params.join(', ')}"
93
+ end
94
+ end
95
+ end
96
+
97
+ end
@@ -0,0 +1,24 @@
1
+ class NationBuilder::Endpoint
2
+
3
+ def initialize(name)
4
+ @name = name
5
+ @name_to_method = {}
6
+ end
7
+
8
+ def name
9
+ @name.downcase.gsub(' ', '_').to_sym
10
+ end
11
+
12
+ def register_method(method)
13
+ @name_to_method[method.name] = method
14
+ end
15
+
16
+ def methods
17
+ @methods ||= @name_to_method.keys
18
+ end
19
+
20
+ def [](method_name)
21
+ @name_to_method[method_name]
22
+ end
23
+
24
+ end
@@ -0,0 +1,48 @@
1
+ class NationBuilder::Method
2
+
3
+ attr_reader :uri, :http_method, :description
4
+
5
+ def initialize(name, http_method, uri, description)
6
+ @name = name
7
+ @http_method = http_method.downcase.to_sym
8
+ @uri = uri
9
+ @description = description
10
+ @name_to_parameter = {}
11
+ end
12
+
13
+ def register_parameter(parameter)
14
+ @name_to_parameter[parameter.name] = parameter
15
+ end
16
+
17
+ def parameters
18
+ @name_to_parameter.keys
19
+ end
20
+
21
+ def name
22
+ @name.downcase.gsub(' ', '_').to_sym
23
+ end
24
+
25
+ def validate_args(args)
26
+ if Set.new(args.keys) != Set.new(parameters)
27
+ raise ArgumentError
28
+ .new("Required args: #{parameters.join(', ')}. Provided args: #{args.keys.join(', ')}")
29
+ end
30
+ end
31
+
32
+ def method_args(args)
33
+ a = {}
34
+ args.each do |k, v|
35
+ a[k] = v if parameters.include?(k)
36
+ end
37
+ a
38
+ end
39
+
40
+ def nonmethod_args(args)
41
+ a = {}
42
+ args.each do |k, v|
43
+ a[k] = v unless parameters.include?(k)
44
+ end
45
+ a
46
+ end
47
+
48
+ end
@@ -0,0 +1,9 @@
1
+ class NationBuilder::Parameter
2
+
3
+ attr_reader :name
4
+
5
+ def initialize(name)
6
+ @name = name.to_sym
7
+ end
8
+
9
+ end
@@ -0,0 +1,28 @@
1
+ class NationBuilder::SpecParser
2
+
3
+ def self.parse(spec_path)
4
+ spec = JSON.parse(File.read(spec_path))
5
+ endpoints = []
6
+
7
+ spec['endpoints'].each do |endpoint|
8
+ nb_endpoint = NationBuilder::Endpoint.new(endpoint['name'])
9
+ endpoints << nb_endpoint
10
+ endpoint['methods'].each do |method|
11
+ nb_method = NationBuilder::Method.new(method['MethodName'],
12
+ method['HTTPMethod'],
13
+ method['URI'],
14
+ method['Synopsis'])
15
+ nb_endpoint.register_method(nb_method)
16
+ method['parameters'].each do |parameter|
17
+ if (parameter['Required'] == 'Y') && (parameter['Name'] != 'body')
18
+ nb_parameter = NationBuilder::Parameter.new(parameter['Name'])
19
+ nb_method.register_parameter(nb_parameter)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ endpoints
26
+ end
27
+
28
+ end
@@ -0,0 +1,80 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+ # stub: nationbuilder-rb 0.0.1 ruby lib
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = "nationbuilder-rb"
9
+ s.version = "0.0.1"
10
+
11
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
12
+ s.authors = ["David Huie"]
13
+ s.date = "2014-06-26"
14
+ s.description = "A Ruby client to the NationBuilder API"
15
+ s.email = "david@nationbuilder.com"
16
+ s.executables = ["nbdoc"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE.txt",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".document",
23
+ ".rspec",
24
+ ".ruby-gemset",
25
+ "Gemfile",
26
+ "Gemfile.lock",
27
+ "LICENSE.txt",
28
+ "README.md",
29
+ "Rakefile",
30
+ "VERSION",
31
+ "bin/nbdoc",
32
+ "lib/nationbuilder.rb",
33
+ "lib/nationbuilder/api_spec.json",
34
+ "lib/nationbuilder/client.rb",
35
+ "lib/nationbuilder/endpoint.rb",
36
+ "lib/nationbuilder/method.rb",
37
+ "lib/nationbuilder/parameter.rb",
38
+ "lib/nationbuilder/spec_parser.rb",
39
+ "nationbuilder-rb.gemspec",
40
+ "spec/fixtures/delete.yml",
41
+ "spec/fixtures/parametered_get.yml",
42
+ "spec/fixtures/parametered_post.yml",
43
+ "spec/fixtures/parametered_put.yml",
44
+ "spec/nationbuilder_client_spec.rb",
45
+ "spec/spec_helper.rb"
46
+ ]
47
+ s.homepage = "http://github.com/3dna/nationbuilder-rb"
48
+ s.licenses = ["MIT"]
49
+ s.require_paths = ["lib"]
50
+ s.rubygems_version = "2.1.11"
51
+ s.summary = "A Ruby client to the NationBuilder API"
52
+
53
+ if s.respond_to? :specification_version then
54
+ s.specification_version = 4
55
+
56
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
57
+ s.add_runtime_dependency(%q<httpclient>, ["~> 2.4.0"])
58
+ s.add_development_dependency(%q<jeweler>, ["~> 2.0.1"])
59
+ s.add_development_dependency(%q<rspec>, ["~> 2.8.0"])
60
+ s.add_development_dependency(%q<simplecov>, ["~> 0.8.2"])
61
+ s.add_development_dependency(%q<vcr>, ["~> 2.9.2"])
62
+ s.add_development_dependency(%q<webmock>, ["~> 1.18.0"])
63
+ else
64
+ s.add_dependency(%q<httpclient>, ["~> 2.4.0"])
65
+ s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
66
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
67
+ s.add_dependency(%q<simplecov>, ["~> 0.8.2"])
68
+ s.add_dependency(%q<vcr>, ["~> 2.9.2"])
69
+ s.add_dependency(%q<webmock>, ["~> 1.18.0"])
70
+ end
71
+ else
72
+ s.add_dependency(%q<httpclient>, ["~> 2.4.0"])
73
+ s.add_dependency(%q<jeweler>, ["~> 2.0.1"])
74
+ s.add_dependency(%q<rspec>, ["~> 2.8.0"])
75
+ s.add_dependency(%q<simplecov>, ["~> 0.8.2"])
76
+ s.add_dependency(%q<vcr>, ["~> 2.9.2"])
77
+ s.add_dependency(%q<webmock>, ["~> 1.18.0"])
78
+ end
79
+ end
80
+
@@ -0,0 +1,65 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: delete
5
+ uri: https://dh.nationbuilder.com/api/v1/people/15
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"access_token":"6e516b5d9a3d21b3cc079bc303c01aae3d59c8d4a7e9e6d2acfc11dada0e054e"}'
9
+ headers:
10
+ User-Agent:
11
+ - HTTPClient/1.0 (2.4.0, ruby 2.0.0 (2013-11-22))
12
+ Accept:
13
+ - application/json
14
+ Date:
15
+ - Wed, 25 Jun 2014 22:41:37 GMT
16
+ Content-Type:
17
+ - application/json
18
+ response:
19
+ status:
20
+ code: 204
21
+ message: No Content
22
+ headers:
23
+ Server:
24
+ - cloudflare-nginx
25
+ Date:
26
+ - Wed, 25 Jun 2014 22:41:39 GMT
27
+ Content-Type:
28
+ - application/octet-stream
29
+ Content-Length:
30
+ - '0'
31
+ Connection:
32
+ - keep-alive
33
+ Set-Cookie:
34
+ - __cfduid=d4ac3918ff3dbcc509787eadf8b8b90451403736098139; expires=Mon, 23-Dec-2019
35
+ 23:50:00 GMT; path=/; domain=.nationbuilder.com; HttpOnly
36
+ X-Ua-Compatible:
37
+ - IE=Edge,chrome=1
38
+ Cache-Control:
39
+ - no-cache
40
+ Nation-Ratelimit-Limit:
41
+ - '10000'
42
+ Nation-Ratelimit-Remaining:
43
+ - '9968'
44
+ Nation-Ratelimit-Reset:
45
+ - '1403740800'
46
+ X-Request-Id:
47
+ - f00da219be79923c08a78e821cc4897b
48
+ X-Runtime:
49
+ - '0.994571'
50
+ X-Rack-Cache:
51
+ - invalidate, pass
52
+ X-Powered-By:
53
+ - Phusion Passenger 4.0.23
54
+ Status:
55
+ - 204 No Content
56
+ Via:
57
+ - 1.1 nationbuilder.com
58
+ Cf-Ray:
59
+ - 1404ac75519c0d67-LAX
60
+ body:
61
+ encoding: UTF-8
62
+ string: ''
63
+ http_version:
64
+ recorded_at: Wed, 25 Jun 2014 22:41:39 GMT
65
+ recorded_with: VCR 2.9.2
@@ -0,0 +1,79 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: https://dh.nationbuilder.com/api/v1/sites/dh/pages/basic_pages?access_token=6e516b5d9a3d21b3cc079bc303c01aae3d59c8d4a7e9e6d2acfc11dada0e054e
6
+ body:
7
+ encoding: UTF-8
8
+ string: ''
9
+ headers:
10
+ User-Agent:
11
+ - HTTPClient/1.0 (2.4.0, ruby 2.0.0 (2013-11-22))
12
+ Accept:
13
+ - application/json
14
+ Date:
15
+ - Wed, 25 Jun 2014 22:28:30 GMT
16
+ Content-Type:
17
+ - application/json
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Server:
24
+ - cloudflare-nginx
25
+ Date:
26
+ - Wed, 25 Jun 2014 22:28:31 GMT
27
+ Content-Type:
28
+ - application/json
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Connection:
32
+ - keep-alive
33
+ Set-Cookie:
34
+ - __cfduid=d32a8837f08e39176e4d1ed146327e7201403735310572; expires=Mon, 23-Dec-2019
35
+ 23:50:00 GMT; path=/; domain=.nationbuilder.com; HttpOnly
36
+ X-Ua-Compatible:
37
+ - IE=Edge,chrome=1
38
+ Cache-Control:
39
+ - max-age=0, private, must-revalidate
40
+ Nation-Ratelimit-Limit:
41
+ - '10000'
42
+ Nation-Ratelimit-Remaining:
43
+ - '9973'
44
+ Nation-Ratelimit-Reset:
45
+ - '1403740800'
46
+ X-Request-Id:
47
+ - c833875bc9d08cf43ca93454d0a4f70f
48
+ X-Runtime:
49
+ - '0.697364'
50
+ X-Rack-Cache:
51
+ - miss
52
+ X-Powered-By:
53
+ - Phusion Passenger 4.0.23
54
+ Status:
55
+ - 200 OK
56
+ Vary:
57
+ - Accept-Encoding
58
+ Via:
59
+ - 1.1 nationbuilder.com
60
+ Cf-Ray:
61
+ - 1404993b14380d67-LAX
62
+ body:
63
+ encoding: UTF-8
64
+ string: '{"page":1,"total_pages":1,"per_page":10,"total":1,"results":[{"slug":"about","path":"/about","status":"published","site_slug":"dh","name":"About","headline":"About","title":"About
65
+ - dh","excerpt":"","author_id":2,"published_at":"2013-07-08T11:07:00-07:00","external_id":null,"tags":[],"id":1,"content":"<div
66
+ style=\"float: right; margin: 0 0 10px 25px;\"><img class=\"img-circle\" src=\"boats.jpg\"
67
+ alt=\"\"></div>\r\n<p>This is where you tell everyone what your blog is about.
68
+ Explain what the intended purpose of your blog is, if there is one. If multiple
69
+ people will be writing for your blog, you might consider posting photos and
70
+ bios of the contributors.</p>\r\n<p>Proin libero diam, consequat ut nisl vestibulum,
71
+ commodo scelerisque lacus. In vehicula, est quis rhoncus tristique, dolor
72
+ sapien aliquam arcu, ut vulputate quam enim quis augue. Phasellus id nunc
73
+ vitae lectus dapibus viverra malesuada at nibh. Suspendisse sagittis odio
74
+ non ipsum feugiat porta.</p>\r\n<p>\u00a0</p>\r\n<p><strong>To change this
75
+ content, click \"Edit this page\" in the Supporter Nav on the right,<br>or
76
+ from your Control Panel navigate to Websites &gt; [about] &gt; Content.</strong></p>"}]}'
77
+ http_version:
78
+ recorded_at: Wed, 25 Jun 2014 22:28:31 GMT
79
+ recorded_with: VCR 2.9.2
@@ -0,0 +1,68 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: post
5
+ uri: https://dh.nationbuilder.com/api/v1/people
6
+ body:
7
+ encoding: UTF-8
8
+ string: '{"person":{"email":"bob@example.com","last_name":"Smith","first_name":"Bob"},"access_token":"6e516b5d9a3d21b3cc079bc303c01aae3d59c8d4a7e9e6d2acfc11dada0e054e"}'
9
+ headers:
10
+ User-Agent:
11
+ - HTTPClient/1.0 (2.4.0, ruby 2.0.0 (2013-11-22))
12
+ Accept:
13
+ - application/json
14
+ Date:
15
+ - Wed, 25 Jun 2014 22:35:22 GMT
16
+ Content-Type:
17
+ - application/json
18
+ response:
19
+ status:
20
+ code: 201
21
+ message: Created
22
+ headers:
23
+ Server:
24
+ - cloudflare-nginx
25
+ Date:
26
+ - Wed, 25 Jun 2014 22:35:22 GMT
27
+ Content-Type:
28
+ - application/json
29
+ Transfer-Encoding:
30
+ - chunked
31
+ Connection:
32
+ - keep-alive
33
+ Set-Cookie:
34
+ - __cfduid=d184a711d4f638864b5e1fa438601ebdc1403735721919; expires=Mon, 23-Dec-2019
35
+ 23:50:00 GMT; path=/; domain=.nationbuilder.com; HttpOnly
36
+ X-Ua-Compatible:
37
+ - IE=Edge,chrome=1
38
+ Cache-Control:
39
+ - max-age=0, private, must-revalidate
40
+ Nation-Ratelimit-Limit:
41
+ - '10000'
42
+ Nation-Ratelimit-Remaining:
43
+ - '9972'
44
+ Nation-Ratelimit-Reset:
45
+ - '1403740800'
46
+ X-Request-Id:
47
+ - 34e7f148285faf579d2885dee6cb5571
48
+ X-Runtime:
49
+ - '0.715257'
50
+ X-Rack-Cache:
51
+ - invalidate, pass
52
+ X-Powered-By:
53
+ - Phusion Passenger 4.0.23
54
+ Status:
55
+ - 201 Created
56
+ Vary:
57
+ - Accept-Encoding
58
+ Via:
59
+ - 1.1 nationbuilder.com
60
+ Cf-Ray:
61
+ - 1404a345f7b20d67-LAX
62
+ body:
63
+ encoding: UTF-8
64
+ string: '{"person":{"birthdate":null,"city_district":null,"civicrm_id":null,"county_district":null,"county_file_id":null,"created_at":"2014-06-25T15:35:22-07:00","do_not_call":false,"do_not_contact":false,"dw_id":null,"email":"bob@example.com","email_opt_in":true,"employer":null,"external_id":null,"federal_district":null,"fire_district":null,"first_name":"Bob","has_facebook":false,"id":15,"is_twitter_follower":false,"is_volunteer":false,"judicial_district":null,"labour_region":null,"last_name":"Smith","linkedin_id":null,"mobile":null,"mobile_opt_in":true,"nbec_guid":null,"ngp_id":null,"note":null,"occupation":null,"party":null,"pf_strat_id":null,"phone":null,"precinct_id":null,"primary_address":null,"recruiter_id":null,"rnc_id":null,"rnc_regid":null,"salesforce_id":null,"school_district":null,"school_sub_district":null,"sex":null,"state_file_id":null,"state_lower_district":null,"state_upper_district":null,"support_level":null,"supranational_district":null,"tags":[],"twitter_id":null,"twitter_name":null,"updated_at":"2014-06-25T15:35:22-07:00","van_id":null,"village_district":null,"active_customer_expires_at":null,"active_customer_started_at":null,"author":null,"author_id":null,"auto_import_id":null,"availability":null,"banned_at":null,"billing_address":null,"bio":null,"call_status_id":null,"call_status_name":null,"capital_amount_in_cents":0,"children_count":0,"church":null,"city_sub_district":null,"closed_invoices_amount_in_cents":null,"closed_invoices_count":null,"contact_status_id":null,"contact_status_name":null,"could_vote_status":null,"demo":null,"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":null,"facebook_address":null,"facebook_profile_url":null,"facebook_updated_at":null,"facebook_username":null,"fax_number":null,"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-06-25T15:35:22-07:00","first_volunteer_at":null,"full_name":"Bob
65
+ Smith","home_address":null,"import_id":null,"inferred_party":null,"inferred_support_level":null,"invoice_payments_amount_in_cents":0,"invoice_payments_referred_amount_in_cents":0,"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":null,"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":null,"mailing_address":null,"marital_status":null,"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":0,"page_slug":null,"parent":null,"parent_id":null,"party_member":false,"phone_normalized":null,"phone_time":null,"precinct_code":null,"precinct_name":null,"prefix":null,"previous_party":null,"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":0,"recruiter":null,"recruits_count":0,"registered_address":null,"registered_at":null,"religion":null,"rule_violations_count":0,"spent_capital_amount_in_cents":0,"submitted_address":null,"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":null,"username":null,"warnings_count":0,"website":null,"work_address":null,"work_phone_number":null},"precinct":null}'
66
+ http_version:
67
+ recorded_at: Wed, 25 Jun 2014 22:35:23 GMT
68
+ recorded_with: VCR 2.9.2