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.
Files changed (52) hide show
  1. data/.rvmrc +1 -0
  2. data/.travis.yml +7 -0
  3. data/.yardopts +4 -0
  4. data/CHANGELOG.markdown +4 -0
  5. data/Gemfile +35 -0
  6. data/Gemfile.lock +110 -0
  7. data/Guardfile.dist +45 -0
  8. data/LICENSE.txt +20 -0
  9. data/README.markdown +138 -0
  10. data/Rakefile +39 -0
  11. data/VERSION +1 -0
  12. data/console +26 -0
  13. data/lib/zuck/facebook/ad_account.rb +40 -0
  14. data/lib/zuck/facebook/ad_campaign.rb +24 -0
  15. data/lib/zuck/facebook/ad_creative.rb +30 -0
  16. data/lib/zuck/facebook/ad_group.rb +39 -0
  17. data/lib/zuck/facebook/targeting_spec.rb +200 -0
  18. data/lib/zuck/fb_object/dsl.rb +110 -0
  19. data/lib/zuck/fb_object/error.rb +8 -0
  20. data/lib/zuck/fb_object/hash_delegator.rb +111 -0
  21. data/lib/zuck/fb_object/helpers.rb +57 -0
  22. data/lib/zuck/fb_object/read.rb +147 -0
  23. data/lib/zuck/fb_object/read_only.rb +0 -0
  24. data/lib/zuck/fb_object/write.rb +75 -0
  25. data/lib/zuck/fb_object.rb +53 -0
  26. data/lib/zuck/koala/koala_methods.rb +27 -0
  27. data/lib/zuck.rb +9 -0
  28. data/spec/fixtures/a_single_account.yml +75 -0
  29. data/spec/fixtures/a_single_campaign.yml +48 -0
  30. data/spec/fixtures/create_ad_campaign.yml +49 -0
  31. data/spec/fixtures/create_ad_group.yml +47 -0
  32. data/spec/fixtures/delete_ad_group.yml +50 -0
  33. data/spec/fixtures/find_a_single_campaign_and_update_it.yml +247 -0
  34. data/spec/fixtures/list_of_ad_accounts.yml +75 -0
  35. data/spec/fixtures/list_of_ad_campaigns.yml +76 -0
  36. data/spec/fixtures/list_of_ad_creatives.yml +51 -0
  37. data/spec/fixtures/list_of_ad_groups.yml +49 -0
  38. data/spec/fixtures/list_of_all_ad_creatives_of_account.yml +86 -0
  39. data/spec/fixtures/reach_for_invalid_keyword.yml +95 -0
  40. data/spec/fixtures/reach_for_valid_keywords.yml +93 -0
  41. data/spec/fixtures/reach_for_valid_keywords_male_young.yml +93 -0
  42. data/spec/lib/zuck/facebook/ad_account_spec.rb +26 -0
  43. data/spec/lib/zuck/facebook/ad_campaign_spec.rb +4 -0
  44. data/spec/lib/zuck/facebook/targeting_spec_spec.rb +174 -0
  45. data/spec/lib/zuck/fb_object/helpers_spec.rb +67 -0
  46. data/spec/lib/zuck/koala/koala_methods_spec.rb +30 -0
  47. data/spec/lib/zuck/util/hash_delegator_spec.rb +54 -0
  48. data/spec/lib/zuck_spec.rb +165 -0
  49. data/spec/spec_helper.rb +47 -0
  50. data/spec/vcr_setup.rb +15 -0
  51. data/zuck.gemspec +141 -0
  52. metadata +389 -0
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use ruby-1.9.3@zuck
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ - jruby-19mode
6
+ - rbx-19mode
7
+ script: bundle exec rspec spec
data/.yardopts ADDED
@@ -0,0 +1,4 @@
1
+ --hide-void-return
2
+ --no-output
3
+ --markup-provider=redcarpet
4
+ --markup=markdown
@@ -0,0 +1,4 @@
1
+ 0.0.4
2
+ -----
3
+
4
+ - integrated targeting spec to fetch reach estimates
data/Gemfile ADDED
@@ -0,0 +1,35 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gem 'rvm'
4
+ gem 'bundler'
5
+ gem 'koala', '>=1.5'
6
+ gem 'activesupport'
7
+
8
+ group :development do
9
+ gem "shoulda", ">= 0"
10
+ gem "rdoc", "~> 3.12"
11
+ gem "jeweler", "~> 1.8.4"
12
+ gem "simplecov", ">= 0", :require => false
13
+ end
14
+
15
+ group :development, :test do
16
+ gem 'webmock'
17
+ gem 'rspec'
18
+ gem 'vcr'
19
+ end
20
+
21
+ platform :ruby do
22
+ group :development do
23
+ gem 'guard'
24
+ gem 'guard-rspec'
25
+ gem 'guard-bundler'
26
+ gem 'guard-yard'
27
+ gem 'growl'
28
+ gem 'redcarpet' # Markdown for yard
29
+ gem 'rb-fsevent'
30
+ end
31
+ end
32
+
33
+ # platform :jruby do
34
+ # # gem 'jruby-openssl'
35
+ # end
data/Gemfile.lock ADDED
@@ -0,0 +1,110 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activesupport (3.2.9)
5
+ i18n (~> 0.6)
6
+ multi_json (~> 1.0)
7
+ addressable (2.3.2)
8
+ bourne (1.1.2)
9
+ mocha (= 0.10.5)
10
+ coderay (1.0.8)
11
+ crack (0.3.1)
12
+ diff-lcs (1.1.3)
13
+ faraday (0.8.4)
14
+ multipart-post (~> 1.1)
15
+ git (1.2.5)
16
+ growl (1.0.3)
17
+ guard (1.6.1)
18
+ listen (>= 0.6.0)
19
+ lumberjack (>= 1.0.2)
20
+ pry (>= 0.9.10)
21
+ thor (>= 0.14.6)
22
+ guard-bundler (1.0.0)
23
+ bundler (~> 1.0)
24
+ guard (~> 1.1)
25
+ guard-rspec (2.3.3)
26
+ guard (>= 1.1)
27
+ rspec (~> 2.11)
28
+ guard-yard (2.0.1)
29
+ guard (>= 1.1.0)
30
+ yard (>= 0.7.0)
31
+ i18n (0.6.1)
32
+ jeweler (1.8.4)
33
+ bundler (~> 1.0)
34
+ git (>= 1.2.5)
35
+ rake
36
+ rdoc
37
+ json (1.7.5)
38
+ json (1.7.5-java)
39
+ koala (1.6.0)
40
+ addressable (~> 2.2)
41
+ faraday (~> 0.8)
42
+ multi_json (~> 1.3)
43
+ listen (0.6.0)
44
+ lumberjack (1.0.2)
45
+ metaclass (0.0.1)
46
+ method_source (0.8.1)
47
+ mocha (0.10.5)
48
+ metaclass (~> 0.0.1)
49
+ multi_json (1.5.0)
50
+ multipart-post (1.1.5)
51
+ pry (0.9.10)
52
+ coderay (~> 1.0.5)
53
+ method_source (~> 0.8)
54
+ slop (~> 3.3.1)
55
+ rake (10.0.3)
56
+ rb-fsevent (0.9.1)
57
+ rdoc (3.12)
58
+ json (~> 1.4)
59
+ redcarpet (2.2.2)
60
+ rspec (2.12.0)
61
+ rspec-core (~> 2.12.0)
62
+ rspec-expectations (~> 2.12.0)
63
+ rspec-mocks (~> 2.12.0)
64
+ rspec-core (2.12.2)
65
+ rspec-expectations (2.12.1)
66
+ diff-lcs (~> 1.1.3)
67
+ rspec-mocks (2.12.1)
68
+ rvm (1.11.3.5)
69
+ shoulda (3.3.2)
70
+ shoulda-context (~> 1.0.1)
71
+ shoulda-matchers (~> 1.4.1)
72
+ shoulda-context (1.0.2)
73
+ shoulda-matchers (1.4.2)
74
+ activesupport (>= 3.0.0)
75
+ bourne (~> 1.1.2)
76
+ simplecov (0.7.1)
77
+ multi_json (~> 1.0)
78
+ simplecov-html (~> 0.7.1)
79
+ simplecov-html (0.7.1)
80
+ slop (3.3.3)
81
+ thor (0.16.0)
82
+ vcr (2.3.0)
83
+ webmock (1.9.0)
84
+ addressable (>= 2.2.7)
85
+ crack (>= 0.1.7)
86
+ yard (0.8.3)
87
+
88
+ PLATFORMS
89
+ java
90
+ ruby
91
+
92
+ DEPENDENCIES
93
+ activesupport
94
+ bundler
95
+ growl
96
+ guard
97
+ guard-bundler
98
+ guard-rspec
99
+ guard-yard
100
+ jeweler (~> 1.8.4)
101
+ koala (>= 1.5)
102
+ rb-fsevent
103
+ rdoc (~> 3.12)
104
+ redcarpet
105
+ rspec
106
+ rvm
107
+ shoulda
108
+ simplecov
109
+ vcr
110
+ webmock
data/Guardfile.dist ADDED
@@ -0,0 +1,45 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'bundler' do
5
+ watch('Gemfile')
6
+ # Uncomment next line if Gemfile contain `gemspec' command
7
+ # watch(/^.+\.gemspec/)
8
+ end
9
+
10
+ guard 'rspec', :version => 2 do
11
+ watch(%r{^spec/.+_spec\.rb$})
12
+ watch('spec/spec_helper.rb') { "spec" }
13
+ watch(%r{^lib/zuck/(.+)\.rb$}) { "spec" }
14
+
15
+ # Rails example
16
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
17
+ watch(%r{^app/(.*)(\.erb|\.haml)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
18
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
19
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
20
+ watch('config/routes.rb') { "spec/routing" }
21
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
22
+
23
+ # Turnip features and steps
24
+ watch(%r{^spec/acceptance/(.+)\.feature$})
25
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
26
+ end
27
+
28
+
29
+ guard 'spork', :cucumber_env => { 'RAILS_ENV' => 'test' }, :rspec_env => { 'RAILS_ENV' => 'test' } do
30
+ watch('config/application.rb')
31
+ watch('config/environment.rb')
32
+ watch('config/environments/test.rb')
33
+ watch(%r{^config/initializers/.+\.rb$})
34
+ watch('Gemfile')
35
+ watch('Gemfile.lock')
36
+ watch('spec/spec_helper.rb') { :rspec }
37
+ watch('test/test_helper.rb') { :test_unit }
38
+ watch(%r{features/support/}) { :cucumber }
39
+ end
40
+
41
+ guard 'yard' do
42
+ watch(%r{app/.+\.rb})
43
+ watch(%r{lib/.+\.rb})
44
+ watch(%r{ext/.+\.c})
45
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Jannis Hermanns
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.markdown ADDED
@@ -0,0 +1,138 @@
1
+ [![Build Status](https://secure.travis-ci.org/moviepilot/zuck.png?branch=master)](https://travis-ci.org/moviepilot/zuck)
2
+
3
+ Zuck; use facebook's advertisement API with ruby
4
+ ================
5
+
6
+ This is a little gem that makes access to facebook's
7
+ ads API a little easier. Check out facebook's
8
+ [documentation](https://developers.facebook.com/docs/reference/ads-api/)
9
+ for a nice diagram that explains how things work.
10
+
11
+ ![](https://dl.dropbox.com/u/1953503/kw29_koelner_gelierzucker_31_oder_diamant_feinster_zucker_462982.jpeg)
12
+
13
+ We just hacked this up and are not using it in production yet,
14
+ so handle with care. On the other hand, simplecov reports 100%
15
+ coverage. But as it is a gem in a very early stage, a warning was
16
+ due.
17
+
18
+ Usage
19
+ =====
20
+
21
+ Not everything is supported yet. Here's what you can do currently.
22
+
23
+
24
+ Reading
25
+ --------
26
+ ```ruby
27
+ # Let's set a default graph object with an access token
28
+ Zuck.graph = Koala::Facebook::API.new('my_access_token')
29
+
30
+ # Fetching all ad accounts associated to that user
31
+ accounts = Zuck::AdAccount.all
32
+
33
+ # Let's look at an account
34
+ my_account = accounts.first
35
+ => #<Zuck::AdAccount id: "act_10150585630710217", account_id: "10150585630710217", name: "", account_status: 1, currency: "USD", timezone_id: 47, timezone_name: "Europe/Berlin", timezone_offset_hours_utc: 2, is_personal: 0, business_name: "Big Mike Alright UG (haftungsbeschr\u00e4nkt)", business_street: "Big Mike Alright UG (haftungsbeschr\u00e4nkt)", business_street2: "J\u00e4gerndorfer Zeile 61", business_city: "Berlin", business_state: "Berlin", business_zip: "12209", business_country_code: "DE", vat_status: 3, daily_spend_limit: 25000, users: [{"uid":501730216,"permissions":[1,2,3,4,5,7],"role":1001}], notification_settings: {"501730216":{"1000":{"1":1},"1001":{"1":1},"1002":{"1":1,"2":60},"1003":{"1":1,"2":60},"1004":{"1":1},"1005":{"1":1},"1006":{"1":1},"1009":{"1":1},"1010":{"1":1},"1011":{"1":1},"2000":{"1":1,"2":60},"2001":{"1":1,"2":60},"2002":{"2":60},"2003":{"1":1,"2":60},"2004":{"1":1,"2":60},"2005":{"1":1,"2":60},"3000":{"1":1,"2":60},"3001":{"1":1,"2":60},"3002":{"2":60},"3003":{"1":1,"2":60},"5000":{"1":1},"6000":{"1":1},"6001":{"1":1},"9000":{"1":1,"2":60},"8000":{"1":1,"2":60}}}, capabilities: [], balance: 0, moo_default_conversion_bid: 1000, moo_default_bid: 1000>
36
+
37
+ # Aha. How do I access properties? The documented properties
38
+ # have getters:
39
+ my_account.currency
40
+ => "USD"
41
+
42
+ # But facebook also returns some non documented stuff
43
+ my_account[:moo_default_bid]
44
+ => 1000
45
+
46
+ # Let's fetch the campaigns for this account
47
+ my_campaign = my_account.ad_campaigns.first
48
+
49
+ # Aha! Does this campaign have ad groups?
50
+ my_group = my_campaign.ad_groups.first
51
+ my_group.name
52
+ => "Group names are silly"
53
+
54
+ # That was surprising. Just like the fact that ad groups
55
+ # have ad creatives associated to them:
56
+ my_creative = my_group.ad_creatives.first
57
+
58
+ # Let's go back up to the parent
59
+ my_creative.ad_group.name
60
+ => "Group names are silly"
61
+ ```
62
+
63
+ Writing
64
+ --------
65
+
66
+ ```ruby
67
+ # Directly defining the creative as JSON
68
+ creative = '{"type":25,"action_spec":{"action.type":"like", "post":10150420410887685}}'
69
+
70
+ # Options for the ad group we want to create
71
+ o = { bid_type: 1,
72
+ max_bid: 1,
73
+ name: "My first ad group",
74
+ targeting: '{"countries":["US"]}',
75
+ creative: creative}
76
+
77
+ # Create it in the context of my_campaign
78
+ group = my_campaign.create_ad_group(o)
79
+ => #<Zuck::AdGroup adgroup_id: 6005851390151, ad_id: 6005851390151, campaign_id: 6005851032951, name: "My first ad group", adgroup_status: 4, bid_type: 1, max_bid: "1", bid_info: {"1":"1"}, ad_status: 4, account_id: "10150585630710217", id: "6005851390151", creative_ids: [6005851371551], targeting: {"countries":["US"],"friends_of_connections":[{"id":"6005851366351","name":null}]}, conversion_specs: [{"action.type":"like","post":"10150420410887685"}], start_time: null, end_time: null, updated_time: 1343916568, created_time: 1343916568>
80
+
81
+ # Shoot, that was the wrong name
82
+ group.name = "My serious ad group"
83
+ group.save
84
+ => true
85
+
86
+ # No wait, let's not spend money on facebook
87
+ group.destroy
88
+ => true
89
+
90
+ # What does destroy mean? Changing the status!
91
+ group.ad_status
92
+ => 3
93
+ ```
94
+
95
+ Supported objects
96
+ -----------------
97
+
98
+ This gem supports basic CRUD on the objects of the facebook ads api.
99
+ Here's a support chart:
100
+
101
+ <table>
102
+ <tr>
103
+ <th style="text-align:right">Object</th>
104
+ <th style="text-align:center">.all</th>
105
+ <th style="text-align:center">.create</th>
106
+ <th style="text-align:center">.save</th>
107
+ <th style="text-align:center">.destroy</th>
108
+ <th style="text-align:center">parent.create_obj*</th>
109
+ <th style="text-align:center">Convenience methods**</th>
110
+ </tr>
111
+ <tr><td style="text-align: right">Ad account</td> <td>✔</td><td>-</td><td>✔</td><td>✔</td><td>-</td><td>-</td></tr>
112
+ <tr><td style="text-align: right">Ad account group</td> <td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
113
+ <tr><td style="text-align: right">Ad campaign</td> <td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>-</td></tr>
114
+ <tr><td style="text-align: right">Ad creative</td> <td>✔</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
115
+ <tr><td style="text-align: right">Ad group</td> <td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>✔</td><td>-</td></tr>
116
+ <tr><td style="text-align: right">Ad image</td> <td>●</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
117
+ <tr><td style="text-align: right">Ad user</td> <td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr>
118
+ </table>
119
+
120
+ (*) This means that you can, for example, create a new ad group by calling
121
+ `my_campaign.create_ad_group(data)` or not.
122
+
123
+ (**) Right now, everything goes right to facebook, but we'll want some
124
+ convenience methods that tell you, for example, what
125
+ `ad_group.ad_status == 3` actually means
126
+
127
+ ( ) These don't exist as their own objects in this gem but live in their
128
+ parents. This means you can, for now, only read them:
129
+
130
+ Users don't exist as objects yet, but you can list all ad users of
131
+ an account via `my_ad_account.users` and you will get an array of hashes.
132
+
133
+ To-Do
134
+ -----
135
+
136
+ Add convenience stuff, right now everything is quite raw and directly
137
+ sent over to facebook. Also, more tests directly to the api with a test
138
+ user. Consolidate and test create code with other objects than AdGroup.
data/Rakefile ADDED
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "zuck"
18
+ gem.homepage = "http://github.com/jayniz/zuck"
19
+ gem.license = "MIT"
20
+ gem.summary = %Q{Ruby adapter to facebook's ad api}
21
+ gem.description = %Q{This gem allows to easily access facebook's ads api in ruby. See https://developers.facebook.com/docs/reference/ads-api/}
22
+ gem.email = "jannis@gmail.com"
23
+ gem.authors = ["Jannis Hermanns"]
24
+ # dependencies defined in Gemfile
25
+ end
26
+ Jeweler::RubygemsDotOrgTasks.new
27
+
28
+
29
+ task :default => :test
30
+
31
+ require 'rdoc/task'
32
+ Rake::RDocTask.new do |rdoc|
33
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
34
+
35
+ rdoc.rdoc_dir = 'rdoc'
36
+ rdoc.title = "zuck #{version}"
37
+ rdoc.rdoc_files.include('README*')
38
+ rdoc.rdoc_files.include('lib/**/*.rb')
39
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.4
data/console ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path(File.join(File.dirname(__FILE__), 'lib'))
3
+
4
+ require 'bundler'
5
+ Bundler.require
6
+
7
+ require 'irb'
8
+ require 'zuck'
9
+
10
+ def reload!
11
+ @loaded_files ||= {}
12
+ count = 0
13
+
14
+ Dir['./lib/**/*.rb'].each do |file|
15
+ mtime = File.stat(file).mtime
16
+ if !@loaded_files.has_key?(file) or mtime > @loaded_files[file]
17
+ STDERR.puts "mtime for #{file} changed, reloading"
18
+ load file
19
+ @loaded_files[file] = mtime
20
+ count += 1
21
+ end
22
+ end
23
+ "reloaded #{count} files"
24
+ end
25
+
26
+ IRB.start
@@ -0,0 +1,40 @@
1
+ module Zuck
2
+ class AdAccount < RawFbObject
3
+
4
+ # The [fb docs](https://developers.facebook.com/docs/reference/ads-api/adaccount/)
5
+ # were incomplete, so I added here what the graph explorer
6
+ # actually returned.
7
+ known_keys :account_id,
8
+ :account_status,
9
+ :balance,
10
+ :business_city,
11
+ :business_country_code,
12
+ :business_name,
13
+ :business_state,
14
+ :business_street,
15
+ :business_street2,
16
+ :business_zip,
17
+ :capabilities,
18
+ :currency,
19
+ :daily_spend_limit,
20
+ :id,
21
+ :is_personal,
22
+ :moo_default_bid,
23
+ :moo_default_conversion_bid,
24
+ :name,
25
+ :notification_settings,
26
+ :timezone_id,
27
+ :timezone_name,
28
+ :timezone_offset_hours_utc,
29
+ :users,
30
+ :vat_status
31
+
32
+
33
+ list_path 'me/adaccounts'
34
+ connections :ad_campaigns
35
+
36
+ def self.all(graph = Zuck.graph)
37
+ super(graph)
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,24 @@
1
+ module Zuck
2
+ class AdCampaign < RawFbObject
3
+
4
+ # The [fb docs](https://developers.facebook.com/docs/reference/ads-api/adaccount/)
5
+ # were incomplete, so I added here what the graph explorer
6
+ # actually returned.
7
+ known_keys :account_id,
8
+ :campaign_id,
9
+ :campaign_status,
10
+ :created_time,
11
+ :daily_imps,
12
+ :end_time,
13
+ :id,
14
+ :lifetime_budget,
15
+ :name,
16
+ :start_time,
17
+ :updated_time
18
+
19
+ parent_object :ad_account
20
+ list_path :adcampaigns
21
+ connections :ad_groups
22
+
23
+ end
24
+ end
@@ -0,0 +1,30 @@
1
+ module Zuck
2
+ class AdCreative < RawFbObject
3
+
4
+ # Can't create this directly (yet)
5
+ read_only
6
+
7
+ # The [fb docs](https://developers.facebook.com/docs/reference/ads-api/adaccount/)
8
+ # were incomplete, so I added here what the graph explorer
9
+ # actually returned.
10
+ known_keys :alt_view_tags,
11
+ :body,
12
+ :count_current_adgroups,
13
+ :creative_id,
14
+ :id,
15
+ :image_hash,
16
+ :image_url,
17
+ :link_url,
18
+ :name,
19
+ :object_id,
20
+ :preview_url,
21
+ :run_status,
22
+ :title,
23
+ :type,
24
+ :view_tag
25
+
26
+ parent_object :ad_group
27
+ list_path :adcreatives
28
+
29
+ end
30
+ end
@@ -0,0 +1,39 @@
1
+ require 'zuck/facebook/ad_creative'
2
+
3
+ module Zuck
4
+ class AdGroup < RawFbObject
5
+
6
+ # The [fb docs](https://developers.facebook.com/docs/reference/ads-api/adaccount/)
7
+ # were incomplete, so I added here what the graph explorer
8
+ # actually returned.
9
+ known_keys :account_id,
10
+ :ad_id,
11
+ :ad_status,
12
+ :adgroup_id,
13
+ :adgroup_status,
14
+ :bid_info,
15
+ :bid_type,
16
+ :campaign_id,
17
+ :conversion_specs,
18
+ :created_time,
19
+ :creative_ids,
20
+ :end_time,
21
+ :id,
22
+ :max_bid,
23
+ :name,
24
+ :start_time,
25
+ :targeting,
26
+ :updated_time
27
+
28
+ parent_object :ad_campaign
29
+ list_path :adgroups
30
+ connections :ad_creatives
31
+
32
+ def self.create(graph, data, ad_campaign)
33
+ path = ad_campaign.ad_account.path
34
+ data['campaign_id'] = ad_campaign.id
35
+ super(graph, data, ad_campaign, path)
36
+ end
37
+
38
+ end
39
+ end