icontact-api 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,3 @@
1
+ .Ti?c}7y?x�I*�J-�U���|QE�kJ3g ZÆhIrh֠@�O���;����=C4H?3�
2
+ ��N�����2s,9��:{K�H�e�ӄ�N��|�f�Y' !4���&�֊.�2 ��DA�j��2H����'N�R����'區��]�ۆV�;3��\�����
3
+ �*�]Do��9�i���`-k�*��bg��'��RDc�F �u0E��gM;k�=KpE�b���҃QZ� ���2��ı
@@ -0,0 +1,4 @@
1
+ == 0.0.1 2009-01-16
2
+
3
+ * 1 major enhancement:
4
+ * Initial release
@@ -0,0 +1,13 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.rdoc
4
+ Rakefile
5
+ lib/icontact-api.rb
6
+ lib/icontact/api.rb
7
+ script/console
8
+ script/destroy
9
+ script/generate
10
+ spec/api_spec.rb
11
+ spec/spec.opts
12
+ spec/spec_helper.rb
13
+ tasks/rspec.rake
@@ -0,0 +1,82 @@
1
+ = icontact-api
2
+
3
+ == DESCRIPTION:
4
+
5
+ This gem provides a thin wrapper around the iContact 2.0 API.
6
+
7
+ == FEATURES/PROBLEMS:
8
+
9
+ * automatically signs each request
10
+ * handles packing and unpacking into json
11
+ * query params can be passed as an options hash
12
+
13
+ == SYNOPSIS:
14
+
15
+ Normally you will want to subclass the Icontact::Api class and define your API_KEY and API_SECRET, and optionally you may wish to hard-code a username and password for the API.
16
+
17
+ @api = MyApi.new(username, password)
18
+ @api.get('/a/000000/c/000000/messages', :limit=>10, :offset=>0)
19
+
20
+ Please see the icontact developer documentation for a full listing of the supported resources and url structure.
21
+
22
+ This gem is not officially supported by iContact. Please contact the author with bug reports, feature requests, or questions about this gem.
23
+
24
+
25
+ == REQUIREMENTS:
26
+
27
+ * requires JSON gem
28
+
29
+ == INSTALL:
30
+
31
+ * sudo gem install icontact-api
32
+
33
+ == USAGE
34
+
35
+ for convenience create a class like this that keeps track of your API_KEY, API_SECRET, and optionally an api username and password:
36
+
37
+ require 'icontact-api'
38
+ class BetaApi < Icontact::Api
39
+ API_USERNAME='username'
40
+ API_PASSWORD='password'
41
+ API_KEY = 'YOUR_API_KEY'
42
+ API_SECRET = 'YOUR_API_SECRET'
43
+ DOMAIN = "http://app.beta.icontact.com/icp"
44
+
45
+ def initialize(username = BetaApi::API_USERNAME, password = BetaApi::API_PASSWORD)
46
+ super(username, password)
47
+ self.key = API_KEY
48
+ self.secret = API_SECRET
49
+ self.domain = DOMAIN
50
+ end
51
+ end
52
+
53
+ Then you can use it like:
54
+
55
+ @api = BetaApi.new
56
+ @api.get('/a')
57
+ @api.post('/a/00000/c/0000/messages', data)
58
+
59
+ == LICENSE:
60
+
61
+ (The MIT License)
62
+
63
+ Copyright (c) 2009 Kevin Olbrich
64
+
65
+ Permission is hereby granted, free of charge, to any person obtaining
66
+ a copy of this software and associated documentation files (the
67
+ 'Software'), to deal in the Software without restriction, including
68
+ without limitation the rights to use, copy, modify, merge, publish,
69
+ distribute, sublicense, and/or sell copies of the Software, and to
70
+ permit persons to whom the Software is furnished to do so, subject to
71
+ the following conditions:
72
+
73
+ The above copyright notice and this permission notice shall be
74
+ included in all copies or substantial portions of the Software.
75
+
76
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
77
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
78
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
79
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
80
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
81
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
82
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,27 @@
1
+ %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
+ require File.dirname(__FILE__) + '/lib/icontact-api'
3
+
4
+ # Generate all the Rake tasks
5
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
+ $hoe = Hoe.new('icontact-api', Icontact::Api::VERSION) do |p|
7
+ p.developer('Kevin Olbrich', 'kevin.olbrich@gmail.com')
8
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
+ p.rubyforge_name = p.name # TODO this is default value
10
+ p.extra_deps = [
11
+ ['json','>= 1.1.3'],
12
+ ]
13
+ p.extra_dev_deps = [
14
+ ['newgem', ">= #{::Newgem::VERSION}"]
15
+ ]
16
+
17
+ p.clean_globs |= %w[**/.DS_Store tmp *.log]
18
+ path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
19
+ p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
20
+ p.rsync_args = '-av --delete --ignore-errors'
21
+ end
22
+
23
+ require 'newgem/tasks' # load /tasks/*.rake
24
+ Dir['tasks/**/*.rake'].each { |t| load t }
25
+
26
+ # TODO - want other tests/tasks run by default? Add them to the list
27
+ # task :default => [:spec, :features]
@@ -0,0 +1,5 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'icontact/api'
5
+ #require 'icontact-api/api'
@@ -0,0 +1,112 @@
1
+ require 'rubygems'
2
+ require 'net/http'
3
+ require 'digest'
4
+ require 'json'
5
+
6
+ class Icontact
7
+ class Api
8
+ VERSION = "0.1"
9
+ API_VERSION = "2.0"
10
+ DOMAIN = 'http://app.icontact.com/icp'
11
+ API_KEY = "API_KEY"
12
+ API_SECRET = "API_SECRET"
13
+ attr_accessor :username
14
+ attr_accessor :password
15
+ attr_accessor :key
16
+ attr_accessor :secret
17
+ attr_accessor :domain
18
+
19
+ def initialize(username, password)
20
+ self.username = username
21
+ self.password = password
22
+ self.domain = DOMAIN
23
+ self.key = API_KEY
24
+ self.secret = API_SECRET
25
+ end
26
+
27
+ # Package up any options into a query string and format it properly for the server
28
+ # arrays become comma separated lists and Times are expressed as iso8601
29
+ def self.package_query_params(params={})
30
+ return nil if params.nil? || params.empty?
31
+ massaged_params = params.map do |key, value|
32
+ case value
33
+ when Array:
34
+ "#{key}=#{value.join(',')}"
35
+ when Time:
36
+ "#{key}=#{value.strftime("%Y-%m-%dT%H:%M:%S")}#{"%+0.2d:00" % (value.gmtoff / 3600)}"
37
+ else
38
+ "#{key}=#{value}"
39
+ end
40
+ end
41
+ "?#{massaged_params.join('&')}"
42
+ end
43
+
44
+ # override this to use a different encoding method for sending data (like xml)
45
+ def self.body_encoder(data)
46
+ data.to_json
47
+ end
48
+
49
+ # override this method to use a different response parser (like REXML for an xml response)
50
+ # when the response is not actually a JSON object an exception is thrown and the raw response is returned in the body instead.
51
+ def self.parse_response(code, response)
52
+ {'code'=>code, 'body' => (JSON.parse(response) rescue response)}
53
+ end
54
+
55
+ def request_signature(method, timestamp, random, url)
56
+ Digest::SHA1.hexdigest("#{secret}#{password}#{timestamp}#{random}#{method.to_s.upcase}#{url}")
57
+ end
58
+
59
+ # populate headers required by the icontact server on each request for authentication
60
+ # Accept and Content-Type are set to application/json to use JSON objects for the
61
+ # data exchange. Also accepts text/xml for either, but then you have to deal with XML encoding and decoding
62
+ # manually
63
+ def apply_headers(method, req, url)
64
+ timestamp = Time.now.getgm.to_i
65
+ random = Kernel.rand(999999)
66
+ req.add_field('API_VERSION', API_VERSION)
67
+ req.add_field('ACCEPT','application/json')
68
+ req.add_field('Content-Type','application/json')
69
+ req.add_field('API_KEY', self.key)
70
+ req.add_field('API_USERNAME', self.username)
71
+ req.add_field('API_TIMESTAMP', timestamp)
72
+ req.add_field('API_NUMBER', random)
73
+ req.add_field('API_SIGNATURE', request_signature(method, timestamp, random, url))
74
+ return req
75
+ end
76
+
77
+ # dynamically create methods for get and delete. These methods do not require a body to be sent
78
+ [:get, :delete].each do |meth|
79
+ define_method(meth) do |url, *options|
80
+ request(meth, url, nil, options)
81
+ end
82
+ end
83
+
84
+ # dynamically create methods for get and delete. These methods require a body to be sent
85
+ [:post, :put].each do |meth|
86
+ define_method(meth) do |url, data, *options|
87
+ request(meth, url, data, options)
88
+ end
89
+ end
90
+
91
+ # Actually make the get, put, post, or delete request
92
+ def request(kind, url, data, options)
93
+ # options passed as optional parameter show up as an array
94
+ options = options.first if options.kind_of? Array
95
+ query_options = self.class.package_query_params(options)
96
+ full_url = URI.parse("#{self.domain}#{url}#{query_options}")
97
+
98
+ # create an object of the class required to process this method
99
+ klass = Object.module_eval("::Net::HTTP::#{kind.to_s.capitalize}", __FILE__, __LINE__)
100
+ request = klass.new([full_url.path, full_url.query].compact.join('?'))
101
+ request = apply_headers(kind, request, full_url)
102
+
103
+ # take passed data and encode it
104
+ request.body = self.class.body_encoder(data) if data
105
+
106
+ Net::HTTP.start(full_url.host, full_url.port) do |http|
107
+ response = http.request(request)
108
+ return self.class.parse_response(response.code, response.body)
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/icontact-api.rb'}"
9
+ puts "Loading icontact-api gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,177 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ describe Icontact::Api do
4
+ before(:each) do
5
+ @mock_time = mock('Time', :getgm => 999999)
6
+ Time.stub!(:now).and_return(@mock_time)
7
+ Kernel.stub!(:rand).and_return(111)
8
+ end
9
+
10
+ describe "api" do
11
+ before(:each) do
12
+ @api = Icontact::Api.new('mock_username', 'mock_password')
13
+ @response = mock('response',:code=>200, :body=>"body")
14
+ @mock_http_request = mock('http', :request=>@response)
15
+ Net::HTTP.stub!(:start).and_yield(@mock_http_request)
16
+ end
17
+
18
+ describe "an http request", :shared=>true do
19
+ it "should apply headers to the request" do
20
+ @mock_request = mock("Request", :body= => true)
21
+ @api.should_receive(:apply_headers).and_return(@mock_request)
22
+ do_request
23
+ end
24
+
25
+ it "should package query params" do
26
+ @api.class.should_receive(:package_query_params)
27
+ do_request(:limit=>10)
28
+ end
29
+
30
+ it "should send the request" do
31
+ Net::HTTP.should_receive(:start)
32
+ do_request
33
+ end
34
+
35
+ it "should parse the server response into a hash" do
36
+ @api.class.should_receive(:parse_response)
37
+ do_request
38
+ end
39
+ end
40
+
41
+ describe "an http request with a body", :shared=>true do
42
+ it_should_behave_like "an http request"
43
+
44
+ it "should package the data into the body" do
45
+ @api.class.should_receive(:body_encoder)
46
+ do_request
47
+ end
48
+ end
49
+
50
+ describe ".get" do
51
+
52
+ def do_request(options={})
53
+ @api.get("/a", options)
54
+ end
55
+
56
+ it_should_behave_like "an http request"
57
+ end
58
+
59
+ describe ".post" do
60
+ def do_request(options={})
61
+ @api.post("/a", {}, options)
62
+ end
63
+
64
+ it_should_behave_like "an http request with a body"
65
+ end
66
+
67
+ describe ".put" do
68
+ def do_request(options={})
69
+ @api.put("/a", {}, options)
70
+ end
71
+
72
+ it_should_behave_like "an http request with a body"
73
+ end
74
+
75
+ describe '.delete' do
76
+ def do_request(options={})
77
+ @api.delete("/a", options)
78
+ end
79
+
80
+ it_should_behave_like "an http request"
81
+ end
82
+ end
83
+
84
+ describe ".request_signature" do
85
+ before(:each) do
86
+ @api = Icontact::Api.new('username','password')
87
+ Kernel.stub!(:rand).and_return(111)
88
+ @mock_time = mock('Time', :getgm => 999999)
89
+ Time.stub!(:now).and_return(@mock_time)
90
+ Digest::SHA1.stub!(:hexdigest).and_return('api_signature')
91
+ end
92
+
93
+ it "should generate an API Signature" do
94
+ Digest::SHA1.should_receive(:hexdigest).with('API_SECRETpasswordtimestamp/urlrandomGET').and_return('api_signature')
95
+ @api.request_signature('get','timestamp''/url', 'random', '').should == "api_signature"
96
+ end
97
+ end
98
+
99
+ describe ".apply_headers" do
100
+ before(:each) do
101
+ @request = mock('Request', :add_field=>true)
102
+ @api = Icontact::Api.new('username','password')
103
+ end
104
+
105
+ def do_apply_headers
106
+ @api.apply_headers(:get, @request, 'http://fakeurl.com')
107
+ end
108
+
109
+ it "should add an API_VERSION header to indicate we are using the 2.0 version of the API" do
110
+ @request.should_receive(:add_field).with('API_VERSION', @api.class::API_VERSION)
111
+ do_apply_headers
112
+ end
113
+
114
+ it "should add an ACCEPT header indicating we want a JSON object back" do
115
+ @request.should_receive(:add_field).with('ACCEPT', 'application/json')
116
+ do_apply_headers
117
+ end
118
+
119
+ it "should add a Content-Type header indicating that passed data is JSON encoded" do
120
+ @request.should_receive(:add_field).with('Content-Type', 'application/json')
121
+ do_apply_headers
122
+ end
123
+
124
+ it "should add an API_KEY header to verify that our application is authrorized to use the API" do
125
+ @request.should_receive(:add_field).with('API_KEY', @api.class::API_KEY)
126
+ do_apply_headers
127
+ end
128
+
129
+ it "should add an API_USERNAME header to verify that our user is authorized to use the API" do
130
+ @request.should_receive(:add_field).with('API_USERNAME', 'username')
131
+ do_apply_headers
132
+ end
133
+
134
+ it "should add an API_TIMESTAMP header to prevent old requests from being replayed" do
135
+ @request.should_receive(:add_field).with('API_TIMESTAMP', 999999)
136
+ do_apply_headers
137
+ end
138
+
139
+ it "should add an API_NUMBER header" do
140
+ @request.should_receive(:add_field).with('API_NUMBER', 111)
141
+ do_apply_headers
142
+ end
143
+
144
+ it "should add an API_SIGNATURE header to ensure this api request is valid" do
145
+ @api.should_receive(:request_signature).and_return('api_signature')
146
+ @request.should_receive(:add_field).with('API_SIGNATURE', 'api_signature')
147
+ do_apply_headers
148
+ end
149
+ end
150
+
151
+ describe "class methods" do
152
+ it ".body_encoder should encode the data to be sent in JSON" do
153
+ data = {:messageIds=>[1,2,3,4,5]}
154
+ Icontact::Api::body_encoder(data).should == data.to_json
155
+ end
156
+
157
+ it ".parse_response should parse the JSON response into a hash" do
158
+ body = {:messageIds=>[1,2,3,4,5]}.to_json
159
+ Icontact::Api::parse_response(200, body).should == {"body"=>{"messageIds"=>[1, 2, 3, 4, 5]}, "code"=>200}
160
+ end
161
+
162
+ describe ".package_query_params" do
163
+ # the "string".split('').sort trick is used because the string may come back in a different order each time because
164
+ # it is generated from an unordered hash, this trick allows comparison
165
+ it "should package a hash into a query string according to the API requirements" do
166
+ options = {:limit=>10, :offset=>10, :messageId=>[1,2,3,4], :createdAt=>Time.at(1234567890)}
167
+ Icontact::Api::package_query_params(options).split('').sort.should ==
168
+ "?limit=10&messageId=1,2,3,4&createdAt=2009-02-13T18:31:30-05:00&offset=10".split('').sort
169
+ end
170
+
171
+ it "should return nil if passed an empty hash" do
172
+ Icontact::Api::package_query_params({}).should be_nil
173
+ end
174
+ end
175
+
176
+ end
177
+ end
@@ -0,0 +1 @@
1
+ --colour
@@ -0,0 +1,10 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ gem 'rspec'
6
+ require 'spec'
7
+ end
8
+
9
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ require 'icontact-api'
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'spec'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'spec'
6
+ end
7
+ begin
8
+ require 'spec/rake/spectask'
9
+ rescue LoadError
10
+ puts <<-EOS
11
+ To use rspec for testing you must install rspec gem:
12
+ gem install rspec
13
+ EOS
14
+ exit(0)
15
+ end
16
+
17
+ desc "Run the specs under spec/models"
18
+ Spec::Rake::SpecTask.new do |t|
19
+ t.spec_opts = ['--options', "spec/spec.opts"]
20
+ t.spec_files = FileList['spec/**/*_spec.rb']
21
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: icontact-api
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Kevin Olbrich
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain:
11
+ - |
12
+ -----BEGIN CERTIFICATE-----
13
+ MIIDPDCCAiSgAwIBAgIBADANBgkqhkiG9w0BAQUFADBEMRYwFAYDVQQDDA1rZXZp
14
+ bi5vbGJyaWNoMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJk/IsZAEZ
15
+ FgNjb20wHhcNMDkwMzA3MTUwMzQ5WhcNMTAwMzA3MTUwMzQ5WjBEMRYwFAYDVQQD
16
+ DA1rZXZpbi5vbGJyaWNoMRUwEwYKCZImiZPyLGQBGRYFZ21haWwxEzARBgoJkiaJ
17
+ k/IsZAEZFgNjb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvza3W
18
+ J5Dloirbhpge6teyZNfvOzuo478vtqnU/c6S8o2EerBkmWm88J+ipItO3U2HDPgP
19
+ a7THrx41/QEj1oG15mO6wtBLf0Z+AOJFAmf+Th8x3b46b3Voo1+suON67fCqCz+U
20
+ L5V2I5NBNywCte5Nzjh7knLkHr+rUCCKAIPK6vq+sASMIgmlhzZUuQfdRZMhRVZP
21
+ clMwf9sIp7LUTq2b/LCdP2dlGFydb1cyvaHjho+X/pk5uWKcr1OkrZtYFdxyeGU4
22
+ ZTtqEd5vaNTacYf0vGBfPfiolIfbmOa8Pgfyj8zkjBug/iukM/YGmwL1KAk8Qs+/
23
+ gInxSkyPxa7zkYTzAgMBAAGjOTA3MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0G
24
+ A1UdDgQWBBS+y2GRZjETz6d3jHKosqOZ6Ll+zjANBgkqhkiG9w0BAQUFAAOCAQEA
25
+ f3hCt6NBuESjAN4fkpbcfi3/Nj06aNl6CAfryfKaOaIfLcypT5nqP1qtqqGih5ne
26
+ QCe7jmtZHOGFC/SSlCS8obHSkCGn2cfUl/InfpF/YQnZV0Kp8esihuVmEjO0SgEU
27
+ yf46wW9Nh4byKctkgKMlWnIqwAyk4G1dD/le6MGJutb4pv5hT9qm1vaTFkAcy1Qu
28
+ 1VMZa+MH6xnINGdFyV8T7AYL5BaQTbp2WYsfbOvy3ZfxbpP5O3wc3wter/Cyp8pu
29
+ Wvn0/+13roT+v5T5yFIpu6NbSpuqvRaKZvS+n2ZgwS10rUPFydzn+335umE4vsfH
30
+ 4Umf0rf1f8h+GJia5xXYww==
31
+ -----END CERTIFICATE-----
32
+
33
+ date: 2009-03-24 00:00:00 -04:00
34
+ default_executable:
35
+ dependencies:
36
+ - !ruby/object:Gem::Dependency
37
+ name: json
38
+ type: :runtime
39
+ version_requirement:
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: 1.1.3
45
+ version:
46
+ - !ruby/object:Gem::Dependency
47
+ name: newgem
48
+ type: :development
49
+ version_requirement:
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 1.2.3
55
+ version:
56
+ - !ruby/object:Gem::Dependency
57
+ name: hoe
58
+ type: :development
59
+ version_requirement:
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: 1.8.0
65
+ version:
66
+ description: This gem provides a thin wrapper around the iContact 2.0 API.
67
+ email:
68
+ - kevin.olbrich@gmail.com
69
+ executables: []
70
+
71
+ extensions: []
72
+
73
+ extra_rdoc_files:
74
+ - History.txt
75
+ - Manifest.txt
76
+ - README.rdoc
77
+ files:
78
+ - History.txt
79
+ - Manifest.txt
80
+ - README.rdoc
81
+ - Rakefile
82
+ - lib/icontact-api.rb
83
+ - lib/icontact/api.rb
84
+ - script/console
85
+ - script/destroy
86
+ - script/generate
87
+ - spec/api_spec.rb
88
+ - spec/spec.opts
89
+ - spec/spec_helper.rb
90
+ - tasks/rspec.rake
91
+ has_rdoc: true
92
+ homepage:
93
+ post_install_message:
94
+ rdoc_options:
95
+ - --main
96
+ - README.rdoc
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: "0"
104
+ version:
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: "0"
110
+ version:
111
+ requirements: []
112
+
113
+ rubyforge_project: icontact-api
114
+ rubygems_version: 1.3.1
115
+ signing_key:
116
+ specification_version: 2
117
+ summary: This gem provides a thin wrapper around the iContact 2.0 API.
118
+ test_files: []
119
+
Binary file