facebook_ads 0.6.11 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +27 -0
  3. data/.rubocop.yml +11 -10
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/CHANGELOG.md +8 -0
  7. data/Gemfile +2 -2
  8. data/LICENSE.md +1 -1
  9. data/README.md +2 -3
  10. data/bin/facebook_ads_console +1 -1
  11. data/facebook_ads.gemspec +5 -3
  12. data/lib/facebook_ads.rb +71 -5
  13. data/lib/facebook_ads/ad_account.rb +18 -23
  14. data/lib/facebook_ads/ad_audience.rb +7 -7
  15. data/lib/facebook_ads/ad_campaign.rb +7 -7
  16. data/lib/facebook_ads/ad_creative.rb +2 -2
  17. data/lib/facebook_ads/ad_exception.rb +1 -0
  18. data/lib/facebook_ads/ad_image.rb +2 -2
  19. data/lib/facebook_ads/ad_insight.rb +3 -3
  20. data/lib/facebook_ads/ad_set.rb +1 -1
  21. data/lib/facebook_ads/ad_targeting.rb +2 -4
  22. data/lib/facebook_ads/base.rb +9 -16
  23. data/spec/facebook_ads/ad_account_spec.rb +16 -13
  24. data/spec/facebook_ads/ad_campaign_spec.rb +0 -3
  25. data/spec/facebook_ads/facebook_ads_spec.rb +50 -10
  26. data/spec/fixtures/cassettes/FacebookAds/_stubbornly_get/executes_the_request_for_the_provided_url.yml +63 -0
  27. data/spec/spec_helper.rb +1 -4
  28. data/spec/support/rest_client.rb +1 -1
  29. metadata +15 -32
  30. data/.coveralls.yml +0 -1
  31. data/.travis.yml +0 -7
  32. data/spec/facebook_ads/ad_creative_spec.rb +0 -6
  33. data/spec/facebook_ads/ad_image_spec.rb +0 -6
  34. data/spec/facebook_ads/ad_insight_spec.rb +0 -6
  35. data/spec/facebook_ads/ad_product_catalog_spec.rb +0 -29
  36. data/spec/facebook_ads/ad_product_feed_spec.rb +0 -6
  37. data/spec/facebook_ads/ad_product_set_spec.rb +0 -6
  38. data/spec/facebook_ads/ad_product_spec.rb +0 -23
  39. data/spec/facebook_ads/ad_set_activity_spec.rb +0 -6
  40. data/spec/facebook_ads/ad_set_spec.rb +0 -49
  41. data/spec/facebook_ads/ad_spec.rb +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9790d052561c68d2593248561f54290c95f66fd1b60461f7632c6a5e7434c507
4
- data.tar.gz: 6b800749dd4f0377ec4d27f70a41b0a505b5e7e5d0fac55a8b6c716513a3ba33
3
+ metadata.gz: 5a7277800ac2a81f155ef378e2f5a0b78a85cf00c284ccb18c521b0288d6d467
4
+ data.tar.gz: 603886d3c551084d3b317fa18a0f55a9992113a7a29ae78bd8036490d56bd18c
5
5
  SHA512:
6
- metadata.gz: c723883cb1995a6e1c076cf4ab98792bc847a343ea7ff6e29d723fd29d07d4dbeae5b727acf35d2744c9cd7a4275a10c59b59b2af4b141f3241e037534a8948e
7
- data.tar.gz: a807df65c0693da9c43ca1b9e34b7b6dfc8702364a47828347e73bbbcb01c78a768b7b60f8b96448ac2c9fa73dcbde2f2e929a2f7d7b378afdebbb9f1eabbf65
6
+ metadata.gz: c943be4095453ed6ef0da92ec2c8b1e542c92e0f10d898c958855f593e857c769697a36b0d0a6b168f8fa6ef7c47f616b84418807c0916b5dda447665130751b
7
+ data.tar.gz: 0ccc1ad73365c2791e1a58329265964d18c6af52fb1ffe85d3d95314971f3802ca716a2d6ca5403b7874882922ca2f2fe55c53104d9199f9e91ef1618489ad1c
@@ -0,0 +1,27 @@
1
+ version: 2.1
2
+
3
+ orbs:
4
+ aws-cli: circleci/aws-cli@1.2.1
5
+ ruby: circleci/ruby@1.1.0
6
+
7
+ jobs:
8
+ test:
9
+ docker:
10
+ - image: circleci/ruby:2.7.0-node
11
+ executor: ruby/default
12
+ working_directory: ~/repo
13
+ environment:
14
+ APP_BUNDLER_VERSION: '2.1.2'
15
+ steps:
16
+ - checkout:
17
+ path: ~/repo
18
+ - ruby/install-deps:
19
+ with-cache: false
20
+ - ruby/rspec-test
21
+ - ruby/rubocop-check
22
+
23
+ workflows:
24
+ version: 2
25
+ build:
26
+ jobs:
27
+ - test
@@ -1,5 +1,6 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.3
2
+ TargetRubyVersion: 2.5
3
+ NewCops: enable
3
4
 
4
5
  Metrics/AbcSize:
5
6
  Enabled: false
@@ -7,9 +8,6 @@ Metrics/CyclomaticComplexity:
7
8
  Enabled: false
8
9
  Metrics/PerceivedComplexity:
9
10
  Enabled: false
10
-
11
- Metrics/LineLength:
12
- Enabled: false
13
11
  Metrics/ClassLength:
14
12
  Enabled: false
15
13
  Metrics/MethodLength:
@@ -19,15 +17,18 @@ Metrics/BlockLength:
19
17
  Metrics/ParameterLists:
20
18
  Enabled: false
21
19
 
22
- Lint/EndAlignment:
20
+ Layout/ElseAlignment:
23
21
  Enabled: false
24
-
25
- Layout/IndentationWidth:
22
+ Layout/EndAlignment:
26
23
  Enabled: false
27
- Layout/ElseAlignment:
24
+ Layout/RescueEnsureAlignment:
25
+ Enabled: false
26
+ Layout/EmptyLineAfterGuardClause:
27
+ Enabled: false
28
+ Layout/LineLength:
29
+ Enabled: false
30
+ Layout/IndentationWidth:
28
31
  Enabled: false
29
32
 
30
33
  Style/Documentation:
31
34
  Enabled: false
