twitter-ads 7.0.1 → 10.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/twitter-ads/account.rb +21 -5
  4. data/lib/twitter-ads/audiences/{tailored_audience.rb → custom_audience.rb} +85 -30
  5. data/lib/twitter-ads/campaign/campaign.rb +1 -0
  6. data/lib/twitter-ads/campaign/line_item.rb +7 -7
  7. data/lib/twitter-ads/campaign/targeting_criteria.rb +1 -0
  8. data/lib/twitter-ads/campaign/tracking_tags.rb +97 -0
  9. data/lib/twitter-ads/client.rb +1 -1
  10. data/lib/twitter-ads/creative/cards.rb +56 -0
  11. data/lib/twitter-ads/creative/cards_fetch.rb +2 -4
  12. data/lib/twitter-ads/creative/image_app_download_card.rb +2 -4
  13. data/lib/twitter-ads/creative/promoted_tweet.rb +1 -1
  14. data/lib/twitter-ads/creative/video_app_download_card.rb +2 -4
  15. data/lib/twitter-ads/cursor.rb +2 -2
  16. data/lib/twitter-ads/enum.rb +21 -30
  17. data/lib/twitter-ads/resources/analytics.rb +2 -1
  18. data/lib/twitter-ads/targeting/{audience_summary.rb → audience_estimate.rb} +3 -3
  19. data/lib/twitter-ads/targeting_criteria/event.rb +1 -0
  20. data/lib/twitter-ads/version.rb +1 -1
  21. data/lib/twitter-ads.rb +4 -2
  22. data/spec/fixtures/accounts_all.json +0 -5
  23. data/spec/fixtures/accounts_load.json +0 -1
  24. data/spec/fixtures/{audience_summary.json → audience_estimate.json} +0 -0
  25. data/spec/fixtures/custom_audiences_all.json +67 -0
  26. data/spec/fixtures/{tailored_audiences_load.json → custom_audiences_load.json} +0 -0
  27. data/spec/fixtures/line_items_all.json +0 -10
  28. data/spec/fixtures/line_items_load.json +0 -1
  29. data/spec/fixtures/tailored_audiences_all.json +3 -0
  30. data/spec/fixtures/targeted_audiences.json +33 -0
  31. data/spec/fixtures/tracking_tags_load.json +17 -0
  32. data/spec/twitter-ads/account_spec.rb +11 -11
  33. data/spec/twitter-ads/audiences/{tailored_audience_spec.rb → custom_audience_spec.rb} +3 -2
  34. data/spec/twitter-ads/campaign/line_item_spec.rb +6 -3
  35. data/spec/twitter-ads/campaign/targeting_criteria_spec.rb +1 -0
  36. data/spec/twitter-ads/campaign/tracking_tag_spec.rb +58 -0
  37. data/spec/twitter-ads/creative/promoted_tweet_spec.rb +18 -0
  38. data/spec/twitter-ads/targeting/{audience_summary_spec.rb → audience_estimate_spec.rb} +2 -2
  39. metadata +50 -40
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b42045b5ca461ee6f6a13ed129264351506089d23622ad2429a1a154e0b2b03f
4
- data.tar.gz: 431d8797b1d1aa606c10672780708112053710b0e745e46e13bd602097c48ca9
3
+ metadata.gz: 41647d8c40a25ad6514610875548e84017bc742bad6dff6c3838a708dce86f1a
4
+ data.tar.gz: 798fd38acef31c22a0032fa9e2ff9188c5061ec3cc04834c8503b33c8a4e2ab2
5
5
  SHA512:
