gibbon 1.1.5 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3eedf8f39648b37f49821cf07606f6632218e2b8
4
- data.tar.gz: 32c2da7b8ed6edd091d8b762e527de5d5c320e2e
3
+ metadata.gz: 3568033ceac76caeac9a0c242498bea98928a54b
4
+ data.tar.gz: 5eaee69f08c43608056f4407058ae68db18ae062
5
5
  SHA512:
6
- metadata.gz: b240b5939c6c0bfba804bddc57ee2d41c9dc92ed363aa204f2fd47092c08bae8f7b0eb1a83ddf40474ff9227caa863a769cd4de73c53499d5c5b697eed9ebf03
7
- data.tar.gz: bcc381f439b1664a8894d7d269b6335ba2f78670ecf4822da31b2bf8444d08208cfd91fe614a95dd22179d0fe9c07202cc1e72c1f903616f652430660b5709e5
6
+ metadata.gz: 6aee46b63e30a3d8b2178864c76f773edc36d4b2f0dbe9c64feecf5b79fba5e008cbb71ce0af31f9deb1c9ab96a0ff85bbe4cfd443187ee7335e90ad10df6c74
7
+ data.tar.gz: 1054e23dc767ec9d60b507febdaecc2c646cfcac98c149b4a35b35cced3ab2c1d98b1e51c25c8c892f8ca0ddbe019ce21dba6a9bdca46b9c94378785998d8566
@@ -1,12 +1,19 @@
1
1
  ## [Unreleased][unreleased]
2
2
  -
3
+
4
+ ## [1.2.0] - 2015-07-16
5
+ - Same as 1.1.6 but rereleased because it's a breaking change
6
+ - Support for Ruby 2 streaming with Export API. Now returns an Array of Array of Strings instead of an Array of Strings.
7
+ - Fix a bug that caused calling methods statically on Gibbon::Export to fail
8
+
9
+ ## [1.1.6] - 2015-06-04 (Yanked)
10
+ - Support for Ruby 2 streaming with Export API
11
+
3
12
  ## [1.1.5] - 2015-02-19
4
- ### Fixed
5
13
  - Update MultiJSON dependency to 1.9.0
6
14
  - Handle single empty space in Export API response
7
15
 
8
16
  ## [1.1.4] - 2012-11-04
9
- ### Fixed
10
17
  - Fix JSON::ParserError on export calls that return blank results
11
18
 
12
19
  [unreleased]: https://github.com/amro/gibbon/compare/v1.1.5...HEAD
data/Gemfile CHANGED
@@ -5,4 +5,8 @@ platforms :rbx do
5
5
  gem 'rubinius-developer_tools'
6
6
  end
7
7
 
8
+ group :development, :test do
9
+ gem 'webmock'
10
+ end
11
+
8
12
  gemspec
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010-2014 Amro Mousa
1
+ Copyright (c) 2010-2015 Amro Mousa
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -9,9 +9,8 @@ Gibbon is an API wrapper for MailChimp's [Primary and Export APIs](http://www.ma
9
9
  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.
10
10
 
11
11
  * Supports MailChimp API 2.0 and Export API 1.0
12
- * Errors are raised by default since 0.4.x
12
+ * Errors are raised by default
13
13
  * Timeouts can be specified per request during initialization
14
- * Ruby 1.9.3+ for now. A future version may be Ruby 2.0 only to take advantage of lazy iteration when using the Export API.
15
14
 
16
15
  ##Installation
17
16
 
@@ -190,7 +189,26 @@ of JSON objects rather than a single JSON array.
190
189
 
191
190
  For example, dumping list members via the "list" method works like this:
192
191
 
193
- gibbon_export.list({:id => list_id})
192
+ gibbon_export.list({:id => *list_id*})
193
+
194
+ One can also use this in a streaming fashion, where each row is parsed on it comes in like this:
195
+
196
+ gibbon_export.list({:id => *list_id*}) { |row| *do_sth_with* row }
197
+
198
+ For the streaming functionality, it is important to supply an explicit block / procedure to the export functions, not an implicit one. So, the preceding and following one will work. Please note this method also includes a counter (*i*, starting at 0) telling which row of data you're receiving:
199
+ ```
200
+ method = Proc.new do |row, i|
201
+ *do_sth_with* row
202
+ end
203
+ gibbon_export.list(params, &method)
204
+ ```
205
+
206
+ Please note, the following example gives a block that is outside of the function and therefore **won't** work:
207
+ ```
208
+ gibbon_export.list({:id => *list_id*}) do |row|
209
+ *do_sth_with* row
210
+ end
211
+ ```
194
212
 
