praxis-blueprints 3.0 → 3.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +35 -0
- data/.travis.yml +10 -5
- data/CHANGELOG.md +27 -0
- data/Gemfile +1 -0
- data/Guardfile +13 -7
- data/README.md +8 -3
- data/Rakefile +4 -3
- data/lib/praxis-blueprints.rb +2 -1
- data/lib/praxis-blueprints/blueprint.rb +96 -87
- data/lib/praxis-blueprints/collection_view.rb +15 -10
- data/lib/praxis-blueprints/config_hash.rb +15 -12
- data/lib/praxis-blueprints/field_expander.rb +60 -48
- data/lib/praxis-blueprints/finalizable.rb +4 -8
- data/lib/praxis-blueprints/renderer.rb +50 -19
- data/lib/praxis-blueprints/version.rb +2 -1
- data/lib/praxis-blueprints/view.rb +22 -29
- data/praxis-blueprints.gemspec +37 -24
- data/spec/praxis-blueprints/blueprint_spec.rb +84 -58
- data/spec/praxis-blueprints/collection_view_spec.rb +16 -7
- data/spec/praxis-blueprints/config_hash_spec.rb +64 -0
- data/spec/praxis-blueprints/field_expander_spec.rb +46 -38
- data/spec/praxis-blueprints/renderer_spec.rb +128 -40
- data/spec/praxis-blueprints/view_spec.rb +24 -10
- data/spec/spec_helper.rb +14 -14
- data/spec/support/spec_blueprints.rb +32 -8
- metadata +112 -35
data/praxis-blueprints.gemspec
CHANGED
@@ -1,38 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
lib = File.expand_path('../lib', __FILE__)
|
2
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
4
|
require 'praxis-blueprints/version'
|
4
5
|
|
5
6
|
Gem::Specification.new do |spec|
|
6
|
-
spec.name =
|
7
|
+
spec.name = 'praxis-blueprints'
|
7
8
|
spec.version = Praxis::BLUEPRINTS_VERSION
|
8
|
-
spec.authors = [
|
9
|
-
spec.summary =
|
10
|
-
spec.description =
|
11
|
-
|
12
|
-
|
9
|
+
spec.authors = ['Josep M. Blanquer', 'Dane Jensen']
|
10
|
+
spec.summary = 'Attributes, views, rendering and example generation for common Blueprint Structures.'
|
11
|
+
spec.description = <<-EOF
|
12
|
+
Praxis Blueprints is a library that allows for defining a reusable class
|
13
|
+
structures that has a set of typed attributes and a set of views with which
|
14
|
+
to render them. Instantiations of Blueprints resemble ruby Structs which
|
15
|
+
respond to methods of the attribute names. Rendering is format-agnostic in
|
16
|
+
that it results in a structured hash instead of an encoded string.
|
17
|
+
Blueprints can automatically generate object structures that follow the
|
18
|
+
attribute definitions.
|
19
|
+
EOF
|
20
|
+
spec.email = ['blanquer@gmail.com', 'dane.jensen@gmail.com']
|
13
21
|
|
14
|
-
spec.homepage =
|
15
|
-
spec.license =
|
16
|
-
spec.required_ruby_version =
|
22
|
+
spec.homepage = 'https://github.com/rightscale/praxis-blueprints'
|
23
|
+
spec.license = 'MIT'
|
24
|
+
spec.required_ruby_version = '>=2.1'
|
17
25
|
|
18
26
|
spec.files = `git ls-files -z`.split("\x0")
|
19
27
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
-
spec.require_paths = [
|
28
|
+
spec.require_paths = ['lib']
|
21
29
|
|
22
|
-
spec.add_runtime_dependency(
|
23
|
-
spec.add_runtime_dependency(
|
24
|
-
spec.add_runtime_dependency(
|
30
|
+
spec.add_runtime_dependency('randexp', ['~> 0'])
|
31
|
+
spec.add_runtime_dependency('attributor', ['>= 5.5'])
|
32
|
+
spec.add_runtime_dependency('activesupport', ['>= 3'])
|
25
33
|
|
26
|
-
spec.add_development_dependency
|
27
|
-
spec.add_development_dependency
|
34
|
+
spec.add_development_dependency 'bundler'
|
35
|
+
spec.add_development_dependency 'rake'
|
28
36
|
|
29
|
-
spec.add_development_dependency(
|
30
|
-
spec.add_development_dependency(
|
31
|
-
spec.add_development_dependency(
|
32
|
-
spec.add_development_dependency(
|
33
|
-
spec.add_development_dependency(
|
34
|
-
spec.add_development_dependency(
|
35
|
-
spec.add_development_dependency(
|
36
|
-
spec.add_development_dependency(
|
37
|
-
spec.add_development_dependency(
|
37
|
+
spec.add_development_dependency('redcarpet', ['< 3.0'])
|
38
|
+
spec.add_development_dependency('yard')
|
39
|
+
spec.add_development_dependency('guard', ['~> 2'])
|
40
|
+
spec.add_development_dependency('guard-rspec', ['>= 0'])
|
41
|
+
spec.add_development_dependency('rspec')
|
42
|
+
spec.add_development_dependency('rspec-its')
|
43
|
+
spec.add_development_dependency('rspec-collection_matchers')
|
44
|
+
spec.add_development_dependency('pry')
|
45
|
+
spec.add_development_dependency('pry-byebug')
|
46
|
+
spec.add_development_dependency('pry-stack_explorer')
|
47
|
+
spec.add_development_dependency('fuubar')
|
48
|
+
spec.add_development_dependency('coveralls')
|
49
|
+
spec.add_development_dependency 'rubocop'
|
50
|
+
spec.add_development_dependency 'guard-rubocop'
|
38
51
|
end
|
@@ -1,10 +1,10 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
3
|
|
3
4
|
describe Praxis::Blueprint do
|
4
|
-
|
5
5
|
subject(:blueprint_class) { Person }
|
6
6
|
|
7
|
-
its(:family){ should eq('hash') }
|
7
|
+
its(:family) { should eq('hash') }
|
8
8
|
|
9
9
|
context 'deterministic examples' do
|
10
10
|
it 'works' do
|
@@ -52,7 +52,6 @@ describe Praxis::Blueprint do
|
|
52
52
|
its(:finalized?) { should be(true) }
|
53
53
|
end
|
54
54
|
|
55
|
-
|
56
55
|
context '.finalize on that subclass' do
|
57
56
|
before do
|
58
57
|
blueprint_class.should_receive(:_finalize!).and_call_original
|
@@ -60,9 +59,7 @@ describe Praxis::Blueprint do
|
|
60
59
|
end
|
61
60
|
|
62
61
|
its(:finalized?) { should be(true) }
|
63
|
-
|
64
62
|
end
|
65
|
-
|
66
63
|
end
|
67
64
|
|
68
65
|
context 'creating a base abstract Blueprint class without attributes' do
|
@@ -76,7 +73,6 @@ describe Praxis::Blueprint do
|
|
76
73
|
blueprint_class.finalize!
|
77
74
|
blueprint_class.finalized?.should be(true)
|
78
75
|
end
|
79
|
-
|
80
76
|
end
|
81
77
|
|
82
78
|
it 'has an inner Struct class for the attributes' do
|
@@ -88,7 +84,6 @@ describe Praxis::Blueprint do
|
|
88
84
|
it 'sorta has view objects' do
|
89
85
|
blueprint_class.views.should have_key(:default)
|
90
86
|
end
|
91
|
-
|
92
87
|
end
|
93
88
|
|
94
89
|
context 'an instance' do
|
@@ -107,30 +102,34 @@ describe Praxis::Blueprint do
|
|
107
102
|
|
108
103
|
context 'validation' do
|
109
104
|
subject(:errors) { blueprint_class.validate(blueprint_instance) }
|
110
|
-
|
111
|
-
it { should be_empty }
|
112
|
-
end
|
105
|
+
it { should be_empty }
|
113
106
|
end
|
114
107
|
end
|
115
108
|
|
116
|
-
|
117
109
|
context 'from Blueprint.example' do
|
118
|
-
subject(:blueprint_instance)
|
110
|
+
subject(:blueprint_instance) do
|
111
|
+
blueprint_class.example('ExamplePerson',
|
112
|
+
address: nil,
|
113
|
+
prior_addresses: [],
|
114
|
+
work_address: nil,
|
115
|
+
myself: nil,
|
116
|
+
friends: []
|
117
|
+
)
|
118
|
+
end
|
119
119
|
it_behaves_like 'a blueprint instance'
|
120
120
|
end
|
121
121
|
|
122
122
|
context 'wrapping an object' do
|
123
|
-
|
124
123
|
let(:data) do
|
125
124
|
{
|
126
125
|
name: 'Bob',
|
127
126
|
full_name: FullName.example,
|
128
|
-
address:
|
129
|
-
email:
|
127
|
+
address: nil,
|
128
|
+
email: 'bob@example.com',
|
130
129
|
aliases: [],
|
131
130
|
prior_addresses: [],
|
132
|
-
parents: { father: Randgen.first_name, mother: Randgen.first_name},
|
133
|
-
href:
|
131
|
+
parents: { father: Randgen.first_name, mother: Randgen.first_name },
|
132
|
+
href: 'www.example.com',
|
134
133
|
alive: true
|
135
134
|
}
|
136
135
|
end
|
@@ -139,7 +138,6 @@ describe Praxis::Blueprint do
|
|
139
138
|
|
140
139
|
subject(:blueprint_instance) { blueprint_class.new(resource) }
|
141
140
|
|
142
|
-
|
143
141
|
it_behaves_like 'a blueprint instance'
|
144
142
|
|
145
143
|
context 'creating additional blueprint instances from that object' do
|
@@ -148,7 +146,7 @@ describe Praxis::Blueprint do
|
|
148
146
|
context 'with caching enabled' do
|
149
147
|
around do |example|
|
150
148
|
Praxis::Blueprint.caching_enabled = true
|
151
|
-
Praxis::Blueprint.cache = Hash.new { |h,k| h[k] =
|
149
|
+
Praxis::Blueprint.cache = Hash.new { |h, k| h[k] = {} }
|
152
150
|
example.run
|
153
151
|
|
154
152
|
Praxis::Blueprint.caching_enabled = false
|
@@ -165,27 +163,31 @@ describe Praxis::Blueprint do
|
|
165
163
|
context 'with caching disabled' do
|
166
164
|
it { should_not be blueprint_instance }
|
167
165
|
end
|
168
|
-
|
169
166
|
end
|
170
|
-
|
171
167
|
end
|
172
|
-
|
173
168
|
end
|
174
169
|
|
175
170
|
context '.describe' do
|
176
|
-
let(:shallow
|
171
|
+
let(:shallow) { false }
|
177
172
|
let(:example_object) { nil }
|
178
173
|
|
179
174
|
before do
|
180
|
-
expect(blueprint_class.attribute.type).to receive(:describe).with(shallow, example: example_object).and_call_original
|
175
|
+
expect(blueprint_class.attribute.type).to receive(:describe).with(shallow, example: example_object).ordered.and_call_original
|
181
176
|
end
|
182
177
|
|
183
178
|
context 'for non-shallow descriptions' do
|
184
|
-
|
179
|
+
before do
|
180
|
+
# Describing a Person also describes the :myself and :friends attributes. They are both a Person and a Coll of Person.
|
181
|
+
# This means that Person type `describe` is called two more times, thes times with shallow=true
|
182
|
+
expect(blueprint_class.attribute.type).to receive(:describe).with(true, example: example_object).twice.and_call_original
|
183
|
+
end
|
184
|
+
|
185
|
+
subject(:output) { blueprint_class.describe }
|
185
186
|
|
186
|
-
its([:name]){ should eq(blueprint_class.name)}
|
187
|
-
its([:id]){ should eq(blueprint_class.id)}
|
188
|
-
its([:views]){ should be_kind_of(Hash)}
|
187
|
+
its([:name]) { should eq(blueprint_class.name) }
|
188
|
+
its([:id]) { should eq(blueprint_class.id) }
|
189
|
+
its([:views]) { should be_kind_of(Hash) }
|
190
|
+
its(:keys) { should_not include(:anonymous) }
|
189
191
|
it 'should contain the an entry for each view' do
|
190
192
|
subject[:views].keys.should include(:default, :current, :extended, :master)
|
191
193
|
end
|
@@ -197,6 +199,23 @@ describe Praxis::Blueprint do
|
|
197
199
|
it 'should not include views' do
|
198
200
|
blueprint_class.describe(true).key?(:views).should be(false)
|
199
201
|
end
|
202
|
+
context 'for anonymous blueprints' do
|
203
|
+
let(:blueprint_class) do
|
204
|
+
klass = Class.new(Praxis::Blueprint) do
|
205
|
+
anonymous_type
|
206
|
+
attributes do
|
207
|
+
attribute :name, String
|
208
|
+
end
|
209
|
+
end
|
210
|
+
klass.finalize!
|
211
|
+
klass
|
212
|
+
end
|
213
|
+
it 'reports their anonymous-ness' do
|
214
|
+
description = blueprint_class.describe(true)
|
215
|
+
expect(description).to have_key(:anonymous)
|
216
|
+
expect(description[:anonymous]).to be(true)
|
217
|
+
end
|
218
|
+
end
|
200
219
|
end
|
201
220
|
|
202
221
|
context 'with an example' do
|
@@ -205,13 +224,21 @@ describe Praxis::Blueprint do
|
|
205
224
|
let(:shallow) { false }
|
206
225
|
|
207
226
|
subject(:output) { blueprint_class.describe(false, example: example) }
|
227
|
+
before do
|
228
|
+
# Describing a Person also describes the :myself and :friends attributes. They are both a Person and a Coll of Person.
|
229
|
+
# This means that Person type `describe` is called two more times, thes times with shallow=true
|
230
|
+
expect(blueprint_class.attribute.type).to receive(:describe)
|
231
|
+
.with(true, example: an_instance_of(blueprint_class.attribute.type)).twice.and_call_original
|
232
|
+
end
|
208
233
|
|
209
234
|
it 'outputs examples for leaf values using the provided example' do
|
210
235
|
output[:attributes][:name][:example].should eq example.name
|
211
236
|
output[:attributes][:age][:example].should eq example.age
|
212
237
|
|
238
|
+
output[:attributes][:aliases].should have_key(:example)
|
239
|
+
output[:attributes][:aliases][:example].should eq example.aliases.dump
|
240
|
+
|
213
241
|
output[:attributes][:full_name].should_not have_key(:example)
|
214
|
-
output[:attributes][:aliases].should_not have_key(:example)
|
215
242
|
|
216
243
|
parents_attributes = output[:attributes][:parents][:type][:attributes]
|
217
244
|
parents_attributes[:father][:example].should eq example.parents.father
|
@@ -221,7 +248,7 @@ describe Praxis::Blueprint do
|
|
221
248
|
end
|
222
249
|
|
223
250
|
context '.validate' do
|
224
|
-
let(:hash) { {name: 'bob'} }
|
251
|
+
let(:hash) { { name: 'bob' } }
|
225
252
|
let(:person) { Person.load(hash) }
|
226
253
|
subject(:errors) { person.validate }
|
227
254
|
|
@@ -230,7 +257,7 @@ describe Praxis::Blueprint do
|
|
230
257
|
end
|
231
258
|
|
232
259
|
context 'with invalid sub-attribute' do
|
233
|
-
let(:hash) { {name: 'bob', address: {state:
|
260
|
+
let(:hash) { { name: 'bob', address: { state: 'ME' } } }
|
234
261
|
|
235
262
|
it { should have(1).item }
|
236
263
|
its(:first) { should =~ /Attribute \$.address.state/ }
|
@@ -238,9 +265,9 @@ describe Praxis::Blueprint do
|
|
238
265
|
|
239
266
|
context 'for objects of the wrong type' do
|
240
267
|
it 'raises an error' do
|
241
|
-
expect
|
268
|
+
expect do
|
242
269
|
Person.validate(Object.new)
|
243
|
-
|
270
|
+
end.to raise_error(ArgumentError, /Error validating .* as Person for an object of type Object/)
|
244
271
|
end
|
245
272
|
end
|
246
273
|
end
|
@@ -248,9 +275,9 @@ describe Praxis::Blueprint do
|
|
248
275
|
context '.load' do
|
249
276
|
let(:hash) do
|
250
277
|
{
|
251
|
-
:
|
252
|
-
:
|
253
|
-
:
|
278
|
+
name: 'Bob',
|
279
|
+
full_name: { first: 'Robert', last: 'Robertson' },
|
280
|
+
address: { street: 'main', state: 'OR' }
|
254
281
|
}
|
255
282
|
end
|
256
283
|
subject(:person) { Person.load(hash) }
|
@@ -267,19 +294,16 @@ describe Praxis::Blueprint do
|
|
267
294
|
it { should be_kind_of(FullName) }
|
268
295
|
end
|
269
296
|
end
|
270
|
-
|
271
297
|
end
|
272
298
|
|
273
|
-
|
274
299
|
context 'decorators' do
|
275
300
|
let(:name) { 'Soren II' }
|
276
301
|
|
277
302
|
let(:object) { Person.example.object }
|
278
303
|
subject(:person) { Person.new(object, decorators) }
|
279
304
|
|
280
|
-
|
281
305
|
context 'as a hash' do
|
282
|
-
let(:decorators) { {name: name} }
|
306
|
+
let(:decorators) { { name: name } }
|
283
307
|
it do
|
284
308
|
person.name.should eq('Soren II')
|
285
309
|
end
|
@@ -287,7 +311,7 @@ describe Praxis::Blueprint do
|
|
287
311
|
its(:name) { should be(name) }
|
288
312
|
|
289
313
|
context 'an additional instance with the equivalent hash' do
|
290
|
-
subject(:additional_person) { Person.new(object,
|
314
|
+
subject(:additional_person) { Person.new(object, name: name) }
|
291
315
|
it { should_not be person }
|
292
316
|
end
|
293
317
|
|
@@ -303,7 +327,7 @@ describe Praxis::Blueprint do
|
|
303
327
|
end
|
304
328
|
|
305
329
|
context 'as an object' do
|
306
|
-
let(:decorators) { double(
|
330
|
+
let(:decorators) { double('decorators', name: name) }
|
307
331
|
its(:name) { should be(name) }
|
308
332
|
|
309
333
|
context 'an additional instance with the same object' do
|
@@ -311,13 +335,10 @@ describe Praxis::Blueprint do
|
|
311
335
|
it { should_not be person }
|
312
336
|
end
|
313
337
|
end
|
314
|
-
|
315
338
|
end
|
316
339
|
|
317
|
-
|
318
340
|
context 'with a provided :reference option on attributes' do
|
319
341
|
context 'that does not match the value set on the class' do
|
320
|
-
|
321
342
|
subject(:mismatched_reference) do
|
322
343
|
Class.new(Praxis::Blueprint) do
|
323
344
|
self.reference = Class.new(Praxis::Blueprint)
|
@@ -326,15 +347,13 @@ describe Praxis::Blueprint do
|
|
326
347
|
end
|
327
348
|
|
328
349
|
it 'should raise an error' do
|
329
|
-
expect
|
350
|
+
expect do
|
330
351
|
mismatched_reference.attributes
|
331
|
-
|
352
|
+
end.to raise_error
|
332
353
|
end
|
333
|
-
|
334
354
|
end
|
335
355
|
end
|
336
356
|
|
337
|
-
|
338
357
|
context '.example' do
|
339
358
|
context 'with some attribute values provided' do
|
340
359
|
let(:name) { 'Sir Bobbert' }
|
@@ -346,7 +365,6 @@ describe Praxis::Blueprint do
|
|
346
365
|
context '.render' do
|
347
366
|
let(:person) { Person.example('1') }
|
348
367
|
it 'is an alias to dump' do
|
349
|
-
|
350
368
|
person.object.contents
|
351
369
|
rendered = Person.render(person, view: :default)
|
352
370
|
dumped = Person.dump(person, view: :default)
|
@@ -360,10 +378,7 @@ describe Praxis::Blueprint do
|
|
360
378
|
let(:render_opts) { {} }
|
361
379
|
subject(:output) { person.render(view: view_name, **render_opts) }
|
362
380
|
|
363
|
-
|
364
|
-
|
365
381
|
context 'with a sub-attribute that is a blueprint' do
|
366
|
-
|
367
382
|
it { should have_key(:name) }
|
368
383
|
it { should have_key(:address) }
|
369
384
|
it 'renders the sub-attribute correctly' do
|
@@ -372,14 +387,13 @@ describe Praxis::Blueprint do
|
|
372
387
|
end
|
373
388
|
|
374
389
|
it 'reports a dump error with the appropriate context' do
|
375
|
-
person.address.should_receive(:state).and_raise(
|
376
|
-
expect
|
390
|
+
person.address.should_receive(:state).and_raise('Kaboom')
|
391
|
+
expect do
|
377
392
|
person.render(view: view_name, context: ['special_root'])
|
378
|
-
|
393
|
+
end.to raise_error(/Error while dumping attribute state of type Address for context special_root.address. Reason: .*Kaboom/)
|
379
394
|
end
|
380
395
|
end
|
381
396
|
|
382
|
-
|
383
397
|
context 'with sub-attribute that is an Attributor::Model' do
|
384
398
|
it { should have_key(:full_name) }
|
385
399
|
it 'renders the model correctly' do
|
@@ -391,7 +405,7 @@ describe Praxis::Blueprint do
|
|
391
405
|
|
392
406
|
context 'using the `fields` option' do
|
393
407
|
context 'as a hash' do
|
394
|
-
subject(:output) { person.render(fields: {address: {state: true}}) }
|
408
|
+
subject(:output) { person.render(fields: { address: { state: true } }) }
|
395
409
|
it 'should only have the address rendered' do
|
396
410
|
output.keys.should eq [:address]
|
397
411
|
end
|
@@ -408,4 +422,16 @@ describe Praxis::Blueprint do
|
|
408
422
|
end
|
409
423
|
end
|
410
424
|
|
425
|
+
context '.as_json_schema' do
|
426
|
+
it 'delegates to the attribute type' do
|
427
|
+
Person.attribute.type.should receive(:as_json_schema)
|
428
|
+
Person.as_json_schema
|
429
|
+
end
|
430
|
+
end
|
431
|
+
context '.json_schema_type' do
|
432
|
+
it 'delegates to the attribute type' do
|
433
|
+
Person.attribute.type.should receive(:json_schema_type)
|
434
|
+
Person.json_schema_type
|
435
|
+
end
|
436
|
+
end
|
411
437
|
end
|
@@ -1,17 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
1
2
|
require_relative '../spec_helper'
|
2
3
|
|
3
4
|
describe Praxis::CollectionView do
|
4
|
-
|
5
5
|
let(:root_context) { ['people'] }
|
6
6
|
|
7
7
|
let(:people) do
|
8
|
-
3
|
9
|
-
context = [
|
8
|
+
Array.new(3) do |i|
|
9
|
+
context = ['people', "at(#{i})"]
|
10
10
|
Person.example(context)
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
-
|
15
14
|
let(:contents_definition) do
|
16
15
|
proc do
|
17
16
|
attribute :name
|
@@ -28,10 +27,21 @@ describe Praxis::CollectionView do
|
|
28
27
|
end
|
29
28
|
|
30
29
|
context 'creating from a member view' do
|
31
|
-
|
32
30
|
it 'gets the proper contents' do
|
33
31
|
collection_view.contents.should eq member_view.contents
|
34
32
|
end
|
33
|
+
|
34
|
+
context 'lazy initializes its contents' do
|
35
|
+
it 'so it will not call contents until it is first needed' do
|
36
|
+
member_view.stub(:contents) { raise 'No!' }
|
37
|
+
expect { collection_view.name }.to_not raise_error
|
38
|
+
end
|
39
|
+
it 'when contents is needed, it will clone it from the member_view' do
|
40
|
+
# Twice is because we're callong member_view.contents for the right side of the equality
|
41
|
+
expect(member_view).to receive(:contents).twice.and_call_original
|
42
|
+
collection_view.contents.should eq member_view.contents
|
43
|
+
end
|
44
|
+
end
|
35
45
|
end
|
36
46
|
|
37
47
|
context 'creating with a set of attributes defined in a block' do
|
@@ -48,7 +58,7 @@ describe Praxis::CollectionView do
|
|
48
58
|
subject(:output) { collection_view.render(people, context: root_context) }
|
49
59
|
|
50
60
|
it { should be_kind_of(Array) }
|
51
|
-
it { should eq people.collect {|person| member_view.render(person)} }
|
61
|
+
it { should eq people.collect { |person| member_view.render(person) } }
|
52
62
|
end
|
53
63
|
|
54
64
|
context '#example' do
|
@@ -69,5 +79,4 @@ describe Praxis::CollectionView do
|
|
69
79
|
its([:attributes]) { should eq(member_view.describe[:attributes]) }
|
70
80
|
its([:type]) { should eq(:collection) }
|
71
81
|
end
|
72
|
-
|
73
82
|
end
|