32
- Style/GuardClause:
33
- Enabled: false
@@ -0,0 +1 @@
1
+ facebook-ruby-ads-sdk
@@ -0,0 +1 @@
1
+ 2.7.0
@@ -1,3 +1,11 @@
1
+ ## 0.7.0 (2020-09-29)
2
+ - Add stubborn network call helpers.
3
+ - Update default version to v7.0.
4
+ - Switch from TravisCI to CircleCI.
5
+ - Remove coveralls.
6
+ - Require ruby 2.5+.
7
+ - Update Rubocop & fix warnings.
8
+
1
9
  ## 0.6.11 (2020-02-28)
2
10
  - Fixed memoization in `FacebookAds::Ad`.
3
11
 
data/Gemfile CHANGED
@@ -7,14 +7,14 @@ group :development, :test do
7
7
  gem 'awesome_print'
8
8
  gem 'pry'
9
9
  gem 'rake'
10
- gem 'rubocop', '0.49.1'
10
+ gem 'rubocop'
11
11
  end
12
12
 
13
13
  group :test do
14
14
  gem 'approvals'
15
- gem 'coveralls', require: false
16
15
  gem 'multi_json'
17
16
  gem 'rspec'
17
+ gem 'rspec_junit_formatter'
18
18
  gem 'vcr'
19
19
  gem 'webmock'
20
20
  end
