aptible-resource 0.3.5 → 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8fe1293ad299a7eccf1b4138383c225b9957437d
4
- data.tar.gz: 9c7ca8e1b928ee4518b213cbf3869c02d68e24a3
3
+ metadata.gz: 31f491541f4e8330accd97a53c1896fe7fca26e2
4
+ data.tar.gz: fa2f72d22a0736be3d38d61d4731e7582ef64c78
5
5
  SHA512:
6
- metadata.gz: d97541a3c1e762fae33810ac916f8143b759730f12edd809a4218e9cdfd5a10c37ae0fbd0e9a3a48b1afa63072ae759c0afde9092068b93d4f4b9f4cb34590bc
7
- data.tar.gz: 4ba7510ecde1e02264c534f7ac0b448f74349e26d4fcb37a964da5b31dcbde90b0b5215355006d7a52d103f94510403bbe8fe66ab6d288b0ce0c230efc1aedfb
6
+ metadata.gz: ea9ed96d16623b924cc4bbd463e128bab5d8ce1463a10451faa3de64be1b079c88aec56efad7ad079b7fea3877cd906c9bae5b24b2048d08ad99bdfa5f23a4a0
7
+ data.tar.gz: 406299c0d2a4cff3faca28f86c736374a27f38cde09ea6d050a127f74853e6d5916477d4bf03cc5feb228a4ee9cc7c8151151dbace303c8f44fab0a847c8333b
data/.travis.yml CHANGED
@@ -2,4 +2,6 @@ sudo: false
2
2
 
3
3
  rvm:
4
4
  - 2.0.0
5
- - jruby
5
+ - 2.1.0
6
+ - 2.2.0
7
+ - jruby-9.0.5.0
@@ -38,18 +38,29 @@ module Aptible
38
38
  name.split('::').last.underscore.pluralize
39
39
  end
40
40
 
41
- # rubocop:disable AbcSize
42
- def self.all(options = {})
43
- resource = find_by_url(options[:href] || collection_href, options)
44
- return [] unless resource
45
- if resource.links.key?('next')
46
- options[:href] = resource.links['next'].href
47
- resource.entries + all(options)
48
- else
49
- resource.entries
41
+ def self.each_page(options = {})
42
+ return unless block_given?
43
+ href = options[:href] || collection_href
44
+ while href
45
+ # TODO: Breaking here is consistent with the existing behavior of
46
+ # .all, but it essentially swallows an error if the page you're
47
+ # hitting happens to 404. This should probably be addressed in an
48
+ # effort to make this API client more strict.
49
+ resource = find_by_url(href, options)
50
+ break if resource.nil?
51
+
52
+ yield resource.entries
53
+
54
+ next_link = resource.links['next']
55
+ href = next_link ? next_link.href : nil
50
56
  end
51
57
  end
52
- # rubocop: enable AbcSize
58
+
59
+ def self.all(options = {})
60
+ out = []
61
+ each_page(options) { |page| out.concat page }
62
+ out
63
+ end
53
64
 
54
65
  def self.where(options = {})
55
66
  params = options.except(:token, :root, :namespace, :headers)
@@ -89,7 +100,7 @@ module Aptible
89
100
 
90
101
  # rubocop:disable PredicateName
91
102
  def self.has_many(relation)
92
- define_has_many_getter(relation)
103
+ define_has_many_getters(relation)
93
104
  define_has_many_setter(relation)
94
105
  end
95
106
  # rubocop:enable PredicateName
@@ -126,7 +137,9 @@ module Aptible
126
137
  end
127
138
  # rubocop:enable PredicateName
128
139
 
129
- def self.define_has_many_getter(relation)
140
+ # rubocop:disable MethodLength
141
+ # rubocop:disable AbcSize
142
+ def self.define_has_many_getters(relation)
130
143
  define_method relation do
131
144
  get unless loaded
132
145
  if (memoized = instance_variable_get("@#{relation}"))
@@ -137,7 +150,17 @@ module Aptible
137
150
  instance_variable_set("@#{relation}", depaginated)
138
151
  end
139
152
  end
