adapi 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/README.markdown +176 -0
- data/Rakefile +32 -0
- data/adapi.gemspec +7 -4
- data/examples/add_ad_group.rb +1 -0
- data/examples/add_bare_ad_group.rb +2 -6
- data/examples/add_bare_campaign.rb +1 -0
- data/examples/add_campaign.rb +1 -0
- data/examples/add_campaign_targets.rb +1 -0
- data/examples/add_invalid_ad_group.rb +1 -0
- data/examples/add_keywords.rb +13 -1
- data/examples/custom_settings.yml +2 -2
- data/examples/customize_configuration.rb +2 -0
- data/examples/delete_keyword.rb +27 -0
- data/examples/find_all_campaigns.rb +13 -0
- data/examples/find_campaign.rb +39 -0
- data/examples/find_campaign_ad_groups.rb +25 -0
- data/examples/log_to_specific_account.rb +1 -0
- data/examples/rollback_campaign.rb +1 -0
- data/lib/adapi.rb +8 -5
- data/lib/adapi/ad.rb +2 -0
- data/lib/adapi/ad/text_ad.rb +15 -0
- data/lib/adapi/ad_group.rb +45 -6
- data/lib/adapi/ad_group_criterion.rb +14 -0
- data/lib/adapi/api.rb +6 -0
- data/lib/adapi/campaign.rb +48 -5
- data/lib/adapi/campaign_target.rb +67 -8
- data/lib/adapi/config.rb +1 -0
- data/lib/adapi/keyword.rb +78 -11
- data/lib/adapi/version.rb +9 -1
- data/lib/httpi_request_monkeypatch.rb +1 -0
- data/test/factories/ad_group_factory.rb +4 -13
- data/test/factories/ad_text_factory.rb +1 -0
- data/test/test_helper.rb +3 -0
- data/test/unit/ad/ad_text_test.rb +2 -0
- data/test/unit/ad_group_test.rb +11 -2
- data/test/unit/ad_test.rb +2 -0
- data/test/unit/campaign_target_test.rb +15 -0
- metadata +67 -32
- data/README.rdoc +0 -162
- data/lib/collection.rb +0 -429
data/.gitignore
CHANGED
data/README.markdown
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
# Adapi #
|
2
|
+
|
3
|
+
## Description ##
|
4
|
+
|
5
|
+
Adapi (ADwords API) is a Ruby library for easy and painless work with Google
|
6
|
+
Adwords API. Its users shouldn't bother with SOAP and tangle of XML- and
|
7
|
+
API-specific objects, inputs and outputs are plain Ruby arrays and hashes.
|
8
|
+
|
9
|
+
Adapi is built on `google-adwords-api` gem. Arrays and hashes instead of objects
|
10
|
+
come from there, but adapi takes it several steps further:
|
11
|
+
|
12
|
+
* AdWords services are represented by ActiveModel-compatible models with
|
13
|
+
relations. Among other things it's possible to create whole campaign in
|
14
|
+
single method call: `Adapi::Campaign.create(campaign_data)`.
|
15
|
+
|
16
|
+
* Various convenience methods are added to the models, for example:
|
17
|
+
`campaign.pause!` (pauses campaign).
|
18
|
+
|
19
|
+
* Adapi enables you to easily work with multiple AdWords accounts at the same time.
|
20
|
+
|
21
|
+
Adapi is *still in development* and not nearly done yet! Version 1.0.0 should
|
22
|
+
have all planned functionality.
|
23
|
+
|
24
|
+
## Installation ##
|
25
|
+
|
26
|
+
```
|
27
|
+
gem install adapi
|
28
|
+
```
|
29
|
+
|
30
|
+
### from git repository ###
|
31
|
+
|
32
|
+
```
|
33
|
+
git clone git@github.com:lstejskal/adapi.git
|
34
|
+
cd adapi
|
35
|
+
bundle install
|
36
|
+
rake install
|
37
|
+
```
|
38
|
+
|
39
|
+
## Configuration ##
|
40
|
+
|
41
|
+
This section explains how to connect to specific AdWords account and client.
|
42
|
+
|
43
|
+
You can set many AdWords accounts to connect to and switch between while running
|
44
|
+
the application. You can even update single values of the settings on-the-fly.
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
# load the settings
|
48
|
+
Adapi::Config.load_settings(:in_hash => {
|
49
|
+
:coca_cola => {
|
50
|
+
:authentication => {
|
51
|
+
:method => 'ClientLogin',
|
52
|
+
:email => 'coca_cola_email@gmail.com',
|
53
|
+
:password => 'coca_cola_password',
|
54
|
+
:developer_token => 'coca_cola_developer_token',
|
55
|
+
:user_agent => 'Coca-Cola Adwords API Test'
|
56
|
+
},
|
57
|
+
:service => {
|
58
|
+
:environment => 'SANDBOX'
|
59
|
+
}
|
60
|
+
},
|
61
|
+
:pepsi => {
|
62
|
+
:authentication => {
|
63
|
+
:method => 'ClientLogin',
|
64
|
+
:email => 'pepsi_email@gmail.com',
|
65
|
+
:password => 'pepsi_password',
|
66
|
+
:developer_token => 'pepsi_developer_token',
|
67
|
+
:user_agent => 'Pepsi Adwords API Test'
|
68
|
+
},
|
69
|
+
:service => {
|
70
|
+
:environment => 'SANDBOX'
|
71
|
+
}
|
72
|
+
}
|
73
|
+
})
|
74
|
+
|
75
|
+
# set to pepsi and specific client
|
76
|
+
Adapi::Config.set(:pepsi, :client_customer_id => '555-666-7777')
|
77
|
+
|
78
|
+
# do some stuff here...
|
79
|
+
|
80
|
+
# set to coca-cola and another client
|
81
|
+
Adapi::Config.set(:coca_cola, :client_customer_id => '777-666-5555')
|
82
|
+
|
83
|
+
# do some stuff here...
|
84
|
+
```
|
85
|
+
|
86
|
+
### Authentication workflow ###
|
87
|
+
|
88
|
+
* load configuration from `~/adapi.yml`
|
89
|
+
* load configuration from `~/adwords_api.yml` (default configuration for AdWords gems
|
90
|
+
from Google)
|
91
|
+
* set configuration directly to `Adapi::Config` (overrides previous settings)
|
92
|
+
|
93
|
+
### Configuration by `adapi.yml` ###
|
94
|
+
|
95
|
+
Stored in `~/adapi.yml`. Supports multiple accounts, which are identifed by
|
96
|
+
aliases. Example:
|
97
|
+
|
98
|
+
```
|
99
|
+
:default:
|
100
|
+
:authentication:
|
101
|
+
:method: ClientLogin
|
102
|
+
:email: default_email@gmail.com
|
103
|
+
:password: default_password
|
104
|
+
:developer_token: default_token
|
105
|
+
:client_customer_id: 777-666-5555
|
106
|
+
:user_agent: My Adwords API Client
|
107
|
+
:service:
|
108
|
+
:environment: PRODUCTION
|
109
|
+
|
110
|
+
:sandbox:
|
111
|
+
:authentication:
|
112
|
+
:method: ClientLogin
|
113
|
+
:email: sandbox_email@gmail.com
|
114
|
+
:password: sandbox_password
|
115
|
+
:developer_token: sandbox_token
|
116
|
+
:client_customer_id: 555-666-7777
|
117
|
+
:user_agent: Adwords API Test
|
118
|
+
:service:
|
119
|
+
:environment: SANDBOX
|
120
|
+
```
|
121
|
+
|
122
|
+
You tell adapi which account to use by setting an alias:
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
Adapi::Config.set(:sandbox)
|
126
|
+
```
|
127
|
+
|
128
|
+
`:default` account is, as name implies, used by default. You must either set an
|
129
|
+
alias to `Adapi::Config` or have account with `:default` alias available.
|
130
|
+
|
131
|
+
### Configuration by adwords_api.yml ###
|
132
|
+
|
133
|
+
If you already have `google-adwords-api` gem configured and use just one account,
|
134
|
+
the same configuration will also work for adapi: `~/adwords_api.yml`
|
135
|
+
|
136
|
+
### Configuration directly in code ###
|
137
|
+
|
138
|
+
Before logging into the Adwords API, you can set global settings through
|
139
|
+
`Adapi::Config`:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
# load the settings
|
143
|
+
Adapi::Config.load_settings(:in_hash => {
|
144
|
+
:sandbox => {
|
145
|
+
:authentication => {
|
146
|
+
:method => "ClientLogin"
|
147
|
+
:email => "sandbox_email@gmail.com",
|
148
|
+
:password => "sandbox_password",
|
149
|
+
:developer_token => "sandbox_token",
|
150
|
+
:client_customer_id => "555-666-7777",
|
151
|
+
:user_agent => "Adwords API Test"
|
152
|
+
},
|
153
|
+
:service => {
|
154
|
+
:environment => "SANDBOX"
|
155
|
+
}
|
156
|
+
}
|
157
|
+
})
|
158
|
+
|
159
|
+
Adapi::Config.set(:sandbox)
|
160
|
+
```
|
161
|
+
|
162
|
+
## API Version Support ##
|
163
|
+
|
164
|
+
* adapi supports only the latest version of Google AdWords API: *v201109*
|
165
|
+
* older versions will not be supported (well, maybe *v201101*)
|
166
|
+
* *v201109* and newer versions will still be supported when new versions are released
|
167
|
+
|
168
|
+
## Examples ##
|
169
|
+
|
170
|
+
Example are available in [examples directory](./master/examples/). For now, they
|
171
|
+
are mostly just uninspired rewrites of examples from `google-adwords-api` gem,
|
172
|
+
but that's going to change when proper UI to AdWords models will be implemented.
|
173
|
+
|
174
|
+
## Author ##
|
175
|
+
|
176
|
+
Lukas Stejskal
|
data/Rakefile
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'bundler/gem_tasks'
|
2
2
|
require 'rake'
|
3
3
|
|
4
|
+
### Tests ###
|
5
|
+
|
4
6
|
task :default => :test
|
5
7
|
|
6
8
|
require 'rake/testtask'
|
@@ -10,3 +12,33 @@ Rake::TestTask.new(:test) do |test|
|
|
10
12
|
test.verbose = true
|
11
13
|
end
|
12
14
|
|
15
|
+
require 'rcov/rcovtask'
|
16
|
+
Rcov::RcovTask.new do |t|
|
17
|
+
t.libs << "test"
|
18
|
+
t.pattern = 'test/*/*_test.rb'
|
19
|
+
t.rcov_opts << '--exclude /gems/'
|
20
|
+
end
|
21
|
+
|
22
|
+
### Documentation ###
|
23
|
+
|
24
|
+
require 'yard'
|
25
|
+
require 'yard/rake/yardoc_task'
|
26
|
+
|
27
|
+
desc "Generate documentation"
|
28
|
+
task :doc => 'doc:generate'
|
29
|
+
|
30
|
+
namespace :doc do
|
31
|
+
GEM_ROOT = File.dirname(__FILE__)
|
32
|
+
RDOC_ROOT = File.join(GEM_ROOT, 'doc')
|
33
|
+
|
34
|
+
YARD::Rake::YardocTask.new(:generate) do |rdoc|
|
35
|
+
rdoc.files = Dir.glob(File.join(GEM_ROOT, 'lib', '**', '*.rb')) +
|
36
|
+
[ File.join(GEM_ROOT, 'README.md') ]
|
37
|
+
rdoc.options = ['--output-dir', RDOC_ROOT, '--readme', 'README.md']
|
38
|
+
end
|
39
|
+
|
40
|
+
desc "Remove generated documentation"
|
41
|
+
task :clobber do
|
42
|
+
FileUtils.rm_rf(RDOC_ROOT) if File.exists?(RDOC_ROOT)
|
43
|
+
end
|
44
|
+
end
|
data/adapi.gemspec
CHANGED
@@ -20,13 +20,16 @@ Gem::Specification.new do |s|
|
|
20
20
|
|
21
21
|
s.add_dependency "google-ads-common", "~> 0.5.0"
|
22
22
|
s.add_dependency "google-adwords-api", "~> 0.4.0"
|
23
|
-
s.add_dependency "activemodel", "~> 3.1
|
24
|
-
s.add_dependency "activesupport", "~> 3.1
|
23
|
+
s.add_dependency "activemodel", "~> 3.1"
|
24
|
+
s.add_dependency "activesupport", "~> 3.1"
|
25
25
|
s.add_dependency "rake", "~> 0.9.2"
|
26
|
-
s.add_dependency "curb", "~> 0.7
|
26
|
+
s.add_dependency "curb", "~> 0.7"
|
27
27
|
|
28
|
-
s.add_development_dependency "
|
28
|
+
s.add_development_dependency "yard", "~> 0.7"
|
29
|
+
s.add_development_dependency "rcov", "~> 0.9"
|
30
|
+
s.add_development_dependency "turn", "0.8.2" # PS: 0.8.3 is broken
|
29
31
|
s.add_development_dependency "shoulda"
|
30
32
|
s.add_development_dependency "fakeweb"
|
31
33
|
s.add_development_dependency "factory_girl"
|
34
|
+
s.add_development_dependency "minitest"
|
32
35
|
end
|
data/examples/add_ad_group.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
|
2
3
|
require 'adapi'
|
3
4
|
|
@@ -15,12 +16,7 @@ $ad_group_data = {
|
|
15
16
|
:bids => {
|
16
17
|
# this should be set automatically, it's dependent on Campaign.bids
|
17
18
|
:xsi_type => 'BudgetOptimizerAdGroupBids',
|
18
|
-
|
19
|
-
:proxy_keyword_max_cpc => {
|
20
|
-
:amount => {
|
21
|
-
:micro_amount => 10000000
|
22
|
-
}
|
23
|
-
}
|
19
|
+
:proxy_keyword_max_cpc => 10
|
24
20
|
}
|
25
21
|
}
|
26
22
|
|
data/examples/add_campaign.rb
CHANGED
data/examples/add_keywords.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
|
2
3
|
require 'adapi'
|
3
4
|
|
@@ -11,4 +12,15 @@ $keywords = Adapi::Keyword.new(
|
|
11
12
|
|
12
13
|
$r = $keywords.create
|
13
14
|
|
14
|
-
|
15
|
+
# get array of keywords from Keyword instance
|
16
|
+
$google_keywords = Adapi::Keyword.find(:all, :ad_group_id => $ad_group[:id]).keywords
|
17
|
+
|
18
|
+
$params_keywords = Adapi::Keyword.parameterized($google_keywords)
|
19
|
+
|
20
|
+
$short_keywords = Adapi::Keyword.shortened($google_keywords)
|
21
|
+
|
22
|
+
p "PARAMS:"
|
23
|
+
pp $params_keywords
|
24
|
+
|
25
|
+
p "\nSHORT:"
|
26
|
+
pp $short_keywords
|
@@ -5,7 +5,7 @@
|
|
5
5
|
:email: default_email@gmail.com
|
6
6
|
:password: default_password
|
7
7
|
:developer_token: default_token
|
8
|
-
:
|
8
|
+
:client_customer_id: 555-666-7777
|
9
9
|
:user_agent: My Adwords API Client
|
10
10
|
:service:
|
11
11
|
:environment: PRODUCTION
|
@@ -16,7 +16,7 @@
|
|
16
16
|
:email: sandbox_email@gmail.com
|
17
17
|
:password: sandbox_password
|
18
18
|
:developer_token: sandbox_token
|
19
|
-
:
|
19
|
+
:client_customer_id: 555-666-7777
|
20
20
|
:user_agent: Adwords API Test
|
21
21
|
:service:
|
22
22
|
:environment: SANDBOX
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'adapi'
|
4
|
+
|
5
|
+
# create ad group
|
6
|
+
require File.join(File.dirname(__FILE__), 'add_bare_ad_group')
|
7
|
+
|
8
|
+
$keywords = Adapi::Keyword.new(
|
9
|
+
:ad_group_id => $ad_group[:id],
|
10
|
+
:keywords => [ 'dem codez', '-hacker' ]
|
11
|
+
)
|
12
|
+
|
13
|
+
$r = $keywords.create
|
14
|
+
|
15
|
+
# get array of keywords for ad_group
|
16
|
+
$google_keywords = Adapi::Keyword.find(:all, :ad_group_id => $ad_group[:id]).keywords
|
17
|
+
|
18
|
+
p "BEFORE DELETE: #{$google_keywords.size} keywords"
|
19
|
+
|
20
|
+
if Adapi::Keyword.new(:ad_group_id => $ad_group[:id]).delete($google_keywords.first[:text][:criterion][:id])
|
21
|
+
p "SUCCESS: first keyword deleted."
|
22
|
+
else
|
23
|
+
p "ERROR: keyword could not be deleted."
|
24
|
+
end
|
25
|
+
|
26
|
+
$google_keywords = Adapi::Keyword.find(:all, :ad_group_id => $ad_group[:id]).keywords
|
27
|
+
p "AFTER DELETE: #{$google_keywords.size} keywords"
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'adapi'
|
4
|
+
|
5
|
+
# find all campaigns for customer
|
6
|
+
|
7
|
+
$campaigns = Adapi::Campaign.find :all
|
8
|
+
|
9
|
+
p "Found %s campaigns." % $campaigns.size
|
10
|
+
|
11
|
+
$campaigns.each do |campaign|
|
12
|
+
p "ID: %s, NAME %s" % [ campaign[:id], campaign[:name] ]
|
13
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'adapi'
|
4
|
+
|
5
|
+
# create campaign
|
6
|
+
require File.join(File.dirname(__FILE__), 'add_campaign')
|
7
|
+
|
8
|
+
$campaign = Adapi::Campaign.find_complete($campaign.id).to_hash
|
9
|
+
|
10
|
+
puts "Campaign id: %s" % $campaign[:id]
|
11
|
+
puts "Name: %s" % $campaign[:name]
|
12
|
+
puts "Status: %s" % $campaign[:status]
|
13
|
+
|
14
|
+
puts "\nBudget delivery method: %s" % $campaign[:budget][:delivery_method]
|
15
|
+
puts "Budget period: %s" % $campaign[:budget][:period]
|
16
|
+
# TODO budget.amount
|
17
|
+
|
18
|
+
puts "\nBidding strategy type: %s" % $campaign[:bidding_strategy][:xsi_type]
|
19
|
+
# TODO bidding_strategy.bid_ceiling
|
20
|
+
|
21
|
+
puts "\nTargets:"
|
22
|
+
$campaign[:targets].each do |target|
|
23
|
+
p target[:xsi_type]
|
24
|
+
p target
|
25
|
+
end
|
26
|
+
|
27
|
+
puts "\nAd groups (#{$campaign[:ad_groups].size} in total):"
|
28
|
+
$campaign[:ad_groups].each do |ad_group|
|
29
|
+
puts "ID: %s, NAME %s, STATUS %s" % [ ad_group[:id], ad_group[:name], ad_group[:status] ]
|
30
|
+
puts "KEYWORDS: %s" % ad_group[:keywords].join(", ")
|
31
|
+
puts "ADS:"
|
32
|
+
ad_group[:ads].each do |ad|
|
33
|
+
puts "\nheadline: %s" % ad[:headline]
|
34
|
+
puts "description1: %s" % ad[:description1]
|
35
|
+
puts "description2: %s" % ad[:description2]
|
36
|
+
puts "url: %s" % ad[:url]
|
37
|
+
puts "display_url: %s" % ad[:display_url]
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'adapi'
|
4
|
+
|
5
|
+
# create campaign
|
6
|
+
require File.join(File.dirname(__FILE__), 'add_bare_ad_group')
|
7
|
+
|
8
|
+
# find all ad_groups for campaign
|
9
|
+
|
10
|
+
$ad_groups = Adapi::AdGroup.find :all, :campaign_id => $campaign.to_param
|
11
|
+
|
12
|
+
p "Found %s ad groups." % $ad_groups.size
|
13
|
+
|
14
|
+
$ad_groups.each do |ad_group|
|
15
|
+
puts "ID: %s, NAME %s, STATUS %s" % [ ad_group[:id], ad_group[:name], ad_group[:status] ]
|
16
|
+
puts "KEYWORDS: %s" % ad_group[:keywords].join(", ")
|
17
|
+
puts "ADS:"
|
18
|
+
ad_group[:ads].each do |ad|
|
19
|
+
puts "\nheadline: %s" % ad[:headline]
|
20
|
+
puts "description1: %s" % ad[:description1]
|
21
|
+
puts "description2: %s" % ad[:description2]
|
22
|
+
puts "url: %s" % ad[:url]
|
23
|
+
puts "display_url: %s" % ad[:display_url]
|
24
|
+
end
|
25
|
+
end
|