praxis-blueprints 2.0.1 → 2.1

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: 66f44c7da0a75ef693bbe9ef10b3b592a700090d
4
- data.tar.gz: 282cad83972b06bb4b185daf03407dffc7f086ac
3
+ metadata.gz: 14169dd33330be68f4e42c2db5ed8884e243b893
4
+ data.tar.gz: c4fb566937d470785645d7899ba7351dfa174289
5
5
  SHA512:
6
- metadata.gz: 7a5256f895d130ff7c7fdc49e41f35899c775b118c226b44b559f7102a64564b87415760ce5f73531a82d275eb6b4cc2cada56e2fdadeea343a7ec4f76f009a2
7
- data.tar.gz: f1bf843427801470ca5539614fd75ef18172109e73689f945e45e6761cd414a026b0cb34bb6bda6dec10de8f53c3fa9d952e748926bf019f621b3777836ad6ca
6
+ metadata.gz: 23dbe2797e5ce3575608d619f56908e21fad55baa53934c2a78dccf594231def06d18b28dc24110b8f09b79a290284eae7cf68d313129925eb8ffd8b32a91c0a
7
+ data.tar.gz: 4dc85caab7023389dcda2a6974328e815850c07adfbc17ce32ffed83423c58803462bbf5cedb3e799d3fe8b72ecf7d7f46451c1d805f56686e8fa6d7baa8dbcb
data/CHANGELOG.md CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  ## next
4
4
 
5
+
6
+ ## 2.1
7
+
8
+ * Fixed handling of objects passed in to `Blueprint.example`.
9
+ * Bumped attributor dependnecy to >= 4.0.1
10
+
11
+
5
12
  ## 2.0.1
6
13
 
7
14
  * relaxed attributor dependency to >= 3.0
@@ -64,10 +64,14 @@ module Praxis
64
64
  'hash'
65
65
  end
66
66
 
67
- def self.describe(shallow=false,**opts)
67
+ def self.describe(shallow=false,example: nil, **opts)
68
68
  type_name = self.ancestors.find { |k| k.name && !k.name.empty? }.name
69
69
 
70
- description = self.attribute.type.describe(shallow,**opts).merge!(id: self.id, name: type_name)
70
+ if example
71
+ example = example.object
72
+ end
73
+
74
+ description = self.attribute.type.describe(shallow,example: example, **opts).merge!(id: self.id, name: type_name)
71
75
 
72
76
  unless shallow
73
77
  description[:views] = self.views.each_with_object({}) do |(view_name, view), hash|
@@ -1,3 +1,3 @@
1
1
  module Praxis
2
- BLUEPRINTS_VERSION = "2.0.1"
2
+ BLUEPRINTS_VERSION = "2.1"
3
3
  end
@@ -20,7 +20,7 @@ it results in a structured hash instead of an encoded string. Blueprints can aut
20
20
  spec.require_paths = ["lib"]
21
21
 
22
22
  spec.add_runtime_dependency(%q<randexp>, ["~> 0"])
23
- spec.add_runtime_dependency(%q<attributor>, [">= 3.0"])
23
+ spec.add_runtime_dependency(%q<attributor>, [">= 4.0.1"])
24
24
  spec.add_runtime_dependency(%q<activesupport>, [">= 3"])
25
25
 
26
26
  spec.add_development_dependency "bundler", "~> 1.6"
@@ -171,16 +171,18 @@ describe Praxis::Blueprint do
171
171
  end
172
172
 
173
173
  context '.describe' do
174
+ let(:shallow ) { false }
175
+ let(:example_object) { nil }
176
+
174
177
  before do
175
- expect(blueprint_class.attribute.type).to receive(:describe).and_return(type_describe)
178
+ expect(blueprint_class.attribute.type).to receive(:describe).with(shallow, example: example_object).and_call_original #.and_return(type_describe)
176
179
  end
177
- let(:type_describe){ {name: "Fake", id: "From Struct attr", other: "type attribute"} }
178
180
 
179
181
  context 'for non-shallow descriptions' do
180
182
  subject(:output){ blueprint_class.describe }
183
+
181
184
  its([:name]){ should eq(blueprint_class.name)}
182
185
  its([:id]){ should eq(blueprint_class.id)}