153
+
154
+ define_method "each_#{relation.to_s.singularize}" do |&block|
155
+ return if block.nil?
156
+ self.class.each_page(href: links[relation].base_href,
157
+ headers: headers) do |page|
158
+ page.each { |entry| block.call entry }
159
+ end
160
+ end
140
161
  end
162
+ # rubocop:enable AbcSize
163
+ # rubocop:enable MethodLength
141
164
 
142
165
  def self.embeds_one(relation)
143
166
  define_method relation do
@@ -1,5 +1,5 @@
1
1
  module Aptible
2
2
  module Resource
3
- VERSION = '0.3.5'
3
+ VERSION = '0.3.6'
4
4
  end
5
5
  end
@@ -9,6 +9,39 @@ describe Aptible::Resource::Base do
9
9
  error_response.stub(:status) { 403 }
10
10
  end
11
11
 
12
+ shared_context 'paginated collection' do
13
+ let(:urls) { ['/mainframes', '/mainframes?page=1'] }
14
+ let(:calls) { [] }
15
+
16
+ before do
17
+ pages = {}
18
+
19
+ urls.each_with_index do |url, idx|
20
+ collection = double("Collection for #{url}")
21
+ links = {}
22
+
23
+ allow(collection).to receive(:entries).and_return(["At #{url}"])
24
+ allow(collection).to receive(:links).and_return(links)
25
+
26
+ next_url = urls[idx + 1]
27
+ if next_url
28
+ links['next'] = HyperResource::Link.new(nil, 'href' => next_url)
29
+ end
30
+
31
+ pages[url] = collection
32
+ end
33
+
34
+ [Api, Api::Mainframe].each do |klass|
35
+ allow_any_instance_of(klass).to receive(:find_by_url) do |u, _|
36
+ calls << u
37
+ page = pages[u]
38
+ fail "Accessed unexpected URL #{u}" if page.nil?
39
+ page
40
+ end
41
+ end
42
+ end
43
+ end
44
+
12
45
  subject { Api.new }
13
46
 
14
47
  describe '.collection_href' do
@@ -33,47 +66,72 @@ describe Aptible::Resource::Base do
33
66
  end
34
67
 
35
68
  describe '.all' do
36
- let(:mainframe) { double 'Mainframe' }
37
- let(:collection) { double 'Api' }
69
+ context 'when not paginated' do
70
+ let(:mainframe) { double 'Mainframe' }
71
+ let(:collection) { double 'Api' }
38
72
 
39
- before do
40
- collection.stub(:entries) { [mainframe] }
41
- collection.stub(:links) { Hash.new }
42
- Api::Mainframe.any_instance.stub(:find_by_url) { collection }
43
- end
73
+ before do
74
+ collection.stub(:entries) { [mainframe] }
75
+ collection.stub(:links) { Hash.new }
76
+ Api::Mainframe.any_instance.stub(:find_by_url) { collection }
77
+ end
44
78
 
45
- it 'should be an array' do
46
- expect(Api::Mainframe.all).to be_a Array
47
- end
79
+ it 'should be an array' do
80
+ expect(Api::Mainframe.all).to be_a Array
81
+ end
48
82
 
49
- it 'should return the root collection' do
50
- expect(Api::Mainframe.all).to eq [mainframe]
51
- end
83
+ it 'should return the root collection' do
84
+ expect(Api::Mainframe.all).to eq [mainframe]
85
+ end
52
86
 
53
- it 'should pass options to the HyperResource initializer' do
54
- klass = Api::Mainframe
55
- options = { token: 'token' }
56
- expect(klass).to receive(:new).with(options).and_return klass.new
57
- Api::Mainframe.all(options)
87
+ it 'should pass options to the HyperResource initializer' do
88
+ klass = Api::Mainframe
89
+ options = { token: 'token' }
90
+ expect(klass).to receive(:new).with(options).and_return klass.new
91
+ Api::Mainframe.all(options)
92
+ end
58
93
  end
59
94
 
60
95
  context 'when paginated' do
