buzzrb 0.1.0

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 77debe2be42e0aaef64398c094531219d7a7bebaa5be3855035f8047f7ff5807
4
+ data.tar.gz: 4d34d129f1d710eb5f5f87a849aefe0853a91c4be6659f2161610feb32b44656
5
+ SHA512:
6
+ metadata.gz: 88998110007260bf612ece0a21f5674f2d6ecb87db008ea183ec0ecba4c32a0d42f49038b1552ed97d03ae5b4155ff2b37ebe6def2521f7fe3beeda82ae777c8
7
+ data.tar.gz: 81d7ef463ce8eda9c599932037c5bd7236e9907d2d38831baadcc4ddec7aecaa581163c0a928d4b309309d1cc84b8f9fef6704f36b05fb76a29b1e4bde2e07b5
data/LICENSE.md ADDED
@@ -0,0 +1,8 @@
1
+ The MIT License (MIT)
2
+ Copyright © 2026 swlkr
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+
6
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+
8
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/buzzrb.gemspec ADDED
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/buzz/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "buzzrb"
7
+ spec.version = Buzz::VERSION
8
+ spec.authors = ["Letterpress"]
9
+ spec.summary = "Ruby client for the Buzz/Freewheel Advertiser API v2.0"
10
+ spec.homepage = "https://github.com/getletterpress/buzzrb"
11
+ spec.license = "MIT"
12
+ spec.required_ruby_version = ">= 3.0"
13
+
14
+ spec.files = Dir["lib/**/*.rb"] + ["buzzrb.gemspec", "LICENSE.md"]
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_development_dependency "minitest", "~> 5.0"
18
+ spec.add_development_dependency "rake", "~> 13.0"
19
+ spec.add_development_dependency "webrick", "~> 1.8"
20
+ end
@@ -0,0 +1,240 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "json"
6
+
7
+ module Buzz
8
+ class Client
9
+ attr_reader :config, :cookie_jar
10
+
11
+ def initialize(buzz_key: nil, email: nil, password: nil, **options)
12
+ @config = if buzz_key
13
+ Configuration.new.tap do |c|
14
+ c.buzz_key = buzz_key
15
+ c.email = email
16
+ c.password = password
17
+ options.each { |k, v| c.public_send(:"#{k}=", v) }
18
+ end
19
+ else
20
+ Buzz.configuration.dup
21
+ end
22
+ @config.validate!
23
+ @cookie_jar = CookieJar.new
24
+ @http = nil
25
+ @authenticated = false
26
+ @mutex = Mutex.new
27
+ end
28
+
29
+ def get(path, params = {})
30
+ request(:get, path, params: params)
31
+ end
32
+
33
+ def post(path, body = {})
34
+ request(:post, path, body: body)
35
+ end
36
+
37
+ def put(path, body = {})
38
+ request(:put, path, body: body)
39
+ end
40
+
41
+ def delete(path, params = {})
42
+ request(:delete, path, params: params)
43
+ end
44
+
45
+ def authenticate
46
+ uri = build_uri("/rest/v2/authenticate")
47
+ body = { email: config.email, password: config.password }
48
+ body[:account_id] = config.account_id if config.account_id
49
+
50
+ req = build_request(:post, uri)
51
+ req.body = JSON.generate(body)
52
+
53
+ response = execute(uri, req)
54
+
55
+ unless response.success?
56
+ raise AuthenticationError.new(
57
+ "Authentication failed: #{response.body}",
58
+ status: response.status,
59
+ body: response.data
60
+ )
61
+ end
62
+
63
+ @authenticated = true
64
+
65
+ if config.keep_logged_in
66
+ keep_logged_in
67
+ end
68
+
69
+ response
70
+ end
71
+
72
+ def authenticated?
73
+ @authenticated
74
+ end
75
+
76
+ # Resource accessors
77
+ def advertisers
78
+ Resources::Advertiser.new(self)
79
+ end
80
+
81
+ def campaigns
82
+ Resources::Campaign.new(self)
83
+ end
84
+
85
+ def line_items
86
+ Resources::LineItem.new(self)
87
+ end
88
+
89
+ def creatives
90
+ Resources::Creative.new(self)
91
+ end
92
+
93
+ def segments
94
+ Resources::Segment.new(self)
95
+ end
96
+
97
+ def targeting
98
+ Resources::Targeting.new(self)
99
+ end
100
+
101
+ def creative_assets
102
+ Resources::CreativeAsset.new(self)
103
+ end
104
+
105
+ def creative_line_items(line_item_id)
106
+ Resources::CreativeLineItem.new(self, line_item_id)
107
+ end
108
+
109
+ def reporting
110
+ Resources::Reporting.new(self)
111
+ end
112
+
113
+ def search(query:, types: nil)
114
+ params = { q: query }
115
+ params[:entity_types] = Array(types).map(&:to_s).join(",") if types
116
+ get("/rest/v2/search", params)
117
+ end
118
+
119
+ private
120
+
121
+ def keep_logged_in
122
+ uri = build_uri("/rest/v2/authenticate/keep_logged_in")
123
+ req = build_request(:post, uri)
124
+ req.body = JSON.generate({})
125
+ execute(uri, req)
126
+ end
127
+
128
+ def request(method, path, params: {}, body: nil)
129
+ ensure_authenticated
130
+
131
+ uri = build_uri(path, params)
132
+ req = build_request(method, uri)
133
+ req.body = JSON.generate(body) if body
134
+
135
+ response = execute(uri, req)
136
+
137
+ if response.status == 401
138
+ @authenticated = false
139
+ authenticate
140
+ uri = build_uri(path, params)
141
+ req = build_request(method, uri)
142
+ req.body = JSON.generate(body) if body
143
+ response = execute(uri, req)
144
+ end
145
+
146
+ handle_errors(response)
147
+ response
148
+ end
149
+
150
+ def ensure_authenticated
151
+ authenticate unless @authenticated
152
+ end
153
+
154
+ def build_uri(path, params = {})
155
+ uri = URI.parse("#{config.base_url}#{path}")
156
+ if params && !params.empty?
157
+ query = params.map { |k, v| "#{URI.encode_www_form_component(k)}=#{URI.encode_www_form_component(v)}" }
158
+ uri.query = query.join("&")
159
+ end
160
+ uri
161
+ end
162
+
163
+ def build_request(method, uri)
164
+ klass = case method
165
+ when :get then Net::HTTP::Get
166
+ when :post then Net::HTTP::Post
167
+ when :put then Net::HTTP::Put
168
+ when :delete then Net::HTTP::Delete
169
+ end
170
+
171
+ req = klass.new(uri)
172
+ req["Content-Type"] = "application/json"
173
+ req["Accept"] = "application/json"
174
+ req["X-Timezone"] = config.timezone if config.timezone
175
+
176
+ cookie = cookie_jar.cookie_header(uri)
177
+ req["Cookie"] = cookie if cookie
178
+
179
+ req
180
+ end
181
+
182
+ def execute(uri, req)
183
+ http = connection_for(uri)
184
+ raw = http.request(req)
185
+
186
+ # Parse cookies from response
187
+ if raw.get_fields("Set-Cookie")
188
+ raw.get_fields("Set-Cookie").each do |cookie_str|
189
+ cookie_jar.parse(cookie_str, uri)
190
+ end
191
+ end
192
+
193
+ Response.new(raw)
194
+ end
195
+
196
+ def connection_for(uri)
197
+ @mutex.synchronize do
198
+ if @http.nil? || !@http.started?
199
+ @http = Net::HTTP.new(uri.host, uri.port)
200
+ @http.use_ssl = uri.scheme == "https"
201
+ @http.open_timeout = config.open_timeout
202
+ @http.read_timeout = config.read_timeout
203
+ @http.keep_alive_timeout = 30
204
+ @http.start
205
+ end
206
+ @http
207
+ end
208
+ end
209
+
210
+ def handle_errors(response)
211
+ case response.status
212
+ when 200..299
213
+ # success
214
+ when 400
215
+ raise ValidationError.new(error_message(response), status: 400, body: response.data)
216
+ when 401
217
+ raise AuthenticationError.new(error_message(response), status: 401, body: response.data)
218
+ when 404
219
+ raise NotFoundError.new(error_message(response), status: 404, body: response.data)
220
+ when 429
221
+ retry_after = response.headers["retry-after"]&.first&.to_i
222
+ raise RateLimitError.new(error_message(response), status: 429, body: response.data, retry_after: retry_after)
223
+ when 500..599
224
+ raise ServerError.new(error_message(response), status: response.status, body: response.data)
225
+ else
226
+ raise Error.new(error_message(response), status: response.status, body: response.data)
227
+ end
228
+ end
229
+
230
+ def error_message(response)
231
+ if response.data.is_a?(Hash) && response.data["message"]
232
+ response.data["message"]
233
+ elsif response.data.is_a?(Hash) && response.data["detail"]
234
+ response.data["detail"]
235
+ else
236
+ "HTTP #{response.status}"
237
+ end
238
+ end
239
+ end
240
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ class Configuration
5
+ attr_accessor :buzz_key, :email, :password, :keep_logged_in,
6
+ :account_id, :timezone, :open_timeout, :read_timeout
7
+ attr_writer :base_url
8
+
9
+ def initialize
10
+ @keep_logged_in = true
11
+ @open_timeout = 10
12
+ @read_timeout = 30
13
+ end
14
+
15
+ def base_url
16
+ @base_url || "https://#{buzz_key}.api.beeswax.com"
17
+ end
18
+
19
+ def validate!
20
+ raise ArgumentError, "buzz_key is required" unless buzz_key && !buzz_key.empty?
21
+ raise ArgumentError, "email is required" unless email && !email.empty?
22
+ raise ArgumentError, "password is required" unless password && !password.empty?
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "uri"
4
+ require "time"
5
+
6
+ module Buzz
7
+ class CookieJar
8
+ Cookie = Struct.new(:name, :value, :domain, :path, :expires, :secure, :httponly, keyword_init: true)
9
+
10
+ def initialize
11
+ @cookies = {}
12
+ @mutex = Mutex.new
13
+ end
14
+
15
+ def parse(set_cookie_header, request_uri)
16
+ return unless set_cookie_header
17
+
18
+ headers = set_cookie_header.is_a?(Array) ? set_cookie_header : [set_cookie_header]
19
+ uri = request_uri.is_a?(URI) ? request_uri : URI.parse(request_uri)
20
+
21
+ @mutex.synchronize do
22
+ headers.each do |header|
23
+ cookie = parse_cookie(header, uri)
24
+ @cookies[cookie.name] = cookie if cookie
25
+ end
26
+ end
27
+ end
28
+
29
+ def cookie_header(uri)
30
+ uri = uri.is_a?(URI) ? uri : URI.parse(uri)
31
+ now = Time.now
32
+
33
+ @mutex.synchronize do
34
+ matching = @cookies.values.select do |cookie|
35
+ next false if cookie.expires && cookie.expires < now
36
+ next false if cookie.secure && uri.scheme != "https"
37
+ path_matches?(uri.path, cookie.path)
38
+ end
39
+
40
+ return nil if matching.empty?
41
+ matching.map { |c| "#{c.name}=#{c.value}" }.join("; ")
42
+ end
43
+ end
44
+
45
+ def clear
46
+ @mutex.synchronize { @cookies.clear }
47
+ end
48
+
49
+ def empty?
50
+ @mutex.synchronize { @cookies.empty? }
51
+ end
52
+
53
+ def size
54
+ @mutex.synchronize { @cookies.size }
55
+ end
56
+
57
+ private
58
+
59
+ def parse_cookie(header, uri)
60
+ parts = header.split(";").map(&:strip)
61
+ return nil if parts.empty?
62
+
63
+ name_value = parts.shift
64
+ eq_index = name_value.index("=")
65
+ return nil unless eq_index
66
+
67
+ name = name_value[0...eq_index].strip
68
+ value = name_value[(eq_index + 1)..].strip
69
+ return nil if name.empty?
70
+
71
+ attrs = { name: name, value: value, domain: uri.host, path: "/", secure: false, httponly: false }
72
+
73
+ parts.each do |part|
74
+ key, val = part.split("=", 2).map(&:strip)
75
+ case key.downcase
76
+ when "domain"
77
+ attrs[:domain] = val&.delete_prefix(".") if val
78
+ when "path"
79
+ attrs[:path] = val if val
80
+ when "expires"
81
+ attrs[:expires] = Time.parse(val) rescue nil if val
82
+ when "max-age"
83
+ attrs[:expires] = Time.now + val.to_i if val
84
+ when "secure"
85
+ attrs[:secure] = true
86
+ when "httponly"
87
+ attrs[:httponly] = true
88
+ end
89
+ end
90
+
91
+ Cookie.new(**attrs)
92
+ end
93
+
94
+ def path_matches?(request_path, cookie_path)
95
+ request_path = "/" if request_path.nil? || request_path.empty?
96
+ cookie_path = "/" if cookie_path.nil? || cookie_path.empty?
97
+ request_path.start_with?(cookie_path)
98
+ end
99
+ end
100
+ end
data/lib/buzz/error.rb ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ class Error < StandardError
5
+ attr_reader :status, :body
6
+
7
+ def initialize(message = nil, status: nil, body: nil)
8
+ @status = status
9
+ @body = body
10
+ super(message)
11
+ end
12
+ end
13
+
14
+ class AuthenticationError < Error; end
15
+ class RateLimitError < Error
16
+ attr_reader :retry_after
17
+
18
+ def initialize(message = nil, status: nil, body: nil, retry_after: nil)
19
+ @retry_after = retry_after
20
+ super(message, status: status, body: body)
21
+ end
22
+ end
23
+ class NotFoundError < Error; end
24
+ class ValidationError < Error; end
25
+ class ServerError < Error; end
26
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ class Paginator
5
+ include Enumerable
6
+
7
+ attr_reader :response
8
+
9
+ def initialize(client, path, params = {})
10
+ @client = client
11
+ @path = path
12
+ @params = params
13
+ @response = nil
14
+ end
15
+
16
+ def each_page
17
+ return enum_for(:each_page) unless block_given?
18
+
19
+ @response = @client.get(@path, @params)
20
+ yield @response
21
+
22
+ while @response.next_url
23
+ next_path = URI.parse(@response.next_url).path
24
+ next_params = parse_query(URI.parse(@response.next_url).query)
25
+ @response = @client.get(next_path, next_params)
26
+ yield @response
27
+ end
28
+ end
29
+
30
+ def each(&block)
31
+ return enum_for(:each) unless block_given?
32
+
33
+ each_page do |page|
34
+ results = page.results || []
35
+ results.each(&block)
36
+ end
37
+ end
38
+
39
+ def to_a
40
+ entries = []
41
+ each { |item| entries << item }
42
+ entries
43
+ end
44
+
45
+ private
46
+
47
+ def parse_query(query_string)
48
+ return {} if query_string.nil? || query_string.empty?
49
+ URI.decode_www_form(query_string).to_h.transform_keys(&:to_sym)
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ class Resource
5
+ attr_reader :client
6
+
7
+ def initialize(client)
8
+ @client = client
9
+ end
10
+
11
+ def list(params = {})
12
+ Paginator.new(client, resource_path, params)
13
+ end
14
+
15
+ def find(id)
16
+ response = client.get("#{resource_path}/#{id}")
17
+ response.data
18
+ end
19
+
20
+ def create(attributes = {})
21
+ response = client.post(resource_path, attributes)
22
+ response.data
23
+ end
24
+
25
+ def update(id, attributes = {})
26
+ response = client.put("#{resource_path}/#{id}", attributes)
27
+ response.data
28
+ end
29
+
30
+ def delete(id)
31
+ response = client.delete("#{resource_path}/#{id}")
32
+ response.data
33
+ end
34
+
35
+ private
36
+
37
+ def resource_path
38
+ raise NotImplementedError, "#{self.class} must implement #resource_path"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class Advertiser < Resource
6
+ private
7
+
8
+ def resource_path
9
+ "/rest/v2/advertisers"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class Campaign < Resource
6
+ private
7
+
8
+ def resource_path
9
+ "/rest/v2/campaigns"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class Creative < Resource
6
+ private
7
+
8
+ def resource_path
9
+ "/rest/v2/creatives"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class CreativeAsset < Resource
6
+ private
7
+
8
+ def resource_path
9
+ "/rest/v2/creative-assets"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class CreativeLineItem
6
+ attr_reader :client, :line_item_id
7
+
8
+ def initialize(client, line_item_id)
9
+ @client = client
10
+ @line_item_id = line_item_id
11
+ end
12
+
13
+ def list(params = {})
14
+ Paginator.new(client, base_path, params)
15
+ end
16
+
17
+ def create(attributes = {})
18
+ response = client.post(base_path, attributes)
19
+ response.data
20
+ end
21
+
22
+ def find(id)
23
+ response = client.get("#{base_path}/#{id}")
24
+ response.data
25
+ end
26
+
27
+ def delete(id)
28
+ response = client.delete("#{base_path}/#{id}")
29
+ response.data
30
+ end
31
+
32
+ private
33
+
34
+ def base_path
35
+ "/rest/v2/line-items/#{line_item_id}/creatives"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class LineItem < Resource
6
+ private
7
+
8
+ def resource_path
9
+ "/rest/v2/line-items"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class Reporting
6
+ attr_reader :client
7
+
8
+ def initialize(client)
9
+ @client = client
10
+ end
11
+
12
+ # Query performance data (spend, impressions, clicks, etc.)
13
+ def query(dimensions: [], metrics: [], **params)
14
+ body = { dimensions: dimensions, metrics: metrics }.merge(params)
15
+ response = client.post("/rest/v2/report-data", body)
16
+ response.data["results"]
17
+ end
18
+
19
+ # CRUD on saved report definitions
20
+ def list(params = {})
21
+ Paginator.new(client, "/rest/v2/reports", params)
22
+ end
23
+
24
+ def find(id)
25
+ client.get("/rest/v2/reports/#{id}").data
26
+ end
27
+
28
+ def create(attributes = {})
29
+ client.post("/rest/v2/reports", attributes).data
30
+ end
31
+
32
+ def delete(id)
33
+ client.delete("/rest/v2/reports/#{id}").data
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class Search < Resource
6
+ private
7
+
8
+ def resource_path
9
+ "/rest/v2/search"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class Segment < Resource
6
+ private
7
+
8
+ def resource_path
9
+ "/rest/v2/segments"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ module Resources
5
+ class Targeting < Resource
6
+ private
7
+
8
+ def resource_path
9
+ "/rest/v2/targeting-expressions"
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+
5
+ module Buzz
6
+ class Response
7
+ attr_reader :status, :headers, :body, :data
8
+
9
+ def initialize(http_response)
10
+ @status = http_response.code.to_i
11
+ @headers = http_response.to_hash
12
+ @body = http_response.body
13
+ @data = parse_body
14
+ end
15
+
16
+ def success?
17
+ status >= 200 && status < 300
18
+ end
19
+
20
+ def results
21
+ data["results"] if data.is_a?(Hash)
22
+ end
23
+
24
+ def count
25
+ data["count"] if data.is_a?(Hash)
26
+ end
27
+
28
+ def next_url
29
+ data["next"] if data.is_a?(Hash)
30
+ end
31
+
32
+ def previous_url
33
+ data["previous"] if data.is_a?(Hash)
34
+ end
35
+
36
+ private
37
+
38
+ def parse_body
39
+ return nil if body.nil? || body.empty?
40
+ JSON.parse(body)
41
+ rescue JSON::ParserError
42
+ nil
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Buzz
4
+ VERSION = "0.1.0"
5
+ end
data/lib/buzz.rb ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "buzz/version"
4
+ require_relative "buzz/configuration"
5
+ require_relative "buzz/error"
6
+ require_relative "buzz/cookie_jar"
7
+ require_relative "buzz/response"
8
+ require_relative "buzz/paginator"
9
+ require_relative "buzz/resource"
10
+ require_relative "buzz/resources/advertiser"
11
+ require_relative "buzz/resources/campaign"
12
+ require_relative "buzz/resources/line_item"
13
+ require_relative "buzz/resources/creative"
14
+ require_relative "buzz/resources/segment"
15
+ require_relative "buzz/resources/targeting"
16
+ require_relative "buzz/resources/creative_asset"
17
+ require_relative "buzz/resources/creative_line_item"
18
+ require_relative "buzz/resources/search"
19
+ require_relative "buzz/resources/reporting"
20
+ require_relative "buzz/client"
21
+
22
+ module Buzz
23
+ class << self
24
+ def configuration
25
+ @configuration ||= Configuration.new
26
+ end
27
+
28
+ def configure
29
+ yield(configuration)
30
+ end
31
+
32
+ def reset_configuration!
33
+ @configuration = Configuration.new
34
+ end
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,100 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: buzzrb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Letterpress
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: minitest
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: '5.0'
19
+ type: :development
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - "~>"
24
+ - !ruby/object:Gem::Version
25
+ version: '5.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: '13.0'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '13.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: webrick
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '1.8'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.8'
54
+ executables: []
55
+ extensions: []
56
+ extra_rdoc_files: []
57
+ files:
58
+ - LICENSE.md
59
+ - buzzrb.gemspec
60
+ - lib/buzz.rb
61
+ - lib/buzz/client.rb
62
+ - lib/buzz/configuration.rb
63
+ - lib/buzz/cookie_jar.rb
64
+ - lib/buzz/error.rb
65
+ - lib/buzz/paginator.rb
66
+ - lib/buzz/resource.rb
67
+ - lib/buzz/resources/advertiser.rb
68
+ - lib/buzz/resources/campaign.rb
69
+ - lib/buzz/resources/creative.rb
70
+ - lib/buzz/resources/creative_asset.rb
71
+ - lib/buzz/resources/creative_line_item.rb
72
+ - lib/buzz/resources/line_item.rb
73
+ - lib/buzz/resources/reporting.rb
74
+ - lib/buzz/resources/search.rb
75
+ - lib/buzz/resources/segment.rb
76
+ - lib/buzz/resources/targeting.rb
77
+ - lib/buzz/response.rb
78
+ - lib/buzz/version.rb
79
+ homepage: https://github.com/getletterpress/buzzrb
80
+ licenses:
81
+ - MIT
82
+ metadata: {}
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '3.0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubygems_version: 3.7.2
98
+ specification_version: 4
99
+ summary: Ruby client for the Buzz/Freewheel Advertiser API v2.0
100
+ test_files: []