183
- its([:other]){ should eq("type attribute")}
184
186
  its([:views]){ should be_kind_of(Hash)}
185
187
  it 'should contain the an entry for each view' do
186
188
  subject[:views].keys.should include(:default, :current, :extended, :master)
@@ -188,11 +190,34 @@ describe Praxis::Blueprint do
188
190
  end
189
191
 
190
192
  context 'for shallow descriptions' do
193
+ let(:shallow) { true }
194
+
191
195
  it 'should not include views' do
192
196
  blueprint_class.describe(true).key?(:views).should be(false)
193
197
  end
194
198
  end
199
+
200
+ context 'with an example' do
201
+ let(:example) { blueprint_class.example }
202
+ let(:example_object) { example.object }
203
+ let(:shallow) { false }
204
+
205
+ subject(:output) { blueprint_class.describe(false, example: example) }
206
+
207
+ it 'outputs examples for leaf values using the provided example' do
208
+ output[:attributes][:name][:example].should eq example.name
209
+ output[:attributes][:age][:example].should eq example.age
210
+
211
+ output[:attributes][:full_name].should_not have_key(:example)
212
+ output[:attributes][:aliases].should_not have_key(:example)
213
+
214
+ parents_attributes = output[:attributes][:parents][:type][:attributes]
215
+ parents_attributes[:father][:example].should eq example.parents.father
216
+ parents_attributes[:mother][:example].should eq example.parents.mother
217
+ end
218
+ end
195
219
  end
220
+
196
221
  context '.validate' do
197
222
  let(:hash) { {name: 'bob'} }
198
223
  let(:person) { Person.load(hash) }
@@ -207,217 +232,217 @@ describe Praxis::Blueprint do
207
232
 
208
233
  it { should have(1).item }
209
234
  its(:first) { should =~ /Attribute \$.address.state/ }
210
- end
211
-
212
- context 'for objects of the wrong type' do
213
- it 'raises an error' do
214
- expect {
215
- Person.validate(Object.new)
216
- }.to raise_error(ArgumentError, /Error validating .* as Person for an object of type Object/)
217
- end
218
- end
219
- end
220
-
221
- context '.load' do
222
- let(:hash) do
223
- {
224
- :name => 'Bob',
225
- :full_name => {:first => 'Robert', :last => 'Robertson'},
226
- :address => {:street => 'main', :state => 'OR'}
227
- }
228
- end
229
- subject(:person) { Person.load(hash) }
230
-
231
- it { should be_kind_of(Person) }
232
-
233
- context 'recursively loading sub-attributes' do
234
- context 'for a Blueprint' do
235
- subject(:address) { person.address }
236
- it { should be_kind_of(Address) }
237
- end
238
- context 'for an Attributor::Model' do
239
- subject(:full_name) { person.full_name }
240
- it { should be_kind_of(FullName) }
241
- end
242
- end
243
-
244
- end
245
-
246
-
247
- context 'decorators' do
248
- let(:name) { 'Soren II' }
249
-
250
- let(:object) { Person.example.object }
251
- subject(:person) { Person.new(object, decorators) }
252
-
253
-
254
- context 'as a hash' do
255
- let(:decorators) { {name: name} }
256
- it do
257
- pers = person
258
- # binding.pry
259
- pers.name.should eq('Soren II')
260
- end
261
-
262
- its(:name) { should be(name) }
263
-
264
- context 'an additional instance with the equivalent hash' do
265
- subject(:additional_person) { Person.new(object, {name: name}) }
266
- it { should_not be person }
267
- end
268
-
269
- context 'an additional instance with the same hash object' do
270
- subject(:additional_person) { Person.new(object, decorators) }
271
- it { should_not be person }
272
- end
273
-
274
- context 'an instance of the same object without decorators' do
275
- subject(:additional_person) { Person.new(object) }
276
- it { should_not be person }
277
- end
278
- end
279
-
280
- context 'as an object' do
281
- let(:decorators) { double("decorators", name: name) }
282
- its(:name) { should be(name) }
283
-
284
- context 'an additional instance with the same object' do
285
- subject(:additional_person) { Person.new(object, decorators) }
286
- it { should_not be person }
287
- end
288
- end
235
+ end
289
236
 
