monkey_wrench 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|