monkey_wrench 0.1.0 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.mdown +6 -1
- data/Rakefile +14 -3
- data/lib/monkey_wrench.rb +0 -0
- data/lib/monkey_wrench/base.rb +47 -11
- data/lib/monkey_wrench/campaign.rb +0 -0
- data/lib/monkey_wrench/campaign_aim.rb +0 -0
- data/lib/monkey_wrench/campaign_stats.rb +0 -0
- data/lib/monkey_wrench/config.rb +2 -1
- data/lib/monkey_wrench/hash.rb +4 -4
- data/lib/monkey_wrench/helper.rb +0 -0
- data/lib/monkey_wrench/list.rb +35 -11
- data/lib/monkey_wrench/security.rb +0 -0
- data/test/fixtures/api_fail.json +0 -0
- data/test/fixtures/campaigns_success.json +0 -0
- data/test/fixtures/listBatchSubscribe1000_success.json +1 -0
- data/test/fixtures/listBatchSubscribe4_success.json +1 -0
- data/test/fixtures/listMemberInfo_success.json +1 -1
- data/test/fixtures/lists_success.json +0 -0
- data/test/monkey_wrench/base_test.rb +55 -0
- data/test/monkey_wrench/campaign_aim_test.rb +0 -0
- data/test/monkey_wrench/campaign_stats_test.rb +0 -0
- data/test/monkey_wrench/campaign_test.rb +0 -0
- data/test/monkey_wrench/hash_test.rb +11 -1
- data/test/monkey_wrench/helper_test.rb +0 -0
- data/test/monkey_wrench/list_test.rb +72 -70
- data/test/monkey_wrench/security_test.rb +0 -0
- data/test/test_helper.rb +35 -35
- metadata +46 -16
data/README.mdown
CHANGED
@@ -15,4 +15,9 @@ From there you've got a rich API for managing Lists and Members. To subscribe a
|
|
15
15
|
|
16
16
|
## Further Reading
|
17
17
|
|
18
|
-
For more information, [check the documentation](http://rdoc.info/projects/rubypond/monkeywrench)
|
18
|
+
For more information, [check the documentation](http://rdoc.info/projects/rubypond/monkeywrench)
|
19
|
+
|
20
|
+
## Credits & Contributions
|
21
|
+
|
22
|
+
* [David Heath](http://davidheath.org/)
|
23
|
+
* [Maxime Guilbot](http://github.com/maxime)
|
data/Rakefile
CHANGED
@@ -1,11 +1,22 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'rake'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
|
6
|
+
spec_data = File.open('monkey_wrench.gemspec').read
|
7
|
+
spec = nil
|
8
|
+
Thread.new do
|
9
|
+
spec = eval("#{spec_data}")
|
10
|
+
end.join
|
11
|
+
|
12
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
13
|
+
pkg.need_zip = false
|
14
|
+
pkg.need_tar = false
|
15
|
+
end
|
3
16
|
|
4
17
|
require 'rake/testtask'
|
5
18
|
Rake::TestTask.new(:test) do |test|
|
6
19
|
test.libs << 'lib' << 'test'
|
7
20
|
test.pattern = 'test/**/*_test.rb'
|
8
21
|
test.verbose = false
|
9
|
-
end
|
10
|
-
|
11
|
-
task :default => :test
|
22
|
+
end
|
data/lib/monkey_wrench.rb
CHANGED
File without changes
|
data/lib/monkey_wrench/base.rb
CHANGED
@@ -10,9 +10,10 @@ module MonkeyWrench
|
|
10
10
|
|
11
11
|
@@apikey = nil
|
12
12
|
@@datacenter = nil
|
13
|
+
@@dryrun = false
|
13
14
|
|
14
15
|
class << self
|
15
|
-
def
|
16
|
+
def default_query_params
|
16
17
|
{ :output => "json", :apikey=> @@apikey}
|
17
18
|
end
|
18
19
|
|
@@ -20,14 +21,34 @@ module MonkeyWrench
|
|
20
21
|
"http://#{datacenter}.api.mailchimp.com/1.2/"
|
21
22
|
end
|
22
23
|
|
23
|
-
def
|
24
|
-
|
25
|
-
|
24
|
+
def default_retry_limit
|
25
|
+
3
|
26
|
+
end
|
27
|
+
|
28
|
+
def get(params, http_options = {})
|
29
|
+
if @@dryrun
|
30
|
+
puts "GET #{base_uri} #{params.merge(default_query_params).inspect}"
|
31
|
+
return {}
|
32
|
+
else
|
33
|
+
robustly(http_options) do
|
34
|
+
response = super(base_uri, http_options.merge(:query => params.merge(default_query_params)))
|
35
|
+
handle_errors(response.parsed_response)
|
36
|
+
end
|
37
|
+
end
|
26
38
|
end
|
27
39
|
|
28
|
-
def post(params)
|
29
|
-
|
30
|
-
|
40
|
+
def post(params, http_options = {})
|
41
|
+
if @@dryrun
|
42
|
+
puts "POST #{base_uri} #{params.merge(default_query_params).inspect}"
|
43
|
+
return {}
|
44
|
+
else
|
45
|
+
robustly(http_options) do
|
46
|
+
post_params = params.dup
|
47
|
+
get_params = default_query_params.merge(:method => post_params.delete(:method))
|
48
|
+
response = super(base_uri, http_options.merge(:body => post_params, :query => get_params))
|
49
|
+
handle_errors(response.parsed_response)
|
50
|
+
end
|
51
|
+
end
|
31
52
|
end
|
32
53
|
|
33
54
|
def handle_errors(objects)
|
@@ -55,12 +76,27 @@ module MonkeyWrench
|
|
55
76
|
end
|
56
77
|
|
57
78
|
private
|
58
|
-
def
|
59
|
-
|
79
|
+
def self.robustly(http_options, &block)
|
80
|
+
retry_limit = http_options[:retry_limit] || default_retry_limit
|
81
|
+
attempts = 0
|
82
|
+
while attempts < retry_limit
|
83
|
+
begin
|
84
|
+
attempts += 1
|
85
|
+
return yield
|
86
|
+
rescue Timeout::Error => e
|
87
|
+
if attempts == retry_limit
|
88
|
+
raise e
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def get(*args)
|
95
|
+
self.class.get(*args)
|
60
96
|
end
|
61
97
|
|
62
|
-
def post(
|
63
|
-
self.class.post(
|
98
|
+
def post(*args)
|
99
|
+
self.class.post(*args)
|
64
100
|
end
|
65
101
|
|
66
102
|
end
|
File without changes
|
File without changes
|
File without changes
|
data/lib/monkey_wrench/config.rb
CHANGED
data/lib/monkey_wrench/hash.rb
CHANGED
@@ -21,7 +21,7 @@ module MonkeyWrench
|
|
21
21
|
def escape_keys!
|
22
22
|
collect_kv!{|k,v| [CGI.escape(k.to_s), v]}
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
def to_mailchimp(index = nil, parent_name = nil)
|
26
26
|
result = self.collect_kv do |k,v|
|
27
27
|
if v.is_a?(Array) && v.first.is_a?(Hash)
|
@@ -35,7 +35,7 @@ module MonkeyWrench
|
|
35
35
|
if parent_name
|
36
36
|
v = v.collect_kv do |key,val|
|
37
37
|
keyname = CGI.escape("#{parent_name.to_s}[#{key.to_s.upcase}]")
|
38
|
-
[keyname, val]
|
38
|
+
[keyname, val.to_s]
|
39
39
|
end
|
40
40
|
else
|
41
41
|
v = { k => v }.to_mailchimp(nil, k)
|
@@ -45,7 +45,7 @@ module MonkeyWrench
|
|
45
45
|
i = 0
|
46
46
|
v.each do |val|
|
47
47
|
keyname = CGI.escape("#{k}[#{i}]")
|
48
|
-
results[keyname] = val
|
48
|
+
results[keyname] = val.to_s
|
49
49
|
i += 1
|
50
50
|
end
|
51
51
|
v = results
|
@@ -66,4 +66,4 @@ end
|
|
66
66
|
|
67
67
|
class Hash
|
68
68
|
include MonkeyWrench::Hash
|
69
|
-
end
|
69
|
+
end
|
data/lib/monkey_wrench/helper.rb
CHANGED
File without changes
|
data/lib/monkey_wrench/list.rb
CHANGED
@@ -2,7 +2,6 @@ require 'cgi'
|
|
2
2
|
|
3
3
|
module MonkeyWrench
|
4
4
|
class List < MonkeyWrench::Base
|
5
|
-
|
6
5
|
# Finds a given list by name
|
7
6
|
#
|
8
7
|
# @example
|
@@ -13,6 +12,14 @@ module MonkeyWrench
|
|
13
12
|
def self.find_by_name(list_name)
|
14
13
|
lists = find_all.detect{|list| list.name == list_name}
|
15
14
|
end
|
15
|
+
|
16
|
+
def ==(other_list)
|
17
|
+
other_list.is_a?(self.class) && self.id == other_list.id
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.find(id)
|
21
|
+
new(:id => id)
|
22
|
+
end
|
16
23
|
|
17
24
|
# Will compare another list against the current one and return true if
|
18
25
|
# they are the same (based on list ID)
|
@@ -47,10 +54,11 @@ module MonkeyWrench
|
|
47
54
|
#
|
48
55
|
# @return [Array<MonkeyWrench::List>]
|
49
56
|
def self.find_all
|
50
|
-
lists
|
57
|
+
@@lists ||= post({ :method => "lists" }).map do |list|
|
51
58
|
List.new(list)
|
52
59
|
end
|
53
60
|
end
|
61
|
+
|
54
62
|
class << self
|
55
63
|
alias :all :find_all
|
56
64
|
end
|
@@ -188,7 +196,7 @@ module MonkeyWrench
|
|
188
196
|
opts = opts.merge(contact_details)
|
189
197
|
else
|
190
198
|
email_address = contact_details
|
191
|
-
end
|
199
|
+
end
|
192
200
|
subscribe_one(email_address, opts)
|
193
201
|
return { :success => 1, :errors => []}
|
194
202
|
end
|
@@ -255,14 +263,25 @@ module MonkeyWrench
|
|
255
263
|
end
|
256
264
|
end
|
257
265
|
|
258
|
-
def
|
259
|
-
|
266
|
+
def batch_size
|
267
|
+
1000
|
268
|
+
end
|
269
|
+
|
270
|
+
def each_batch(subscribers, batch_size, &block)
|
260
271
|
i = 0
|
261
272
|
while i < subscribers.size
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
273
|
+
start = Time.now
|
274
|
+
yield subscribers[i..(i+batch_size-1)], i
|
275
|
+
i += batch_size
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
279
|
+
def subscribe_in_batches(subscribers, opts)
|
280
|
+
cumulative_response = { :success => 0, :errors => [] }
|
281
|
+
each_batch(subscribers, batch_size) do |batch, i|
|
282
|
+
response = subscribe_one_batch(batch, opts)
|
283
|
+
cumulative_response[:success] += (response["success_count"] || 0)
|
284
|
+
cumulative_response[:errors] += (response["errors"] || [])
|
266
285
|
end
|
267
286
|
cumulative_response
|
268
287
|
end
|
@@ -273,7 +292,12 @@ module MonkeyWrench
|
|
273
292
|
params[:update_existing] = opts[:update_existing] if opts.has_key?(:update_existing)
|
274
293
|
params[:replace_interests] = opts[:replace_interests] if opts.has_key?(:replace_interests)
|
275
294
|
params.merge!({ :batch => subscribers }.to_mailchimp)
|
276
|
-
post(params)
|
295
|
+
post(params, :timeout => timeout_for_batch(subscribers))
|
296
|
+
end
|
297
|
+
|
298
|
+
def timeout_for_batch(batch)
|
299
|
+
# 5 mins for a batch of 1000
|
300
|
+
((batch.size.to_f / 1000) * (5 * 60)).to_i
|
277
301
|
end
|
278
302
|
|
279
303
|
def subscribe_one_at_a_time(subscribers, opts)
|
@@ -297,7 +321,7 @@ module MonkeyWrench
|
|
297
321
|
:update_existing => opts.delete(:update_existing),
|
298
322
|
:replace_interests => opts.delete(:replace_interests),
|
299
323
|
:send_welcome => opts.delete(:send_welcome),
|
300
|
-
:
|
324
|
+
:email_address => email_address
|
301
325
|
}
|
302
326
|
params.reject!{ |k,v| v.nil? }
|
303
327
|
merge_vars = { :merge_vars => opts }.to_mailchimp
|
File without changes
|
data/test/fixtures/api_fail.json
CHANGED
File without changes
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
{"success_count":1000,"error_count":0,"errors":[]}
|
@@ -0,0 +1 @@
|
|
1
|
+
{"success_count":4,"error_count":0,"errors":[]}
|
@@ -1 +1 @@
|
|
1
|
-
{"id":"a58cbece83","email":"david@email.com","email_type":"html","ip_opt":"66.132.220.59","ip_signup":null,"member_rating":4,"merges":{"EMAIL":"david@email.com","MERGE0":"david@email.com","FNAME":"David","MERGE1":"David","LNAME":"Heath","MERGE2":"Heath","EXPIRYDATE":"2008-02-04","MERGE5":"2008-02-04","USERNAME":"Test1","MERGE6":"Test1","DURATION":"1","MERGE3":"1","PRODUCT":"One week subscription","MERGE4":"One week subscription","CURRENCY":"GBP","MERGE7":"GBP","ROLLING":"false","MERGE8":"false","EXPIRED":"true","MERGE9":"true","TRIAL":"","MERGE10":"","MMERGE11":"","MERGE11":"","MMERGE12":"","MERGE12":"","MMERGE13":"","MERGE13":"","MMERGE14":"","MERGE14":"","TRACKER":"","MERGE15":"","SUBSTYPE":"","MERGE16":"","FIRSTEBOOK":"","MERGE17":"","MMERGE18":"","MERGE18":"","INTERESTS":"freetrial, tutorials"},"status":"subscribed","timestamp":"2009-11-16 14:11:57","lists":{"699791bff9":"unsubscribed"}}
|
1
|
+
{"id":"a58cbece83","email":"david@email.com","email_type":"html","ip_opt":"66.132.220.59","ip_signup":null,"member_rating":4,"merges":{"EMAIL":"david@email.com","MERGE0":"david@email.com","FNAME":"David","MERGE1":"David","LNAME":"Heath","MERGE2":"Heath","EXPIRYDATE":"2008-02-04","MERGE5":"2008-02-04","USERNAME":"Test1","MERGE6":"Test1","DURATION":"1","MERGE3":"1","PRODUCT":"One week subscription","MERGE4":"One week subscription","CURRENCY":"GBP","MERGE7":"GBP","ROLLING":"false","MERGE8":"false","EXPIRED":"true","MERGE9":"true","TRIAL":"","MERGE10":"","MMERGE11":"","MERGE11":"","MMERGE12":"","MERGE12":"","MMERGE13":"","MERGE13":"","MMERGE14":"","MERGE14":"","TRACKER":"","MERGE15":"","SUBSTYPE":"","MERGE16":"","FIRSTEBOOK":"","MERGE17":"","MMERGE18":"","MERGE18":"","INTERESTS":"freetrial, tutorials"},"status":"subscribed","timestamp":"2009-11-16 14:11:57","lists":{"699791bff9":"unsubscribed"}}
|
File without changes
|
@@ -0,0 +1,55 @@
|
|
1
|
+
$:.unshift File.expand_path("..", File.dirname(__FILE__))
|
2
|
+
require "test_helper"
|
3
|
+
|
4
|
+
class MonkeyWrench::BaseTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
context "making an HTTP GET" do
|
7
|
+
should "retry if HTTP GET times out" do
|
8
|
+
retries = sequence('retries')
|
9
|
+
response = mock('')
|
10
|
+
response.stubs(:parsed_response).returns("the response")
|
11
|
+
MonkeyWrench::Base.stubs(:base_uri).returns('http://example.com');
|
12
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).raises(Timeout::Error)
|
13
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).raises(Timeout::Error)
|
14
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).returns(response)
|
15
|
+
assert_equal MonkeyWrench::Base.get({}), 'the response'
|
16
|
+
end
|
17
|
+
|
18
|
+
should "rethrow Timeout::Error if retry limit exceeded" do
|
19
|
+
retries = sequence('retries')
|
20
|
+
response = mock('')
|
21
|
+
response.stubs(:parsed_response).returns("the response")
|
22
|
+
MonkeyWrench::Base.stubs(:base_uri).returns('http://example.com');
|
23
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).raises(Timeout::Error)
|
24
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).raises(Timeout::Error)
|
25
|
+
assert_raise Timeout::Error do
|
26
|
+
MonkeyWrench::Base.get({}, :retry_limit => 2)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context "making an HTTP POST" do
|
32
|
+
should "retry if HTTP POST times out" do
|
33
|
+
retries = sequence('retries')
|
34
|
+
response = mock('')
|
35
|
+
response.stubs(:parsed_response).returns("the response")
|
36
|
+
MonkeyWrench::Base.stubs(:base_uri).returns('http://example.com');
|
37
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).raises(Timeout::Error)
|
38
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).raises(Timeout::Error)
|
39
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).returns(response)
|
40
|
+
assert_equal MonkeyWrench::Base.post({}), 'the response'
|
41
|
+
end
|
42
|
+
|
43
|
+
should "rethrow Timeout::Error if retry limit exceeded" do
|
44
|
+
retries = sequence('retries')
|
45
|
+
response = mock('')
|
46
|
+
response.stubs(:parsed_response).returns("the response")
|
47
|
+
MonkeyWrench::Base.stubs(:base_uri).returns('http://example.com');
|
48
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).raises(Timeout::Error)
|
49
|
+
HTTParty::Request.any_instance.expects(:perform).in_sequence(retries).raises(Timeout::Error)
|
50
|
+
assert_raise Timeout::Error do
|
51
|
+
MonkeyWrench::Base.post({}, :retry_limit => 2)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
File without changes
|
File without changes
|
File without changes
|
@@ -43,5 +43,15 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
43
43
|
assert @example_hash.to_mailchimp.keys.include?("vars%5BEMAIL_ADDRESS%5D")
|
44
44
|
assert @example_hash.to_mailchimp.keys.include?("vars%5BTYPE%5D")
|
45
45
|
end
|
46
|
+
|
47
|
+
should "convert symbols to strings" do
|
48
|
+
assert_equal @example_hash.to_mailchimp['vars%5BTYPE%5D'], 'html'
|
49
|
+
end
|
50
|
+
|
51
|
+
should_eventually "recursively convert hashes" do
|
52
|
+
example = { :a => { :b => { :c => 1 }}}
|
53
|
+
expected = {"a%5BV%5D%5BC%5D" => 1}
|
54
|
+
assert_equal expected, example.to_mailchimp
|
55
|
+
end
|
46
56
|
end
|
47
|
-
end
|
57
|
+
end
|
File without changes
|
@@ -7,14 +7,15 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
7
7
|
setup_config
|
8
8
|
mock_chimp_post(:lists)
|
9
9
|
@list = MonkeyWrench::List.find_by_name("A test list")
|
10
|
-
clear_fakeweb
|
11
10
|
end
|
12
11
|
|
13
12
|
context "multiple subscribers at once" do
|
14
13
|
should "subscribe users" do
|
15
|
-
form_params = {
|
16
|
-
|
17
|
-
|
14
|
+
form_params = {
|
15
|
+
:batch => [{'EMAIL' => "mail@chimp.com",
|
16
|
+
'TYPE' => "html"
|
17
|
+
}],
|
18
|
+
:id => "my-list-id"}
|
18
19
|
mock_chimp_post(:listBatchSubscribe, form_params)
|
19
20
|
|
20
21
|
subscribers = [{:email => "mail@chimp.com", :type => :html}]
|
@@ -22,34 +23,23 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
22
23
|
assert_equal expected, @list.subscribe(subscribers)
|
23
24
|
end
|
24
25
|
|
25
|
-
should "split more than
|
26
|
-
|
27
|
-
|
28
|
-
10.times do |i|
|
29
|
-
first_batch["batch[#{i}][EMAIL]"] = "mail#{i}@chimp.com"
|
30
|
-
first_batch["batch[#{i}][TYPE]"] = "html"
|
31
|
-
subscribers << {:email => "mail#{i}@chimp.com", :type => :html}
|
32
|
-
end
|
33
|
-
mock_chimp_post(:listBatchSubscribe, first_batch,
|
34
|
-
true, 'listBatchSubscribe10')
|
35
|
-
|
36
|
-
second_batch = {:id => "my-list-id"}
|
37
|
-
5.times do |i|
|
38
|
-
second_batch["batch[#{i}][EMAIL]"] = "mail1#{i}@chimp.com"
|
39
|
-
second_batch["batch[#{i}][TYPE]"] = "html"
|
40
|
-
subscribers << {:email => "mail1#{i}@chimp.com", :type => :html}
|
26
|
+
should "split more than one thousand subscribers into batches" do
|
27
|
+
subscribers = (1..1004).map do |i|
|
28
|
+
{:email => "mail#{i}@chimp.com", :type => :html}
|
41
29
|
end
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
30
|
+
response_sequence = [
|
31
|
+
{:body => canned_response('listBatchSubscribe1000_success.json'), :headers => {'Content-Type' => 'application/json'}},
|
32
|
+
{:body => canned_response('listBatchSubscribe4_success.json'), :headers => {'Content-Type' => 'application/json'}}
|
33
|
+
]
|
34
|
+
stub_request(:post, uri_for_remote_method('listBatchSubscribe')).to_return(response_sequence)
|
35
|
+
expected = {:success => 1004, :errors => []}
|
46
36
|
assert_equal expected, @list.subscribe(subscribers)
|
47
37
|
end
|
48
38
|
|
49
39
|
should "send welcome email" do
|
50
|
-
form_params = {"
|
51
|
-
:
|
52
|
-
:send_welcome => true}
|
40
|
+
form_params = {:merge_vars => {"FOO" => "bar"}, :id => "my-list-id",
|
41
|
+
:email_address => "mail@chimp.com", :type => "html",
|
42
|
+
:send_welcome => "true"}
|
53
43
|
mock_chimp_post(:listSubscribe, form_params)
|
54
44
|
|
55
45
|
subscribers = [{:email => "mail@chimp.com", :type => :html, :foo => "bar"}]
|
@@ -62,10 +52,10 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
62
52
|
|
63
53
|
should "collate errors" do
|
64
54
|
form_params = {
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
55
|
+
:batch => [
|
56
|
+
{'EMAIL' => "mail@chimp.com", 'TYPE' => 'html'},
|
57
|
+
{'EMAIL' => "bademail@badmail", 'TYPE' => 'html'}
|
58
|
+
],
|
69
59
|
:id => "my-list-id"}
|
70
60
|
mock_chimp_post(:listBatchSubscribe, form_params, true, 'listBatchSubscribe_with_error')
|
71
61
|
|
@@ -84,15 +74,14 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
84
74
|
|
85
75
|
context "a single subscriber" do
|
86
76
|
should "subsbscibe a user" do
|
87
|
-
form_params = { :type
|
88
|
-
:update_existing=>true,
|
89
|
-
|
90
|
-
:replace_interests=>false,
|
91
|
-
:double_optin=>false,
|
92
|
-
"merge_vars[FNAME]"=>"Joe",
|
77
|
+
form_params = { :type=> "html",
|
78
|
+
:update_existing => "true",
|
79
|
+
:merge_vars => {'MY_DATE'=>"20090101", 'FNAME' => 'Joe'},
|
80
|
+
:replace_interests => "false",
|
81
|
+
:double_optin => "false",
|
93
82
|
:id => "my-list-id",
|
94
|
-
:send_welcome=>true,
|
95
|
-
:
|
83
|
+
:send_welcome => "true",
|
84
|
+
:email_address => "mail@chimp.com" }
|
96
85
|
mock_chimp_post(:listSubscribe, form_params)
|
97
86
|
|
98
87
|
params = { :type => :html,
|
@@ -119,7 +108,7 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
119
108
|
|
120
109
|
context "multiple subscribers at once" do
|
121
110
|
should "unsubscribe" do
|
122
|
-
form_params = {"emails
|
111
|
+
form_params = {"emails" => ["mail@chimp.com"], :id => "my-list-id"}
|
123
112
|
mock_chimp_post(:listBatchUnsubscribe, form_params)
|
124
113
|
subscribers = ["mail@chimp.com"]
|
125
114
|
|
@@ -128,8 +117,8 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
128
117
|
end
|
129
118
|
|
130
119
|
should "delete subscriber" do
|
131
|
-
form_params = {"emails
|
132
|
-
:delete_member => true}
|
120
|
+
form_params = {"emails" => ["mail@chimp.com"], :id => "my-list-id",
|
121
|
+
:delete_member => "true"}
|
133
122
|
mock_chimp_post(:listBatchUnsubscribe, form_params)
|
134
123
|
subscribers = ["mail@chimp.com"]
|
135
124
|
|
@@ -138,8 +127,8 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
138
127
|
end
|
139
128
|
|
140
129
|
should "send goodbye" do
|
141
|
-
form_params = {"emails
|
142
|
-
:send_goodbye => true}
|
130
|
+
form_params = {"emails" => ["mail@chimp.com"], :id => "my-list-id",
|
131
|
+
:send_goodbye => "true"}
|
143
132
|
mock_chimp_post(:listBatchUnsubscribe, form_params)
|
144
133
|
subscribers = ["mail@chimp.com"]
|
145
134
|
|
@@ -148,8 +137,8 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
148
137
|
end
|
149
138
|
|
150
139
|
should "send unsubscribe notification" do
|
151
|
-
form_params = {"emails
|
152
|
-
:send_notify => true}
|
140
|
+
form_params = {"emails" => ["mail@chimp.com"], :id => "my-list-id",
|
141
|
+
:send_notify => "true"}
|
153
142
|
mock_chimp_post(:listBatchUnsubscribe, form_params)
|
154
143
|
subscribers = ["mail@chimp.com"]
|
155
144
|
|
@@ -160,7 +149,7 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
160
149
|
|
161
150
|
context "a single subscriber" do
|
162
151
|
should "unsubscribe" do
|
163
|
-
form_params = { "emails
|
152
|
+
form_params = { "emails" => ["mail@chimp.com"], :id => "my-list-id" }
|
164
153
|
mock_chimp_post(:listBatchUnsubscribe, form_params)
|
165
154
|
|
166
155
|
expected = {:success => 1, :errors => []}
|
@@ -178,12 +167,14 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
178
167
|
|
179
168
|
context "multiple subscribers at once" do
|
180
169
|
should "opt out" do
|
181
|
-
form_params = {
|
182
|
-
|
170
|
+
form_params = { :batch => [
|
171
|
+
{'EMAIL' => "mail@chimp.com"},
|
172
|
+
{'EMAIL' => 'foo@bar.com'}
|
173
|
+
], :id => "my-list-id"
|
174
|
+
}
|
183
175
|
mock_chimp_post(:listBatchSubscribe, form_params)
|
184
|
-
form_params = {
|
185
|
-
"
|
186
|
-
:send_goodbye => false, :send_notify => false }
|
176
|
+
form_params = { :emails => ["mail@chimp.com", "foo@bar.com"], :id => "my-list-id",
|
177
|
+
:send_goodbye => "false", :send_notify => "false" }
|
187
178
|
mock_chimp_post(:listBatchUnsubscribe, form_params)
|
188
179
|
subscribers = ["mail@chimp.com", "foo@bar.com"]
|
189
180
|
|
@@ -194,10 +185,10 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
194
185
|
|
195
186
|
context "a single subscriber" do
|
196
187
|
should "opt out" do
|
197
|
-
form_params = {
|
188
|
+
form_params = { :batch => [{"EMAIL" => "mail@chimp.com"}], :id => "my-list-id" }
|
198
189
|
mock_chimp_post(:listBatchSubscribe, form_params)
|
199
|
-
form_params = {
|
200
|
-
:send_goodbye => false, :send_notify => false}
|
190
|
+
form_params = { :emails => ["mail@chimp.com"], :id => "my-list-id",
|
191
|
+
:send_goodbye => "false", :send_notify => "false"}
|
201
192
|
mock_chimp_post(:listBatchUnsubscribe, form_params)
|
202
193
|
|
203
194
|
expected = {:success => 1, :errors => []}
|
@@ -223,9 +214,13 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
223
214
|
end
|
224
215
|
|
225
216
|
should "iterate over all members" do
|
226
|
-
|
227
|
-
|
228
|
-
|
217
|
+
response_sequence = %w{listMembers listMembers listMembers_none}.map do |fixture|
|
218
|
+
{
|
219
|
+
:body => canned_response("#{fixture}_success.json"),
|
220
|
+
:headers => {'Content-Type' => 'application/json'}
|
221
|
+
}
|
222
|
+
end
|
223
|
+
stub_request(:post, uri_for_remote_method('listMembers')).to_return(response_sequence)
|
229
224
|
|
230
225
|
expected = [
|
231
226
|
MonkeyWrench::Member.new({"timestamp"=>"2009-11-12 15:46:20", "email"=>"david@email.com"}),
|
@@ -249,32 +244,39 @@ class MonkeyWrench::ListTest < Test::Unit::TestCase
|
|
249
244
|
should "accept single member's email address change as hash" do
|
250
245
|
member = {:email => "foo@bar.com", :new_email => "bar@foo.com"}
|
251
246
|
form_params = {:email_address => "foo@bar.com",
|
252
|
-
"
|
253
|
-
:replace_interests => true, :id => "my-list-id"}
|
247
|
+
:merge_vars => {"EMAIL" => 'bar@foo.com'},
|
248
|
+
:replace_interests => "true", :id => "my-list-id"}
|
254
249
|
mock_chimp_post(:listUpdateMember, form_params)
|
255
250
|
@list.update_members(member, :replace_interests => true)
|
256
251
|
end
|
257
252
|
|
258
253
|
should "accept single member's email address change as list" do
|
259
254
|
members = [{:email => "foo@bar.com", :new_email => "bar@foo.com"}]
|
260
|
-
form_params = {
|
261
|
-
|
262
|
-
|
255
|
+
form_params = {
|
256
|
+
:email_address => "foo@bar.com",
|
257
|
+
:merge_vars => {'EMAIL' => 'bar@foo.com'},
|
258
|
+
:replace_interests => "true", :id => "my-list-id"
|
259
|
+
}
|
263
260
|
mock_chimp_post(:listUpdateMember, form_params)
|
264
261
|
@list.update_members(members, :replace_interests => true)
|
265
262
|
end
|
266
263
|
|
267
264
|
should "update multiple members emails addresses" do
|
268
|
-
members = [
|
265
|
+
members = [
|
266
|
+
{:email => "foo@bar.com", :new_email => "bar@foo.com"},
|
269
267
|
{:email => "spock@vulcan.com", :new_email => "sylar@heroes.com"}
|
270
268
|
]
|
271
|
-
form_params = {
|
272
|
-
|
273
|
-
|
269
|
+
form_params = {
|
270
|
+
:email_address => "foo@bar.com",
|
271
|
+
:merge_vars => {"EMAIL" => 'bar@foo.com'},
|
272
|
+
:replace_interests => "true", :id => "my-list-id"
|
273
|
+
}
|
274
274
|
mock_chimp_post(:listUpdateMember, form_params)
|
275
|
-
form_params = {
|
276
|
-
|
277
|
-
|
275
|
+
form_params = {
|
276
|
+
:email_address => "spock@vulcan.com",
|
277
|
+
:merge_vars => {'EMAIL' => 'sylar@heroes.com'},
|
278
|
+
:replace_interests => "true", :id => "my-list-id"
|
279
|
+
}
|
278
280
|
mock_chimp_post(:listUpdateMember, form_params)
|
279
281
|
@list.update_members(members, :replace_interests => true)
|
280
282
|
end
|
File without changes
|
data/test/test_helper.rb
CHANGED
@@ -2,66 +2,66 @@ require 'rubygems'
|
|
2
2
|
require 'test/unit'
|
3
3
|
require 'shoulda'
|
4
4
|
require 'net/http'
|
5
|
+
require 'mocha'
|
6
|
+
require 'webmock/test_unit'
|
7
|
+
require 'yajl/json_gem'
|
5
8
|
|
6
9
|
begin
|
7
10
|
require "redgreen"
|
8
11
|
rescue LoadError;
|
9
12
|
end
|
10
13
|
|
11
|
-
require File.expand_path(File.dirname(__FILE__)) + '/lib/fakeweb/lib/fake_web'
|
12
|
-
|
13
14
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
15
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
16
|
require "#{File.dirname(__FILE__)}/../lib/monkey_wrench"
|
16
17
|
|
17
|
-
FakeWeb.allow_net_connect = false
|
18
|
-
|
19
18
|
class Test::Unit::TestCase
|
19
|
+
include WebMock
|
20
|
+
|
20
21
|
protected
|
21
22
|
|
22
23
|
def setup_config
|
23
24
|
MonkeyWrench::Config.new(:apikey => "my-key", :datacenter => "my-dc")
|
24
25
|
end
|
25
|
-
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
response = File.read(json_fixture_path(fixture, is_success))
|
31
|
-
store_response(uri, params, response)
|
32
|
-
FakeWeb.register_uri(method, uri, { :body => response, :content_type => 'application/json' })
|
26
|
+
|
27
|
+
def uri_for_remote_method(remote_method)
|
28
|
+
get_params = { :method => remote_method, :output => :json, :apikey => "my-key"}
|
29
|
+
query_string = map_form_params(get_params).gsub(/%5([b-d])/) {|s| s.upcase}
|
30
|
+
"http://my-dc.api.mailchimp.com/1.2/?#{query_string}"
|
33
31
|
end
|
34
|
-
|
35
|
-
def
|
36
|
-
|
32
|
+
|
33
|
+
def mock_chimp_posts(remote_method, sequence)
|
34
|
+
uri = uri_for_remote_method(remote_method)
|
35
|
+
sequence.each do |response|
|
36
|
+
response_body = canned_response(fixture_filename(response[:fixture] || remote_method, response[:is_success]))
|
37
|
+
stub_request(:post, uri).with(:body => response[:params]).
|
38
|
+
to_return(:body => response_body, :headers => {'Content-Type' => 'application/json'})
|
39
|
+
end
|
37
40
|
end
|
38
|
-
|
39
|
-
def
|
40
|
-
|
41
|
-
@stored_responses[uri] ||= {}
|
42
|
-
@stored_responses[uri][params.collect_kv{|k,v| [k.to_s, v.to_s]}.inspect] = response
|
41
|
+
|
42
|
+
def mock_chimp_post(remote_method, post_params = {}, is_success = true, fixture = nil)
|
43
|
+
mock_chimp_posts remote_method, [{:params => post_params, :is_success => is_success, :fixture => fixture}]
|
43
44
|
end
|
44
45
|
|
45
|
-
def
|
46
|
-
|
47
|
-
raise "Unable to handle request to #{uri} with params: #{actual_params.inspect}" unless response
|
48
|
-
response
|
46
|
+
def escape(string)
|
47
|
+
URI.escape(string, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]"))
|
49
48
|
end
|
50
|
-
|
49
|
+
|
51
50
|
def map_form_params(params)
|
52
|
-
|
53
|
-
request.set_form_data(params)
|
54
|
-
request.body
|
51
|
+
params.map { |k,v| escape(k.to_s) + '=' + escape(v.to_s) }.join('&')
|
55
52
|
end
|
56
53
|
|
57
|
-
def
|
58
|
-
|
59
|
-
File.join(File.dirname(__FILE__), "fixtures", "#{fixture}_#{response}.json")
|
54
|
+
def canned_response(filename)
|
55
|
+
File.read(fixture_path(filename))
|
60
56
|
end
|
61
|
-
|
62
|
-
def
|
63
|
-
|
64
|
-
|
57
|
+
|
58
|
+
def fixture_filename(fixture, is_success)
|
59
|
+
outcome = is_success ? "success" : "fail"
|
60
|
+
"#{fixture}_#{outcome}.json"
|
65
61
|
end
|
66
62
|
|
63
|
+
def fixture_path(filename)
|
64
|
+
File.join(File.dirname(__FILE__), "fixtures", filename)
|
65
|
+
end
|
66
|
+
|
67
67
|
end
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: monkey_wrench
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 31
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 2
|
10
|
+
version: 0.1.2
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Glenn Gillen
|
@@ -9,29 +15,41 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date: 2010-
|
18
|
+
date: 2010-10-01 00:00:00 +01:00
|
13
19
|
default_executable:
|
14
20
|
dependencies:
|
15
21
|
- !ruby/object:Gem::Dependency
|
16
|
-
name:
|
17
|
-
|
18
|
-
|
19
|
-
|
22
|
+
name: yajl-ruby
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
20
26
|
requirements:
|
21
27
|
- - "="
|
22
28
|
- !ruby/object:Gem::Version
|
23
|
-
|
24
|
-
|
29
|
+
hash: 13
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 7
|
33
|
+
- 7
|
34
|
+
version: 0.7.7
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
25
37
|
- !ruby/object:Gem::Dependency
|
26
38
|
name: httparty
|
27
|
-
|
28
|
-
|
29
|
-
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
30
42
|
requirements:
|
31
43
|
- - "="
|
32
44
|
- !ruby/object:Gem::Version
|
33
|
-
|
34
|
-
|
45
|
+
hash: 5
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
- 6
|
49
|
+
- 1
|
50
|
+
version: 0.6.1
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
35
53
|
description: A ruby API for managing lists, campaigns, subscribers, etc. within Mailchimp (http://www.mailchimp.com/)
|
36
54
|
email: glenn@rubypond.com
|
37
55
|
executables: []
|
@@ -58,7 +76,9 @@ files:
|
|
58
76
|
- lib/monkey_wrench.rb
|
59
77
|
- test/fixtures/api_fail.json
|
60
78
|
- test/fixtures/campaigns_success.json
|
79
|
+
- test/fixtures/listBatchSubscribe1000_success.json
|
61
80
|
- test/fixtures/listBatchSubscribe10_success.json
|
81
|
+
- test/fixtures/listBatchSubscribe4_success.json
|
62
82
|
- test/fixtures/listBatchSubscribe5_success.json
|
63
83
|
- test/fixtures/listBatchSubscribe_success.json
|
64
84
|
- test/fixtures/listBatchSubscribe_with_error_success.json
|
@@ -71,6 +91,7 @@ files:
|
|
71
91
|
- test/fixtures/listSubscribe_success.json
|
72
92
|
- test/fixtures/listUnsubscribe_success.json
|
73
93
|
- test/fixtures/listUpdateMember_success.json
|
94
|
+
- test/monkey_wrench/base_test.rb
|
74
95
|
- test/monkey_wrench/campaign_aim_test.rb
|
75
96
|
- test/monkey_wrench/campaign_stats_test.rb
|
76
97
|
- test/monkey_wrench/campaign_test.rb
|
@@ -90,28 +111,36 @@ require_paths:
|
|
90
111
|
- .
|
91
112
|
- lib
|
92
113
|
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
none: false
|
93
115
|
requirements:
|
94
116
|
- - ">="
|
95
117
|
- !ruby/object:Gem::Version
|
118
|
+
hash: 3
|
119
|
+
segments:
|
120
|
+
- 0
|
96
121
|
version: "0"
|
97
|
-
version:
|
98
122
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
99
124
|
requirements:
|
100
125
|
- - ">="
|
101
126
|
- !ruby/object:Gem::Version
|
127
|
+
hash: 3
|
128
|
+
segments:
|
129
|
+
- 0
|
102
130
|
version: "0"
|
103
|
-
version:
|
104
131
|
requirements: []
|
105
132
|
|
106
133
|
rubyforge_project:
|
107
|
-
rubygems_version: 1.3.
|
134
|
+
rubygems_version: 1.3.7
|
108
135
|
signing_key:
|
109
136
|
specification_version: 2
|
110
137
|
summary: A ruby wrapper for the Mailchimp API
|
111
138
|
test_files:
|
112
139
|
- test/fixtures/api_fail.json
|
113
140
|
- test/fixtures/campaigns_success.json
|
141
|
+
- test/fixtures/listBatchSubscribe1000_success.json
|
114
142
|
- test/fixtures/listBatchSubscribe10_success.json
|
143
|
+
- test/fixtures/listBatchSubscribe4_success.json
|
115
144
|
- test/fixtures/listBatchSubscribe5_success.json
|
116
145
|
- test/fixtures/listBatchSubscribe_success.json
|
117
146
|
- test/fixtures/listBatchSubscribe_with_error_success.json
|
@@ -124,6 +153,7 @@ test_files:
|
|
124
153
|
- test/fixtures/listSubscribe_success.json
|
125
154
|
- test/fixtures/listUnsubscribe_success.json
|
126
155
|
- test/fixtures/listUpdateMember_success.json
|
156
|
+
- test/monkey_wrench/base_test.rb
|
127
157
|
- test/monkey_wrench/campaign_aim_test.rb
|
128
158
|
- test/monkey_wrench/campaign_stats_test.rb
|
129
159
|
- test/monkey_wrench/campaign_test.rb
|