acts_as_icontact 0.3.0 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +95 -26
- data/Rakefile +12 -1
- data/VERSION +1 -1
- data/acts_as_icontact.gemspec +29 -5
- data/bin/icontact +1 -1
- data/lib/acts_as_icontact/resource.rb +7 -1
- data/lib/acts_as_icontact/resource_collection.rb +16 -2
- data/lib/acts_as_icontact/resources/campaign.rb +30 -0
- data/lib/acts_as_icontact/resources/client.rb +9 -9
- data/lib/acts_as_icontact/resources/contact.rb +0 -5
- data/lib/acts_as_icontact/resources/list.rb +1 -4
- data/lib/acts_as_icontact/resources/message.rb +9 -0
- data/spec/resource_collection_spec.rb +28 -0
- data/spec/resource_spec.rb +10 -3
- data/spec/resources/campaign_spec.rb +58 -0
- data/spec/resources/{client_spec.rb → clientfolder_spec.rb} +14 -14
- data/spec/resources/message_spec.rb +3 -1
- data/spec/support/spec_fakeweb.rb +11 -5
- metadata +69 -6
data/README.markdown
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
ActsAsIcontact
|
2
2
|
==============
|
3
|
-
ActsAsIcontact connects Ruby applications with the [iContact e-mail marketing service]
|
3
|
+
ActsAsIcontact connects Ruby applications with the [iContact e-mail marketing service][1] using the iContact API v2.0. Building on the [RestClient][2] gem, it offers three significant feature sets:
|
4
4
|
|
5
|
-
* Simple, consistent access to all resources in the iContact API;
|
5
|
+
* Simple, consistent access to all resources in the iContact API;
|
6
|
+
* A simple command-line client; and
|
6
7
|
* Automatic synchronizing between ActiveRecord models and iContact contact lists for Rails applications.
|
7
8
|
|
8
9
|
Prerequisites
|
9
10
|
-------------
|
10
11
|
You'll need the following to use this gem properly:
|
11
12
|
|
12
|
-
1. **Ruby 1.9
|
13
|
+
1. **Ruby 1.9:** Yes, we know, many other gems still only work in 1.8. But ActsAsIcontact makes use of a few 1.9.1 features for efficiency, such as fiber-based Enumerators to step through large collections without instantiating a thousand objects at once. It's _possible_ that this might work in 1.8.7 if you install the **JSON** gem and `require 'enumerator'` explicitly -- but the author hasn't tested it. If you need it to work in 1.8, speak up. Or better yet, make it work and submit a patch.
|
13
14
|
|
14
|
-
2. **Rails 2.1
|
15
|
+
2. **Rails 2.1 or higher:** _(If using Rails integration)_ We use ActiveRecord's 'dirty fields' feature that first appeared in 2.1 to determine whether iContact needs updating. If you're on a version of Rails older than this, it's probably worth your while to update anyway.
|
15
16
|
|
16
|
-
3. **
|
17
|
+
3. **Other gems:** This gem requires the [RestClient][2], [ActiveSupport][3] and [Bond][4] gems in order to work. Simply doing a `gem install` _should_ install these dependencies as well.
|
17
18
|
|
18
19
|
Setting Up
|
19
20
|
----------
|
@@ -31,21 +32,36 @@ Using ActsAsIcontact is easy, but going through iContact's authorization process
|
|
31
32
|
|
32
33
|
* **PRODUCTION:** Go to <http://app.icontact.com/icp/core/externallogin> and enter `IYDOhgaZGUKNjih3hl1ItLln7zpAtWN2` for the Application Id. Choose a password for ActsAsIcontact that's different from your account password.
|
33
34
|
|
34
|
-
4. Set your _(sandbox, if applicable)_ account username and the password you just chose for API access.
|
35
|
+
4. Set your _(sandbox, if applicable)_ account username and the password you just chose for API access. See the next section for how to specify these.
|
36
|
+
|
37
|
+
5. Rinse and repeat with production credentials when you're ready to move out of the sandbox environment. For more information, consult the [iContact API developer documentation][5].
|
38
|
+
|
39
|
+
Authentication
|
40
|
+
--------------
|
41
|
+
ActsAsIcontact already knows iContact's URL and its own Application Id, so the only things you need to tell it are your username, password, and whether you want to access the production or sandbox environments. There are three simple ways to do that:
|
42
|
+
|
43
|
+
1. Set the environment variables `ICONTACT_MODE`, `ICONTACT_USERNAME`, and `ICONTACT_PASSWORD`. The `ICONTACT_MODE` environment variable should have a value of either ___production___ or ___sandbox___.
|
44
|
+
|
45
|
+
2. Create a directory called **.icontact** under your home directory and place a YAML file in it titled **config.yml**:
|
46
|
+
---
|
47
|
+
mode: production
|
48
|
+
username: my_username
|
49
|
+
password: my_password
|
50
|
+
This hidden directory is also used for the command line client's history file, and future versions of ActsAsIcontact may use it for caching.
|
51
|
+
|
52
|
+
3. You can explicitly set them anywhere in your code with calls to the Config module (note that the mode is a symbol, not a string):
|
35
53
|
|
36
54
|
require 'rubygems'
|
37
55
|
require 'acts_as_icontact'
|
38
56
|
|
39
57
|
ActsAsIcontact::Config.mode = :sandbox
|
40
|
-
ActsAsIcontact::Config.username = my_sandbox_username
|
41
|
-
ActsAsIcontact::Config.password = my_api_password
|
58
|
+
ActsAsIcontact::Config.username = "my_sandbox_username"
|
59
|
+
ActsAsIcontact::Config.password = "my_api_password"
|
42
60
|
|
43
61
|
If you're using Rails, the recommended approach is to require the gem with `config.gem 'acts_as_icontact'` in your **config/environment.rb** file, and then set up an initializer (i.e. **config/initializers/acts\_as\_icontact.rb**) with the above code. See more about Rails below.
|
44
62
|
|
45
|
-
|
46
|
-
|
47
|
-
API Access
|
48
|
-
----------
|
63
|
+
Using the API
|
64
|
+
-------------
|
49
65
|
Whether or not you're using Rails, retrieving and modifying iContact resources is simple. The gem autodiscovers your account and client folder IDs (you only have one of each unless you're an 'agency' account), so you can jump straight to the good parts:
|
50
66
|
|
51
67
|
contacts = ActsAsIcontact::Contact.find(:all) # => <#ActsAsIcontact::ResourceCollection>
|
@@ -61,7 +77,7 @@ Whether or not you're using Rails, retrieving and modifying iContact resources i
|
|
61
77
|
|
62
78
|
|
63
79
|
### Nesting
|
64
|
-
The interface is deliberately as "ActiveRecord-like" as possible, with methods linking resources that are either nested in iContact's URLs or logically related. Messages have a Message#bounces method. Lists have List#subscribers to list the Contacts subscribed to them, and Contacts have Contact#lists
|
80
|
+
The interface is deliberately as "ActiveRecord-like" as possible, with methods linking resources that are either nested in iContact's URLs or logically related. Messages have a Message#bounces method. Lists have `List#subscribers` to list the Contacts subscribed to them, and Contacts have `Contact#lists`. Read the [documentation][5] for each class to find out what you can do:
|
65
81
|
|
66
82
|
* ActsAsIcontact::Account
|
67
83
|
* ActsAsIcontact::ClientFolder
|
@@ -86,17 +102,64 @@ The interface is deliberately as "ActiveRecord-like" as possible, with methods l
|
|
86
102
|
* ActsAsIcontact::Time
|
87
103
|
|
88
104
|
### Searching
|
89
|
-
Searches are handled
|
105
|
+
Searches are handled using the same query options that iContact accepts, but with a syntax based on ActiveRecord. At this time, special searches (i.e. _gte_, _bet_ etc.) are not yet supported. Fields requiring dates must be given a string corresponding to the ISO8601 timestamp (e.g. `2006-09-16T14:30:00-06:00`); proper date/time conversion will happen soon. See the [iContact developer docs][5] for available search options.
|
106
|
+
|
107
|
+
The following class methods are offered (using the Message class as an example):
|
108
|
+
|
109
|
+
#### Message.first
|
110
|
+
|
111
|
+
Returns a single Message. With no parameters, it returns the first Message in iContact's system, which may be arbitrary. You can specify one or more search parameters as an options hash (note the Ruby 1.9 syntax):
|
112
|
+
Message.first(messageType: "welcome") # => The first welcome message
|
113
|
+
Message.first(orderby: "createDate:desc") # => Most recent message
|
114
|
+
|
115
|
+
If no records can be found matching the parameters, the **first** method returns nil.
|
116
|
+
|
117
|
+
#### Message.all
|
118
|
+
|
119
|
+
Returns a collection of Messages matching the search parameters. The _limit_ and _offset_ parameters are important here; if no _limit_ is provided, a default limit of 500 records is used. (That default is also the maximum, at the request of iContact's technical staff.)
|
120
|
+
|
121
|
+
The collection is an object of type ResourceCollection, and it acts both as an array and an enumerator. For efficiency, individual Message objects are instantiated only when you access them.
|
122
|
+
Message.all(messageType: "confirmation") # => All confirmation messages (up to 500)
|
123
|
+
Message.all(limit: 20) # => The first 20 messages
|
124
|
+
Message.all(limit: 20, offset: 40) # => Messages 41-60
|
125
|
+
Message.all(offset:500) # => Messages 501-1000
|
126
|
+
|
127
|
+
# Example of collection iteration
|
128
|
+
@messages = Message.all # => Assigns the first 500 messages to @messages
|
129
|
+
@messages.count # => Number of messages
|
130
|
+
@messages[11] # => Twelfth message in the collection (arrays are 0-based)
|
131
|
+
@messages.first # => First message
|
132
|
+
@messages.next # => Second message
|
133
|
+
@messages.next # => Third message (et cetera)
|
134
|
+
|
135
|
+
If no records can be found matching the parameters, the **all** method returns nil.
|
136
|
+
|
137
|
+
#### Message.find
|
90
138
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
139
|
+
Like its ActiveRecord role model, #find has several behaviors depending on its parameter list:
|
140
|
+
|
141
|
+
Message.find(:first, messageType: "welcome") # => Identical to Message.first(messageType: "welcome")
|
142
|
+
Message.find(:all, limit: 20) # => Identical to Message.all(limit: 20)
|
143
|
+
Message.find(7) # => Single Message found with messageId of 7
|
144
|
+
Message.find("foo") # => Single Message found with subject of "foo"
|
145
|
+
|
146
|
+
The _integer_ and _string_ parameter modes warrant some explanation. Passing an integer to **find** on most resource classes will do a primary key lookup. So Accounts will match on the accountId, Contacts will match on the contactId, etc. The integer variant is unsupported for the CustomField and Subscription classes, which use string-based primary keys.
|
147
|
+
|
148
|
+
Passing a string to **find** on most resource classes will do a single-record search based on the field most likely to be unique and important:
|
149
|
+
|
150
|
+
* **Account:** userName
|
151
|
+
* **Campaign:** name
|
152
|
+
* **ClientFolder:** name
|
153
|
+
* **Contact:** email
|
154
|
+
* **CustomField:** customFieldId _(primary key)_
|
155
|
+
* **List:** name
|
156
|
+
* **Message:** subject
|
157
|
+
* **Segment:** name
|
158
|
+
* **Subscription:** subscriptionId _(primary key)_
|
159
|
+
* **User:** userName
|
160
|
+
|
161
|
+
If no records can be found using **find**, the _:first_ and _:all_ variants will return nil (just like **first** and **all**). The _integer_ and _string_ variants will return an exception, on the assumption that you knew exactly what you were looking for and expected it to be there. (I.e., matching the behavior of ActiveRecord.)
|
98
162
|
|
99
|
-
At this time, special searches are not yet supported. Fields requiring dates must also be given a string corresponding to the ISO8601 timestamp (e.g. `2006-09-16T14:30:00-06:00`). Proper date/time conversion will happen soon.
|
100
163
|
|
101
164
|
### Updating
|
102
165
|
|
@@ -107,11 +170,11 @@ Again, think ActiveRecord. When you initialize an object, you can optionally pa
|
|
107
170
|
:email => "bob@example.org")
|
108
171
|
c.address = "123 Test Street"
|
109
172
|
|
110
|
-
Each resource
|
173
|
+
Each resource object has a **#save** method which returns true or false. If false, the **#error** method contains the reply back from iContact about what went wrong. (Which may or may not be informative, but we can't tell you more than they do.) There's also a **#save!** method which throws an exception on failure instead of returning false.
|
111
174
|
|
112
|
-
Nested resources can be created using the
|
175
|
+
Nested resources can be created using the **build\_foo** method (which returns an object but doesn't save it right away) or **create\_foo** method (which does save it upon creation). The full panoply of ActiveRecord association methods are not implemented yet. (Hey, we said it was AR-_like._)
|
113
176
|
|
114
|
-
The
|
177
|
+
The **#delete** method on each object works as you'd expect, assuming iContact allows deletes on that resource. Resource collections containing the resource are not updated, however, so you may need to requery.
|
115
178
|
|
116
179
|
Multiple-record updates are not implemented at this time.
|
117
180
|
|
@@ -197,4 +260,10 @@ iContact's interface is really quite good at handling pretty much every other re
|
|
197
260
|
|
198
261
|
Copyright
|
199
262
|
---------
|
200
|
-
Copyright (c) 2009 Stephen Eley. See LICENSE for details.
|
263
|
+
Copyright (c) 2009 Stephen Eley. See LICENSE for details.
|
264
|
+
|
265
|
+
[1]: http://icontact.com "iContact"
|
266
|
+
[2]: http://rest-client.heroku.com "Rest-Client"
|
267
|
+
[3]: http://as.rubyonrails.org/ "ActiveSupport"
|
268
|
+
[4]: http://tagaholic.me/bond "Bond"
|
269
|
+
[5]: http://developer.icontact.com/ "iContact Developer Portal"
|
data/Rakefile
CHANGED
@@ -10,7 +10,18 @@ begin
|
|
10
10
|
gem.homepage = "http://github.com/SFEley/acts_as_icontact"
|
11
11
|
gem.authors = ["Stephen Eley"]
|
12
12
|
gem.rubyforge_project = "actsasicontact"
|
13
|
+
gem.executables = "icontact"
|
14
|
+
gem.has_rdoc = true
|
13
15
|
gem.extra_rdoc_files = ["README.markdown"]
|
16
|
+
gem.rdoc_options << '--all'
|
17
|
+
gem.add_dependency 'rest-client', '>= 1.0'
|
18
|
+
gem.add_dependency 'activesupport', '>= 2.3.2'
|
19
|
+
gem.add_dependency 'bond', '>= 0.1.4'
|
20
|
+
gem.add_development_dependency 'rspec'
|
21
|
+
gem.add_development_dependency 'mocha'
|
22
|
+
gem.add_development_dependency 'fakeweb'
|
23
|
+
|
24
|
+
|
14
25
|
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
15
26
|
gem.description = <<ENDDESC
|
16
27
|
ActsAsIcontact connects Ruby applications with the iContact e-mail marketing service using the iContact API v2.0. Building on the RestClient gem, it offers two significant feature sets:
|
@@ -40,7 +51,7 @@ end
|
|
40
51
|
|
41
52
|
task :default => :spec
|
42
53
|
|
43
|
-
require '
|
54
|
+
require 'rake/rdoctask'
|
44
55
|
Rake::RDocTask.new do |rdoc|
|
45
56
|
if File.exist?('VERSION.yml')
|
46
57
|
config = YAML.load(File.read('VERSION.yml'))
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.2
|
data/acts_as_icontact.gemspec
CHANGED
@@ -1,12 +1,15 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
1
4
|
# -*- encoding: utf-8 -*-
|
2
5
|
|
3
6
|
Gem::Specification.new do |s|
|
4
7
|
s.name = %q{acts_as_icontact}
|
5
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.2"
|
6
9
|
|
7
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
11
|
s.authors = ["Stephen Eley"]
|
9
|
-
s.date = %q{2009-08-
|
12
|
+
s.date = %q{2009-08-08}
|
10
13
|
s.default_executable = %q{icontact}
|
11
14
|
s.description = %q{ActsAsIcontact connects Ruby applications with the iContact e-mail marketing service using the iContact API v2.0. Building on the RestClient gem, it offers two significant feature sets:
|
12
15
|
|
@@ -40,6 +43,7 @@ Gem::Specification.new do |s|
|
|
40
43
|
"lib/acts_as_icontact/resource.rb",
|
41
44
|
"lib/acts_as_icontact/resource_collection.rb",
|
42
45
|
"lib/acts_as_icontact/resources/account.rb",
|
46
|
+
"lib/acts_as_icontact/resources/campaign.rb",
|
43
47
|
"lib/acts_as_icontact/resources/client.rb",
|
44
48
|
"lib/acts_as_icontact/resources/contact.rb",
|
45
49
|
"lib/acts_as_icontact/resources/custom_field.rb",
|
@@ -56,7 +60,8 @@ Gem::Specification.new do |s|
|
|
56
60
|
"spec/resource_collection_spec.rb",
|
57
61
|
"spec/resource_spec.rb",
|
58
62
|
"spec/resources/account_spec.rb",
|
59
|
-
"spec/resources/
|
63
|
+
"spec/resources/campaign_spec.rb",
|
64
|
+
"spec/resources/clientfolder_spec.rb",
|
60
65
|
"spec/resources/contact_spec.rb",
|
61
66
|
"spec/resources/custom_field_spec.rb",
|
62
67
|
"spec/resources/list_spec.rb",
|
@@ -69,7 +74,7 @@ Gem::Specification.new do |s|
|
|
69
74
|
"spec/support/spec_fakeweb.rb"
|
70
75
|
]
|
71
76
|
s.homepage = %q{http://github.com/SFEley/acts_as_icontact}
|
72
|
-
s.rdoc_options = ["--charset=UTF-8"]
|
77
|
+
s.rdoc_options = ["--charset=UTF-8", "--all"]
|
73
78
|
s.require_paths = ["lib"]
|
74
79
|
s.rubyforge_project = %q{actsasicontact}
|
75
80
|
s.rubygems_version = %q{1.3.5}
|
@@ -84,7 +89,8 @@ Gem::Specification.new do |s|
|
|
84
89
|
"spec/resource_collection_spec.rb",
|
85
90
|
"spec/resource_spec.rb",
|
86
91
|
"spec/resources/account_spec.rb",
|
87
|
-
"spec/resources/
|
92
|
+
"spec/resources/campaign_spec.rb",
|
93
|
+
"spec/resources/clientfolder_spec.rb",
|
88
94
|
"spec/resources/contact_spec.rb",
|
89
95
|
"spec/resources/custom_field_spec.rb",
|
90
96
|
"spec/resources/list_spec.rb",
|
@@ -101,8 +107,26 @@ Gem::Specification.new do |s|
|
|
101
107
|
s.specification_version = 3
|
102
108
|
|
103
109
|
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
110
|
+
s.add_runtime_dependency(%q<rest-client>, [">= 1.0"])
|
111
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 2.3.2"])
|
112
|
+
s.add_runtime_dependency(%q<bond>, [">= 0.1.4"])
|
113
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
114
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
115
|
+
s.add_development_dependency(%q<fakeweb>, [">= 0"])
|
104
116
|
else
|
117
|
+
s.add_dependency(%q<rest-client>, [">= 1.0"])
|
118
|
+
s.add_dependency(%q<activesupport>, [">= 2.3.2"])
|
119
|
+
s.add_dependency(%q<bond>, [">= 0.1.4"])
|
120
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
121
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
122
|
+
s.add_dependency(%q<fakeweb>, [">= 0"])
|
105
123
|
end
|
106
124
|
else
|
125
|
+
s.add_dependency(%q<rest-client>, [">= 1.0"])
|
126
|
+
s.add_dependency(%q<activesupport>, [">= 2.3.2"])
|
127
|
+
s.add_dependency(%q<bond>, [">= 0.1.4"])
|
128
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
129
|
+
s.add_dependency(%q<mocha>, [">= 0"])
|
130
|
+
s.add_dependency(%q<fakeweb>, [">= 0"])
|
107
131
|
end
|
108
132
|
end
|
data/bin/icontact
CHANGED
@@ -12,7 +12,7 @@ module ActsAsIcontact
|
|
12
12
|
history_file = File.join(ENV["HOME"], '.icontact_history')
|
13
13
|
IO.readlines(history_file).each {|e| Readline::HISTORY << e.chomp } if File.exists?(history_file)
|
14
14
|
print "# ActsAsIcontact command line (type 'exit' to quit)\n"
|
15
|
-
while (input = Readline.readline(
|
15
|
+
while (input = Readline.readline("\n>> ", true)) != 'exit'
|
16
16
|
begin puts "=> #{eval(input).inspect}"; rescue Exception; puts "Error: #{$!}" end
|
17
17
|
end
|
18
18
|
File.open(history_file, 'w') {|f| f.write Readline::HISTORY.to_a.join("\n") }
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'activesupport'
|
2
2
|
require 'uri'
|
3
|
+
require 'YAML'
|
3
4
|
|
4
5
|
module ActsAsIcontact
|
5
6
|
# Base class for shared functionality between iContact resources. Supports getting, finding, saving,
|
@@ -150,6 +151,11 @@ module ActsAsIcontact
|
|
150
151
|
properties == obj.properties
|
151
152
|
end
|
152
153
|
|
154
|
+
# Returns a nice formatted string for command line use.
|
155
|
+
def inspect
|
156
|
+
properties.to_yaml
|
157
|
+
end
|
158
|
+
|
153
159
|
protected
|
154
160
|
# The minimum set of fields that must be sent back to iContact on an update.
|
155
161
|
# Includes any fields that changed or were added, the primary key, and anything
|
@@ -173,7 +179,7 @@ module ActsAsIcontact
|
|
173
179
|
# The base RestClient resource that this particular class nests from. Defaults to
|
174
180
|
# the clientFolders path since that's the most common case.
|
175
181
|
def self.base
|
176
|
-
ActsAsIcontact.
|
182
|
+
ActsAsIcontact.clientfolder
|
177
183
|
end
|
178
184
|
|
179
185
|
# The name of the singular resource type pulled from iContact. Defaults to the lowercase
|
@@ -1,15 +1,17 @@
|
|
1
1
|
module ActsAsIcontact
|
2
2
|
class ResourceCollection < Enumerator
|
3
|
-
attr_reader :total, :retrieved
|
3
|
+
attr_reader :total, :retrieved, :offset, :collection_name
|
4
4
|
|
5
5
|
def initialize(klass, collection, forwardTo=nil)
|
6
6
|
@klass = klass
|
7
7
|
@forwardTo = forwardTo
|
8
8
|
|
9
|
-
@
|
9
|
+
@collection_name = klass.collection_name
|
10
|
+
@collection = collection[collection_name]
|
10
11
|
# Get number of elements
|
11
12
|
@retrieved = @collection.size
|
12
13
|
@total = collection["total"]
|
14
|
+
@offset = collection["offset"]
|
13
15
|
|
14
16
|
enumcode = Proc.new do |yielder|
|
15
17
|
counter = 0
|
@@ -32,6 +34,18 @@ module ActsAsIcontact
|
|
32
34
|
self.next
|
33
35
|
end
|
34
36
|
|
37
|
+
# Returns a nice formatted string for command line use.
|
38
|
+
def inspect
|
39
|
+
if offset.to_i > 0
|
40
|
+
"#{retrieved} out of #{total} #{collection_name} (offset #{offset})"
|
41
|
+
elsif retrieved != total
|
42
|
+
"#{retrieved} out of #{total} #{collection_name}"
|
43
|
+
else
|
44
|
+
"#{total} #{collection_name}"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
35
49
|
private
|
36
50
|
def resource(properties)
|
37
51
|
if @forwardTo
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
class Campaign < Resource
|
3
|
+
|
4
|
+
# Defaults forwardToFriend to 0; subscriptionManagement, clickTrackMode to true; and useAccountAddress, archiveByDefault to false
|
5
|
+
def initialize(properties={})
|
6
|
+
super({:forwardToFriend => 0,
|
7
|
+
:clickTrackMode => true,
|
8
|
+
:subscriptionManagement => true,
|
9
|
+
:useAccountAddress => false,
|
10
|
+
:archiveByDefault => false}.merge(properties))
|
11
|
+
end
|
12
|
+
|
13
|
+
# Requires name, fromName, fromEmail, forwardToFriend, subscriptionManagement, clickTrackMode, useAccountAddress, and archiveByDefault
|
14
|
+
def self.required_on_create
|
15
|
+
super + %w(name fromName fromEmail forwardToFriend subscriptionManagement clickTrackMode useAccountAddress archiveByDefault)
|
16
|
+
end
|
17
|
+
|
18
|
+
# The following can be set with true or false: subscriptionManagement, clickTrackMode, useAccountAddress, archiveByDefault
|
19
|
+
def self.boolean_fields
|
20
|
+
super + %w(subscriptionManagement clickTrackMode useAccountAddress archiveByDefault)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns a collection of all Message resources matching this campaignId. Additional search options can be passed to further restrict the result set.
|
24
|
+
def messages(options={})
|
25
|
+
search = {:campaignId => id}.merge(options)
|
26
|
+
Message.all(search)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActsAsIcontact
|
2
2
|
# The nested Client Folder resource from iContact. Currently only supports retrieval -- and is
|
3
3
|
# highly targeted toward the _first_ client folder, since that seems to be the dominant use case.
|
4
|
-
class
|
4
|
+
class ClientFolder < Resource
|
5
5
|
# Derives from the Account resource.
|
6
6
|
def self.base
|
7
7
|
ActsAsIcontact.account
|
@@ -26,25 +26,25 @@ module ActsAsIcontact
|
|
26
26
|
|
27
27
|
# The clientFolderId retrieved from iContact. Can also be set manually for performance
|
28
28
|
# optimization, but remembers it so that it won't be pulled more than once anyway.
|
29
|
-
def self.
|
30
|
-
@
|
29
|
+
def self.clientfolder_id
|
30
|
+
@clientfolder_id ||= ClientFolder.first.clientFolderId.to_i
|
31
31
|
end
|
32
32
|
|
33
33
|
# Manually sets the clientFolderId used in subsequent calls. Setting this in your
|
34
34
|
# initializer will save at least one unnecessary request to the iContact server.
|
35
|
-
def self.
|
36
|
-
@
|
35
|
+
def self.clientfolder_id=(val)
|
36
|
+
@clientfolder_id = val
|
37
37
|
end
|
38
38
|
|
39
39
|
# RestClient subresource scoped to the specific account ID. Most other iContact calls will derive
|
40
40
|
# from this one.
|
41
|
-
def self.
|
42
|
-
@
|
41
|
+
def self.clientfolder
|
42
|
+
@clientfolder ||= account["c/#{clientfolder_id}"]
|
43
43
|
end
|
44
44
|
|
45
45
|
# Clears the account resource from memory. Called by reset_connection! since the only likely reason
|
46
46
|
# to do this is connecting as a different user.
|
47
|
-
def self.
|
48
|
-
@
|
47
|
+
def self.reset_clientfolder!
|
48
|
+
@clientfolder = nil
|
49
49
|
end
|
50
50
|
end
|
@@ -1,9 +1,5 @@
|
|
1
1
|
module ActsAsIcontact
|
2
2
|
class List < Resource
|
3
|
-
# Derives from clientFolder.
|
4
|
-
def self.base
|
5
|
-
ActsAsIcontact.client
|
6
|
-
end
|
7
3
|
|
8
4
|
# Searches on list name.
|
9
5
|
def self.find_by_string(value)
|
@@ -15,6 +11,7 @@ module ActsAsIcontact
|
|
15
11
|
super << "name" << "emailOwnerOnChange" << "welcomeOnManualAdd" << "welcomeOnSignupAdd" << "welcomeMessageId"
|
16
12
|
end
|
17
13
|
|
14
|
+
# The following can be set with true or false: emailOwnerOnChange, welcomeOnManualAdd, welcomeOnSignupAdd
|
18
15
|
def self.boolean_fields
|
19
16
|
super << "emailOwnerOnChange" << "welcomeOnManualAdd" << "welcomeOnSignupAdd"
|
20
17
|
end
|
@@ -15,5 +15,14 @@ module ActsAsIcontact
|
|
15
15
|
messageType = %w(normal autoresponder welcome confirmation)
|
16
16
|
raise ActsAsIcontact::ValidationError, "messageType must be one of: " + messageType.join(', ') unless messageType.include?(fields["messageType"])
|
17
17
|
end
|
18
|
+
|
19
|
+
# Returns the Campaign resource associated with this message, if campaignId is set. Otherwise returns nil. Returns an exception if the campaignId is set but the campaign cannot be found.
|
20
|
+
def campaign
|
21
|
+
if (c = campaignId.to_i) > 0
|
22
|
+
Campaign.find(c)
|
23
|
+
else
|
24
|
+
nil
|
25
|
+
end
|
26
|
+
end
|
18
27
|
end
|
19
28
|
end
|
@@ -24,4 +24,32 @@ describe ActsAsIcontact::ResourceCollection do
|
|
24
24
|
@this.first.foo.should == "bar"
|
25
25
|
@this.next.yoo.should == "yar"
|
26
26
|
end
|
27
|
+
|
28
|
+
it "knows its total size" do
|
29
|
+
@this.total.should == 2
|
30
|
+
end
|
31
|
+
|
32
|
+
it "knows its count" do
|
33
|
+
@this.count.should == 2
|
34
|
+
end
|
35
|
+
|
36
|
+
it "knows its offset" do
|
37
|
+
@this.offset.should == 0
|
38
|
+
end
|
39
|
+
|
40
|
+
it "has a nice string representation when all resources are retrieved" do
|
41
|
+
r = ActsAsIcontact::Resource.all
|
42
|
+
r.inspect.should =~ /^12 resources/
|
43
|
+
end
|
44
|
+
|
45
|
+
it "has a nice string representation when some resources are retrieved" do
|
46
|
+
r = ActsAsIcontact::Resource.all(limit: 5)
|
47
|
+
r.inspect.should =~ /^5 out of 12 resources/
|
48
|
+
end
|
49
|
+
|
50
|
+
it "has a nice string representation when an offset is used" do
|
51
|
+
r = ActsAsIcontact::Resource.all(limit: 5, offset: 5)
|
52
|
+
r.inspect.should =~ /^5 out of 12 resources \(offset 5\)/
|
53
|
+
end
|
54
|
+
|
27
55
|
end
|
data/spec/resource_spec.rb
CHANGED
@@ -2,7 +2,7 @@ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
2
|
|
3
3
|
describe ActsAsIcontact::Resource do
|
4
4
|
it "has a RestClient connection" do
|
5
|
-
ActsAsIcontact::Resource.connection.url.should == ActsAsIcontact.
|
5
|
+
ActsAsIcontact::Resource.connection.url.should == ActsAsIcontact.clientfolder['resources'].url
|
6
6
|
end
|
7
7
|
|
8
8
|
it "can return all resources for the given URL" do
|
@@ -13,6 +13,13 @@ describe ActsAsIcontact::Resource do
|
|
13
13
|
ActsAsIcontact::Resource.first.should be_a_kind_of(ActsAsIcontact::Resource)
|
14
14
|
end
|
15
15
|
|
16
|
+
it "has a nice string representation" do
|
17
|
+
r = ActsAsIcontact::Resource.first
|
18
|
+
r.inspect.should =~ /foo: bar/m
|
19
|
+
r.inspect.should =~ /resourceId: 1/m
|
20
|
+
r.inspect.should =~ /too: bar/m
|
21
|
+
end
|
22
|
+
|
16
23
|
describe "find method" do
|
17
24
|
it "returns a ResourceCollection when given :all" do
|
18
25
|
r = ActsAsIcontact::Resource.find(:all)
|
@@ -104,7 +111,7 @@ describe ActsAsIcontact::Resource do
|
|
104
111
|
|
105
112
|
it "has its own connection if it's not new" do
|
106
113
|
r = ActsAsIcontact::Resource.first
|
107
|
-
r.connection.url.should == ActsAsIcontact.
|
114
|
+
r.connection.url.should == ActsAsIcontact.clientfolder['resources/1'].url
|
108
115
|
end
|
109
116
|
|
110
117
|
it "does not have a connection if it's new" do
|
@@ -113,7 +120,7 @@ describe ActsAsIcontact::Resource do
|
|
113
120
|
end
|
114
121
|
|
115
122
|
it "knows its REST base resource" do
|
116
|
-
ActsAsIcontact::Resource.base.should == ActsAsIcontact.
|
123
|
+
ActsAsIcontact::Resource.base.should == ActsAsIcontact.clientfolder
|
117
124
|
end
|
118
125
|
|
119
126
|
it "knows its primary key" do
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe ActsAsIcontact::Campaign do
|
4
|
+
before(:each) do
|
5
|
+
@contact = ActsAsIcontact::Campaign.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "requires a name" do
|
9
|
+
lambda{@contact.save}.should raise_error(ActsAsIcontact::ValidationError, /name/)
|
10
|
+
end
|
11
|
+
|
12
|
+
it "requires a fromName" do
|
13
|
+
lambda{@contact.save}.should raise_error(ActsAsIcontact::ValidationError, /fromName/)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
it "requires a fromEmail" do
|
18
|
+
lambda{@contact.save}.should raise_error(ActsAsIcontact::ValidationError, /fromEmail/)
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
it "defaults forwardToFriend to 0" do
|
23
|
+
@contact.forwardToFriend.should == 0
|
24
|
+
end
|
25
|
+
|
26
|
+
it "defaults subscriptionManagement to true" do
|
27
|
+
@contact.subscriptionManagement.should be_true
|
28
|
+
end
|
29
|
+
|
30
|
+
it "defaults clickTrackMode to true" do
|
31
|
+
@contact.subscriptionManagement.should be_true
|
32
|
+
end
|
33
|
+
|
34
|
+
it "defaults useAccountAddress to false" do
|
35
|
+
@contact.useAccountAddress.should be_false
|
36
|
+
end
|
37
|
+
|
38
|
+
it "defaults archiveByDefault to false" do
|
39
|
+
@contact.archiveByDefault.should be_false
|
40
|
+
end
|
41
|
+
|
42
|
+
context "associations" do
|
43
|
+
before(:each) do
|
44
|
+
@campaign = ActsAsIcontact::Campaign.first
|
45
|
+
end
|
46
|
+
|
47
|
+
it "knows which messages it has (if any)" do
|
48
|
+
m = @campaign.messages
|
49
|
+
m.count.should == 2
|
50
|
+
end
|
51
|
+
|
52
|
+
it "can narrow down the messages list" do
|
53
|
+
m = @campaign.messages(messageType: "welcome")
|
54
|
+
m.count.should == 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
@@ -2,51 +2,51 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
|
2
2
|
|
3
3
|
describe ActsAsIcontact, "account_id" do
|
4
4
|
it "returns the ID from the first client folder returned by iContact" do
|
5
|
-
ActsAsIcontact.
|
5
|
+
ActsAsIcontact.clientfolder_id.should == 222222
|
6
6
|
end
|
7
7
|
|
8
8
|
it "can be set by the user" do
|
9
|
-
ActsAsIcontact.
|
10
|
-
ActsAsIcontact.
|
9
|
+
ActsAsIcontact.clientfolder_id = 456
|
10
|
+
ActsAsIcontact.clientfolder_id.should == 456
|
11
11
|
end
|
12
12
|
|
13
13
|
after(:each) do
|
14
|
-
ActsAsIcontact.
|
14
|
+
ActsAsIcontact.clientfolder_id = nil
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
18
|
|
19
|
-
describe ActsAsIcontact, "
|
19
|
+
describe ActsAsIcontact, "clientfolder method" do
|
20
20
|
it "returns a RestClient resource" do
|
21
|
-
ActsAsIcontact.
|
21
|
+
ActsAsIcontact.clientfolder.should be_a_kind_of(RestClient::Resource)
|
22
22
|
end
|
23
23
|
|
24
24
|
it "builds upon the 'account' object" do
|
25
25
|
ActsAsIcontact.expects(:account).returns(ActsAsIcontact.instance_variable_get(:@account))
|
26
|
-
ActsAsIcontact.
|
26
|
+
ActsAsIcontact.clientfolder.should_not be_nil
|
27
27
|
end
|
28
28
|
|
29
29
|
it "can be cleared with the reset_account! method" do
|
30
|
-
ActsAsIcontact.
|
31
|
-
ActsAsIcontact.instance_variable_get(:@
|
30
|
+
ActsAsIcontact.reset_clientfolder!
|
31
|
+
ActsAsIcontact.instance_variable_get(:@clientfolder).should be_nil
|
32
32
|
end
|
33
33
|
|
34
34
|
after(:each) do
|
35
|
-
ActsAsIcontact.
|
35
|
+
ActsAsIcontact.reset_clientfolder!
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
describe ActsAsIcontact::
|
39
|
+
describe ActsAsIcontact::ClientFolder do
|
40
40
|
it "can return all clients for the given account" do
|
41
|
-
ActsAsIcontact::
|
41
|
+
ActsAsIcontact::ClientFolder.all.count.should == 1
|
42
42
|
end
|
43
43
|
|
44
44
|
it "can return the first client" do
|
45
|
-
ActsAsIcontact::
|
45
|
+
ActsAsIcontact::ClientFolder.first.should be_a_kind_of(ActsAsIcontact::ClientFolder)
|
46
46
|
end
|
47
47
|
|
48
48
|
it "knows its properties" do
|
49
|
-
c = ActsAsIcontact::
|
49
|
+
c = ActsAsIcontact::ClientFolder.first
|
50
50
|
c.emailRecipient.should == "bob@example.org"
|
51
51
|
end
|
52
52
|
end
|
@@ -22,7 +22,9 @@ describe ActsAsIcontact::Message do
|
|
22
22
|
@message = ActsAsIcontact::Message.first(:subject => "Test Message")
|
23
23
|
end
|
24
24
|
|
25
|
-
it "knows which campaign it has (if any)"
|
25
|
+
it "knows which campaign it has (if any)" do
|
26
|
+
@message.campaign.name.should == "Test Campaign"
|
27
|
+
end
|
26
28
|
end
|
27
29
|
|
28
30
|
end
|
@@ -7,7 +7,7 @@ ic = "#{i}/a/111111/c/222222"
|
|
7
7
|
|
8
8
|
# Resources (this one's a fake stub for pure testing)
|
9
9
|
FakeWeb.register_uri(:get, "#{ic}/resources?limit=500", :body => %q<{"resources":[{"foo":"bar","resourceId":"1","too":"bar"},{"foo":"aar","resourceId":"2"},{"foo":"far","resourceId":"3"},{"foo":"car","resourceId":"4"},{"foo":"dar","resourceId":"5"},{"foo":"ear","resourceId":"6"},{"foo":"gar","resourceId":"7"},{"foo":"har","resourceId":"8"},{"foo":"iar","resourceId":"9"},{"foo":"jar","resourceId":"10"},{"foo":"kar","resourceId":"11"},{"foo":"yar","resourceId":"12"}],"total":12,"limit":20,"offset":0}>)
|
10
|
-
FakeWeb.register_uri(:get, "#{ic}/resources?limit=1", :body => %q<{"resources":[{"foo":"bar","resourceId":"1","too":"bar"}
|
10
|
+
FakeWeb.register_uri(:get, "#{ic}/resources?limit=1", :body => %q<{"resources":[{"foo":"bar","resourceId":"1","too":"bar"}],"total":12,"limit":1,"offset":0}>)
|
11
11
|
FakeWeb.register_uri(:get, "#{ic}/resources?limit=5", :body => %q<{"resources":[{"foo":"bar","resourceId":"1"},{"foo":"aar","resourceId":"2"},{"foo":"far","resourceId":"3"},{"foo":"car","resourceId":"4"},{"foo":"dar","resourceId":"5"}],"total":12,"limit":5,"offset":0}>)
|
12
12
|
FakeWeb.register_uri(:get, "#{ic}/resources?limit=500&offset=5", :body => %q<{"resources":[{"foo":"ear","resourceId":"6"},{"foo":"gar","resourceId":"7"},{"foo":"har","resourceId":"8"},{"foo":"iar","resourceId":"9"},{"foo":"jar","resourceId":"10"},{"foo":"kar","resourceId":"11"},{"foo":"yar","resourceId":"12"}],"total":12,"limit":20,"offset":5}>)
|
13
13
|
FakeWeb.register_uri(:get, "#{ic}/resources?offset=5&limit=5", :body => %q<{"resources":[{"foo":"ear","resourceId":"6"},{"foo":"gar","resourceId":"7"},{"foo":"har","resourceId":"8"},{"foo":"iar","resourceId":"9"},{"foo":"jar","resourceId":"10"}],"total":12,"limit":5,"offset":5}>)
|
@@ -40,12 +40,14 @@ FakeWeb.register_uri(:get, "#{ic}/lists/444444", :body => %q<{"list":{"listId":"
|
|
40
40
|
|
41
41
|
# Message
|
42
42
|
#### Test welcome message for List association
|
43
|
-
FakeWeb.register_uri(:get, "#{ic}/messages/555555", :body => %q<{"message":{"messageId":"555555","subject":"Welcome!","messageType":"welcome","textBody":"Welcome to the Test List!","htmlBody":"<p>Welcome to the <b>Test List</b>!</p>","createDate":"20090725 14:55:12"}}>)
|
43
|
+
FakeWeb.register_uri(:get, "#{ic}/messages/555555", :body => %q<{"message":{"messageId":"555555","subject":"Welcome!","messageType":"welcome","textBody":"Welcome to the Test List!","htmlBody":"<p>Welcome to the <b>Test List</b>!</p>","createDate":"20090725 14:55:12","campaignId":"777777"}}>)
|
44
44
|
#### Test confirmation message
|
45
|
-
FakeWeb.register_uri(:get, "#{ic}/messages/555666", :body => %q<{"message":{"messageId":"555666","subject":"Confirm!","messageType":"confirmation","textBody":"Please confirm your subscription.","htmlBody":"<p>Please confirm your subscription.</p>","createDate":"20090727 14:55:12"}}>)
|
46
|
-
|
45
|
+
FakeWeb.register_uri(:get, "#{ic}/messages/555666", :body => %q<{"message":{"messageId":"555666","subject":"Confirm!","messageType":"confirmation","textBody":"Please confirm your subscription.","htmlBody":"<p>Please confirm your subscription.</p>","createDate":"20090727 14:55:12","campaignId":"777777"}}>)
|
46
|
+
#### Searches from campaignId
|
47
|
+
FakeWeb.register_uri(:get, "#{ic}/messages?limit=500&campaignId=777777", :body => %q<{"messages":[{"messageId":"555555","subject":"Welcome!","messageType":"welcome","textBody":"Welcome to the Test List!","htmlBody":"<p>Welcome to the <b>Test List</b>!</p>","createDate":"20090725 14:55:12","campaignId":"777777"},{"messageId":"555666","subject":"Confirm!","messageType":"confirmation","textBody":"Please confirm your subscription.","htmlBody":"<p>Please confirm your subscription.</p>","createDate":"20090727 14:55:12","campaignId":"777777"}],"count":2}>)
|
48
|
+
FakeWeb.register_uri(:get, "#{ic}/messages?limit=500&campaignId=777777&messageType=welcome", :body => %q<{"messages":[{"messageId":"555555","subject":"Welcome!","messageType":"welcome","textBody":"Welcome to the Test List!","htmlBody":"<p>Welcome to the <b>Test List</b>!</p>","createDate":"20090725 14:55:12","campaignId":"777777"}],"count":1}>)
|
47
49
|
#### Test message for associations originating from Message spec
|
48
|
-
FakeWeb.register_uri(:get, "#{ic}/messages?limit=1&subject=Test%20Message", :body => %q<{"messages":[{"messageId":"666666","subject":"Test Message","messageType":"normal","textBody":"Hi there!\nThis is just a test.","htmlBody":"<p><b>Hi there!</b></p><p>This is just a <i>test.</i></p>","createDate":"20090725 14:53:33"}]}>)
|
50
|
+
FakeWeb.register_uri(:get, "#{ic}/messages?limit=1&subject=Test%20Message", :body => %q<{"messages":[{"messageId":"666666","subject":"Test Message","messageType":"normal","textBody":"Hi there!\nThis is just a test.","htmlBody":"<p><b>Hi there!</b></p><p>This is just a <i>test.</i></p>","createDate":"20090725 14:53:33","campaignId":"777777"}]}>)
|
49
51
|
|
50
52
|
# CustomField
|
51
53
|
FakeWeb.register_uri(:get, "#{ic}/customfields?limit=500", :body => %q<{"customfields":[{"privateName":"test_field","publicName":"Test Field","displayToUser":"0","fieldType":"text"},{"privateName":"custom_field","publicName":"This is for the Rails integration specs","displayToUser":1,"fieldType":"text"}],"total":2}>)
|
@@ -60,3 +62,7 @@ FakeWeb.register_uri(:get, "#{ic}/subscriptions?limit=1&contactId=333444", :body
|
|
60
62
|
FakeWeb.register_uri(:get, "#{ic}/subscriptions?limit=500&contactId=333444", :body => %q<{"subscriptions":[{"status":"normal","addDate":"2009-07-27T15:36:37-04:00","contactId":333444,"listId":444444, "subscriptionId":"444444_333444","confirmationMessageId":555666}]}>)
|
61
63
|
FakeWeb.register_uri(:get, "#{ic}/subscriptions?limit=500&contactId=333333", :body => %q<{"subscriptions":[{"status":"normal","addDate":"2009-07-27T15:36:37-04:00","contactId":333333,"listId":444444, "subscriptionId":"444444_333333","confirmationMessageId":555666}]}>)
|
62
64
|
FakeWeb.register_uri(:post, "#{ic}/subscriptions", :body => %q<{"subscriptions":[{"status":"normal","addDate":"2009-07-27T15:36:37-04:00","contactId":333333,"listId":444444, "subscriptionId":"444444_333333","confirmationMessageId":555666}]}>)
|
65
|
+
|
66
|
+
# Campaign
|
67
|
+
FakeWeb.register_uri(:get, "#{ic}/campaigns?limit=1", :body => %q<{"campaigns":[{"campaignId":"777777","name":"Test Campaign","fromName":"Bob Smith","fromEmail":"bob@example.org","forwardToFriend":0,"subscriptionManagement":1,"clickTrackMode":1,"useAccountAddress":0,"archiveByDefault":0,"description":""}],"count":1}>)
|
68
|
+
FakeWeb.register_uri(:get, "#{ic}/campaigns/777777", :body => %q<{"campaign":{"campaignId":"777777","name":"Test Campaign","fromName":"Bob Smith","fromEmail":"bob@example.org","forwardToFriend":0,"subscriptionManagement":1,"clickTrackMode":1,"useAccountAddress":0,"archiveByDefault":0,"description":""}}>)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acts_as_icontact
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Eley
|
@@ -9,10 +9,69 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-08-
|
12
|
+
date: 2009-08-08 00:00:00 -04:00
|
13
13
|
default_executable: icontact
|
14
|
-
dependencies:
|
15
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rest-client
|
17
|
+
type: :runtime
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "1.0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: activesupport
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 2.3.2
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: bond
|
37
|
+
type: :runtime
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 0.1.4
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: rspec
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mocha
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: fakeweb
|
67
|
+
type: :development
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
16
75
|
description: |
|
17
76
|
ActsAsIcontact connects Ruby applications with the iContact e-mail marketing service using the iContact API v2.0. Building on the RestClient gem, it offers two significant feature sets:
|
18
77
|
|
@@ -48,6 +107,7 @@ files:
|
|
48
107
|
- lib/acts_as_icontact/resource.rb
|
49
108
|
- lib/acts_as_icontact/resource_collection.rb
|
50
109
|
- lib/acts_as_icontact/resources/account.rb
|
110
|
+
- lib/acts_as_icontact/resources/campaign.rb
|
51
111
|
- lib/acts_as_icontact/resources/client.rb
|
52
112
|
- lib/acts_as_icontact/resources/contact.rb
|
53
113
|
- lib/acts_as_icontact/resources/custom_field.rb
|
@@ -64,7 +124,8 @@ files:
|
|
64
124
|
- spec/resource_collection_spec.rb
|
65
125
|
- spec/resource_spec.rb
|
66
126
|
- spec/resources/account_spec.rb
|
67
|
-
- spec/resources/
|
127
|
+
- spec/resources/campaign_spec.rb
|
128
|
+
- spec/resources/clientfolder_spec.rb
|
68
129
|
- spec/resources/contact_spec.rb
|
69
130
|
- spec/resources/custom_field_spec.rb
|
70
131
|
- spec/resources/list_spec.rb
|
@@ -82,6 +143,7 @@ licenses: []
|
|
82
143
|
post_install_message:
|
83
144
|
rdoc_options:
|
84
145
|
- --charset=UTF-8
|
146
|
+
- --all
|
85
147
|
require_paths:
|
86
148
|
- lib
|
87
149
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -113,7 +175,8 @@ test_files:
|
|
113
175
|
- spec/resource_collection_spec.rb
|
114
176
|
- spec/resource_spec.rb
|
115
177
|
- spec/resources/account_spec.rb
|
116
|
-
- spec/resources/
|
178
|
+
- spec/resources/campaign_spec.rb
|
179
|
+
- spec/resources/clientfolder_spec.rb
|
117
180
|
- spec/resources/contact_spec.rb
|
118
181
|
- spec/resources/custom_field_spec.rb
|
119
182
|
- spec/resources/list_spec.rb
|