twitter-ads 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
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