knievel 0.1.4 → 0.1.5
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +4 -4
- data/lib/knievel/client.rb +102 -0
- data/lib/knievel/resources/ads.rb +17 -0
- data/lib/knievel/resources/advertisers.rb +17 -0
- data/lib/knievel/resources/base.rb +90 -0
- data/lib/knievel/resources/campaigns.rb +17 -0
- data/lib/knievel/resources/creative_templates.rb +17 -0
- data/lib/knievel/resources/creatives.rb +17 -0
- data/lib/knievel/resources/flights.rb +17 -0
- data/lib/knievel/resources/sites.rb +17 -0
- data/lib/knievel/resources/zones.rb +17 -0
- data/lib/knievel/resources.rb +17 -0
- data/lib/knievel/version.rb +1 -1
- data/spec/client_spec.rb +72 -0
- data/spec/resources/advertisers_spec.rb +123 -0
- metadata +16 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 76508b7a3c559ea20c2c3e693db94332b6ba8f7fc8059705b32d869240e8166f
|
|
4
|
+
data.tar.gz: 0f34f12b4a0e45193769e98d018ff688ca5392c6664a63a888fa67f5a0791c4f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 64e02e131435fcb3d5a2154469cbcee417456140f5045688ade9cd8531cfa2a0fb10f08c138689f992575f7729acf0c6dbc340ed6da915e36b6691e84d6ee5bd
|
|
7
|
+
data.tar.gz: 42640a24ba684d28147f83a234f859f1842eb22057d6103853953ce5e7808c57a81a7267c36eb91d1be021c1b5883fb86d736d04154cb64066ed9d16d6e41ac0
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -7,7 +7,7 @@ No description provided (generated by Openapi Generator https://github.com/opena
|
|
|
7
7
|
This SDK is automatically generated by the [OpenAPI Generator](https://openapi-generator.tech) project:
|
|
8
8
|
|
|
9
9
|
- API version: 0.1.0
|
|
10
|
-
- Package version: 0.1.
|
|
10
|
+
- Package version: 0.1.5
|
|
11
11
|
- Generator version: 7.23.0-SNAPSHOT
|
|
12
12
|
- Build package: org.openapitools.codegen.languages.RubyClientCodegen
|
|
13
13
|
|
|
@@ -24,16 +24,16 @@ gem build knievel.gemspec
|
|
|
24
24
|
Then either install the gem locally:
|
|
25
25
|
|
|
26
26
|
```shell
|
|
27
|
-
gem install ./knievel-0.1.
|
|
27
|
+
gem install ./knievel-0.1.5.gem
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
(for development, run `gem install --dev ./knievel-0.1.
|
|
30
|
+
(for development, run `gem install --dev ./knievel-0.1.5.gem` to install the development dependencies)
|
|
31
31
|
|
|
32
32
|
or publish the gem to a gem hosting service, e.g. [RubyGems](https://rubygems.org/).
|
|
33
33
|
|
|
34
34
|
Finally add this to the Gemfile:
|
|
35
35
|
|
|
36
|
-
gem 'knievel', '~> 0.1.
|
|
36
|
+
gem 'knievel', '~> 0.1.5'
|
|
37
37
|
|
|
38
38
|
### Install from Git
|
|
39
39
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
require "knievel"
|
|
5
|
+
require_relative "resources"
|
|
6
|
+
|
|
7
|
+
module Knievel
|
|
8
|
+
# Convenience facade around the generated transport
|
|
9
|
+
# (`Knievel::ApiClient` + `Knievel::Configuration`) and the
|
|
10
|
+
# hand-written `Knievel::Resources::*` wrappers.
|
|
11
|
+
#
|
|
12
|
+
# Typical usage:
|
|
13
|
+
#
|
|
14
|
+
# client = Knievel::Client.new(
|
|
15
|
+
# host: "https://api.knievel-ads.example",
|
|
16
|
+
# access_token: ENV.fetch("KNIEVEL_TOKEN"),
|
|
17
|
+
# )
|
|
18
|
+
#
|
|
19
|
+
# client.advertisers("pj_abc").each { |adv| puts adv.name }
|
|
20
|
+
# client.advertisers("pj_abc").first(10)
|
|
21
|
+
# client.advertisers("pj_abc").lazy.select(&:is_active).first(20)
|
|
22
|
+
# client.advertisers("pj_abc").each_page { |page| process(page) }
|
|
23
|
+
#
|
|
24
|
+
# Pass `page_size:` to a resource accessor to override the
|
|
25
|
+
# default 500-row page size:
|
|
26
|
+
#
|
|
27
|
+
# client.advertisers("pj_abc", page_size: 50).each { ... }
|
|
28
|
+
class Client
|
|
29
|
+
# `host` is the API base URL — accepts either a full URL
|
|
30
|
+
# (`https://api.knievel-ads.example`,
|
|
31
|
+
# `http://localhost:8080`) or a bare hostname. The
|
|
32
|
+
# generated `Configuration#host=` setter strips the scheme
|
|
33
|
+
# silently, so we parse the URL ourselves to keep the
|
|
34
|
+
# scheme/port the caller intended. Falls back to the
|
|
35
|
+
# spec-stamped default (`http://localhost:8080`) when
|
|
36
|
+
# omitted — handy for local dev against compose.
|
|
37
|
+
#
|
|
38
|
+
# `access_token` is the bearer token. The `Configuration`
|
|
39
|
+
# block is a convenience for callers that need to twiddle
|
|
40
|
+
# other settings (timeouts, custom headers, etc.) before
|
|
41
|
+
# the underlying `ApiClient` materializes.
|
|
42
|
+
def initialize(host: nil, access_token: nil)
|
|
43
|
+
@config = Knievel::Configuration.new
|
|
44
|
+
apply_host(host) if host
|
|
45
|
+
@config.access_token = access_token if access_token
|
|
46
|
+
yield @config if block_given?
|
|
47
|
+
@api_client = Knievel::ApiClient.new(@config)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
private def apply_host(host)
|
|
51
|
+
uri = URI.parse(host)
|
|
52
|
+
if uri.scheme && uri.host
|
|
53
|
+
@config.scheme = uri.scheme
|
|
54
|
+
@config.host = uri.port && uri.port != uri.default_port ? "#{uri.host}:#{uri.port}" : uri.host
|
|
55
|
+
else
|
|
56
|
+
# Bare hostname (no scheme). Trust the configured default
|
|
57
|
+
# scheme and let `Configuration#host=` do its sanitization.
|
|
58
|
+
@config.host = host
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
public
|
|
63
|
+
|
|
64
|
+
# Underlying generated transport. Reach for this when you
|
|
65
|
+
# need the non-paginated endpoints (single `get_*`,
|
|
66
|
+
# `create_*`, `update_*`) — the hand-written wrappers only
|
|
67
|
+
# cover list operations.
|
|
68
|
+
attr_reader :api_client
|
|
69
|
+
|
|
70
|
+
def advertisers(project_id, **opts)
|
|
71
|
+
Resources::Advertisers.new(@api_client, project_id, **opts)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def campaigns(project_id, **opts)
|
|
75
|
+
Resources::Campaigns.new(@api_client, project_id, **opts)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def flights(project_id, **opts)
|
|
79
|
+
Resources::Flights.new(@api_client, project_id, **opts)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def ads(project_id, **opts)
|
|
83
|
+
Resources::Ads.new(@api_client, project_id, **opts)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def creatives(project_id, **opts)
|
|
87
|
+
Resources::Creatives.new(@api_client, project_id, **opts)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def creative_templates(project_id, **opts)
|
|
91
|
+
Resources::CreativeTemplates.new(@api_client, project_id, **opts)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def sites(project_id, **opts)
|
|
95
|
+
Resources::Sites.new(@api_client, project_id, **opts)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def zones(project_id, **opts)
|
|
99
|
+
Resources::Zones.new(@api_client, project_id, **opts)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "knievel"
|
|
4
|
+
|
|
5
|
+
module Knievel
|
|
6
|
+
module Resources
|
|
7
|
+
# Base class for hand-written list-endpoint wrappers that
|
|
8
|
+
# turn a paginated `list_*` API method into an `Enumerable`.
|
|
9
|
+
#
|
|
10
|
+
# Subclasses declare `list_method` (the snake_case method
|
|
11
|
+
# on the generated `*Api` class) and `api_class` (the
|
|
12
|
+
# generated class itself); this base handles the cursor
|
|
13
|
+
# walk and limit defaulting.
|
|
14
|
+
#
|
|
15
|
+
# See `REQUIREMENTS.md` § 8 item 3 ("idiomatic Ruby use
|
|
16
|
+
# including each, each_page, lazy, first(n), and
|
|
17
|
+
# short-circuiting iteration — all without the caller
|
|
18
|
+
# writing pagination loops") and `API.md` § "Pagination"
|
|
19
|
+
# (limit defaults 50, max 500; cursor is opaque, only
|
|
20
|
+
# valid for the endpoint that minted it).
|
|
21
|
+
#
|
|
22
|
+
# The default `each_page` walks the maximum 500-row page
|
|
23
|
+
# size to minimize HTTP round-trips. Callers that want
|
|
24
|
+
# smaller pages (e.g. low-latency progress reporting) can
|
|
25
|
+
# override via `page_size:` on the subclass constructor.
|
|
26
|
+
class Base
|
|
27
|
+
include Enumerable
|
|
28
|
+
|
|
29
|
+
# Server cap. Larger values fail with `400 invalid_limit`.
|
|
30
|
+
MAX_PAGE_SIZE = 500
|
|
31
|
+
|
|
32
|
+
# Subclasses override:
|
|
33
|
+
# def list_method = :list_<resource>
|
|
34
|
+
# def api_class = Knievel::<Resource>Api
|
|
35
|
+
def list_method
|
|
36
|
+
raise NotImplementedError
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def api_class
|
|
40
|
+
raise NotImplementedError
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# `api_client` is a `Knievel::ApiClient` (the generated
|
|
44
|
+
# transport, holds the base URL + auth). `project_id` is
|
|
45
|
+
# the path scope. `**filters` are forwarded to the
|
|
46
|
+
# generated `list_*` method as `opts` — once the server
|
|
47
|
+
# implements query-param filtering (e.g. `external_id=`)
|
|
48
|
+
# those keys flow through unchanged.
|
|
49
|
+
def initialize(api_client, project_id, page_size: MAX_PAGE_SIZE, **filters)
|
|
50
|
+
if page_size < 1 || page_size > MAX_PAGE_SIZE
|
|
51
|
+
raise ArgumentError, "page_size must be between 1 and #{MAX_PAGE_SIZE}"
|
|
52
|
+
end
|
|
53
|
+
@api_client = api_client
|
|
54
|
+
@project_id = project_id
|
|
55
|
+
@page_size = page_size
|
|
56
|
+
@filters = filters
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# `Enumerable` plumbing — yields rows one at a time
|
|
60
|
+
# across the entire cursor walk. Returns an `Enumerator`
|
|
61
|
+
# when called without a block (so `lazy`, `first(n)`,
|
|
62
|
+
# `take_while`, etc. work).
|
|
63
|
+
def each(&block)
|
|
64
|
+
return enum_for(:each) unless block_given?
|
|
65
|
+
|
|
66
|
+
each_page do |page_items|
|
|
67
|
+
page_items.each(&block)
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Yields one array per page. Useful for batch-style
|
|
72
|
+
# processing where per-row work has setup overhead worth
|
|
73
|
+
# amortizing. Returns an `Enumerator` without a block.
|
|
74
|
+
def each_page
|
|
75
|
+
return enum_for(:each_page) unless block_given?
|
|
76
|
+
|
|
77
|
+
cursor = nil
|
|
78
|
+
api = api_class.new(@api_client)
|
|
79
|
+
loop do
|
|
80
|
+
opts = @filters.merge(limit: @page_size)
|
|
81
|
+
opts[:cursor] = cursor unless cursor.nil?
|
|
82
|
+
response = api.public_send(list_method, @project_id, opts)
|
|
83
|
+
yield response.items
|
|
84
|
+
cursor = response.next_cursor
|
|
85
|
+
break if cursor.nil?
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "base"
|
|
4
|
+
|
|
5
|
+
module Knievel
|
|
6
|
+
module Resources
|
|
7
|
+
class CreativeTemplates < Base
|
|
8
|
+
def list_method
|
|
9
|
+
:list_creative_templates
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def api_class
|
|
13
|
+
Knievel::CreativeTemplatesApi
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Hand-written `Enumerable` wrappers over the generated `*Api`
|
|
4
|
+
# classes. See `REQUIREMENTS.md` § 8 item 3 and `Knievel::Client`
|
|
5
|
+
# for the typical entry point. Each subclass is one paginated
|
|
6
|
+
# resource; cursor walks are uniform across all of them via
|
|
7
|
+
# `Knievel::Resources::Base`.
|
|
8
|
+
|
|
9
|
+
require_relative "resources/base"
|
|
10
|
+
require_relative "resources/advertisers"
|
|
11
|
+
require_relative "resources/campaigns"
|
|
12
|
+
require_relative "resources/flights"
|
|
13
|
+
require_relative "resources/ads"
|
|
14
|
+
require_relative "resources/creatives"
|
|
15
|
+
require_relative "resources/creative_templates"
|
|
16
|
+
require_relative "resources/sites"
|
|
17
|
+
require_relative "resources/zones"
|
data/lib/knievel/version.rb
CHANGED
data/spec/client_spec.rb
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "ostruct"
|
|
5
|
+
require "knievel/client"
|
|
6
|
+
|
|
7
|
+
RSpec.describe Knievel::Client do
|
|
8
|
+
describe "#initialize" do
|
|
9
|
+
it "splits a full URL into scheme/host on the underlying Configuration" do
|
|
10
|
+
client = described_class.new(host: "https://example.test", access_token: "kvl_xyz")
|
|
11
|
+
expect(client.api_client.config.scheme).to eq("https")
|
|
12
|
+
expect(client.api_client.config.host).to eq("example.test")
|
|
13
|
+
expect(client.api_client.config.access_token).to eq("kvl_xyz")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "preserves a non-default port on the host" do
|
|
17
|
+
client = described_class.new(host: "http://localhost:8080")
|
|
18
|
+
expect(client.api_client.config.scheme).to eq("http")
|
|
19
|
+
expect(client.api_client.config.host).to eq("localhost:8080")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "accepts a bare hostname (no scheme) and trusts the configured default scheme" do
|
|
23
|
+
client = described_class.new(host: "example.test")
|
|
24
|
+
expect(client.api_client.config.host).to eq("example.test")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "yields the configuration block for advanced tweaks" do
|
|
28
|
+
client = described_class.new(host: "https://example.test") do |config|
|
|
29
|
+
config.access_token = "kvl_via_block"
|
|
30
|
+
end
|
|
31
|
+
expect(client.api_client.config.access_token).to eq("kvl_via_block")
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "leaves the configuration default host alone when host: omitted" do
|
|
35
|
+
default = Knievel::Configuration.new.host
|
|
36
|
+
client = described_class.new(access_token: "kvl_xyz")
|
|
37
|
+
expect(client.api_client.config.host).to eq(default)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
describe "resource accessors" do
|
|
42
|
+
let(:client) { described_class.new(access_token: "kvl_xyz") }
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
advertisers: Knievel::Resources::Advertisers,
|
|
46
|
+
campaigns: Knievel::Resources::Campaigns,
|
|
47
|
+
flights: Knievel::Resources::Flights,
|
|
48
|
+
ads: Knievel::Resources::Ads,
|
|
49
|
+
creatives: Knievel::Resources::Creatives,
|
|
50
|
+
creative_templates: Knievel::Resources::CreativeTemplates,
|
|
51
|
+
sites: Knievel::Resources::Sites,
|
|
52
|
+
zones: Knievel::Resources::Zones,
|
|
53
|
+
}.each do |method, klass|
|
|
54
|
+
it "##{method} returns a #{klass.name.split('::').last} bound to the project" do
|
|
55
|
+
resource = client.public_send(method, "pj_abc")
|
|
56
|
+
expect(resource).to be_a(klass)
|
|
57
|
+
expect(resource).to be_a(Enumerable)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "forwards page_size + filter kwargs to the resource constructor" do
|
|
62
|
+
resource = client.advertisers("pj_abc", page_size: 25, external_id: "acme")
|
|
63
|
+
# Stub out the api_class so calling #to_a doesn't try real HTTP.
|
|
64
|
+
api = instance_double(Knievel::AdvertisersApi)
|
|
65
|
+
allow(Knievel::AdvertisersApi).to receive(:new).and_return(api)
|
|
66
|
+
expect(api).to receive(:list_advertisers)
|
|
67
|
+
.with("pj_abc", { external_id: "acme", limit: 25 })
|
|
68
|
+
.and_return(OpenStruct.new(items: [], next_cursor: nil))
|
|
69
|
+
resource.to_a
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "spec_helper"
|
|
4
|
+
require "ostruct"
|
|
5
|
+
require "knievel/client"
|
|
6
|
+
|
|
7
|
+
# Exercises the wrapper contract via the Advertisers resource —
|
|
8
|
+
# representative of all eight `Knievel::Resources::*` classes
|
|
9
|
+
# (they share `Resources::Base`, so per-class divergence is
|
|
10
|
+
# only the constants).
|
|
11
|
+
|
|
12
|
+
RSpec.describe Knievel::Resources::Advertisers do
|
|
13
|
+
let(:api_client) { instance_double(Knievel::ApiClient) }
|
|
14
|
+
let(:api) { instance_double(Knievel::AdvertisersApi) }
|
|
15
|
+
let(:project_id) { "pj_abc" }
|
|
16
|
+
|
|
17
|
+
before do
|
|
18
|
+
allow(Knievel::AdvertisersApi).to receive(:new).with(api_client).and_return(api)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def page(item_ids, next_cursor:)
|
|
22
|
+
items = item_ids.map { |id| OpenStruct.new(id: id, name: "adv-#{id}") }
|
|
23
|
+
OpenStruct.new(items: items, next_cursor: next_cursor)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe "#each" do
|
|
27
|
+
it "walks every page and yields rows in order until next_cursor is nil" do
|
|
28
|
+
expect(api).to receive(:list_advertisers)
|
|
29
|
+
.with(project_id, { limit: 500 })
|
|
30
|
+
.and_return(page([1, 2, 3], next_cursor: "c1"))
|
|
31
|
+
expect(api).to receive(:list_advertisers)
|
|
32
|
+
.with(project_id, { limit: 500, cursor: "c1" })
|
|
33
|
+
.and_return(page([4, 5], next_cursor: "c2"))
|
|
34
|
+
expect(api).to receive(:list_advertisers)
|
|
35
|
+
.with(project_id, { limit: 500, cursor: "c2" })
|
|
36
|
+
.and_return(page([6], next_cursor: nil))
|
|
37
|
+
|
|
38
|
+
collected = described_class.new(api_client, project_id).map(&:id)
|
|
39
|
+
expect(collected).to eq([1, 2, 3, 4, 5, 6])
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "honors a non-default page_size on the underlying limit param" do
|
|
43
|
+
expect(api).to receive(:list_advertisers)
|
|
44
|
+
.with(project_id, { limit: 50 })
|
|
45
|
+
.and_return(page([1], next_cursor: nil))
|
|
46
|
+
|
|
47
|
+
described_class.new(api_client, project_id, page_size: 50).to_a
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "passes filter kwargs through to the generated API call" do
|
|
51
|
+
expect(api).to receive(:list_advertisers)
|
|
52
|
+
.with(project_id, { external_id: "acme", limit: 500 })
|
|
53
|
+
.and_return(page([1], next_cursor: nil))
|
|
54
|
+
|
|
55
|
+
described_class.new(api_client, project_id, external_id: "acme").to_a
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "returns an Enumerator without a block" do
|
|
59
|
+
enumerator = described_class.new(api_client, project_id).each
|
|
60
|
+
expect(enumerator).to be_a(Enumerator)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "Enumerable laziness" do
|
|
65
|
+
it "stops fetching pages once `first(n)` is satisfied" do
|
|
66
|
+
expect(api).to receive(:list_advertisers)
|
|
67
|
+
.once
|
|
68
|
+
.with(project_id, { limit: 500 })
|
|
69
|
+
.and_return(page([1, 2, 3], next_cursor: "should-not-be-followed"))
|
|
70
|
+
|
|
71
|
+
result = described_class.new(api_client, project_id).lazy.first(2)
|
|
72
|
+
expect(result.map(&:id)).to eq([1, 2])
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it "supports short-circuiting `take_while` over the lazy walk" do
|
|
76
|
+
expect(api).to receive(:list_advertisers)
|
|
77
|
+
.once
|
|
78
|
+
.with(project_id, { limit: 500 })
|
|
79
|
+
.and_return(page([1, 2, 3, 4], next_cursor: "should-not-be-followed"))
|
|
80
|
+
|
|
81
|
+
result = described_class.new(api_client, project_id).lazy.take_while { |a| a.id < 3 }.to_a
|
|
82
|
+
expect(result.map(&:id)).to eq([1, 2])
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe "#each_page" do
|
|
87
|
+
it "yields one array per cursor hop" do
|
|
88
|
+
expect(api).to receive(:list_advertisers)
|
|
89
|
+
.with(project_id, { limit: 500 })
|
|
90
|
+
.and_return(page([1, 2], next_cursor: "c1"))
|
|
91
|
+
expect(api).to receive(:list_advertisers)
|
|
92
|
+
.with(project_id, { limit: 500, cursor: "c1" })
|
|
93
|
+
.and_return(page([3], next_cursor: nil))
|
|
94
|
+
|
|
95
|
+
pages = []
|
|
96
|
+
described_class.new(api_client, project_id).each_page { |p| pages << p.map(&:id) }
|
|
97
|
+
expect(pages).to eq([[1, 2], [3]])
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
describe "page_size validation" do
|
|
102
|
+
it "rejects page_size < 1" do
|
|
103
|
+
expect {
|
|
104
|
+
described_class.new(api_client, project_id, page_size: 0)
|
|
105
|
+
}.to raise_error(ArgumentError, /between 1 and 500/)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
it "rejects page_size > 500" do
|
|
109
|
+
expect {
|
|
110
|
+
described_class.new(api_client, project_id, page_size: 501)
|
|
111
|
+
}.to raise_error(ArgumentError, /between 1 and 500/)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
it "accepts page_size at the boundary" do
|
|
115
|
+
expect {
|
|
116
|
+
described_class.new(api_client, project_id, page_size: 500)
|
|
117
|
+
}.not_to raise_error
|
|
118
|
+
expect {
|
|
119
|
+
described_class.new(api_client, project_id, page_size: 1)
|
|
120
|
+
}.not_to raise_error
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: knievel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Knievel Ads
|
|
@@ -211,6 +211,7 @@ files:
|
|
|
211
211
|
- lib/knievel/api_client.rb
|
|
212
212
|
- lib/knievel/api_error.rb
|
|
213
213
|
- lib/knievel/api_model_base.rb
|
|
214
|
+
- lib/knievel/client.rb
|
|
214
215
|
- lib/knievel/configuration.rb
|
|
215
216
|
- lib/knievel/models/ad.rb
|
|
216
217
|
- lib/knievel/models/ad_library_item.rb
|
|
@@ -297,6 +298,16 @@ files:
|
|
|
297
298
|
- lib/knievel/models/version_response.rb
|
|
298
299
|
- lib/knievel/models/zone.rb
|
|
299
300
|
- lib/knievel/models/zone_list.rb
|
|
301
|
+
- lib/knievel/resources.rb
|
|
302
|
+
- lib/knievel/resources/ads.rb
|
|
303
|
+
- lib/knievel/resources/advertisers.rb
|
|
304
|
+
- lib/knievel/resources/base.rb
|
|
305
|
+
- lib/knievel/resources/campaigns.rb
|
|
306
|
+
- lib/knievel/resources/creative_templates.rb
|
|
307
|
+
- lib/knievel/resources/creatives.rb
|
|
308
|
+
- lib/knievel/resources/flights.rb
|
|
309
|
+
- lib/knievel/resources/sites.rb
|
|
310
|
+
- lib/knievel/resources/zones.rb
|
|
300
311
|
- lib/knievel/version.rb
|
|
301
312
|
- openapi-generator-config.json
|
|
302
313
|
- spec/api/ad_library_api_spec.rb
|
|
@@ -315,6 +326,7 @@ files:
|
|
|
315
326
|
- spec/api/taxonomy_api_spec.rb
|
|
316
327
|
- spec/api/tokens_api_spec.rb
|
|
317
328
|
- spec/api/zones_api_spec.rb
|
|
329
|
+
- spec/client_spec.rb
|
|
318
330
|
- spec/models/ad_library_item_list_spec.rb
|
|
319
331
|
- spec/models/ad_library_item_spec.rb
|
|
320
332
|
- spec/models/ad_list_spec.rb
|
|
@@ -400,6 +412,7 @@ files:
|
|
|
400
412
|
- spec/models/version_response_spec.rb
|
|
401
413
|
- spec/models/zone_list_spec.rb
|
|
402
414
|
- spec/models/zone_spec.rb
|
|
415
|
+
- spec/resources/advertisers_spec.rb
|
|
403
416
|
- spec/spec_helper.rb
|
|
404
417
|
homepage: https://github.com/knievel-ads/knievel-ruby
|
|
405
418
|
licenses:
|
|
@@ -441,6 +454,7 @@ test_files:
|
|
|
441
454
|
- spec/api/flights_api_spec.rb
|
|
442
455
|
- spec/api/ads_api_spec.rb
|
|
443
456
|
- spec/api/tokens_api_spec.rb
|
|
457
|
+
- spec/client_spec.rb
|
|
444
458
|
- spec/models/error_envelope_spec.rb
|
|
445
459
|
- spec/models/create_ad_library_item_request_spec.rb
|
|
446
460
|
- spec/models/ad_type_list_spec.rb
|
|
@@ -526,4 +540,5 @@ test_files:
|
|
|
526
540
|
- spec/models/force_override_spec.rb
|
|
527
541
|
- spec/models/create_zone_request_spec.rb
|
|
528
542
|
- spec/models/batch_upsert_sites_request_spec.rb
|
|
543
|
+
- spec/resources/advertisers_spec.rb
|
|
529
544
|
- spec/spec_helper.rb
|