grape-entity 0.4.5 → 0.4.6
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 +4 -4
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +11 -33
- data/CHANGELOG.md +14 -0
- data/Gemfile +1 -1
- data/README.md +72 -10
- data/lib/grape_entity.rb +1 -0
- data/lib/grape_entity/delegator.rb +23 -0
- data/lib/grape_entity/delegator/base.rb +17 -0
- data/lib/grape_entity/delegator/fetchable_object.rb +11 -0
- data/lib/grape_entity/delegator/hash_object.rb +11 -0
- data/lib/grape_entity/delegator/openstruct_object.rb +11 -0
- data/lib/grape_entity/delegator/plain_object.rb +15 -0
- data/lib/grape_entity/entity.rb +161 -134
- data/lib/grape_entity/version.rb +1 -1
- data/spec/grape_entity/entity_spec.rb +304 -79
- metadata +32 -28
data/lib/grape_entity/version.rb
CHANGED
@@ -70,14 +70,14 @@ describe Grape::Entity do
|
|
70
70
|
|
71
71
|
context 'with parameters passed to the block' do
|
72
72
|
it 'sets the :proc option in the exposure options' do
|
73
|
-
block =
|
73
|
+
block = ->(_) { true }
|
74
74
|
subject.expose :name, using: 'Awesome', &block
|
75
75
|
expect(subject.exposures[:name]).to eq(proc: block, using: 'Awesome')
|
76
76
|
end
|
77
77
|
|
78
78
|
it 'references an instance of the entity without any options' do
|
79
79
|
subject.expose(:size) { |_| self }
|
80
|
-
expect(subject.represent(
|
80
|
+
expect(subject.represent({}).send(:value_for, :size)).to be_an_instance_of fresh_class
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
@@ -91,10 +91,10 @@ describe Grape::Entity do
|
|
91
91
|
end
|
92
92
|
|
93
93
|
expect(subject.exposures).to eq(
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
94
|
+
awesome: {},
|
95
|
+
awesome__nested: { nested: true },
|
96
|
+
awesome__nested__moar_nested: { as: 'weee', nested: true },
|
97
|
+
awesome__another_nested: { using: 'Awesome', nested: true }
|
98
98
|
)
|
99
99
|
end
|
100
100
|
|
@@ -105,15 +105,15 @@ describe Grape::Entity do
|
|
105
105
|
end
|
106
106
|
|
107
107
|
expect(subject.represent({}).send(:value_for, :awesome)).to eq(
|
108
|
-
|
109
|
-
|
108
|
+
nested: 'value',
|
109
|
+
another_nested: 'value'
|
110
110
|
)
|
111
111
|
end
|
112
112
|
|
113
113
|
it 'does not represent nested exposures whose conditions are not met' do
|
114
114
|
subject.expose :awesome do
|
115
|
-
subject.expose(:condition_met, if:
|
116
|
-
subject.expose(:condition_not_met, if:
|
115
|
+
subject.expose(:condition_met, if: ->(_, _) { true }) { |_| 'value' }
|
116
|
+
subject.expose(:condition_not_met, if: ->(_, _) { false }) { |_| 'value' }
|
117
117
|
end
|
118
118
|
|
119
119
|
expect(subject.represent({}).send(:value_for, :awesome)).to eq(condition_met: 'value')
|
@@ -129,13 +129,13 @@ describe Grape::Entity do
|
|
129
129
|
end
|
130
130
|
|
131
131
|
expect(subject.represent({}).serializable_hash).to eq(
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
132
|
+
awesome: {
|
133
|
+
nested: 'value',
|
134
|
+
another_nested: 'value',
|
135
|
+
second_level_nested: {
|
136
|
+
deeply_exposed_attr: 'value'
|
137
|
+
}
|
138
|
+
}
|
139
139
|
)
|
140
140
|
end
|
141
141
|
|
@@ -162,22 +162,22 @@ describe Grape::Entity do
|
|
162
162
|
end
|
163
163
|
|
164
164
|
expect(ClassRoom.represent({}).serializable_hash).to eq(
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
165
|
+
parents: [
|
166
|
+
{
|
167
|
+
user: { in_first: 'value' },
|
168
|
+
children: [
|
169
|
+
{ user: { in_first: 'value', user_id: 'value', display_id: 'value' } },
|
170
|
+
{ user: { in_first: 'value', user_id: 'value', display_id: 'value' } }
|
171
|
+
]
|
172
|
+
},
|
173
|
+
{
|
174
|
+
user: { in_first: 'value' },
|
175
|
+
children: [
|
176
|
+
{ user: { in_first: 'value', user_id: 'value', display_id: 'value' } },
|
177
|
+
{ user: { in_first: 'value', user_id: 'value', display_id: 'value' } }
|
178
|
+
]
|
179
|
+
}
|
180
|
+
]
|
181
181
|
)
|
182
182
|
end
|
183
183
|
|
@@ -190,11 +190,14 @@ describe Grape::Entity do
|
|
190
190
|
subject.expose :nested
|
191
191
|
end
|
192
192
|
end
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
193
|
+
expect(subject.represent({}, serializable: true)).to eq(
|
194
|
+
awesome: {
|
195
|
+
nested: 'value'
|
196
|
+
},
|
197
|
+
not_awesome: {
|
198
|
+
nested: nil
|
199
|
+
}
|
200
|
+
)
|
198
201
|
end
|
199
202
|
end
|
200
203
|
end
|
@@ -228,7 +231,7 @@ describe Grape::Entity do
|
|
228
231
|
end
|
229
232
|
|
230
233
|
context 'register formatters' do
|
231
|
-
let(:date_formatter) {
|
234
|
+
let(:date_formatter) { ->(date) { date.strftime('%m/%d/%Y') } }
|
232
235
|
|
233
236
|
it 'registers a formatter' do
|
234
237
|
subject.format_with :timestamp, &date_formatter
|
@@ -259,9 +262,9 @@ describe Grape::Entity do
|
|
259
262
|
end
|
260
263
|
|
261
264
|
it 'formats an exposure with a :format_with lambda that returns a value from the entity instance' do
|
262
|
-
object =
|
265
|
+
object = {}
|
263
266
|
|
264
|
-
subject.expose(:size, format_with:
|
267
|
+
subject.expose(:size, format_with: ->(_value) { self.object.class.to_s })
|
265
268
|
expect(subject.represent(object).send(:value_for, :size)).to eq object.class.to_s
|
266
269
|
end
|
267
270
|
|
@@ -270,7 +273,7 @@ describe Grape::Entity do
|
|
270
273
|
self.object.class.to_s
|
271
274
|
end
|
272
275
|
|
273
|
-
object =
|
276
|
+
object = {}
|
274
277
|
|
275
278
|
subject.expose(:size, format_with: :size_formatter)
|
276
279
|
expect(subject.represent(object).send(:value_for, :size)).to eq object.class.to_s
|
@@ -296,23 +299,12 @@ describe Grape::Entity do
|
|
296
299
|
expect(subject.exposures).to eq(name: {}, email: {})
|
297
300
|
end
|
298
301
|
|
299
|
-
|
300
|
-
|
301
|
-
it 'remove from parent and all child classes that have not locked down their attributes with an .exposures call' do
|
302
|
+
context 'when called from the parent class' do
|
303
|
+
it 'remove from parent and do not remove from child classes' do
|
302
304
|
subject.expose :name, :email
|
303
305
|
child_class = Class.new(subject)
|
304
306
|
subject.unexpose :email
|
305
307
|
|
306
|
-
expect(subject.exposures).to eq(name: {})
|
307
|
-
expect(child_class.exposures).to eq(name: {})
|
308
|
-
end
|
309
|
-
|
310
|
-
it 'remove from parent and do not remove from child classes that have locked down their attributes with an .exposures call' do
|
311
|
-
subject.expose :name, :email
|
312
|
-
child_class = Class.new(subject)
|
313
|
-
child_class.exposures
|
314
|
-
subject.unexpose :email
|
315
|
-
|
316
308
|
expect(subject.exposures).to eq(name: {})
|
317
309
|
expect(child_class.exposures).to eq(name: {}, email: {})
|
318
310
|
end
|
@@ -364,7 +356,7 @@ describe Grape::Entity do
|
|
364
356
|
end
|
365
357
|
|
366
358
|
it 'merges nested :if option' do
|
367
|
-
match_proc =
|
359
|
+
match_proc = ->(_obj, _opts) { true }
|
368
360
|
|
369
361
|
subject.class_eval do
|
370
362
|
# Symbol
|
@@ -383,13 +375,13 @@ describe Grape::Entity do
|
|
383
375
|
end
|
384
376
|
|
385
377
|
expect(subject.exposures[:awesome_thing]).to eq(
|
386
|
-
|
387
|
-
|
378
|
+
if: { awesome: false, less_awesome: true },
|
379
|
+
if_extras: [:awesome, match_proc]
|
388
380
|
)
|
389
381
|
end
|
390
382
|
|
391
383
|
it 'merges nested :unless option' do
|
392
|
-
match_proc =
|
384
|
+
match_proc = ->(_, _) { true }
|
393
385
|
|
394
386
|
subject.class_eval do
|
395
387
|
# Symbol
|
@@ -408,8 +400,8 @@ describe Grape::Entity do
|
|
408
400
|
end
|
409
401
|
|
410
402
|
expect(subject.exposures[:awesome_thing]).to eq(
|
411
|
-
|
412
|
-
|
403
|
+
unless: { awesome: false, less_awesome: true },
|
404
|
+
unless_extras: [:awesome, match_proc]
|
413
405
|
)
|
414
406
|
end
|
415
407
|
|
@@ -433,10 +425,10 @@ describe Grape::Entity do
|
|
433
425
|
end
|
434
426
|
|
435
427
|
it 'overrides nested :proc option' do
|
436
|
-
match_proc =
|
428
|
+
match_proc = ->(_obj, _opts) { 'more awesomer' }
|
437
429
|
|
438
430
|
subject.class_eval do
|
439
|
-
with_options(proc:
|
431
|
+
with_options(proc: ->(_obj, _opts) { 'awesome' }) do
|
440
432
|
expose :awesome_thing, proc: match_proc
|
441
433
|
end
|
442
434
|
end
|
@@ -461,7 +453,7 @@ describe Grape::Entity do
|
|
461
453
|
end
|
462
454
|
|
463
455
|
it 'returns a single entity if called with a hash' do
|
464
|
-
expect(subject.represent(
|
456
|
+
expect(subject.represent({})).to be_kind_of(subject)
|
465
457
|
end
|
466
458
|
|
467
459
|
it 'returns multiple entities if called with a collection' do
|
@@ -506,6 +498,164 @@ describe Grape::Entity do
|
|
506
498
|
subject.represent(Object.new, serializable: true)
|
507
499
|
end.to raise_error(NoMethodError, /missing attribute `awesome'/)
|
508
500
|
end
|
501
|
+
|
502
|
+
context 'with specified fields' do
|
503
|
+
it 'returns only specified fields with only option' do
|
504
|
+
subject.expose(:id, :name, :phone)
|
505
|
+
representation = subject.represent(OpenStruct.new, only: [:id, :name], serializable: true)
|
506
|
+
expect(representation).to eq(id: nil, name: nil)
|
507
|
+
end
|
508
|
+
|
509
|
+
it 'returns all fields except the ones specified in the except option' do
|
510
|
+
subject.expose(:id, :name, :phone)
|
511
|
+
representation = subject.represent(OpenStruct.new, except: [:phone], serializable: true)
|
512
|
+
expect(representation).to eq(id: nil, name: nil)
|
513
|
+
end
|
514
|
+
|
515
|
+
it 'returns only fields specified in the only option and not specified in the except option' do
|
516
|
+
subject.expose(:id, :name, :phone)
|
517
|
+
representation = subject.represent(OpenStruct.new,
|
518
|
+
only: [:name, :phone],
|
519
|
+
except: [:phone], serializable: true)
|
520
|
+
expect(representation).to eq(name: nil)
|
521
|
+
end
|
522
|
+
|
523
|
+
context 'with strings or symbols passed to only and except' do
|
524
|
+
let(:object) { OpenStruct.new(user: {}) }
|
525
|
+
|
526
|
+
before do
|
527
|
+
user_entity = Class.new(Grape::Entity)
|
528
|
+
user_entity.expose(:id, :name, :email)
|
529
|
+
|
530
|
+
subject.expose(:id, :name, :phone, :address)
|
531
|
+
subject.expose(:user, using: user_entity)
|
532
|
+
end
|
533
|
+
|
534
|
+
it 'can specify "only" option attributes as strings' do
|
535
|
+
representation = subject.represent(object, only: ['id', 'name', { 'user' => ['email'] }], serializable: true)
|
536
|
+
expect(representation).to eq(id: nil, name: nil, user: { email: nil })
|
537
|
+
end
|
538
|
+
|
539
|
+
it 'can specify "except" option attributes as strings' do
|
540
|
+
representation = subject.represent(object, except: ['id', 'name', { 'user' => ['email'] }], serializable: true)
|
541
|
+
expect(representation).to eq(phone: nil, address: nil, user: { id: nil, name: nil })
|
542
|
+
end
|
543
|
+
|
544
|
+
it 'can specify "only" option attributes as symbols' do
|
545
|
+
representation = subject.represent(object, only: [:name, :phone, { user: [:name] }], serializable: true)
|
546
|
+
expect(representation).to eq(name: nil, phone: nil, user: { name: nil })
|
547
|
+
end
|
548
|
+
|
549
|
+
it 'can specify "except" option attributes as symbols' do
|
550
|
+
representation = subject.represent(object, except: [:name, :phone, { user: [:name] }], serializable: true)
|
551
|
+
expect(representation).to eq(id: nil, address: nil, user: { id: nil, email: nil })
|
552
|
+
end
|
553
|
+
|
554
|
+
it 'can specify "only" attributes as strings and symbols' do
|
555
|
+
representation = subject.represent(object, only: [:id, 'address', { user: [:id, 'name'] }], serializable: true)
|
556
|
+
expect(representation).to eq(id: nil, address: nil, user: { id: nil, name: nil })
|
557
|
+
end
|
558
|
+
|
559
|
+
it 'can specify "except" attributes as strings and symbols' do
|
560
|
+
representation = subject.represent(object, except: [:id, 'address', { user: [:id, 'name'] }], serializable: true)
|
561
|
+
expect(representation).to eq(name: nil, phone: nil, user: { email: nil })
|
562
|
+
end
|
563
|
+
end
|
564
|
+
|
565
|
+
it 'can specify children attributes with only' do
|
566
|
+
user_entity = Class.new(Grape::Entity)
|
567
|
+
user_entity.expose(:id, :name, :email)
|
568
|
+
|
569
|
+
subject.expose(:id, :name, :phone)
|
570
|
+
subject.expose(:user, using: user_entity)
|
571
|
+
|
572
|
+
representation = subject.represent(OpenStruct.new(user: {}), only: [:id, :name, { user: [:name, :email] }], serializable: true)
|
573
|
+
expect(representation).to eq(id: nil, name: nil, user: { name: nil, email: nil })
|
574
|
+
end
|
575
|
+
|
576
|
+
it 'can specify children attributes with except' do
|
577
|
+
user_entity = Class.new(Grape::Entity)
|
578
|
+
user_entity.expose(:id, :name, :email)
|
579
|
+
|
580
|
+
subject.expose(:id, :name, :phone)
|
581
|
+
subject.expose(:user, using: user_entity)
|
582
|
+
|
583
|
+
representation = subject.represent(OpenStruct.new(user: {}), except: [:phone, { user: [:id] }], serializable: true)
|
584
|
+
expect(representation).to eq(id: nil, name: nil, user: { name: nil, email: nil })
|
585
|
+
end
|
586
|
+
|
587
|
+
it 'can specify children attributes with mixed only and except' do
|
588
|
+
user_entity = Class.new(Grape::Entity)
|
589
|
+
user_entity.expose(:id, :name, :email, :address)
|
590
|
+
|
591
|
+
subject.expose(:id, :name, :phone, :mobile_phone)
|
592
|
+
subject.expose(:user, using: user_entity)
|
593
|
+
|
594
|
+
representation = subject.represent(OpenStruct.new(user: {}),
|
595
|
+
only: [:id, :name, :phone, user: [:id, :name, :email]],
|
596
|
+
except: [:phone, { user: [:id] }], serializable: true)
|
597
|
+
expect(representation).to eq(id: nil, name: nil, user: { name: nil, email: nil })
|
598
|
+
end
|
599
|
+
|
600
|
+
context 'specify attribute with exposure condition' do
|
601
|
+
it 'returns only specified fields' do
|
602
|
+
subject.expose(:id)
|
603
|
+
subject.with_options(if: { condition: true }) do
|
604
|
+
subject.expose(:name)
|
605
|
+
end
|
606
|
+
|
607
|
+
representation = subject.represent(OpenStruct.new, condition: true, only: [:id, :name], serializable: true)
|
608
|
+
expect(representation).to eq(id: nil, name: nil)
|
609
|
+
end
|
610
|
+
|
611
|
+
it 'does not return fields specified in the except option' do
|
612
|
+
subject.expose(:id, :phone)
|
613
|
+
subject.with_options(if: { condition: true }) do
|
614
|
+
subject.expose(:name, :mobile_phone)
|
615
|
+
end
|
616
|
+
|
617
|
+
representation = subject.represent(OpenStruct.new, condition: true, except: [:phone, :mobile_phone], serializable: true)
|
618
|
+
expect(representation).to eq(id: nil, name: nil)
|
619
|
+
end
|
620
|
+
end
|
621
|
+
|
622
|
+
context 'attribute with alias' do
|
623
|
+
it 'returns only specified fields' do
|
624
|
+
subject.expose(:id)
|
625
|
+
subject.expose(:name, as: :title)
|
626
|
+
|
627
|
+
representation = subject.represent(OpenStruct.new, condition: true, only: [:id, :title], serializable: true)
|
628
|
+
expect(representation).to eq(id: nil, title: nil)
|
629
|
+
end
|
630
|
+
|
631
|
+
it 'does not return fields specified in the except option' do
|
632
|
+
subject.expose(:id)
|
633
|
+
subject.expose(:name, as: :title)
|
634
|
+
subject.expose(:phone, as: :phone_number)
|
635
|
+
|
636
|
+
representation = subject.represent(OpenStruct.new, condition: true, except: [:phone_number], serializable: true)
|
637
|
+
expect(representation).to eq(id: nil, title: nil)
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
context 'attribute that is an entity itself' do
|
642
|
+
it 'returns correctly the children entity attributes' do
|
643
|
+
user_entity = Class.new(Grape::Entity)
|
644
|
+
user_entity.expose(:id, :name, :email)
|
645
|
+
|
646
|
+
nephew_entity = Class.new(Grape::Entity)
|
647
|
+
nephew_entity.expose(:id, :name, :email)
|
648
|
+
|
649
|
+
subject.expose(:id, :name, :phone)
|
650
|
+
subject.expose(:user, using: user_entity)
|
651
|
+
subject.expose(:nephew, using: nephew_entity)
|
652
|
+
|
653
|
+
representation = subject.represent(OpenStruct.new(user: {}),
|
654
|
+
only: [:id, :name, :user], except: [:nephew], serializable: true)
|
655
|
+
expect(representation).to eq(id: nil, name: nil, user: { id: nil, name: nil, email: nil })
|
656
|
+
end
|
657
|
+
end
|
658
|
+
end
|
509
659
|
end
|
510
660
|
|
511
661
|
describe '.present_collection' do
|
@@ -623,6 +773,30 @@ describe Grape::Entity do
|
|
623
773
|
end
|
624
774
|
end
|
625
775
|
end
|
776
|
+
|
777
|
+
context 'inheriting from parent entity' do
|
778
|
+
before(:each) do
|
779
|
+
subject.root 'things', 'thing'
|
780
|
+
end
|
781
|
+
|
782
|
+
it 'inherits single root' do
|
783
|
+
child_class = Class.new(subject)
|
784
|
+
representation = child_class.represent(Object.new)
|
785
|
+
expect(representation).to be_kind_of Hash
|
786
|
+
expect(representation).to have_key 'thing'
|
787
|
+
expect(representation['thing']).to be_kind_of(child_class)
|
788
|
+
end
|
789
|
+
|
790
|
+
it 'inherits array root root' do
|
791
|
+
child_class = Class.new(subject)
|
792
|
+
representation = child_class.represent(4.times.map { Object.new })
|
793
|
+
expect(representation).to be_kind_of Hash
|
794
|
+
expect(representation).to have_key('things')
|
795
|
+
expect(representation['things']).to be_kind_of Array
|
796
|
+
expect(representation['things'].size).to eq 4
|
797
|
+
expect(representation['things'].reject { |r| r.is_a?(child_class) }).to be_empty
|
798
|
+
end
|
799
|
+
end
|
626
800
|
end
|
627
801
|
|
628
802
|
describe '#initialize' do
|
@@ -677,12 +851,23 @@ describe Grape::Entity do
|
|
677
851
|
expect { fresh_class.new(model).serializable_hash }.not_to raise_error
|
678
852
|
end
|
679
853
|
|
680
|
-
it
|
854
|
+
it 'exposes values of private method calls' do
|
855
|
+
some_class = Class.new do
|
856
|
+
define_method :name do
|
857
|
+
true
|
858
|
+
end
|
859
|
+
private :name
|
860
|
+
end
|
861
|
+
fresh_class.expose :name, safe: true
|
862
|
+
expect(fresh_class.new(some_class.new).serializable_hash).to eq(name: true)
|
863
|
+
end
|
864
|
+
|
865
|
+
it "does expose attributes that don't exist on the object as nil" do
|
681
866
|
fresh_class.expose :email, :nonexistent_attribute, :name, safe: true
|
682
867
|
|
683
868
|
res = fresh_class.new(model).serializable_hash
|
684
869
|
expect(res).to have_key :email
|
685
|
-
expect(res).
|
870
|
+
expect(res).to have_key :nonexistent_attribute
|
686
871
|
expect(res).to have_key :name
|
687
872
|
end
|
688
873
|
|
@@ -693,15 +878,15 @@ describe Grape::Entity do
|
|
693
878
|
expect(res).to have_key :name
|
694
879
|
end
|
695
880
|
|
696
|
-
it "does
|
881
|
+
it "does expose attributes that don't exist on the object as nil if criteria is true" do
|
697
882
|
fresh_class.expose :email
|
698
|
-
fresh_class.expose :nonexistent_attribute, safe: true, if:
|
699
|
-
fresh_class.expose :nonexistent_attribute2, safe: true, if:
|
883
|
+
fresh_class.expose :nonexistent_attribute, safe: true, if: ->(_obj, _opts) { false }
|
884
|
+
fresh_class.expose :nonexistent_attribute2, safe: true, if: ->(_obj, _opts) { true }
|
700
885
|
|
701
886
|
res = fresh_class.new(model).serializable_hash
|
702
887
|
expect(res).to have_key :email
|
703
888
|
expect(res).not_to have_key :nonexistent_attribute
|
704
|
-
expect(res).
|
889
|
+
expect(res).to have_key :nonexistent_attribute2
|
705
890
|
end
|
706
891
|
end
|
707
892
|
|
@@ -720,9 +905,9 @@ describe Grape::Entity do
|
|
720
905
|
end
|
721
906
|
|
722
907
|
it 'does not expose attributes that are generated by a block but have not passed criteria' do
|
723
|
-
fresh_class.expose :nonexistent_attribute,
|
724
|
-
|
725
|
-
|
908
|
+
fresh_class.expose :nonexistent_attribute,
|
909
|
+
proc: ->(_model, _opts) { 'I exist, but it is not yet my time to shine' },
|
910
|
+
if: ->(_model, _opts) { false }
|
726
911
|
res = fresh_class.new(model).serializable_hash
|
727
912
|
expect(res).not_to have_key :nonexistent_attribute
|
728
913
|
end
|
@@ -742,9 +927,9 @@ describe Grape::Entity do
|
|
742
927
|
end
|
743
928
|
|
744
929
|
it 'does not expose attributes that are generated by a block but have not passed criteria' do
|
745
|
-
fresh_class.expose :nonexistent_attribute,
|
746
|
-
|
747
|
-
|
930
|
+
fresh_class.expose :nonexistent_attribute,
|
931
|
+
proc: ->(_, _) { 'I exist, but it is not yet my time to shine' },
|
932
|
+
if: ->(_, _) { false }
|
748
933
|
res = fresh_class.new(model).serializable_hash
|
749
934
|
expect(res).not_to have_key :nonexistent_attribute
|
750
935
|
end
|
@@ -823,7 +1008,7 @@ describe Grape::Entity do
|
|
823
1008
|
date.strftime('%m/%d/%Y')
|
824
1009
|
end
|
825
1010
|
|
826
|
-
expose :fantasies, format_with:
|
1011
|
+
expose :fantasies, format_with: ->(f) { f.reverse }
|
827
1012
|
end
|
828
1013
|
end
|
829
1014
|
|
@@ -1071,6 +1256,46 @@ describe Grape::Entity do
|
|
1071
1256
|
|
1072
1257
|
expect(subject.documentation).to eq(label: doc, email: doc)
|
1073
1258
|
end
|
1259
|
+
|
1260
|
+
context 'inherited documentation' do
|
1261
|
+
it 'returns documentation from ancestor' do
|
1262
|
+
doc = { type: 'foo', desc: 'bar' }
|
1263
|
+
fresh_class.expose :name, documentation: doc
|
1264
|
+
child_class = Class.new(fresh_class)
|
1265
|
+
child_class.expose :email, documentation: doc
|
1266
|
+
|
1267
|
+
expect(fresh_class.documentation).to eq(name: doc)
|
1268
|
+
expect(child_class.documentation).to eq(name: doc, email: doc)
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
it 'obeys unexposed attributes in subclass' do
|
1272
|
+
doc = { type: 'foo', desc: 'bar' }
|
1273
|
+
fresh_class.expose :name, documentation: doc
|
1274
|
+
fresh_class.expose :email, documentation: doc
|
1275
|
+
child_class = Class.new(fresh_class)
|
1276
|
+
child_class.unexpose :email
|
1277
|
+
|
1278
|
+
expect(fresh_class.documentation).to eq(name: doc, email: doc)
|
1279
|
+
expect(child_class.documentation).to eq(name: doc)
|
1280
|
+
end
|
1281
|
+
|
1282
|
+
it 'obeys re-exposed attributes in subclass' do
|
1283
|
+
doc = { type: 'foo', desc: 'bar' }
|
1284
|
+
fresh_class.expose :name, documentation: doc
|
1285
|
+
fresh_class.expose :email, documentation: doc
|
1286
|
+
|
1287
|
+
child_class = Class.new(fresh_class)
|
1288
|
+
child_class.unexpose :email
|
1289
|
+
|
1290
|
+
nephew_class = Class.new(child_class)
|
1291
|
+
new_doc = { type: 'todler', descr: '???' }
|
1292
|
+
nephew_class.expose :email, documentation: new_doc
|
1293
|
+
|
1294
|
+
expect(fresh_class.documentation).to eq(name: doc, email: doc)
|
1295
|
+
expect(child_class.documentation).to eq(name: doc)
|
1296
|
+
expect(nephew_class.documentation).to eq(name: doc, email: new_doc)
|
1297
|
+
end
|
1298
|
+
end
|
1074
1299
|
end
|
1075
1300
|
|
1076
1301
|
describe '#key_for' do
|
@@ -1120,7 +1345,7 @@ describe Grape::Entity do
|
|
1120
1345
|
end
|
1121
1346
|
|
1122
1347
|
it 'only passes through proc :if exposure if it returns truthy value' do
|
1123
|
-
exposure_options = { if:
|
1348
|
+
exposure_options = { if: ->(_, opts) { opts[:true] } }
|
1124
1349
|
|
1125
1350
|
expect(subject.send(:conditions_met?, exposure_options, true: false)).to be false
|
1126
1351
|
expect(subject.send(:conditions_met?, exposure_options, true: true)).to be true
|
@@ -1138,7 +1363,7 @@ describe Grape::Entity do
|
|
1138
1363
|
end
|
1139
1364
|
|
1140
1365
|
it 'only passes through proc :unless exposure if it returns falsy value' do
|
1141
|
-
exposure_options = { unless:
|
1366
|
+
exposure_options = { unless: ->(_, opts) { opts[:true] == true } }
|
1142
1367
|
|
1143
1368
|
expect(subject.send(:conditions_met?, exposure_options, true: false)).to be true
|
1144
1369
|
expect(subject.send(:conditions_met?, exposure_options, true: true)).to be false
|