zuck 0.2.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.travis.yml +0 -1
- data/CHANGELOG.markdown +12 -1
- data/Gemfile +4 -4
- data/Gemfile.lock +40 -11
- data/README.markdown +6 -6
- data/VERSION +1 -1
- data/lib/zuck/facebook/ad_interest.rb +44 -0
- data/lib/zuck/facebook/targeting_spec.rb +23 -22
- data/spec/fixtures/ad_interest_search_disney.yml +54 -0
- data/spec/fixtures/ad_interest_search_moviepilot.yml +138 -0
- data/spec/fixtures/{ad_keyword_search_nonexistant.yml → ad_interest_search_nonexistant.yml} +12 -12
- data/spec/fixtures/reach_for_invalid_interest.yml +186 -0
- data/spec/fixtures/reach_for_valid_keywords.yml +56 -11
- data/spec/fixtures/reach_for_valid_keywords_male_young.yml +65 -14
- data/spec/lib/zuck/facebook/ad_interest_spec.rb +23 -0
- data/spec/lib/zuck/facebook/targeting_spec_spec.rb +35 -34
- data/zuck.gemspec +24 -23
- metadata +61 -102
- data/lib/zuck/facebook/ad_keyword.rb +0 -45
- data/spec/fixtures/ad_keyword_search_disney.yml +0 -53
- data/spec/fixtures/ad_keyword_search_moviepilot.yml +0 -48
- data/spec/fixtures/reach_for_invalid_keyword.yml +0 -48
- data/spec/lib/zuck/facebook/ad_keyword_spec.rb +0 -23
@@ -1,45 +0,0 @@
|
|
1
|
-
module Zuck
|
2
|
-
module AdKeyword
|
3
|
-
extend Zuck::Helpers
|
4
|
-
extend self
|
5
|
-
|
6
|
-
# Given a keyword, make a guess on what the closest keyword
|
7
|
-
# on the facebook ads api is. It tends to use a # prefixed
|
8
|
-
# keyword if available, and also a more popular one over a less
|
9
|
-
# popular one
|
10
|
-
def best_guess(graph, keyword)
|
11
|
-
search(graph, keyword).sort do |a,b|
|
12
|
-
if a[:audience].to_i > 0 || b[:audience].to_i > 0
|
13
|
-
a[:audience].to_i <=> b[:audience].to_i
|
14
|
-
else
|
15
|
-
b[:keyword].length <=> a[:keyword].length
|
16
|
-
end
|
17
|
-
end.last
|
18
|
-
end
|
19
|
-
|
20
|
-
# Checks the ad api to see if the given keywords are valid
|
21
|
-
# @return [Hash] The keys are the (lowercased) keywords and the values their validity
|
22
|
-
def validate(graph, keywords)
|
23
|
-
keywords = normalize_array(keywords).map{|k| k.gsub(',', '%2C')}
|
24
|
-
search = graph.search(nil, type: 'adkeywordvalid', keyword_list: keywords.join(","))
|
25
|
-
results = {}
|
26
|
-
search.each do |r|
|
27
|
-
results[r['name']] = r['valid']
|
28
|
-
end
|
29
|
-
results
|
30
|
-
end
|
31
|
-
|
32
|
-
# Ad keyword search
|
33
|
-
def search(graph, keyword)
|
34
|
-
results = graph.search(keyword, type: :adkeyword).map do |r|
|
35
|
-
audience = r['description'].scan(/[0-9]+/).join('').to_i rescue nil
|
36
|
-
{
|
37
|
-
keyword: r['name'],
|
38
|
-
id: r['id'],
|
39
|
-
audience: audience
|
40
|
-
}
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
@@ -1,53 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: get
|
5
|
-
uri: https://graph.facebook.com/search?access_token=CAAEvJ5vzhl8BAH8aCPOx0Ft9uNB147TF8weJ8hK0g7YVDRWU4eEih7tEKdJgmfk0vABZClZACJbEzyhSMbiShL6RpsfkZASfX1C9nv1AlFvjJajflqkyYZAlpE2edT0FJHjdh4NFg0ZCt0sBgq0kZABtKsjuU18aMURLE7rjKHR4X8NkXBUafg1T4uZARRNqboZD&q=disney&type=adkeyword
|
6
|
-
body:
|
7
|
-
encoding: US-ASCII
|
8
|
-
string: ''
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.7
|
12
|
-
Accept-Encoding:
|
13
|
-
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
-
Accept:
|
15
|
-
- ! '*/*'
|
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
|
-
- application/json; charset=UTF-8
|
27
|
-
Etag:
|
28
|
-
- ! '"ddd1522d71e8cbd1a1e68ee5ff6cf1e5dbde04cb"'
|
29
|
-
Expires:
|
30
|
-
- Sat, 01 Jan 2000 00:00:00 GMT
|
31
|
-
Pragma:
|
32
|
-
- no-cache
|
33
|
-
X-Fb-Rev:
|
34
|
-
- '934677'
|
35
|
-
X-Fb-Debug:
|
36
|
-
- EMkma5AVfp17cYzoavOVQXmuVbL15If4/tXmFADlVHw=
|
37
|
-
Date:
|
38
|
-
- Thu, 12 Sep 2013 13:21:33 GMT
|
39
|
-
Connection:
|
40
|
-
- keep-alive
|
41
|
-
Content-Length:
|
42
|
-
- '587'
|
43
|
-
body:
|
44
|
-
encoding: US-ASCII
|
45
|
-
string: ! '{"data":[{"name":"Disney Channel","id":6003711659516},{"name":"Disneyland","id":6003361056187},{"name":"Disney","id":6003663755307},{"name":"#The
|
46
|
-
Walt Disney Company","description":"Audience: 78,100,000","id":6003270522085},{"name":"#Disneyland","description":"Audience:
|
47
|
-
26,200,000","id":6003274193708},{"name":"#Disney Channel","description":"Audience:
|
48
|
-
22,600,000","id":6003327130854},{"name":"#The Walt Disney Company#Walt Disney
|
49
|
-
Pictures","description":"Audience: 9,200,000","id":6004710425192},{"name":"#Walt
|
50
|
-
Disney Pictures","description":"Audience: 9,200,000","id":6003050377616}]}'
|
51
|
-
http_version:
|
52
|
-
recorded_at: Thu, 12 Sep 2013 13:21:33 GMT
|
53
|
-
recorded_with: VCR 2.3.0
|
@@ -1,48 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: get
|
5
|
-
uri: https://graph.facebook.com/search?access_token=CAAEvJ5vzhl8BAH8aCPOx0Ft9uNB147TF8weJ8hK0g7YVDRWU4eEih7tEKdJgmfk0vABZClZACJbEzyhSMbiShL6RpsfkZASfX1C9nv1AlFvjJajflqkyYZAlpE2edT0FJHjdh4NFg0ZCt0sBgq0kZABtKsjuU18aMURLE7rjKHR4X8NkXBUafg1T4uZARRNqboZD&q=moviepilot&type=adkeyword
|
6
|
-
body:
|
7
|
-
encoding: US-ASCII
|
8
|
-
string: ''
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.7
|
12
|
-
Accept-Encoding:
|
13
|
-
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
-
Accept:
|
15
|
-
- ! '*/*'
|
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
|
-
- application/json; charset=UTF-8
|
27
|
-
Etag:
|
28
|
-
- ! '"5af1c2df3403480db8f57d9e9bfd2ed4a6f925ef"'
|
29
|
-
Expires:
|
30
|
-
- Sat, 01 Jan 2000 00:00:00 GMT
|
31
|
-
Pragma:
|
32
|
-
- no-cache
|
33
|
-
X-Fb-Rev:
|
34
|
-
- '934677'
|
35
|
-
X-Fb-Debug:
|
36
|
-
- 1gdeJKsX7G0woVPQzROCOkunT0R3FhMp/a/w9gdoUpE=
|
37
|
-
Date:
|
38
|
-
- Thu, 12 Sep 2013 13:21:33 GMT
|
39
|
-
Connection:
|
40
|
-
- keep-alive
|
41
|
-
Content-Length:
|
42
|
-
- '95'
|
43
|
-
body:
|
44
|
-
encoding: US-ASCII
|
45
|
-
string: ! '{"data":[{"name":"Moviepilot","id":6003327847780},{"name":"Moviepilotcom","id":6003495809986}]}'
|
46
|
-
http_version:
|
47
|
-
recorded_at: Thu, 12 Sep 2013 13:21:33 GMT
|
48
|
-
recorded_with: VCR 2.3.0
|
@@ -1,48 +0,0 @@
|
|
1
|
-
---
|
2
|
-
http_interactions:
|
3
|
-
- request:
|
4
|
-
method: get
|
5
|
-
uri: https://graph.facebook.com/search?access_token=CAAEvJ5vzhl8BAH8aCPOx0Ft9uNB147TF8weJ8hK0g7YVDRWU4eEih7tEKdJgmfk0vABZClZACJbEzyhSMbiShL6RpsfkZASfX1C9nv1AlFvjJajflqkyYZAlpE2edT0FJHjdh4NFg0ZCt0sBgq0kZABtKsjuU18aMURLE7rjKHR4X8NkXBUafg1T4uZARRNqboZD&keyword_list=Eminem,invalidsssssssssssssss&type=adkeywordvalid
|
6
|
-
body:
|
7
|
-
encoding: US-ASCII
|
8
|
-
string: ''
|
9
|
-
headers:
|
10
|
-
User-Agent:
|
11
|
-
- Faraday v0.8.7
|
12
|
-
Accept-Encoding:
|
13
|
-
- gzip;q=1.0,deflate;q=0.6,identity;q=0.3
|
14
|
-
Accept:
|
15
|
-
- ! '*/*'
|
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
|
-
- application/json; 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
|
-
- '934677'
|
35
|
-
X-Fb-Debug:
|
36
|
-
- J8DeY1E4Yqw7bJX0tlNMHLA1W2i+1busrhuPm8oG1vg=
|
37
|
-
Date:
|
38
|
-
- Thu, 12 Sep 2013 13:21:34 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: Thu, 12 Sep 2013 13:21:34 GMT
|
48
|
-
recorded_with: VCR 2.3.0
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Zuck::AdKeyword do
|
4
|
-
let(:graph){ Koala::Facebook::API.new(test_access_token)}
|
5
|
-
|
6
|
-
it "finds the best keyword with a #" do
|
7
|
-
VCR.use_cassette('ad_keyword_search_disney') do
|
8
|
-
Zuck::AdKeyword.best_guess(graph, 'disney')[:keyword].should == '#The Walt Disney Company'
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
it "finds the best keyword when no keyword with # is available" do
|
13
|
-
VCR.use_cassette('ad_keyword_search_moviepilot') do
|
14
|
-
Zuck::AdKeyword.best_guess(graph, 'moviepilot')[:keyword].should == 'Moviepilot'
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
it "returns nil when nothing could be found" do
|
19
|
-
VCR.use_cassette('ad_keyword_search_nonexistant') do
|
20
|
-
Zuck::AdKeyword.best_guess(graph, 'ick spickeby').should be_nil
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|