mailchimp 0.0.1.alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,61 @@
1
+ if defined?(ActionMailer)
2
+ require File.join(File.dirname(__FILE__), 'handlers', 'mandrill_delivery_handler')
3
+ end
4
+
5
+ module Mailchimp
6
+ class Mandrill
7
+ include HTTParty
8
+ default_timeout 30
9
+
10
+ attr_accessor :api_key, :timeout, :options
11
+
12
+ def initialize(api_key = nil, extra_params = {})
13
+ @api_key = api_key || ENV['MAILCHIMP_API_KEY'] || self.class.api_key
14
+ @default_params = {
15
+ :key => @api_key,
16
+ :options => {
17
+ :track_opens => true,
18
+ :track_clicks => true
19
+ }
20
+ }.merge(extra_params)
21
+ end
22
+
23
+ def api_key=(value)
24
+ @api_key = value
25
+ @default_params = @default_params.merge({:key => @api_key})
26
+ end
27
+
28
+ def base_api_url
29
+ "http://mandrillapp.com/api/1.0/"
30
+ end
31
+
32
+ def call(method, params = {})
33
+ url = "#{base_api_url}#{method}"
34
+ params = @default_params.merge(params)
35
+ response = self.class.post(url, :body => params, :timeout => @timeout)
36
+
37
+ begin
38
+ response = JSON.parse(response.body)
39
+ rescue
40
+ response = response.body
41
+ end
42
+ response
43
+ end
44
+
45
+ def method_missing(method, *args)
46
+ match = method.to_s.match(/([a-z]*)_([a-z]*)_?([a-z]*)/)
47
+ method = "#{match[1]}/#{match[2]}#{match[3] == '' ? "" : "-"+match[3]}"
48
+ args = {} unless args.length > 0
49
+ args = args[0] if (args.class.to_s == "Array")
50
+ call(method, args)
51
+ end
52
+
53
+ class << self
54
+ attr_accessor :api_key
55
+
56
+ def method_missing(sym, *args, &block)
57
+ new(self.api_key).send(sym, *args, &block)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,61 @@
1
+ if defined?(ActionMailer)
2
+ require File.join(File.dirname(__FILE__), 'handlers', 'sts_delivery_handler')
3
+ end
4
+
5
+ module Mailchimp
6
+ class STS
7
+ include HTTParty
8
+ default_timeout 30
9
+
10
+ attr_accessor :api_key, :timeout, :options
11
+
12
+ def initialize(api_key = nil, extra_params = {})
13
+ @api_key = api_key || ENV['MAILCHIMP_API_KEY'] || self.class.api_key
14
+ @default_params = {
15
+ :apikey => @api_key,
16
+ :options => {
17
+ :track_opens => true,
18
+ :track_clicks => true
19
+ }
20
+ }.merge(extra_params)
21
+ end
22
+
23
+ def api_key=(value)
24
+ @api_key = value
25
+ @default_params = @default_params.merge({:apikey => @api_key})
26
+ end
27
+
28
+ def base_api_url
29
+ dc = (@api_key == '' || @api_key == nil) ? '' : "#{@api_key.split("-").last}."
30
+ "https://#{dc}sts.mailchimp.com/1.0/"
31
+ end
32
+
33
+ def call(method, params = {})
34
+ url = "#{base_api_url}#{method}"
35
+ params = @default_params.merge(params)
36
+ response = self.class.post(url, :body => params, :timeout => @timeout)
37
+
38
+ begin
39
+ response = JSON.parse(response.body)
40
+ rescue
41
+ response = response.body
42
+ end
43
+ response
44
+ end
45
+
46
+ def method_missing(method, *args)
47
+ method = method.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } #Thanks for the gsub, Rails
48
+ args = {} unless args.length > 0
49
+ args = args[0] if (args.class.to_s == "Array")
50
+ call(method, args)
51
+ end
52
+
53
+ class << self
54
+ attr_accessor :api_key
55
+
56
+ def method_missing(sym, *args, &block)
57
+ new(self.api_key).send(sym, *args, &block)
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module Mailchimp
2
+ VERSION = "0.0.1.alpha"
3
+ end
data/lib/mailchimp.rb ADDED
@@ -0,0 +1,13 @@
1
+ require 'httparty'
2
+ require 'json'
3
+ require 'cgi'
4
+
5
+ require "mailchimp/ext/httparty"
6
+
7
+ require "mailchimp/version"
8
+ require "mailchimp/api"
9
+ require "mailchimp/sts"
10
+ require "mailchimp/mandrill"
11
+
12
+ module Mailchimp
13
+ end
data/mailchimp.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mailchimp/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "mailchimp"
7
+ s.version = Mailchimp::VERSION
8
+ s.authors = ["Chris Kelly"]
9
+ s.email = ["chris@highgroove.com"]
10
+ s.homepage = ""
11
+ s.summary = %q{Mailchimp APIs in Ruby}
12
+ s.description = %q{This provides Ruby access to (eventually) all of Mailchimp's APIs}
13
+
14
+ s.rubyforge_project = "mailchimp"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency('httparty')
22
+
23
+ s.add_development_dependency('ruby-debug19')
24
+ s.add_development_dependency('rake')
25
+ s.add_development_dependency('shoulda')
26
+ s.add_development_dependency('mocha')
27
+ s.add_development_dependency('cover_me')
28
+ s.add_development_dependency('fakeweb')
29
+ end
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ class ApiIntegrationTest < Test::Unit::TestCase
4
+
5
+ should "send request to Mailchimp API" do
6
+ FakeWeb.register_uri(
7
+ :post,
8
+ 'https://us1.api.mailchimp.com/1.3/?method=ping',
9
+ body: "Everything's Chimpy!".to_json
10
+ )
11
+ expected_request = {"apikey"=>"abc123-us1"}
12
+
13
+ m = Mailchimp::API.new('abc123-us1')
14
+ assert_equal "Everything's Chimpy!", m.ping
15
+ assert_equal expected_request, JSON.parse(URI::decode(FakeWeb.last_request.body))
16
+ end
17
+
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ class MandrillIntegrationTest < Test::Unit::TestCase
4
+
5
+ should "send request to Mandrill API" do
6
+ FakeWeb.register_uri(
7
+ :post,
8
+ 'http://mandrillapp.com/api/1.0/users/ping',
9
+ body: "PONG!"
10
+ )
11
+ expected_request = "key=abc123-us1&options[track_opens]=true&options[track_clicks]=true"
12
+
13
+ m = Mailchimp::Mandrill.new('abc123-us1')
14
+ assert_equal "PONG!", m.users_ping
15
+ assert_equal expected_request, URI::decode(FakeWeb.last_request.body)
16
+ end
17
+
18
+ end
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ class STSIntegrationTest < Test::Unit::TestCase
4
+
5
+ should "send request to STS API" do
6
+ FakeWeb.register_uri(
7
+ :post,
8
+ 'https://us1.sts.mailchimp.com/1.0/Ping',
9
+ body: "Everything's Chimpy!"
10
+ )
11
+ expected_request = "apikey=abc123-us1&options[track_opens]=true&options[track_clicks]=true"
12
+
13
+ m = Mailchimp::STS.new('abc123-us1')
14
+ assert_equal "Everything's Chimpy!", m.ping
15
+ assert_equal expected_request, URI::decode(FakeWeb.last_request.body)
16
+ end
17
+
18
+ end
@@ -0,0 +1,191 @@
1
+ require 'test_helper'
2
+
3
+ class ApiTest < Test::Unit::TestCase
4
+
5
+ context "attributes" do
6
+
7
+ setup do
8
+ @api_key = "123-us1"
9
+ end
10
+
11
+ should "have no API by default" do
12
+ @api = Mailchimp::API.new
13
+ assert_equal(nil, @api.api_key)
14
+ end
15
+
16
+ should "set an API key in constructor" do
17
+ @api = Mailchimp::API.new(@api_key)
18
+ assert_equal(@api_key, @api.api_key)
19
+ end
20
+
21
+ should "set an API key from the 'MAILCHIMP_API_KEY' ENV variable" do
22
+ ENV['MAILCHIMP_API_KEY'] = @api_key
23
+ @api = Mailchimp::API.new
24
+ assert_equal(@api_key, @api.api_key)
25
+ ENV.delete('MAILCHIMP_API_KEY')
26
+ end
27
+
28
+ should "set an API key via setter" do
29
+ @api = Mailchimp::API.new
30
+ @api.api_key = @api_key
31
+ assert_equal(@api_key, @api.api_key)
32
+ end
33
+
34
+ should "set timeout and get" do
35
+ @api = Mailchimp::API.new
36
+ timeout = 30
37
+ @api.timeout = timeout
38
+ assert_equal(timeout, @api.timeout)
39
+ end
40
+ end
41
+
42
+ context "build api url" do
43
+ setup do
44
+ @api = Mailchimp::API.new
45
+ @url = "https://api.mailchimp.com/1.3/?method=sayHello"
46
+ end
47
+
48
+ should "handle empty api key" do
49
+ expect_post(@url, {"apikey" => nil})
50
+ @api.say_hello
51
+ end
52
+
53
+ should "handle malformed api key" do
54
+ @api_key = "123"
55
+ @api.api_key = @api_key
56
+ expect_post(@url, {"apikey" => @api_key})
57
+ @api.say_hello
58
+ end
59
+
60
+ should "handle timeout" do
61
+ expect_post(@url, {"apikey" => nil}, 120)
62
+ @api.timeout=120
63
+ @api.say_hello
64
+ end
65
+
66
+ should "handle api key with dc" do
67
+ @api_key = "TESTKEY-us1"
68
+ @api.api_key = @api_key
69
+ expect_post("https://us1.api.mailchimp.com/1.3/?method=sayHello", {"apikey" => @api_key})
70
+ @api.say_hello
71
+ end
72
+ end
73
+
74
+ context "build api body" do
75
+ setup do
76
+ @key = "TESTKEY-us1"
77
+ @api = Mailchimp::API.new(@key)
78
+ @url = "https://us1.api.mailchimp.com/1.3/?method=sayHello"
79
+ @body = {"apikey" => @key}
80
+ end
81
+
82
+ should "escape string parameters" do
83
+ @message = "simon says"
84
+ expect_post(@url, @body.merge("message" => CGI::escape(@message)))
85
+ @api.say_hello(:message => @message)
86
+ end
87
+
88
+ should "escape string parameters in an array" do
89
+ expect_post(@url, @body.merge("messages" => ["simon+says", "do+this"]))
90
+ @api.say_hello(:messages => ["simon says", "do this"])
91
+ end
92
+
93
+ should "escape string parameters in a hash" do
94
+ expect_post(@url, @body.merge("messages" => {"simon+says" => "do+this"}))
95
+ @api.say_hello(:messages => {"simon says" => "do this"})
96
+ end
97
+
98
+ should "escape nested string parameters" do
99
+ expect_post(@url, @body.merge("messages" => {"simon+says" => ["do+this", "and+this"]}))
100
+ @api.say_hello(:messages => {"simon says" => ["do this", "and this"]})
101
+ end
102
+
103
+ should "pass through non string parameters" do
104
+ expect_post(@url, @body.merge("fee" => 99))
105
+ @api.say_hello(:fee => 99)
106
+ end
107
+ end
108
+
109
+ context "API instances" do
110
+ setup do
111
+ @key = "TESTKEY-us1"
112
+ @api = Mailchimp::API.new(@key)
113
+ @url = "https://us1.api.mailchimp.com/1.3/?method=sayHello"
114
+ @body = {"apikey" => @key}
115
+ @returns = Struct.new(:body).new(["array", "entries"].to_json)
116
+ end
117
+
118
+ should "produce a good exporter" do
119
+ @exporter = @api.get_exporter
120
+ assert_equal(@exporter.api_key, @api.api_key)
121
+ end
122
+
123
+ should "throw exception if configured to and the API replies with a JSON hash containing a key called 'error'" do
124
+ Mailchimp::API.stubs(:post).returns(Struct.new(:body).new({'error' => 'bad things'}.to_json))
125
+ assert_nothing_raised do
126
+ result = @api.say_hello
127
+ end
128
+
129
+ ap result
130
+ end
131
+
132
+ should "throw exception if configured to and the API replies with a JSON hash containing a key called 'error'" do
133
+ @api.throws_exceptions = true
134
+ Mailchimp::API.stubs(:post).returns(Struct.new(:body).new({'error' => 'bad things'}.to_json))
135
+ assert_raise RuntimeError do
136
+ @api.say_hello
137
+ end
138
+ end
139
+ end
140
+
141
+ context "export API" do
142
+ setup do
143
+ @key = "TESTKEY-us1"
144
+ @api = Mailchimp::APIExport.new(@key)
145
+ @url = "http://us1.api.mailchimp.com/export/1.0/"
146
+ @body = {:apikey => @key, :id => "listid"}
147
+ @returns = Struct.new(:body).new(["array", "entries"].to_json)
148
+ end
149
+
150
+ should "handle api key with dc" do
151
+ @api_key = "TESTKEY-us2"
152
+ @api = Mailchimp::APIExport.new(@api_key)
153
+
154
+ params = {:body => @body, :timeout => nil}
155
+
156
+ url = @url.gsub('us1', 'us2') + "sayHello/"
157
+ Mailchimp::APIExport.expects(:post).with(url, params).returns(@returns)
158
+ @api.say_hello(@body)
159
+ end
160
+
161
+ should "not throw exception if the Export API replies with a JSON hash containing a key called 'error'" do
162
+ Mailchimp::APIExport.stubs(:post).returns(Struct.new(:body).new({'error' => 'bad things'}.to_json))
163
+
164
+ assert_nothing_raised do
165
+ @api.say_hello(@body)
166
+ end
167
+ end
168
+
169
+ should "throw exception if configured to and the Export API replies with a JSON hash containing a key called 'error'" do
170
+ @api.throws_exceptions = true
171
+ params = {:body => @body, :timeout => nil}
172
+ Mailchimp::APIExport.stubs(:post).returns(Struct.new(:body).new({'error' => 'bad things', 'code' => '123'}.to_json))
173
+
174
+ assert_raise RuntimeError do
175
+ @api.say_hello(@body)
176
+ end
177
+ end
178
+
179
+ end
180
+
181
+ private
182
+
183
+ def expect_post(expected_url, expected_body, expected_timeout=nil)
184
+ Mailchimp::API.expects(:post).with do |url, opts|
185
+ url == expected_url &&
186
+ JSON.parse(URI::decode(opts[:body])) == expected_body &&
187
+ opts[:timeout] == expected_timeout
188
+ end.returns(Struct.new(:body).new("") )
189
+ end
190
+
191
+ end
@@ -0,0 +1,78 @@
1
+ require 'test_helper'
2
+
3
+ class MandrillTest < Test::Unit::TestCase
4
+
5
+ DEFAULT_OPTIONS= {:options=>{:track_opens=>true, :track_clicks=>true}}
6
+
7
+ context "attributes" do
8
+
9
+ setup do
10
+ @api_key = "123-us1"
11
+ end
12
+
13
+ should "have no API by default" do
14
+ @api = Mailchimp::Mandrill.new
15
+ assert_equal(nil, @api.api_key)
16
+ end
17
+
18
+ should "set an API key in constructor" do
19
+ @api = Mailchimp::Mandrill.new(@api_key)
20
+ assert_equal(@api_key, @api.api_key)
21
+ end
22
+
23
+ should "set an API key from the 'MAILCHIMP_API_KEY' ENV variable" do
24
+ ENV['MAILCHIMP_API_KEY'] = @api_key
25
+ @api = Mailchimp::Mandrill.new
26
+ assert_equal(@api_key, @api.api_key)
27
+ ENV.delete('MAILCHIMP_API_KEY')
28
+ end
29
+
30
+ should "set an API key via setter" do
31
+ @api = Mailchimp::Mandrill.new
32
+ @api.api_key = @api_key
33
+ assert_equal(@api_key, @api.api_key)
34
+ end
35
+
36
+ should "set timeout and get" do
37
+ @api = Mailchimp::Mandrill.new
38
+ timeout = 30
39
+ @api.timeout = timeout
40
+ assert_equal(timeout, @api.timeout)
41
+ end
42
+ end
43
+
44
+ context "build api url" do
45
+ setup do
46
+ @api = Mailchimp::Mandrill.new
47
+ @url = "http://mandrillapp.com/api/1.0/users/ping"
48
+ end
49
+
50
+ should "handle empty api key" do
51
+ expect_post(@url, DEFAULT_OPTIONS.merge(:key => nil))
52
+ @api.users_ping
53
+ end
54
+
55
+ should "handle malformed api key" do
56
+ @api_key = "123"
57
+ @api.api_key = @api_key
58
+ expect_post(@url, DEFAULT_OPTIONS.merge(:key => @api_key))
59
+ @api.users_ping
60
+ end
61
+
62
+ should "handle timeout" do
63
+ expect_post(@url, DEFAULT_OPTIONS.merge(:key => nil), 120)
64
+ @api.timeout = 120
65
+ @api.users_ping
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def expect_post(expected_url, expected_body, expected_timeout=nil)
72
+ Mailchimp::Mandrill.expects(:post).with do |url, opts|
73
+ url == expected_url &&
74
+ opts[:body] == expected_body &&
75
+ opts[:timeout] == expected_timeout
76
+ end.returns(Struct.new(:body).new("") )
77
+ end
78
+ end
@@ -0,0 +1,78 @@
1
+ require 'test_helper'
2
+
3
+ class STSTest < Test::Unit::TestCase
4
+
5
+ DEFAULT_OPTIONS= {:options=>{:track_opens=>true, :track_clicks=>true}}
6
+
7
+ context "attributes" do
8
+
9
+ setup do
10
+ @api_key = "123-us1"
11
+ end
12
+
13
+ should "have no API by default" do
14
+ @api = Mailchimp::STS.new
15
+ assert_equal(nil, @api.api_key)
16
+ end
17
+
18
+ should "set an API key in constructor" do
19
+ @api = Mailchimp::STS.new(@api_key)
20
+ assert_equal(@api_key, @api.api_key)
21
+ end
22
+
23
+ should "set an API key from the 'MAILCHIMP_API_KEY' ENV variable" do
24
+ ENV['MAILCHIMP_API_KEY'] = @api_key
25
+ @api = Mailchimp::STS.new
26
+ assert_equal(@api_key, @api.api_key)
27
+ ENV.delete('MAILCHIMP_API_KEY')
28
+ end
29
+
30
+ should "set an API key via setter" do
31
+ @api = Mailchimp::STS.new
32
+ @api.api_key = @api_key
33
+ assert_equal(@api_key, @api.api_key)
34
+ end
35
+
36
+ should "set timeout and get" do
37
+ @api = Mailchimp::STS.new
38
+ timeout = 30
39
+ @api.timeout = timeout
40
+ assert_equal(timeout, @api.timeout)
41
+ end
42
+ end
43
+
44
+ context "build api url" do
45
+ setup do
46
+ @api = Mailchimp::STS.new
47
+ @url = "https://sts.mailchimp.com/1.0/Ping"
48
+ end
49
+
50
+ should "handle empty api key" do
51
+ expect_post(@url, DEFAULT_OPTIONS.merge(:apikey => nil))
52
+ @api.ping
53
+ end
54
+
55
+ should "handle api key" do
56
+ @api_key = "123-us1"
57
+ @api.api_key = @api_key
58
+ expect_post("https://us1.sts.mailchimp.com/1.0/Ping", DEFAULT_OPTIONS.merge(:apikey => @api_key))
59
+ @api.ping
60
+ end
61
+
62
+ should "handle timeout" do
63
+ expect_post(@url, DEFAULT_OPTIONS.merge(:apikey => nil), 120)
64
+ @api.timeout = 120
65
+ @api.ping
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ def expect_post(expected_url, expected_body, expected_timeout=nil)
72
+ Mailchimp::STS.expects(:post).with do |url, opts|
73
+ url == expected_url &&
74
+ opts[:body] == expected_body &&
75
+ opts[:timeout] == expected_timeout
76
+ end.returns(Struct.new(:body).new("") )
77
+ end
78
+ end
@@ -0,0 +1,22 @@
1
+ require 'cover_me'
2
+ require 'rubygems'
3
+ require 'bundler'
4
+
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+
13
+ require 'test/unit'
14
+ require 'shoulda'
15
+ require 'mocha'
16
+ require 'fakeweb'
17
+
18
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
19
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
20
+ require 'mailchimp'
21
+
22
+ FakeWeb.allow_net_connect = false