290
- end
237
+ context 'for objects of the wrong type' do
238
+ it 'raises an error' do
239
+ expect {
240
+ Person.validate(Object.new)
241
+ }.to raise_error(ArgumentError, /Error validating .* as Person for an object of type Object/)
242
+ end
243
+ end
244
+ end
291
245
 
246
+ context '.load' do
247
+ let(:hash) do
248
+ {
249
+ :name => 'Bob',
250
+ :full_name => {:first => 'Robert', :last => 'Robertson'},
251
+ :address => {:street => 'main', :state => 'OR'}
252
+ }
253
+ end
254
+ subject(:person) { Person.load(hash) }
255
+
256
+ it { should be_kind_of(Person) }
257
+
258
+ context 'recursively loading sub-attributes' do
259
+ context 'for a Blueprint' do
260
+ subject(:address) { person.address }
261
+ it { should be_kind_of(Address) }
262
+ end
263
+ context 'for an Attributor::Model' do
264
+ subject(:full_name) { person.full_name }
265
+ it { should be_kind_of(FullName) }
266
+ end
267
+ end
292
268
 
293
- context 'with a provided :reference option on attributes' do
294
- context 'that does not match the value set on the class' do
269
+ end
295
270
 
296
- subject(:mismatched_reference) do
297
- Class.new(Praxis::Blueprint) do
298
- self.reference = Class.new(Praxis::Blueprint)
299
- attributes(reference: Class.new(Praxis::Blueprint)) {}
300
- end
301
- end
302
271
 
303
- it 'should raise an error' do
304
- expect {
305
- mismatched_reference.attributes
306
- }.to raise_error
307
- end
272
+ context 'decorators' do
273
+ let(:name) { 'Soren II' }
308
274
 
309
- end
310
- end
275
+ let(:object) { Person.example.object }
276
+ subject(:person) { Person.new(object, decorators) }
311
277
 
312
278
 
313
- context '.example' do
314
- context 'with some attribute values provided' do
315
- let(:name) { 'Sir Bobbert' }
316
- subject(:person) { Person.example(name: name) }
317
- its(:name) { should eq(name) }
318
- end
319
- end
279
+ context 'as a hash' do
280
+ let(:decorators) { {name: name} }
281
+ it do
282
+ pers = person
283
+ # binding.pry
284
+ pers.name.should eq('Soren II')
285
+ end
320
286
 
321
- context '.render' do
322
- let(:person) { Person.example }
323
- it 'is an alias to dump' do
324
- rendered = Person.render(person, view: :default)
325
- dumped = Person.dump(person, view: :default)
326
- expect(rendered).to eq(dumped)
327
- end
328
- end
287
+ its(:name) { should be(name) }
329
288
 
330
- context '#render' do
331
- let(:person) { Person.example }
332
- let(:view_name) { :default }
333
- let(:render_opts) { {} }
334
- subject(:output) { person.render(view: view_name, **render_opts) }
335
-
336
- context 'caches rendered views' do
337
- it 'in the instance, by view name' do
338
- person.instance_variable_get(:@rendered_views)[view_name].should be_nil
339
- person.render(view: view_name)
340
- cached = person.instance_variable_get(:@rendered_views)[view_name]
341
- cached.should_not be_nil
342
- end
289
+ context 'an additional instance with the equivalent hash' do
290
+ subject(:additional_person) { Person.new(object, {name: name}) }
291
+ it { should_not be person }
292
+ end
343
293
 
344
- it 'and does not re-render a view if one is already cached' do
345
- rendered1 = person.render(view: view_name)
346
- rendered2 = person.render(view: view_name)
347
- rendered1.should be(rendered2)
348
- end
294
+ context 'an additional instance with the same hash object' do
295
+ subject(:additional_person) { Person.new(object, decorators) }
296
+ it { should_not be person }
297
+ end
349
298
 
350
- context 'even when :fields are specified' do
351
- let(:render_opts) { {fields: {email: nil, age: nil, address: {street: nil, state: nil}}} }
299
+ context 'an instance of the same object without decorators' do
300
+ subject(:additional_person) { Person.new(object) }
301
+ it { should_not be person }
302
+ end
303
+ end
352
304
 