195
213
  ##Thanks
196
214
 
@@ -198,5 +216,5 @@ Thanks to everyone who's [contributed](https://github.com/amro/gibbon/contributo
198
216
 
199
217
  ##Copyright
200
218
 
201
- * Copyright (c) 2010-2014 Amro Mousa. See LICENSE.txt for details.
202
- * MailChimp (c) 2001-2014 The Rocket Science Group.
219
+ * Copyright (c) 2010-2015 Amro Mousa. See LICENSE.txt for details.
220
+ * MailChimp (c) 2001-2015 The Rocket Science Group.
@@ -1,9 +1,10 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  $:.push File.expand_path("../lib", __FILE__)
3
+ require 'gibbon/version'
3
4
 
4
5
  Gem::Specification.new do |s|
5
6
  s.name = "gibbon"
6
- s.version = "1.1.5"
7
+ s.version = Gibbon::VERSION
7
8
  s.authors = ["Amro Mousa"]
8
9
  s.email = ["amromousa@gmail.com"]
9
10
  s.homepage = "http://github.com/amro/gibbon"
@@ -27,27 +27,26 @@ module Gibbon
27
27
  headers = params.delete(:headers) || {}
28
28
  response = self.class.post(api_url, :body => MultiJson.dump(params), :headers => headers, :timeout => @timeout)
29
29
 
30
- parsed_response = nil
31
-
32
- if (response.body)
33
- begin
34
- parsed_response = MultiJson.load(response.body)
35
- rescue MultiJson::ParseError
36
- parsed_response = {
37
- "error" => "Unparseable response: #{response.body}",
38
- "name" => "UNPARSEABLE_RESPONSE",
39
- "code" => 500
40
- }
41
- end
42
-
43
- if should_raise_for_response?(parsed_response)
44
- error = MailChimpError.new(parsed_response["error"])
45
- error.code = parsed_response["code"]
46
- error.name = parsed_response["name"]
47
- raise error
48
- end
30
+ parse_response(response.body) if response.body
31
+ end
32
+
33
+ def parse_response(response, check_error = true)
34
+ begin
35
+ parsed_response = MultiJson.load(response)
36
+ rescue MultiJson::ParseError
37
+ parsed_response = {
38
+ "error" => "Unparseable response: #{response}",
39
+ "name" => "UNPARSEABLE_RESPONSE",
40
+ "code" => 500
41
+ }
49
42
  end
50
43
 
44
+ if should_raise_for_response?(parsed_response)
45
+ error = MailChimpError.new(parsed_response["error"])
46
+ error.code = parsed_response["code"]
47
+ error.name = parsed_response["name"]
48
+ raise error
49
+ end
51
50
  parsed_response
52
51
  end
53
52
 
@@ -61,7 +60,7 @@ module Gibbon
61
60
  if ((args.length > 0) && args[0].is_a?(Hash))
62
61
  method_missing(:send, args[0])
63
62
  else
64
- __send__(args)
63
+ __send__(*args)
65
64
  end
66
65
  end
67
66
 
@@ -100,7 +99,6 @@ module Gibbon
100
99
  data_center
101
100
  end
102
101
 
103
-
104
102
  private
105
103
 
106
104
  def ensure_api_key(params)
@@ -14,37 +14,51 @@ module Gibbon
14
14
  "http://#{get_data_center_from_api_key}api.mailchimp.com/export/1.0/"
15
15
  end
16
16
 
17
- def call(method, params = {})
18
- ensure_api_key params
17
+ # fsluis: Alternative, streaming, interface to mailchimp export api
18
+ # Prevents having to keep lots of data in memory
19
+ def call(method, params = {}, &block)
20
+ rows = []
19
21
 
20
22
  api_url = export_api_url + method + "/"
21
23
  params = @default_params.merge(params).merge({:apikey => @api_key})
22
- response = self.class.post(api_url, :body => MultiJson.dump(params), :timeout => @timeout)
23
-
24
- lines = response.body.lines
25
- if @throws_exceptions
26
- # ignore blank responses
27
- return [] if !lines.first || lines.first.strip.empty?
28
-
29
- first_line = MultiJson.load(lines.first) if lines.first
24
+ block = Proc.new { |row| rows << row } unless block_given?
25
+ ensure_api_key params
30
26
 
