gibbon 4.0.0 → 4.0.1
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.
- checksums.yaml +4 -4
- data/.document +3 -3
- data/.github/workflows/ci.yml +18 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +5 -0
- data/README.markdown +114 -66
- data/gibbon.gemspec +12 -1
- data/lib/gibbon/api_request.rb +25 -0
- data/lib/gibbon/gibbon_error.rb +3 -0
- data/lib/gibbon/gibbon_helpers.rb +9 -2
- data/lib/gibbon/mailchimp_error.rb +20 -1
- data/lib/gibbon/request.rb +94 -3
- data/lib/gibbon/response.rb +15 -2
- data/lib/gibbon/version.rb +2 -1
- data/lib/gibbon.rb +1 -0
- data/spec/gibbon/api_request_spec.rb +44 -0
- data/spec/gibbon/gibbon_spec.rb +16 -0
- metadata +40 -5
- data/.travis.yml +0 -23
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 421fe35f5c093158bac5d59d0a684325e8b77888257b6758fd805d9c86608520
|
|
4
|
+
data.tar.gz: cd15c1fa018171363d7fe32c6dddbe14e14985ed02ca1cbdcb313240e39c1640
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0da6bfbdd8f9bff5ffbeac3943f3c3f571204b9a38869dfa2e75cba7bc1ba2863aa7dcdcb82e3167b54ed9dd0222d118a7b74606b2d7d8f92ec8fc8681529d24
|
|
7
|
+
data.tar.gz: 0ff34fa92007f022b7faf7368cf1285ed995efa43e964b0328928e8c466bc1661d0cdc0a32f0fed612e4cb5d54deaba74dfdfecae5dc264e4215ddb4bfc39ddf
|
data/.document
CHANGED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on: [push, pull_request]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
test:
|
|
7
|
+
runs-on: ubuntu-latest
|
|
8
|
+
strategy:
|
|
9
|
+
fail-fast: false
|
|
10
|
+
matrix:
|
|
11
|
+
ruby: ['3.1', '3.2', '3.3', '3.4', '4.0']
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v5
|
|
14
|
+
- uses: ruby/setup-ruby@v1
|
|
15
|
+
with:
|
|
16
|
+
ruby-version: ${{ matrix.ruby }}
|
|
17
|
+
bundler-cache: true
|
|
18
|
+
- run: bundle exec rake
|
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
## [4.0.1] - 2026-10-23
|
|
2
|
+
- Honor explicit `false` instance overrides for `symbolize_keys` and `debug`, while preserving class defaults for omitted options and `nil`.
|
|
3
|
+
- Constrain `json` to versions below 3.0 to preserve compatibility with the `multi_json` adapter available on Ruby 3.1.
|
|
4
|
+
- Expand API documentation, update usage examples, and add gem metadata links.
|
|
5
|
+
|
|
1
6
|
## [4.0.0] - 2026-07-23
|
|
2
7
|
- Require Ruby 3.1+ (drops support for EOL Rubies 2.4 through 3.0)
|
|
3
8
|
- Require TLS 1.2 as a minimum instead of pinning it exactly, allowing TLS 1.3
|
data/README.markdown
CHANGED
|
@@ -2,21 +2,32 @@
|
|
|
2
2
|
|
|
3
3
|
Gibbon is an API wrapper for MailChimp's [API](https://mailchimp.com/developer/marketing/api/).
|
|
4
4
|
|
|
5
|
-
[](https://github.com/amro/gibbon/actions/workflows/ci.yml)
|
|
6
6
|
|
|
7
7
|
## Important Notes
|
|
8
8
|
|
|
9
9
|
Please read MailChimp's [Getting Started Guide](https://mailchimp.com/developer/marketing/guides/quick-start/).
|
|
10
10
|
|
|
11
|
-
Gibbon
|
|
11
|
+
Gibbon returns a `Gibbon::Response`, which exposes the parsed response `body` and the response `headers`. See [Responses](#responses) below.
|
|
12
|
+
|
|
13
|
+
See the [CHANGELOG](CHANGELOG.md) for release history and [Upgrading](#upgrading) for breaking changes.
|
|
12
14
|
|
|
13
15
|
## Installation
|
|
14
16
|
|
|
15
17
|
$ gem install gibbon
|
|
16
18
|
|
|
19
|
+
Or add it to your `Gemfile`:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
gem "gibbon"
|
|
23
|
+
```
|
|
24
|
+
|
|
17
25
|
## Requirements
|
|
18
26
|
|
|
19
|
-
|
|
27
|
+
* **Ruby 3.1 or newer.** Gibbon 4.0 dropped support for Ruby 2.4 through 3.0.
|
|
28
|
+
* A MailChimp account and API key. You can see your API keys [here](https://admin.mailchimp.com/account/api).
|
|
29
|
+
|
|
30
|
+
Gibbon depends on [Faraday](https://github.com/lostisland/faraday) (both 1.x and 2.x are supported) and [MultiJson](https://github.com/intridea/multi_json). Connections to MailChimp negotiate TLS 1.2 or newer.
|
|
20
31
|
|
|
21
32
|
## Usage
|
|
22
33
|
|
|
@@ -26,7 +37,7 @@ First, create a *one-time use instance* of `Gibbon::Request`:
|
|
|
26
37
|
gibbon = Gibbon::Request.new(api_key: "your_api_key")
|
|
27
38
|
```
|
|
28
39
|
|
|
29
|
-
***Note*** Only reuse instances of Gibbon after terminating a call with a verb, which makes a request. Requests are light weight objects that update an internal path based on your call chain. When you terminate a call chain with a verb, a request instance makes a request and resets the path.
|
|
40
|
+
***Note*** Only reuse instances of Gibbon after terminating a call with a verb, which makes a request. Requests are light weight objects that update an internal path based on your call chain. When you terminate a call chain with a verb, a request instance makes a request and resets the path. See [How call chains build paths](#how-call-chains-build-paths).
|
|
30
41
|
|
|
31
42
|
You can set an individual request's `timeout` and `open_timeout` like this:
|
|
32
43
|
|
|
@@ -40,7 +51,15 @@ You can read about `timeout` and `open_timeout` in the [Net::HTTP](https://docs.
|
|
|
40
51
|
Now you can make requests using the resources defined in [MailChimp's docs](https://mailchimp.com/developer/marketing/api/). Resource IDs
|
|
41
52
|
are specified inline and a `CRUD` (`create`, `retrieve` (or `get`), `update`, `upsert`, or `delete`) verb initiates the request. `upsert` lets you update a record, if it exists, or insert it otherwise where supported by MailChimp's API.
|
|
42
53
|
|
|
43
|
-
|
|
54
|
+
Each verb maps to an HTTP method:
|
|
55
|
+
|
|
56
|
+
| Gibbon verb | HTTP method | Accepts `body` |
|
|
57
|
+
| --------------------- | ----------- | -------------- |
|
|
58
|
+
| `create` | `POST` | yes |
|
|
59
|
+
| `retrieve` (or `get`) | `GET` | no |
|
|
60
|
+
| `update` | `PATCH` | yes |
|
|
61
|
+
| `upsert` | `PUT` | yes |
|
|
62
|
+
| `delete` | `DELETE` | no |
|
|
44
63
|
|
|
45
64
|
You can specify `headers`, `params`, and `body` when calling a `CRUD` method. For example:
|
|
46
65
|
|
|
@@ -48,8 +67,6 @@ You can specify `headers`, `params`, and `body` when calling a `CRUD` method. Fo
|
|
|
48
67
|
gibbon.lists.retrieve(headers: {"SomeHeader": "SomeHeaderValue"}, params: {"query_param": "query_param_value"})
|
|
49
68
|
```
|
|
50
69
|
|
|
51
|
-
***Note*** `get` can be substituted for `retrieve` as of Gibbon version 3.4.1 or newer!
|
|
52
|
-
|
|
53
70
|
Of course, `body` is only supported on `create`, `update`, and `upsert` calls. Those map to HTTP `POST`, `PATCH`, and `PUT` verbs respectively.
|
|
54
71
|
|
|
55
72
|
You can set `api_key`, `timeout`, `open_timeout`, `faraday_adapter`, `proxy`, `symbolize_keys`, `logger`, and `debug` globally:
|
|
@@ -76,8 +93,6 @@ You can also set the environment variable `MAILCHIMP_API_KEY` and Gibbon will us
|
|
|
76
93
|
gibbon = Gibbon::Request.new
|
|
77
94
|
```
|
|
78
95
|
|
|
79
|
-
***Note*** Substitute an underscore if a resource name contains a hyphen.
|
|
80
|
-
|
|
81
96
|
Pass `symbolize_keys: true` to use symbols (instead of strings) as hash keys in API responses.
|
|
82
97
|
|
|
83
98
|
```ruby
|
|
@@ -86,6 +101,57 @@ gibbon = Gibbon::Request.new(api_key: "your_api_key", symbolize_keys: true)
|
|
|
86
101
|
|
|
87
102
|
MailChimp's [resource documentation](https://mailchimp.com/developer/marketing/api/) is a list of available resources.
|
|
88
103
|
|
|
104
|
+
## How call chains build paths
|
|
105
|
+
|
|
106
|
+
`Gibbon::Request` defines no methods for MailChimp's resources. Any unknown method appends a segment to an internal path and returns the same object; a CRUD verb turns the accumulated path into a request. So `gibbon.lists(list_id).members.retrieve` builds `lists/<list_id>/members` and issues a `GET`.
|
|
107
|
+
|
|
108
|
+
Three consequences are worth knowing.
|
|
109
|
+
|
|
110
|
+
**Underscores become hyphens.** Segments containing a hyphen aren't valid Ruby method names, so write them with underscores and Gibbon converts:
|
|
111
|
+
|
|
112
|
+
```ruby
|
|
113
|
+
gibbon.lists(list_id).members(subscriber_hash).actions.delete_permanent.create
|
|
114
|
+
# POST lists/<list_id>/members/<subscriber_hash>/actions/delete-permanent
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**`send` is special cased.** `Object#send` would otherwise shadow the path segment, so `Gibbon::Request#send` falls through to path building when called with no arguments. That's what makes sending a campaign work:
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
gibbon.campaigns(campaign_id).actions.send.create
|
|
121
|
+
# POST campaigns/<campaign_id>/actions/send
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Called *with* arguments, `send` keeps its usual Ruby meaning and invokes the named method.
|
|
125
|
+
|
|
126
|
+
**An instance is reusable only after a verb.** The path resets when a verb runs, not when a chain goes out of scope. Abandoning a chain leaves its segments in place and corrupts the next call:
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
gibbon = Gibbon::Request.new(api_key: "your_api_key")
|
|
130
|
+
|
|
131
|
+
gibbon.lists # no verb, so nothing is sent and nothing is reset
|
|
132
|
+
gibbon.campaigns.retrieve # GET lists/campaigns -- not what you wanted
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Use a fresh instance per chain unless you know the previous one ended in a verb.
|
|
136
|
+
|
|
137
|
+
## Responses
|
|
138
|
+
|
|
139
|
+
Every CRUD verb returns a `Gibbon::Response` with two attributes:
|
|
140
|
+
|
|
141
|
+
* `body` — the parsed JSON response, as a `Hash` (or `Array`, depending on the endpoint)
|
|
142
|
+
* `headers` — the response headers, keyed by lower case string
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
response = gibbon.lists.retrieve
|
|
146
|
+
|
|
147
|
+
response.body["lists"] # => [{"id" => "...", "name" => "...", ...}, ...]
|
|
148
|
+
response.headers["content-type"] # => "application/json; charset=utf-8"
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`body` respects `symbolize_keys`; `headers` keys are always strings.
|
|
152
|
+
|
|
153
|
+
A response with an empty body — as with a successful `delete`, which MailChimp answers with `204 No Content` — returns `nil` rather than a `Gibbon::Response`.
|
|
154
|
+
|
|
89
155
|
## Debug Logging
|
|
90
156
|
|
|
91
157
|
Pass `debug: true` to enable debug logging to STDOUT.
|
|
@@ -96,7 +162,7 @@ gibbon = Gibbon::Request.new(api_key: "your_api_key", debug: true)
|
|
|
96
162
|
|
|
97
163
|
### Custom logger
|
|
98
164
|
|
|
99
|
-
Ruby `Logger.new` is used by default, but it can be
|
|
165
|
+
Ruby `Logger.new` is used by default, but it can be overridden using:
|
|
100
166
|
|
|
101
167
|
```ruby
|
|
102
168
|
gibbon = Gibbon::Request.new(api_key: "your_api_key", debug: true, logger: MyLogger.new)
|
|
@@ -268,7 +334,7 @@ campaigns = gibbon.campaigns.retrieve
|
|
|
268
334
|
Fetch the number of opens for a campaign
|
|
269
335
|
|
|
270
336
|
```ruby
|
|
271
|
-
email_stats = gibbon.reports(campaign_id).retrieve["opens"]
|
|
337
|
+
email_stats = gibbon.reports(campaign_id).retrieve.body["opens"]
|
|
272
338
|
```
|
|
273
339
|
|
|
274
340
|
Create a new campaign:
|
|
@@ -337,7 +403,7 @@ gibbon.campaigns(campaign_id).actions.schedule.create(body: body)
|
|
|
337
403
|
|
|
338
404
|
### Interests
|
|
339
405
|
|
|
340
|
-
Interests are a little more complicated than other parts of the API, so here's an example of how you would set interests
|
|
406
|
+
Interests are a little more complicated than other parts of the API, so here's an example of how you would set interests at subscription time or update them later. The ID of the interests you want to opt in or out of must be known ahead of time so an example of how to find interest IDs is also included.
|
|
341
407
|
|
|
342
408
|
Subscribing a member to a list with specific interests up front:
|
|
343
409
|
|
|
@@ -357,13 +423,13 @@ So how do we get the interest IDs? When you query the API for a specific list me
|
|
|
357
423
|
gibbon.lists(list_id).members(member_id).retrieve
|
|
358
424
|
```
|
|
359
425
|
|
|
360
|
-
The response body (i.e. `response.body`) looks
|
|
426
|
+
The response body (i.e. `response.body`) looks something like this (unrelated things removed):
|
|
361
427
|
|
|
362
428
|
```ruby
|
|
363
429
|
{"id"=>"...", "email_address"=>"...", ..., "interests"=>{"3def637141"=>true, "f7cc4ee841"=>false, "fcdc951b9f"=>false, "3daf3cf27d"=>true, "293a3703ed"=>false, "72370e0d1f"=>false, "d434d21a1c"=>false, "bdb1ff199f"=>false, "a54e78f203"=>false, "c4527fd018"=>false} ...}
|
|
364
430
|
```
|
|
365
431
|
|
|
366
|
-
The API returns a map of interest ID to boolean value. Now we to get interest details so we know what these interest IDs map to. Looking at [this doc page](https://mailchimp.com/developer/marketing/api/interests/), we need to do this:
|
|
432
|
+
The API returns a map of interest ID to boolean value. Now we need to get interest details so we know what these interest IDs map to. Looking at [this doc page](https://mailchimp.com/developer/marketing/api/interests/), we need to do this:
|
|
367
433
|
|
|
368
434
|
```ruby
|
|
369
435
|
gibbon.lists(list_id).interest_categories.retrieve
|
|
@@ -383,21 +449,6 @@ gibbon.lists(list_id).interest_categories("0ace7aa498").interests.retrieve
|
|
|
383
449
|
|
|
384
450
|
That response gives the interest data, including the ID for the interests themselves, which we can use to update a list member's interests or set them when we call the API to subscribe her or him to a list.
|
|
385
451
|
|
|
386
|
-
### Error handling
|
|
387
|
-
|
|
388
|
-
Gibbon raises an error when the API returns an error.
|
|
389
|
-
|
|
390
|
-
`Gibbon::MailChimpError` has the following attributes: `title`, `detail`, `body`, `raw_body`, `status_code`. Some or all of these may not be
|
|
391
|
-
available depending on the nature of the error. For example:
|
|
392
|
-
|
|
393
|
-
```ruby
|
|
394
|
-
begin
|
|
395
|
-
gibbon.lists(list_id).members.create(body: body)
|
|
396
|
-
rescue Gibbon::MailChimpError => e
|
|
397
|
-
puts "Houston, we have a problem: #{e.message} - #{e.raw_body}"
|
|
398
|
-
end
|
|
399
|
-
```
|
|
400
|
-
|
|
401
452
|
### Other
|
|
402
453
|
|
|
403
454
|
Overriding Gibbon's API endpoint (i.e. if using an access token from OAuth and have the `api_endpoint` from the [metadata](https://mailchimp.com/developer/marketing/guides/access-user-data-oauth-2/)):
|
|
@@ -419,73 +470,70 @@ You can set a different [Faraday adapter](https://github.com/lostisland/faraday)
|
|
|
419
470
|
gibbon = Gibbon::Request.new(api_key: "your_api_key", faraday_adapter: :net_http)
|
|
420
471
|
```
|
|
421
472
|
|
|
422
|
-
|
|
473
|
+
## Error handling
|
|
423
474
|
|
|
424
|
-
Gibbon
|
|
475
|
+
Gibbon raises two error types, both subclasses of `StandardError`.
|
|
425
476
|
|
|
426
|
-
|
|
477
|
+
### Gibbon::GibbonError
|
|
427
478
|
|
|
428
|
-
Gibbon
|
|
479
|
+
Raised *before* a request goes out, when Gibbon can't tell where to send it. In practice that means the API key is missing, or it carries no data center suffix and no `api_endpoint` was set:
|
|
429
480
|
|
|
430
481
|
```ruby
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
Gibbon 2.x+:
|
|
482
|
+
Gibbon::Request.new.lists.retrieve
|
|
483
|
+
# => Gibbon::GibbonError: You must set an api_key prior to making a call
|
|
435
484
|
|
|
436
|
-
|
|
437
|
-
|
|
485
|
+
Gibbon::Request.new(api_key: "your_api_key").lists.retrieve
|
|
486
|
+
# => Gibbon::GibbonError: You must set an api_key prior to making a call
|
|
438
487
|
```
|
|
439
488
|
|
|
440
|
-
|
|
489
|
+
A key like `your_api_key-us1` carries its data center (`us1`) and works on its own. Access tokens obtained through OAuth do not, so pass `api_endpoint` alongside them — see [Other](#other) above.
|
|
441
490
|
|
|
442
|
-
|
|
491
|
+
### Gibbon::MailChimpError
|
|
443
492
|
|
|
444
|
-
|
|
493
|
+
Raised when a request fails. It exposes `title`, `detail`, `body`, `raw_body`, and `status_code`:
|
|
445
494
|
|
|
446
495
|
```ruby
|
|
447
|
-
|
|
496
|
+
begin
|
|
497
|
+
gibbon.lists(list_id).members.create(body: body)
|
|
498
|
+
rescue Gibbon::MailChimpError => e
|
|
499
|
+
puts "Houston, we have a problem: #{e.message} - #{e.raw_body}"
|
|
500
|
+
end
|
|
448
501
|
```
|
|
449
502
|
|
|
450
|
-
|
|
503
|
+
Some or all of those attributes may be `nil` depending on the nature of the failure. MailChimp returning a `4xx` or `5xx` populates all of them from the error document. A transport level failure — a timeout, a refused connection — has no response to read, so only `message` is set.
|
|
451
504
|
|
|
452
|
-
|
|
453
|
-
gibbon.lists.retrieve
|
|
454
|
-
```
|
|
505
|
+
Gibbon also raises `Gibbon::MailChimpError` when a *successful* response body isn't valid JSON. That error has a `title` of `"UNPARSEABLE_RESPONSE"` and a `status_code` of `500`, and its message includes the raw body.
|
|
455
506
|
|
|
456
|
-
|
|
507
|
+
## Upgrading
|
|
457
508
|
|
|
458
|
-
|
|
509
|
+
Full release history lives in the [CHANGELOG](CHANGELOG.md). The breaking changes are summarized here.
|
|
459
510
|
|
|
460
|
-
|
|
461
|
-
gibbon.lists.members({:id => list_id})
|
|
462
|
-
```
|
|
511
|
+
### Upgrading to 4.0
|
|
463
512
|
|
|
464
|
-
Gibbon
|
|
513
|
+
Gibbon 4.0 contains no API changes. It changes what it runs on:
|
|
465
514
|
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
```
|
|
515
|
+
* **Ruby 3.1 or newer is required.** Rubies 2.4 through 3.0 are EOL and are no longer supported. If you are on an older Ruby, stay on Gibbon 3.5.0.
|
|
516
|
+
* **TLS 1.2 is now a minimum rather than an exact pin.** Connections previously negotiated exactly TLS 1.2; they now accept TLS 1.3 as well. No code change is needed, but if you inspect the negotiated protocol in tests or middleware, expect 1.3.
|
|
469
517
|
|
|
470
|
-
|
|
518
|
+
### Upgrading to 3.0
|
|
471
519
|
|
|
472
|
-
Gibbon
|
|
520
|
+
`create`, `retrieve`/`get`, `update`, `upsert`, and `delete` return a `Gibbon::Response` rather than the parsed body. Add `.body`:
|
|
473
521
|
|
|
474
522
|
```ruby
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
Gibbon 2.x+:
|
|
523
|
+
# Gibbon 2.x
|
|
524
|
+
gibbon.lists.retrieve["lists"]
|
|
479
525
|
|
|
480
|
-
|
|
481
|
-
gibbon.lists
|
|
526
|
+
# Gibbon 3.x and newer
|
|
527
|
+
gibbon.lists.retrieve.body["lists"]
|
|
482
528
|
```
|
|
483
529
|
|
|
530
|
+
In exchange you also get `.headers`, which carries MailChimp's rate limit and content metadata. See [Responses](#responses).
|
|
531
|
+
|
|
484
532
|
## Thanks
|
|
485
533
|
|
|
486
534
|
Thanks to everyone who has [contributed](https://github.com/amro/gibbon/contributors) to Gibbon's development.
|
|
487
535
|
|
|
488
536
|
## Copyright
|
|
489
537
|
|
|
490
|
-
* Copyright (c) 2010-
|
|
491
|
-
* MailChimp (c) 2001-
|
|
538
|
+
* Copyright (c) 2010-2026 Amro Mousa. See LICENSE.txt for details.
|
|
539
|
+
* MailChimp (c) 2001-2026 The Rocket Science Group.
|
data/gibbon.gemspec
CHANGED
|
@@ -10,9 +10,16 @@ Gem::Specification.new do |s|
|
|
|
10
10
|
s.homepage = "https://github.com/amro/gibbon"
|
|
11
11
|
|
|
12
12
|
s.summary = %q{A wrapper for MailChimp API 3.0}
|
|
13
|
-
s.description = %q{
|
|
13
|
+
s.description = %q{Gibbon is a Ruby wrapper for MailChimp's Marketing API (version 3.0). Ruby method chains map onto API resource paths, so every documented resource is reachable without waiting on a gem update.}
|
|
14
14
|
s.license = "MIT"
|
|
15
15
|
|
|
16
|
+
s.metadata = {
|
|
17
|
+
"source_code_uri" => "https://github.com/amro/gibbon",
|
|
18
|
+
"changelog_uri" => "https://github.com/amro/gibbon/blob/master/CHANGELOG.md",
|
|
19
|
+
"bug_tracker_uri" => "https://github.com/amro/gibbon/issues",
|
|
20
|
+
"documentation_uri" => "https://rubydoc.info/gems/gibbon"
|
|
21
|
+
}
|
|
22
|
+
|
|
16
23
|
s.files = `git ls-files`.split("\n")
|
|
17
24
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
18
25
|
s.require_paths = ["lib"]
|
|
@@ -20,9 +27,13 @@ Gem::Specification.new do |s|
|
|
|
20
27
|
|
|
21
28
|
s.add_dependency('faraday', '>= 1.0')
|
|
22
29
|
s.add_dependency('multi_json', '>= 1.11.0')
|
|
30
|
+
# Ruby 3.1 uses multi_json <= 1.19.1, whose JSON adapter passes options
|
|
31
|
+
# positionally. JSON 3 requires keyword arguments.
|
|
32
|
+
s.add_dependency('json', '< 3.0')
|
|
23
33
|
|
|
24
34
|
s.add_development_dependency 'rake'
|
|
25
35
|
s.add_development_dependency "rspec", "~> 3.13"
|
|
26
36
|
s.add_development_dependency 'webmock', '~> 3.8'
|
|
37
|
+
s.add_development_dependency 'yard', '~> 0.9'
|
|
27
38
|
|
|
28
39
|
end
|
data/lib/gibbon/api_request.rb
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
module Gibbon
|
|
2
|
+
# Carries out the HTTP request described by a {Request}.
|
|
3
|
+
#
|
|
4
|
+
# This is an implementation detail of {Request}, which constructs one per
|
|
5
|
+
# call and reads its own configuration back out of it. Use {Request}'s CRUD
|
|
6
|
+
# verbs rather than instantiating this directly.
|
|
2
7
|
class APIRequest
|
|
3
8
|
include Helpers
|
|
4
9
|
|
|
10
|
+
# @param builder [Request] the request whose path and configuration to use
|
|
5
11
|
def initialize(builder: nil)
|
|
6
12
|
@request_builder = builder
|
|
7
13
|
end
|
|
8
14
|
|
|
15
|
+
# @param params [Hash, nil] query string parameters
|
|
16
|
+
# @param headers [Hash, nil] additional request headers
|
|
17
|
+
# @param body [Hash, nil] request body, serialized to JSON
|
|
18
|
+
# @return [Response, nil] the response, or nil when the body is empty
|
|
19
|
+
# @raise [GibbonError] if no usable API key is configured
|
|
20
|
+
# @raise [MailChimpError] if the request fails or the response cannot be parsed
|
|
9
21
|
def post(params: nil, headers: nil, body: nil)
|
|
10
22
|
validate_api_key
|
|
11
23
|
|
|
@@ -19,6 +31,9 @@ module Gibbon
|
|
|
19
31
|
end
|
|
20
32
|
end
|
|
21
33
|
|
|
34
|
+
# @param (see #post)
|
|
35
|
+
# @return (see #post)
|
|
36
|
+
# @raise (see #post)
|
|
22
37
|
def patch(params: nil, headers: nil, body: nil)
|
|
23
38
|
validate_api_key
|
|
24
39
|
|
|
@@ -32,6 +47,9 @@ module Gibbon
|
|
|
32
47
|
end
|
|
33
48
|
end
|
|
34
49
|
|
|
50
|
+
# @param (see #post)
|
|
51
|
+
# @return (see #post)
|
|
52
|
+
# @raise (see #post)
|
|
35
53
|
def put(params: nil, headers: nil, body: nil)
|
|
36
54
|
validate_api_key
|
|
37
55
|
|
|
@@ -45,6 +63,10 @@ module Gibbon
|
|
|
45
63
|
end
|
|
46
64
|
end
|
|
47
65
|
|
|
66
|
+
# @param params [Hash, nil] query string parameters
|
|
67
|
+
# @param headers [Hash, nil] additional request headers
|
|
68
|
+
# @return (see #post)
|
|
69
|
+
# @raise (see #post)
|
|
48
70
|
def get(params: nil, headers: nil)
|
|
49
71
|
validate_api_key
|
|
50
72
|
|
|
@@ -58,6 +80,9 @@ module Gibbon
|
|
|
58
80
|
end
|
|
59
81
|
end
|
|
60
82
|
|
|
83
|
+
# @param (see #get)
|
|
84
|
+
# @return (see #post)
|
|
85
|
+
# @raise (see #post)
|
|
61
86
|
def delete(params: nil, headers: nil)
|
|
62
87
|
validate_api_key
|
|
63
88
|
|
data/lib/gibbon/gibbon_error.rb
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
module Gibbon
|
|
2
|
+
# Shared helpers mixed into {APIRequest}.
|
|
2
3
|
module Helpers
|
|
4
|
+
# Extracts the data center prefix from an API key, e.g. `"us1."` from
|
|
5
|
+
# `"TESTKEY-us1"`.
|
|
6
|
+
#
|
|
7
|
+
# @param api_key [String, nil] the API key
|
|
8
|
+
# @return [String] the prefix including its trailing dot, or an empty string
|
|
9
|
+
# when the key carries no data center suffix
|
|
3
10
|
def get_data_center_from_api_key(api_key)
|
|
4
11
|
# Return an empty string for invalid API keys so Gibbon hits the main endpoint
|
|
5
12
|
data_center = ""
|
|
6
13
|
|
|
7
14
|
if api_key && api_key["-"]
|
|
8
|
-
# Remove all non-
|
|
15
|
+
# Remove all non-alphanumeric characters in case someone attempts to inject
|
|
9
16
|
# a different domain into the API key (e.g. when consuming user form-provided keys)
|
|
10
|
-
# This approach avoids assuming a 3 letter prefix (e.g.
|
|
17
|
+
# This approach avoids assuming a 3 letter prefix (e.g. if MC were to create
|
|
11
18
|
# a us10 DC, this would continue to work), and will continue to hit MC's server
|
|
12
19
|
# rather than a would-be attacker's servers.
|
|
13
20
|
data_center = "#{api_key.split('-').last.gsub(/[^0-9a-z ]/i, '')}."
|
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
module Gibbon
|
|
2
|
+
# Raised when a request fails.
|
|
3
|
+
#
|
|
4
|
+
# A `4xx` or `5xx` from MailChimp populates every attribute from the error
|
|
5
|
+
# document it returns. A transport level failure, such as a timeout, has no
|
|
6
|
+
# response to read, so only the message is set. Gibbon also raises this when a
|
|
7
|
+
# successful response body is not valid JSON, with a {#title} of
|
|
8
|
+
# `"UNPARSEABLE_RESPONSE"` and a {#status_code} of `500`.
|
|
2
9
|
class MailChimpError < StandardError
|
|
3
|
-
|
|
10
|
+
# @return [String, nil] MailChimp's short name for the error, e.g. `"Resource Not Found"`
|
|
11
|
+
attr_reader :title
|
|
12
|
+
# @return [String, nil] MailChimp's human readable explanation of the error
|
|
13
|
+
attr_reader :detail
|
|
14
|
+
# @return [Hash, nil] the parsed error document
|
|
15
|
+
attr_reader :body
|
|
16
|
+
# @return [String, nil] the unparsed error response body
|
|
17
|
+
attr_reader :raw_body
|
|
18
|
+
# @return [Integer, nil] the HTTP status code
|
|
19
|
+
attr_reader :status_code
|
|
4
20
|
|
|
21
|
+
# @param message [String] the error message
|
|
22
|
+
# @param params [Hash] any of `:title`, `:detail`, `:body`, `:raw_body`, `:status_code`
|
|
5
23
|
def initialize(message = "", params = {})
|
|
6
24
|
@title = params[:title]
|
|
7
25
|
@detail = params[:detail]
|
|
@@ -12,6 +30,7 @@ module Gibbon
|
|
|
12
30
|
super(message)
|
|
13
31
|
end
|
|
14
32
|
|
|
33
|
+
# @return [String] the message followed by every populated attribute
|
|
15
34
|
def to_s
|
|
16
35
|
super + " " + instance_variables_to_s
|
|
17
36
|
end
|
data/lib/gibbon/request.rb
CHANGED
|
@@ -1,11 +1,42 @@
|
|
|
1
1
|
module Gibbon
|
|
2
|
+
# Builds and issues requests against MailChimp's Marketing API.
|
|
3
|
+
#
|
|
4
|
+
# `Request` defines no methods for MailChimp's resources. An unknown method
|
|
5
|
+
# appends a segment to an internal path and returns `self`, so
|
|
6
|
+
# `gibbon.lists(list_id).members` builds `lists/<list_id>/members`. A CRUD
|
|
7
|
+
# verb ({#create}, {#retrieve}, {#update}, {#upsert}, {#delete}) then issues
|
|
8
|
+
# the request and resets the path. Because of that reset, an instance is safe
|
|
9
|
+
# to reuse only after a verb has run.
|
|
10
|
+
#
|
|
11
|
+
# @example Fetching lists
|
|
12
|
+
# gibbon = Gibbon::Request.new(api_key: "your_api_key-us1")
|
|
13
|
+
# gibbon.lists.retrieve.body["lists"]
|
|
14
|
+
#
|
|
15
|
+
# @see https://mailchimp.com/developer/marketing/api/ MailChimp's resource documentation
|
|
2
16
|
class Request
|
|
17
|
+
# Per-instance configuration. Each falls back to the matching class level
|
|
18
|
+
# setting, then to an environment variable or built-in default; see
|
|
19
|
+
# {#initialize} for the resolution order.
|
|
3
20
|
attr_accessor :api_key, :api_endpoint, :timeout, :open_timeout, :proxy, :faraday_adapter, :symbolize_keys, :debug, :logger
|
|
4
21
|
|
|
22
|
+
# Default read timeout, in seconds.
|
|
5
23
|
DEFAULT_TIMEOUT = 60
|
|
24
|
+
# Default connection open timeout, in seconds.
|
|
6
25
|
DEFAULT_OPEN_TIMEOUT = 60
|
|
7
26
|
|
|
8
|
-
|
|
27
|
+
# @param api_key [String, nil] API key or OAuth access token. Falls back to
|
|
28
|
+
# `Gibbon::Request.api_key`, then `ENV["MAILCHIMP_API_KEY"]`.
|
|
29
|
+
# @param api_endpoint [String, nil] Base URL, e.g. `"https://us1.api.mailchimp.com"`.
|
|
30
|
+
# Required when the key carries no data center suffix, as OAuth access
|
|
31
|
+
# tokens do not; otherwise it is derived from the key.
|
|
32
|
+
# @param timeout [Integer, nil] Read timeout in seconds. Defaults to {DEFAULT_TIMEOUT}.
|
|
33
|
+
# @param open_timeout [Integer, nil] Open timeout in seconds. Defaults to {DEFAULT_OPEN_TIMEOUT}.
|
|
34
|
+
# @param proxy [String, nil] Proxy URL. Falls back to `ENV["MAILCHIMP_PROXY"]`.
|
|
35
|
+
# @param faraday_adapter [Symbol, nil] Faraday adapter. Defaults to `Faraday.default_adapter`.
|
|
36
|
+
# @param symbolize_keys [Boolean] Whether parsed response bodies use symbol keys.
|
|
37
|
+
# @param debug [Boolean] Whether to log requests and responses.
|
|
38
|
+
# @param logger [Logger, nil] Logger used when `debug` is true. Defaults to `Logger.new(STDOUT)`.
|
|
39
|
+
def initialize(api_key: nil, api_endpoint: nil, timeout: nil, open_timeout: nil, proxy: nil, faraday_adapter: nil, symbolize_keys: nil, debug: nil, logger: nil)
|
|
9
40
|
@path_parts = []
|
|
10
41
|
@api_key = api_key || self.class.api_key || ENV['MAILCHIMP_API_KEY']
|
|
11
42
|
@api_key = @api_key.strip if @api_key
|
|
@@ -14,11 +45,15 @@ module Gibbon
|
|
|
14
45
|
@open_timeout = open_timeout || self.class.open_timeout || DEFAULT_OPEN_TIMEOUT
|
|
15
46
|
@proxy = proxy || self.class.proxy || ENV['MAILCHIMP_PROXY']
|
|
16
47
|
@faraday_adapter = faraday_adapter || self.class.faraday_adapter || Faraday.default_adapter
|
|
17
|
-
@symbolize_keys = symbolize_keys
|
|
18
|
-
@debug = debug
|
|
48
|
+
@symbolize_keys = symbolize_keys.nil? ? (self.class.symbolize_keys || false) : symbolize_keys
|
|
49
|
+
@debug = debug.nil? ? (self.class.debug || false) : debug
|
|
19
50
|
@logger = logger || self.class.logger || ::Logger.new(STDOUT)
|
|
20
51
|
end
|
|
21
52
|
|
|
53
|
+
# Appends the method name to the request path, along with any arguments as
|
|
54
|
+
# further segments, and returns `self` so calls can be chained.
|
|
55
|
+
#
|
|
56
|
+
# @return [Request] self
|
|
22
57
|
def method_missing(method, *args)
|
|
23
58
|
# To support underscores, we replace them with hyphens when calling the API
|
|
24
59
|
@path_parts << method.to_s.gsub("_", "-").downcase
|
|
@@ -27,10 +62,19 @@ module Gibbon
|
|
|
27
62
|
self
|
|
28
63
|
end
|
|
29
64
|
|
|
65
|
+
# Every method name is a potential path segment, so this always returns true.
|
|
66
|
+
#
|
|
67
|
+
# @return [true]
|
|
30
68
|
def respond_to_missing?(method_name, include_private = false)
|
|
31
69
|
true
|
|
32
70
|
end
|
|
33
71
|
|
|
72
|
+
# Appends `send` as a path segment when called with no arguments, so that
|
|
73
|
+
# `gibbon.campaigns(id).actions.send.create` reaches
|
|
74
|
+
# `campaigns/<id>/actions/send`. Called with arguments, this behaves like
|
|
75
|
+
# `Object#send` and invokes the named method.
|
|
76
|
+
#
|
|
77
|
+
# @return [Request, Object] self, or the return value of the invoked method
|
|
34
78
|
def send(*args)
|
|
35
79
|
if args.length == 0
|
|
36
80
|
method_missing(:send, args)
|
|
@@ -39,38 +83,75 @@ module Gibbon
|
|
|
39
83
|
end
|
|
40
84
|
end
|
|
41
85
|
|
|
86
|
+
# @return [String] the path accumulated so far, e.g. `"lists/abc123/members"`
|
|
42
87
|
def path
|
|
43
88
|
@path_parts.join('/')
|
|
44
89
|
end
|
|
45
90
|
|
|
91
|
+
# Issues a `POST` to the accumulated path, then resets it.
|
|
92
|
+
#
|
|
93
|
+
# @param params [Hash, nil] query string parameters
|
|
94
|
+
# @param headers [Hash, nil] additional request headers
|
|
95
|
+
# @param body [Hash, nil] request body, serialized to JSON
|
|
96
|
+
# @return [Response, nil] the response, or nil when MailChimp returns an empty body
|
|
97
|
+
# @raise [GibbonError] if no usable API key is configured
|
|
98
|
+
# @raise [MailChimpError] if the request fails or the response cannot be parsed
|
|
46
99
|
def create(params: nil, headers: nil, body: nil)
|
|
47
100
|
APIRequest.new(builder: self).post(params: params, headers: headers, body: body)
|
|
48
101
|
ensure
|
|
49
102
|
reset
|
|
50
103
|
end
|
|
51
104
|
|
|
105
|
+
# Issues a `PATCH` to the accumulated path, then resets it.
|
|
106
|
+
#
|
|
107
|
+
# @param (see #create)
|
|
108
|
+
# @return (see #create)
|
|
109
|
+
# @raise (see #create)
|
|
52
110
|
def update(params: nil, headers: nil, body: nil)
|
|
53
111
|
APIRequest.new(builder: self).patch(params: params, headers: headers, body: body)
|
|
54
112
|
ensure
|
|
55
113
|
reset
|
|
56
114
|
end
|
|
57
115
|
|
|
116
|
+
# Issues a `PUT` to the accumulated path, then resets it. Updates the record
|
|
117
|
+
# if it exists and inserts it otherwise, where MailChimp supports it.
|
|
118
|
+
#
|
|
119
|
+
# @param (see #create)
|
|
120
|
+
# @return (see #create)
|
|
121
|
+
# @raise (see #create)
|
|
58
122
|
def upsert(params: nil, headers: nil, body: nil)
|
|
59
123
|
APIRequest.new(builder: self).put(params: params, headers: headers, body: body)
|
|
60
124
|
ensure
|
|
61
125
|
reset
|
|
62
126
|
end
|
|
63
127
|
|
|
128
|
+
# Alias for {#retrieve}.
|
|
129
|
+
#
|
|
130
|
+
# @param (see #retrieve)
|
|
131
|
+
# @return (see #retrieve)
|
|
132
|
+
# @raise (see #retrieve)
|
|
64
133
|
def get(params: nil, headers: nil)
|
|
65
134
|
retrieve(params: params, headers: headers)
|
|
66
135
|
end
|
|
67
136
|
|
|
137
|
+
# Issues a `GET` to the accumulated path, then resets it.
|
|
138
|
+
#
|
|
139
|
+
# @param params [Hash, nil] query string parameters
|
|
140
|
+
# @param headers [Hash, nil] additional request headers
|
|
141
|
+
# @return [Response, nil] the response, or nil when MailChimp returns an empty body
|
|
142
|
+
# @raise [GibbonError] if no usable API key is configured
|
|
143
|
+
# @raise [MailChimpError] if the request fails or the response cannot be parsed
|
|
68
144
|
def retrieve(params: nil, headers: nil)
|
|
69
145
|
APIRequest.new(builder: self).get(params: params, headers: headers)
|
|
70
146
|
ensure
|
|
71
147
|
reset
|
|
72
148
|
end
|
|
73
149
|
|
|
150
|
+
# Issues a `DELETE` to the accumulated path, then resets it.
|
|
151
|
+
#
|
|
152
|
+
# @param (see #retrieve)
|
|
153
|
+
# @return (see #retrieve)
|
|
154
|
+
# @raise (see #retrieve)
|
|
74
155
|
def delete(params: nil, headers: nil)
|
|
75
156
|
APIRequest.new(builder: self).delete(params: params, headers: headers)
|
|
76
157
|
ensure
|
|
@@ -84,12 +165,22 @@ module Gibbon
|
|
|
84
165
|
end
|
|
85
166
|
|
|
86
167
|
class << self
|
|
168
|
+
# Class level defaults applied to every new instance. Setting these is a
|
|
169
|
+
# convenient way to configure Gibbon once, e.g. from a Rails initializer.
|
|
87
170
|
attr_accessor :api_key, :timeout, :open_timeout, :api_endpoint, :proxy, :faraday_adapter, :symbolize_keys, :debug, :logger
|
|
88
171
|
|
|
172
|
+
# Starts a call chain on a new instance built from the class level
|
|
173
|
+
# configuration, so `Gibbon::Request.lists.retrieve` works once
|
|
174
|
+
# {api_key} has been set.
|
|
175
|
+
#
|
|
176
|
+
# @return [Request] a new instance carrying the first path segment
|
|
89
177
|
def method_missing(sym, *args, &block)
|
|
90
178
|
new(api_key: self.api_key, api_endpoint: self.api_endpoint, timeout: self.timeout, open_timeout: self.open_timeout, faraday_adapter: self.faraday_adapter, symbolize_keys: self.symbolize_keys, debug: self.debug, proxy: self.proxy, logger: self.logger).send(sym, *args, &block)
|
|
91
179
|
end
|
|
92
180
|
|
|
181
|
+
# Every method name is a potential path segment, so this always returns true.
|
|
182
|
+
#
|
|
183
|
+
# @return [true]
|
|
93
184
|
def respond_to_missing?(method_name, include_private = false)
|
|
94
185
|
true
|
|
95
186
|
end
|
data/lib/gibbon/response.rb
CHANGED
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
module Gibbon
|
|
2
|
+
# A parsed response from MailChimp, returned by every CRUD verb on {Request}.
|
|
3
|
+
#
|
|
4
|
+
# @example
|
|
5
|
+
# response = gibbon.lists.retrieve
|
|
6
|
+
# response.body["lists"]
|
|
7
|
+
# response.headers["content-type"]
|
|
2
8
|
class Response
|
|
3
|
-
|
|
4
|
-
|
|
9
|
+
# @return [Hash, Array] the parsed JSON response body. Keys are symbols when
|
|
10
|
+
# the request was built with `symbolize_keys: true`, strings otherwise.
|
|
11
|
+
attr_accessor :body
|
|
12
|
+
|
|
13
|
+
# @return [Hash] the response headers, keyed by lower case string.
|
|
14
|
+
attr_accessor :headers
|
|
15
|
+
|
|
16
|
+
# @param body [Hash, Array] the parsed response body
|
|
17
|
+
# @param headers [Hash] the response headers
|
|
5
18
|
def initialize(body: {}, headers: {})
|
|
6
19
|
@body = body
|
|
7
20
|
@headers = headers
|
data/lib/gibbon/version.rb
CHANGED
data/lib/gibbon.rb
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
require 'webmock/rspec'
|
|
3
|
+
require 'stringio'
|
|
3
4
|
|
|
4
5
|
describe Gibbon::APIRequest do
|
|
5
6
|
let(:api_key) { "1234-us1" }
|
|
@@ -151,6 +152,49 @@ describe Gibbon::APIRequest do
|
|
|
151
152
|
end
|
|
152
153
|
end
|
|
153
154
|
|
|
155
|
+
context "instance overrides of class defaults" do
|
|
156
|
+
before do
|
|
157
|
+
allow(Gibbon::Request).to receive(:symbolize_keys).and_return(true)
|
|
158
|
+
allow(Gibbon::Request).to receive(:debug).and_return(true)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
let(:log_output) { StringIO.new }
|
|
162
|
+
let(:gibbon) do
|
|
163
|
+
Gibbon::Request.new(api_key: api_key, symbolize_keys: false, debug: false, logger: Logger.new(log_output))
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
it "returns string keys, including nested keys, when symbolization is disabled" do
|
|
167
|
+
stub_request(:get, "#{@api_root}/lists")
|
|
168
|
+
.to_return(body: '{"lists": [{"id": "abc123"}]}')
|
|
169
|
+
|
|
170
|
+
expect(gibbon.lists.retrieve.body).to eq({ "lists" => [{ "id" => "abc123" }] })
|
|
171
|
+
expect(Gibbon::Request.symbolize_keys).to be true
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "preserves error details with string keys when symbolization is disabled" do
|
|
175
|
+
error_body = '{"title": "Invalid Resource", "detail": "Invalid email address"}'
|
|
176
|
+
stub_request(:get, "#{@api_root}/lists").to_return(status: 422, body: error_body)
|
|
177
|
+
|
|
178
|
+
expect { gibbon.lists.retrieve }.to raise_error(Gibbon::MailChimpError) { |error|
|
|
179
|
+
expect(error.status_code).to eq 422
|
|
180
|
+
expect(error.title).to eq "Invalid Resource"
|
|
181
|
+
expect(error.detail).to eq "Invalid email address"
|
|
182
|
+
expect(error.body).to eq({ "title" => "Invalid Resource", "detail" => "Invalid email address" })
|
|
183
|
+
expect(error.raw_body).to eq error_body
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
it "does not log requests or responses when debug is disabled" do
|
|
188
|
+
stub_request(:get, "#{@api_root}/lists")
|
|
189
|
+
.to_return(body: '{"email_address": "private@example.com"}')
|
|
190
|
+
|
|
191
|
+
gibbon.lists.retrieve
|
|
192
|
+
|
|
193
|
+
expect(log_output.string).to be_empty
|
|
194
|
+
expect(Gibbon::Request.debug).to be true
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
154
198
|
context "configure_request" do
|
|
155
199
|
it "sets params, headers, body, and timeouts on the request" do
|
|
156
200
|
gibbon = Gibbon::Request.new(api_key: api_key, timeout: 45, open_timeout: 15)
|
data/spec/gibbon/gibbon_spec.rb
CHANGED
|
@@ -219,10 +219,26 @@ describe Gibbon do
|
|
|
219
219
|
expect(Gibbon::Request.new.symbolize_keys).to eq(Gibbon::Request.symbolize_keys)
|
|
220
220
|
end
|
|
221
221
|
|
|
222
|
+
it "allows instance symbolize_keys false to override the class setting" do
|
|
223
|
+
expect(Gibbon::Request.new(symbolize_keys: false).symbolize_keys).to be false
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
it "inherits the class symbolize_keys setting when explicitly passed nil" do
|
|
227
|
+
expect(Gibbon::Request.new(symbolize_keys: nil).symbolize_keys).to be true
|
|
228
|
+
end
|
|
229
|
+
|
|
222
230
|
it "set debug on new instances" do
|
|
223
231
|
expect(Gibbon::Request.new.debug).to eq(Gibbon::Request.debug)
|
|
224
232
|
end
|
|
225
233
|
|
|
234
|
+
it "allows instance debug false to override the class setting" do
|
|
235
|
+
expect(Gibbon::Request.new(debug: false).debug).to be false
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
it "inherits the class debug setting when explicitly passed nil" do
|
|
239
|
+
expect(Gibbon::Request.new(debug: nil).debug).to be true
|
|
240
|
+
end
|
|
241
|
+
|
|
226
242
|
it "set faraday_adapter on new instances" do
|
|
227
243
|
expect(Gibbon::Request.new.faraday_adapter).to eq(Gibbon::Request.faraday_adapter)
|
|
228
244
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gibbon
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.0.
|
|
4
|
+
version: 4.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Amro Mousa
|
|
@@ -37,6 +37,20 @@ dependencies:
|
|
|
37
37
|
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: 1.11.0
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: json
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - "<"
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '3.0'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - "<"
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '3.0'
|
|
40
54
|
- !ruby/object:Gem::Dependency
|
|
41
55
|
name: rake
|
|
42
56
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -79,7 +93,23 @@ dependencies:
|
|
|
79
93
|
- - "~>"
|
|
80
94
|
- !ruby/object:Gem::Version
|
|
81
95
|
version: '3.8'
|
|
82
|
-
|
|
96
|
+
- !ruby/object:Gem::Dependency
|
|
97
|
+
name: yard
|
|
98
|
+
requirement: !ruby/object:Gem::Requirement
|
|
99
|
+
requirements:
|
|
100
|
+
- - "~>"
|
|
101
|
+
- !ruby/object:Gem::Version
|
|
102
|
+
version: '0.9'
|
|
103
|
+
type: :development
|
|
104
|
+
prerelease: false
|
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - "~>"
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0.9'
|
|
110
|
+
description: Gibbon is a Ruby wrapper for MailChimp's Marketing API (version 3.0).
|
|
111
|
+
Ruby method chains map onto API resource paths, so every documented resource is
|
|
112
|
+
reachable without waiting on a gem update.
|
|
83
113
|
email:
|
|
84
114
|
- amromousa@gmail.com
|
|
85
115
|
executables: []
|
|
@@ -88,8 +118,9 @@ extra_rdoc_files: []
|
|
|
88
118
|
files:
|
|
89
119
|
- ".document"
|
|
90
120
|
- ".github/FUNDING.yml"
|
|
121
|
+
- ".github/workflows/ci.yml"
|
|
91
122
|
- ".gitignore"
|
|
92
|
-
- ".
|
|
123
|
+
- ".yardopts"
|
|
93
124
|
- CHANGELOG.md
|
|
94
125
|
- CODE_OF_CONDUCT.md
|
|
95
126
|
- Gemfile
|
|
@@ -116,7 +147,11 @@ files:
|
|
|
116
147
|
homepage: https://github.com/amro/gibbon
|
|
117
148
|
licenses:
|
|
118
149
|
- MIT
|
|
119
|
-
metadata:
|
|
150
|
+
metadata:
|
|
151
|
+
source_code_uri: https://github.com/amro/gibbon
|
|
152
|
+
changelog_uri: https://github.com/amro/gibbon/blob/master/CHANGELOG.md
|
|
153
|
+
bug_tracker_uri: https://github.com/amro/gibbon/issues
|
|
154
|
+
documentation_uri: https://rubydoc.info/gems/gibbon
|
|
120
155
|
rdoc_options: []
|
|
121
156
|
require_paths:
|
|
122
157
|
- lib
|
|
@@ -131,7 +166,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
131
166
|
- !ruby/object:Gem::Version
|
|
132
167
|
version: '0'
|
|
133
168
|
requirements: []
|
|
134
|
-
rubygems_version: 4.0.
|
|
169
|
+
rubygems_version: 4.0.20
|
|
135
170
|
specification_version: 4
|
|
136
171
|
summary: A wrapper for MailChimp API 3.0
|
|
137
172
|
test_files: []
|
data/.travis.yml
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
language: ruby
|
|
2
|
-
cache: bundler
|
|
3
|
-
rvm:
|
|
4
|
-
- 3.1
|
|
5
|
-
- 3.2
|
|
6
|
-
- 3.3
|
|
7
|
-
- 3.4
|
|
8
|
-
jobs:
|
|
9
|
-
include:
|
|
10
|
-
# rvm's stable release does not know Ruby 4.0 yet, so boot on 3.4,
|
|
11
|
-
# then upgrade rvm to master and install 4.0 from there
|
|
12
|
-
- name: "4.0 (via rvm master)"
|
|
13
|
-
rvm: 3.4
|
|
14
|
-
before_install:
|
|
15
|
-
- rvm get master
|
|
16
|
-
- rvm install ruby-4.0
|
|
17
|
-
- rvm use ruby-4.0
|
|
18
|
-
- ruby -v
|
|
19
|
-
# Bundler 4 (shipped with Ruby 4.0) removed the --path flag that
|
|
20
|
-
# Travis's default install step still passes
|
|
21
|
-
install:
|
|
22
|
-
- bundle config set --local path vendor/bundle
|
|
23
|
-
- bundle install --jobs=3 --retry=3
|