blurb 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f418adffdec8cb6dad94905f36907bbb783afc52
4
- data.tar.gz: 275ea7f93bc0ca704db76c4476c10cd4ecc1ea8a
3
+ metadata.gz: 4daa2abcd906bc38246e020252bd4334f5079724
4
+ data.tar.gz: 9a6782e3f58651dbbf4d4f91fe1b2f1b43d64dd8
5
5
  SHA512:
6
- metadata.gz: 5bb60ed1768e2c2bb618518741768fd31759b9a10cae29210ab7ab3c1a5f7ee9d8d05f0059f8d3cd139653b2f6789d8fcaade68fbc0d96f4e4a81a043c2b59b8
7
- data.tar.gz: be5d2d3a75f03c76493b1ff560f5041a87fc3bb402566d5fa63d96ec9e5e7a4749354d34fbc145ed595abf7c3ab87fc3683aa63306da2f2bbb26cb2405ab20d3
6
+ metadata.gz: 413565b433b897c04ece25f6869e535e9c8c39bf9c3c632ce4832ea0863bbcf2d9b2b54ad6c1a87474b39959f2b188117bccb56efe25e9401edfa79c8785f240
7
+ data.tar.gz: 30d7f25c7b81150eda725fb1da9abbf4408a0fe5f7fa2acc8dee0a51537194ba3bbb92b16239f7503bdca4e7fa9f5964fa8fe3b5f14f091c16fa8a4f07e2f483
data/README.md CHANGED
@@ -130,7 +130,26 @@ Blurb.test_env = true
130
130
  ## Usage
131
131
 
132
132
  All API calls have been setup as closely as possible to REST Resource calls.
133
- All you need to do is find the appropriate resource object and make a method call on it and Blurb will do the rest.
133
+ All you need to do is instantiate a resource object and make a method call on it and Blurb will do the rest.
134
+
135
+ For example, to use the keywords resource object:
136
+
137
+ ```ruby
138
+ blurb_instance = Blurb::Keyword.new()
139
+ ```
140
+
141
+ Optionally, you may pass in a set of account credentials to override the default API keys and tokens
142
+
143
+ ```ruby
144
+ authorization_hash = {
145
+ client_id: 'my_client_id',
146
+ profile_id: 'my_profile_id',
147
+ client_secret: 'client_secret',
148
+ refresh_token: 'refresh_token'
149
+ }
150
+
151
+ blurb_instance = Blurb::Keyword.new(authorization_hash)
152
+ ```
134
153
 
135
154
  In calls that require 'campaign_type' as a parameter, you must pass in either 'sp' for sponsored products or 'hsa' for sponsored brands (formerly known as headline search ads).
136
155
 
@@ -145,32 +164,37 @@ Blurb::Profile.list()
145
164
  ```
146
165
 
147
166
  ### Campaigns
167
+
168
+ ```ruby
169
+ campaign_instance = Blurb::Campaign.new
170
+ ```
171
+
148
172
  List campaigns
149
173
 
150
174
  ```ruby
151
- Blurb::Campaign.list(campaign_type)
175
+ campaign_instance.list(campaign_type)
152
176
  ```
153
177
  or
154
178
  ```ruby
155
- Blurb::Campaign.list_extended(campaign_type)
179
+ campaign_instance.list_extended(campaign_type)
156
180
  ```
157
181
  Note that the extended call returns the complete set of campaign fields (including serving status and other read-only fields), but is less efficient.
158
182
 
159
183
  Get a campaign
160
184
 
161
185
  ```ruby
162
- Blurb::Campaign.retrieve(campaign_id, campaign_type)
186
+ campaign_instance.retrieve(campaign_id, campaign_type)
163
187
  ```
164
188
  or
165
189
  ```ruby
166
- Blurb::Campaign.retrieve_extended(campaign_id, campaign_type)
190
+ campaign_instance.retrieve_extended(campaign_id, campaign_type)
167
191
  ```
168
192
  Note that the extended call returns the complete set of campaign fields (including serving status and other read-only fields), but is less efficient.
169
193
 
170
194
  Create a campaign
171
195
 
172
196
  ```ruby
