adapi 0.0.9 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +35 -27
- data/adapi.gemspec +8 -8
- data/examples/add_ad_group.rb +13 -7
- data/examples/add_bare_ad_group.rb +12 -6
- data/examples/add_bare_campaign.rb +13 -6
- data/examples/add_campaign.rb +22 -10
- data/examples/add_campaign_criteria.rb +22 -8
- data/examples/add_invalid_ad_group.rb +9 -5
- data/examples/add_invalid_keywords.rb +3 -0
- data/examples/add_invalid_text_ad.rb +12 -6
- data/examples/add_keywords.rb +20 -9
- data/examples/add_text_ads.rb +45 -0
- data/examples/rollback_campaign.rb +37 -14
- data/examples/update_campaign.rb +1 -5
- data/examples/update_complete_campaign.rb +3 -4
- data/lib/adapi.rb +5 -4
- data/lib/adapi/ad.rb +14 -39
- data/lib/adapi/ad/text_ad.rb +38 -23
- data/lib/adapi/ad_group.rb +35 -30
- data/lib/adapi/ad_group_criterion.rb +7 -4
- data/lib/adapi/ad_param.rb +8 -16
- data/lib/adapi/api.rb +88 -8
- data/lib/adapi/campaign.rb +87 -76
- data/lib/adapi/campaign_criterion.rb +6 -4
- data/lib/adapi/campaign_target.rb +6 -4
- data/lib/adapi/config.rb +2 -2
- data/lib/adapi/keyword.rb +11 -58
- data/lib/adapi/version.rb +7 -1
- data/test/integration/create_ad_group_test.rb +48 -0
- data/test/integration/create_campaign_test.rb +1 -4
- data/test/test_helper.rb +49 -0
- metadata +43 -41
data/README.markdown
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
# Adapi
|
1
|
+
# Adapi [![Code Climate](https://codeclimate.com/badge.png)](https://codeclimate.com/github/lstejskal/adapi)
|
2
2
|
|
3
|
-
## Description
|
3
|
+
## Description
|
4
4
|
|
5
5
|
Adapi (ADwords API) is a Ruby library for easy and painless work with Google
|
6
6
|
Adwords API. Its users shouldn't bother with SOAP and tangle of XML- and
|
@@ -21,11 +21,13 @@ come from there, but adapi takes it several steps further:
|
|
21
21
|
Adapi is *still in development* and not nearly done yet! Version 1.0.0 should
|
22
22
|
have all planned functionality.
|
23
23
|
|
24
|
-
|
24
|
+
Adapi supports the latest version of AdWords API: *v201206*.
|
25
|
+
|
26
|
+
## Installation
|
25
27
|
|
26
28
|
`gem install adapi`
|
27
29
|
|
28
|
-
### from git repository
|
30
|
+
### from git repository
|
29
31
|
|
30
32
|
```
|
31
33
|
git clone git@github.com:lstejskal/adapi.git
|
@@ -34,17 +36,17 @@ bundle install
|
|
34
36
|
rake install
|
35
37
|
```
|
36
38
|
|
37
|
-
## Configuration
|
39
|
+
## Configuration
|
38
40
|
|
39
41
|
This section explains how to connect to specific AdWords account and client.
|
40
42
|
There are several options to choose from:
|
41
43
|
|
42
|
-
#### Configuration by adwords_api.yml
|
44
|
+
#### Configuration by adwords_api.yml
|
43
45
|
|
44
46
|
If you already have `google-adwords-api` gem configured and use just one account,
|
45
47
|
the same configuration will also work for adapi: `~/adwords_api.yml`
|
46
48
|
|
47
|
-
#### Single account set directly in code
|
49
|
+
#### Single account set directly in code
|
48
50
|
|
49
51
|
```ruby
|
50
52
|
Adapi::Config.load_settings(:in_hash => {
|
@@ -66,7 +68,7 @@ Adapi::Config.load_settings(:in_hash => {
|
|
66
68
|
Adapi::Config.set(:sandbox)
|
67
69
|
```
|
68
70
|
|
69
|
-
#### Multiple accounts set directly in code
|
71
|
+
#### Multiple accounts set directly in code
|
70
72
|
|
71
73
|
You can set many AdWords accounts to connect to and switch between while running
|
72
74
|
the application. You can even update single values of the settings on-the-fly.
|
@@ -110,7 +112,7 @@ Adapi::Config.set(:coca_cola, :client_customer_id => '777-666-5555')
|
|
110
112
|
# do some stuff here...
|
111
113
|
```
|
112
114
|
|
113
|
-
#### Configuration by `adapi.yml`
|
115
|
+
#### Configuration by `adapi.yml`
|
114
116
|
|
115
117
|
Stored in `~/adapi.yml`. Supports multiple accounts, which are identifed by
|
116
118
|
aliases. Example:
|
@@ -149,7 +151,7 @@ Adapi::Config.set(:sandbox)
|
|
149
151
|
`:default` account available, you have to manually set account alias to
|
150
152
|
`Adapi::Config`.
|
151
153
|
|
152
|
-
### Authentication workflow
|
154
|
+
### Authentication workflow
|
153
155
|
|
154
156
|
* try to load configuration from `~/adapi.yml`
|
155
157
|
* if `~/adapi.yml`doesn't exist, try to load configuration from
|
@@ -157,16 +159,22 @@ Adapi::Config.set(:sandbox)
|
|
157
159
|
* if there are no configuration files available, set configuration directly to
|
158
160
|
`Adapi::Config` (overrides previous settings)
|
159
161
|
|
160
|
-
## API Version Support
|
162
|
+
## API Version Support
|
163
|
+
|
164
|
+
Adapi supports the latest version of AdWords API: *v201206*.
|
161
165
|
|
162
|
-
|
163
|
-
|
166
|
+
For support of earlier versions of AdWords API, downgrade to earlier
|
167
|
+
versions of adapi: 0.0.9 for *v201109_1*, 0.07 for *v201109*.
|
168
|
+
(You shoudn't need it though, because older versions of AdWords API are
|
169
|
+
eventually shut down.) Latest revision for specific AdWords API version
|
170
|
+
is also marked by a tag.
|
164
171
|
|
165
|
-
|
166
|
-
|
167
|
-
|
172
|
+
Adapi tries to not to bother users with AdWords API low-level specifics as much
|
173
|
+
as possible, if you're upgrading to newer version of AdWords API, please be cautious,
|
174
|
+
check the [release notes](https://developers.google.com/adwords/api/docs/reference/)
|
175
|
+
and update your code accordingly. Adapi won't accept obsolete attributes etc.
|
168
176
|
|
169
|
-
## Unsupported AdWords services
|
177
|
+
## Unsupported AdWords services
|
170
178
|
|
171
179
|
Following AdWords services are not supported by adapi at the moment. However,
|
172
180
|
they will be implemented (this also serves as TODO list):
|
@@ -188,18 +196,18 @@ they will be implemented (this also serves as TODO list):
|
|
188
196
|
* MutateJobService
|
189
197
|
* BulkMutateJobService
|
190
198
|
|
191
|
-
## Examples
|
199
|
+
## Examples
|
192
200
|
|
193
201
|
Examples are available in [examples directory](./master/examples/). For now, they
|
194
202
|
are mostly just uninspired rewrites of examples from `google-adwords-api` gem,
|
195
203
|
but that's going to change when proper UI to AdWords models will be implemented.
|
196
204
|
|
197
|
-
### Getting started
|
205
|
+
### Getting started
|
198
206
|
|
199
207
|
Here are some examples to get you started with adapi. (All this is also
|
200
208
|
available in [examples directory](./master/examples/).)
|
201
209
|
|
202
|
-
#### Create complete campaign
|
210
|
+
#### Create complete campaign
|
203
211
|
|
204
212
|
Creates a campaign with ad_groups and ad_texts from hash - by single method call.
|
205
213
|
|
@@ -246,7 +254,7 @@ campaign = Adapi::Campaign.create(
|
|
246
254
|
)
|
247
255
|
```
|
248
256
|
|
249
|
-
#### Create campaign step by step
|
257
|
+
#### Create campaign step by step
|
250
258
|
|
251
259
|
Creates a campaign with ad_groups and ad_texts step by step.
|
252
260
|
|
@@ -295,7 +303,7 @@ new_campaign = Adapi::Campaign.find_complete(campaign.id)
|
|
295
303
|
puts new_campaign.to_hash.inspect
|
296
304
|
```
|
297
305
|
|
298
|
-
#### Create campaign criteria
|
306
|
+
#### Create campaign criteria
|
299
307
|
|
300
308
|
Campaign criteria (formerly targets) have been rewritten from the scratch for
|
301
309
|
*v201109*. The goal is to provide a simple DSL for criteria so user doesn't have
|
@@ -303,7 +311,7 @@ to deal with somewhat convoluted AdWords API syntax made for machines, not
|
|
303
311
|
humans. So far, this has been done only for *language* and *location* criterion.
|
304
312
|
You can use any other criteria, you just have to enter them in AdWords format.
|
305
313
|
|
306
|
-
##### Language
|
314
|
+
##### Language
|
307
315
|
|
308
316
|
```ruby
|
309
317
|
Adapi::CampaignCriterion.create(
|
@@ -317,7 +325,7 @@ Adapi::CampaignCriterion.create(
|
|
317
325
|
`:language` parameter accepts string or symbols for single language target or
|
318
326
|
array of strings/symbols for several language targets.
|
319
327
|
|
320
|
-
##### Location
|
328
|
+
##### Location
|
321
329
|
|
322
330
|
```ruby
|
323
331
|
Adapi::CampaignCriterion.create(
|
@@ -384,7 +392,7 @@ Adapi::CampaignCriterion.create(
|
|
384
392
|
)
|
385
393
|
```
|
386
394
|
|
387
|
-
##### Criterion in AdWords format
|
395
|
+
##### Criterion in AdWords format
|
388
396
|
|
389
397
|
Convenient shortcuts for other criteria besides *language* and *location* are
|
390
398
|
not yet implemented. However, you can use any other criteria, you just have to
|
@@ -399,7 +407,7 @@ Adapi::CampaignCriterion.create(
|
|
399
407
|
)
|
400
408
|
```
|
401
409
|
|
402
|
-
## Logging
|
410
|
+
## Logging
|
403
411
|
|
404
412
|
By default, communication with AdWords API is not logged. In order to log
|
405
413
|
messages of certain log level or above, set `library/log_level` in configuration
|
@@ -421,7 +429,7 @@ Example of logger configuration:
|
|
421
429
|
:log_pretty_format: true
|
422
430
|
```
|
423
431
|
|
424
|
-
## Author
|
432
|
+
## Author
|
425
433
|
|
426
434
|
2011-2012 Lukas Stejskal, Ataxo Interactive, a.s.
|
427
435
|
|
data/adapi.gemspec
CHANGED
@@ -27,20 +27,20 @@ Gem::Specification.new do |s|
|
|
27
27
|
# versions of both gems are freezed, because both gems change a lot and
|
28
28
|
# automatic updates through '~>' can (and already did) break something
|
29
29
|
#
|
30
|
-
s.add_dependency "google-ads-common", "0.
|
31
|
-
s.add_dependency "google-adwords-api", "0.
|
30
|
+
s.add_dependency "google-ads-common", "0.8.0"
|
31
|
+
s.add_dependency "google-adwords-api", "0.7.0"
|
32
32
|
|
33
33
|
s.add_dependency "activemodel", "~> 3.0"
|
34
34
|
s.add_dependency "activesupport", "~> 3.0"
|
35
35
|
s.add_dependency "rake", "~> 0.9.2"
|
36
|
-
s.add_dependency "curb", "~> 0.8.
|
36
|
+
s.add_dependency "curb", "~> 0.8.1"
|
37
37
|
|
38
|
-
s.add_development_dependency "yard", "~> 0.
|
38
|
+
s.add_development_dependency "yard", "~> 0.8"
|
39
39
|
s.add_development_dependency "rcov", "~> 0.9"
|
40
40
|
s.add_development_dependency "turn", "~> 0.9.6"
|
41
|
-
s.add_development_dependency "shoulda"
|
42
|
-
s.add_development_dependency "fakeweb"
|
43
|
-
s.add_development_dependency "factory_girl", "~> 3.3
|
44
|
-
s.add_development_dependency "minitest"
|
41
|
+
s.add_development_dependency "shoulda", "~> 3.1"
|
42
|
+
s.add_development_dependency "fakeweb", "~> 1.3"
|
43
|
+
s.add_development_dependency "factory_girl", "~> 3.3"
|
44
|
+
s.add_development_dependency "minitest", "~> 3.3"
|
45
45
|
|
46
46
|
end
|
data/examples/add_ad_group.rb
CHANGED
@@ -2,12 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'adapi'
|
4
4
|
|
5
|
-
# create campaign
|
6
5
|
require_relative 'add_bare_campaign'
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
ad_group_data = {
|
7
|
+
$ad_group_data = {
|
11
8
|
:name => "AdGroup #%d" % (Time.new.to_f * 1000).to_i,
|
12
9
|
:status => 'ENABLED',
|
13
10
|
:campaign_id => $campaign[:id],
|
@@ -25,7 +22,16 @@ ad_group_data = {
|
|
25
22
|
]
|
26
23
|
}
|
27
24
|
|
28
|
-
$ad_group = Adapi::AdGroup.create(ad_group_data)
|
25
|
+
$ad_group = Adapi::AdGroup.create($ad_group_data)
|
26
|
+
|
27
|
+
unless $ad_group.errors.empty?
|
28
|
+
|
29
|
+
puts "ERROR WHEN CREATING AD GROUP:"
|
30
|
+
pp $ad_group.errors.full_messages
|
31
|
+
|
32
|
+
else
|
33
|
+
|
34
|
+
puts "\nCREATED AD GROUP #{$ad_group[:id]} FOR CAMPAIGN #{$ad_group[:campaign_id]}\n"
|
35
|
+
pp $ad_group.attributes
|
29
36
|
|
30
|
-
|
31
|
-
p $ad_group.attributes
|
37
|
+
end
|
@@ -2,7 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'adapi'
|
4
4
|
|
5
|
-
# create campaign
|
6
5
|
require_relative 'add_bare_campaign'
|
7
6
|
|
8
7
|
# create ad group with basic data only
|
@@ -14,13 +13,20 @@ $ad_group_data = {
|
|
14
13
|
:status => 'ENABLED',
|
15
14
|
:bids => {
|
16
15
|
:xsi_type => 'BudgetOptimizerAdGroupBids',
|
17
|
-
|
18
|
-
:proxy_keyword_max_cpc => 15,
|
19
|
-
:proxy_site_max_cpc => 30
|
16
|
+
:proxy_keyword_max_cpc => 15
|
20
17
|
}
|
21
18
|
}
|
22
19
|
|
23
20
|
$ad_group = Adapi::AdGroup.create($ad_group_data)
|
24
21
|
|
25
|
-
|
26
|
-
|
22
|
+
unless $ad_group.errors.empty?
|
23
|
+
|
24
|
+
puts "ERROR WHEN CREATING AD GROUP:"
|
25
|
+
pp $ad_group.errors.full_messages
|
26
|
+
|
27
|
+
else
|
28
|
+
|
29
|
+
puts "\nCREATED AD GROUP #{$ad_group[:id]} FOR CAMPAIGN #{$ad_group[:campaign_id]}\n"
|
30
|
+
pp $ad_group.attributes
|
31
|
+
|
32
|
+
end
|
@@ -16,13 +16,20 @@ $campaign_data = {
|
|
16
16
|
:network_setting => {
|
17
17
|
:target_google_search => true,
|
18
18
|
:target_search_network => true,
|
19
|
-
:target_content_network => false
|
20
|
-
:target_content_contextual => false,
|
21
|
-
:target_partner_search_network => false
|
19
|
+
:target_content_network => false
|
22
20
|
}
|
23
21
|
}
|
24
|
-
|
22
|
+
|
25
23
|
$campaign = Adapi::Campaign.create($campaign_data)
|
26
24
|
|
27
|
-
|
28
|
-
|
25
|
+
unless $campaign.errors.empty?
|
26
|
+
|
27
|
+
puts "ERROR WHEN CREATING CAMPAIGN:"
|
28
|
+
pp $campaign.errors.full_messages
|
29
|
+
|
30
|
+
else
|
31
|
+
|
32
|
+
puts "\nCREATED CAMPAIGN #{$campaign[:id]}\n"
|
33
|
+
pp $campaign.attributes
|
34
|
+
|
35
|
+
end
|
data/examples/add_campaign.rb
CHANGED
@@ -15,8 +15,7 @@ campaign_data = {
|
|
15
15
|
:network_setting => {
|
16
16
|
:target_google_search => true,
|
17
17
|
:target_search_network => true,
|
18
|
-
:target_content_network => false
|
19
|
-
:target_content_contextual => false
|
18
|
+
:target_content_network => false
|
20
19
|
},
|
21
20
|
|
22
21
|
# PS: :targets key is obsolete, this should be named :criteria, but it still works
|
@@ -46,15 +45,28 @@ campaign_data = {
|
|
46
45
|
]
|
47
46
|
|
48
47
|
}
|
49
|
-
|
50
|
-
$campaign = Adapi::Campaign.create(campaign_data)
|
51
48
|
|
52
|
-
$campaign = Adapi::Campaign.
|
49
|
+
$campaign = Adapi::Campaign.new(campaign_data)
|
53
50
|
|
54
|
-
|
55
|
-
pp $campaign.attributes
|
51
|
+
$campaign.create
|
56
52
|
|
57
|
-
|
53
|
+
unless $campaign.errors.empty?
|
58
54
|
|
59
|
-
|
60
|
-
pp $
|
55
|
+
puts "ERROR WHEN CREATING CAMPAIGN:"
|
56
|
+
pp $campaign.errors.full_messages
|
57
|
+
|
58
|
+
else
|
59
|
+
|
60
|
+
puts "\nCREATED CAMPAIGN #{$campaign[:id]}\n"
|
61
|
+
|
62
|
+
$campaign = Adapi::Campaign.find($campaign[:id])
|
63
|
+
|
64
|
+
puts "\nCAMPAIGN DATA:"
|
65
|
+
pp $campaign.attributes
|
66
|
+
|
67
|
+
$campaign_criteria = Adapi::CampaignCriterion.find( :campaign_id => $campaign[:id] )
|
68
|
+
|
69
|
+
puts "\nCRITERIA:"
|
70
|
+
pp $campaign_criteria
|
71
|
+
|
72
|
+
end
|
@@ -2,12 +2,11 @@
|
|
2
2
|
|
3
3
|
require 'adapi'
|
4
4
|
|
5
|
-
# create campaign
|
6
5
|
require_relative 'add_bare_campaign'
|
7
6
|
|
8
|
-
$
|
9
|
-
:campaign_id => $campaign
|
10
|
-
:
|
7
|
+
$campaign_criteria_data = {
|
8
|
+
:campaign_id => $campaign[:id],
|
9
|
+
:criteria => {
|
11
10
|
:language => %w{ en cs },
|
12
11
|
|
13
12
|
:location => {
|
@@ -19,9 +18,24 @@ $campaign_criterion = Adapi::CampaignCriterion.new(
|
|
19
18
|
# add custom platform criteria
|
20
19
|
:platform => [ { :id => 30001} ]
|
21
20
|
}
|
22
|
-
|
21
|
+
}
|
23
22
|
|
24
|
-
$
|
23
|
+
$campaign_criteria = Adapi::CampaignCriterion.new($campaign_criteria_data)
|
25
24
|
|
26
|
-
$
|
27
|
-
|
25
|
+
$campaign_criteria.create
|
26
|
+
|
27
|
+
unless $campaign_criteria.errors.empty?
|
28
|
+
|
29
|
+
puts "ERROR WHEN CREATING CAMPAIGN CRITERIA FOR CAMPAIGN #{$campaign[:id]}:"
|
30
|
+
pp $campaign_criteria.errors.full_messages
|
31
|
+
|
32
|
+
else
|
33
|
+
|
34
|
+
puts "\nCREATED CAMPAIGN CRITERIA FOR CAMPAIGN #{$campaign[:id]}\n"
|
35
|
+
|
36
|
+
$campaign_criteria = Adapi::CampaignCriterion.find( :campaign_id => $campaign[:id] )
|
37
|
+
|
38
|
+
puts "\nCRITERIA:"
|
39
|
+
pp $campaign_criteria
|
40
|
+
|
41
|
+
end
|
@@ -27,10 +27,14 @@ ad_group_data = {
|
|
27
27
|
|
28
28
|
$ad_group = Adapi::AdGroup.create(ad_group_data)
|
29
29
|
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
unless $ad_group.errors.empty?
|
31
|
+
|
32
|
+
puts "ERROR WHEN CREATING AD GROUP:"
|
33
|
+
pp $ad_group.errors.full_messages
|
34
|
+
|
33
35
|
else
|
34
|
-
|
35
|
-
puts $ad_group
|
36
|
+
|
37
|
+
puts "AD GROUP #{$ad_group[:id]} CREATED"
|
38
|
+
pp $ad_group.attributes
|
39
|
+
|
36
40
|
end
|
@@ -4,6 +4,9 @@ require 'adapi'
|
|
4
4
|
|
5
5
|
# Errors will appear only in production, not in sandbox
|
6
6
|
#
|
7
|
+
# Adapi performs exemption requests on receiving policy violation errors.
|
8
|
+
# If keyword errors are exemptable, they will eventually pass.
|
9
|
+
#
|
7
10
|
#Adapi::Config.load_settings
|
8
11
|
#Adapi::Config.set(:production_settings)
|
9
12
|
#
|
@@ -3,6 +3,9 @@ require 'adapi'
|
|
3
3
|
|
4
4
|
# PolicyViolations will appear only in production, not in sandbox
|
5
5
|
#
|
6
|
+
# Adapi performs exemption requests on receiving policy violation errors.
|
7
|
+
# If text_ad errors are exemptable, they will eventually pass.
|
8
|
+
#
|
6
9
|
#Adapi::Config.load_settings
|
7
10
|
#Adapi::Config.set(:production_settings)
|
8
11
|
#
|
@@ -10,21 +13,24 @@ require 'adapi'
|
|
10
13
|
|
11
14
|
require_relative 'add_bare_ad_group'
|
12
15
|
|
16
|
+
# PS: exemptable PolicyViolationError is triggered by "ho":
|
17
|
+
# legimitateword in Czech, but suspicious word in English
|
18
|
+
#
|
13
19
|
$ad = Adapi::Ad::TextAd.create(
|
14
20
|
:ad_group_id => $ad_group[:id],
|
15
|
-
:headline => "
|
16
|
-
:description1 => '
|
17
|
-
:description2 => 'Check out my
|
21
|
+
:headline => "Neo Blog - poznej ho",
|
22
|
+
:description1 => 'Poznej ho kdekoliv',
|
23
|
+
:description2 => 'Check out my ho blog',
|
18
24
|
:url => 'http://www.demcodez.com',
|
19
25
|
:display_url => 'http://www.demcodez.com',
|
20
26
|
:status => 'PAUSED'
|
21
27
|
)
|
22
28
|
|
23
29
|
if $ad.errors.empty?
|
24
|
-
puts "
|
30
|
+
puts "INVALID TEXT AD CREATED"
|
25
31
|
$fresh_ad = Adapi::Ad::TextAd.find(:first, :id => $ad.id, :ad_group_id => $ad_group[:id])
|
26
32
|
pp $fresh_ad.attributes
|
27
33
|
else
|
28
|
-
puts "
|
29
|
-
|
34
|
+
puts "ERRORS:"
|
35
|
+
pp $ad.errors.messages
|
30
36
|
end
|