praxis-blueprints 2.0.1 → 2.1

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 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