173
- Blurb::Campaign.create(campaign_type, {
197
+ campaign_instance.create(campaign_type, {
174
198
  "name" => "test",
175
199
  "state" => "enabled",
176
200
  "dailyBudget" => 10,
@@ -181,11 +205,70 @@ Blurb::Campaign.create(campaign_type, {
181
205
 
182
206
  Note: Sponsored Brands cannot be created through the Amazon Advertising API and must be added through the user interface. The create call only works for Sponsored Products.
183
207
 
208
+ ### Keywords
209
+
210
+ ```ruby
211
+ keyword_instance = Blurb::Keyword.new
212
+ ```
213
+
214
+ List keywords
215
+
216
+ ```ruby
217
+ keyword_instance.list(campaign_type)
218
+ ```
219
+ or
220
+ ```ruby
221
+ keyword_instance.list_extended(campaign_type)
222
+ ```
223
+
224
+ Get a keyword
225
+
226
+ ```ruby
227
+ keyword_instance.retrieve(campaign_id, campaign_type)
228
+ ```
229
+ or
230
+ ```ruby
231
+ keyword_instance.retrieve_extended(campaign_id, campaign_type)
232
+ ```
233
+
234
+ Create a keyword
235
+
236
+ ```ruby
237
+ keyword_instance.create(campaign_type, {
238
+ "campaignId" => "1234",
239
+ "adGroupId" => "5678",
240
+ "keywordText" => 'keyword',
241
+ "matchType" => 'broad',
242
+ "state" => "enabled"
243
+ "bid" => 0.1
244
+ })
245
+ ```
246
+
247
+ Bulk update keywords
248
+
249
+ ```ruby
250
+ updates = [
251
+ {
252
+ "keywordId" => "1234",
253
+ "bid" => 0.1
254
+ },
255
+ {
256
+ "keywordId" => "2345",
257
+ "bid" => 0.3
258
+ }
259
+ ]
260
+ keyword_instance.update(campaign_type, updates)
261
+ ```
262
+
184
263
  ### Reports
264
+ ```ruby
265
+ report_instance = Blurb::Report.new
266
+ ```
267
+
185
268
  Request a report
186
269
 
187
270
  ```ruby
188
- payload_response = Blurb::Report.create({
271
+ payload_response = report_instance.create({
189
272
  "campaignType" => Blurb::Report::SPONSORED_PRODUCTS,
190
273
  "recordType" => Blurb::Report::KEYWORDS,
191
274
  "reportDate" => (Time.now - 2592000).strftime('%Y%m%d'),
@@ -215,20 +298,24 @@ Blurb::Report::SPONSORED_BRANDS
215
298
  Check report status
216
299
 
217
300
  ```ruby
218
- Blurb::Report.status(report_id)
301
+ report_instance.status(report_id)
219
302
  ```
220
303
 
221
304
  Download report file content
222
305
 
223
306
  ```ruby
224
- Blurb::Report.download(report_location_url)
307
+ report_instance.download(report_location_url)
225
308
  ```
226
309
 
227
310
  ### Snapshots
311
+ ```ruby
312
+ snapshot_instance = Blurb::Snapshot.new
313
+ ```
314
+
228
315
  Request a snapshot
229
316
 
230
317
  ```ruby
231
- payload_response = Blurb::Snapshot.create({
318
+ payload_response = snapshot_instance.create({
232
319
  "recordType" => Blurb::Snapshot::KEYWORDS,
233
320
  "campaignType" => Blurb::Snapshot::SPONSORED_PRODUCTS,
234
321
  "stateFilter" => "enabled,paused,archived"
@@ -257,20 +344,24 @@ Blurb::Report::SPONSORED_BRANDS
257
344
  Check snapshot status
258
345
 
259
346
  ```ruby
260
- Blurb::Snapshot.status(snapshot_id)
347
+ snapshot_instance.status(snapshot_id)
261
348
  ```
262
349
 
263
350
  Download snapshot file content
264
351
 
265
352
  ```ruby
266
- Blurb::Snapshot.download(snapshot_location_url)
353
+ snapshot_instance.download(snapshot_location_url)
267
354
  ```
268
355
 
269
356
  ### Suggested Keywords
357
+ ```ruby
358
+ suggested_keyword_instance = Blurb::SuggestedKeyword.new
359
+ ```
360
+
270
361
  Suggestions by ASIN
271
362
 
272
363
  ```ruby
273
- Blurb::SuggestedKeyword.asin_suggestions({
364
+ suggested_keyword_instance.asin_suggestions({
274
365
  "asinValue" => "B0006HUJJO"
275
366
  })
276
367
  ```
@@ -278,7 +369,7 @@ Blurb::SuggestedKeyword.asin_suggestions({
278
369
  Suggestions for a list of ASIN's
279
370
 
280
371
  ```ruby
281
- Blurb::SuggestedKeyword.bulk_asin_suggestions({
372
+ suggested_keyword_instance.bulk_asin_suggestions({
282
373
  "asins" => ["B0006HUJJO","B0042SWOHI"]
283
374
  })
284
375
  ```
@@ -10,6 +10,8 @@ require "blurb/profile"
10
10
  require "blurb/report"
11
11
  require "blurb/snapshot"
12
12
  require "blurb/suggested_keyword"
13
+ require "blurb/keyword"
14
+ require "blurb/ad_group"
13
15
 
14
16
  module Blurb
15
17
 
@@ -0,0 +1,40 @@
1
+ module Blurb
2
+ class AdGroup < BaseResource
3
+
4
+ URL_PARAMS = ['startIndex', 'campaignType', 'count', 'matchTypeFilter', 'name', 'state', 'campaignIdFilter', 'adGroupIdFilter']
5
+
6
+ def retrieve(keyword_id, campaign_type)
7
+ raise ArgumentError.new("adGroups interface is only supported for Sponsored Products") unless campaign_type == SPONSORED_PRODUCTS
8
+ get_request("/v2/#{campaign_type}/adGroups/#{keyword_id}")
9
+ end
10
+
11
+ def retrieve_extended(keyword_id, campaign_type)
12
+ raise ArgumentError.new("adGroups interface is only supported for Sponsored Products") unless campaign_type == SPONSORED_PRODUCTS
13
+ get_request("/v2/#{campaign_type}/adGroups/extended/#{keyword_id}")
14
+ end
15
+
16
+ def list(campaign_type, params = {}, opts = {})
17
+ raise ArgumentError.new("adGroups interface is only supported for Sponsored Products") unless campaign_type == SPONSORED_PRODUCTS
18
+ get_request("/v2/#{campaign_type}/adGroups?#{setup_url_params(params, URL_PARAMS)}")
19
+ end
20
+
21
+ def list_extended(campaign_type, params = {}, opts = {})
22
+ raise ArgumentError.new("adGroups interface is only supported for Sponsored Products") unless campaign_type == SPONSORED_PRODUCTS
23
+ get_request("/v2/#{campaign_type}/adGroups/extended?#{setup_url_params(params, URL_PARAMS)}")
24
+ end
25
+
26
+ def create(campaign_type, params = {}, opts = {})
27
+ # required argument checks
28
+ if !params["name"] && !params["targetingType"] && !params["state"] && !params["dailyBudget"] && !params["startDate"]
29
+ raise ArgumentError.new("params hash must contain name, targetingType, state, dailyBudget and startDate")
30
+ end
31
+ raise ArgumentError.new("Only sponsored product adGroups can be created through the api. Sponsored Brands adGroups must be created through the user interface") unless campaign_type == SPONSORED_PRODUCTS
32
+
33
+ post_request("/v2/#{campaign_type}/adGroups", [params])
34
+ end
35
+
36
+ def delete(keyword_id)
37
+ delete_request("/v2/adGroups/#{keyword_id}")
38
+ end
39
+ end
40
+ end
@@ -7,6 +7,9 @@ module Blurb
7
7
  TEST_API_URL = "https://advertising-api-test.amazon.com"
8
8
  EU_API_URL = "https://advertising-api-eu.amazon.com"
9
9
 
10
+ SPONSORED_PRODUCTS = "sp"
11
+ SPONSORED_BRANDS = "hsa"
12
+
10
13
  def initialize(account=Blurb.default_account)
11
14
  @client_secret = account[:client_secret]
12
15
  @client_id = account[:client_id]
@@ -83,25 +86,13 @@ module Blurb
83
86
  end
84
87
 
85
88
  def get_request(api_path, opts = {})
86
- access_token = retrieve_token()
87
-
88
89
  url = "#{active_api_url}#{api_path}"
89
90
  url = api_path if opts[:full_path]
90
91
 
91
- headers_hash = {
92
- "Authorization" => "Bearer #{access_token['access_token']}",
93
- "Content-Type" => "application/json",
94
- "Amazon-Advertising-API-Scope" => @profile_id,
95
- "Amazon-Advertising-API-ClientId" => @client_id
96
- }
97
-
98
- headers_hash["Content-Encoding"] = "gzip" if opts[:gzip]
99
- # headers_hash.delete("Authorization") if opts[:no_token]
100
-
101
92
  request_config = {
102
93
  method: :get,
103
94
  url: url,
104
- headers: headers_hash,
95
+ headers: headers_hash(opts),
105
96
  max_redirects: 0
106
97
  }
107
98
 
@@ -109,33 +100,28 @@ module Blurb
109
100
  end
110
101
 
111
102
  def post_request(api_path, payload)
112
- access_token = retrieve_token()
113
-
114
103
  request_config = {
115
104
  method: :post,
116
105
  url: "#{active_api_url}#{api_path}",
117
106
  payload: payload.to_json,
118
- headers: {
119
- "Authorization" => "Bearer #{access_token['access_token']}",
120
- "Content-Type" => "application/json",
121
- "Amazon-Advertising-API-Scope" => @profile_id.to_i,
122
- "Amazon-Advertising-API-ClientId" => @client_id
123
- }
107
+ headers: headers_hash
124
108
  }
125
109
 
126
110
  return make_request(request_config)
127
111
  end
128
112
 
129
- def delete_request(api_path)
130
- access_token = retrieve_token()
113
+ def put_request(api_path, payload)
114
+ request_config = {
115
+ method: :put,
116
+ url: "#{active_api_url}#{api_path}",
117
+ payload: payload.to_json,
118
+ headers: headers_hash
119
+ }
131
120
 
132
- headers_hash = {
133
- "Authorization" => "Bearer #{access_token['access_token']}",
134
- "Content-Type" => "application/json",
135
- "Amazon-Advertising-API-Scope" => @profile_id,
136
- "Amazon-Advertising-API-ClientId" => @client_id
137
- }
121
+ return make_request(request_config)
122
+ end
138
123
 
124
+ def delete_request(api_path)
139
125
  request_config = {
140
126
  method: :delete,
141
127
  url: "#{active_api_url}#{api_path}",
@@ -162,5 +148,25 @@ module Blurb
162
148
  response = JSON.parse(resp) if resp
163
149
  return response
164
150
  end
151
+
152
+ def headers_hash(opts = {})
153
+ access_token = retrieve_token()
154
+
155
+ headers_hash = {
156
+ "Authorization" => "Bearer #{access_token['access_token']}",
157
+ "Content-Type" => "application/json",
158
+ "Amazon-Advertising-API-Scope" => @profile_id,
159
+ "Amazon-Advertising-API-ClientId" => @client_id
160
+ }
161
+
162
+ headers_hash["Content-Encoding"] = "gzip" if opts[:gzip]
163
+
164
+ return headers_hash
165
+ end
166
+
167
+ def setup_url_params(params, whitelist)
168
+ whitelisted_params = params.select { |k,v| whitelist.include?(k) }
169
+ return URI.encode_www_form(whitelisted_params)
170
+ end
165
171
  end
166
172
  end
@@ -1,7 +1,7 @@
1
1
  module Blurb
2
2
  class Campaign < BaseResource
3
- SPONSORED_PRODUCTS = "sp"
4
- SPONSORED_BRANDS = "hsa"
3
+
4
+ URL_PARAMS = ['count', 'stateFilter', 'startIndex', 'name', 'campaignIdFilter']
5
5
 
6
6
  def retrieve(campaign_id, campaign_type)
7
7
  get_request("/v2/#{campaign_type}/campaigns/#{campaign_id}")
@@ -13,12 +13,12 @@ module Blurb
13
13
  end
14
14
 
15
15
  def list(campaign_type, params = {}, opts = {})
16
- get_request("/v2/#{campaign_type}/campaigns?#{setup_url_params(params)}")
16
+ get_request("/v2/#{campaign_type}/campaigns?#{setup_url_params(params, URL_PARAMS)}")
17
17
  end
18
18
 
19
19
  def list_extended(campaign_type, params = {}, opts = {})
20
20
  raise ArgumentError.new("Extended campaigns interface is only supported for Sponsored Products") unless campaign_type == SPONSORED_PRODUCTS
21
- get_request("/v2/#{campaign_type}/campaigns/extended?#{setup_url_params(params)}")
21
+ get_request("/v2/#{campaign_type}/campaigns/extended?#{setup_url_params(params, URL_PARAMS)}")
22
22
  end
23
23
 
24
24
  def create(campaign_type, params = {}, opts = {})
@@ -34,34 +34,5 @@ module Blurb
34
34
  def delete(campaign_id)
35
35
  delete_request("/v2/campaigns/#{campaign_id}")
36
36
  end
37
-
38
- private
39
-
40
- def setup_url_params(params)
41
- url_params = ""
42
- url_params = "startIndex=#{params['startIndex']}" if params['startIndex']
43
-
44
- if params['count']
45
- url_params += "&" if url_params.size > 0
46
- url_params += "count=#{params['count']}"
47
- end
48
-
49
- if params['stateFilter']
50
- url_params += "&" if url_params.size > 0
51
- url_params += "stateFilter=#{params['stateFilter']}"
52
- end
53
-
54
- if params['name']
55
- url_params += "&" if url_params.size > 0
56
- url_params += "name=#{params['name']}"
57
- end
58
-
59
- if params['campaignIdFilter']
60
- url_params += "&" if url_params.size > 0
61
- url_params += "campaignIdFilter=#{params['campaignIdFilter']}"
62
- end
63
-
64
- return url_params
65
- end
66
37
  end
67
38
  end
@@ -0,0 +1,51 @@
1
+ module Blurb
2
+ class Keyword < BaseResource
3
+ URL_PARAMS = ['startIndex', 'count', 'matchTypeFilter', 'keywordText', 'state', 'campaignIdFilter', 'adGroupIdFilter']
4
+
5
+ def retrieve(keyword_id, campaign_type)
6
+ get_request("/v2/#{campaign_type}/keywords/#{keyword_id}")
7
+ end
8
+
9
+ def retrieve_extended(keyword_id, campaign_type)
10
+ raise ArgumentError.new("Extended keywords interface is only supported for Sponsored Products") unless campaign_type == SPONSORED_PRODUCTS
11
+ get_request("/v2/#{campaign_type}/keywords/extended/#{keyword_id}")
12
+ end
13
+
14
+ def list(campaign_type, params = {}, opts = {})
15
+ get_request("/v2/#{campaign_type}/keywords?#{setup_url_params(params, URL_PARAMS)}")
16
+ end
17
+
18
+ def list_extended(campaign_type, params = {}, opts = {})
19
+ raise ArgumentError.new("Extended keywords interface is only supported for Sponsored Products") unless campaign_type == SPONSORED_PRODUCTS
20
+ get_request("/v2/#{campaign_type}/keywords/extended?#{setup_url_params(params, URL_PARAMS)}")
21
+ end
22
+
23
+ def update(campaign_type, payload, opts = {})
24
+ raise ArgumentError.new("Extended keywords interface is only supported for Sponsored Products") unless campaign_type == SPONSORED_PRODUCTS
25
+ payload = [payload] unless payload.class == Array
26
+
27
+ # The Amazon Advertising API only accepts bulk changes of up to 1000 keywords
28
+ results = []
29
+ payloads = payload.each_slice(1000).to_a
30
+ payloads.each do |p|
31
+ results << put_request("/v2/#{campaign_type}/keywords", p)
32
+ end
33
+
34
+ return results.flatten
35
+ end
36
+
37
+ def create(campaign_type, params = {}, opts = {})
38
+ # required argument checks
39
+ if !params["campaignId"] && !params["adGroupId"] && !params["keywordText"] && !params["matchType"] && !params["state"]
40
+ raise ArgumentError.new("params hash must contain campaignId, adGroupId, keywordText, matchType and state")
41
+ end
42
+ raise ArgumentError.new("Only sponsored product keywords can be created through the api. Sponsored Brands keywords must be created through the user interface") unless campaign_type == SPONSORED_PRODUCTS
43
+
44
+ post_request("/v2/#{campaign_type}/keywords", [params])
45
+ end
46
+
47
+ def delete(keyword_id)
48
+ delete_request("/v2/keywords/#{keyword_id}")
49
+ end
50
+ end
51
+ end
@@ -6,8 +6,6 @@ module Blurb
6
6
  PRODUCT_ADS = "productAds"
7
7
  ASINS = "asins"
8
8
  TARGETS = "targets"
9
- SPONSORED_PRODUCTS = "sp"
10
- SPONSORED_BRANDS = "hsa"
11
9
 
12
10
  def create(params = {}, opts = {})
13
11
  # required argument checks
@@ -7,8 +7,6 @@ module Blurb
7
7
  CAMPAIGN_NEGATIVE_KEYWORDS = "campaignNegativeKeywords"
8
8
  PRODUCT_ADS = "productAds"
9
9
  TARGETS = "targets"
10
- SPONSORED_PRODUCTS = "sp"
11
- SPONSORED_BRANDS = "hsa"
12
10
 
13
11
  def create(params = {}, opts = {})
14
12
  # required argument checks
@@ -1,24 +1,26 @@
1
1
  module Blurb
2
2
  class SuggestedKeyword < BaseResource
3
+ URL_PARAMS = ['maxNumSuggestions', 'adStateFilter', 'suggestBids']
4
+
3
5
  def ad_group_suggestions(params = {}, opts = {})
4
6
  # required argument checks
5
7
  raise ArgumentError.new("params hash must contain an adGroupId") unless params["adGroupId"]
6
8
 
7
- get_request("/v2/adGroups/#{params["adGroupId"]}/suggested/keywords?#{setup_url_params(params)}")
9
+ get_request("/v2/adGroups/#{params["adGroupId"]}/suggested/keywords?#{setup_url_params(params, URL_PARAMS)}")
8
10
  end
9
11
 
10
12
  def ad_group_extended_suggestions(params = {}, opts = {})
11
13
  # required argument checks
12
14
  raise ArgumentError.new("params hash must contain an adGroupId") unless params["adGroupId"]
13
15
 
14
- get_request("/v2/adGroups/#{params["adGroupId"]}/suggested/keywords/extended?#{setup_url_params(params)}")
16
+ get_request("/v2/adGroups/#{params["adGroupId"]}/suggested/keywords/extended?#{setup_url_params(params, URL_PARAMS)}")
15
17
  end
16
18
 
17
19
  def asin_suggestions(params = {}, opts = {})
18
20
  # required argument checks
19
21
  raise ArgumentError.new("params hash must contain an asinValue") unless params["asinValue"]
20
22
 
21
- get_request("/v2/asins/#{params["asinValue"]}/suggested/keywords?#{setup_url_params(params)}")
23
+ get_request("/v2/asins/#{params["asinValue"]}/suggested/keywords?#{setup_url_params(params, URL_PARAMS)}")
22
24
  end
23
25
 
24
26
  def bulk_asin_suggestions(params = {}, opts = {})
@@ -33,24 +35,5 @@ module Blurb
33
35
  "maxNumSuggestions" => maxNumSuggestions
34
36
  })
35
37
  end
36
-
37
- private
38
-
39
- def setup_url_params(params)
40
- url_params = ""
41
- url_params = "maxNumSuggestions=#{params['maxNumSuggestions']}" if params['maxNumSuggestions']
42
-
43
- if params['adStateFilter']
44
- url_params += "&" if url_params.size > 0
45
- url_params += "adStateFilter=#{params['adStateFilter']}"
46
- end
47
-
48
- if params['suggestBids']
49
- url_params += "&" if url_params.size > 0
50
- url_params += "suggestBids=#{params['suggestBids']}"
51
- end
52
-
53
- return url_params
54
- end
55
38
  end
56
39
  end
@@ -1,3 +1,3 @@
1
1
  module Blurb
2
- VERSION = "0.3.0".freeze
2
+ VERSION = "0.3.1".freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: blurb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - dlbunker
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-03-21 00:00:00.000000000 Z
11
+ date: 2019-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -115,9 +115,11 @@ files:
115
115
  - bin/setup
116
116
  - blurb.gemspec
117
117
  - lib/blurb.rb
118
+ - lib/blurb/ad_group.rb
118
119
  - lib/blurb/base_resource.rb
119
120
  - lib/blurb/bid_recommendation.rb
120
121
  - lib/blurb/campaign.rb
122
+ - lib/blurb/keyword.rb
121
123
  - lib/blurb/profile.rb
122
124
  - lib/blurb/report.rb
123
125
  - lib/blurb/snapshot.rb