31
- if should_raise_for_response?(first_line)
32
- error = MailChimpError.new(first_line["error"])
33
- error.code = first_line["code"]
34
- raise error
27
+ url = URI.parse(api_url)
28
+ req = Net::HTTP::Post.new(url.path, initheader = {'Content-Type' => 'application/json'})
29
+ req.body = MultiJson.dump(params)
30
+ Net::HTTP.start(url.host, url.port, :read_timeout => @timeout) do |http|
31
+ # http://stackoverflow.com/questions/29598196/ruby-net-http-read-body-nethttpokread-body-called-twice-ioerror
32
+ http.request req do |response|
33
+ i = -1
34
+ last = ''
35
+ response.read_body do |chunk|
36
+ next if chunk.nil? or chunk.strip.empty?
37
+ lines = (last+chunk).split("\n")
38
+ last = lines.pop || ''
39
+ lines.each do |line|
40
+ block.call(parse_response(line, i < 0), i += 1) unless line.nil?
41
+ end
42
+ end
43
+ block.call(parse_response(last, i < 0), i += 1) unless last.nil? or last.empty?
35
44
  end
36
45
  end
46
+ rows unless block_given?
47
+ end
37
48
 
38
- lines
49
+ def parse_response(res, check_error)
50
+ return [] if res.strip.empty?
51
+ super(res, check_error)
39
52
  end
40
53
 
41
54
  def set_instance_defaults
42
- super
43
55
  @api_key = self.class.api_key if @api_key.nil?
44
56
  @timeout = self.class.timeout if @timeout.nil?
57
+ super
45
58
  end
46
59
 
47
- def method_missing(method, *args)
60
+ # fsluis: added a &block to this method and function call
61
+ def method_missing(method, *args, &block)
48
62
  # To support underscores, we camelize the method name
49
63
 
50
64
  # Thanks for the camelize gsub, Rails
@@ -55,16 +69,25 @@ module Gibbon
55
69
  # must be upcased (See "Campaign Report Data Methods" in their API docs).
56
70
  method = method[0].chr.downcase + method[1..-1].gsub(/aim$/i, 'AIM')
57
71
 
58
- call(method, *args)
72
+ call(method, *args, &block)
59
73
  end
60
74
 
61
75
  def respond_to_missing?(method, include_private = false)
62
76
  %w{list ecommOrders ecomm_orders campaignSubscriberActivity campaign_subscriber_activity}.include?(method.to_s) || super
63
77
  end
64
78
 
65
-
66
79
  private
67
80
 
81
+ def split_json(lines, delimiter)
82
+ lines.map do |line|
83
+ if line.include? delimiter
84
+ line.split(delimiter).each_with_index.map{ |s, i| i % 2 == 0 ? s + delimiter[0] : delimiter[1] + s }
85
+ else
86
+ line
87
+ end
88
+ end.flatten
89
+ end
90
+
68
91
  def ensure_api_key(params)
69
92
  unless @api_key || @default_params[:apikey] || params[:apikey]
70
93
  raise Gibbon::GibbonError, "You must set an api_key prior to making a call"
@@ -0,0 +1,3 @@
1
+ module Gibbon
2
+ VERSION = "1.2.0"
3
+ end
@@ -1,5 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'cgi'
3
+ require 'webmock'
4
+ require 'webmock/rspec'
3
5
 
4
6
  describe Gibbon do
5
7
 
@@ -229,7 +231,8 @@ describe Gibbon do
229
231
  @gibbon = Gibbon::Export.new(@key)
230
232
  @url = "http://us1.api.mailchimp.com/export/1.0/"
231
233
  @body = {:apikey => @key, :id => "listid"}
232
- @returns = Struct.new(:body).new(MultiJson.dump(["array", "entries"]))
234
+ @return_items = ["array", "entries"]
235
+ @returns = MultiJson.dump(@return_items)
233
236
  end
234
237
 
235
238
  it "handle api key with dc" do
@@ -237,43 +240,70 @@ describe Gibbon do
237
240
  @gibbon = Gibbon::Export.new(@api_key)
238
241
 
239
242
  @body[:apikey] = @api_key
240
- params = {:body => MultiJson.dump(@body), :timeout => 30}
241
-
242
243
  url = @url.gsub('us1', 'us2') + "sayHello/"