data/LICENSE.md CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2017 Tophatter, Inc.
3
+ Copyright (c) 2020 Tophatter, Inc.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,6 +1,5 @@
1
1
  [![Gem Version](https://badge.fury.io/rb/facebook_ads.svg)](https://badge.fury.io/rb/facebook_ads)
2
- [![Build Status](https://travis-ci.org/tophatter/facebook-ruby-ads-sdk.svg?branch=master)](https://travis-ci.org/tophatter/facebook-ruby-ads-sdk)
3
- [![Coverage Status](https://coveralls.io/repos/github/tophatter/facebook-ruby-ads-sdk/badge.svg?branch=master)](https://coveralls.io/github/tophatter/facebook-ruby-ads-sdk?branch=master)
2
+ [![Build Status](https://circleci.com/gh/tophatter/facebook-ruby-ads-sdk.svg?style=svg&circle-token=3fa538bc2aece310fdc07b82ce77d117758afb02)](https://circleci.com/gh/tophatter/facebook-ruby-ads-sdk)
4
3
 
5
4
  # [Facebook Marketing API](https://developers.facebook.com/docs/marketing-apis) SDK for Ruby
6
5
 
@@ -17,7 +16,7 @@ gem install facebook_ads
17
16
  Or, add the following to your Gemfile:
18
17
 
19
18
  ```ruby
20
- gem 'facebook_ads', '~> 0.6'
19
+ gem 'facebook_ads', '~> 0.7'
21
20
  ```
22
21
 
23
22
  ## Permissions
@@ -19,7 +19,7 @@ rescue Errno::ENOENT
19
19
  puts 'Create a test_business_id file and add your Business ID to it.'
20
20
  end
21
21
 
22
- FacebookAds.logger = Logger.new(STDOUT)
22
+ FacebookAds.logger = Logger.new($stdout)
23
23
  FacebookAds.logger.level = Logger::Severity::DEBUG
24
24
 
25
25
  require 'awesome_print'
@@ -2,10 +2,10 @@
2
2
 
3
3
  # To publish the next version:
4
4
  # gem build facebook_ads.gemspec
5
- # gem push facebook_ads-0.6.10.gem
5
+ # gem push facebook_ads-0.7.0.gem
6
6
  Gem::Specification.new do |s|
7
7
  s.name = 'facebook_ads'
8
- s.version = '0.6.11'
8
+ s.version = '0.7.0'
9
9
  s.platform = Gem::Platform::RUBY
10
10
  s.licenses = ['MIT']
11
11
  s.authors = ['Chris Estreich']
@@ -16,7 +16,9 @@ Gem::Specification.new do |s|
16
16
 
17
17
  s.extra_rdoc_files = ['README.md']
18
18
 
19
- s.add_dependency 'hashie', '~> 3.4'
19
+ s.required_ruby_version = '>= 2.5'
20
+
21
+ s.add_dependency 'hashie'
20
22
  s.add_dependency 'rest-client', '>= 1.6'
21
23
 
22
24
  s.files = `git ls-files`.split("\n")
@@ -9,10 +9,31 @@ require 'openssl'
9
9
 
10
10
  # Internal requires.
11
11
  require 'facebook_ads/base'
12
- Dir[File.expand_path('../facebook_ads/*.rb', __FILE__)].each { |f| require f }
12
+ require 'facebook_ads/account'
13
+ require 'facebook_ads/ad_account'
14
+ require 'facebook_ads/ad_audience'
15
+ require 'facebook_ads/ad_campaign'
16
+ require 'facebook_ads/ad_creative'
17
+ require 'facebook_ads/ad_exception'
18
+ require 'facebook_ads/ad_image'
19
+ require 'facebook_ads/ad_insight'
20
+ require 'facebook_ads/ad_product_catalog'
21
+ require 'facebook_ads/ad_product_feed'
22
+ require 'facebook_ads/ad_product'
23
+ require 'facebook_ads/ad_set_activity'
24
+ require 'facebook_ads/ad_set'
25
+ require 'facebook_ads/ad_targeting'
26
+ require 'facebook_ads/ad_user'
27
+ require 'facebook_ads/ad'
28
+ require 'facebook_ads/advertisable_application'
13
29
 
14
30
  # The primary namespace for this gem.
15
31
  module FacebookAds
32
+ REQUEST_HEADERS = { accept: :json, accept_encoding: :identity }.freeze
33
+ RETRYABLE_ERRORS = [RestClient::ExceptionWithResponse, Errno::ECONNRESET, Errno::ECONNREFUSED].freeze
34
+ RETRY_LIMIT = 10
35
+ RECOVERABLE_CODES = [1, 2, 2601].freeze
36
+
16
37
  def self.logger=(logger)
17
38
  @logger = logger
18
39
  end
@@ -31,17 +52,16 @@ module FacebookAds
31
52
  end
32
53
 
33
54
  def self.base_uri
34
- @base_uri = "https://graph.facebook.com/v#{api_version}" unless defined?(@base_uri)
35
- @base_uri
55
+ @base_uri ||= "https://graph.facebook.com/v#{api_version}"
36
56
  end
37
57
 
38
58
  def self.api_version=(api_version)
39
59
  @api_version = api_version
60
+ @base_uri = nil
40
61
  end
41
62
 
42
63
  def self.api_version
43
- @api_version = '3.2' unless defined?(@api_version)
44
- @api_version
64
+ @api_version ||= '7.0'
45
65
  end
46
66
 
47
67
  def self.access_token=(access_token)
@@ -71,4 +91,50 @@ module FacebookAds
71
91
  def self.business_id
72
92
  @business_id
73
93
  end
94
+
95
+ # Stubborn network calls.
96
+
97
+ def self.stubbornly(retry_limit: RETRY_LIMIT, recoverable_codes: RECOVERABLE_CODES, debug: false)
98
+ raise ArgumentError unless block_given?
99
+
100
+ response = nil
101
+ retry_count = 0
102
+
103
+ loop do
104
+ response = yield
105
+ break
106
+ rescue *RETRYABLE_ERRORS => e
107
+ if e.is_a?(RestClient::ExceptionWithResponse)
108
+ error = begin
109
+ JSON.parse(e.response)
110
+ rescue JSON::ParserError
111
+ nil
112
+ end
113
+
114
+ code = error&.[]('code')
115
+ raise e if code && !recoverable_codes.include?(code)
116
+ end
117
+
118
+ raise e if retry_count >= retry_limit
119
+
120
+ retry_count += 1
121
+ wait = (retry_count**2) + 15 + (rand(15) * (retry_count + 1))
122
+ puts "retry ##{retry_count} will start in #{wait}s" if debug
123
+ sleep wait
124
+ end
125
+
126
+ response
127
+ end
128
+
129
+ def self.stubbornly_get(url, retry_limit: RETRY_LIMIT, recoverable_codes: RECOVERABLE_CODES, debug: false)
130
+ stubbornly(retry_limit: retry_limit, recoverable_codes: recoverable_codes, debug: debug) do
131
+ RestClient.get(url, REQUEST_HEADERS)
132
+ end
133
+ end
134
+
135
+ def self.stubbornly_post(url, payload, retry_limit: RETRY_LIMIT, recoverable_codes: RECOVERABLE_CODES, debug: false)
136
+ stubbornly(retry_limit: retry_limit, recoverable_codes: recoverable_codes, debug: debug) do
137
+ RestClient.post(url, payload, REQUEST_HEADERS)
138
+ end
139
+ end
74
140
  end
@@ -30,15 +30,15 @@ module FacebookAds
30
30
  end
31
31
 
32
32
  def create_ad_campaign(name:, objective:, status: 'ACTIVE')
33
- raise Exception, "Objective must be one of: #{AdCampaign::OBJECTIVES.join(', ')}" unless AdCampaign::OBJECTIVES.include?(objective)
34
- raise Exception, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
33
+ raise ArgumentError, "Objective must be one of: #{AdCampaign::OBJECTIVES.join(', ')}" unless AdCampaign::OBJECTIVES.include?(objective)
34
+ raise ArgumentError, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
35
35
  query = { name: name, objective: objective, status: status }
36
36
  result = AdCampaign.post("/#{id}/campaigns", query: query)
37
37
  AdCampaign.find(result['id'])
38
38
  end
39
39
 
40
40
  def create_dynamic_ad_campaign(name:, product_catalog_id:, status: 'ACTIVE')
41
- raise Exception, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
41
+ raise ArgumentError, "Status must be one of: #{AdCampaign::STATUSES.join(', ')}" unless AdCampaign::STATUSES.include?(status)
42
42
  query = { name: name, objective: 'PRODUCT_CATALOG_SALES', status: status, promoted_object: { product_catalog_id: product_catalog_id } }
43
43
  result = AdCampaign.post("/#{id}/campaigns", query: query)
44
44
  AdCampaign.find(result['id'])
@@ -73,7 +73,7 @@ module FacebookAds
73
73
  end.to_h
74
74
 
75
75
  response = AdImage.post("/#{id}/adimages", query: files)
76
- files.values.each { |file| File.delete(file.path) }
76
+ files.each_value { |file| File.delete(file.path) }
77
77
  !response['images'].nil? ? ad_images(hashes: response['images'].map { |_key, hash| hash['hash'] }) : []
78
78
  end
79
79
 
@@ -84,8 +84,9 @@ module FacebookAds
84
84
  end
85
85
 
86
86
  def create_ad_creative(creative, creative_type: nil, carousel: false)
87
- # Support old deprecated carousel param
87
+ # Support old deprecated carousel param.
88
88
  return create_carousel_ad_creative(creative) if carousel
89
+
89
90
  case creative_type
90
91
  when 'carousel'
91
92
  create_carousel_ad_creative(creative)
@@ -127,14 +128,11 @@ module FacebookAds
127
128
  end
128
129
 
129
130
  def reach_estimate(targeting:, optimization_goal:, currency: 'USD')
130
- raise Exception, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
131
+ raise ArgumentError, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
131
132
 
132
133
  if targeting.is_a?(AdTargeting)
133
- if targeting.validate!
134
- targeting = targeting.to_hash
135
- else
136
- raise Exception, 'The provided targeting spec is not valid.'
137
- end
134
+ raise ArgumentError, 'The provided targeting spec is not valid.' unless targeting.validate!
135
+ targeting = targeting.to_hash
138
136
  end
139
137
 
140
138
  query = {
@@ -147,14 +145,11 @@ module FacebookAds
147
145
  end
148
146
 
149
147
  def delivery_estimate(targeting:, optimization_goal:, currency: 'USD')
150
- raise Exception, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
148
+ raise ArgumentError, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
151
149
 
152
150
  if targeting.is_a?(AdTargeting)
153
- if targeting.validate!
154
- targeting = targeting.to_hash
155
- else
156
- raise Exception, 'The provided targeting spec is not valid.'
157
- end
151
+ raise ArgumentError, 'The provided targeting spec is not valid.' unless targeting.validate!
152
+ targeting = targeting.to_hash
158
153
  end
159
154
 
160
155
  query = {
@@ -172,12 +167,12 @@ module FacebookAds
172
167
  required = %i[name page_id link message assets call_to_action_type multi_share_optimized multi_share_end_card]
173
168
 
174
169
  unless (keys = required - creative.keys).length.zero?
175
- raise Exception, "Creative is missing the following: #{keys.join(', ')}"
170
+ raise ArgumentError, "Creative is missing the following: #{keys.join(', ')}"
176
171
  end
177
172
 
178
- raise Exception, "Creative call_to_action_type must be one of: #{AdCreative::CALL_TO_ACTION_TYPES.join(', ')}" unless AdCreative::CALL_TO_ACTION_TYPES.include?(creative[:call_to_action_type])
173
+ raise ArgumentError, "Creative call_to_action_type must be one of: #{AdCreative::CALL_TO_ACTION_TYPES.join(', ')}" unless AdCreative::CALL_TO_ACTION_TYPES.include?(creative[:call_to_action_type])
179
174
 
180
- query = if creative[:product_set_id].present?
175
+ query = if creative[:product_set_id]
181
176
  AdCreative.product_set(
182
177
  name: creative[:name],
183
178
  page_id: creative[:page_id],
@@ -199,10 +194,10 @@ module FacebookAds
199
194
  required = %i[name page_id message link link_title image_hash call_to_action_type]
200
195
 
201
196
  unless (keys = required - creative.keys).length.zero?
202
- raise Exception, "Creative is missing the following: #{keys.join(', ')}"
197
+ raise ArgumentError, "Creative is missing the following: #{keys.join(', ')}"
203
198
  end
204
199
 
205
- raise Exception, "Creative call_to_action_type must be one of: #{AdCreative::CALL_TO_ACTION_TYPES.join(', ')}" unless AdCreative::CALL_TO_ACTION_TYPES.include?(creative[:call_to_action_type])
200
+ raise ArgumentError, "Creative call_to_action_type must be one of: #{AdCreative::CALL_TO_ACTION_TYPES.join(', ')}" unless AdCreative::CALL_TO_ACTION_TYPES.include?(creative[:call_to_action_type])
206
201
  query = AdCreative.photo(creative)
207
202
  result = AdCreative.post("/#{id}/adcreatives", query: query)
208
203
  AdCreative.find(result['id'])
@@ -212,7 +207,7 @@ module FacebookAds
212
207
  required = %i[name title body object_url link_url image_hash page_id]
213
208
 
214
209
  unless (keys = required - creative.keys).length.zero?
215
- raise Exception, "Creative is missing the following: #{keys.join(', ')}"
210
+ raise ArgumentError, "Creative is missing the following: #{keys.join(', ')}"
216
211
  end
217
212
 
218
213
  query = AdCreative.link(creative)
@@ -14,13 +14,13 @@ module FacebookAds
14
14
  # actions
15
15
 
16
16
  def share(account_id)
17
- query = {
18
- share_with_object_id: account_id,
19
- share_with_object_type: 'Account'
20
- }
21
- result = AdAccount.post("/#{id}/share_with_objects", query: query)
22
- # result['success']
23
- result # No idea what this response looks like.
17
+ AdAccount.post(
18
+ "/#{id}/share_with_objects",
19
+ query: {
20
+ share_with_object_id: account_id,
21
+ share_with_object_type: 'Account'
22
+ }
23
+ )
24
24
  end
25
25
  end
26
26
  end
@@ -59,10 +59,10 @@ module FacebookAds
59
59
  AdSet.paginate("/#{id}/adsets", query: { effective_status: effective_status, limit: limit })
60
60
  end
61
61
 
62
- def create_ad_set(name:, promoted_object: {}, targeting:, daily_budget: nil, lifetime_budget: nil, end_time: nil, optimization_goal:, billing_event: 'IMPRESSIONS', status: 'ACTIVE', bid_strategy: nil, bid_amount: nil)
63
- raise Exception, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
64
- raise Exception, "Billing event must be one of: #{AdSet::BILLING_EVENTS.join(', ')}" unless AdSet::BILLING_EVENTS.include?(billing_event)
65
- raise Exception, "Bid strategy must be one of: #{AdSet::BID_STRATEGIES.join(', ')}" unless AdSet::BID_STRATEGIES.include?(bid_strategy)
62
+ def create_ad_set(name:, targeting:, optimization_goal:, promoted_object: {}, daily_budget: nil, lifetime_budget: nil, end_time: nil, billing_event: 'IMPRESSIONS', status: 'ACTIVE', bid_strategy: nil, bid_amount: nil)
63
+ raise ArgumentError, "Optimization goal must be one of: #{AdSet::OPTIMIZATION_GOALS.join(', ')}" unless AdSet::OPTIMIZATION_GOALS.include?(optimization_goal)
64
+ raise ArgumentError, "Billing event must be one of: #{AdSet::BILLING_EVENTS.join(', ')}" unless AdSet::BILLING_EVENTS.include?(billing_event)
65
+ raise ArgumentError, "Bid strategy must be one of: #{AdSet::BID_STRATEGIES.join(', ')}" unless AdSet::BID_STRATEGIES.include?(bid_strategy)
66
66
 
67
67
  if targeting.is_a?(Hash)
68
68
  # NOP
@@ -83,9 +83,9 @@ module FacebookAds
83
83
  bid_amount: bid_amount
84
84
  }
85
85
 
86
- if daily_budget && lifetime_budget
87
- raise Exception 'Only one budget may be set between daily_budget and life_budget'
88
- elsif daily_budget
86
+ raise ArgumentError 'Only one budget may be set between daily_budget and life_budget' if daily_budget && lifetime_budget
87
+
88
+ if daily_budget
89
89
  query[:daily_budget] = daily_budget
90
90
  elsif lifetime_budget
91
91
  query[:lifetime_budget] = lifetime_budget
@@ -8,7 +8,7 @@ module FacebookAds
8
8
  CALL_TO_ACTION_TYPES = %w[SHOP_NOW INSTALL_MOBILE_APP USE_MOBILE_APP SIGN_UP DOWNLOAD BUY_NOW NO_BUTTON].freeze
9
9
 
10
10
  class << self
11
- def photo(name:, page_id:, instagram_actor_id: nil, message:, link:, app_link: nil, link_title:, image_hash:, call_to_action_type:, link_description: nil)
11
+ def photo(name:, page_id:, message:, link:, link_title:, image_hash:, call_to_action_type:, instagram_actor_id: nil, app_link: nil, link_description: nil)
12
12
  object_story_spec = {
13
13
  'page_id' => page_id, # 300664329976860
14
14
  'instagram_actor_id' => instagram_actor_id, # 503391023081924
@@ -36,7 +36,7 @@ module FacebookAds
36
36
  end
37
37
 
38
38
  # https://developers.facebook.com/docs/marketing-api/guides/videoads
39
- def carousel(name:, page_id:, instagram_actor_id: nil, link:, app_link: nil, message:, assets:, call_to_action_type:, multi_share_optimized:, multi_share_end_card:)
39
+ def carousel(name:, page_id:, link:, message:, assets:, call_to_action_type:, multi_share_optimized:, multi_share_end_card:, instagram_actor_id: nil, app_link: nil)
40
40
  object_story_spec = {
41
41
  'page_id' => page_id, # 300664329976860
42
42
  'instagram_actor_id' => instagram_actor_id, # 503391023081924
@@ -5,6 +5,7 @@ module FacebookAds
5
5
  attr_reader :code, :title, :message
6
6
 
7
7
  def initialize(code:, title:, message:)
8
+ super(message)
8
9
  @code = code
9
10
  @title = title
10
11
  @message = message
@@ -8,7 +8,7 @@ module FacebookAds
8
8
 
9
9
  class << self
10
10
  def find(_id)
11
- raise Exception, 'NOT IMPLEMENTED'
11
+ raise NotImplementedError
12
12
  end
13
13
  end
14
14
 
@@ -21,7 +21,7 @@ module FacebookAds
21
21
  end
22
22
 
23
23
  def update(_data)
24
- raise Exception, 'NOT IMPLEMENTED'
24
+ raise NotImplementedError
25
25
  end
26
26
 
27
27
  def destroy
@@ -10,16 +10,16 @@ module FacebookAds
10
10
 
11
11
  class << self
12
12
  def find(_id)
13
- raise Exception, 'NOT IMPLEMENTED'
13
+ raise NotImplementedError
14
14
  end
15
15
  end
16
16
 
17
17
  def update(_data)
18
- raise Exception, 'NOT IMPLEMENTED'
18
+ raise NotImplementedError
19
19
  end
20
20
 
21
21
  def destroy
22
- raise Exception, 'NOT IMPLEMENTED'
22
+ raise NotImplementedError
23
23
  end
24
24
  end
25
25
  end
@@ -81,7 +81,7 @@ module FacebookAds
81
81
  # AdCampaign
82
82
 
83
83
  def ad_campaign
84
- @campaign ||= AdCampaign.find(campaign_id)
84
+ @ad_campaign ||= AdCampaign.find(campaign_id)
85
85
  end
86
86
 
87
87
  # Ad
@@ -40,16 +40,14 @@ module FacebookAds
40
40
 
41
41
  def validate!
42
42
  { gender: genders, countries: countries, user_os: user_os, user_device: user_device, custom_locations: custom_locations }.each_pair do |key, array|
43
- if !array.nil? && !array.is_a?(Array)
44
- raise Exception, "#{self.class.name}: #{key} must be an array"
45
- end
43
+ raise ArgumentError, "#{self.class.name}: #{key} must be an array" if !array.nil? && !array.is_a?(Array)
46
44
  end
47
45
 
48
46
  { genders: [genders, GENDERS], user_os: [user_os, OSES], user_device: [user_device, DEVICES] }.each_pair do |key, provided_and_acceptable|
49
47
  provided, acceptable = provided_and_acceptable
50
48
 
51
49
  if !provided.nil? && !(invalid = provided.detect { |value| !acceptable.include?(value) }).nil?
52
- raise Exception, "#{self.class.name}: #{invalid} is an invalid #{key}"
50
+ raise ArgumentError, "#{self.class.name}: #{invalid} is an invalid #{key}"
53
51
  end
54
52
  end
55
53
 
@@ -6,13 +6,13 @@ module FacebookAds
6
6
  class << self
7
7
  # HTTP verbs.
8
8
 
9
- def get(path, query: {}, objectify:)
9
+ def get(path, objectify:, query: {})
10
10
  query = pack(query, objectify: objectify)
11
11
  uri = "#{FacebookAds.base_uri}#{path}?" + build_nested_query(query)
12
12
  FacebookAds.logger.debug "GET #{uri}"
13
13
 
14
14
  response = begin
15
- RestClient.get(uri, accept: :json, accept_encoding: :identity)
15
+ RestClient.get(uri, FacebookAds::REQUEST_HEADERS)
16
16
  rescue RestClient::Exception => e
17
17
  exception(:get, path, e)
18
18
  end
@@ -116,19 +116,12 @@ module FacebookAds
116
116
  end
117
117
 
118
118
  def unpack(response, objectify:)
119
- raise Exception, 'Invalid nil response' if response.nil?
119
+ raise ArgumentError, 'Invalid nil response' if response.nil?
120
120
  response = response.body if response.is_a?(RestClient::Response)
121
+ response = JSON.parse(response) if response.is_a?(String)
121
122
 
122
- if response.is_a?(String)
123
- response = begin
124
- JSON.parse(response)
125
- rescue JSON::ParserError
126
- raise Exception, "Invalid JSON response: #{response.inspect}"
127
- end
128
- end
129
-
130
- raise Exception, "Invalid response: #{response.class.name} #{response.inspect}" unless response.is_a?(Hash)
131
- raise Exception, "[#{response['error']['code']}] #{response['error']['message']} - raw response: #{response.inspect}" unless response['error'].nil?
123
+ raise ArgumentError, "Invalid response: #{response.class.name} #{response.inspect}" unless response.is_a?(Hash)
124
+ raise ArgumentError, "[#{response['error']['code']}] #{response['error']['message']} - raw response: #{response.inspect}" unless response['error'].nil?
132
125
  return response unless objectify
133
126
 
134
127
  if response.key?('data') && (data = response['data']).is_a?(Array)
@@ -138,8 +131,8 @@ module FacebookAds
138
131
  end
139
132
  end
140
133
 
141
- def escape(s)
142
- URI.encode_www_form_component(s)
134
+ def escape(str)
135
+ URI.encode_www_form_component(str)
143
136
  end
144
137
 
145
138
  # https://github.com/rack/rack/blob/master/lib/rack/utils.rb
@@ -190,7 +183,7 @@ module FacebookAds
190
183
  def save
191
184
  return nil if changes.nil? || changes.length.zero?
192
185
  data = {}
193
- changes.keys.each { |key| data[key] = self[key] }
186
+ changes.each_key { |key| data[key] = self[key] }
194
187
  return nil unless update(data)
195
188
  self.class.find(id)
196
189
  end
@@ -70,19 +70,22 @@ describe FacebookAds::AdAccount do
70
70
  describe '.create_ad_creative' do
71
71
  it 'creates carousel ad creative', :vcr do
72
72
  ad_images = account.create_ad_images(%w[https://img0.etsystatic.com/108/1/13006112/il_570xN.1047856494_l2gp.jpg https://img1.etsystatic.com/143/0/13344107/il_570xN.1141249285_xciv.jpg])
73
- carousel_ad_creative = account.create_ad_creative({
74
- name: 'Test Carousel Creative',
75
- page_id: '300664329976860', # Add your Facebook Page ID here.
76
- link: 'http://play.google.com/store/apps/details?id=com.tophatter', # Add your Play Store ID here.
77
- message: 'A message.',
78
- assets: [
79
- { hash: ad_images[0].hash, title: 'Image #1 Title' },
80
- { hash: ad_images[1].hash, title: 'Image #2 Title' }
81
- ],
82
- call_to_action_type: 'SHOP_NOW',
83
- multi_share_optimized: true,
84
- multi_share_end_card: false
85
- }, creative_type: 'carousel')
73
+ carousel_ad_creative = account.create_ad_creative(
74
+ {
75
+ name: 'Test Carousel Creative',
76
+ page_id: '300664329976860', # Add your Facebook Page ID here.
77
+ link: 'http://play.google.com/store/apps/details?id=com.tophatter', # Add your Play Store ID here.
78
+ message: 'A message.',
79
+ assets: [
80
+ { hash: ad_images[0].hash, title: 'Image #1 Title' },
81
+ { hash: ad_images[1].hash, title: 'Image #2 Title' }
82
+ ],
83
+ call_to_action_type: 'SHOP_NOW',
84
+ multi_share_optimized: true,
85
+ multi_share_end_card: false
86
+ },
87
+ creative_type: 'carousel'
88
+ )
86
89
  expect(carousel_ad_creative.id).to eq('120330000008134415')
87
90
  end
88
91
  end
@@ -32,9 +32,6 @@ describe FacebookAds::AdCampaign do
32
32
  targeting
33
33
  end
34
34
 
35
- xdescribe '.ad_sets' do
36
- end
37
-
38
35
  describe '.create_ad_set' do
39
36
  it 'creates_valid_ad_set', :vcr do
40
37
  ad_set = campaign.create_ad_set(
@@ -5,24 +5,64 @@ require 'spec_helper'
5
5
  # rspec spec/facebook_ads/facebook_ads_spec.rb
6
6
  describe FacebookAds do
7
7
  describe '#base_uri' do
8
- it 'is currently v2.9' do
9
- expect(FacebookAds.base_uri.include?('2.9')).to be_truthy
8
+ subject { FacebookAds.base_uri }
9
+
10
+ context 'when the version is not overridden' do
11
+ it { is_expected.to eq('https://graph.facebook.com/v2.9') }
10
12
  end
11
13
 
12
- it 'can be set to v2.10' do
13
- FacebookAds.base_uri = 'https://graph.facebook.com/v2.10'
14
- expect(FacebookAds.base_uri.include?('2.10')).to be_truthy
14
+ context 'when the version is overridden' do
15
+ before { FacebookAds.api_version = '2.10' }
16
+ after { FacebookAds.api_version = '2.9' }
17
+
18
+ it { is_expected.to eq('https://graph.facebook.com/v2.10') }
15
19
  end
16
20
  end
17
21
 
18
22
  describe '#api_version' do
19
- it 'is currently 2.9' do
20
- expect(FacebookAds.api_version).to eq '2.9'
23
+ subject { FacebookAds.api_version }
24
+
25
+ context 'when the version is not overridden' do
26
+ it { is_expected.to eq('2.9') }
27
+ end
28
+
29
+ context 'when the version is overridden' do
30
+ before { FacebookAds.api_version = '2.10' }
31
+ after { FacebookAds.api_version = '2.9' }
32
+
33
+ it { is_expected.to eq('2.10') }
21
34
  end
35
+ end
36
+
37
+ describe '#stubbornly' do
38
+ subject { FacebookAds.stubbornly { true } }
39
+
40
+ it { is_expected.to eq(true) }
41
+ end
42
+
43
+ describe '#stubbornly_get', :vcr do
44
+ subject(:response) { FacebookAds.stubbornly_get('http://worldtimeapi.org/api/ip') }
45
+
46
+ let(:parsed_response) { JSON.parse(response) }
22
47
 
23
- it 'can be set to 2.10' do
24
- FacebookAds.api_version = '2.10'
25
- expect(FacebookAds.api_version).to eq '2.10'
48
+ it 'executes the request for the provided url' do
49
+ expect(parsed_response).to eq(
50
+ 'abbreviation' => 'AKDT',
51
+ 'client_ip' => '66.58.139.118',
52
+ 'datetime' => '2020-09-29T11:59:09.743279-08:00',
53
+ 'day_of_week' => 2,
54
+ 'day_of_year' => 273,
55
+ 'dst' => true,
56
+ 'dst_from' => '2020-03-08T11:00:00+00:00',
57
+ 'dst_offset' => 3600,
58
+ 'dst_until' => '2020-11-01T10:00:00+00:00',
59
+ 'raw_offset' => -32_400,
60
+ 'timezone' => 'America/Anchorage',
61
+ 'unixtime' => 1_601_409_549,
62
+ 'utc_datetime' => '2020-09-29T19:59:09.743279+00:00',
63
+ 'utc_offset' => '-08:00',
64
+ 'week_number' => 40
65
+ )
26
66
  end
27
67
  end
28
68
  end
@@ -0,0 +1,63 @@
1
+ ---
2
+ http_interactions:
3
+ - request:
4
+ method: get
5
+ uri: http://worldtimeapi.org/api/ip
6
+ body:
7
+ encoding: US-ASCII
8
+ string: ''
9
+ headers:
10
+ Accept:
11
+ - application/json
12
+ Accept-Encoding:
13
+ - identity
14
+ User-Agent:
15
+ - Ruby
16
+ Host:
17
+ - worldtimeapi.org
18
+ response:
19
+ status:
20
+ code: 200
21
+ message: OK
22
+ headers:
23
+ Connection:
24
+ - keep-alive
25
+ Access-Control-Allow-Credentials:
26
+ - 'true'
27
+ Access-Control-Allow-Origin:
28
+ - "*"
29
+ Access-Control-Expose-Headers:
30
+ - ''
31
+ Cache-Control:
32
+ - max-age=0, private, must-revalidate
33
+ Content-Length:
34
+ - '401'
35
+ Content-Type:
36
+ - application/json; charset=utf-8
37
+ Cross-Origin-Window-Policy:
38
+ - deny
39
+ Date:
40
+ - Tue, 29 Sep 2020 19:59:09 GMT
41
+ Server:
42
+ - Cowboy
43
+ X-Content-Type-Options:
44
+ - nosniff
45
+ X-Download-Options:
46
+ - noopen
47
+ X-Frame-Options:
48
+ - SAMEORIGIN
49
+ X-Permitted-Cross-Domain-Policies:
50
+ - none
51
+ X-Request-Id:
52
+ - 28a7b795-69b3-423c-b539-08675ebfa8f9
53
+ X-Runtime:
54
+ - 16ms
55
+ X-Xss-Protection:
56
+ - 1; mode=block
57
+ Via:
58
+ - 1.1 vegur
59
+ body:
60
+ encoding: UTF-8
61
+ string: '{"abbreviation":"AKDT","client_ip":"66.58.139.118","datetime":"2020-09-29T11:59:09.743279-08:00","day_of_week":2,"day_of_year":273,"dst":true,"dst_from":"2020-03-08T11:00:00+00:00","dst_offset":3600,"dst_until":"2020-11-01T10:00:00+00:00","raw_offset":-32400,"timezone":"America/Anchorage","unixtime":1601409549,"utc_datetime":"2020-09-29T19:59:09.743279+00:00","utc_offset":"-08:00","week_number":40}'
62
+ recorded_at: Tue, 29 Sep 2020 19:59:09 GMT
63
+ recorded_with: VCR 6.0.0
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'coveralls'
4
- Coveralls.wear!
5
-
6
3
  require 'awesome_print'
7
4
  require 'facebook_ads'
8
5
 
9
- Dir[File.expand_path(File.join(File.dirname(__FILE__), 'support', '**', '*.rb'))].each { |f| require f }
6
+ Dir[File.expand_path('support/*.rb', __dir__)].sort.each { |f| require f }
@@ -5,7 +5,7 @@
5
5
  module RestClient
6
6
  class Request
7
7
  def default_headers
8
- { accept: 'application/json', accept_encoding: 'identity' }
8
+ FacebookAds::REQUEST_HEADERS
9
9
  end
10
10
  end
11
11
  end
metadata CHANGED
@@ -1,29 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: facebook_ads
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.11
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Estreich
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-02-28 00:00:00.000000000 Z
11
+ date: 2020-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hashie
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '3.4'
19
+ version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '3.4'
26
+ version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rest-client
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -47,11 +47,12 @@ extensions: []
47
47
  extra_rdoc_files:
48
48
  - README.md
49
49
  files:
50
- - ".coveralls.yml"
50
+ - ".circleci/config.yml"
51
51
  - ".gitignore"
52
52
  - ".rspec"
53
53
  - ".rubocop.yml"
54
- - ".travis.yml"
54
+ - ".ruby-gemset"
55
+ - ".ruby-version"
55
56
  - CHANGELOG.md
56
57
  - Gemfile
57
58
  - LICENSE.md
@@ -81,16 +82,6 @@ files:
81
82
  - lib/facebook_ads/base.rb
82
83
  - spec/facebook_ads/ad_account_spec.rb
83
84
  - spec/facebook_ads/ad_campaign_spec.rb
84
- - spec/facebook_ads/ad_creative_spec.rb
85
- - spec/facebook_ads/ad_image_spec.rb
86
- - spec/facebook_ads/ad_insight_spec.rb
87
- - spec/facebook_ads/ad_product_catalog_spec.rb
88
- - spec/facebook_ads/ad_product_feed_spec.rb
89
- - spec/facebook_ads/ad_product_set_spec.rb
90
- - spec/facebook_ads/ad_product_spec.rb
91
- - spec/facebook_ads/ad_set_activity_spec.rb
92
- - spec/facebook_ads/ad_set_spec.rb
93
- - spec/facebook_ads/ad_spec.rb
94
85
  - spec/facebook_ads/ad_targeting_spec.rb
95
86
  - spec/facebook_ads/facebook_ads_spec.rb
96
87
  - spec/fixtures/approvals/facebookads_adaccount/ad_campaigns/lists_campaigns.approved.json
@@ -103,6 +94,7 @@ files:
103
94
  - spec/fixtures/approvals/facebookads_adaccount/create_ad_images/creates_an_image.approved.json
104
95
  - spec/fixtures/approvals/facebookads_adaccount/find_by/finds_a_specific_account.approved.json
105
96
  - spec/fixtures/approvals/facebookads_adaccount/reach_estimate/estimates_the_reach_of_a_targeting_spec.approved.json
97
+ - spec/fixtures/cassettes/FacebookAds/_stubbornly_get/executes_the_request_for_the_provided_url.yml
106
98
  - spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_campaigns/lists_campaigns.yml
107
99
  - spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_creatives/lists_creatives.yml
108
100
  - spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_images/lists_images.yml
@@ -125,7 +117,7 @@ homepage: https://github.com/tophatter/facebook-ruby-ads-sdk
125
117
  licenses:
126
118
  - MIT
127
119
  metadata: {}
128
- post_install_message:
120
+ post_install_message:
129
121
  rdoc_options: []
130
122
  require_paths:
131
123
  - lib
@@ -133,7 +125,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
125
  requirements:
134
126
  - - ">="
135
127
  - !ruby/object:Gem::Version
136
- version: '0'
128
+ version: '2.5'
137
129
  required_rubygems_version: !ruby/object:Gem::Requirement
138
130
  requirements:
139
131
  - - ">="
@@ -141,22 +133,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
133
  version: '0'
142
134
  requirements: []
143
135
  rubygems_version: 3.1.2
144
- signing_key:
136
+ signing_key:
145
137
  specification_version: 4
146
138
  summary: Facebook Marketing API SDK for Ruby.
147
139
  test_files:
148
140
  - spec/facebook_ads/ad_account_spec.rb
149
141
  - spec/facebook_ads/ad_campaign_spec.rb
150
- - spec/facebook_ads/ad_creative_spec.rb
151
- - spec/facebook_ads/ad_image_spec.rb
152
- - spec/facebook_ads/ad_insight_spec.rb
153
- - spec/facebook_ads/ad_product_catalog_spec.rb
154
- - spec/facebook_ads/ad_product_feed_spec.rb
155
- - spec/facebook_ads/ad_product_set_spec.rb
156
- - spec/facebook_ads/ad_product_spec.rb
157
- - spec/facebook_ads/ad_set_activity_spec.rb
158
- - spec/facebook_ads/ad_set_spec.rb
159
- - spec/facebook_ads/ad_spec.rb
160
142
  - spec/facebook_ads/ad_targeting_spec.rb
161
143
  - spec/facebook_ads/facebook_ads_spec.rb
162
144
  - spec/fixtures/approvals/facebookads_adaccount/ad_campaigns/lists_campaigns.approved.json
@@ -169,6 +151,7 @@ test_files:
169
151
  - spec/fixtures/approvals/facebookads_adaccount/create_ad_images/creates_an_image.approved.json
170
152
  - spec/fixtures/approvals/facebookads_adaccount/find_by/finds_a_specific_account.approved.json
171
153
  - spec/fixtures/approvals/facebookads_adaccount/reach_estimate/estimates_the_reach_of_a_targeting_spec.approved.json
154
+ - spec/fixtures/cassettes/FacebookAds/_stubbornly_get/executes_the_request_for_the_provided_url.yml
172
155
  - spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_campaigns/lists_campaigns.yml
173
156
  - spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_creatives/lists_creatives.yml
174
157
  - spec/fixtures/cassettes/FacebookAds_AdAccount/_ad_images/lists_images.yml
@@ -1 +0,0 @@
1
- service_name: travis-ci
@@ -1,7 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - 2.3
4
- script:
5
- - bundle exec rubocop
6
- - bundle exec rake
7
- cache: bundler
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::AdCreative do
6
- end
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::AdImage do
6
- end
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::AdInsight do
6
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::AdProductCatalog do
6
- # def test_all
7
- # vcr do
8
- # catalog = FacebookAds::AdProductCatalog.all.first
9
- # assert_equal '197871307315718', catalog.id
10
- # assert_equal 'Test', catalog.name
11
- # assert_equal 'commerce', catalog.vertical
12
- # assert_equal 1, catalog.product_count
13
- # assert_equal 1, catalog.feed_count
14
- # end
15
- # end
16
- #
17
- # def test_create
18
- # vcr do
19
- # catalog = FacebookAds::AdProductCatalog.create(name: 'Foo Bar')
20
- # assert_equal 'Foo Bar', catalog.name
21
- # assert_equal 'commerce', catalog.vertical
22
- # assert_equal 0, catalog.product_count
23
- # assert_equal 0, catalog.feed_count
24
- # catalog = FacebookAds::AdProductCatalog.find(catalog.id)
25
- # assert_equal true, catalog.destroy
26
- # assert_nil FacebookAds::AdProductCatalog.find_by(name: 'Foo Bar')
27
- # end
28
- # end
29
- end
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::AdProductFeed do
6
- end
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::AdProductSet do
6
- end
@@ -1,23 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::AdProduct do
6
- # def test_list
7
- # vcr do
8
- # catalog = FacebookAds::AdProductCatalog.find_by(name: 'Test')
9
- # products = catalog.ad_products
10
- # product = products.first
11
- # assert_equal '1489112071104048', product.id
12
- # assert_equal 'retro-ruby-earrings', product.retailer_id
13
- # assert_equal 'Precious Retro .925 Sterling Silver Artificial Ruby Earrings', product.name
14
- # assert_equal '$5 shipping - at your doorstep within 25-27 business days.', product.description
15
- # assert_equal 'Adoration-Precious', product.brand
16
- # assert_equal 'Jewelry | Earrings', product.category
17
- # assert_equal 'USD', product.currency
18
- # assert_equal '$156.00', product.price
19
- # assert_equal 'https://external.xx.fbcdn.net/safe_image.php?d=AQALnOfu1mhkpb4T&url=https%3A%2F%2Fd38eepresuu519.cloudfront.net%2F12c85243d743ac3cb21b71c34192b252%2Flarge.jpg&cfs=1&_nc_hash=AQBlxlDCq59tO6sE', product.image_url
20
- # assert_equal 'https://tophatter.com/lots/23275728', product.url
21
- # end
22
- # end
23
- end
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::AdSetActivity do
6
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::AdSet do
6
- # def test_create
7
- # vcr do
8
- # ad_campaign = FacebookAds::AdCampaign.find('6069436026057')
9
- # ad_set = ad_campaign.create_ad_set(
10
- # name: 'Test',
11
- # promoted_object: {
12
- # pixel_id: '1472889202927380',
13
- # custom_event_type: 'PURCHASE'
14
- # },
15
- # targeting: {
16
- # age_max: 65,
17
- # age_min: 18,
18
- # app_install_state: 'not_installed',
19
- # excluded_custom_audiences: [{ "name"=>"All-Users-2016-07-28", "id"=>"6068994792257" }],
20
- # genders: [2],
21
- # geo_locations: { countries: %w(US), location_types: %w(home recent) },
22
- # locales: [24, 6],
23
- # publisher_platforms: %w(facebook instagram audience_network),
24
- # device_platforms: %w(desktop),
25
- # facebook_positions: %w(feed right_hand_column)
26
- # },
27
- # daily_budget: 1000,
28
- # optimization_goal: 'OFFSITE_CONVERSIONS'
29
- # )
30
- # assert_equal '6081945233457', ad_set.id
31
- # assert_equal '1000', ad_set.daily_budget
32
- # assert_equal 'OFFSITE_CONVERSIONS', ad_set.optimization_goal
33
- # end
34
- # end
35
- #
36
- # def test_update
37
- # vcr do
38
- # ad_set = FacebookAds::AdSet.find('6078462927057')
39
- # assert ad_set.update(daily_budget: 149900)
40
- # end
41
- # end
42
- #
43
- # def test_destroy
44
- # vcr do
45
- # ad_set = FacebookAds::AdSet.find('6081945233457')
46
- # assert ad_set.destroy
47
- # end
48
- # end
49
- end
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe FacebookAds::Ad do
6
- end