towerdata_api 1.3.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,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 53f6bd6c8d2b1d232fdf12fd6506031c51a74d9f
4
+ data.tar.gz: 36bdb7c4537e8f0b7272b3c0c0ff24ec299abb09
5
+ SHA512:
6
+ metadata.gz: 7498f850f77e5d0af26dc927d889813f8d3d47a088d55e3d83c27e503d71c49ff97c75a034e203ddfd5db0309cbeb7befd07ac7fc4fd49f1d1efd7bed2a30e36
7
+ data.tar.gz: ef19b0a10d17c05b47d421ab5874452a0986855b9c7c28d36ec757e9d4d547f4eb9a512e111e8c0af2a7a7810764ea4dc72089103178b6dee69d2274f324ea8b
@@ -0,0 +1,13 @@
1
+ v1.2.3. Bulk API support
2
+
3
+ v1.2.2. Downcase emails before hashing
4
+
5
+ v1.2.1. Support ca_file instead of ca_path in constructor
6
+
7
+ v1.2.0. Bump version number to match User-Agent
8
+
9
+ v0.1.1. Bug fixes
10
+
11
+ v0.1.0. Added support for show_available
12
+
13
+ v0.0.1. Initial version
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ * The Rapleaf Personalization API has separate terms and conditions, which can
2
+ be found at http://www.rapleaf.com/developers/api_usage.
3
+ * If you send us code, please keep in mind that it will be distributed under
4
+ the same license as the rest of the project.
5
+ * This code is licensed under the Apache License which follows...
6
+
7
+ Copyright 2011 Rapleaf
8
+
9
+ Licensed under the Apache License, Version 2.0 (the "License");
10
+ you may not use this file except in compliance with the License.
11
+ You may obtain a copy of the License at
12
+
13
+ http://www.apache.org/licenses/LICENSE-2.0
14
+
15
+ Unless required by applicable law or agreed to in writing, software
16
+ distributed under the License is distributed on an "AS IS" BASIS,
17
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
+ See the License for the specific language governing permissions and
19
+ limitations under the License.
@@ -0,0 +1,7 @@
1
+ CHANGELOG
2
+ LICENSE
3
+ Manifest
4
+ README.md
5
+ Rakefile
6
+ lib/towerdata_api.rb
7
+ towerdata_api.gemspec
@@ -0,0 +1,86 @@
1
+ How to Use
2
+ ==========
3
+
4
+ Installation
5
+ ------------
6
+ > gem install towerdata_api
7
+
8
+ This gem depends on the "json" gem.
9
+
10
+ Usage
11
+ -----
12
+ require 'towerdata_api'
13
+ api = TowerDataApi::Api.new('my secret API key')
14
+ h = api.query_by_email('test@rapleaf.com')
15
+ => {"gender"=>"Male", "age"=>"25-34"}
16
+
17
+ Or using global configuration
18
+
19
+ require 'towerdata_api'
20
+ TowerDataApi::Configuration.begin do |config|
21
+ config.api_key= 'my secret API key'
22
+ config.timeout= 10
23
+ end
24
+ api = TowerDataApi::Api.new
25
+ h = api.query_by_email('test@rapleaf.com')
26
+ => {"gender"=>"Male", "age"=>"25-34"}
27
+
28
+
29
+
30
+ Constructor Options
31
+ -------------------
32
+ You can pass in an options hash to the API constructor, like so:
33
+
34
+ api = TowerData::Api.new('my secret API key', :timeout => 10)
35
+
36
+ The possible options/keys accepted by the constructor are:
37
+
38
+ - :timeout => The max amount of time to wait for a request to finish. Defaults to 2.
39
+ - :ca_file => Set this to your system-wide root CA cert path if you're having SSL verification issues. Defaults to nil.
40
+
41
+ Query Options
42
+ -------------
43
+ The gem supports several ways to query TowerData's API: email, hashed email (either MD5 or SHA1 hash), name and postal (NAP), or name and ZIP+4 (NAZ).
44
+
45
+ ### query_by_email(email, options)
46
+
47
+ This method queries TowerData's API with the specified email. The options hash accepts the following keys:
48
+
49
+ - :hash_email => Whether to (SHA1) hash the email before querying TowerData's API with it. Defaults to nil.
50
+
51
+ ### query_by_md5(md5_email, options)
52
+ ### query_by_sha1(sha1_email, options)
53
+
54
+ ### query_by_nap(first, last, street, city, state, options)
55
+
56
+ This method queries TowerData's API with a name and postal address: first name, last name, street, city, and state acronym (i.e., the state's 2-character postal code). It also accepts the following options hash:
57
+
58
+ - :email => You can include an email in your NAP query to increase the hit rate. Defaults to nil.
59
+
60
+ ### query_by_naz(first, last, zip4, options)
61
+
62
+ This method queries TowerData's API with a name and ZIP+4 code. The ZIP+4 is a string with a 5-digit ZIP code and 4-digit extension separated by a dash. This method accepts the following options:
63
+
64
+ - :email => You can include an email in your NAP query to increase the hit rate. Defaults to nil.
65
+
66
+ ### email_validation(email)
67
+
68
+ This method queries TowerData's API with email and return email_validation object. Raise error if email_validation is not enabled.
69
+
70
+ ### valid_email?(email)
71
+
72
+ This method queries TowerData's API with email and return boolean or nil if response is timeout. Raise error if email_validation is not enabled.
73
+
74
+
75
+ Contributing
76
+ ============
77
+ If you have suggestions or patches, feel free to email us at
78
+ [developer at towerdata dot com]. We look forward to hearing from you!
79
+
80
+
81
+ Contributors
82
+ ============
83
+ - Greg Poulos [greg at rapleaf dot com]
84
+ - Sean Carr [sean at rapleaf dot com]
85
+ - Vlad Shulman [vlad at rapleaf dot com]
86
+ - Bojan Milosavljevic [milboj at gmail dot com]
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ #require 'echoe'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new('spec')
7
+
8
+ # If you want to make this the default task
9
+ task :default => :spec
10
+
@@ -0,0 +1,200 @@
1
+ # Copyright 2011 Rapleaf
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ require "json"
16
+ require "net/https"
17
+ require "timeout"
18
+ require "digest"
19
+ require "open-uri"
20
+ require "towerdata_api/configuration"
21
+ require "towerdata_api/errors"
22
+ require "towerdata_api/email_validation"
23
+
24
+ module TowerDataApi
25
+ HOST= "api.towerdata.com".freeze
26
+ PORT= 443.freeze
27
+ HEADERS = {'User-Agent' => 'TowerDataApi/Ruby/1.3'}.freeze
28
+ API_VERSION= 5.freeze
29
+ BASE_PATH= '/td'.freeze
30
+ BULK_PATH= '/ei/bulk'.freeze
31
+
32
+ class Api
33
+
34
+ def initialize(api_key=nil, options = {})
35
+ @api_key = api_key.nil? ? Configuration.api_key : api_key
36
+ options.each do |key, value|
37
+ Configuration.send("#{key}=", value)
38
+ end
39
+ end
40
+
41
+ # Takes an e-mail and returns a hash which maps attribute fields onto attributes
42
+ # Options:
43
+ # :hash_email - the email will be hashed before it's sent to Rapleaf
44
+ def query_by_email(email, options = {})
45
+ if options[:hash_email]
46
+ query_by_sha1(Digest::SHA1.hexdigest(email.downcase))
47
+ else
48
+ get_json_response("#{base_path}&email=#{url_encode(email)}")
49
+ end
50
+ end
51
+
52
+ # Takes an e-mail that has already been hashed by md5
53
+ # and returns a hash which maps attribute fields onto attributes,
54
+ # optionally showing available data in the response
55
+ def query_by_md5(md5_email, options = {})
56
+ get_json_response("#{base_path}&md5_email=#{url_encode(md5_email)}")
57
+ end
58
+
59
+ # Takes an e-mail that has already been hashed by sha1
60
+ # and returns a hash which maps attribute fields onto attributes,
61
+ # optionally showing available data in the response
62
+ def query_by_sha1(sha1_email, options = {})
63
+ get_json_response("#{base_path}&sha1_email=#{url_encode(sha1_email)}")
64
+ end
65
+
66
+ # Takes first name, last name, and postal (street, city, and state acronym),
67
+ # and returns a hash which maps attribute fields onto attributes
68
+ # Options:
69
+ # :email - query with an email to increase the hit rate
70
+ def query_by_nap(first, last, street, city, state, options = {})
71
+ if options[:email]
72
+ url = "#{base_path}&email=#{url_encode(options[:email])}&first=#{url_encode(first)}&last=#{url_encode(last)}" +
73
+ "&street=#{url_encode(street)}&city=#{url_encode(city)}&state=#{url_encode(state)}"
74
+ else
75
+ url = "#{base_path}&first=#{url_encode(first)}&last=#{url_encode(last)}" +
76
+ "&street=#{url_encode(street)}&city=#{url_encode(city)}&state=#{url_encode(state)}"
77
+ end
78
+ get_json_response(url)
79
+ end
80
+
81
+ # Takes first name, last name, and zip4 code (5-digit zip
82
+ # and 4-digit extension separated by a dash as a string),
83
+ # and returns a hash which maps attribute fields onto attributes
84
+ # Options:
85
+ # :email - query with an email to increase the hit rate
86
+ def query_by_naz(first, last, zip4, options = {})
87
+ if options[:email]
88
+ url = "#{base_path}&email=#{url_encode(options[:email])}&first=#{url_encode(first)}&last=#{url_encode(last)}&zip4=#{zip4}"
89
+ else
90
+ url = "#{base_path}&first=#{url_encode(first)}&last=#{url_encode(last)}&zip4=#{zip4}"
91
+ end
92
+ get_json_response(url)
93
+ end
94
+
95
+
96
+ # For given email returns EmailValidation object
97
+ # This method will rise TowerDataApi::Error::Unsupported
98
+ # if yours api key doesn't have email validation field
99
+ #
100
+ def email_validation email
101
+ begin
102
+ result = query_by_email email
103
+ rescue TowerDataApi::Error::BadRequest
104
+ result = {'email_validation' => {'ok' => false}}
105
+ end
106
+
107
+ if result.has_key? 'email_validation'
108
+ EmailValidation.new result['email_validation']
109
+ else
110
+ raise TowerDataApi::Error::Unsupported, 'Email validation is not supported with yours api key.'
111
+ end
112
+ end
113
+
114
+ # Check is email valid
115
+ # This method will rise TowerDataApi::Error::Api
116
+ # if yours api key doesn't have email validation field
117
+ # Value can be true, false and nil
118
+ def valid_email? email
119
+ email_validation(email).valid?
120
+ end
121
+
122
+
123
+ # Get bulk request
124
+ # set - is array of hashes in format
125
+ #
126
+ # [{email: 'first_email'}, {email: 'second_email'}]
127
+ #
128
+ def bulk_query(set)
129
+ get_bulk_response(bulk_path, JSON.generate(set))
130
+ end
131
+
132
+ private
133
+
134
+ def url_encode value
135
+ URI::encode value
136
+ end
137
+
138
+ def get_bulk_response(path, data)
139
+ response = Timeout::timeout(@BULK_TIMEOUT) do
140
+ begin
141
+ http_client.post(path, data, HEADERS.merge('Content-Type' => 'application/json'))
142
+ rescue EOFError # Connection cut out. Just try a second time.
143
+ http_client.post(path, data, HEADERS.merge('Content-Type' => 'application/json'))
144
+ end
145
+ end
146
+
147
+ if response.code =~ /^2\d\d/
148
+ (response.body && response.body != "") ? JSON.parse(response.body) : []
149
+ else
150
+ raise TowerDataApi::Error::Api, "Error Code #{response.code}: \"#{response.body}\""
151
+ end
152
+ end
153
+
154
+ # Takes a url and returns a hash mapping attribute fields onto attributes
155
+ # Note that an exception is raised in the case that
156
+ # an HTTP response code other than 200 is sent back
157
+ # The error code and error body are put in the exception's message
158
+ def get_json_response(path)
159
+ response = Timeout::timeout(Configuration.timeout) do
160
+ begin
161
+ http_client.get(path, HEADERS)
162
+ rescue EOFError # Connection cut out. Just try a second time.
163
+ http_client.get(path, HEADERS)
164
+ end
165
+ end
166
+
167
+ if response.code =~ /^2\d\d/
168
+ (response.body && response.body != "") ? JSON.parse(response.body) : {}
169
+ elsif response.code == '400'
170
+ raise TowerDataApi::Error::BadRequest, "Bad request#{response.code}: \"#{response.body}\""
171
+ else
172
+ raise TowerDataApi::Error::Api, "Error Code #{response.code}: \"#{response.body}\""
173
+ end
174
+ end
175
+
176
+ # Returns http connection to HOST on PORT
177
+ def http_client
178
+ unless defined?(@http_client)
179
+ @http_client = Net::HTTP.new(HOST, PORT)
180
+ @http_client.use_ssl = true
181
+ @http_client.ca_file = Configuration.ca_file if Configuration.ca_file
182
+ #@http_client.verify_mode = OpenSSL::SSL::VERIFY_PEER
183
+ @http_client.start
184
+ end
185
+ @http_client
186
+ end
187
+
188
+ def bulk_path
189
+ "#{api_path}#{BULK_PATH}?api_key=#{@api_key}"
190
+ end
191
+
192
+ def base_path
193
+ "#{api_path}#{BASE_PATH}?api_key=#{@api_key}"
194
+ end
195
+
196
+ def api_path
197
+ "/v#{API_VERSION}"
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,46 @@
1
+ module TowerDataApi
2
+ class Configuration
3
+
4
+ @@api_key = nil
5
+ @@ca_file = nil
6
+ @@bulk_timeout = 30
7
+ @@timeout = 2
8
+
9
+ def self.api_key= api_key
10
+ @@api_key = api_key
11
+ end
12
+
13
+ def self.api_key
14
+ @@api_key
15
+ end
16
+
17
+ def self.ca_file= ca_file
18
+ @@ca_file = ca_file
19
+ end
20
+
21
+ def self.ca_file
22
+ @@ca_file
23
+ end
24
+
25
+ def self.timeout= timeout
26
+ @@timeout = timeout
27
+ end
28
+
29
+ def self.timeout
30
+ @@timeout
31
+ end
32
+
33
+ def self.bulk_timeout= timeout
34
+ @@bulk_timeout = timeout
35
+ end
36
+
37
+ def self.timeout
38
+ @@timeout
39
+ end
40
+
41
+ def self.begin
42
+ yield self
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,13 @@
1
+ module TowerDataApi
2
+ class EmailValidation
3
+ attr_accessor :status_code, :status, :ok, :domain_type, :email_correction
4
+ alias_method :valid?, :ok
5
+
6
+ def initialize values
7
+ values.each do |key, value|
8
+ self.send("#{key}=", value)
9
+ end
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,9 @@
1
+ module TowerDataApi
2
+ module Error
3
+ class Base < StandardError; end
4
+ class Configuration < Base; end
5
+ class Api < Base; end
6
+ class BadRequest < Base; end
7
+ class Unsupported < Base; end
8
+ end
9
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{towerdata_api}
5
+ s.version = "1.3.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["TowerData"]
9
+ s.date = %q{2014-12-17}
10
+ s.description = %q{A library for interacting with TowerData's Personalization and Utilities APIs.}
11
+ s.email = %q{developer @nospam@ towerdata.com}
12
+ s.extra_rdoc_files = ["CHANGELOG", "LICENSE", "README.md", "lib/towerdata_api.rb"]
13
+ s.files = Dir["{lib}/**/*"] + ["CHANGELOG", "LICENSE", "Manifest", "README.md", "Rakefile", "towerdata_api.gemspec"]
14
+ s.homepage = %q{http://www.towerdata.com}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Rapleaf_api", "--main", "README.md"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{towerdata_api}
18
+ s.license = 'Apache-2.0'
19
+
20
+ s.rubygems_version = ">=1.6.1"
21
+ s.summary = %q{A library for interacting with TowerData's Personalization API.}
22
+ s.add_development_dependency "rspec", '~>3.1'
23
+
24
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: towerdata_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.3.1
5
+ platform: ruby
6
+ authors:
7
+ - TowerData
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-12-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.1'
27
+ description: A library for interacting with TowerData's Personalization and Utilities
28
+ APIs.
29
+ email: developer @nospam@ towerdata.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files:
33
+ - CHANGELOG
34
+ - LICENSE
35
+ - README.md
36
+ - lib/towerdata_api.rb
37
+ files:
38
+ - CHANGELOG
39
+ - LICENSE
40
+ - Manifest
41
+ - README.md
42
+ - Rakefile
43
+ - lib/towerdata_api.rb
44
+ - lib/towerdata_api/configuration.rb
45
+ - lib/towerdata_api/email_validation.rb
46
+ - lib/towerdata_api/errors.rb
47
+ - towerdata_api.gemspec
48
+ homepage: http://www.towerdata.com
49
+ licenses:
50
+ - Apache-2.0
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options:
54
+ - "--line-numbers"
55
+ - "--inline-source"
56
+ - "--title"
57
+ - Rapleaf_api
58
+ - "--main"
59
+ - README.md
60
+ require_paths:
61
+ - lib
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: '1.2'
72
+ requirements: []
73
+ rubyforge_project: towerdata_api
74
+ rubygems_version: 2.2.2
75
+ signing_key:
76
+ specification_version: 4
77
+ summary: A library for interacting with TowerData's Personalization API.
78
+ test_files: []