pocus 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 8896dcbe66d0ba28169c9cd8f073d9b165f7bbf2
4
+ data.tar.gz: 9eabcc7873c4040bdc0caee91c37b63787056b0c
5
+ SHA512:
6
+ metadata.gz: b64105a21925bbfc931c664e82650c41149573074983f08674762fb5332e0bba69a5c754a1befeff2696b851363c280c4a9bf39c1270a8cf372f90786370f4b1
7
+ data.tar.gz: 781724db172ae05386e1031cbac66e11704c64aa853459475f3a516e17232588e31ca43ab6997eaeb671a9fbafae92f049c1b69b95aaf29a4265c2978e873fd1
data/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2016 [Varyonic](https://www.varyonic.com).
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,100 @@
1
+ # Pocus
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/pocus.svg)](http://badge.fury.io/rb/pocus)
4
+ [![Code Climate GPA](https://codeclimate.com/github//pocus.svg)](https://codeclimate.com/github//pocus)
5
+ [![Code Climate Coverage](https://codeclimate.com/github//pocus/coverage.svg)](https://codeclimate.com/github//pocus)
6
+ [![Gemnasium Status](https://gemnasium.com//pocus.svg)](https://gemnasium.com//pocus)
7
+ [![Travis CI Status](https://secure.travis-ci.org//pocus.svg)](https://travis-ci.org//pocus)
8
+
9
+ <!-- Tocer[start]: Auto-generated, don't remove. -->
10
+
11
+ # Table of Contents
12
+
13
+ - [Features](#features)
14
+ - [Requirements](#requirements)
15
+ - [Setup](#setup)
16
+ - [Usage](#usage)
17
+ - [Tests](#tests)
18
+ - [Versioning](#versioning)
19
+ - [Code of Conduct](#code-of-conduct)
20
+ - [Contributions](#contributions)
21
+ - [License](#license)
22
+ - [History](#history)
23
+ - [Credits](#credits)
24
+
25
+ <!-- Tocer[finish]: Auto-generated, don't remove. -->
26
+
27
+ # Features
28
+
29
+ Unofficial Ruby API client for [iContact API](See https://www.icontact.com/developerportal), fka. Vocus
30
+
31
+ # Requirements
32
+
33
+ 0. [MRI 2.3.0](https://www.ruby-lang.org)
34
+
35
+ # Setup
36
+
37
+ For a secure install, type the following (recommended):
38
+
39
+ gem cert --add <(curl --location --silent https://www.varyonic.com/gem-public.pem)
40
+ gem install pocus --trust-policy MediumSecurity
41
+
42
+ NOTE: A HighSecurity trust policy would be best but MediumSecurity enables signed gem verification while
43
+ allowing the installation of unsigned dependencies since they are beyond the scope of this gem.
44
+
45
+ For an insecure install, type the following (not recommended):
46
+
47
+ gem install pocus
48
+
49
+ Add the following to your Gemfile:
50
+
51
+ gem "pocus"
52
+
53
+ # Usage
54
+
55
+ # Tests
56
+
57
+ To run the tests you will need your own iContact account with a test folder. Populate ~/.pocus/fixtures.yml as follows:
58
+
59
+ ```
60
+ credentials:
61
+ app_id: ...
62
+ username: ...
63
+ password: ...
64
+ account_id: ...
65
+ test_client_folder_id: ...
66
+ ```
67
+ To test, run:
68
+
69
+ bundle exec rake
70
+
71
+ # Versioning
72
+
73
+ Read [Semantic Versioning](http://semver.org) for details. Briefly, it means:
74
+
75
+ - Patch (x.y.Z) - Incremented for small, backwards compatible bug fixes.
76
+ - Minor (x.Y.z) - Incremented for new, backwards compatible public API enhancements and/or bug fixes.
77
+ - Major (X.y.z) - Incremented for any backwards incompatible public API changes.
78
+
79
+ # Code of Conduct
80
+
81
+ Please note that this project is released with a [CODE OF CONDUCT](CODE_OF_CONDUCT.md). By participating in this project
82
+ you agree to abide by its terms.
83
+
84
+ # Contributions
85
+
86
+ Read [CONTRIBUTING](CONTRIBUTING.md) for details.
87
+
88
+ # License
89
+
90
+ Copyright (c) 2016 [Varyonic](https://www.varyonic.com).
91
+ Read the [LICENSE](LICENSE.md) for details.
92
+
93
+ # History
94
+
95
+ Read the [CHANGELOG](CHANGELOG.md) for details.
96
+ Built with [Gemsmith](https://github.com/bkuhlmann/gemsmith).
97
+
98
+ # Credits
99
+
100
+ Developed by [Piers Chambers](https://www.varyonic.com) at [Varyonic](https://www.varyonic.com).
@@ -0,0 +1,8 @@
1
+ module Pocus
2
+ class Account < Resource
3
+ self.path = :a
4
+ self.primary_key = :account_id
5
+
6
+ has_many :clientfolders, path: '/c', class: 'ClientFolder'
7
+ end
8
+ end
@@ -0,0 +1,35 @@
1
+ module Pocus
2
+ class Association < Array
3
+ attr_reader :owner, :path, :klass
4
+
5
+ def initialize(owner, name, options)
6
+ @owner = owner
7
+ @path = options[:path] || "/#{name}"
8
+ @klass = Object.const_get('Pocus::'.concat(options[:class] || camelize(name)))
9
+ end
10
+
11
+ def all
12
+ owner.get_multiple(path, klass)
13
+ end
14
+
15
+ def create(fields_multiple)
16
+ if fields_multiple.is_a?(Array)
17
+ owner.post_multiple(path, klass, fields_multiple)
18
+ else
19
+ response = owner.post_multiple(path, klass, [fields_multiple])
20
+ return response if response.empty?
21
+ resource = response.first
22
+ resource.assign_attributes(errors: response.errors || [], warnings: response.warnings || [])
23
+ resource
24
+ end
25
+ end
26
+
27
+ def find(id)
28
+ owner.get("#{path}/#{id}", klass)
29
+ end
30
+
31
+ def where(filters)
32
+ owner.get_multiple(path, klass, filters)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,14 @@
1
+ module Pocus
2
+ # See https://www.icontact.com/developerportal/documentation/client-folders
3
+ class ClientFolder < Resource
4
+ self.path = :c
5
+ self.primary_key = :client_folder_id
6
+
7
+ has_many :lists, class: 'List'
8
+ has_many :contacts, class: 'Contact'
9
+ has_many :customfields, class: 'CustomField'
10
+ has_many :segments, class: 'Segment'
11
+ has_many :subscriptions, class: 'Subscription'
12
+ has_many :users, class: 'User'
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ module Pocus
2
+ # See https://www.icontact.com/developerportal/documentation/contacts
3
+ class Contact < Resource
4
+ self.path = :contacts
5
+ self.primary_key = :contact_id
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Pocus
2
+ # See https://www.icontact.com/developerportal/documentation/custom-fields
3
+ class CustomField < Resource
4
+ self.path = :customfields
5
+ self.primary_key = :custom_field_id
6
+ end
7
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pocus
4
+ # Gem identity information.
5
+ module Identity
6
+ def self.name
7
+ 'pocus'
8
+ end
9
+
10
+ def self.label
11
+ 'Pocus'
12
+ end
13
+
14
+ def self.version
15
+ '0.5.0'
16
+ end
17
+
18
+ def self.version_label
19
+ "#{label} #{version}"
20
+ end
21
+ end
22
+ end
data/lib/pocus/list.rb ADDED
@@ -0,0 +1,7 @@
1
+ module Pocus
2
+ # See https://www.icontact.com/developerportal/documentation/lists
3
+ class List < Resource
4
+ self.path = :lists
5
+ self.primary_key = :list_id
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module Pocus
2
+ # https://www.icontact.com/developerportal/documentation/permissions
3
+ class Permission < Resource
4
+ self.path = :permissions
5
+ self.primary_key = nil
6
+ end
7
+ end
@@ -0,0 +1,169 @@
1
+ module Pocus
2
+ # Combine array of resources returned by API with error and warning attributes.
3
+ class ResponseArray < Array
4
+ attr_reader :errors, :warnings
5
+
6
+ def initialize(resources, errors, warnings)
7
+ @errors = (errors || [])
8
+ @warnings = (warnings || [])
9
+ super resources
10
+ end
11
+ end
12
+
13
+ # Base class for API resources.
14
+ class Resource
15
+ attr_reader :path
16
+ attr_accessor :parent
17
+
18
+ class << self
19
+ attr_accessor :path, :primary_key
20
+
21
+ def associations
22
+ @associations ||= {}
23
+ end
24
+
25
+ def has_many(name, options = {})
26
+ attr_accessor(name)
27
+ associations[name] = options
28
+ end
29
+
30
+ def tag
31
+ name.split('::').last.downcase
32
+ end
33
+
34
+ def tag_multiple
35
+ tag.concat('s')
36
+ end
37
+ end
38
+
39
+ def initialize(attributes)
40
+ assign_attributes(attributes)
41
+ self.class.associations.each_pair do |name, options|
42
+ send("#{name}=", Association.new(self, name, options))
43
+ end
44
+ end
45
+
46
+ def assign_attributes(attributes)
47
+ attributes.each do |ck, v|
48
+ k = underscore(ck)
49
+ self.class.__send__(:attr_accessor, k) unless respond_to?(k)
50
+ send("#{k}=", v)
51
+ end
52
+ end
53
+
54
+ def delete
55
+ session.send_request('DELETE', path) == []
56
+ end
57
+ alias destroy delete
58
+
59
+ def fields
60
+ field_names.reduce(Hash[]) do |hash, field_name|
61
+ hash.tap { |h| h[camelize field_name] = send field_name }
62
+ end
63
+ end
64
+
65
+ # Fetch and instantiate a single resource from a path.
66
+ def get(request_path, klass)
67
+ response = session.send_request('GET', path + request_path)
68
+ data = response.fetch(klass.tag)
69
+ resource = klass.new(data.merge(parent: self))
70
+ resource.assign_errors(response)
71
+ resource
72
+ end
73
+
74
+ def get_multiple(request_path, klass, filters = {})
75
+ response = session.send_request('GET', path + request_path, camelize_filters(filters))
76
+ data = response.fetch(klass.tag_multiple)
77
+ resources = data.map { |fields| klass.new(fields.merge(parent: self)) }
78
+ ResponseArray.new(resources, response['errors'], response['warnings'])
79
+ end
80
+
81
+ def id
82
+ send self.class.primary_key
83
+ end
84
+
85
+ def logger
86
+ session.logger
87
+ end
88
+
89
+ def path
90
+ "#{parent ? parent.path : ""}/#{self.class.path}/#{id}"
91
+ end
92
+
93
+ def post
94
+ response = session.send_request('POST', path, fields)
95
+ assign_attributes(response.fetch(self.class.tag))
96
+ assign_errors(response)
97
+ self
98
+ rescue UnexpectedHttpResponse => e
99
+ response = JSON.parse(e.response.body)
100
+ response['errors'] || response['warnings'] or raise
101
+ assign_errors(response)
102
+ self
103
+ end
104
+
105
+ def post_multiple(request_path, klass, fields_multiple)
106
+ data = fields_multiple.map { |fields| camelize_fields(fields) }
107
+ response = session.send_request('POST', path + request_path, data)
108
+ resources = response.fetch(klass.tag_multiple).map { |fields| klass.new(fields.merge(parent: self)) }
109
+ ResponseArray.new(resources, response['errors'], response['warnings'])
110
+ end
111
+
112
+ # Fetch and update this resource from a path.
113
+ def reload
114
+ response = session.send_request('GET', path)
115
+ assign_attributes(response.fetch(self.class.tag))
116
+ assign_errors(response)
117
+ self
118
+ end
119
+
120
+ def session
121
+ Session.instance
122
+ end
123
+
124
+ protected
125
+
126
+ def required(attributes, attr_names)
127
+ missing = attr_names - attributes.keys
128
+ fail "missing required atrributes: #{missing.inspect}" if missing.any?
129
+ end
130
+
131
+ def camelize(str)
132
+ return str.to_s unless str.to_s.include?('_')
133
+ parts = str.to_s.split('_')
134
+ first = parts.shift
135
+ first + parts.each(&:capitalize!).join
136
+ end
137
+
138
+ def camelize_fields(hash)
139
+ hash.reduce({}) do |h, e|
140
+ h[camelize e[0]] = e[1]
141
+ h
142
+ end
143
+ end
144
+
145
+ def camelize_filters(hash)
146
+ hash.reduce({}) do |h, e|
147
+ key = camelize(e[0])
148
+ h[key] = e[1]
149
+ h[key + 'SearchType'] = 'eq'
150
+ h
151
+ end
152
+ end
153
+
154
+ def field_names
155
+ instance_variables.map { |n| n.to_s.sub('@', '').to_sym } - [:session, :parent, :path]
156
+ end
157
+
158
+ def assign_errors(response)
159
+ assign_attributes(errors: response['errors'] || [], warnings: response['warnings'] || [])
160
+ end
161
+
162
+ def underscore(camel_cased_word)
163
+ camel_cased_word.to_s.dup.tap do |word|
164
+ word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
165
+ word.downcase!
166
+ end
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,9 @@
1
+ module Pocus
2
+ # https://www.icontact.com/developerportal/documentation/segments
3
+ class Segment < Resource
4
+ self.path = :segments
5
+ self.primary_key = :segment_id
6
+
7
+ has_many :criteria, class: 'SegmentCriteria'
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Pocus
2
+ # https://www.icontact.com/developerportal/documentation/segment-criteria
3
+ class SegmentCriteria < Resource
4
+ self.path = :criteria
5
+ self.primary_key = :criterion_id
6
+
7
+ def self.tag_multiple
8
+ 'criteria'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,79 @@
1
+ require 'benchmark'
2
+ require 'json'
3
+ require 'logger'
4
+
5
+ # See https://www.icontact.com/developerportal/documentation
6
+ module Pocus
7
+ class UnexpectedHttpResponse < RuntimeError
8
+ attr_reader :response
9
+ def initialize(response)
10
+ @response = response
11
+ super "Unexpected response [#{response.code}] #{response.body}"
12
+ end
13
+ end
14
+
15
+ # Sends authenticated JSON requests to remote service using HTTPS.
16
+ class Session
17
+ BASE_URL = 'https://api.invoc.us/icp'.freeze
18
+ attr_reader :credentials
19
+ attr_accessor :logger
20
+
21
+ def initialize(app_id: '', username: '', password: '', logger: Logger.new('/dev/null'))
22
+ @credentials = {
23
+ 'API-AppId' => app_id,
24
+ 'API-Username' => username,
25
+ 'API-Password' => password
26
+ }
27
+ @logger = logger
28
+ end
29
+
30
+ def self.config(options = {})
31
+ @config = options
32
+ end
33
+
34
+ def self.instance
35
+ @instance ||= new(@config)
36
+ end
37
+
38
+ # Accepts hash of fields to send.
39
+ # Returns parsed response body, always a hash.
40
+ def send_request(method, path, fields = {})
41
+ response = send_logged_request(URI(BASE_URL + path), method, request_data(fields))
42
+ fail UnexpectedHttpResponse, response unless response.is_a? Net::HTTPSuccess
43
+ JSON.parse(response.body)
44
+ end
45
+
46
+ protected
47
+
48
+ def headers(type = 'application/json')
49
+ Hash['API-Version' => '2.2', 'Accept' => type, 'Content-Type' => type]
50
+ end
51
+
52
+ def https(uri)
53
+ Net::HTTP.new(uri.host, uri.port).tap do |http|
54
+ http.use_ssl = true
55
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
56
+ end
57
+ end
58
+
59
+ def request_data(fields)
60
+ fields.to_json unless fields.empty?
61
+ end
62
+
63
+ def send_logged_request(uri, method, data)
64
+ log_request_response(uri, method, data) do |u, m, d|
65
+ https(uri).send_request(m, u.to_s, d, headers.merge(credentials))
66
+ end
67
+ end
68
+
69
+ def log_request_response(uri, method, data)
70
+ logger.info "request = #{uri}#{data ? '?' + data : ''}"
71
+ response = nil
72
+ tms = Benchmark.measure do
73
+ response = yield uri, method, data
74
+ end
75
+ logger.info("API response (#{tms.real}s): #{response.inspect} #{response.body}")
76
+ response
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,6 @@
1
+ module Pocus
2
+ class Subscription < Resource
3
+ self.path = :subscriptions
4
+ self.primary_key = :subscription_id
5
+ end
6
+ end
data/lib/pocus/user.rb ADDED
@@ -0,0 +1,9 @@
1
+ module Pocus
2
+ # https://www.icontact.com/developerportal/documentation/users
3
+ class User < Resource
4
+ self.path = :users
5
+ self.primary_key = :user_id
6
+
7
+ has_many :permissions, class: 'Permission'
8
+ end
9
+ end
data/lib/pocus.rb ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pocus/identity'
4
+ require 'pocus/session.rb'
5
+ require 'pocus/association.rb'
6
+ require 'pocus/resource.rb'
7
+ require 'pocus/account.rb'
8
+ require 'pocus/client_folder.rb'
9
+
10
+ require 'pocus/user.rb'
11
+ require 'pocus/permission.rb'
12
+
13
+ require 'pocus/list.rb'
14
+ require 'pocus/contact.rb'
15
+ require 'pocus/custom_field.rb'
16
+ require 'pocus/segment.rb'
17
+ require 'pocus/segment_criteria.rb'
18
+ require 'pocus/subscription.rb'
@@ -0,0 +1,7 @@
1
+ desc 'Open IRB console for gem development environment'
2
+ task :console do
3
+ require 'irb'
4
+ require 'pocus'
5
+ ARGV.clear
6
+ IRB.start
7
+ end
@@ -0,0 +1,6 @@
1
+ begin
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new(:spec)
4
+ rescue LoadError => error
5
+ puts error.message
6
+ end
@@ -0,0 +1,6 @@
1
+ begin
2
+ require 'rubocop/rake_task'
3
+ RuboCop::RakeTask.new
4
+ rescue LoadError => error
5
+ puts error.message
6
+ end
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pocus
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.5.0
5
+ platform: ruby
6
+ authors:
7
+ - Piers Chambers
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-05-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.12'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.12'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '11.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '11.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: gemsmith
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '7.7'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '7.7'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry-byebug
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry-state
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.4'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.4'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rubocop
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.40'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.40'
125
+ - !ruby/object:Gem::Dependency
126
+ name: codeclimate-test-reporter
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: Unofficial Ruby client for iContact API
140
+ email:
141
+ - piers@varyonic.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files:
145
+ - README.md
146
+ - LICENSE.md
147
+ files:
148
+ - LICENSE.md
149
+ - README.md
150
+ - lib/pocus.rb
151
+ - lib/pocus/account.rb
152
+ - lib/pocus/association.rb
153
+ - lib/pocus/client_folder.rb
154
+ - lib/pocus/contact.rb
155
+ - lib/pocus/custom_field.rb
156
+ - lib/pocus/identity.rb
157
+ - lib/pocus/list.rb
158
+ - lib/pocus/permission.rb
159
+ - lib/pocus/resource.rb
160
+ - lib/pocus/segment.rb
161
+ - lib/pocus/segment_criteria.rb
162
+ - lib/pocus/session.rb
163
+ - lib/pocus/subscription.rb
164
+ - lib/pocus/user.rb
165
+ - lib/tasks/console.rake
166
+ - lib/tasks/rspec.rake
167
+ - lib/tasks/rubocop.rake
168
+ homepage: https://github.com//pocus
169
+ licenses:
170
+ - MIT
171
+ metadata: {}
172
+ post_install_message:
173
+ rdoc_options: []
174
+ require_paths:
175
+ - lib
176
+ required_ruby_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ required_rubygems_version: !ruby/object:Gem::Requirement
182
+ requirements:
183
+ - - ">="
184
+ - !ruby/object:Gem::Version
185
+ version: '0'
186
+ requirements: []
187
+ rubyforge_project:
188
+ rubygems_version: 2.5.1
189
+ signing_key:
190
+ specification_version: 4
191
+ summary: Unofficial Ruby client for iContact API
192
+ test_files: []