zuck 0.0.4
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.
- data/.rvmrc +1 -0
- data/.travis.yml +7 -0
- data/.yardopts +4 -0
- data/CHANGELOG.markdown +4 -0
- data/Gemfile +35 -0
- data/Gemfile.lock +110 -0
- data/Guardfile.dist +45 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +138 -0
- data/Rakefile +39 -0
- data/VERSION +1 -0
- data/console +26 -0
- data/lib/zuck/facebook/ad_account.rb +40 -0
- data/lib/zuck/facebook/ad_campaign.rb +24 -0
- data/lib/zuck/facebook/ad_creative.rb +30 -0
- data/lib/zuck/facebook/ad_group.rb +39 -0
- data/lib/zuck/facebook/targeting_spec.rb +200 -0
- data/lib/zuck/fb_object/dsl.rb +110 -0
- data/lib/zuck/fb_object/error.rb +8 -0
- data/lib/zuck/fb_object/hash_delegator.rb +111 -0
- data/lib/zuck/fb_object/helpers.rb +57 -0
- data/lib/zuck/fb_object/read.rb +147 -0
- data/lib/zuck/fb_object/read_only.rb +0 -0
- data/lib/zuck/fb_object/write.rb +75 -0
- data/lib/zuck/fb_object.rb +53 -0
- data/lib/zuck/koala/koala_methods.rb +27 -0
- data/lib/zuck.rb +9 -0
- data/spec/fixtures/a_single_account.yml +75 -0
- data/spec/fixtures/a_single_campaign.yml +48 -0
- data/spec/fixtures/create_ad_campaign.yml +49 -0
- data/spec/fixtures/create_ad_group.yml +47 -0
- data/spec/fixtures/delete_ad_group.yml +50 -0
- data/spec/fixtures/find_a_single_campaign_and_update_it.yml +247 -0
- data/spec/fixtures/list_of_ad_accounts.yml +75 -0
- data/spec/fixtures/list_of_ad_campaigns.yml +76 -0
- data/spec/fixtures/list_of_ad_creatives.yml +51 -0
- data/spec/fixtures/list_of_ad_groups.yml +49 -0
- data/spec/fixtures/list_of_all_ad_creatives_of_account.yml +86 -0
- data/spec/fixtures/reach_for_invalid_keyword.yml +95 -0
- data/spec/fixtures/reach_for_valid_keywords.yml +93 -0
- data/spec/fixtures/reach_for_valid_keywords_male_young.yml +93 -0
- data/spec/lib/zuck/facebook/ad_account_spec.rb +26 -0
- data/spec/lib/zuck/facebook/ad_campaign_spec.rb +4 -0
- data/spec/lib/zuck/facebook/targeting_spec_spec.rb +174 -0
- data/spec/lib/zuck/fb_object/helpers_spec.rb +67 -0
- data/spec/lib/zuck/koala/koala_methods_spec.rb +30 -0
- data/spec/lib/zuck/util/hash_delegator_spec.rb +54 -0
- data/spec/lib/zuck_spec.rb +165 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/vcr_setup.rb +15 -0
- data/zuck.gemspec +141 -0
- metadata +389 -0
@@ -0,0 +1,95 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://graph.facebook.com/search?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&keyword_list=eminem,invalidsssssssssssssss&type=adkeywordvalid
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- ! '*/*'
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Access-Control-Allow-Origin:
|
22
|
+
- ! '*'
|
23
|
+
Cache-Control:
|
24
|
+
- private, no-cache, no-store, must-revalidate
|
25
|
+
Content-Type:
|
26
|
+
- text/javascript; charset=UTF-8
|
27
|
+
Etag:
|
28
|
+
- ! '"1b6af91a08d48aeee5ffa0cf3437f38b61281b68"'
|
29
|
+
Expires:
|
30
|
+
- Sat, 01 Jan 2000 00:00:00 GMT
|
31
|
+
Pragma:
|
32
|
+
- no-cache
|
33
|
+
X-Fb-Rev:
|
34
|
+
- '698469'
|
35
|
+
X-Fb-Debug:
|
36
|
+
- 7so4yUGhkG2hb0KiZDAFNlrgtEmcB0xQ9Xilxl/LfRw=
|
37
|
+
Date:
|
38
|
+
- Wed, 19 Dec 2012 14:36:48 GMT
|
39
|
+
Connection:
|
40
|
+
- keep-alive
|
41
|
+
Content-Length:
|
42
|
+
- '108'
|
43
|
+
body:
|
44
|
+
encoding: US-ASCII
|
45
|
+
string: ! '{"data":[{"name":"Eminem","valid":true,"id":6003170652434},{"name":"invalidsssssssssssssss","valid":false}]}'
|
46
|
+
http_version:
|
47
|
+
recorded_at: Wed, 19 Dec 2012 14:36:48 GMT
|
48
|
+
- request:
|
49
|
+
method: get
|
50
|
+
uri: https://graph.facebook.com/act_10150585630710217/reachestimate?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&targeting_spec=%7B%22countries%22:%5B%22US%22%5D,%22keywords%22:%5B%22eminem%22,%22invalidsssssssssssssss%22%5D,%22age_min%22:13,%22connections%22:%5B%5D%7D
|
51
|
+
body:
|
52
|
+
encoding: US-ASCII
|
53
|
+
string: ''
|
54
|
+
headers:
|
55
|
+
Accept-Encoding:
|
56
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
57
|
+
Accept:
|
58
|
+
- ! '*/*'
|
59
|
+
User-Agent:
|
60
|
+
- Ruby
|
61
|
+
response:
|
62
|
+
status:
|
63
|
+
code: 400
|
64
|
+
message: Bad Request
|
65
|
+
headers:
|
66
|
+
Access-Control-Allow-Origin:
|
67
|
+
- ! '*'
|
68
|
+
Cache-Control:
|
69
|
+
- no-store
|
70
|
+
Content-Type:
|
71
|
+
- text/javascript; charset=UTF-8
|
72
|
+
Expires:
|
73
|
+
- Sat, 01 Jan 2000 00:00:00 GMT
|
74
|
+
Pragma:
|
75
|
+
- no-cache
|
76
|
+
Www-Authenticate:
|
77
|
+
- ! 'OAuth "Facebook Platform" "invalid_token" "Error validating access token:
|
78
|
+
Session has expired at unix time 1355932800. The current unix time is 1355934833."'
|
79
|
+
X-Fb-Rev:
|
80
|
+
- '698469'
|
81
|
+
X-Fb-Debug:
|
82
|
+
- Kkjlojh5eu19FxaW5yu6N5A+5xmmbKyfKsCpa+y2eOc=
|
83
|
+
Date:
|
84
|
+
- Wed, 19 Dec 2012 16:33:53 GMT
|
85
|
+
Connection:
|
86
|
+
- keep-alive
|
87
|
+
Content-Length:
|
88
|
+
- '191'
|
89
|
+
body:
|
90
|
+
encoding: US-ASCII
|
91
|
+
string: ! '{"error":{"message":"Error validating access token: Session has expired
|
92
|
+
at unix time 1355932800. The current unix time is 1355934833.","type":"OAuthException","code":190,"error_subcode":463}}'
|
93
|
+
http_version:
|
94
|
+
recorded_at: Wed, 19 Dec 2012 16:33:53 GMT
|
95
|
+
recorded_with: VCR 2.2.4
|
@@ -0,0 +1,93 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://graph.facebook.com/search?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&keyword_list=eminem,sting&type=adkeywordvalid
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- ! '*/*'
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Access-Control-Allow-Origin:
|
22
|
+
- ! '*'
|
23
|
+
Cache-Control:
|
24
|
+
- private, no-cache, no-store, must-revalidate
|
25
|
+
Content-Type:
|
26
|
+
- text/javascript; charset=UTF-8
|
27
|
+
Etag:
|
28
|
+
- ! '"a684dbf074d5467a7775189984027b177954edef"'
|
29
|
+
Expires:
|
30
|
+
- Sat, 01 Jan 2000 00:00:00 GMT
|
31
|
+
Pragma:
|
32
|
+
- no-cache
|
33
|
+
X-Fb-Rev:
|
34
|
+
- '698469'
|
35
|
+
X-Fb-Debug:
|
36
|
+
- vtS1+m1EAAr/YCY4TKxUueU+DfmYhcASPsoK5LMzkW8=
|
37
|
+
Date:
|
38
|
+
- Wed, 19 Dec 2012 15:13:41 GMT
|
39
|
+
Connection:
|
40
|
+
- keep-alive
|
41
|
+
Content-Length:
|
42
|
+
- '109'
|
43
|
+
body:
|
44
|
+
encoding: US-ASCII
|
45
|
+
string: ! '{"data":[{"name":"Eminem","valid":true,"id":6003170652434},{"name":"Sting","valid":true,"id":6003164299249}]}'
|
46
|
+
http_version:
|
47
|
+
recorded_at: Wed, 19 Dec 2012 15:13:42 GMT
|
48
|
+
- request:
|
49
|
+
method: get
|
50
|
+
uri: https://graph.facebook.com/act_10150585630710217/reachestimate?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&targeting_spec=%7B%22countries%22:%5B%22US%22%5D,%22keywords%22:%5B%22eminem%22,%22sting%22%5D,%22age_min%22:13,%22connections%22:%5B%5D,%22broad_age%22:false%7D
|
51
|
+
body:
|
52
|
+
encoding: US-ASCII
|
53
|
+
string: ''
|
54
|
+
headers:
|
55
|
+
Accept-Encoding:
|
56
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
57
|
+
Accept:
|
58
|
+
- ! '*/*'
|
59
|
+
User-Agent:
|
60
|
+
- Ruby
|
61
|
+
response:
|
62
|
+
status:
|
63
|
+
code: 200
|
64
|
+
message: OK
|
65
|
+
headers:
|
66
|
+
Access-Control-Allow-Origin:
|
67
|
+
- ! '*'
|
68
|
+
Cache-Control:
|
69
|
+
- private, no-cache, no-store, must-revalidate
|
70
|
+
Content-Type:
|
71
|
+
- text/javascript; charset=UTF-8
|
72
|
+
Etag:
|
73
|
+
- ! '"486581ad6483292ae854bf5e25d36d1b564b1865"'
|
74
|
+
Expires:
|
75
|
+
- Sat, 01 Jan 2000 00:00:00 GMT
|
76
|
+
Pragma:
|
77
|
+
- no-cache
|
78
|
+
X-Fb-Rev:
|
79
|
+
- '698469'
|
80
|
+
X-Fb-Debug:
|
81
|
+
- m+Eupy9dFg5wCI+Ej1LdCnZ73lJ1YHyikHIHA1+ET5Y=
|
82
|
+
Date:
|
83
|
+
- Wed, 19 Dec 2012 15:13:43 GMT
|
84
|
+
Connection:
|
85
|
+
- keep-alive
|
86
|
+
Content-Length:
|
87
|
+
- '322'
|
88
|
+
body:
|
89
|
+
encoding: US-ASCII
|
90
|
+
string: ! '{"users":16830580,"bid_estimations":[{"location":3,"cpc_min":43,"cpc_median":71,"cpc_max":145,"cpm_min":2,"cpm_median":15,"cpm_max":502}],"imp_estimates":[],"data":{"users":16830580,"bid_estimations":[{"location":3,"cpc_min":43,"cpc_median":71,"cpc_max":145,"cpm_min":2,"cpm_median":15,"cpm_max":502}],"imp_estimates":[]}}'
|
91
|
+
http_version:
|
92
|
+
recorded_at: Wed, 19 Dec 2012 15:13:43 GMT
|
93
|
+
recorded_with: VCR 2.2.4
|
@@ -0,0 +1,93 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://graph.facebook.com/search?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&keyword_list=sting&type=adkeywordvalid
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
Accept-Encoding:
|
11
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
12
|
+
Accept:
|
13
|
+
- ! '*/*'
|
14
|
+
User-Agent:
|
15
|
+
- Ruby
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Access-Control-Allow-Origin:
|
22
|
+
- ! '*'
|
23
|
+
Cache-Control:
|
24
|
+
- private, no-cache, no-store, must-revalidate
|
25
|
+
Content-Type:
|
26
|
+
- text/javascript; charset=UTF-8
|
27
|
+
Etag:
|
28
|
+
- ! '"66bd8a85c55324c07c1c2afcb1eac4e2fd358bf5"'
|
29
|
+
Expires:
|
30
|
+
- Sat, 01 Jan 2000 00:00:00 GMT
|
31
|
+
Pragma:
|
32
|
+
- no-cache
|
33
|
+
X-Fb-Rev:
|
34
|
+
- '698469'
|
35
|
+
X-Fb-Debug:
|
36
|
+
- XuqZnN5WjRA/b3sTn4Nz0jyvTkw2S0OCP5x8OKrUO54=
|
37
|
+
Date:
|
38
|
+
- Wed, 19 Dec 2012 15:20:53 GMT
|
39
|
+
Connection:
|
40
|
+
- keep-alive
|
41
|
+
Content-Length:
|
42
|
+
- '59'
|
43
|
+
body:
|
44
|
+
encoding: US-ASCII
|
45
|
+
string: ! '{"data":[{"name":"Sting","valid":true,"id":6003164299249}]}'
|
46
|
+
http_version:
|
47
|
+
recorded_at: Wed, 19 Dec 2012 15:20:53 GMT
|
48
|
+
- request:
|
49
|
+
method: get
|
50
|
+
uri: https://graph.facebook.com/act_10150585630710217/reachestimate?access_token=AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD&targeting_spec=%7B%22countries%22:%5B%22US%22%5D,%22keywords%22:%5B%22sting%22%5D,%22age_min%22:13,%22age_max%22:24,%22genders%22:%5B2%5D,%22connections%22:%5B%5D,%22broad_age%22:false%7D
|
51
|
+
body:
|
52
|
+
encoding: US-ASCII
|
53
|
+
string: ''
|
54
|
+
headers:
|
55
|
+
Accept-Encoding:
|
56
|
+
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
57
|
+
Accept:
|
58
|
+
- ! '*/*'
|
59
|
+
User-Agent:
|
60
|
+
- Ruby
|
61
|
+
response:
|
62
|
+
status:
|
63
|
+
code: 200
|
64
|
+
message: OK
|
65
|
+
headers:
|
66
|
+
Access-Control-Allow-Origin:
|
67
|
+
- ! '*'
|
68
|
+
Cache-Control:
|
69
|
+
- private, no-cache, no-store, must-revalidate
|
70
|
+
Content-Type:
|
71
|
+
- text/javascript; charset=UTF-8
|
72
|
+
Etag:
|
73
|
+
- ! '"430ebe9f4489fdfc008a2c301d51e68d633c8978"'
|
74
|
+
Expires:
|
75
|
+
- Sat, 01 Jan 2000 00:00:00 GMT
|
76
|
+
Pragma:
|
77
|
+
- no-cache
|
78
|
+
X-Fb-Rev:
|
79
|
+
- '698469'
|
80
|
+
X-Fb-Debug:
|
81
|
+
- H+RabGZXmTXmsUVynJuDJRCthPTjpJLfPD7iwdJA3WA=
|
82
|
+
Date:
|
83
|
+
- Wed, 19 Dec 2012 15:20:55 GMT
|
84
|
+
Connection:
|
85
|
+
- keep-alive
|
86
|
+
Content-Length:
|
87
|
+
- '314'
|
88
|
+
body:
|
89
|
+
encoding: US-ASCII
|
90
|
+
string: ! '{"users":39400,"bid_estimations":[{"location":3,"cpc_min":38,"cpc_median":58,"cpc_max":115,"cpm_min":1,"cpm_median":6,"cpm_max":383}],"imp_estimates":[],"data":{"users":39400,"bid_estimations":[{"location":3,"cpc_min":38,"cpc_median":58,"cpc_max":115,"cpm_min":1,"cpm_median":6,"cpm_max":383}],"imp_estimates":[]}}'
|
91
|
+
http_version:
|
92
|
+
recorded_at: Wed, 19 Dec 2012 15:20:55 GMT
|
93
|
+
recorded_with: VCR 2.2.4
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Zuck::AdAccount do
|
4
|
+
|
5
|
+
let(:graph){ Koala::Facebook::API.new(:token) }
|
6
|
+
let(:acc){ Zuck::AdAccount.new(graph, name: :dance_in_style) }
|
7
|
+
|
8
|
+
it "initializes graph correctly" do
|
9
|
+
acc.graph.should == graph
|
10
|
+
end
|
11
|
+
|
12
|
+
it "initializes data correctly" do
|
13
|
+
acc[:name].should == :dance_in_style
|
14
|
+
end
|
15
|
+
|
16
|
+
it "defines getters" do
|
17
|
+
acc.name.should == :dance_in_style
|
18
|
+
end
|
19
|
+
|
20
|
+
it "defines setters" do
|
21
|
+
acc.name = :bazinga
|
22
|
+
acc.name.should == :bazinga
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,174 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Zuck::TargetingSpec do
|
4
|
+
let(:ad_account){ "2ijdsfoij" }
|
5
|
+
let(:graph){ mock('koala') }
|
6
|
+
let(:reach_response){
|
7
|
+
{ # These can probably go since we have
|
8
|
+
"users" => 23688420, # vcr cassetes with http requests and
|
9
|
+
"bid_estimations" => [ # responses in place
|
10
|
+
{
|
11
|
+
"location" => 3,
|
12
|
+
"cpc_min" => 37,
|
13
|
+
"cpc_median" => 44,
|
14
|
+
"cpc_max" => 57,
|
15
|
+
"cpm_min" => 6,
|
16
|
+
"cpm_median" => 12,
|
17
|
+
"cpm_max" => 33
|
18
|
+
}
|
19
|
+
],
|
20
|
+
"imp_estimates" => [
|
21
|
+
],
|
22
|
+
"data" => {
|
23
|
+
"users" => 23688420,
|
24
|
+
"bid_estimations" => [
|
25
|
+
{
|
26
|
+
"location" => 3,
|
27
|
+
"cpc_min" => 37,
|
28
|
+
"cpc_median" => 44,
|
29
|
+
"cpc_max" => 57,
|
30
|
+
"cpm_min" => 6,
|
31
|
+
"cpm_median" => 12,
|
32
|
+
"cpm_max" => 33
|
33
|
+
}
|
34
|
+
],
|
35
|
+
"imp_estimates" => [
|
36
|
+
]
|
37
|
+
}
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
|
42
|
+
describe "validating keywords" do
|
43
|
+
|
44
|
+
let(:valid_keyword_result){ [{"name" => "foo", "valid" => true }] }
|
45
|
+
let(:invalid_keyword_result){ [{"name" => "sdjf", "valid" => false }] }
|
46
|
+
|
47
|
+
it "escapes commas" do
|
48
|
+
o = {type: 'adkeywordvalid', keyword_list: 'foo%2Cbar' }
|
49
|
+
graph.should_receive(:search).with(nil, o).and_return []
|
50
|
+
fts = Zuck::TargetingSpec.new(graph, ad_account, keywords: 'foo,bar')
|
51
|
+
fts.validate_keyword('foo,bar').should == false
|
52
|
+
end
|
53
|
+
|
54
|
+
it "acknowledges valid keywords" do
|
55
|
+
o = {type: 'adkeywordvalid', keyword_list: 'foo' }
|
56
|
+
graph.should_receive(:search).with(nil, o).and_return valid_keyword_result
|
57
|
+
fts = Zuck::TargetingSpec.new(graph, ad_account)
|
58
|
+
|
59
|
+
fts.validate_keyword('foo').should == true
|
60
|
+
end
|
61
|
+
|
62
|
+
it "refuses invalid keywords" do
|
63
|
+
o = {type: 'adkeywordvalid', keyword_list: 'sdjf' }
|
64
|
+
graph.should_receive(:search).with(nil, o).and_return invalid_keyword_result
|
65
|
+
fts = Zuck::TargetingSpec.new(graph, ad_account)
|
66
|
+
|
67
|
+
fts.validate_keyword('sdjf').should == false
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe "options given in spec" do
|
72
|
+
it "accepts male as gender" do
|
73
|
+
expect{
|
74
|
+
Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'], gender: 'male')
|
75
|
+
}.to_not raise_error
|
76
|
+
end
|
77
|
+
|
78
|
+
it "accepts male as gender for young people" do
|
79
|
+
expect{
|
80
|
+
Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'], gender: 'male', age_class: 'young')
|
81
|
+
}.to_not raise_error
|
82
|
+
end
|
83
|
+
|
84
|
+
it "accepts male as gender for old people" do
|
85
|
+
expect{
|
86
|
+
Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'], gender: 'male', age_class: 'old')
|
87
|
+
}.to_not raise_error
|
88
|
+
end
|
89
|
+
|
90
|
+
it "accepts without gender" do
|
91
|
+
expect{
|
92
|
+
Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'])
|
93
|
+
}.to_not raise_error
|
94
|
+
end
|
95
|
+
|
96
|
+
it "accepts single keywrod" do
|
97
|
+
expect{
|
98
|
+
Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keyword: 'foo')
|
99
|
+
}.to_not raise_error
|
100
|
+
end
|
101
|
+
|
102
|
+
it "does not accept invalid genders" do
|
103
|
+
expect{
|
104
|
+
Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], keywords: ['foo'], gender: 'gemale')
|
105
|
+
}.to raise_error("Gender can only be male or female")
|
106
|
+
end
|
107
|
+
|
108
|
+
it "does not accept targetings with neither :keywords nor :connections" do
|
109
|
+
expect{
|
110
|
+
ts = Zuck::TargetingSpec.new(graph, ad_account, countries: ['US'], gender: 'female')
|
111
|
+
ts.fetch_reach
|
112
|
+
}.to raise_error("Need to set :keywords or :connections")
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
describe "fetching reach" do
|
117
|
+
let(:graph){ Koala::Facebook::API.new('AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD') }
|
118
|
+
let(:ad_account){ 'act_10150585630710217' }
|
119
|
+
|
120
|
+
it "bugs out when trying to use an invalid keyword" do
|
121
|
+
VCR.use_cassette('reach_for_invalid_keyword') do
|
122
|
+
spec = {countries: ['us'], keywords: ['eminem', 'invalidsssssssssssssss'] }
|
123
|
+
ts = Zuck::TargetingSpec.new(graph, ad_account, spec)
|
124
|
+
expect{
|
125
|
+
ts.validate_keywords
|
126
|
+
}.to raise_error(Zuck::InvalidKeywordError, 'invalidsssssssssssssss')
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it "works without gender or age" do
|
131
|
+
VCR.use_cassette('reach_for_valid_keywords') do
|
132
|
+
spec = {countries: ['us'], keywords: ['eminem', 'sting'] }
|
133
|
+
ts = Zuck::TargetingSpec.new(graph, ad_account, spec)
|
134
|
+
reach = ts.fetch_reach
|
135
|
+
reach[:users].should == 16830580
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
it "works with gender and age" do
|
140
|
+
VCR.use_cassette('reach_for_valid_keywords_male_young') do
|
141
|
+
spec = {countries: ['us'], keywords: ['sting'], gender: :female, age_class: :young }
|
142
|
+
ts = Zuck::TargetingSpec.new(graph, ad_account, spec)
|
143
|
+
reach = ts.fetch_reach
|
144
|
+
reach[:users].should == 39400
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
it "without instanciating manually" do
|
149
|
+
x = stub()
|
150
|
+
x.should_receive(:fetch_reach).and_return 9
|
151
|
+
Zuck::TargetingSpec.should_receive(:new).with(:graph, :ad_account, :options).and_return x
|
152
|
+
|
153
|
+
Zuck::TargetingSpec.fetch_reach(:graph, :ad_account, :options)
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
describe "Batch processing" do
|
159
|
+
let(:graph){ Koala::Facebook::API.new('AAAEvJ5vzhl8BAPLr6fQgNy2wdUHDJ7ZAoX9PTZCFnebwuTBZBEqO7lNTVZA3XNsTHPTATpTmVFs6o6Jp1pZAL8ZA54BRBXWYtztVug8bm2BAZDZD') }
|
160
|
+
let(:ad_account){ 'act_10150585630710217' }
|
161
|
+
|
162
|
+
it "doesn't split up small bunches" do
|
163
|
+
requests = [{some: :thing}] * 50
|
164
|
+
graph.should_receive(:batch).once.and_return([])
|
165
|
+
Zuck::TargetingSpec.batch_reaches(graph, ad_account, requests)
|
166
|
+
end
|
167
|
+
|
168
|
+
it "splits up into 50 request bunches" do
|
169
|
+
requests = [{some: :thing}] * 51
|
170
|
+
graph.should_receive(:batch).twice.and_return([])
|
171
|
+
Zuck::TargetingSpec.batch_reaches(graph, ad_account, requests)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class HTest
|
4
|
+
extend Zuck::FbObject::Helpers
|
5
|
+
include Zuck::FbObject::Helpers
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Zuck::FbObject::Helpers do
|
9
|
+
|
10
|
+
let(:graph_mock){ mock('graph') }
|
11
|
+
|
12
|
+
context "get" do
|
13
|
+
it "forwards to koala" do
|
14
|
+
graph_mock.should_receive(:get_object).with('/foo').and_return(true)
|
15
|
+
HTest.send(:get, graph_mock, "/foo")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "does not swallow exceptions" do
|
19
|
+
graph_mock.should_receive(:get_object).with('/foo').and_raise("broken")
|
20
|
+
expect{
|
21
|
+
HTest.send(:get, graph_mock, "/foo")
|
22
|
+
}.to raise_error("broken")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context "create_connection" do
|
27
|
+
it "forwards to koala" do
|
28
|
+
graph_mock.should_receive(:put_connections).with(:parent, :connection, :args, :opts).and_return(true)
|
29
|
+
HTest.send(:create_connection, graph_mock, :parent, :connection, :args, :opts)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "does not swallow exceptions" do
|
33
|
+
graph_mock.should_receive(:put_connections).with(:parent, :connection, :args, :opts).and_raise("broken")
|
34
|
+
expect{
|
35
|
+
HTest.send(:create_connection, graph_mock, :parent, :connection, :args, :opts)
|
36
|
+
}.to raise_error("broken")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
context "post" do
|
41
|
+
it "forwards to koala" do
|
42
|
+
graph_mock.should_receive(:graph_call).with("path", :data, "post", :opts).and_return(true)
|
43
|
+
HTest.send(:post, graph_mock, :path, :data, :opts)
|
44
|
+
end
|
45
|
+
|
46
|
+
it "does not swallow exceptions" do
|
47
|
+
graph_mock.should_receive(:graph_call).with("path", :data, "post", :opts).and_raise("broken")
|
48
|
+
expect{
|
49
|
+
HTest.send(:post, graph_mock, :path, :data, :opts)
|
50
|
+
}.to raise_error("broken")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context "delete" do
|
55
|
+
it "forwards to koala" do
|
56
|
+
graph_mock.should_receive(:delete_object).with(:id).and_return(true)
|
57
|
+
HTest.send(:delete, graph_mock, :id)
|
58
|
+
end
|
59
|
+
|
60
|
+
it "does not swallow exceptions" do
|
61
|
+
graph_mock.should_receive(:delete_object).with(:id).and_raise("broken")
|
62
|
+
expect{
|
63
|
+
HTest.send(:delete, graph_mock, :id)
|
64
|
+
}.to raise_error("broken")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class KMTest
|
4
|
+
extend Zuck::KoalaMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Zuck::KoalaMethods do
|
8
|
+
describe "assigning a graph instance" do
|
9
|
+
|
10
|
+
it "raises when not a Koala instance" do
|
11
|
+
expect{
|
12
|
+
KMTest.graph = :something_else
|
13
|
+
}.to raise_error "Symbol is not a Koala::Facebook::API"
|
14
|
+
KMTest.graph.should be_nil
|
15
|
+
end
|
16
|
+
|
17
|
+
it "raises when not a Koala instance" do
|
18
|
+
expect{
|
19
|
+
KMTest.graph = Koala::Facebook::API.new()
|
20
|
+
}.to raise_error
|
21
|
+
KMTest.graph.should be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "that's valid" do
|
25
|
+
KMTest.graph.should be_nil
|
26
|
+
KMTest.graph = Koala::Facebook::API.new(:some_token)
|
27
|
+
KMTest.graph.should_not be_nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class HDTest
|
4
|
+
include Zuck::HashDelegator
|
5
|
+
known_keys :bar
|
6
|
+
end
|
7
|
+
|
8
|
+
describe Zuck::HashDelegator do
|
9
|
+
|
10
|
+
let(:del){ HDTest.new }
|
11
|
+
|
12
|
+
it "assigns a value" do
|
13
|
+
del[:foo] = :bar
|
14
|
+
del[:foo].should == :bar
|
15
|
+
end
|
16
|
+
|
17
|
+
it "has a shortcut getter" do
|
18
|
+
del[:foo] = :bar
|
19
|
+
del.data.should == {foo: :bar}
|
20
|
+
end
|
21
|
+
|
22
|
+
it "transforms keys to symbols" do
|
23
|
+
del['bar'] = :foo
|
24
|
+
del['bar'].should == :foo
|
25
|
+
del[:bar].should == :foo
|
26
|
+
end
|
27
|
+
|
28
|
+
it "becomes a pretty string" do
|
29
|
+
x = HDTest.new
|
30
|
+
x[:some] = "thing"
|
31
|
+
x[:bar] = 1
|
32
|
+
x.to_s.should == '#<HDTest some: "thing", bar: 1>'
|
33
|
+
end
|
34
|
+
|
35
|
+
it "allows to assign a hash" do
|
36
|
+
x = HDTest.new
|
37
|
+
x.set_data('some' => "thing", bar: 1)
|
38
|
+
x.to_s.should == '#<HDTest some: "thing", bar: 1>'
|
39
|
+
x[:some].should == "thing"
|
40
|
+
end
|
41
|
+
|
42
|
+
it "allows to assign a hash using a shortcut" do
|
43
|
+
x = HDTest.new
|
44
|
+
x.data = {'some' => "thing", bar: 1}
|
45
|
+
x.to_s.should == '#<HDTest some: "thing", bar: 1>'
|
46
|
+
x[:some].should == "thing"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "has methods defined for the known keys" do
|
50
|
+
del[:bar] = :foo
|
51
|
+
del.bar.should == :foo
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|