6
- metadata.gz: fb703d3ef21d673d313c7223474e5dabbdb0d64233b88550a1135773118273a71272a38b791c927139773de1b62e639f06075fd9a25a94668e9a7cefd9bd0f82
7
- data.tar.gz: bcef25e9c1a7a4d3ac331bbf901dbaefbe00121a7f0ca6e66c484f0b93585d5d8e85d7d8e46d3bfe771cc5daa584735626300a3b56743e529e4de5031aff3a36
6
+ metadata.gz: 1d4fffa9b3eaa288a6ef9d173fb7f6fcbb1cfd2e5286c0167be9b01f4e751179fb83d4efff294f193837c44f84a2b52a696cfa826b3e7a7ff2635696242e931b
7
+ data.tar.gz: 46f6c010335bbf314877e71decef4692fada6a9317436a38fa8bf31ad334a2742ddec724e61074ebefa23420490b2243d522360b7dce76907cd03f3d289a5a8a
data/README.md CHANGED
@@ -52,7 +52,7 @@ This project is designed to work with Ruby 2.4.0 or greater. While it may work o
52
52
 
53
53
  Platform | Versions
54
54
  -------- | --------
55
- MRI | 2.4.x, 2.5.x, 2.6.x
55
+ MRI | 2.4.x, 2.5.x, 2.6.x, 2.7, 3.0
56
56
  Rubinius | 2.4.x, 2.5.x
57
57
 
