puppet_forge 1.0.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.
Files changed (51) hide show
  1. data/.gitignore +22 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +13 -0
  4. data/README.md +172 -0
  5. data/Rakefile +2 -0
  6. data/lib/her/lazy_accessors.rb +140 -0
  7. data/lib/her/lazy_relations.rb +86 -0
  8. data/lib/puppet_forge.rb +19 -0
  9. data/lib/puppet_forge/middleware/json_for_her.rb +37 -0
  10. data/lib/puppet_forge/v3.rb +10 -0
  11. data/lib/puppet_forge/v3/base.rb +98 -0
  12. data/lib/puppet_forge/v3/base/paginated_collection.rb +73 -0
  13. data/lib/puppet_forge/v3/module.rb +15 -0
  14. data/lib/puppet_forge/v3/release.rb +35 -0
  15. data/lib/puppet_forge/v3/user.rb +21 -0
  16. data/lib/puppet_forge/version.rb +3 -0
  17. data/puppet_forge.gemspec +31 -0
  18. data/spec/fixtures/v3/files/puppetlabs-apache-0.0.1.tar.gz.headers +14 -0
  19. data/spec/fixtures/v3/files/puppetlabs-apache-0.0.1.tar.gz.json +0 -0
  20. data/spec/fixtures/v3/modules.headers +14 -0
  21. data/spec/fixtures/v3/modules.json +4197 -0
  22. data/spec/fixtures/v3/modules/puppetlabs-apache.headers +14 -0
  23. data/spec/fixtures/v3/modules/puppetlabs-apache.json +390 -0
  24. data/spec/fixtures/v3/modules?owner=puppetlabs.headers +14 -0
  25. data/spec/fixtures/v3/modules?owner=puppetlabs.json +4179 -0
  26. data/spec/fixtures/v3/modules?query=apache.headers +14 -0
  27. data/spec/fixtures/v3/modules?query=apache.json +3151 -0
  28. data/spec/fixtures/v3/releases.headers +14 -0
  29. data/spec/fixtures/v3/releases.json +3072 -0
  30. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.1.headers +14 -0
  31. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.1.json +93 -0
  32. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.2.headers +14 -0
  33. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.2.json +93 -0
  34. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.3.headers +14 -0
  35. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.3.json +93 -0
  36. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.4.headers +14 -0
  37. data/spec/fixtures/v3/releases/puppetlabs-apache-0.0.4.json +126 -0
  38. data/spec/fixtures/v3/releases/puppetlabs-apache-0.1.1.headers +14 -0
  39. data/spec/fixtures/v3/releases/puppetlabs-apache-0.1.1.json +140 -0
  40. data/spec/fixtures/v3/releases?module=puppetlabs-apache.headers +14 -0
  41. data/spec/fixtures/v3/releases?module=puppetlabs-apache.json +3287 -0
  42. data/spec/fixtures/v3/users/puppetlabs.headers +14 -0
  43. data/spec/fixtures/v3/users/puppetlabs.json +10 -0
  44. data/spec/spec_helper.rb +60 -0
  45. data/spec/unit/forge/v3/base/paginated_collection_spec.rb +88 -0
  46. data/spec/unit/forge/v3/module_spec.rb +118 -0
  47. data/spec/unit/forge/v3/release_spec.rb +112 -0
  48. data/spec/unit/forge/v3/user_spec.rb +50 -0
  49. data/spec/unit/her/lazy_accessors_spec.rb +142 -0
  50. data/spec/unit/her/lazy_relations_spec.rb +309 -0
  51. metadata +261 -0