243
- expect(Gibbon::Export).to receive(:post).with(url, params).and_return(@returns)
244
+
245
+ # Fake request
246
+ stub_request(:post, url).
247
+ to_return(:body => @returns, :status => 200)
248
+
249
+ # Check request url
244
250
  @gibbon.say_hello(@body)
251
+ expect(WebMock).to have_requested(:post, url).with(:body => @body)
252
+ end
253
+
254
+ it "uses timeout if set" do
255
+ Gibbon::Export.timeout = 45
256
+ expect(Gibbon::Export.new.timeout).to eql 45
245
257
  end
246
258
 
247
259
  it "not throw exception if the Export API replies with a JSON hash containing a key called 'error'" do
248
260
  @gibbon.throws_exceptions = false
249
- allow(Gibbon::Export).to receive(:post).and_return(Struct.new(:body).new(MultiJson.dump({'error' => 'bad things'})))
261
+ reply = MultiJson.dump({:error => 'bad things'})
262
+ stub_request(:post, @url + 'sayHello/').
263
+ to_return(:body => reply, :status => 200)
250
264
 
251
265
  @gibbon.say_hello(@body)
252
266
  end
253
267
 
254
268
  it "throw exception if configured to and the Export API replies with a JSON hash containing a key called 'error'" do
255
269
  @gibbon.throws_exceptions = true
256
- params = {:body => @body, :timeout => 30}
257
- reply = Struct.new(:body).new MultiJson.dump({'error' => 'bad things', 'code' => '123'})
258
- allow(Gibbon::Export).to receive(:post).and_return reply
270
+ reply = MultiJson.dump({:error => 'bad things', :code => '123'})
271
+ stub_request(:post, @url + 'sayHello/').
272
+ to_return(:body => reply, :status => 200)
259
273
 
260
274
  expect {@gibbon.say_hello(@body)}.to raise_error(Gibbon::MailChimpError)
261
275
  end
262
276
 
263
277
  it "should handle a single empty space response without throwing an exception" do
264
278
  @gibbon.throws_exceptions = true
265
- allow(Gibbon::Export).to receive(:post).and_return(Struct.new(:body).new(" "))
279
+ stub_request(:post, @url + 'sayHello/').
280
+ to_return(:body => " ", :status => 200)
281
+ #allow(Gibbon::Export).to receive(:post).and_return(Struct.new(:body).new(" "))
266
282
 
267
283
  expect(@gibbon.say_hello(@body)).to eq([])
268
284
  end
269
285
 
270
286
  it "should handle an empty response without throwing an exception" do
271
287
  @gibbon.throws_exceptions = true
272
- allow(Gibbon::Export).to receive(:post).and_return(Struct.new(:body).new(""))
288
+ stub_request(:post, @url + 'sayHello/').
289
+ to_return(:body => "", :status => 200)
290
+ #allow(Gibbon::Export).to receive(:post).and_return(Struct.new(:body).new(""))
273
291
 
274
292
  expect(@gibbon.say_hello(@body)).to eq([])
275
293
  end
276
294
 
295
+ it "should feed API results per row to a given block" do
296
+ # Fake request
297
+ stub_request(:post, @url + 'sayHello/').
298
+ to_return(:body => @returns, :status => 200)
299
+
300
+ # Check request url
301
+ @result = []
302
+ @gibbon.say_hello(@body) { |res| @result << res }
303
+ expect(@result).to contain_exactly(@return_items)
304
+ end
305
+
306
+
277
307
  end
278
308
 
279
309
  private
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gibbon
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.5
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amro Mousa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-19 00:00:00.000000000 Z
11
+ date: 2015-07-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -88,6 +88,7 @@ files:
88
88
  - lib/gibbon/export.rb
89
89
  - lib/gibbon/gibbon_error.rb
90
90
  - lib/gibbon/mailchimp_error.rb
91
+ - lib/gibbon/version.rb
91
92
  - spec/gibbon/gibbon_spec.rb
92
93
  - spec/spec_helper.rb
93
94
  homepage: http://github.com/amro/gibbon
@@ -113,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
114
  version: '0'
114
115
  requirements: []
115
116
  rubyforge_project: gibbon
116
- rubygems_version: 2.3.0
117
+ rubygems_version: 2.4.6
117
118
  signing_key:
118
119
  specification_version: 4
119
120
  summary: A wrapper for MailChimp API 2.0 and Export API 1.0