acts_as_icontact 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +6 -0
- data/LICENSE +20 -0
- data/README.markdown +196 -0
- data/Rakefile +57 -0
- data/VERSION +1 -0
- data/acts_as_icontact.gemspec +74 -0
- data/lib/acts_as_icontact.rb +19 -0
- data/lib/acts_as_icontact/config.rb +106 -0
- data/lib/acts_as_icontact/connection.rb +32 -0
- data/lib/acts_as_icontact/exceptions.rb +19 -0
- data/lib/acts_as_icontact/resource.rb +204 -0
- data/lib/acts_as_icontact/resource_collection.rb +27 -0
- data/lib/acts_as_icontact/resources/account.rb +38 -0
- data/lib/acts_as_icontact/resources/client.rb +45 -0
- data/lib/acts_as_icontact/resources/contact.rb +7 -0
- data/spec/config_spec.rb +181 -0
- data/spec/connection_spec.rb +36 -0
- data/spec/resource_collection_spec.rb +23 -0
- data/spec/resource_spec.rb +301 -0
- data/spec/resources/account_spec.rb +52 -0
- data/spec/resources/client_spec.rb +52 -0
- data/spec/resources/contact_spec.rb +8 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_fakeweb.rb +23 -0
- data/spec/spec_helper.rb +18 -0
- metadata +93 -0
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# Returns an instance of RestClient::Resource with iContact authentication headers. All other
|
3
|
+
# resource classes build from this method. Throws an ActsAsIcontact::ConfigError if the username
|
4
|
+
# or password are missing from configuration.
|
5
|
+
#
|
6
|
+
# (Author's Note: I'm not especially thrilled with this name, since it implies some sort of keepalive
|
7
|
+
# or other persistent state. I'd rather call this 'client' -- but that's already a bit overloaded
|
8
|
+
# within iContact's nomenclature. And calling it 'server' got _me_ confused. This is the best of a
|
9
|
+
# motley array of possibilities.)
|
10
|
+
def self.connection
|
11
|
+
@connection or begin
|
12
|
+
raise ConfigError, "Username is required" unless Config.username
|
13
|
+
raise ConfigError, "Password is required" unless Config.password
|
14
|
+
@connection = RestClient::Resource.new(Config.url, :headers => {
|
15
|
+
:accept => Config.content_type,
|
16
|
+
:content_type => Config.content_type,
|
17
|
+
:api_version => Config.api_version,
|
18
|
+
:api_appid => Config.app_id,
|
19
|
+
:api_username => Config.username,
|
20
|
+
:api_password => Config.password
|
21
|
+
})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Clears the connection object from memory. This will force a reload the next time it's accessed.
|
26
|
+
# Because nothing is directly cached within the client, the only likely reason to do this is if
|
27
|
+
# the username and password are changed. Also resets the account subresource.
|
28
|
+
def self.reset_connection!
|
29
|
+
reset_account!
|
30
|
+
@connection = nil
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# Thrown when a configuration value isn't provided or is invalid.
|
3
|
+
class ConfigError < StandardError; end
|
4
|
+
|
5
|
+
# Thrown when a resource calls save! and fails. Contains the +.errors+ array from
|
6
|
+
# the resource.
|
7
|
+
class RecordNotSaved < StandardError
|
8
|
+
attr_reader :errors
|
9
|
+
|
10
|
+
def initialize(errors = [])
|
11
|
+
@errors = errors
|
12
|
+
end
|
13
|
+
|
14
|
+
def message
|
15
|
+
errors.first
|
16
|
+
end
|
17
|
+
alias_method :error, :message
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
require 'activesupport'
|
2
|
+
require 'uri'
|
3
|
+
|
4
|
+
module ActsAsIcontact
|
5
|
+
# Base class for shared functionality between iContact resources. Supports getting, finding, saving,
|
6
|
+
# all that fun stuff.
|
7
|
+
class Resource
|
8
|
+
|
9
|
+
# Creates a new resource object from a values hash. (Which is passed to us via the magic of JSON.)
|
10
|
+
def initialize(properties={})
|
11
|
+
@properties = properties
|
12
|
+
@new_record = !@properties.has_key?(self.class.primary_key)
|
13
|
+
# Initialize other useful attributes
|
14
|
+
@errors = []
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns the primary key ID for an existing resource. Returns nil if the resource is a new record.
|
19
|
+
def id
|
20
|
+
@properties[self.class.primary_key].to_i unless new_record?
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the specific RestClient connection for an existing resource. (E.g., the connection
|
24
|
+
# to "http://api.icontact.com/icp/a/12345" for account 12345.) Returns nil if the resource
|
25
|
+
# is a new record.
|
26
|
+
def connection
|
27
|
+
self.class.connection[id] unless new_record?
|
28
|
+
end
|
29
|
+
|
30
|
+
# Enables keys from the iContact resource to act as attribute methods.
|
31
|
+
def method_missing(method, *params)
|
32
|
+
property = method.to_s
|
33
|
+
if property =~ /(.*)=$/ # It's a value assignment
|
34
|
+
@newvalues ||= []
|
35
|
+
@newvalues << $1
|
36
|
+
@properties[$1] = params[0]
|
37
|
+
else
|
38
|
+
if @properties.has_key?(property)
|
39
|
+
@properties[property]
|
40
|
+
else
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Returns true if the resource object did not originate from iContact. We determine this
|
47
|
+
# by the rather naive method of checking upon creation whether one of the properties passed
|
48
|
+
# was the primary key.
|
49
|
+
def new_record?
|
50
|
+
@new_record
|
51
|
+
end
|
52
|
+
|
53
|
+
# Sends changes to iContact. Returns true if the save was successful (i.e. we receive
|
54
|
+
# an updated object back from them); if it was not, returns false and populates the
|
55
|
+
# +errors+ array with the warnings iContact sends to us. If iContact returns an HTTP
|
56
|
+
# error, raises an exception with it.
|
57
|
+
def save
|
58
|
+
if new_record?
|
59
|
+
result_type = self.class.collection_name
|
60
|
+
payload = {self.class.collection_name => [create_fields]}
|
61
|
+
response = self.class.connection.post(payload.to_json)
|
62
|
+
else
|
63
|
+
result_type = self.class.resource_name
|
64
|
+
response = connection.post(update_fields.to_json)
|
65
|
+
end
|
66
|
+
parsed = JSON.parse(response)
|
67
|
+
if parsed[result_type].empty?
|
68
|
+
@errors = parsed["warnings"]
|
69
|
+
false
|
70
|
+
else
|
71
|
+
@properties = (new_record? ? parsed[result_type].first : parsed[result_type])
|
72
|
+
@new_record = false
|
73
|
+
@errors = []
|
74
|
+
true
|
75
|
+
end
|
76
|
+
rescue RestClient::RequestFailed => e
|
77
|
+
response = e.response.body
|
78
|
+
parsed = JSON.parse(response)
|
79
|
+
@errors = parsed["errors"] || [e.message]
|
80
|
+
false
|
81
|
+
end
|
82
|
+
|
83
|
+
# Like +save+, but raises an ActsAsIcontact::RecordNotSaved exception if the save
|
84
|
+
# failed. The exception message contains the first error from iContact.
|
85
|
+
def save!
|
86
|
+
save or raise ActsAsIcontact::RecordNotSaved.new(errors)
|
87
|
+
end
|
88
|
+
|
89
|
+
# The first message from the +errors+ array.
|
90
|
+
def error
|
91
|
+
errors.first
|
92
|
+
end
|
93
|
+
|
94
|
+
# The warning messages sent back by iContact on a failed request.
|
95
|
+
def errors
|
96
|
+
@errors
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns an array of resources starting at the base.
|
100
|
+
def self.find(type, options={})
|
101
|
+
uri_extension = uri_component + build_query(options)
|
102
|
+
response = base[uri_extension].get
|
103
|
+
parsed = JSON.parse(response)
|
104
|
+
case type
|
105
|
+
when :first then
|
106
|
+
self.new(parsed[collection_name].first) if parsed[collection_name]
|
107
|
+
when :all then
|
108
|
+
ResourceCollection.new(self, parsed)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
# Returns an array of resources starting at the base.
|
113
|
+
def self.all
|
114
|
+
find(:all)
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns the first account associated with this username.
|
118
|
+
def self.first
|
119
|
+
find(:first)
|
120
|
+
end
|
121
|
+
|
122
|
+
protected
|
123
|
+
# The minimum set of fields that must be sent back to iContact on an update.
|
124
|
+
# Includes any fields that changed or were added, the primary key, and anything
|
125
|
+
# else from the "required_on_update" set from the class definition. It excludes
|
126
|
+
# anything from the "never_on_update" set.
|
127
|
+
def update_fields
|
128
|
+
fieldlist = self.class.required_on_update + @newvalues.to_a - self.class.never_on_update
|
129
|
+
@properties.select{|key, value| fieldlist.include?(key)}
|
130
|
+
end
|
131
|
+
|
132
|
+
# The minimum set of fields that must be sent back to iContact on a create.
|
133
|
+
# Includes any fields that were added and anything
|
134
|
+
# else from the "required_on_create" set from the class definition. It excludes
|
135
|
+
# anything from the "never_on_create" set.
|
136
|
+
def create_fields
|
137
|
+
self.class.required_on_create.each{|key| @properties[key] ||= ""} # Add required fields
|
138
|
+
self.class.never_on_create.each{|key| @properties.delete(key)} # Remove prohibited fields
|
139
|
+
@properties
|
140
|
+
end
|
141
|
+
|
142
|
+
# The base RestClient resource that this particular class nests from. Starts with
|
143
|
+
# the resource connection at 'https://api.icontact.com/icp/' and works its way up.
|
144
|
+
def self.base
|
145
|
+
ActsAsIcontact.connection
|
146
|
+
end
|
147
|
+
|
148
|
+
# The name of the singular resource type pulled from iContact. Defaults to the lowercase
|
149
|
+
# version of the class name.
|
150
|
+
def self.resource_name
|
151
|
+
name.demodulize.downcase
|
152
|
+
end
|
153
|
+
|
154
|
+
# The name of the resource collection pulled from iContact. Defaults to the lowercase
|
155
|
+
# pluralized version of the class name.
|
156
|
+
def self.collection_name
|
157
|
+
resource_name.pluralize
|
158
|
+
end
|
159
|
+
|
160
|
+
# The URI component name corresponding to this resource type. In many cases it's the same as the
|
161
|
+
# collection name; exceptions include accounts ('a') and clientFolders ('c').
|
162
|
+
def self.uri_component
|
163
|
+
collection_name
|
164
|
+
end
|
165
|
+
|
166
|
+
# The RestClient resource object for this resource class. Its own find/update methods
|
167
|
+
# will call on this, and singular objects will derive from it.
|
168
|
+
def self.connection
|
169
|
+
base[uri_component]
|
170
|
+
end
|
171
|
+
|
172
|
+
# The primary key field for this resource. Used on updates.
|
173
|
+
def self.primary_key
|
174
|
+
resource_name + "Id"
|
175
|
+
end
|
176
|
+
|
177
|
+
# Fields that _must_ be included for this resource upon creation.
|
178
|
+
def self.required_on_create
|
179
|
+
[]
|
180
|
+
end
|
181
|
+
|
182
|
+
# Fields that _must_ be included for this resource upon updating.
|
183
|
+
def self.required_on_update
|
184
|
+
[primary_key]
|
185
|
+
end
|
186
|
+
|
187
|
+
# Fields that _cannot_ be included for this resource upon creation.
|
188
|
+
def self.never_on_create
|
189
|
+
[primary_key]
|
190
|
+
end
|
191
|
+
|
192
|
+
# Fields that _cannot_ be included for this resource upon updating.
|
193
|
+
def self.never_on_update
|
194
|
+
[]
|
195
|
+
end
|
196
|
+
|
197
|
+
private
|
198
|
+
def self.build_query(options={})
|
199
|
+
return "" if options.empty?
|
200
|
+
terms = options.collect{|k,v| "#{k}=#{URI.escape(v.to_s)}"}
|
201
|
+
build = "?" + terms.join('&')
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
class ResourceCollection < Enumerator
|
3
|
+
attr_reader :total
|
4
|
+
|
5
|
+
def initialize(klass, collection)
|
6
|
+
@klass = klass
|
7
|
+
@collection = collection[klass.collection_name]
|
8
|
+
# Get number of elements
|
9
|
+
@total = @collection.size
|
10
|
+
|
11
|
+
enumcode = Proc.new do |yielder|
|
12
|
+
counter = 0
|
13
|
+
while counter < @total
|
14
|
+
yielder.yield klass.new(@collection[counter])
|
15
|
+
counter += 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
super(&enumcode)
|
20
|
+
end
|
21
|
+
|
22
|
+
def [](index)
|
23
|
+
@klass.new(@collection[index]) if @collection[index]
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# The top-level Accounts resource from iContact. Currently only supports retrieval -- and is
|
3
|
+
# highly targeted toward the _first_ account, since that seems to be the dominant use case.
|
4
|
+
class Account < Resource
|
5
|
+
def self.uri_component
|
6
|
+
'a'
|
7
|
+
end
|
8
|
+
|
9
|
+
# Accounts can't pass back a userName or password on updating
|
10
|
+
def self.never_on_update
|
11
|
+
['userName','password']
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# The accountId retrieved from iContact. Can also be set manually for performance optimization,
|
16
|
+
# but remembers it so that it won't be pulled more than once anyway.
|
17
|
+
def self.account_id
|
18
|
+
@account_id ||= Account.first.accountId.to_i
|
19
|
+
end
|
20
|
+
|
21
|
+
# Manually sets the accountId used in subsequent calls. Setting this in your initializer will save
|
22
|
+
# at least one unnecessary request to the iContact server.
|
23
|
+
def self.account_id=(val)
|
24
|
+
@account_id = val
|
25
|
+
end
|
26
|
+
|
27
|
+
# RestClient subresource scoped to the specific account ID. Most other iContact calls will derive
|
28
|
+
# from this one.
|
29
|
+
def self.account
|
30
|
+
@account ||= connection["a/#{account_id}"]
|
31
|
+
end
|
32
|
+
|
33
|
+
# Clears the account resource from memory. Called by reset_connection! since the only likely reason
|
34
|
+
# to do this is connecting as a different user.
|
35
|
+
def self.reset_account!
|
36
|
+
@account = nil
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module ActsAsIcontact
|
2
|
+
# The nested Client Folder resource from iContact. Currently only supports retrieval -- and is
|
3
|
+
# highly targeted toward the _first_ client folder, since that seems to be the dominant use case.
|
4
|
+
class Client < Resource
|
5
|
+
def self.resource_name
|
6
|
+
'clientfolder'
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.collection_name
|
10
|
+
'clientfolders'
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.uri_component
|
14
|
+
'c'
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.base
|
18
|
+
ActsAsIcontact.account
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# The clientFolderId retrieved from iContact. Can also be set manually for performance
|
23
|
+
# optimization, but remembers it so that it won't be pulled more than once anyway.
|
24
|
+
def self.client_id
|
25
|
+
@client_id ||= Client.first.clientFolderId.to_i
|
26
|
+
end
|
27
|
+
|
28
|
+
# Manually sets the clientFolderId used in subsequent calls. Setting this in your
|
29
|
+
# initializer will save at least one unnecessary request to the iContact server.
|
30
|
+
def self.client_id=(val)
|
31
|
+
@client_id = val
|
32
|
+
end
|
33
|
+
|
34
|
+
# RestClient subresource scoped to the specific account ID. Most other iContact calls will derive
|
35
|
+
# from this one.
|
36
|
+
def self.client
|
37
|
+
@client ||= account["c/#{client_id}"]
|
38
|
+
end
|
39
|
+
|
40
|
+
# Clears the account resource from memory. Called by reset_connection! since the only likely reason
|
41
|
+
# to do this is connecting as a different user.
|
42
|
+
def self.reset_client!
|
43
|
+
@client = nil
|
44
|
+
end
|
45
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Configuration" do
|
4
|
+
Rails = "dummy"
|
5
|
+
Rack = "dummy"
|
6
|
+
before(:all) do
|
7
|
+
# Copy our configuration to a safe place, then wipe it
|
8
|
+
@old_config = {}
|
9
|
+
ActsAsIcontact::Config.instance_variables.each do |v|
|
10
|
+
@old_config[v] = ActsAsIcontact::Config.instance_variable_get(v)
|
11
|
+
ActsAsIcontact::Config.instance_variable_set(v,nil)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "mode" do
|
16
|
+
before(:all) do
|
17
|
+
@old_mode = ENV["ICONTACT_MODE"]
|
18
|
+
ENV["ICONTACT_MODE"] = nil
|
19
|
+
end
|
20
|
+
it "defaults to production if nothing else is set" do
|
21
|
+
ActsAsIcontact::Config.mode.should == :production
|
22
|
+
end
|
23
|
+
|
24
|
+
it "can set the mode attribute manually" do
|
25
|
+
ActsAsIcontact::Config.mode = :foo
|
26
|
+
ActsAsIcontact::Config.mode.should == :foo
|
27
|
+
end
|
28
|
+
|
29
|
+
it "reads the ICONTACT_MODE environment variable" do
|
30
|
+
ENV["ICONTACT_MODE"] = 'bar'
|
31
|
+
ActsAsIcontact::Config.mode.should == :bar
|
32
|
+
ENV["ICONTACT_MODE"] = @old_mode
|
33
|
+
end
|
34
|
+
|
35
|
+
context "within a Rails application" do
|
36
|
+
before(:all) do
|
37
|
+
@old_rails_env = ENV["RAILS_ENV"]
|
38
|
+
end
|
39
|
+
|
40
|
+
before(:each) do
|
41
|
+
Object.expects(:const_defined?).with(:Rails).returns(true)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "is beta if RAILS_ENV is not production" do
|
45
|
+
ENV["RAILS_ENV"] = 'staging'
|
46
|
+
ActsAsIcontact::Config.mode.should == :beta
|
47
|
+
end
|
48
|
+
|
49
|
+
it "is production if RAILS_ENV is production" do
|
50
|
+
ENV["RAILS_ENV"] = 'production'
|
51
|
+
ActsAsIcontact::Config.mode.should == :production
|
52
|
+
end
|
53
|
+
|
54
|
+
after(:all) do
|
55
|
+
ENV["RAILS_ENV"] = @old_rails_env
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context "within a Rack environment" do
|
60
|
+
before(:all) do
|
61
|
+
@old_rack_env = ENV["RACK_ENV"]
|
62
|
+
end
|
63
|
+
before(:each) do
|
64
|
+
Object.expects(:const_defined?).with(:Rails).returns(false)
|
65
|
+
Object.expects(:const_defined?).with(:Rack).returns(true)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "is beta if RACK_ENV is not production" do
|
69
|
+
ENV["RACK_ENV"] = 'staging'
|
70
|
+
ActsAsIcontact::Config.mode.should == :beta
|
71
|
+
end
|
72
|
+
|
73
|
+
it "is production if RACK_ENV is production" do
|
74
|
+
ENV["RACK_ENV"] = 'production'
|
75
|
+
ActsAsIcontact::Config.mode.should == :production
|
76
|
+
end
|
77
|
+
|
78
|
+
after(:all) do
|
79
|
+
ENV["RACK_ENV"] = @old_rack_env
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
context ":beta" do
|
85
|
+
before(:each) do
|
86
|
+
ActsAsIcontact::Config.mode = :beta
|
87
|
+
end
|
88
|
+
|
89
|
+
it "returns the beta AppId" do
|
90
|
+
ActsAsIcontact::Config.app_id.should == "Ml5SnuFhnoOsuZeTOuZQnLUHTbzeUyhx"
|
91
|
+
end
|
92
|
+
|
93
|
+
it "returns the beta URL" do
|
94
|
+
ActsAsIcontact::Config.url.should == "https://app.beta.icontact.com/icp/"
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
context ":production" do
|
100
|
+
before(:each) do
|
101
|
+
ActsAsIcontact::Config.mode = :production
|
102
|
+
end
|
103
|
+
|
104
|
+
it "returns the production AppId" do
|
105
|
+
ActsAsIcontact::Config.app_id.should == "IYDOhgaZGUKNjih3hl1ItLln7zpAtWN2"
|
106
|
+
end
|
107
|
+
|
108
|
+
it "returns the production URL" do
|
109
|
+
ActsAsIcontact::Config.url.should == "https://app.icontact.com/icp/"
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
after(:each) do
|
115
|
+
ActsAsIcontact::Config.mode = nil
|
116
|
+
ENV["ICONTACT_MODE"] = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
after(:all) do
|
120
|
+
ENV["ICONTACT_MODE"] = @old_mode
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
it "knows it's version 2.0" do
|
126
|
+
ActsAsIcontact::Config.api_version.should == 2.0
|
127
|
+
end
|
128
|
+
|
129
|
+
it "can set its URL base" do
|
130
|
+
ActsAsIcontact::Config.url = "https://blah.example.com/foo/bar/"
|
131
|
+
ActsAsIcontact::Config.url.should == "https://blah.example.com/foo/bar/"
|
132
|
+
end
|
133
|
+
|
134
|
+
it "knows its content type" do
|
135
|
+
ActsAsIcontact::Config.content_type.should == "application/json"
|
136
|
+
end
|
137
|
+
|
138
|
+
it "can set its content type to XML" do
|
139
|
+
ActsAsIcontact::Config.content_type = "text/xml"
|
140
|
+
ActsAsIcontact::Config.content_type.should == "text/xml"
|
141
|
+
end
|
142
|
+
|
143
|
+
it "throws an error if the content type is anything other than JSON or XML" do
|
144
|
+
lambda{ActsAsIcontact::Config.content_type = "text/plain"}.should raise_error(ActsAsIcontact::ConfigError, "Content Type must be application/json or text/xml")
|
145
|
+
end
|
146
|
+
|
147
|
+
it "knows the username you give it" do
|
148
|
+
ActsAsIcontact::Config.username = "johndoe"
|
149
|
+
ActsAsIcontact::Config.username.should == "johndoe"
|
150
|
+
end
|
151
|
+
|
152
|
+
it "gets the username from an environment variable if not supplied" do
|
153
|
+
old_env = ENV['ICONTACT_USERNAME']
|
154
|
+
ENV['ICONTACT_USERNAME'] = "bobdoe"
|
155
|
+
ActsAsIcontact::Config.username.should == "bobdoe"
|
156
|
+
# Set our environment back to the way we like it
|
157
|
+
ENV['ICONTACT_USERNAME'] = old_env if old_env
|
158
|
+
end
|
159
|
+
|
160
|
+
it "knows the password you give it" do
|
161
|
+
ActsAsIcontact::Config.password = "foobar"
|
162
|
+
ActsAsIcontact::Config.password.should == "foobar"
|
163
|
+
end
|
164
|
+
|
165
|
+
it "gets the username from an environment variable if not supplied" do
|
166
|
+
old_env = ENV['ICONTACT_PASSWORD']
|
167
|
+
ENV['ICONTACT_PASSWORD'] = "hoohar"
|
168
|
+
ActsAsIcontact::Config.password.should == "hoohar"
|
169
|
+
ENV['ICONTACT_PASSWORD'] = old_env if old_env
|
170
|
+
end
|
171
|
+
|
172
|
+
after(:each) do
|
173
|
+
# Clear any variables we might have set
|
174
|
+
ActsAsIcontact::Config.instance_variables.each{|v| ActsAsIcontact::Config.instance_variable_set(v,nil)}
|
175
|
+
end
|
176
|
+
|
177
|
+
after(:all) do
|
178
|
+
# Restore our saved configuration
|
179
|
+
@old_config.each_pair {|k, v| ActsAsIcontact::Config.instance_variable_set(k,v)}
|
180
|
+
end
|
181
|
+
end
|