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.
- checksums.yaml +7 -0
- data/CHANGELOG +13 -0
- data/LICENSE +19 -0
- data/Manifest +7 -0
- data/README.md +86 -0
- data/Rakefile +10 -0
- data/lib/towerdata_api.rb +200 -0
- data/lib/towerdata_api/configuration.rb +46 -0
- data/lib/towerdata_api/email_validation.rb +13 -0
- data/lib/towerdata_api/errors.rb +9 -0
- data/towerdata_api.gemspec +24 -0
- metadata +78 -0
checksums.yaml
ADDED
@@ -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
|
data/CHANGELOG
ADDED
@@ -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.
|
data/Manifest
ADDED
data/README.md
ADDED
@@ -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]
|
data/Rakefile
ADDED
@@ -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,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: []
|