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 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
@@ -1 +1,4 @@
1
- rvm: 1.9.3
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/README.markdown CHANGED
@@ -1,16 +1,18 @@
1
1
  # gibbon
2
2
 
3
- Gibbon is a simple wrapper for MailChimp's [Primary and Export APIs](http://www.mailchimp.com/api).
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.4.0+
7
+ ##Important Notes About Version 0.5.0+
8
+ ### (It's different!)
8
9
 
9
- * Ruby 1.9.x+
10
- * Errors are now raised by default
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
- * The environment variable 'MC_API_KEY' no longer works. Please use 'MAILCHIMP_API_KEY' instead.
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
- u = Gibbon.new
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/1.3/) for details.
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.list_member_info({:id => list_id, :email_address => email_array})
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.list_members({:id => list_id})
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.list_members({:id => list_id, :status => "unsubscribed"})
93
+ gb.lists.members({:id => list_id, :status => "unsubscribed"})
90
94
 
91
95
  Subscribe a member to a list:
92
96
 
93
- gb.list_subscribe({:id => list_id, :email_address => "email_address", :merge_vars => {:FNAME => "First Name", :LNAME => "Last Name"}})
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.list_batch_subscribe(:id => list_id, :batch => [{:EMAIL => "email1", :FNAME => "FirstName1", :LNAME => "LastName1"},{:EMAIL => "email2", :FNAME => "FirstName2", :LNAME => "LastName2"}])
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 open and click detail for recipients of a particular campaign:
109
+ Fetch recipients who opened particular campaign:
105
110
 
106
- email_stats = gb.campaign_email_stats_aim({:cid => campaign_id, :email_address => email_array})
111
+ email_stats = gb.reports.opened({:cid => campaign_id})
107
112
 
108
113
  or
109
114
 
110
- email_stats = gb.campaignEmailStatsAIM({:cid => campaign_id, :email_address => email_array})
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
- gb.timeout = 5
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 [error code list](http://apidocs.mailchimp.com/api/rtfm/exceptions.field.php).
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 = GibbonExport.new("your_api_key")
158
+ gibbon_export = Gibbon::Export.new("your_api_key")
151
159
 
152
- Calling Export API functions is identical to making standard API calls but the
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. This is because the data returned from the Export API is a stream
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 'rake/testtask'
1
+ require 'rubygems'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubygems/specification'
2
4
  require 'bundler/gem_tasks'
3
5
 
4
- Rake::TestTask.new(:test) do |test|
5
- test.libs << 'lib' << 'test'
6
- test.pattern = 'test/test_*.rb'
7
- test.verbose = true
8
- end
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.4.6"
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 simple wrapper for MailChimp's primary and export APIs}
12
- s.description = %q{A simple wrapper for MailChimp's primary and export APIs}
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 = "Warning: Gibbon versions 0.4.0 and newer include breaking changes like throwing exceptions by default!\n" +
16
- "Please read more at http://github.com/amro/gibbon before upgrading from 0.3.x!"
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('rake')
29
- s.add_development_dependency('debugger')
30
- s.add_development_dependency('shoulda')
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
- class Gibbon
6
- include HTTParty
7
- format :plain
8
- default_timeout 30
5
+ require 'gibbon/mailchimp_error'
6
+ require 'gibbon/api_category'
7
+ require 'gibbon/api'
8
+ require 'gibbon/export'
9
9
 
10
- attr_accessor :api_key, :api_endpoint, :timeout, :throws_exceptions
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