@@ -0,0 +1,142 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+
4
+ describe Her::LazyAccessors do
5
+ let(:klass) do
6
+ Class.new do
7
+ include Her::Model
8
+ include Her::LazyAccessors
9
+
10
+ def request_path
11
+ "/things/#{id}"
12
+ end
13
+
14
+ def standalone_method
15
+ "a/b/c"
16
+ end
17
+
18
+ def satisified_dependent_method
19
+ "-#{local}-"
20
+ end
21
+
22
+ def unsatisfied_dependent_method
23
+ "-#{remote}-"
24
+ end
25
+
26
+ def shadow
27
+ "-#{super}-"
28
+ end
29
+
30
+ def remote_shadow
31
+ "-#{super}-"
32
+ end
33
+ end
34
+ end
35
+
36
+ let(:local_data) { { :id => 1, :local => 'data', :shadow => 'x' } }
37
+ let(:remote_data) { local_data.merge(:remote => 'DATA', :remote_shadow => 'X') }
38
+
39
+ subject { klass.new(local_data) }
40
+
41
+ it 'does not call methods to #inspect' do
42
+ subject.should_not_receive(:shadow)
43
+ subject.inspect
44
+ end
45
+
46
+ describe 'local attributes' do
47
+ before { klass.should_not_receive(:request) }
48
+
49
+ example 'allow access to local attributes' do
50
+ expect(subject.local).to eql('data')
51
+ end
52
+
53
+ example 'provide local attributes predicates' do
54
+ expect(subject.local?).to be true
55
+ end
56
+
57
+ example 'provide local attributes setters' do
58
+ subject.local = 'foo'
59
+ expect(subject.local).to eql('foo')
60
+ end
61
+
62
+ example 'allow access to local standalone methods' do
63
+ expect(subject.standalone_method).to eql('a/b/c')
64
+ end
65
+
66
+ example 'allow access to locally satisfiable methods' do
67
+ expect(subject.satisified_dependent_method).to eql('-data-')
68
+ end
69
+
70
+ example 'allow `super` access to shadowed attributes' do
71
+ expect(subject.shadow).to eql('-x-')
72
+ end
73
+
74
+ example 'do not create accessors on the base class itself' do
75
+ expect(klass.instance_methods(false)).to_not include(:local)
76
+ subject.local rescue nil
77
+ expect(klass.instance_methods(false)).to_not include(:local)
78
+ end
79
+ end
80
+
81
+ describe 'remote attributes' do
82
+ before do
83
+ stub_api_for(klass) do |api|
84
+ api.get('/things/1') do
85
+ [ 200, { 'Content-Type' => 'json' }, remote_data.to_json ]
86
+ end
87
+ end
88
+ end
89
+
90
+ example 'allow access to remote attributes' do
91
+ expect(subject.remote).to eql('DATA')
92
+ end
93
+
94
+ example 'provide remote attributes predicates' do
95
+ expect(subject.remote?).to be true
96
+ end
97
+
98
+ example 'provide remote attributes setters' do
99
+ subject.remote = 'foo'
100
+ expect(subject.remote).to eql('foo')
101
+ end
102
+
103
+ example 'allow multiple instances to access remote attributes' do
104
+ klass.should_receive(:request).exactly(9).times.and_call_original
105
+ 9.times { expect(klass.new(local_data).remote).to eql('DATA') }
106
+ end
107
+
108
+ example 'allow access to locally unsatisfiable methods' do
109
+ expect(subject.unsatisfied_dependent_method).to eql('-DATA-')
110
+ end
111
+
112
+ example 'allow `super` access to shadowed remote attributes' do
113
+ expect(subject.remote_shadow).to eql('-X-')
114
+ end
115
+
116
+ example 'do not create accessors on the base class itself' do
117
+ expect(klass.instance_methods(false)).to_not include(:remote)
118
+ subject.remote rescue nil
119
+ expect(klass.instance_methods(false)).to_not include(:remote)
120
+ end
121
+ end
122
+
123
+ describe 'unsatisfiable attributes' do
124
+ before do
125
+ stub_api_for(klass) do |api|
126
+ api.get('/things/1') do
127
+ [ 200, { 'Content-Type' => 'json' }, remote_data.to_json ]
128
+ end
129
+ end
130
+ end
131
+
132
+ example 'raise an exception when accessing an unknown attribute' do
133
+ expect { subject.unknown_attribute }.to raise_error(NoMethodError)
134
+ end
135
+
136
+ example 'do not create accessors on the base class itself' do
137
+ expect(klass.instance_methods(false)).to_not include(:local)
138
+ subject.unknown_attribute rescue nil
139
+ expect(klass.instance_methods(false)).to_not include(:local)
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,309 @@
1
+ require 'spec_helper'
2
+ require 'json'
3
+
4
+ describe Her::LazyRelations do
5
+ let(:klass) do |*args|
6
+ ctx = self
7
+
8
+ Class.new do
9
+ include Her::Model
10
+ include Her::LazyRelations
11
+
12
+ lazy :relation, ctx.related_class
13
+ lazy :chained, self
14
+ lazy_collection :relations, ctx.related_class
15
+ lazy_collection :parents, self
16
+
17
+ def request_path
18
+ "/parents/#{id}"
19
+ end
20
+ end
21
+ end
22
+
23
+ let(:related_class) do
24
+ Class.new do
25
+ include Her::Model
26
+
27
+ def request_path
28
+ "/things/#{id}"
29
+ end
30
+
31
+ def standalone_method
32
+ "a/b/c"
33
+ end
34
+
35
+ def satisified_dependent_method
36
+ "-#{local}-"
37
+ end
38
+
39
+ def unsatisfied_dependent_method
40
+ "-#{remote}-"
41
+ end
42
+
43
+ def shadow
44
+ "-#{super}-"
45
+ end
46
+
47
+ def remote_shadow
48
+ "-#{super}-"
49
+ end
50
+ end
51
+ end
52
+
53
+ let(:local_data) { { :id => 1, :local => 'data', :shadow => 'x' } }
54
+ let(:remote_data) { local_data.merge(:remote => 'DATA', :remote_shadow => 'X') }
55
+
56
+ describe '.lazy' do
57
+ subject { klass.new(:relation => local_data).relation }
58
+
59
+ it { should be_a(related_class) }
60
+
61
+ it 'does not call methods to #inspect' do
62
+ subject.should_not_receive(:shadow)
63
+ subject.inspect
64
+ end
65
+
66
+ describe 'local attributes' do
67
+ before { related_class.should_not_receive(:request) }
68
+
69
+ example 'allow access to local attributes' do
70
+ expect(subject.local).to eql('data')
71
+ end
72
+
73
+ example 'provide local attributes predicates' do
74
+ expect(subject.local?).to be true
75
+ end
76
+
77
+ example 'provide local attributes setters' do
78
+ subject.local = 'foo'
79
+ expect(subject.local).to eql('foo')
80
+ end
81
+
82
+ example 'allow access to local standalone methods' do
83
+ expect(subject.standalone_method).to eql('a/b/c')
84
+ end
85
+
86
+ example 'allow access to locally satisfiable methods' do
87
+ expect(subject.satisified_dependent_method).to eql('-data-')
88
+ end
89
+
90
+ example 'allow `super` access to shadowed attributes' do
91
+ expect(subject.shadow).to eql('-x-')
92
+ end
93
+ end
94
+
95
+ describe 'remote attributes' do
96
+ before do
97
+ stub_api_for(related_class) do |api|
98
+ api.get('/things/1') do
99
+ [ 200, { 'Content-Type' => 'json' }, remote_data.to_json ]
100
+ end
101
+ end
102
+ end
103
+
104
+ example 'allow access to remote attributes' do
105
+ expect(subject.remote).to eql('DATA')
106
+ end
107
+
108
+ example 'provide remote attributes predicates' do
109
+ expect(subject.remote?).to be true
110
+ end
111
+
112
+ example 'provide remote attributes setters' do
113
+ subject.remote = 'foo'
114
+ expect(subject.remote).to eql('foo')
115
+ end
116
+
117
+ example 'allow multiple instances to access remote attributes' do
118
+ related_class.should_receive(:request) \
119
+ .exactly(9).times \
120
+ .and_call_original
121
+
122
+ 9.times do
123
+ subject = klass.new(:relation => local_data).relation
124
+ expect(subject.remote).to eql('DATA')
125
+ end
126
+ end
127
+
128
+ example 'allow access to locally unsatisfiable methods' do
129
+ expect(subject.unsatisfied_dependent_method).to eql('-DATA-')
130
+ end
131
+
132
+ example 'allow `super` access to shadowed remote attributes' do
133
+ expect(subject.remote_shadow).to eql('-X-')
134
+ end
135
+ end
136
+
137
+ describe 'remote relations' do
138
+ before do
139
+ stub_api_for(klass) do |api|
140
+ api.get('/parents/1') do
141
+ data = { :id => 1, :relation => local_data }
142
+ [ 200, { 'Content-Type' => 'json' }, data.to_json ]
143
+ end
144
+ end
145
+
146
+ stub_api_for(related_class) do |api|
147
+ api.get('/things/1') do
148
+ [ 200, { 'Content-Type' => 'json' }, remote_data.to_json ]
149
+ end
150
+ end
151
+ end
152
+
153
+ subject { klass.new(:chained => { :id => 1 }) }
154
+
155
+ example 'allow chained lookups of lazy relations' do
156
+ expect(subject.chained.relation.remote).to eql('DATA')
157
+ end
158
+ end
159
+
160
+ describe 'null relations' do
161
+ subject { klass.new(:relation => nil) }
162
+
163
+ example 'do not return new instances' do
164
+ expect(subject.relation).to be nil
165
+ end
166
+ end
167
+
168
+ describe 'unsatisfiable attributes' do
169
+ before do
170
+ stub_api_for(klass) do |api|
171
+ api.get('/things/1') do
172
+ [ 200, { 'Content-Type' => 'json' }, remote_data.to_json ]
173
+ end
174
+ end
175
+ end
176
+
177
+ example 'raise an exception when accessing an unknown attribute' do
178
+ expect { subject.unknown_attribute }.to raise_error(NoMethodError)
179
+ end
180
+ end
181
+ end
182
+
183
+ describe '.lazy_collection' do
184
+ subject { klass.new(:relations => [local_data]).relations.first }
185
+
186
+ it { should be_a(related_class) }
187
+
188
+ it 'does not call methods to #inspect' do
189
+ subject.should_not_receive(:shadow)
190
+ subject.inspect
191
+ end
192
+
193
+ describe 'local attributes' do
194
+ before { related_class.should_not_receive(:request) }
195
+
196
+ example 'allow access to local attributes' do
197
+ expect(subject.local).to eql('data')
198
+ end
199
+
200
+ example 'provide local attributes predicates' do
201
+ expect(subject.local?).to be true
202
+ end
203
+
204
+ example 'provide local attributes setters' do
205
+ subject.local = 'foo'
206
+ expect(subject.local).to eql('foo')
207
+ end
208
+
209
+ example 'allow access to local standalone methods' do
210
+ expect(subject.standalone_method).to eql('a/b/c')
211
+ end
212
+
213
+ example 'allow access to locally satisfiable methods' do
214
+ expect(subject.satisified_dependent_method).to eql('-data-')
215
+ end
216
+
217
+ example 'allow `super` access to shadowed attributes' do
218
+ expect(subject.shadow).to eql('-x-')
219
+ end
220
+ end
221
+
222
+ describe 'remote attributes' do
223
+ before do
224
+ stub_api_for(related_class) do |api|
225
+ api.get('/things/1') do
226
+ [ 200, { 'Content-Type' => 'json' }, remote_data.to_json ]
227
+ end
228
+ end
229
+ end
230
+
231
+ example 'allow access to remote attributes' do
232
+ expect(subject.remote).to eql('DATA')
233
+ end
234
+
235
+ example 'provide remote attributes predicates' do
236
+ expect(subject.remote?).to be true
237
+ end
238
+
239
+ example 'provide remote attributes setters' do
240
+ subject.remote = 'foo'
241
+ expect(subject.remote).to eql('foo')
242
+ end
243
+
244
+ example 'allow multiple instances to access remote attributes' do
245
+ related_class.should_receive(:request) \
246
+ .exactly(9).times \
247
+ .and_call_original
248
+
249
+ 9.times do
250
+ subject = klass.new(:relations => [local_data]).relations.first
251
+ expect(subject.remote).to eql('DATA')
252
+ end
253
+ end
254
+
255
+ example 'allow access to locally unsatisfiable methods' do
256
+ expect(subject.unsatisfied_dependent_method).to eql('-DATA-')
257
+ end
258
+
259
+ example 'allow `super` access to shadowed remote attributes' do
260
+ expect(subject.remote_shadow).to eql('-X-')
261
+ end
262
+ end
263
+
264
+ describe 'remote relations' do
265
+ before do
266
+ stub_api_for(klass) do |api|
267
+ api.get('/parents/1') do
268
+ data = { :id => 1, :parents => [{ :id => 1, :relation => local_data }] }
269
+ [ 200, { 'Content-Type' => 'json' }, data.to_json ]
270
+ end
271
+ end
272
+
273
+ stub_api_for(related_class) do |api|
274
+ api.get('/things/1') do
275
+ [ 200, { 'Content-Type' => 'json' }, remote_data.to_json ]
276
+ end
277
+ end
278
+ end
279
+
280
+ subject { klass.new(:id => 1) }
281
+
282
+ example 'allow chained lookups of lazy relations' do
283
+ expect(subject.parents[0].relation.remote).to eql('DATA')
284
+ end
285
+ end
286
+
287
+ describe 'null relations' do
288
+ subject { klass.new(:relations => nil) }
289
+
290
+ example 'return an empty list' do
291
+ expect(subject.relations).to be_empty
292
+ end
293
+ end
294
+
295
+ describe 'unsatisfiable attributes' do
296
+ before do
297
+ stub_api_for(klass) do |api|
298
+ api.get('/things/1') do
299
+ [ 200, { 'Content-Type' => 'json' }, remote_data.to_json ]
300
+ end
301
+ end
302
+ end
303
+
304
+ example 'raise an exception when accessing an unknown attribute' do
305
+ expect { subject.unknown_attribute }.to raise_error(NoMethodError)
306
+ end
307
+ end
308
+ end
309
+ end