twitter-ads 0.3.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 (94) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -0
  4. data/CONTRIBUTING.md +77 -0
  5. data/LICENSE +22 -0
  6. data/README.md +111 -0
  7. data/Rakefile +86 -0
  8. data/bin/twitter-ads +42 -0
  9. data/lib/twitter-ads.rb +54 -0
  10. data/lib/twitter-ads/account.rb +229 -0
  11. data/lib/twitter-ads/audiences/tailored_audience.rb +177 -0
  12. data/lib/twitter-ads/campaign/app_list.rb +42 -0
  13. data/lib/twitter-ads/campaign/campaign.rb +40 -0
  14. data/lib/twitter-ads/campaign/funding_instrument.rb +33 -0
  15. data/lib/twitter-ads/campaign/line_item.rb +91 -0
  16. data/lib/twitter-ads/campaign/promotable_user.rb +28 -0
  17. data/lib/twitter-ads/campaign/targeting_criteria.rb +77 -0
  18. data/lib/twitter-ads/campaign/tweet.rb +83 -0
  19. data/lib/twitter-ads/client.rb +92 -0
  20. data/lib/twitter-ads/creative/app_download_card.rb +44 -0
  21. data/lib/twitter-ads/creative/image_app_download_card.rb +44 -0
  22. data/lib/twitter-ads/creative/image_conversation_card.rb +44 -0
  23. data/lib/twitter-ads/creative/lead_gen_card.rb +46 -0
  24. data/lib/twitter-ads/creative/promoted_account.rb +38 -0
  25. data/lib/twitter-ads/creative/promoted_tweet.rb +87 -0
  26. data/lib/twitter-ads/creative/video.rb +43 -0
  27. data/lib/twitter-ads/creative/video_app_download_card.rb +47 -0
  28. data/lib/twitter-ads/creative/video_conversation_card.rb +46 -0
  29. data/lib/twitter-ads/creative/website_card.rb +48 -0
  30. data/lib/twitter-ads/cursor.rb +127 -0
  31. data/lib/twitter-ads/enum.rb +135 -0
  32. data/lib/twitter-ads/error.rb +93 -0
  33. data/lib/twitter-ads/http/request.rb +127 -0
  34. data/lib/twitter-ads/http/response.rb +74 -0
  35. data/lib/twitter-ads/http/ton_upload.rb +140 -0
  36. data/lib/twitter-ads/legacy.rb +7 -0
  37. data/lib/twitter-ads/resources/analytics.rb +90 -0
  38. data/lib/twitter-ads/resources/dsl.rb +108 -0
  39. data/lib/twitter-ads/resources/persistence.rb +43 -0
  40. data/lib/twitter-ads/resources/resource.rb +92 -0
  41. data/lib/twitter-ads/targeting/reach_estimate.rb +69 -0
  42. data/lib/twitter-ads/utils.rb +76 -0
  43. data/lib/twitter-ads/version.rb +6 -0
  44. data/spec/fixtures/accounts_all.json +65 -0
  45. data/spec/fixtures/accounts_features.json +18 -0
  46. data/spec/fixtures/accounts_load.json +19 -0
  47. data/spec/fixtures/app_lists_all.json +22 -0
  48. data/spec/fixtures/app_lists_load.json +31 -0
  49. data/spec/fixtures/campaigns_all.json +208 -0
  50. data/spec/fixtures/campaigns_load.json +27 -0
  51. data/spec/fixtures/funding_instruments_all.json +74 -0
  52. data/spec/fixtures/funding_instruments_load.json +28 -0
  53. data/spec/fixtures/line_items_all.json +292 -0
  54. data/spec/fixtures/line_items_load.json +36 -0
  55. data/spec/fixtures/placements.json +35 -0
  56. data/spec/fixtures/promotable_users_all.json +57 -0
  57. data/spec/fixtures/promotable_users_load.json +18 -0
  58. data/spec/fixtures/promoted_tweets_all.json +212 -0
  59. data/spec/fixtures/promoted_tweets_load.json +19 -0
  60. data/spec/fixtures/reach_estimate.json +19 -0
  61. data/spec/fixtures/tailored_audiences_all.json +67 -0
  62. data/spec/fixtures/tailored_audiences_load.json +29 -0
  63. data/spec/fixtures/tweet_preview.json +24 -0
  64. data/spec/fixtures/videos_all.json +50 -0
  65. data/spec/fixtures/videos_load.json +22 -0
  66. data/spec/quality_spec.rb +15 -0
  67. data/spec/shared/properties.rb +20 -0
  68. data/spec/spec_helper.rb +61 -0
  69. data/spec/support/helpers.rb +42 -0
  70. data/spec/twitter-ads/account_spec.rb +315 -0
  71. data/spec/twitter-ads/audiences/tailored_audience_spec.rb +45 -0
  72. data/spec/twitter-ads/campaign/app_list_spec.rb +108 -0
  73. data/spec/twitter-ads/campaign/line_item_spec.rb +95 -0
  74. data/spec/twitter-ads/campaign/reach_estimate_spec.rb +98 -0
  75. data/spec/twitter-ads/campaign/targeting_criteria_spec.rb +39 -0
  76. data/spec/twitter-ads/campaign/tweet_spec.rb +83 -0
  77. data/spec/twitter-ads/client_spec.rb +115 -0
  78. data/spec/twitter-ads/creative/app_download_card_spec.rb +44 -0
  79. data/spec/twitter-ads/creative/image_app_download_card_spec.rb +43 -0
  80. data/spec/twitter-ads/creative/image_conversation_card_spec.rb +40 -0
  81. data/spec/twitter-ads/creative/lead_gen_card_spec.rb +46 -0
  82. data/spec/twitter-ads/creative/promoted_account_spec.rb +30 -0
  83. data/spec/twitter-ads/creative/promoted_tweet_spec.rb +46 -0
  84. data/spec/twitter-ads/creative/video_app_download_card_spec.rb +42 -0
  85. data/spec/twitter-ads/creative/video_conversation_card_spec.rb +52 -0
  86. data/spec/twitter-ads/creative/video_legacy_spec.rb +43 -0
  87. data/spec/twitter-ads/creative/video_spec.rb +43 -0
  88. data/spec/twitter-ads/creative/website_card_spec.rb +37 -0
  89. data/spec/twitter-ads/cursor_spec.rb +67 -0
  90. data/spec/twitter-ads/placements_spec.rb +36 -0
  91. data/spec/twitter-ads/utils_spec.rb +101 -0
  92. data/twitter-ads.gemspec +37 -0
  93. metadata +247 -0
  94. metadata.gz.sig +0 -0
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2015 Twitter, Inc.
3
+
4
+ module TwitterAds
5
+ module Creative
6
+
7
+ class Video
8
+
9
+ include TwitterAds::DSL
10
+ include TwitterAds::Resource
11
+ include TwitterAds::Persistence
12
+
13
+ attr_reader :account
14
+
15
+ property :id, read_only: true
16
+ property :tweeted, type: :bool, read_only: true
17
+ property :ready_to_tweet, type: :bool, read_only: true
18
+ property :duration, read_only: true
19
+ property :reasons_not_servable, read_only: true
20
+ property :preview_url, read_only: true
21
+ property :created_at, type: :time, read_only: true
22
+ property :updated_at, type: :time, read_only: true
23
+ property :deleted, type: :bool, read_only: true
24
+
25
+ property :title
26
+ property :description
27
+ property :video_media_id
28
+
29
+ RESOURCE_COLLECTION = '/0/accounts/%{account_id}/videos'.freeze # @api private
30
+ RESOURCE = '/0/accounts/%{account_id}/videos/%{id}'.freeze # @api private
31
+
32
+ def initialize(account)
33
+ @account = account
34
+ self
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+ end
41
+
42
+ # TODO: legacy namespace support, to be removed in v1.0.0 (next major)
43
+ TwitterAds::Video = TwitterAds::Creative::Video
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2015 Twitter, Inc.
3
+
4
+ module TwitterAds
5
+ module Creative
6
+
7
+ class VideoAppDownloadCard
8
+
9
+ include TwitterAds::DSL
10
+ include TwitterAds::Resource
11
+ include TwitterAds::Persistence
12
+
13
+ attr_reader :account
14
+
15
+ property :id, read_only: true
16
+ property :preview_url, read_only: true
17
+ property :video_url, read_only: true
18
+ property :video_poster_url, read_only: true
19
+ property :deleted, type: :bool, read_only: true
20
+ property :created_at, type: :time, read_only: true
21
+ property :updated_at, type: :time, read_only: true
22
+
23
+ property :name
24
+ property :app_country_code
25
+ property :iphone_app_id
26
+ property :iphone_deep_link
27
+ property :ipad_app_id
28
+ property :ipad_deep_link
29
+ property :googleplay_app_id
30
+ property :googleplay_deep_link
31
+ property :app_cta
32
+ property :image_media_id
33
+ property :video_id
34
+
35
+ RESOURCE_COLLECTION =
36
+ '/0/accounts/%{account_id}/cards/video_app_download'.freeze # @api private
37
+ RESOURCE = '/0/accounts/%{account_id}/cards/video_app_download/%{id}'.freeze # @api private
38
+
39
+ def initialize(account)
40
+ @account = account
41
+ self
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2015 Twitter, Inc.
3
+
4
+ module TwitterAds
5
+ module Creative
6
+
7
+ class VideoConversationCard
8
+
9
+ include TwitterAds::DSL
10
+ include TwitterAds::Resource
11
+ include TwitterAds::Persistence
12
+
13
+ attr_reader :account
14
+
15
+ property :id, read_only: true
16
+ property :preview_url, read_only: true
17
+ property :video_url, read_only: true
18
+ property :video_poster_url, read_only: true
19
+ property :deleted, type: :bool, read_only: true
20
+ property :created_at, type: :time, read_only: true
21
+ property :updated_at, type: :time, read_only: true
22
+
23
+ property :name
24
+ property :title
25
+ property :first_cta
26
+ property :first_cta_tweet
27
+ property :second_cta
28
+ property :second_cta_tweet
29
+ property :thank_you_text
30
+ property :thank_you_url
31
+ property :image_media_id
32
+ property :video_id
33
+
34
+ RESOURCE_COLLECTION =
35
+ '/0/accounts/%{account_id}/cards/video_conversation'.freeze # @api private
36
+ RESOURCE = '/0/accounts/%{account_id}/cards/video_conversation/%{id}'.freeze # @api private
37
+
38
+ def initialize(account)
39
+ @account = account
40
+ self
41
+ end
42
+
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2015 Twitter, Inc.
3
+
4
+ module TwitterAds
5
+ module Creative
6
+
7
+ class WebsiteCard
8
+
9
+ include TwitterAds::DSL
10
+ include TwitterAds::Resource
11
+ include TwitterAds::Persistence
12
+
13
+ attr_reader :account
14
+
15
+ property :id, read_only: true
16
+ property :preview_url, read_only: true
17
+ property :deleted, type: :bool, read_only: true
18
+ property :created_at, type: :time, read_only: true
19
+ property :updated_at, type: :time, read_only: true
20
+
21
+ property :name
22
+ property :website_title
23
+ property :website_url
24
+ # @return [String] An enum value for the call-to-action prompt.
25
+ # @deprecated Please see https://t.co/deprecated-website-card-cta for more info.
26
+ property :website_cta
27
+ property :image_media_id
28
+
29
+ RESOURCE_COLLECTION = '/0/accounts/%{account_id}/cards/website'.freeze # @api private
30
+ RESOURCE = '/0/accounts/%{account_id}/cards/website/%{id}'.freeze # @api private
31
+
32
+ def initialize(account)
33
+ @account = account
34
+ self
35
+ end
36
+
37
+ # Overload for CTA deprecation warning.
38
+ # @private
39
+ def website_cta=(value)
40
+ TwitterAds::Utils.deprecated(
41
+ "#{self.class}#website_cta", refer: 'https://t.co/deprecated-website-card-cta')
42
+ @website_cta = value
43
+ end
44
+
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2015 Twitter, Inc.
3
+
4
+ module TwitterAds
5
+ class Cursor
6
+
7
+ include ::Enumerable
8
+ extend ::Forwardable
9
+
10
+ def_delegators :@collection, :first, :[]
11
+
12
+ # Creates a new Cursor instance.
13
+ #
14
+ # @param klass [String] The object class the contained by the Cursor instance.
15
+ # @param request [Request] The Request object instance.
16
+ # @param opts [Hash] A Hash of extended options.
17
+ #
18
+ # @return [Cursor] The new Cursor instance.
19
+ #
20
+ # @since 0.1.0
21
+ def initialize(klass, request, opts = {})
22
+ @klass = klass
23
+ @client = request.client
24
+ @method = request.method
25
+ @resource = request.resource
26
+ @options = opts.merge!(request.options)
27
+ @collection = []
28
+ from_response(request.perform)
29
+ self
30
+ end
31
+
32
+ # Exhausts the Cursor then returns the last object in the collection.
33
+ #
34
+ # @return [Object] The last object in the collection.
35
+ #
36
+ # @since 0.2.0
37
+ def last
38
+ each {}
39
+ @collection.last
40
+ end
41
+
42
+ # Method to fetch the next page only.
43
+ #
44
+ # @return [Array] A collection containing the next page of objects.
45
+ #
46
+ # @since 0.1.0
47
+ def next
48
+ return @collection unless @next_cursor
49
+ current_size = @collection.size - 1
50
+ fetch_next
51
+ @collection[current_size..-1]
52
+ end
53
+
54
+ # Method to iterate through all items until the Cursor is exhausted.
55
+ #
56
+ # @return [Cursor] The current Cursor instance.
57
+ #
58
+ # @since 0.1.0
59
+ def each(offset = 0)
60
+ return to_enum(:each, offset) unless block_given?
61
+ @collection[offset..-1].each { |element| yield(element) }
62
+ unless exhausted?
63
+ offset = [@collection.size, offset].max
64
+ fetch_next
65
+ each(offset, &Proc.new)
66
+ end
67
+ self
68
+ end
69
+
70
+ # Determines whether or not the current Cusor instance has been exhausted.
71
+ #
72
+ # @return [Boolean] A boolean value indicating Cursor status.
73
+ #
74
+ # @since 0.1.0
75
+ def exhausted?
76
+ !@next_cursor
77
+ end
78
+
79
+ # Returns the full size of the cursor (even if not exhausted).
80
+ #
81
+ # @return [Integer] The Cursor count / size.
82
+ #
83
+ # @since 0.1.0
84
+ def count
85
+ @total_count || @collection.size
86
+ end
87
+ alias size count
88
+
89
+ # Returns an inspection string for the current Cursor instance.
90
+ #
91
+ # @example
92
+ # cursor.inspect
93
+ #
94
+ # @since 0.1.0
95
+ #
96
+ # @return [String] The inspection string.
97
+ def inspect
98
+ "#<#{self.class.name}:0x#{object_id} " \
99
+ "count=#{size} fetched=#{@collection.size} " \
100
+ "exhausted=#{exhausted?}>"
101
+ end
102
+
103
+ private
104
+
105
+ def fetch_next
106
+ return unless @next_cursor
107
+ opts = @options.dup
108
+ opts[:params] = opts.fetch(:params, {}).merge!(cursor: @next_cursor)
109
+ from_response(Request.new(@client, @method, @resource, opts).perform)
110
+ end
111
+
112
+ def from_response(response)
113
+ @next_cursor = response.body[:next_cursor]
114
+ @total_count = response.body[:total_count].to_i if response.body.key?(:total_count)
115
+ response.body.fetch(:data, []).each do |object|
116
+ @collection << if @klass && @klass.method_defined?(:from_response)
117
+ @klass.new(
118
+ *@options[:init_with]).from_response(object)
119
+ else
120
+ object
121
+ end
122
+ end
123
+ end
124
+
125
+ end
126
+
127
+ end
@@ -0,0 +1,135 @@
1
+ # frozen_string_literal: true
2
+ # Copyright (C) 2015 Twitter, Inc.
3
+
4
+ # Copyright (Cend 2015 Twitter, Inc.
5
+
6
+ module TwitterAds
7
+ module Enum
8
+
9
+ module Objective
10
+ APP_ENGAGEMENTS = 'APP_ENGAGEMENTS'.freeze
11
+ APP_INSTALLS = 'APP_INSTALLS'.freeze
12
+ FOLLOWERS = 'FOLLOWERS'.freeze
13
+ LEAD_GENERATION = 'LEAD_GENERATION'.freeze
14
+ TWEET_ENGAGEMENTS = 'TWEET_ENGAGEMENTS'.freeze
15
+ VIDEO_VIEWS = 'VIDEO_VIEWS'.freeze
16
+ WEBSITE_CLICKS = 'WEBSITE_CLICKS'.freeze
17
+
18
+ # @deprecated
19
+ CUSTOM = 'CUSTOM'.freeze
20
+ end
21
+
22
+ module Product
23
+ PROMOTED_ACCOUNT = 'PROMOTED_ACCOUNT'.freeze
24
+ PROMOTED_TWEETS = 'PROMOTED_TWEETS'.freeze
25
+ end
26
+
27
+ module Placement
28
+ ALL_ON_TWITTER = 'ALL_ON_TWITTER'.freeze
29
+ TWITTER_SEARCH = 'TWITTER_SEARCH'.freeze
30
+ TWITTER_TIMELINE = 'TWITTER_TIMELINE'.freeze
31
+ PUBLISHER_NETWORK = 'PUBLISHER_NETWORK'.freeze
32
+ end
33
+
34
+ module Placement
35
+ class << self
36
+
37
+ # Helper method to return a list a valid placement combinations by Product.
38
+ #
39
+ # @example
40
+ # Placement.valid_combinations(Product::PROMOTED_TWEETS)
41
+ #
42
+ # @param product_type [Product] The enum value for the Product type being targeted.
43
+ #
44
+ # @return [Array] An array of valid placement combinations.
45
+ #
46
+ # @deprecated use LineItems#placements(). Will be deprecated in v1.0.0.
47
+ #
48
+ # @since 0.1.0
49
+ # @see https://dev.twitter.com/ads/reference/get/line_items/placements
50
+ def valid_combinations(client, product_type)
51
+ TwitterAds::Utils.deprecated(
52
+ 'Placement#valid_combinations', replacement: 'LineItem#placements')
53
+ TwitterAds::LineItem.placements(client, product_type)
54
+ end
55
+
56
+ end
57
+ end
58
+
59
+ module BidUnit
60
+ APP_CLICK = 'APP_CLICK'.freeze
61
+ APP_INSTALL = 'APP_INSTALL'.freeze
62
+ ENGAGEMENT = 'ENGAGEMENT'.freeze
63
+ FOLLOW = 'FOLLOW'.freeze
64
+ LEAD = 'LEAD'.freeze
65
+ LINK_CLICK = 'LINK_CLICK'.freeze
66
+ VIEW = 'VIEW'.freeze
67
+ end
68
+
69
+ module ChargeBy
70
+ APP_CLICK = 'APP_CLICK'.freeze
71
+ APP_INSTALL = 'APP_INSTALL'.freeze
72
+ ENGAGEMENT = 'ENGAGEMENT'.freeze
73
+ FOLLOW = 'FOLLOW'.freeze
74
+ LEAD = 'LEAD'.freeze
75
+ LINK_CLICK = 'LINK_CLICK'.freeze
76
+ VIEW = 'VIEW'.freeze
77
+ end
78
+
79
+ module Optimizations
80
+ DEFAULT = 'DEFAULT'.freeze
81
+ WEBSITE_CONVERSIONS = 'WEBSITE_CONVERSIONS'.freeze
82
+ end
83
+
84
+ module Granularity
85
+ HOUR = 'HOUR'.freeze
86
+ DAY = 'DAY'.freeze
87
+ TOTAL = 'TOTAL'.freeze
88
+ end
89
+
90
+ module AgeBucket
91
+ AGE_13_TO_17 = 'AGE_13_TO_17'.freeze
92
+ AGE_18_TO_24 = 'AGE_18_TO_24'.freeze
93
+ AGE_25_TO_34 = 'AGE_25_TO_34'.freeze
94
+ AGE_35_TO_44 = 'AGE_35_TO_44'.freeze
95
+ AGE_45_TO_54 = 'AGE_45_TO_54'.freeze
96
+ AGE_55_TO_64 = 'AGE_55_TO_64'.freeze
97
+ AGE_OVER_65 = 'AGE_OVER_65'.freeze
98
+ end
99
+
100
+ module AgeBucketCoarse
101
+ AGE_18_TO_34 = 'AGE_18_TO_34'.freeze
102
+ AGE_18_TO_49 = 'AGE_18_TO_49'.freeze
103
+ AGE_25_TO_54 = 'AGE_25_TO_54'.freeze
104
+ AGE_OVER_21 = 'AGE_OVER_21'.freeze
105
+ end
106
+
107
+ module Events
108
+ MUSIC_AND_ENTERTAINMENT = 'MUSIC_AND_ENTERTAINMENT'.freeze
109
+ SPORTS = 'SPORTS'.freeze
110
+ HOLIDAY = 'HOLIDAY'.freeze
111
+ CONFERENCE = 'CONFERENCE'.freeze
112
+ OTHER = 'OTHER'.freeze
113
+ end
114
+
115
+ module Sentiment
116
+ ALL = 'ALL'.freeze
117
+ POSITIVE_ONLY = 'POSITIVE_ONLY'.freeze
118
+ end
119
+
120
+ module TAListTypes
121
+ EMAIL = 'EMAIL'.freeze
122
+ DEVICE_ID = 'DEVICE_ID'.freeze
123
+ TWITTER_ID = 'TWITTER_ID'.freeze
124
+ HANDLE = 'HANDLE'.freeze
125
+ PHONE_NUMBER = 'PHONE_NUMBER'.freeze
126
+ end
127
+
128
+ module TAOperations
129
+ ADD = 'ADD'.freeze
130
+ REMOVE = 'REMOVE'.freeze
131
+ REPLACE = 'REPLACE'.freeze
132
+ end
133
+
134
+ end
135
+ end