353
- it 'caches the output in a different key than just the view_name' do
354
- plain_view_render = person.render(view: view_name)
355
- fields_render = person.render(view: view_name, **render_opts)
356
- plain_view_render.should_not be(fields_render)
357
- end
305
+ context 'as an object' do
306
+ let(:decorators) { double("decorators", name: name) }
307
+ its(:name) { should be(name) }
358
308
 
359
- it 'it still caches the object if rendered for the same fields' do
360
- rendered1 = person.render(view: view_name, **render_opts)
361
- rendered2 = person.render(view: view_name, **render_opts)
362
- rendered1.should be(rendered2)
363
- end
309
+ context 'an additional instance with the same object' do
310
+ subject(:additional_person) { Person.new(object, decorators) }
311
+ it { should_not be person }
312
+ end
313
+ end
364
314
 
365
- it 'it still caches the object if rendered for the same fields (even from an "equivalent" hash)' do
366
- rendered1 = person.render(view: view_name, **render_opts)
315
+ end
367
316
 
368
- equivalent_render_opts = { fields: {age: nil, address: {state: nil, street: nil}, email: nil} }
369
- rendered2 = person.render(view: view_name, **equivalent_render_opts)
370
317
 
371
- rendered1.should be(rendered2)
372
- end
373
- end
318
+ context 'with a provided :reference option on attributes' do
319
+ context 'that does not match the value set on the class' do
374
320
 
375
- end
321
+ subject(:mismatched_reference) do
322
+ Class.new(Praxis::Blueprint) do
323
+ self.reference = Class.new(Praxis::Blueprint)
324
+ attributes(reference: Class.new(Praxis::Blueprint)) {}
325
+ end
326
+ end
376
327
 
377
- context 'with a sub-attribute that is a blueprint' do
328
+ it 'should raise an error' do
329
+ expect {
330
+ mismatched_reference.attributes
331
+ }.to raise_error
332
+ end
378
333
 
379
- it { should have_key(:name) }
380
- it { should have_key(:address) }
381
- it 'renders the sub-attribute correctly' do
382
- output[:address].should have_key(:street)
383
- output[:address].should have_key(:state)
384
- end
334
+ end
335
+ end
385
336
 
386
- it 'reports a dump error with the appropriate context' do
387
- person.address.should_receive(:state).and_raise("Kaboom")
388
- expect {
389
- person.render(view: view_name, context: ['special_root'])
390
- }.to raise_error(/Error while dumping attribute state of type Address for context special_root.address. Reason: .*Kaboom/)
391
- end
392
- end
393
337
 
338
+ context '.example' do
339
+ context 'with some attribute values provided' do
340
+ let(:name) { 'Sir Bobbert' }
341
+ subject(:person) { Person.example(name: name) }
342
+ its(:name) { should eq(name) }
343
+ end
344
+ end
394
345
 
395
- context 'with sub-attribute that is an Attributor::Model' do
396
- it { should have_key(:full_name) }
397
- it 'renders the model correctly' do
398
- output[:full_name].should be_kind_of(Hash)
399
- output[:full_name].should have_key(:first)
400
- output[:full_name].should have_key(:last)
401
- end
402
- end
346
+ context '.render' do
347
+ let(:person) { Person.example }
348
+ it 'is an alias to dump' do
349
+ rendered = Person.render(person, view: :default)
350
+ dumped = Person.dump(person, view: :default)
351
+ expect(rendered).to eq(dumped)
352
+ end
353
+ end
403
354
 
