zuck 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- 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,165 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Zuck::FbObject do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
Zuck.graph = Koala::Facebook::API.new('AAAEvJ5vzhl8BABhTSazJZB2D0B4N0l242VX22Hg9J2WZA7fptcAztfXxfAZB9mhZB6W1nl5dz5tXMlb9DJk9ibs6RqtP7PtO6a3XCiHWVwZDZD')
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:graph) { Zuck.graph }
|
10
|
+
let(:account) { Zuck::AdAccount.new(graph, {id: "act_10150585630710217"}) }
|
11
|
+
let(:campaign){ Zuck::AdCampaign.new(graph, {id: "6005950787751"}, account) }
|
12
|
+
let(:group) { Zuck::AdGroup.new(graph, {id: "6004497038951"}, campaign)}
|
13
|
+
let(:creative){ Zuck::AdCreative.new(graph, {id: "1234567890123"}, group) }
|
14
|
+
|
15
|
+
|
16
|
+
describe "read only objects" do
|
17
|
+
it "can't be created" do
|
18
|
+
expect{
|
19
|
+
Zuck::AdCreative.create(:x, {}, :y)
|
20
|
+
}.to raise_error(Zuck::Error::ReadOnly)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "can't be saved" do
|
24
|
+
expect{
|
25
|
+
creative.save
|
26
|
+
}.to raise_error(Zuck::Error::ReadOnly)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "can't be destroyed" do
|
30
|
+
expect{
|
31
|
+
creative.destroy
|
32
|
+
}.to raise_error(Zuck::Error::ReadOnly)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "talking to facebook" do
|
37
|
+
context "reading" do
|
38
|
+
|
39
|
+
it "a list of ad accounts" do
|
40
|
+
VCR.use_cassette('list_of_ad_accounts') do
|
41
|
+
Zuck::AdAccount.all.should have(1).item
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "a list of ad campaigns" do
|
46
|
+
VCR.use_cassette('list_of_ad_campaigns') do
|
47
|
+
account.ad_campaigns.should have(3).items
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "a list of ad groups" do
|
52
|
+
VCR.use_cassette('list_of_ad_groups') do
|
53
|
+
campaign.ad_groups.should have(1).item
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "list of ad creatives" do
|
58
|
+
VCR.use_cassette('list_of_ad_creatives') do
|
59
|
+
group.ad_creatives.should have(1).items
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
it "list of all ad creatives of an account" do
|
64
|
+
g = graph
|
65
|
+
Zuck::AdAccount.should_receive(:all).and_return([account])
|
66
|
+
VCR.use_cassette('list_of_all_ad_creatives_of_account') do
|
67
|
+
Zuck::AdCreative.all(g).should have(6).items
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "an id directly" do
|
72
|
+
|
73
|
+
it "with the correct type" do
|
74
|
+
VCR.use_cassette('a_single_campaign') do
|
75
|
+
c = Zuck::AdCampaign.find(6005950787751, graph)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
it "with the correct type" do
|
80
|
+
VCR.use_cassette('a_single_account') do
|
81
|
+
c = Zuck::AdAccount.find('act_10150585630710217', graph)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it "when expecting an ad group but the id belongs to a campaign" do
|
86
|
+
expected_error = <<-END_ERROR
|
87
|
+
Invalid type.
|
88
|
+
|
89
|
+
Expected data['id']="6005950787751" to be equal to one of these:
|
90
|
+
* data['account_id']="10150585630710217"
|
91
|
+
* data['group_id']=nil
|
92
|
+
* data['adgroup_id']=nil
|
93
|
+
END_ERROR
|
94
|
+
VCR.use_cassette('a_single_campaign') do
|
95
|
+
expect{
|
96
|
+
c = Zuck::AdGroup.find(6005950787751, graph)
|
97
|
+
}.to raise_error(expected_error)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
it "and saving it" do
|
102
|
+
VCR.use_cassette('find_a_single_campaign_and_update_it') do
|
103
|
+
group = Zuck::AdGroup.find(6005859287551, graph)
|
104
|
+
group.name = "My old name"
|
105
|
+
group.save
|
106
|
+
group.name.should == "My old name"
|
107
|
+
group.name = "My new name"
|
108
|
+
group.save
|
109
|
+
group.name.should == "My new name"
|
110
|
+
group.reload
|
111
|
+
group.name.should == "My new name"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
|
119
|
+
context "creating" do
|
120
|
+
it "an ad campaign" do
|
121
|
+
VCR.use_cassette('create_ad_campaign') do
|
122
|
+
o = {daily_budget: 1000, name: "bloody" }
|
123
|
+
campaign = Zuck::AdCampaign.create(graph, o, account)
|
124
|
+
campaign.name.should == "bloody"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
it "an ad campaign via an existing ad account" do
|
129
|
+
VCR.use_cassette('create_ad_campaign') do
|
130
|
+
o = {daily_budget: 1000, name: "bloody" }
|
131
|
+
campaign = account.create_ad_campaign(o)
|
132
|
+
campaign.name.should == "bloody"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
it "an ad group" do
|
137
|
+
VCR.use_cassette('create_ad_group') do
|
138
|
+
o = {bid_type: 1, max_bid: 1, name: "Rap like me", targeting: '{"countries":["US"]}',
|
139
|
+
creative: '{"type":25,"action_spec":{"action.type":"like", "post":10150420410887685}}'}
|
140
|
+
group = Zuck::AdGroup.create(graph, o, campaign)
|
141
|
+
group.name.should == "Rap like me"
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
it "an ad group via an existing ad campaign" do
|
146
|
+
VCR.use_cassette('create_ad_group') do
|
147
|
+
o = {bid_type: 1, max_bid: 1, name: "Rap like me", targeting: '{"countries":["US"]}',
|
148
|
+
creative: '{"type":25,"action_spec":{"action.type":"like", "post":10150420410887685}}'}
|
149
|
+
group = campaign.create_ad_group(o)
|
150
|
+
group.name.should == "Rap like me"
|
151
|
+
group.bid_type.should == 1
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context "deleting" do
|
157
|
+
it "an ad group" do
|
158
|
+
VCR.use_cassette('delete_ad_group') do
|
159
|
+
group.destroy.should be_true
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'simplecov'
|
3
|
+
SimpleCov.start
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.require
|
6
|
+
|
7
|
+
# This file is copied to spec/ when you run 'rails generate rspec:install'
|
8
|
+
ENV["RAILS_ENV"] ||= 'test'
|
9
|
+
# require File.expand_path("../../config/environment", __FILE__)
|
10
|
+
require 'webmock/rspec'
|
11
|
+
require 'vcr_setup'
|
12
|
+
#require 'capybara/poltergeist'
|
13
|
+
|
14
|
+
# Requires supporting ruby files with custom matchers and macros, etc,
|
15
|
+
# in spec/support/ and its subdirectories.
|
16
|
+
Dir[File.expand_path("../../spec/support/**/*.rb", __FILE__)].each {|f| require f}
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
# == Mock Framework
|
20
|
+
#
|
21
|
+
# If you prefer to use mocha, flexmock or RR, uncomment the appropriate line:
|
22
|
+
#
|
23
|
+
# config.mock_with :mocha
|
24
|
+
# config.mock_with :flexmock
|
25
|
+
# config.mock_with :rr
|
26
|
+
config.mock_with :rspec
|
27
|
+
|
28
|
+
# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
module TestResponseExtensions
|
33
|
+
def json_body
|
34
|
+
JSON.parse(self.body)
|
35
|
+
end
|
36
|
+
|
37
|
+
def unauthorized?
|
38
|
+
code.to_i == 401
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def expect_id_and_return(id, ret_val)
|
43
|
+
lambda { |id| id.to_s.should == id.to_s; ret_val }
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
require File.expand_path("../../lib/zuck", __FILE__)
|
data/spec/vcr_setup.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# VCR Config
|
2
|
+
require 'vcr'
|
3
|
+
FileUtils.mkdir("log") rescue nil
|
4
|
+
VCR.configure do |c|
|
5
|
+
dir = File.expand_path("../../spec/fixtures", __FILE__)
|
6
|
+
c.cassette_library_dir = dir
|
7
|
+
c.hook_into :webmock
|
8
|
+
c.ignore_localhost = true
|
9
|
+
c.default_cassette_options = {
|
10
|
+
record: :new_episodes,
|
11
|
+
match_requests_on: [:method, :body, :uri]
|
12
|
+
}
|
13
|
+
c.allow_http_connections_when_no_cassette = false
|
14
|
+
c.debug_logger = File.open(File.expand_path("../../log/vcr.log", __FILE__), "w")
|
15
|
+
end
|
data/zuck.gemspec
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "zuck"
|
8
|
+
s.version = "0.0.4"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Jannis Hermanns"]
|
12
|
+
s.date = "2013-01-03"
|
13
|
+
s.description = "This gem allows to easily access facebook's ads api in ruby. See https://developers.facebook.com/docs/reference/ads-api/"
|
14
|
+
s.email = "jannis@gmail.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE.txt",
|
17
|
+
"README.markdown"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".rvmrc",
|
21
|
+
".travis.yml",
|
22
|
+
".yardopts",
|
23
|
+
"CHANGELOG.markdown",
|
24
|
+
"Gemfile",
|
25
|
+
"Gemfile.lock",
|
26
|
+
"Guardfile.dist",
|
27
|
+
"LICENSE.txt",
|
28
|
+
"README.markdown",
|
29
|
+
"Rakefile",
|
30
|
+
"VERSION",
|
31
|
+
"console",
|
32
|
+
"lib/zuck.rb",
|
33
|
+
"lib/zuck/facebook/ad_account.rb",
|
34
|
+
"lib/zuck/facebook/ad_campaign.rb",
|
35
|
+
"lib/zuck/facebook/ad_creative.rb",
|
36
|
+
"lib/zuck/facebook/ad_group.rb",
|
37
|
+
"lib/zuck/facebook/targeting_spec.rb",
|
38
|
+
"lib/zuck/fb_object.rb",
|
39
|
+
"lib/zuck/fb_object/dsl.rb",
|
40
|
+
"lib/zuck/fb_object/error.rb",
|
41
|
+
"lib/zuck/fb_object/hash_delegator.rb",
|
42
|
+
"lib/zuck/fb_object/helpers.rb",
|
43
|
+
"lib/zuck/fb_object/read.rb",
|
44
|
+
"lib/zuck/fb_object/read_only.rb",
|
45
|
+
"lib/zuck/fb_object/write.rb",
|
46
|
+
"lib/zuck/koala/koala_methods.rb",
|
47
|
+
"spec/fixtures/a_single_account.yml",
|
48
|
+
"spec/fixtures/a_single_campaign.yml",
|
49
|
+
"spec/fixtures/create_ad_campaign.yml",
|
50
|
+
"spec/fixtures/create_ad_group.yml",
|
51
|
+
"spec/fixtures/delete_ad_group.yml",
|
52
|
+
"spec/fixtures/find_a_single_campaign_and_update_it.yml",
|
53
|
+
"spec/fixtures/list_of_ad_accounts.yml",
|
54
|
+
"spec/fixtures/list_of_ad_campaigns.yml",
|
55
|
+
"spec/fixtures/list_of_ad_creatives.yml",
|
56
|
+
"spec/fixtures/list_of_ad_groups.yml",
|
57
|
+
"spec/fixtures/list_of_all_ad_creatives_of_account.yml",
|
58
|
+
"spec/fixtures/reach_for_invalid_keyword.yml",
|
59
|
+
"spec/fixtures/reach_for_valid_keywords.yml",
|
60
|
+
"spec/fixtures/reach_for_valid_keywords_male_young.yml",
|
61
|
+
"spec/lib/zuck/facebook/ad_account_spec.rb",
|
62
|
+
"spec/lib/zuck/facebook/ad_campaign_spec.rb",
|
63
|
+
"spec/lib/zuck/facebook/targeting_spec_spec.rb",
|
64
|
+
"spec/lib/zuck/fb_object/helpers_spec.rb",
|
65
|
+
"spec/lib/zuck/koala/koala_methods_spec.rb",
|
66
|
+
"spec/lib/zuck/util/hash_delegator_spec.rb",
|
67
|
+
"spec/lib/zuck_spec.rb",
|
68
|
+
"spec/spec_helper.rb",
|
69
|
+
"spec/vcr_setup.rb",
|
70
|
+
"zuck.gemspec"
|
71
|
+
]
|
72
|
+
s.homepage = "http://github.com/jayniz/zuck"
|
73
|
+
s.licenses = ["MIT"]
|
74
|
+
s.require_paths = ["lib"]
|
75
|
+
s.rubygems_version = "1.8.24"
|
76
|
+
s.summary = "Ruby adapter to facebook's ad api"
|
77
|
+
|
78
|
+
if s.respond_to? :specification_version then
|
79
|
+
s.specification_version = 3
|
80
|
+
|
81
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
82
|
+
s.add_runtime_dependency(%q<rvm>, [">= 0"])
|
83
|
+
s.add_runtime_dependency(%q<bundler>, [">= 0"])
|
84
|
+
s.add_runtime_dependency(%q<koala>, [">= 1.5"])
|
85
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
86
|
+
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
87
|
+
s.add_development_dependency(%q<rdoc>, ["~> 3.12"])
|
88
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.8.4"])
|
89
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
90
|
+
s.add_development_dependency(%q<webmock>, [">= 0"])
|
91
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
92
|
+
s.add_development_dependency(%q<vcr>, [">= 0"])
|
93
|
+
s.add_development_dependency(%q<guard>, [">= 0"])
|
94
|
+
s.add_development_dependency(%q<guard-rspec>, [">= 0"])
|
95
|
+
s.add_development_dependency(%q<guard-bundler>, [">= 0"])
|
96
|
+
s.add_development_dependency(%q<guard-yard>, [">= 0"])
|
97
|
+
s.add_development_dependency(%q<growl>, [">= 0"])
|
98
|
+
s.add_development_dependency(%q<redcarpet>, [">= 0"])
|
99
|
+
s.add_development_dependency(%q<rb-fsevent>, [">= 0"])
|
100
|
+
else
|
101
|
+
s.add_dependency(%q<rvm>, [">= 0"])
|
102
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
103
|
+
s.add_dependency(%q<koala>, [">= 1.5"])
|
104
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
105
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
106
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
107
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
108
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
109
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
110
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
111
|
+
s.add_dependency(%q<vcr>, [">= 0"])
|
112
|
+
s.add_dependency(%q<guard>, [">= 0"])
|
113
|
+
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
114
|
+
s.add_dependency(%q<guard-bundler>, [">= 0"])
|
115
|
+
s.add_dependency(%q<guard-yard>, [">= 0"])
|
116
|
+
s.add_dependency(%q<growl>, [">= 0"])
|
117
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
118
|
+
s.add_dependency(%q<rb-fsevent>, [">= 0"])
|
119
|
+
end
|
120
|
+
else
|
121
|
+
s.add_dependency(%q<rvm>, [">= 0"])
|
122
|
+
s.add_dependency(%q<bundler>, [">= 0"])
|
123
|
+
s.add_dependency(%q<koala>, [">= 1.5"])
|
124
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
125
|
+
s.add_dependency(%q<shoulda>, [">= 0"])
|
126
|
+
s.add_dependency(%q<rdoc>, ["~> 3.12"])
|
127
|
+
s.add_dependency(%q<jeweler>, ["~> 1.8.4"])
|
128
|
+
s.add_dependency(%q<simplecov>, [">= 0"])
|
129
|
+
s.add_dependency(%q<webmock>, [">= 0"])
|
130
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
131
|
+
s.add_dependency(%q<vcr>, [">= 0"])
|
132
|
+
s.add_dependency(%q<guard>, [">= 0"])
|
133
|
+
s.add_dependency(%q<guard-rspec>, [">= 0"])
|
134
|
+
s.add_dependency(%q<guard-bundler>, [">= 0"])
|
135
|
+
s.add_dependency(%q<guard-yard>, [">= 0"])
|
136
|
+
s.add_dependency(%q<growl>, [">= 0"])
|
137
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
138
|
+
s.add_dependency(%q<rb-fsevent>, [">= 0"])
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|