zuck 2.0.0 → 2.1.0
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 +13 -5
- data/CHANGELOG.markdown +9 -0
- data/README.markdown +7 -1
- data/VERSION +1 -1
- data/lib/zuck/facebook/ad_creative.rb +0 -3
- data/lib/zuck/facebook/ad_group.rb +7 -7
- data/lib/zuck/facebook/targeting_spec.rb +0 -1
- data/lib/zuck.rb +6 -0
- data/spec/fixtures/a_single_account.yml +31 -111
- data/spec/fixtures/a_single_campaign.yml +11 -57
- data/spec/fixtures/a_single_group.yml +13 -62
- data/spec/fixtures/ad_interest_search_disney.yml +19 -19
- data/spec/fixtures/ad_interest_search_moviepilot.yml +15 -18
- data/spec/fixtures/ad_interest_search_nonexistant.yml +11 -11
- data/spec/fixtures/create_a_creative.yml +48 -0
- data/spec/fixtures/create_ad_campaign.yml +44 -226
- data/spec/fixtures/create_ad_group.yml +13 -155
- data/spec/fixtures/create_ad_set.yml +11 -57
- data/spec/fixtures/delete_ad_group.yml +10 -55
- data/spec/fixtures/delete_ad_set.yml +48 -0
- data/spec/fixtures/delete_campaign.yml +93 -0
- data/spec/fixtures/delete_creative.yml +48 -0
- data/spec/fixtures/find_a_single_group_and_update_it.yml +84 -110
- data/spec/fixtures/list_of_ad_accounts.yml +10 -57
- data/spec/fixtures/list_of_ad_campaigns.yml +10 -57
- data/spec/fixtures/list_of_ad_creatives.yml +9 -56
- data/spec/fixtures/list_of_ad_groups.yml +10 -57
- data/spec/fixtures/list_of_all_ad_creatives_of_account.yml +10 -57
- data/spec/fixtures/reach_for_invalid_interest.yml +28 -31
- data/spec/fixtures/reach_for_valid_keywords.yml +13 -13
- data/spec/fixtures/reach_for_valid_keywords_male_young.yml +13 -13
- data/spec/lib/zuck/facebook/ad_interest_spec.rb +1 -1
- data/spec/lib/zuck/facebook/targeting_spec_spec.rb +3 -3
- data/spec/lib/zuck_spec.rb +125 -86
- data/spec/spec_helper.rb +14 -0
- data/test_access_token +1 -1
- data/zuck.gemspec +7 -3
- metadata +49 -45
data/spec/lib/zuck_spec.rb
CHANGED
@@ -2,56 +2,121 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Zuck::FbObject do
|
4
4
|
|
5
|
-
before(:all)
|
5
|
+
before(:all) {
|
6
|
+
puts "Koala version: #{Koala.config.api_version}"
|
6
7
|
Zuck.graph = Koala::Facebook::API.new(test_access_token)
|
7
|
-
|
8
|
+
}
|
8
9
|
|
9
|
-
let(:graph) { Zuck.graph }
|
10
|
-
let(:account) { Zuck::AdAccount.new(graph, {id: "act_10150585630710217"}) }
|
11
|
-
let(:campaign){ Zuck::AdCampaign.new(graph, {id: "6021499361751"}, account) }
|
12
|
-
let(:group) { Zuck::AdGroup.new(graph, {id: "6010889169151"}, campaign)}
|
13
|
-
let(:creative){ Zuck::AdCreative.new(graph, {id: "6021396606151"}, group) }
|
14
|
-
let(:set) { Zuck::AdSet.new(graph, {id: "6021525283751"}, account) }
|
15
10
|
|
11
|
+
let(:graph) { Zuck.graph }
|
12
|
+
let(:account_id) { "act_367106653" }
|
13
|
+
let(:account) { Zuck::AdAccount.new(graph, {id: account_id}) }
|
16
14
|
|
17
|
-
describe "
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
15
|
+
describe "talking to facebook" do
|
16
|
+
act_campaign = nil
|
17
|
+
campaign = nil
|
18
|
+
creative = nil
|
19
|
+
group = nil
|
20
|
+
set = nil
|
23
21
|
|
24
|
-
|
25
|
-
expect{
|
26
|
-
creative.save
|
27
|
-
}.to raise_error(Zuck::Error::ReadOnly)
|
28
|
-
end
|
22
|
+
context "creating" do
|
29
23
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
24
|
+
it "an ad campaign via an existing ad account" do
|
25
|
+
VCR.use_cassette('create_ad_campaign') do
|
26
|
+
o = {
|
27
|
+
daily_budget: 1000,
|
28
|
+
name: "bloody campaign (via account)"
|
29
|
+
}
|
30
|
+
explain_error {
|
31
|
+
act_campaign = account.create_ad_campaign(o)
|
32
|
+
act_campaign.name.should == "bloody campaign (via account)"
|
33
|
+
}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
it "an ad campaign" do
|
39
|
+
VCR.use_cassette('create_ad_campaign') do
|
40
|
+
o = {
|
41
|
+
objective: 'NONE',
|
42
|
+
name: "bloody campaign",
|
43
|
+
campaign_group_status: 'PAUSED'
|
44
|
+
}
|
45
|
+
explain_error {
|
46
|
+
campaign = Zuck::AdCampaign.create(graph, o, account)
|
47
|
+
campaign.name.should == "bloody campaign"
|
48
|
+
}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
it "an ad set" do
|
53
|
+
VCR.use_cassette('create_ad_set') do
|
54
|
+
o = {
|
55
|
+
bid_type: 'CPC',
|
56
|
+
bid_info: "{'CLICKS': 1}",
|
57
|
+
name: 'bloody ad set',
|
58
|
+
campaign_status: 'PAUSED',
|
59
|
+
daily_budget: 100,
|
60
|
+
targeting: "{'geo_locations':{'countries':['US','GB']}}",
|
61
|
+
campaign_group_id: campaign.id
|
62
|
+
}
|
63
|
+
explain_error {
|
64
|
+
set = Zuck::AdSet.create(graph, o, account)
|
65
|
+
set.name.should == 'bloody ad set'
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "a creative by uploading an image" do
|
71
|
+
VCR.use_cassette('create a creative') do
|
72
|
+
o = {
|
73
|
+
title: 'bloody title',
|
74
|
+
body: 'bloody body',
|
75
|
+
object_url: 'http://moviepilot.com/',
|
76
|
+
image_url: 'http://images-cdn.moviepilot.com/image/upload/c_fill,h_246,w_470/v1427727623/moviepilot.jpg'
|
77
|
+
}
|
78
|
+
explain_error {
|
79
|
+
creative = Zuck::AdCreative.create(graph, o, account)
|
80
|
+
creative.id.should_not == nil
|
81
|
+
}
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
it "an ad group via an existing ad campaign" do
|
87
|
+
VCR.use_cassette('create_ad_group') do
|
88
|
+
o = {
|
89
|
+
name: "Rap like me",
|
90
|
+
# targeting: '{"geo_locations": {"countries":["US"]}}',
|
91
|
+
objective: 'WEBSITE_CLICKS',
|
92
|
+
creative: '{"creative_id": '+creative.id+'}'
|
93
|
+
}
|
94
|
+
explain_error {
|
95
|
+
group = set.create_ad_group(o)
|
96
|
+
group.name.should == "Rap like me"
|
97
|
+
group['bid_type'].should == 'CPC'
|
98
|
+
}
|
99
|
+
end
|
100
|
+
end
|
34
101
|
end
|
35
|
-
end
|
36
102
|
|
37
|
-
describe "talking to facebook" do
|
38
103
|
context "reading" do
|
39
104
|
|
40
105
|
it "a list of ad accounts" do
|
41
106
|
VCR.use_cassette('list_of_ad_accounts') do
|
42
|
-
Zuck::AdAccount.all.should
|
107
|
+
Zuck::AdAccount.all.should have_at_least(1).items
|
43
108
|
end
|
44
109
|
end
|
45
110
|
|
46
111
|
it "a list of ad campaigns" do
|
47
112
|
VCR.use_cassette('list_of_ad_campaigns') do
|
48
|
-
account.ad_campaigns.should
|
113
|
+
account.ad_campaigns.should have_at_least(2).items
|
49
114
|
end
|
50
115
|
end
|
51
116
|
|
52
117
|
it "a list of ad groups" do
|
53
118
|
VCR.use_cassette('list_of_ad_groups') do
|
54
|
-
campaign.ad_groups.should
|
119
|
+
campaign.ad_groups.should have_at_least(1).item
|
55
120
|
end
|
56
121
|
end
|
57
122
|
|
@@ -65,7 +130,7 @@ describe Zuck::FbObject do
|
|
65
130
|
g = graph
|
66
131
|
Zuck::AdAccount.should_receive(:all).and_return([account])
|
67
132
|
VCR.use_cassette('list_of_all_ad_creatives_of_account') do
|
68
|
-
Zuck::AdCreative.all(g).should
|
133
|
+
Zuck::AdCreative.all(g).should have_at_least(1).items
|
69
134
|
end
|
70
135
|
end
|
71
136
|
|
@@ -73,97 +138,71 @@ describe Zuck::FbObject do
|
|
73
138
|
|
74
139
|
it "campaign with the correct type" do
|
75
140
|
VCR.use_cassette('a_single_campaign') do
|
76
|
-
c = Zuck::AdCampaign.find(
|
141
|
+
c = Zuck::AdCampaign.find(campaign.id, graph)
|
142
|
+
c.buying_type.should == "AUCTION"
|
77
143
|
end
|
78
144
|
end
|
79
145
|
|
80
146
|
it "account with the correct type" do
|
81
147
|
VCR.use_cassette('a_single_account') do
|
82
|
-
c = Zuck::AdAccount.find(
|
148
|
+
c = Zuck::AdAccount.find(account_id, graph)
|
149
|
+
c.account_id.should == account_id[4..-1]
|
150
|
+
c.account_status.should == 1
|
83
151
|
end
|
84
152
|
end
|
85
153
|
|
86
154
|
it "when expecting an ad group but the id belongs to a campaign" do
|
87
155
|
VCR.use_cassette('a_single_group') do
|
88
156
|
expect{
|
89
|
-
|
157
|
+
Zuck::AdGroup.find(campaign.id, graph)
|
90
158
|
}.to raise_error(Koala::Facebook::ClientError)
|
91
159
|
end
|
92
160
|
end
|
93
161
|
|
94
162
|
it "and saving it" do
|
95
163
|
VCR.use_cassette('find_a_single_group_and_update_it') do
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
164
|
+
explain_error {
|
165
|
+
found_group = Zuck::AdGroup.find(group.id, graph)
|
166
|
+
found_group.name = "My old name"
|
167
|
+
found_group.save
|
168
|
+
found_group.name.should == "My old name"
|
169
|
+
found_group.name = "My new name"
|
170
|
+
found_group.save
|
171
|
+
found_group.name.should == "My new name"
|
172
|
+
found_group.reload
|
173
|
+
found_group.name.should == "My new name"
|
174
|
+
}
|
105
175
|
end
|
106
176
|
end
|
107
177
|
|
108
178
|
end
|
109
179
|
end
|
110
180
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
o = {
|
116
|
-
name: 'test ad set',
|
117
|
-
campaign_status: 'PAUSED',
|
118
|
-
daily_budget: 100,
|
119
|
-
targeting: "{'geo_locations':{'countries':['US','GB']}}",
|
120
|
-
campaign_group_id: campaign.id
|
121
|
-
}
|
122
|
-
ad_set = Zuck::AdSet.create(graph, o, account)
|
123
|
-
ad_set.name.should == 'test ad set'
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
it "an ad campaign" do
|
128
|
-
VCR.use_cassette('create_ad_campaign') do
|
129
|
-
o = {objective: 'NONE', name: "bloody", campaign_group_status: 'PAUSED' }
|
130
|
-
campaign = Zuck::AdCampaign.create(graph, o, account)
|
131
|
-
campaign.name.should == "bloody"
|
181
|
+
context "deleting" do
|
182
|
+
it "an ad group" do
|
183
|
+
VCR.use_cassette('delete_ad_group') do
|
184
|
+
group.destroy.should be_true
|
132
185
|
end
|
133
186
|
end
|
134
187
|
|
135
|
-
it "an ad
|
136
|
-
VCR.use_cassette('
|
137
|
-
|
138
|
-
campaign = account.create_ad_campaign(o)
|
139
|
-
campaign.name.should == "bloody"
|
188
|
+
it "an ad set" do
|
189
|
+
VCR.use_cassette('delete_ad_set') do
|
190
|
+
set.destroy.should be_true
|
140
191
|
end
|
141
192
|
end
|
142
193
|
|
143
|
-
it "
|
144
|
-
VCR.use_cassette('
|
145
|
-
|
146
|
-
bid_type: 'CPC',
|
147
|
-
bid_info: '{"CLICKS": 1}',
|
148
|
-
name: "Rap like me",
|
149
|
-
targeting: '{"geo_locations": {"countries":["US"]}}',
|
150
|
-
objective: 'WEBSITE_CLICKS',
|
151
|
-
creative: '{"creative_id": "6021396606151"}'
|
152
|
-
}
|
153
|
-
group = set.create_ad_group(o)
|
154
|
-
group.name.should == "Rap like me"
|
155
|
-
group.bid_type.should == 'CPC'
|
194
|
+
it "a creative" do
|
195
|
+
VCR.use_cassette('delete_creative') do
|
196
|
+
creative.destroy.should be_true
|
156
197
|
end
|
157
198
|
end
|
158
|
-
end
|
159
199
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
200
|
+
it "a campaign" do
|
201
|
+
VCR.use_cassette('delete_campaign') do
|
202
|
+
campaign.destroy.should be_true
|
203
|
+
act_campaign.destroy.should be_true
|
164
204
|
end
|
165
205
|
end
|
166
206
|
end
|
167
|
-
|
168
207
|
end
|
169
208
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -44,4 +44,18 @@ def test_access_token
|
|
44
44
|
@test_access_token ||= File.read("test_access_token")
|
45
45
|
end
|
46
46
|
|
47
|
+
def explain_error(&block)
|
48
|
+
raise "missing code block" unless block_given?
|
49
|
+
|
50
|
+
begin
|
51
|
+
block.call
|
52
|
+
rescue Koala::Facebook::APIError => e
|
53
|
+
puts "=== Facebook API Error ===================================="
|
54
|
+
body = JSON.parse e.response_body
|
55
|
+
body['error'].each { |k, v| printf("%-20s %s\n", k+":", v) }
|
56
|
+
puts "==========================================================="
|
57
|
+
raise e
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
47
61
|
require File.expand_path("../../lib/zuck", __FILE__)
|
data/test_access_token
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
FAKEACCESSTOKEN
|
data/zuck.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: zuck 2.
|
5
|
+
# stub: zuck 2.1.0 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "zuck"
|
9
|
-
s.version = "2.
|
9
|
+
s.version = "2.1.0"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Jannis Hermanns"]
|
14
|
-
s.date = "2015-
|
14
|
+
s.date = "2015-04-15"
|
15
15
|
s.description = "This gem allows to easily access facebook's ads api in ruby. See https://developers.facebook.com/docs/reference/ads-api/"
|
16
16
|
s.email = "jannis@gmail.com"
|
17
17
|
s.extra_rdoc_files = [
|
@@ -55,10 +55,14 @@ Gem::Specification.new do |s|
|
|
55
55
|
"spec/fixtures/ad_interest_search_disney.yml",
|
56
56
|
"spec/fixtures/ad_interest_search_moviepilot.yml",
|
57
57
|
"spec/fixtures/ad_interest_search_nonexistant.yml",
|
58
|
+
"spec/fixtures/create_a_creative.yml",
|
58
59
|
"spec/fixtures/create_ad_campaign.yml",
|
59
60
|
"spec/fixtures/create_ad_group.yml",
|
60
61
|
"spec/fixtures/create_ad_set.yml",
|
61
62
|
"spec/fixtures/delete_ad_group.yml",
|
63
|
+
"spec/fixtures/delete_ad_set.yml",
|
64
|
+
"spec/fixtures/delete_campaign.yml",
|
65
|
+
"spec/fixtures/delete_creative.yml",
|
62
66
|
"spec/fixtures/find_a_single_group_and_update_it.yml",
|
63
67
|
"spec/fixtures/list_of_ad_accounts.yml",
|
64
68
|
"spec/fixtures/list_of_ad_campaigns.yml",
|