61
- before do
62
- page = double('page')
63
- allow(page).to receive(:href).and_return(
64
- '/next/page', '/next/page', '/next/page'
65
- )
66
- allow(collection).to receive(:links).and_return(
67
- { 'next' => page }, { 'next' => page }, {}
68
- )
96
+ include_context 'paginated collection'
97
+
98
+ it 'should collect entries from all pages' do
99
+ records = Api::Mainframe.all
100
+ expect(records.size).to eq(2)
101
+ expect(records.first).to eq('At /mainframes')
102
+ expect(records.second).to eq('At /mainframes?page=1')
103
+ expect(calls).to eq(urls)
69
104
  end
70
105
 
71
- it 'should collect entries on all pages' do
72
- expect(Api::Mainframe.all).to eq [mainframe] + [mainframe]
106
+ it "should return an empty list for a URL that doesn't exist" do
107
+ allow_any_instance_of(Api::Mainframe).to receive(:find_by_url) { nil }
108
+ expect(Api::Mainframe.all).to eq([])
73
109
  end
74
110
  end
75
111
  end
76
112
 
113
+ describe '.each_page' do
114
+ include_context 'paginated collection'
115
+
116
+ it 'should iterate over all pages' do
117
+ pages = 0
118
+ Api::Mainframe.each_page { pages += 1 }
119
+ expect(pages).to eq(2)
120
+ expect(calls).to eq(urls)
121
+ end
122
+
123
+ it 'should find all records' do
124
+ records = ['At /mainframes', 'At /mainframes?page=1']
125
+ Api::Mainframe.each_page { |p| expect(p).to eq([records.shift]) }
126
+ expect(calls).to eq(urls)
127
+ end
128
+
129
+ it 'should not access more URLs if the consumer breaks' do
130
+ Api::Mainframe.each_page { break }
131
+ expect(calls).to eq(['/mainframes'])
132
+ end
133
+ end
134
+
77
135
  describe '.create' do
78
136
  let(:mainframe) { Api::Mainframe.new }
79
137
  let(:mainframes_link) { HyperResource::Link.new(href: '/mainframes') }
@@ -263,10 +321,38 @@ describe Aptible::Resource::Base do
263
321
  end
264
322
 
265
323
  describe '#{relation}s' do
266
- it 'should defer to self.class.all' do
267
- expect(subject.class).to receive(:all).with(href: '/mainframes',
268
- headers: subject.headers)
269
- subject.mainframes
324
+ include_context 'paginated collection'
325
+
326
+ it 'should return all records' do
327
+ records = subject.mainframes
328
+
329
+ expect(records.size).to eq(2)
330
+ expect(records.first).to eq('At /mainframes')
331
+ expect(records.second).to eq('At /mainframes?page=1')
332
+ expect(calls).to eq(urls)
333
+ end
334
+ end
335
+
336
+ describe 'each_#{relation}' do
337
+ include_context 'paginated collection'
338
+
339
+ it 'should iterate over all records' do
340
+ records = []
341
+ subject.each_mainframe { |mainframe| records << mainframe }
342
+
343
+ expect(records.size).to eq(2)
344
+ expect(records.first).to eq('At /mainframes')
345
+ expect(records.second).to eq('At /mainframes?page=1')
346
+ expect(calls).to eq(urls)
347
+ end
348
+
349
+ it 'should stop iterating when the consumer breaks' do
350
+ subject.each_mainframe { |_| break }
351
+ expect(calls).to eq([urls[0]])
352
+ end
353
+
354
+ it 'should not fail if not passed a block' do
355
+ subject.each_mainframe
270
356
  end
271
357
  end
272
358
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aptible-resource
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.5
4
+ version: 0.3.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Frank Macreery
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-24 00:00:00.000000000 Z
11
+ date: 2016-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: uri_template
@@ -225,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
225
225
  version: '0'
226
226
  requirements: []
227
227
  rubyforge_project:
228
- rubygems_version: 2.5.1
228
+ rubygems_version: 2.6.4
229
229
  signing_key:
230
230
  specification_version: 4
231
231
  summary: Foundation classes for Aptible resource server gems