gibbon 0.4.6 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of gibbon might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.travis.yml +4 -1
- data/README.markdown +51 -39
- data/Rakefile +9 -8
- data/gibbon.gemspec +9 -10
- data/lib/gibbon.rb +6 -138
- data/lib/gibbon/api.rb +34 -0
- data/lib/gibbon/api_category.rb +83 -0
- data/lib/gibbon/export.rb +64 -0
- data/lib/gibbon/mailchimp_error.rb +5 -0
- data/spec/gibbon/gibbon_spec.rb +247 -0
- data/spec/spec_helper.rb +12 -0
- metadata +32 -76
- data/test/helper.rb +0 -16
- data/test/test_gibbon.rb +0 -245
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d877b249bb882f814168716848be16e5304b2db8
|
4
|
+
data.tar.gz: 0fe273859157553a5871637df736b144a00da7c1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4e3b5dce4a2f0e2da5da2e0e0c0ece8330d5347d5162ec8fb2f8469bd46362ae3b9cae42037d1b6ae24261e306eb51cf46db044d7bb23c0277f145e7276620dd
|
7
|
+
data.tar.gz: cc1109531c71356394808a777474ecaf90aba07eefd4828e931177f347b3888704d553c467b5920fac23dcd098aca29f7fde345a89cff960280f1fbba53f2451
|
data/.travis.yml
CHANGED
data/README.markdown
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
# gibbon
|
2
2
|
|
3
|
-
Gibbon is
|
3
|
+
Gibbon is an API wrapper for MailChimp's [Primary and Export APIs](http://www.mailchimp.com/api).
|
4
4
|
|
5
5
|
[![Build Status](https://secure.travis-ci.org/amro/gibbon.png)](http://travis-ci.org/amro/gibbon)
|
6
6
|
|
7
|
-
##Important Notes About Version 0.
|
7
|
+
##Important Notes About Version 0.5.0+
|
8
|
+
### (It's different!)
|
8
9
|
|
9
|
-
|
10
|
-
|
10
|
+
Gibbon now targets MailChimp API 2.0, which is substantially different from API 1.3. Please use Gibbon 0.4.6 if you need to use API 1.3.
|
11
|
+
|
12
|
+
* Supports MailChimp API 2.0 and Export API 1.0
|
13
|
+
* Errors are raised by default since 0.4.x
|
11
14
|
* Timeouts can be specified per request during initialization
|
12
|
-
*
|
13
|
-
* The code has been cleaned up a bit and a few more comments have been added
|
15
|
+
* Ruby 1.9.x+ for now. A future version may be Ruby 2.0 only to take advantage of lazy iteration when using the Export API.
|
14
16
|
|
15
17
|
##Installation
|
16
18
|
|
@@ -26,103 +28,108 @@ There are a few ways to use Gibbon:
|
|
26
28
|
|
27
29
|
You can create an instance of the API wrapper:
|
28
30
|
|
29
|
-
gb = Gibbon.new("your_api_key")
|
31
|
+
gb = Gibbon::API.new("your_api_key")
|
30
32
|
|
31
33
|
You can set `api_key`, `timeout` and `throws_exceptions` globally:
|
32
34
|
|
33
|
-
Gibbon.api_key = "your_api_key"
|
34
|
-
Gibbon.timeout = 15
|
35
|
-
Gibbon.throws_exceptions = false
|
35
|
+
Gibbon::API.api_key = "your_api_key"
|
36
|
+
Gibbon::API.timeout = 15
|
37
|
+
Gibbon::API.throws_exceptions = false
|
36
38
|
|
39
|
+
similarly
|
40
|
+
|
41
|
+
Gibbon::Export.api_key = "your_api_key"
|
42
|
+
Gibbon::Export.timeout = 15
|
43
|
+
Gibbon::Export.throws_exceptions = false
|
44
|
+
|
37
45
|
For example, you could set the values above in an `initializer` file in your `Rails` app (e.g. your\_app/config/initializers/gibbon.rb).
|
38
46
|
|
39
47
|
Assuming you've set an `api_key` on Gibbon, you can conveniently make API calls on the class itself:
|
40
48
|
|
41
|
-
Gibbon.lists
|
49
|
+
Gibbon::API.lists.list
|
42
50
|
|
43
51
|
You can also set the environment variable `MAILCHIMP_API_KEY` and Gibbon will use it when you create an instance:
|
44
52
|
|
45
|
-
|
53
|
+
gb = Gibbon::API.new
|
46
54
|
|
47
55
|
> Note: In an effort to simplify Gibbon, the environment variable 'MC_API_KEY' is no longer available as of version 0.4.0. Please use 'MAILCHIMP_API_KEY' instead.
|
48
56
|
|
49
57
|
Fetching data is as simple as calling API methods directly on the wrapper
|
50
|
-
object. The API calls may be made with either camelcase or underscore
|
58
|
+
object with a given category (e.g. campaigns.list). The API calls may be made with either camelcase or underscore
|
51
59
|
separated formatting as you see in the "More Advanced Examples" section below.
|
52
60
|
|
53
|
-
Check the API [documentation](http://apidocs.mailchimp.com/api/
|
61
|
+
Check the API [documentation](http://apidocs.mailchimp.com/api/2.0/) for details.
|
54
62
|
|
55
63
|
### Fetching Campaigns
|
56
64
|
|
57
65
|
For example, to fetch your first 100 campaigns (page 0):
|
58
66
|
|
59
|
-
campaigns = gb.campaigns({:start => 0, :limit => 100})
|
67
|
+
campaigns = gb.campaigns.list({:start => 0, :limit => 100})
|
60
68
|
|
61
69
|
### Fetching Lists
|
62
70
|
|
63
71
|
Similarly, to fetch your first 100 lists:
|
64
72
|
|
65
|
-
lists = gb.lists({:start => 0, :limit=> 100})
|
73
|
+
lists = gb.lists.list({:start => 0, :limit=> 100})
|
66
74
|
|
67
75
|
Or, to fetch a list by name:
|
68
76
|
|
69
|
-
list = gb.lists({:filters => {:list_name => list_name}})
|
77
|
+
list = gb.lists.list({:filters => {:list_name => list_name}})
|
70
78
|
|
71
79
|
### More Advanced Examples
|
72
80
|
|
73
81
|
Getting batch member information for subscribers looks like this:
|
74
82
|
|
75
|
-
info = gb.
|
76
|
-
|
77
|
-
or
|
78
|
-
|
79
|
-
info = gb.listMemberInfo({:id => list_id, :email_address => email_array})
|
83
|
+
info = gb.lists.member_info({:id => list_id, :email_address => email_array})
|
80
84
|
|
81
85
|
List subscribers for a list:
|
82
86
|
|
83
|
-
gb.
|
87
|
+
gb.lists.members({:id => list_id})
|
84
88
|
|
85
89
|
or
|
86
90
|
|
87
91
|
List unsubscribed members for a list
|
88
92
|
|
89
|
-
gb.
|
93
|
+
gb.lists.members({:id => list_id, :status => "unsubscribed"})
|
90
94
|
|
91
95
|
Subscribe a member to a list:
|
92
96
|
|
93
|
-
gb.
|
97
|
+
gb.lists.subscribe({:id => list_id, :email => {:email => 'email_address'}, :merge_vars => {:FNAME => 'First Name', :LNAME => 'Last Name'}, :double_optin => false})
|
98
|
+
|
94
99
|
> Note: This will send a welcome email to the new subscriber
|
95
100
|
|
96
101
|
or
|
97
102
|
|
98
103
|
Batch subscribe members to a list:
|
99
104
|
|
100
|
-
gb.
|
105
|
+
gb.lists.batch_subscribe(:id => list_id, :batch => [{:EMAIL => "email1", :FNAME => "FirstName1", :LNAME => "LastName1"},{:EMAIL => "email2", :FNAME => "FirstName2", :LNAME => "LastName2"}])
|
101
106
|
|
102
107
|
> Note: This will send welcome emails to the new subscribers
|
103
108
|
|
104
|
-
Fetch
|
109
|
+
Fetch recipients who opened particular campaign:
|
105
110
|
|
106
|
-
email_stats = gb.
|
111
|
+
email_stats = gb.reports.opened({:cid => campaign_id})
|
107
112
|
|
108
113
|
or
|
109
114
|
|
110
|
-
|
115
|
+
Create a campaign:
|
116
|
+
|
117
|
+
gb.campaigns.create({type: "regular", options: {list_id: list_id, subject: "Gibbon is cool", from_email: "you@example.com", from_name: "Darth Vader", generate_text: true}, content: {html: "<html><head></head><body><h1>Foo</h1><p>Bar</p></body></html>"}})
|
111
118
|
|
112
119
|
Overriding Gibbon's API endpoint (i.e. if using an access token from OAuth and have the `api_endpoint` from the [metadata](http://apidocs.mailchimp.com/oauth2/)):
|
113
120
|
|
114
|
-
Gibbon.api_endpoint = "https://us1.api.mailchimp.com"
|
115
|
-
Gibbon.api_key = your_access_token_or_api_key
|
121
|
+
Gibbon::API.api_endpoint = "https://us1.api.mailchimp.com"
|
122
|
+
Gibbon::API.api_key = your_access_token_or_api_key
|
116
123
|
|
117
124
|
### Setting timeouts
|
118
125
|
|
119
126
|
Gibbon defaults to a 30 second timeout. You can optionally set your own timeout (in seconds) like so:
|
120
127
|
|
121
|
-
gb = Gibbon.new("your_api_key", {:timeout => 5})
|
128
|
+
gb = Gibbon::API.new("your_api_key", {:timeout => 5})
|
122
129
|
|
123
130
|
or
|
124
131
|
|
125
|
-
|
132
|
+
gb.timeout = 5
|
126
133
|
|
127
134
|
### Error handling
|
128
135
|
|
@@ -134,7 +141,8 @@ APIs will return a Hash with two keys "errors", a string containing some textual
|
|
134
141
|
information about the error, and "code", the numeric code of the error.
|
135
142
|
|
136
143
|
If you rescue Gibbon::MailChimpError, you are provided with the error message itself as well as
|
137
|
-
a `code` attribute that you can map onto the API's
|
144
|
+
a `code` attribute that you can map onto the API's error list. The API docs list possible errors
|
145
|
+
at the bottom of each page.
|
138
146
|
|
139
147
|
> Note: In an effort to make Gibbon easier to use, errors are raised automatically as of version 0.4.0.
|
140
148
|
|
@@ -142,21 +150,25 @@ a `code` attribute that you can map onto the API's [error code list](http://apid
|
|
142
150
|
|
143
151
|
In addition to the primary API, you can make calls to the [Export API](http://apidocs.mailchimp.com/export/1.0/) using an instance of GibbonExport. Given an existing instance of Gibbon, you can request a new GibbonExporter object:
|
144
152
|
|
145
|
-
g = Gibbon.new("your_api_key")
|
153
|
+
g = Gibbon::API.new("your_api_key")
|
146
154
|
gibbon_export = g.get_exporter
|
147
155
|
|
148
156
|
or you can construct a new object directly:
|
149
157
|
|
150
|
-
gibbon_export =
|
158
|
+
gibbon_export = Gibbon::Export.new("your_api_key")
|
151
159
|
|
152
|
-
|
160
|
+
Making calls to Export API endpoints is similar to making standard API calls but the
|
153
161
|
return value is an Enumerator which loops over the lines returned from the
|
154
|
-
Export API.
|
162
|
+
Export API. This is because the data returned from the Export API is a stream
|
155
163
|
of JSON objects rather than a single JSON array.
|
156
164
|
|
165
|
+
For example, dumping list members via the "list" method works like this:
|
166
|
+
|
167
|
+
gibbon_export.list({id => list_id})
|
168
|
+
|
157
169
|
##Thanks
|
158
170
|
|
159
|
-
Thanks to everyone who's [contributed](https://github.com/amro/gibbon/contributors) to Gibbon's development.
|
171
|
+
Thanks to everyone who's [contributed](https://github.com/amro/gibbon/contributors) to Gibbon's development. Major props to Jesse at MailChimp for adding nice stuff in API 2.0 that makes it easier to develop against.
|
160
172
|
|
161
173
|
##Copyright
|
162
174
|
|
data/Rakefile
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
require '
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'rubygems/specification'
|
2
4
|
require 'bundler/gem_tasks'
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
task default: [:test]
|
6
|
+
task :default => :spec
|
7
|
+
desc "Run specs"
|
8
|
+
RSpec::Core::RakeTask.new do |t|
|
9
|
+
t.pattern = FileList['spec/**/*_spec.rb']
|
10
|
+
t.rspec_opts = %w(-fs --color)
|
11
|
+
end
|
data/gibbon.gemspec
CHANGED
@@ -3,18 +3,18 @@ $:.push File.expand_path("../lib", __FILE__)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = "gibbon"
|
6
|
-
s.version = "0.
|
6
|
+
s.version = "0.5.0"
|
7
7
|
s.authors = ["Amro Mousa"]
|
8
8
|
s.email = ["amromousa@gmail.com"]
|
9
9
|
s.homepage = "http://github.com/amro/gibbon"
|
10
10
|
|
11
|
-
s.summary = %q{A
|
12
|
-
s.description = %q{A
|
11
|
+
s.summary = %q{A wrapper for MailChimp API 2.0 and Export API 1.0}
|
12
|
+
s.description = %q{A wrapper for MailChimp API 2.0 and Export API 1.0}
|
13
13
|
s.license = "MIT"
|
14
14
|
|
15
|
-
s.post_install_message = "
|
16
|
-
|
17
|
-
|
15
|
+
s.post_install_message = "IMPORTANT: Gibbon now targets MailChimp API 2.0, which is substantially different from API 1.3.\n \
|
16
|
+
Please use Gibbon 0.4.6 if you need to use API 1.3.\nIf you're upgrading from <0.5.0 your code WILL break."
|
17
|
+
|
18
18
|
s.rubyforge_project = "gibbon"
|
19
19
|
|
20
20
|
s.files = `git ls-files`.split("\n")
|
@@ -25,8 +25,7 @@ Gem::Specification.new do |s|
|
|
25
25
|
s.add_dependency('httparty')
|
26
26
|
s.add_dependency('multi_json', '>= 1.3.4')
|
27
27
|
|
28
|
-
s.add_development_dependency
|
29
|
-
s.add_development_dependency
|
30
|
-
|
31
|
-
s.add_development_dependency('mocha')
|
28
|
+
s.add_development_dependency 'rake'
|
29
|
+
s.add_development_dependency "rspec", "~> 2.13.0"
|
30
|
+
|
32
31
|
end
|
data/lib/gibbon.rb
CHANGED
@@ -2,142 +2,10 @@ require 'httparty'
|
|
2
2
|
require 'multi_json'
|
3
3
|
require 'cgi'
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
require 'gibbon/mailchimp_error'
|
6
|
+
require 'gibbon/api_category'
|
7
|
+
require 'gibbon/api'
|
8
|
+
require 'gibbon/export'
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
def initialize(api_key = nil, default_parameters = {})
|
13
|
-
@api_key = api_key || self.class.api_key || ENV['MAILCHIMP_API_KEY']
|
14
|
-
@api_key = @api_key.strip if @api_key
|
15
|
-
|
16
|
-
@api_endpoint = default_parameters.delete(:api_endpoint)
|
17
|
-
@timeout = default_parameters.delete(:timeout)
|
18
|
-
@throws_exceptions = default_parameters.delete(:throws_exceptions)
|
19
|
-
|
20
|
-
@default_params = {apikey: @api_key}.merge(default_parameters)
|
21
|
-
|
22
|
-
set_instance_defaults
|
23
|
-
end
|
24
|
-
|
25
|
-
def api_key=(value)
|
26
|
-
@api_key = value.strip if value
|
27
|
-
@default_params = @default_params.merge({apikey: @api_key})
|
28
|
-
end
|
29
|
-
|
30
|
-
def get_exporter
|
31
|
-
GibbonExport.new(@api_key, @default_params)
|
32
|
-
end
|
33
|
-
|
34
|
-
protected
|
35
|
-
|
36
|
-
def call(method, params = {})
|
37
|
-
api_url = base_api_url + method
|
38
|
-
params = @default_params.merge(params)
|
39
|
-
response = self.class.post(api_url, body: CGI::escape(MultiJson.dump(params)), timeout: @timeout)
|
40
|
-
|
41
|
-
# MailChimp API sometimes returns JSON fragments (e.g. true from listSubscribe)
|
42
|
-
# so we parse after adding brackets to create a JSON array so
|
43
|
-
# parsing succeeds. This also handles the case of an empty response
|
44
|
-
parsed_response = MultiJson.load("[#{response.body}]").first
|
45
|
-
|
46
|
-
if should_raise_for_response?(parsed_response)
|
47
|
-
error = MailChimpError.new("MailChimp API Error: #{parsed_response["error"]} (code #{parsed_response["code"]})")
|
48
|
-
error.code = parsed_response["code"]
|
49
|
-
raise error
|
50
|
-
end
|
51
|
-
|
52
|
-
parsed_response
|
53
|
-
end
|
54
|
-
|
55
|
-
def method_missing(method, *args)
|
56
|
-
# To support underscores, we camelize the method name
|
57
|
-
|
58
|
-
# Thanks for the camelize gsub, Rails
|
59
|
-
method = method.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
|
60
|
-
|
61
|
-
# We need to downcase the first letter of every API method
|
62
|
-
# and MailChimp has a few of API methods that end in "AIM," which
|
63
|
-
# must be upcased (See "Campaign Report Data Methods" in their API docs).
|
64
|
-
method = method[0].chr.downcase + method[1..-1].gsub(/aim$/i, 'AIM')
|
65
|
-
|
66
|
-
call(method, *args)
|
67
|
-
end
|
68
|
-
|
69
|
-
def set_instance_defaults
|
70
|
-
@timeout = (self.class.timeout || 30) if @timeout.nil?
|
71
|
-
@api_endpoint = self.class.api_endpoint if @api_endpoint.nil?
|
72
|
-
# Two lines because the class variable could be false and (false || true) is always true
|
73
|
-
@throws_exceptions = self.class.throws_exceptions if @throws_exceptions.nil?
|
74
|
-
@throws_exceptions = true if @throws_exceptions.nil?
|
75
|
-
end
|
76
|
-
|
77
|
-
def should_raise_for_response?(response)
|
78
|
-
@throws_exceptions && response.is_a?(Hash) && response["error"]
|
79
|
-
end
|
80
|
-
|
81
|
-
def base_api_url
|
82
|
-
"#{@api_endpoint || get_api_endpoint}/1.3/?method="
|
83
|
-
end
|
84
|
-
|
85
|
-
def get_api_endpoint
|
86
|
-
"https://#{get_data_center_from_api_key}api.mailchimp.com"
|
87
|
-
end
|
88
|
-
|
89
|
-
class << self
|
90
|
-
attr_accessor :api_key, :timeout, :throws_exceptions, :api_endpoint
|
91
|
-
|
92
|
-
def method_missing(sym, *args, &block)
|
93
|
-
new(self.api_key, {api_endpoint: self.api_endpoint, timeout: self.timeout, throws_exceptions: self.throws_exceptions}).send(sym, *args, &block)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
def get_data_center_from_api_key
|
98
|
-
# Return an empty string for invalid API keys so Gibbon hits the main endpoint
|
99
|
-
data_center = ""
|
100
|
-
|
101
|
-
if (@api_key && @api_key["-"])
|
102
|
-
# Add a period since the data_center is a subdomain and it keeps things dry
|
103
|
-
data_center = "#{@api_key.split('-').last}."
|
104
|
-
end
|
105
|
-
|
106
|
-
data_center
|
107
|
-
end
|
108
|
-
|
109
|
-
class MailChimpError < StandardError
|
110
|
-
attr_accessor :code
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
class GibbonExport < Gibbon
|
115
|
-
def initialize(api_key = nil, default_parameters = {})
|
116
|
-
super(api_key, default_parameters)
|
117
|
-
end
|
118
|
-
|
119
|
-
protected
|
120
|
-
|
121
|
-
def export_api_url
|
122
|
-
"http://#{get_data_center_from_api_key}api.mailchimp.com/export/1.0/"
|
123
|
-
end
|
124
|
-
|
125
|
-
def call(method, params = {})
|
126
|
-
api_url = export_api_url + method + "/"
|
127
|
-
params = @default_params.merge(params)
|
128
|
-
response = self.class.post(api_url, body: CGI::escape(MultiJson.dump(params)), timeout: @timeout)
|
129
|
-
|
130
|
-
lines = response.body.lines
|
131
|
-
if @throws_exceptions
|
132
|
-
first_line = MultiJson.load(lines.first) if lines.first
|
133
|
-
|
134
|
-
if should_raise_for_response?(first_line)
|
135
|
-
error = MailChimpError.new("MailChimp Export API Error: #{first_line["error"]} (code #{first_line["code"]})")
|
136
|
-
error.code = first_line["code"]
|
137
|
-
raise error
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
lines
|
142
|
-
end
|
143
|
-
end
|
10
|
+
module Gibbon
|
11
|
+
end
|
data/lib/gibbon/api.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
module Gibbon
|
2
|
+
class API
|
3
|
+
attr_accessor :api_key, :api_endpoint, :timeout, :throws_exceptions
|
4
|
+
|
5
|
+
def initialize(api_key = nil, default_parameters = {})
|
6
|
+
@api_key = api_key || self.class.api_key || ENV['MAILCHIMP_API_KEY']
|
7
|
+
@api_key = @api_key.strip if @api_key
|
8
|
+
|
9
|
+
@api_endpoint = default_parameters.delete(:api_endpoint) || self.class.api_endpoint
|
10
|
+
@timeout = default_parameters.delete(:timeout) || self.class.timeout
|
11
|
+
@throws_exceptions = default_parameters.delete(:throws_exceptions) || self.class.throws_exceptions
|
12
|
+
|
13
|
+
@default_params = {apikey: @api_key}.merge(default_parameters)
|
14
|
+
end
|
15
|
+
|
16
|
+
def get_exporter
|
17
|
+
Export.new(@api_key, @default_params)
|
18
|
+
end
|
19
|
+
|
20
|
+
def method_missing(method, *args)
|
21
|
+
api = APICategory.new(method.to_s, @api_key, @timeout, @throws_exceptions, @api_endpoint, @default_params)
|
22
|
+
api.api_endpoint = @api_endpoint if @api_endpoint
|
23
|
+
api
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
attr_accessor :api_key, :timeout, :throws_exceptions, :api_endpoint
|
28
|
+
|
29
|
+
def method_missing(sym, *args, &block)
|
30
|
+
new(self.api_key, {api_endpoint: self.api_endpoint, timeout: self.timeout, throws_exceptions: self.throws_exceptions}).send(sym, *args, &block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|