blurb 0.3.0 → 0.3.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 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