58
58
  All releases adhere to strict [semantic versioning](http://semver.org). For Example, major.minor.patch-pre (aka. stick.carrot.oops-peek).
@@ -89,7 +89,7 @@ Like the [Response](https://github.com/twitterdev/twitter-ruby-ads-sdk/blob/mast
89
89
 
90
90
  The MIT License (MIT)
91
91
 
92
- Copyright (C) 2019 Twitter, Inc.
92
+ Copyright (C) 2021 Twitter, Inc.
93
93
 
94
94
  Permission is hereby granted, free of charge, to any person obtaining a copy
95
95
  of this software and associated documentation files (the "Software"), to deal
@@ -10,7 +10,6 @@ module TwitterAds
10
10
 
11
11
  property :id, read_only: true
12
12
  property :name, read_only: true
13
- property :salt, read_only: true
14
13
  property :timezone, read_only: true
15
14
  property :timezone_switch_at, type: :time, read_only: true
16
15
  property :created_at, type: :time, read_only: true
@@ -218,6 +217,23 @@ module TwitterAds
218
217
  load_resource(LineItem, id, opts)
219
218
  end
220
219
 
220
+ # Returns a collection of tracking tags available to the
221
+ # current account.
222
+ #
223
+ # @param id [String] The LineItem ID value.
224
+ # @param opts [Hash] A Hash of extended options.
225
+ # @option opts [Boolean] :with_deleted Indicates if deleted items should be included.
226
+ # @option opts [String] :sort_by The object param to sort the API response by.
227
+ # @option opts [String] :line_item_ids The object param to sort the API response by.
228
+ # @option opts [String] :tracking_tag_ids The object param to sort the API response by.
229
+ #
230
+ # @return A Cursor or object instance.
231
+ #
232
+ # @since 10.0.0
233
+ def tracking_tags(id = nil, opts = {})
234
+ load_resource(TrackingTag, id, opts)
235
+ end
236
+
221
237
  # Returns a collection of app lists available to the current account.
222
238
  #
223
239
  # @param id [String] The AppList ID value.
@@ -232,9 +248,9 @@ module TwitterAds
232
248
  load_resource(AppList, id, opts)
233
249
  end
234
250
 
235
- # Returns a collection of tailored audiences available to the current account.
251
+ # Returns a collection of custom audiences available to the current account.
236
252
  #
237
- # @param id [String] The TailoredAudience ID value.
253
+ # @param id [String] The CustomAudience ID value.
238
254
  # @param opts [Hash] A Hash of extended options.
239
255
  # @option opts [Boolean] :with_deleted Indicates if deleted items should be included.
240
256
  # @option opts [String] :sort_by The object param to sort the API response by.
@@ -242,8 +258,8 @@ module TwitterAds
242
258
  # @since 0.3.0
243
259
  #
244
260
  # @return A Cursor or object instance.
245
- def tailored_audiences(id = nil, opts = {})
246
- load_resource(TailoredAudience, id, opts)
261
+ def custom_audiences(id = nil, opts = {})
262
+ load_resource(CustomAudience, id, opts)
247
263
  end
248
264
 
249
265
  def authenticated_user_access
@@ -2,7 +2,7 @@
2
2
  # Copyright (C) 2019 Twitter, Inc.
3
3
 
4
4
  module TwitterAds
5
- class TailoredAudience
5
+ class CustomAudience
6
6
 
7
7
  include TwitterAds::DSL
8
8
  include TwitterAds::Resource
@@ -19,18 +19,19 @@ module TwitterAds
19
19
 
20
20
  property :audience_size, read_only: true
21
21
  property :audience_type, read_only: true
22
- property :metadata, read_only: true
23
22
  property :partner_source, read_only: true
24
23
  property :reasons_not_targetable, read_only: true
25
24
  property :targetable, type: :bool, read_only: true
26
25
  property :targetable_types, read_only: true
26
+ property :permission_level, read_only: true
27
+ property :owner_account_id, read_only: true
27
28
 
28
29
  RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
29
- 'accounts/%{account_id}/tailored_audiences' # @api private
30
+ 'accounts/%{account_id}/custom_audiences' # @api private
30
31
  RESOURCE = "/#{TwitterAds::API_VERSION}/" \
31
- 'accounts/%{account_id}/tailored_audiences/%{id}' # @api private
32
+ 'accounts/%{account_id}/custom_audiences/%{id}' # @api private
32
33
  RESOURCE_USERS = "/#{TwitterAds::API_VERSION}/" \
33
- 'accounts/%{account_id}/tailored_audiences/' \
34
+ 'accounts/%{account_id}/custom_audiences/' \
34
35
  '%{id}/users' # @api private
35
36
 
36
37
  LIST_TYPES = %w(
@@ -54,17 +55,17 @@ module TwitterAds
54
55
 
55
56
  class << self
56
57
 
57
- # Creates a new tailored audience.
58
+ # Creates a new custom audience.
58
59
  #
59
60
  # @example
60
- # audience = TailoredAudience.create(account, 'my list')
61
+ # audience = CustomAudience.create(account, 'my list')
61
62
  #
62
63
  # @param account [Account] The account object instance.
63
- # @param name [String] The tailored audience name.
64
+ # @param name [String] The custom audience name.
64
65
  #
65
66
  # @since 4.0
66
67
  #
67
- # @return [TailoredAudience] The newly created tailored audience instance.
68
+ # @return [CustomAudience] The newly created custom audience instance.
68
69
  def create(account, name)
69
70
  audience = new(account)
70
71
  params = { name: name }
@@ -75,7 +76,7 @@ module TwitterAds
75
76
 
76
77
  end
77
78
 
78
- # Deletes the current tailored audience instance.
79
+ # Deletes the current custom audience instance.
79
80
  #
80
81
  # @example
81
82
  # audience.delete!
@@ -84,21 +85,21 @@ module TwitterAds
84
85
  #
85
86
  # @since 0.3.0
86
87
  #
87
- # @return [self] Returns the tailored audience instance refreshed from the API.
88
+ # @return [self] Returns the custom audience instance refreshed from the API.
88
89
  def delete!
89
90
  resource = RESOURCE % { account_id: account.id, id: id }
90
91
  response = Request.new(account.client, :delete, resource).perform
91
92
  from_response(response.body[:data])
92
93
  end
93
94
 
94
- # This is a private API and requires whitelisting from Twitter.
95
+ # This is a private API and requires allowlisting from Twitter.
95
96
  #
96
97
  # This endpoint will allow partners to add, update and remove users from a given
97
- # tailored_audience_id.
98
+ # custom_audience_id.
98
99
  # The endpoint will also accept multiple user identifier types per user as well.
99
100
  #
100
101
  # @example
101
- # tailored_audience.users(
102
+ # custom_audience.users(
102
103
  # account,
103
104
  # [
104
105
  # {
@@ -137,9 +138,63 @@ module TwitterAds
137
138
  [success_count, total_count]
138
139
  end
139
140
 
141
+ # Retrieves the entites targeting the current tailored audience instance.
142
+ #
143
+ # @example
144
+ # audience.targeted(with_active=true)
145
+ #
146
+ # @param with_active [bool] Include active/inactive
147
+ #
148
+ # @since 8.0.0
149
+ #
150
+ # @return [self] Returns a Cursor instance of the targeted entities.
151
+ def targeted(opts = {})
152
+ validate_loaded
153
+ params = {}.merge!(opts)
154
+ TargetedTailoredAudience.load(account, id, params)
155
+ end
156
+
157
+ def validate_loaded
158
+ raise ArgumentError.new(
159
+ "Error! #{self.class} object not yet initialized, " \
160
+ "call #{self.class}.load first") if id.nil?
161
+ end
162
+ end
163
+
164
+ class TargetedTailoredAudience
165
+
166
+ include TwitterAds::DSL
167
+ include TwitterAds::Resource
168
+
169
+ attr_reader :account
170
+
171
+ # read-only
172
+ property :campaign_id, read_only: true
173
+ property :campaign_name, read_only: true
174
+ property :line_items, read_only: true
175
+
176
+ RESOURCE_TARGETED = "/#{TwitterAds::API_VERSION}/" \
177
+ 'accounts/%{account_id}/tailored_audiences/%{id}/targeted' # @api private
178
+
179
+ def initialize(account)
180
+ @account = account
181
+ self
182
+ end
183
+
184
+ class << self
185
+
186
+ def load(account, tailored_audience_id, params)
187
+ resource = RESOURCE_TARGETED % { account_id: account.id, id: tailored_audience_id }
188
+ request = TwitterAds::Request.new(account.client,
189
+ :get,
190
+ resource,
191
+ params: params)
192
+ Cursor.new(self, request, init_with: [account])
193
+ end
194
+ end
140
195
  end
141
196
 
142
- class TailoredAudiencePermission
197
+ class CustomAudiencePermission
143
198
 
144
199
  include TwitterAds::DSL
145
200
  include TwitterAds::Resource
@@ -152,16 +207,16 @@ module TwitterAds
152
207
  property :deleted, type: :bool, read_only: true
153
208
 
154
209
  property :id
155
- property :tailored_audience_id
210
+ property :custom_audience_id
156
211
  property :granted_account_id
157
212
  property :permission_level
158
213
 
159
214
  RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
160
- 'accounts/%{account_id}/tailored_audiences/' \
161
- '%{tailored_audience_id}/permissions' # @api private
215
+ 'accounts/%{account_id}/custom_audiences/' \
216
+ '%{custom_audience_id}/permissions' # @api private
162
217
  RESOURCE = "/#{TwitterAds::API_VERSION}/" \
163
- 'accounts/%{account_id}/tailored_audiences/' \
164
- '%{tailored_audience_id}/permissions/%{id}' # @api private
218
+ 'accounts/%{account_id}/custom_audiences/' \
219
+ '%{custom_audience_id}/permissions/%{id}' # @api private
165
220
 
166
221
  def initialize(account)
167
222
  @account = account
@@ -171,22 +226,22 @@ module TwitterAds
171
226
  class << self
172
227
 
173
228
  # Retrieve details for some or
174
- # all permissions associated with the specified tailored audience.
229
+ # all permissions associated with the specified custom audience.
175
230
  #
176
231
  # @exapmle
177
- # permissions = TailoredAudiencePermission.all(account, '36n4f')
232
+ # permissions = CustomAudiencePermission.all(account, '36n4f')
178
233
  #
179
234
  # @param account [Account] The account object instance.
180
- # @param tailored_audience_id [String] The tailored audience id.
235
+ # @param custom_audience_id [String] The custom audience id.
181
236
  #
182
237
  # @since 5.2.0
183
238
  #
184
- # @return [TailoredAudiencePermission] The tailored audience permission instance.
185
- def all(account, tailored_audience_id, opts = {})
239
+ # @return [CustomAudiencePermission] The custom audience permission instance.
240
+ def all(account, custom_audience_id, opts = {})
186
241
  params = {}.merge!(opts)
187
242
  resource = RESOURCE_COLLECTION % {
188
243
  account_id: account.id,
189
- tailored_audience_id: tailored_audience_id
244
+ custom_audience_id: custom_audience_id
190
245
  }
191
246
  request = Request.new(account.client, :get, resource, params: params)
192
247
  Cursor.new(self, request, init_with: [account])
@@ -195,7 +250,7 @@ module TwitterAds
195
250
  end
196
251
 
197
252
  # Saves or updates the current object instance
198
- # depending on the presence of `object.tailored_audience_id`.
253
+ # depending on the presence of `object.custom_audience_id`.
199
254
  #
200
255
  # @exapmle
201
256
  # object.save
@@ -206,14 +261,14 @@ module TwitterAds
206
261
  def save
207
262
  resource = RESOURCE_COLLECTION % {
208
263
  account_id: account.id,
209
- tailored_audience_id: tailored_audience_id
264
+ custom_audience_id: custom_audience_id
210
265
  }
211
266
  params = to_params
212
267
  response = Request.new(account.client, :post, resource, params: params).perform
213
268
  from_response(response.body[:data])
214
269
  end
215
270
 
216
- # Deletes the current or specified tailored audience permission.
271
+ # Deletes the current or specified custom audience permission.
217
272
  #
218
273
  # @example
219
274
  # object.delete!
@@ -226,7 +281,7 @@ module TwitterAds
226
281
  def delete!
227
282
  resource = RESOURCE % {
228
283
  account_id: account.id,
229
- tailored_audience_id: tailored_audience_id,
284
+ custom_audience_id: custom_audience_id,
230
285
  id: @id
231
286
  }
232
287
  response = Request.new(account.client, :delete, resource).perform
@@ -23,6 +23,7 @@ module TwitterAds
23
23
  property :end_time, type: :time
24
24
  property :start_time, type: :time
25
25
  property :entity_status
26
+ property :effective_status
26
27
  property :currency
27
28
  property :standard_delivery
28
29
  property :daily_budget_amount_local_micro
@@ -18,18 +18,18 @@ module TwitterAds
18
18
 
19
19
  property :advertiser_domain
20
20
  property :android_app_store_identifier
21
- property :automatically_select_bid
21
+ property :audience_expansion
22
22
  property :bid_amount_local_micro
23
- property :bid_unit
23
+ property :bid_strategy
24
24
  property :campaign_id
25
25
  property :categories
26
- property :charge_by
27
26
  property :end_time, type: :time
28
27
  property :entity_status
28
+ property :goal
29
29
  property :ios_app_store_identifier
30
30
  property :name
31
31
  property :objective
32
- property :optimization
32
+ property :pay_by
33
33
  property :placements
34
34
  property :primary_web_event_tag
35
35
  property :product_type
@@ -38,9 +38,6 @@ module TwitterAds
38
38
 
39
39
  # beta (not yet generally available)
40
40
  property :advertiser_user_id
41
- property :bid_type
42
- property :tracking_tags
43
- property :audience_expansion
44
41
 
45
42
  # sdk only
46
43
  property :to_delete, type: :bool
@@ -95,5 +92,8 @@ module TwitterAds
95
92
  id ? TargetingCriteria.load(account, id, opts) : TargetingCriteria.all(account, @id, opts)
96
93
  end
97
94
 
95
+ def tracking_tags(id = nil, opts = {})
96
+ id ? TrackingTag.load(account, id, opts) : TrackingTag.all(account, @id, opts)
97
+ end
98
98
  end
99
99
  end
@@ -21,6 +21,7 @@ module TwitterAds
21
21
  property :line_item_id
22
22
  property :targeting_type
23
23
  property :targeting_value
24
+ property :operator_type
24
25
  property :tailored_audience_expansion, type: :bool
25
26
  property :location_type
26
27
 
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2019 Twitter, Inc.
3
+
4
+ module TwitterAds
5
+ class TrackingTag
6
+
7
+ include TwitterAds::DSL
8
+ include TwitterAds::Resource
9
+ include TwitterAds::Persistence
10
+
11
+ attr_reader :account
12
+
13
+ property :id, read_only: true
14
+ property :deleted, type: :bool, read_only: true
15
+ property :created_at, type: :time, read_only: true
16
+ property :updated_at, type: :time, read_only: true
17
+
18
+ property :line_item_id
19
+ property :tracking_tag_type
20
+ property :tracking_tag_url
21
+
22
+ # sdk only
23
+ property :to_delete, type: :bool
24
+
25
+ RESOURCE_COLLECTION = "/#{TwitterAds::API_VERSION}/" \
26
+ 'accounts/%{account_id}/tracking_tags' # @api private
27
+ RESOURCE = "/#{TwitterAds::API_VERSION}/" \
28
+ 'accounts/%{account_id}/tracking_tags/%{id}' # @api private
29
+
30
+ def initialize(account)
31
+ @account = account
32
+ self
33
+ end
34
+
35
+ # Creates a new Tracking Tag
36
+ #
37
+ # @param line_item_id [String] The line item id to create tags for.
38
+ # @param tracking_tag_url [String] tracking tag URL.
39
+ #
40
+ # @return [self] Returns the instance refreshed from the API
41
+ def create(line_item_id, tracking_tag_url)
42
+ resource = self.class::RESOURCE_COLLECTION % { account_id: account.id }
43
+ params = to_params.merge!(
44
+ line_item_id: line_item_id,
45
+ tracking_tag_url: tracking_tag_url,
46
+ tracking_tag_type: 'IMPRESSION_TAG'
47
+ )
48
+ response = Request.new(account.client, :post, resource, params: params).perform
49
+ from_response(response.body[:data])
50
+ end
51
+
52
+ class << self
53
+
54
+ # Returns a Cursor instance for a given resource.
55
+ #
56
+ # @param account [Account] The Account object instance.
57
+ # @param line_item_ids [String] A String or String array of Line Item IDs.
58
+ # @param opts [Hash] An optional Hash of extended options.
59
+ # @option opts [Boolean] :with_deleted Indicates if deleted items should be included.
60
+ # @option opts [String] :sort_by The object param to sort the API response by.
61
+ #
62
+ # @return [Cursor] A Cusor object ready to iterate through the API response.
63
+ #
64
+ # @since 0.3.1
65
+ # @see Cursor
66
+ # @see https://dev.twitter.com/ads/basics/sorting Sorting
67
+ def all(account, line_item_ids, opts = {})
68
+ if !line_item_ids.empty?
69
+ params = { line_item_ids: Array(line_item_ids).join(',') }.merge!(opts)
70
+ end
71
+ resource = RESOURCE_COLLECTION % { account_id: account.id }
72
+ request = Request.new(account.client, :get, resource, params: params)
73
+ Cursor.new(self, request, init_with: [account])
74
+ end
75
+
76
+ # Returns an object instance for a given resource.
77
+ #
78
+ # @param account [Account] The Account object instance.
79
+ # @param id [String] The ID of the specific object to be loaded.
80
+ # @param opts [Hash] An optional Hash of extended options.
81
+ # @option opts [Boolean] :with_deleted Indicates if deleted items should be included.
82
+ # @option opts [String] :sort_by The object param to sort the API response by.
83
+ #
84
+ # @return [self] The object instance for the specified resource.
85
+ #
86
+ # @since 0.3.1
87
+ def load(account, id, opts = {})
88
+ params = { with_deleted: true }.merge!(opts)
89
+ resource = RESOURCE % { account_id: account.id, id: id }
90
+ response = Request.new(account.client, :get, resource, params: params).perform
91
+ new(account).from_response(response.body[:data])
92
+ end
93
+
94
+ end
95
+
96
+ end
97
+ end
@@ -3,7 +3,7 @@
3
3
 
4
4
  module TwitterAds
5
5
 
6
- API_VERSION = '7'
6
+ API_VERSION = '10'
7
7
 
8
8
  # The Ads API Client class which functions as a
9
9
  # container for basic API consumer information.
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2019 Twitter, Inc.
3
+
4
+ module TwitterAds
5
+ module Creative
6
+
7
+ class Cards
8
+
9
+ include TwitterAds::DSL
10
+ include TwitterAds::Resource
11
+ include TwitterAds::Persistence
12
+
13
+ attr_reader :account
14
+
15
+ property :card_uri, read_only: true
16
+ property :created_at, type: :time, read_only: true
17
+ property :deleted, type: :bool, read_only: true
18
+ property :updated_at, type: :time, read_only: true
19
+ # these are writable, but not in the sense that they can be set on an object and then saved
20
+ property :name, read_only: true
21
+ property :components, read_only: true
22
+
23
+ RESOURCE = "/#{TwitterAds::API_VERSION}/" +
24
+ 'accounts/%{account_id}/cards' # @api private
25
+
26
+ def load(*)
27
+ raise ArgumentError.new(
28
+ "'Cards' object has no attribute 'load'")
29
+ end
30
+
31
+ def reload(*)
32
+ raise ArgumentError.new(
33
+ "'Cards' object has no attribute 'reload'")
34
+ end
35
+
36
+ def create(account, name, components)
37
+ resource = RESOURCE % { account_id: account.id }
38
+ params = { 'name': name, 'components': components }
39
+ headers = { 'Content-Type' => 'application/json' }
40
+ response = Request.new(account.client,
41
+ :post,
42
+ resource,
43
+ headers: headers,
44
+ body: params.to_json).perform
45
+ from_response(response.body[:data])
46
+ end
47
+
48
+ def initialize(account)
49
+ @account = account
50
+ self
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+ end
@@ -35,10 +35,8 @@ module TwitterAds
35
35
  property :image, read_only: true
36
36
  property :image_display_height, read_only: true
37
37
  property :image_display_width, read_only: true
38
- property :ipad_app_id, read_only: true
39
- property :ipad_deep_link, read_only: true
40
- property :iphone_app_id, read_only: true
41
- property :iphone_deep_link, read_only: true
38
+ property :ios_app_store_identifier, read_only: true
39
+ property :ios_deep_link, read_only: true
42
40
  property :name, read_only: true
43
41
  property :recipient_user_id, read_only: true
44
42
  property :second_choice, read_only: true
@@ -26,10 +26,8 @@ module TwitterAds
26
26
  property :app_cta
27
27
  property :googleplay_app_id
28
28
  property :googleplay_deep_link
29
- property :iphone_app_id
30
- property :iphone_deep_link
31
- property :ipad_app_id
32
- property :ipad_deep_link
29
+ property :ios_app_store_identifier
30
+ property :ios_deep_link
33
31
  property :name
34
32
  property :media_key
35
33
 
@@ -48,7 +48,7 @@ module TwitterAds
48
48
 
49
49
  # convert to `tweet_ids` param
50
50
  params = to_params
51
- params[:tweet_ids] = *params.delete(:tweet_id) if params.key?(:tweet_id)
51
+ params[:tweet_ids] = params.delete(:tweet_id) if params.key?(:tweet_id)
52
52
 
53
53
  if @id
54
54
  raise TwitterAds::NotFound.new(nil, 'Method PUT not allowed.', 404)
@@ -25,10 +25,8 @@ module TwitterAds
25
25
  property :country_code
26
26
  property :app_cta
27
27
  property :poster_media_key
28
- property :ipad_app_id
29
- property :ipad_deep_link
30
- property :iphone_app_id
31
- property :iphone_deep_link
28
+ property :ios_app_store_identifier
29
+ property :ios_deep_link
32
30
  property :googleplay_app_id
33
31
  property :googleplay_deep_link
34
32
  property :name
@@ -56,13 +56,13 @@ module TwitterAds
56
56
  # @return [Cursor] The current Cursor instance.
57
57
  #
58
58
  # @since 0.1.0
59
- def each(offset = 0)
59
+ def each(offset = 0, &block)
60
60
  return to_enum(:each, offset) unless block_given?
61
61
  @collection[offset..-1].each { |element| yield(element) }
62
62
  unless exhausted?
63
63
  offset = [@collection.size, offset].max
64
64
  fetch_next
65
- each(offset, &Proc.new)
65
+ each(offset, &block)
66
66
  end
67
67
  self
68
68
  end