404
- context 'using the `fields` option' do
405
- context 'as a hash' do
406
- subject(:output) { person.render(view: view_name, fields: {address: { state: nil} } ) }
407
- it 'should only have the address rendered' do
408
- output.keys.should == [:address]
409
- end
410
- it 'address should only have state' do
411
- output[:address].keys.should == [:state]
412
- end
413
- end
414
- context 'as a simple array' do
415
- subject(:output) { person.render(view: view_name, fields: [:address] ) }
416
- it 'accepts it as the list of top-level attributes to be rendered' do
417
- output.keys.should == [:address]
418
- end
419
- end
420
- end
421
- end
355
+ context '#render' do
356
+ let(:person) { Person.example }
357
+ let(:view_name) { :default }
358
+ let(:render_opts) { {} }
359
+ subject(:output) { person.render(view: view_name, **render_opts) }
360
+
361
+ context 'caches rendered views' do
362
+ it 'in the instance, by view name' do
363
+ person.instance_variable_get(:@rendered_views)[view_name].should be_nil
364
+ person.render(view: view_name)
365
+ cached = person.instance_variable_get(:@rendered_views)[view_name]
366
+ cached.should_not be_nil
367
+ end
368
+
369
+ it 'and does not re-render a view if one is already cached' do
370
+ rendered1 = person.render(view: view_name)
371
+ rendered2 = person.render(view: view_name)
372
+ rendered1.should be(rendered2)
373
+ end
374
+
375
+ context 'even when :fields are specified' do
376
+ let(:render_opts) { {fields: {email: nil, age: nil, address: {street: nil, state: nil}}} }
377
+
378
+ it 'caches the output in a different key than just the view_name' do
379
+ plain_view_render = person.render(view: view_name)
380
+ fields_render = person.render(view: view_name, **render_opts)
381
+ plain_view_render.should_not be(fields_render)
382
+ end
383
+
384
+ it 'it still caches the object if rendered for the same fields' do
385
+ rendered1 = person.render(view: view_name, **render_opts)
386
+ rendered2 = person.render(view: view_name, **render_opts)
387
+ rendered1.should be(rendered2)
388
+ end
389
+
390
+ it 'it still caches the object if rendered for the same fields (even from an "equivalent" hash)' do
391
+ rendered1 = person.render(view: view_name, **render_opts)
392
+
393
+ equivalent_render_opts = { fields: {age: nil, address: {state: nil, street: nil}, email: nil} }
394
+ rendered2 = person.render(view: view_name, **equivalent_render_opts)
395
+
396
+ rendered1.should be(rendered2)
397
+ end
398
+ end
399
+
400
+ end
401
+
402
+ context 'with a sub-attribute that is a blueprint' do
403
+
404
+ it { should have_key(:name) }
405
+ it { should have_key(:address) }
406
+ it 'renders the sub-attribute correctly' do
407
+ output[:address].should have_key(:street)
408
+ output[:address].should have_key(:state)
409
+ end
410
+
411
+ it 'reports a dump error with the appropriate context' do
412
+ person.address.should_receive(:state).and_raise("Kaboom")
413
+ expect {
414
+ person.render(view: view_name, context: ['special_root'])
415
+ }.to raise_error(/Error while dumping attribute state of type Address for context special_root.address. Reason: .*Kaboom/)
416
+ end
417
+ end
418
+
419
+
420
+ context 'with sub-attribute that is an Attributor::Model' do
421
+ it { should have_key(:full_name) }
422
+ it 'renders the model correctly' do
423
+ output[:full_name].should be_kind_of(Hash)
424
+ output[:full_name].should have_key(:first)
425
+ output[:full_name].should have_key(:last)
426
+ end
427
+ end
428
+
429
+ context 'using the `fields` option' do
430
+ context 'as a hash' do
431
+ subject(:output) { person.render(view: view_name, fields: {address: { state: nil} } ) }
432
+ it 'should only have the address rendered' do
433
+ output.keys.should == [:address]
434
+ end
435
+ it 'address should only have state' do
436
+ output[:address].keys.should == [:state]
437
+ end
438
+ end
439
+ context 'as a simple array' do
440
+ subject(:output) { person.render(view: view_name, fields: [:address] ) }
441
+ it 'accepts it as the list of top-level attributes to be rendered' do
442
+ output.keys.should == [:address]
443
+ end
444
+ end
445
+ end
446
+ end
422
447
 
423
- end
448
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: praxis-blueprints
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: '2.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Josep M. Blanquer
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2015-07-08 00:00:00.000000000 Z
12
+ date: 2015-08-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: randexp
@@ -31,14 +31,14 @@ dependencies:
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: '3.0'
34
+ version: 4.0.1
35
35
  type: :runtime
36
36
  prerelease: false
37
37
  version_requirements: !ruby/object:Gem::Requirement
38
38
  requirements:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
- version: '3.0'
41
+ version: 4.0.1
42
42
  - !ruby/object:Gem::Dependency
43
43
  name: activesupport
44
44
  requirement: !ruby/object:Gem::Requirement