grape-entity 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +69 -0
- data/.travis.yml +5 -6
- data/CHANGELOG.md +35 -0
- data/Gemfile +7 -0
- data/Guardfile +0 -1
- data/README.md +320 -0
- data/Rakefile +3 -33
- data/lib/grape-entity.rb +1 -1
- data/lib/grape_entity.rb +2 -5
- data/lib/grape_entity/entity.rb +190 -71
- data/lib/grape_entity/version.rb +1 -1
- data/spec/grape_entity/entity_spec.rb +539 -158
- metadata +6 -5
- data/CHANGELOG.markdown +0 -21
- data/README.markdown +0 -197
data/lib/grape_entity/version.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Grape::Entity do
|
4
|
+
|
4
5
|
let(:fresh_class) { Class.new(Grape::Entity) }
|
5
6
|
|
6
7
|
context 'class methods' do
|
@@ -14,33 +15,115 @@ describe Grape::Entity do
|
|
14
15
|
end
|
15
16
|
|
16
17
|
it 'sets the same options for all exposures passed' do
|
17
|
-
subject.expose :name, :email, :location, :
|
18
|
-
subject.exposures.values.each{|v| v.should == {:
|
18
|
+
subject.expose :name, :email, :location, documentation: true
|
19
|
+
subject.exposures.values.each { |v| v.should == { documentation: true } }
|
19
20
|
end
|
20
21
|
end
|
21
22
|
|
22
23
|
context 'option validation' do
|
23
24
|
it 'makes sure that :as only works on single attribute calls' do
|
24
|
-
expect{ subject.expose :name, :email, :
|
25
|
-
expect{ subject.expose :name, :
|
25
|
+
expect { subject.expose :name, :email, as: :foo }.to raise_error ArgumentError
|
26
|
+
expect { subject.expose :name, as: :foo }.not_to raise_error
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'makes sure that :format_with as a proc cannot be used with a block' do
|
30
|
+
expect { subject.expose :name, format_with: proc {} {} }.to raise_error ArgumentError
|
26
31
|
end
|
27
32
|
|
28
|
-
it 'makes sure
|
29
|
-
expect { subject.expose :name, :
|
33
|
+
it 'makes sure unknown options are not silently ignored' do
|
34
|
+
expect { subject.expose :name, unknown: nil }.to raise_error ArgumentError
|
30
35
|
end
|
31
36
|
end
|
32
37
|
|
33
38
|
context 'with a block' do
|
34
39
|
it 'errors out if called with multiple attributes' do
|
35
|
-
expect{ subject.expose(:name, :email)
|
36
|
-
true
|
37
|
-
end }.to raise_error(ArgumentError)
|
40
|
+
expect { subject.expose(:name, :email) { true } }.to raise_error ArgumentError
|
38
41
|
end
|
39
42
|
|
40
|
-
it '
|
41
|
-
|
42
|
-
|
43
|
-
|
43
|
+
it 'references an instance of the entity with :using option' do
|
44
|
+
module EntitySpec
|
45
|
+
class SomeObject1
|
46
|
+
attr_accessor :prop1
|
47
|
+
|
48
|
+
def initialize
|
49
|
+
@prop1 = "value1"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class BogusEntity < Grape::Entity
|
54
|
+
expose :prop1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
subject.expose(:bogus, using: EntitySpec::BogusEntity) do |entity|
|
59
|
+
entity.prop1 = "MODIFIED 2"
|
60
|
+
entity
|
61
|
+
end
|
62
|
+
|
63
|
+
object = EntitySpec::SomeObject1.new
|
64
|
+
value = subject.represent(object).send(:value_for, :bogus)
|
65
|
+
value.should be_instance_of EntitySpec::BogusEntity
|
66
|
+
|
67
|
+
prop1 = value.send(:value_for, :prop1)
|
68
|
+
prop1.should == "MODIFIED 2"
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with parameters passed to the block' do
|
72
|
+
it 'sets the :proc option in the exposure options' do
|
73
|
+
block = lambda { |_| true }
|
74
|
+
subject.expose :name, using: 'Awesome', &block
|
75
|
+
subject.exposures[:name].should == { proc: block, using: 'Awesome' }
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'references an instance of the entity without any options' do
|
79
|
+
subject.expose(:size) { |_| self }
|
80
|
+
subject.represent(Hash.new).send(:value_for, :size).should be_an_instance_of fresh_class
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'with no parameters passed to the block' do
|
85
|
+
it 'adds a nested exposure' do
|
86
|
+
subject.expose :awesome do
|
87
|
+
subject.expose :nested do
|
88
|
+
subject.expose :moar_nested, as: 'weee'
|
89
|
+
end
|
90
|
+
subject.expose :another_nested, using: 'Awesome'
|
91
|
+
end
|
92
|
+
|
93
|
+
subject.exposures.should == {
|
94
|
+
awesome: {},
|
95
|
+
awesome__nested: {},
|
96
|
+
awesome__nested__moar_nested: { as: 'weee' },
|
97
|
+
awesome__another_nested: { using: 'Awesome' }
|
98
|
+
}
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'represents the exposure as a hash of its nested exposures' do
|
102
|
+
subject.expose :awesome do
|
103
|
+
subject.expose(:nested) { |_| "value" }
|
104
|
+
subject.expose(:another_nested) { |_| "value" }
|
105
|
+
end
|
106
|
+
|
107
|
+
subject.represent({}).send(:value_for, :awesome).should == {
|
108
|
+
nested: "value",
|
109
|
+
another_nested: "value"
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'is safe if its nested exposures are safe' do
|
114
|
+
subject.with_options safe: true do
|
115
|
+
subject.expose :awesome do
|
116
|
+
subject.expose(:nested) { |_| "value" }
|
117
|
+
end
|
118
|
+
subject.expose :not_awesome do
|
119
|
+
subject.expose :nested
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
valid_keys = subject.represent({}).valid_exposures.keys
|
124
|
+
valid_keys.include?(:awesome).should == true && \
|
125
|
+
valid_keys.include?(:not_awesome).should == false
|
126
|
+
end
|
44
127
|
end
|
45
128
|
end
|
46
129
|
|
@@ -73,7 +156,7 @@ describe Grape::Entity do
|
|
73
156
|
end
|
74
157
|
|
75
158
|
context 'register formatters' do
|
76
|
-
let(:date_formatter) { lambda {|date| date.strftime('%m/%d/%Y') }}
|
159
|
+
let(:date_formatter) { lambda { |date| date.strftime('%m/%d/%Y') } }
|
77
160
|
|
78
161
|
it 'registers a formatter' do
|
79
162
|
subject.format_with :timestamp, &date_formatter
|
@@ -89,7 +172,7 @@ describe Grape::Entity do
|
|
89
172
|
end
|
90
173
|
|
91
174
|
it 'does not allow registering a formatter without a block' do
|
92
|
-
expect{ subject.format_with :foo }.to raise_error
|
175
|
+
expect { subject.format_with :foo }.to raise_error ArgumentError
|
93
176
|
end
|
94
177
|
|
95
178
|
it 'formats an exposure with a registered formatter' do
|
@@ -97,45 +180,164 @@ describe Grape::Entity do
|
|
97
180
|
date.strftime('%m/%d/%Y')
|
98
181
|
end
|
99
182
|
|
100
|
-
subject.expose :birthday, :
|
183
|
+
subject.expose :birthday, format_with: :timestamp
|
184
|
+
|
185
|
+
model = { birthday: Time.gm(2012, 2, 27) }
|
186
|
+
subject.new(double(model)).as_json[:birthday].should == '02/27/2012'
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'formats an exposure with a :format_with lambda that returns a value from the entity instance' do
|
190
|
+
object = Hash.new
|
101
191
|
|
102
|
-
|
103
|
-
subject.
|
192
|
+
subject.expose(:size, format_with: lambda { |value| self.object.class.to_s })
|
193
|
+
subject.represent(object).send(:value_for, :size).should == object.class.to_s
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'formats an exposure with a :format_with symbol that returns a value from the entity instance' do
|
197
|
+
subject.format_with :size_formatter do |date|
|
198
|
+
self.object.class.to_s
|
199
|
+
end
|
200
|
+
|
201
|
+
object = Hash.new
|
202
|
+
|
203
|
+
subject.expose(:size, format_with: :size_formatter)
|
204
|
+
subject.represent(object).send(:value_for, :size).should == object.class.to_s
|
104
205
|
end
|
105
206
|
end
|
106
207
|
end
|
107
208
|
|
108
209
|
describe '.with_options' do
|
109
|
-
it '
|
210
|
+
it 'raises an error for unknown options' do
|
211
|
+
block = proc do
|
212
|
+
with_options(unknown: true) do
|
213
|
+
expose :awesome_thing
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
expect { subject.class_eval(&block) }.to raise_error ArgumentError
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'applies the options to all exposures inside' do
|
110
221
|
subject.class_eval do
|
111
|
-
with_options(:
|
112
|
-
expose :awesome_thing, :
|
222
|
+
with_options(if: { awesome: true }) do
|
223
|
+
expose :awesome_thing, using: 'Awesome'
|
113
224
|
end
|
114
225
|
end
|
115
226
|
|
116
|
-
subject.exposures[:awesome_thing].should == {:
|
227
|
+
subject.exposures[:awesome_thing].should == { if: { awesome: true }, using: 'Awesome' }
|
117
228
|
end
|
118
229
|
|
119
|
-
it '
|
230
|
+
it 'allows for nested .with_options' do
|
120
231
|
subject.class_eval do
|
121
|
-
with_options(:
|
122
|
-
with_options(:
|
232
|
+
with_options(if: { awesome: true }) do
|
233
|
+
with_options(using: 'Something') do
|
123
234
|
expose :awesome_thing
|
124
235
|
end
|
125
236
|
end
|
126
237
|
end
|
127
238
|
|
128
|
-
subject.exposures[:awesome_thing].should == {:
|
239
|
+
subject.exposures[:awesome_thing].should == { if: { awesome: true }, using: 'Something' }
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'overrides nested :as option' do
|
243
|
+
subject.class_eval do
|
244
|
+
with_options(as: :sweet) do
|
245
|
+
expose :awesome_thing, as: :extra_smooth
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
subject.exposures[:awesome_thing].should == { as: :extra_smooth }
|
250
|
+
end
|
251
|
+
|
252
|
+
it "merges nested :if option" do
|
253
|
+
match_proc = lambda { |obj, opts| true }
|
254
|
+
|
255
|
+
subject.class_eval do
|
256
|
+
# Symbol
|
257
|
+
with_options(if: :awesome) do
|
258
|
+
# Hash
|
259
|
+
with_options(if: { awesome: true }) do
|
260
|
+
# Proc
|
261
|
+
with_options(if: match_proc) do
|
262
|
+
# Hash (override existing key and merge new key)
|
263
|
+
with_options(if: { awesome: false, less_awesome: true }) do
|
264
|
+
expose :awesome_thing
|
265
|
+
end
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
subject.exposures[:awesome_thing].should == {
|
272
|
+
if: { awesome: false, less_awesome: true },
|
273
|
+
if_extras: [:awesome, match_proc]
|
274
|
+
}
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'merges nested :unless option' do
|
278
|
+
match_proc = lambda { |obj, opts| true }
|
279
|
+
|
280
|
+
subject.class_eval do
|
281
|
+
# Symbol
|
282
|
+
with_options(unless: :awesome) do
|
283
|
+
# Hash
|
284
|
+
with_options(unless: { awesome: true }) do
|
285
|
+
# Proc
|
286
|
+
with_options(unless: match_proc) do
|
287
|
+
# Hash (override existing key and merge new key)
|
288
|
+
with_options(unless: { awesome: false, less_awesome: true }) do
|
289
|
+
expose :awesome_thing
|
290
|
+
end
|
291
|
+
end
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
subject.exposures[:awesome_thing].should == {
|
297
|
+
unless: { awesome: false, less_awesome: true },
|
298
|
+
unless_extras: [:awesome, match_proc]
|
299
|
+
}
|
129
300
|
end
|
130
301
|
|
131
|
-
it '
|
302
|
+
it 'overrides nested :using option' do
|
132
303
|
subject.class_eval do
|
133
|
-
with_options(:
|
134
|
-
expose :
|
304
|
+
with_options(using: 'Something') do
|
305
|
+
expose :awesome_thing, using: 'SomethingElse'
|
135
306
|
end
|
136
307
|
end
|
137
308
|
|
138
|
-
subject.exposures[:
|
309
|
+
subject.exposures[:awesome_thing].should == { using: 'SomethingElse' }
|
310
|
+
end
|
311
|
+
|
312
|
+
it 'aliases :with option to :using option' do
|
313
|
+
subject.class_eval do
|
314
|
+
with_options(using: 'Something') do
|
315
|
+
expose :awesome_thing, with: 'SomethingElse'
|
316
|
+
end
|
317
|
+
end
|
318
|
+
subject.exposures[:awesome_thing].should == { using: 'SomethingElse' }
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'overrides nested :proc option' do
|
322
|
+
match_proc = lambda { |obj, opts| 'more awesomer' }
|
323
|
+
|
324
|
+
subject.class_eval do
|
325
|
+
with_options(proc: lambda { |obj, opts| 'awesome' }) do
|
326
|
+
expose :awesome_thing, proc: match_proc
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
subject.exposures[:awesome_thing].should == { proc: match_proc }
|
331
|
+
end
|
332
|
+
|
333
|
+
it 'overrides nested :documentation option' do
|
334
|
+
subject.class_eval do
|
335
|
+
with_options(documentation: { desc: 'Description.' }) do
|
336
|
+
expose :awesome_thing, documentation: { desc: 'Other description.' }
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
subject.exposures[:awesome_thing].should == { documentation: { desc: 'Other description.' } }
|
139
341
|
end
|
140
342
|
end
|
141
343
|
|
@@ -149,15 +351,27 @@ describe Grape::Entity do
|
|
149
351
|
end
|
150
352
|
|
151
353
|
it 'returns multiple entities if called with a collection' do
|
152
|
-
representation = subject.represent(4.times.map{Object.new})
|
354
|
+
representation = subject.represent(4.times.map { Object.new })
|
153
355
|
representation.should be_kind_of Array
|
154
356
|
representation.size.should == 4
|
155
|
-
representation.reject{|r| r.kind_of?(subject)}.should be_empty
|
357
|
+
representation.reject { |r| r.kind_of?(subject) }.should be_empty
|
156
358
|
end
|
157
359
|
|
158
|
-
it 'adds the :
|
159
|
-
representation = subject.represent(4.times.map{Object.new})
|
160
|
-
representation.each{|r| r.options[:collection].should be_true}
|
360
|
+
it 'adds the collection: true option if called with a collection' do
|
361
|
+
representation = subject.represent(4.times.map { Object.new })
|
362
|
+
representation.each { |r| r.options[:collection].should be_true }
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'returns a serialized hash of a single object if serializable: true' do
|
366
|
+
subject.expose(:awesome) { |_| true }
|
367
|
+
representation = subject.represent(Object.new, serializable: true)
|
368
|
+
representation.should == { awesome: true }
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'returns a serialized array of hashes of multiple objects if serializable: true' do
|
372
|
+
subject.expose(:awesome) { |_| true }
|
373
|
+
representation = subject.represent(2.times.map { Object.new }, serializable: true)
|
374
|
+
representation.should == [{ awesome: true }, { awesome: true }]
|
161
375
|
end
|
162
376
|
end
|
163
377
|
|
@@ -178,29 +392,29 @@ describe Grape::Entity do
|
|
178
392
|
|
179
393
|
context 'with an array of objects' do
|
180
394
|
it 'allows a root element name to be specified' do
|
181
|
-
representation = subject.represent(4.times.map{Object.new})
|
395
|
+
representation = subject.represent(4.times.map { Object.new })
|
182
396
|
representation.should be_kind_of Hash
|
183
397
|
representation.should have_key 'things'
|
184
398
|
representation['things'].should be_kind_of Array
|
185
399
|
representation['things'].size.should == 4
|
186
|
-
representation['things'].reject{|r| r.kind_of?(subject)}.should be_empty
|
400
|
+
representation['things'].reject { |r| r.kind_of?(subject) }.should be_empty
|
187
401
|
end
|
188
402
|
end
|
189
403
|
|
190
404
|
context 'it can be overridden' do
|
191
405
|
it 'can be disabled' do
|
192
|
-
representation = subject.represent(4.times.map{Object.new}, :
|
406
|
+
representation = subject.represent(4.times.map { Object.new }, root: false)
|
193
407
|
representation.should be_kind_of Array
|
194
408
|
representation.size.should == 4
|
195
|
-
representation.reject{|r| r.kind_of?(subject)}.should be_empty
|
409
|
+
representation.reject { |r| r.kind_of?(subject) }.should be_empty
|
196
410
|
end
|
197
411
|
it 'can use a different name' do
|
198
|
-
representation = subject.represent(4.times.map{Object.new}, :
|
412
|
+
representation = subject.represent(4.times.map { Object.new }, root: 'others')
|
199
413
|
representation.should be_kind_of Hash
|
200
414
|
representation.should have_key 'others'
|
201
415
|
representation['others'].should be_kind_of Array
|
202
416
|
representation['others'].size.should == 4
|
203
|
-
representation['others'].reject{|r| r.kind_of?(subject)}.should be_empty
|
417
|
+
representation['others'].reject { |r| r.kind_of?(subject) }.should be_empty
|
204
418
|
end
|
205
419
|
end
|
206
420
|
end
|
@@ -221,10 +435,10 @@ describe Grape::Entity do
|
|
221
435
|
|
222
436
|
context 'with an array of objects' do
|
223
437
|
it 'allows a root element name to be specified' do
|
224
|
-
representation = subject.represent(4.times.map{Object.new})
|
438
|
+
representation = subject.represent(4.times.map { Object.new })
|
225
439
|
representation.should be_kind_of Array
|
226
440
|
representation.size.should == 4
|
227
|
-
representation.reject{|r| r.kind_of?(subject)}.should be_empty
|
441
|
+
representation.reject { |r| r.kind_of?(subject) }.should be_empty
|
228
442
|
end
|
229
443
|
end
|
230
444
|
end
|
@@ -242,12 +456,12 @@ describe Grape::Entity do
|
|
242
456
|
|
243
457
|
context 'with an array of objects' do
|
244
458
|
it 'allows a root element name to be specified' do
|
245
|
-
representation = subject.represent(4.times.map{Object.new})
|
459
|
+
representation = subject.represent(4.times.map { Object.new })
|
246
460
|
representation.should be_kind_of Hash
|
247
461
|
representation.should have_key('things')
|
248
462
|
representation['things'].should be_kind_of Array
|
249
463
|
representation['things'].size.should == 4
|
250
|
-
representation['things'].reject{|r| r.kind_of?(subject)}.should be_empty
|
464
|
+
representation['things'].reject { |r| r.kind_of?(subject) }.should be_empty
|
251
465
|
end
|
252
466
|
end
|
253
467
|
end
|
@@ -255,9 +469,9 @@ describe Grape::Entity do
|
|
255
469
|
|
256
470
|
describe '#initialize' do
|
257
471
|
it 'takes an object and an optional options hash' do
|
258
|
-
expect{ subject.new(Object.new) }.not_to raise_error
|
259
|
-
expect{ subject.new }.to raise_error
|
260
|
-
expect{ subject.new(Object.new, {}) }.not_to raise_error
|
472
|
+
expect { subject.new(Object.new) }.not_to raise_error
|
473
|
+
expect { subject.new }.to raise_error ArgumentError
|
474
|
+
expect { subject.new(Object.new, {}) }.not_to raise_error
|
261
475
|
end
|
262
476
|
|
263
477
|
it 'has attribute readers for the object and options' do
|
@@ -266,63 +480,95 @@ describe Grape::Entity do
|
|
266
480
|
entity.options.should == {}
|
267
481
|
end
|
268
482
|
end
|
483
|
+
|
269
484
|
end
|
270
485
|
|
271
486
|
context 'instance methods' do
|
272
|
-
|
273
|
-
let(:model){ mock(attributes) }
|
274
|
-
|
275
|
-
let(:attributes) { {
|
276
|
-
:name => 'Bob Bobson',
|
277
|
-
:email => 'bob@example.com',
|
278
|
-
:birthday => Time.gm(2012, 2, 27),
|
279
|
-
:fantasies => ['Unicorns', 'Double Rainbows', 'Nessy'],
|
280
|
-
:friends => [
|
281
|
-
mock(:name => "Friend 1", :email => 'friend1@example.com', :fantasies => [], :birthday => Time.gm(2012, 2, 27), :friends => []),
|
282
|
-
mock(:name => "Friend 2", :email => 'friend2@example.com', :fantasies => [], :birthday => Time.gm(2012, 2, 27), :friends => [])
|
283
|
-
]
|
284
|
-
} }
|
285
|
-
|
286
|
-
subject{ fresh_class.new(model) }
|
287
487
|
|
288
|
-
|
488
|
+
let(:model) { double(attributes) }
|
289
489
|
|
490
|
+
let(:attributes) {
|
491
|
+
{
|
492
|
+
name: 'Bob Bobson',
|
493
|
+
email: 'bob@example.com',
|
494
|
+
birthday: Time.gm(2012, 2, 27),
|
495
|
+
fantasies: ['Unicorns', 'Double Rainbows', 'Nessy'],
|
496
|
+
friends: [
|
497
|
+
double(name: "Friend 1", email: 'friend1@example.com', fantasies: [], birthday: Time.gm(2012, 2, 27), friends: []),
|
498
|
+
double(name: "Friend 2", email: 'friend2@example.com', fantasies: [], birthday: Time.gm(2012, 2, 27), friends: [])
|
499
|
+
]
|
500
|
+
}
|
501
|
+
}
|
502
|
+
|
503
|
+
subject { fresh_class.new(model) }
|
504
|
+
|
505
|
+
describe '#serializable_hash' do
|
290
506
|
it 'does not throw an exception if a nil options object is passed' do
|
291
|
-
expect{ fresh_class.new(model).serializable_hash(nil) }.not_to raise_error
|
507
|
+
expect { fresh_class.new(model).serializable_hash(nil) }.not_to raise_error
|
292
508
|
end
|
293
509
|
|
294
510
|
it 'does not blow up when the model is nil' do
|
295
511
|
fresh_class.expose :name
|
296
|
-
expect{ fresh_class.new(nil).serializable_hash }.not_to raise_error
|
512
|
+
expect { fresh_class.new(nil).serializable_hash }.not_to raise_error
|
297
513
|
end
|
298
514
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
515
|
+
context "with safe option" do
|
516
|
+
it 'does not throw an exception when an attribute is not found on the object' do
|
517
|
+
fresh_class.expose :name, :nonexistent_attribute, safe: true
|
518
|
+
expect { fresh_class.new(model).serializable_hash }.not_to raise_error
|
519
|
+
end
|
303
520
|
|
304
|
-
|
305
|
-
|
521
|
+
it "does not expose attributes that don't exist on the object" do
|
522
|
+
fresh_class.expose :email, :nonexistent_attribute, :name, safe: true
|
306
523
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
524
|
+
res = fresh_class.new(model).serializable_hash
|
525
|
+
res.should have_key :email
|
526
|
+
res.should_not have_key :nonexistent_attribute
|
527
|
+
res.should have_key :name
|
528
|
+
end
|
529
|
+
|
530
|
+
it "does not expose attributes that don't exist on the object, even with criteria" do
|
531
|
+
fresh_class.expose :email
|
532
|
+
fresh_class.expose :nonexistent_attribute, safe: true, if: lambda { false }
|
533
|
+
fresh_class.expose :nonexistent_attribute2, safe: true, if: lambda { true }
|
534
|
+
|
535
|
+
res = fresh_class.new(model).serializable_hash
|
536
|
+
res.should have_key :email
|
537
|
+
res.should_not have_key :nonexistent_attribute
|
538
|
+
res.should_not have_key :nonexistent_attribute2
|
539
|
+
end
|
311
540
|
end
|
312
541
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
542
|
+
context "without safe option" do
|
543
|
+
it 'throws an exception when an attribute is not found on the object' do
|
544
|
+
fresh_class.expose :name, :nonexistent_attribute
|
545
|
+
expect { fresh_class.new(model).serializable_hash }.to raise_error
|
546
|
+
end
|
317
547
|
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
548
|
+
it "exposes attributes that don't exist on the object only when they are generated by a block" do
|
549
|
+
fresh_class.expose :nonexistent_attribute do |model, _|
|
550
|
+
"well, I do exist after all"
|
551
|
+
end
|
552
|
+
res = fresh_class.new(model).serializable_hash
|
553
|
+
res.should have_key :nonexistent_attribute
|
554
|
+
end
|
555
|
+
|
556
|
+
it "does not expose attributes that are generated by a block but have not passed criteria" do
|
557
|
+
fresh_class.expose :nonexistent_attribute, proc: lambda { |model, _|
|
558
|
+
"I exist, but it is not yet my time to shine"
|
559
|
+
}, if: lambda { |model, _| false }
|
560
|
+
res = fresh_class.new(model).serializable_hash
|
561
|
+
res.should_not have_key :nonexistent_attribute
|
562
|
+
end
|
322
563
|
end
|
323
564
|
|
324
|
-
it "exposes attributes that don't exist on the object only when they are generated by a block" do
|
325
|
-
|
565
|
+
it "exposes attributes that don't exist on the object only when they are generated by a block with options" do
|
566
|
+
module EntitySpec
|
567
|
+
class TestEntity < Grape::Entity
|
568
|
+
end
|
569
|
+
end
|
570
|
+
|
571
|
+
fresh_class.expose :nonexistent_attribute, using: EntitySpec::TestEntity do |model, _|
|
326
572
|
"well, I do exist after all"
|
327
573
|
end
|
328
574
|
res = fresh_class.new(model).serializable_hash
|
@@ -330,71 +576,88 @@ describe Grape::Entity do
|
|
330
576
|
end
|
331
577
|
|
332
578
|
it "does not expose attributes that are generated by a block but have not passed criteria" do
|
333
|
-
fresh_class.expose :nonexistent_attribute, :
|
579
|
+
fresh_class.expose :nonexistent_attribute, proc: lambda { |model, _|
|
334
580
|
"I exist, but it is not yet my time to shine"
|
335
|
-
},
|
581
|
+
}, if: lambda { |model, _| false }
|
336
582
|
res = fresh_class.new(model).serializable_hash
|
337
583
|
res.should_not have_key :nonexistent_attribute
|
338
584
|
end
|
339
585
|
|
340
586
|
context '#serializable_hash' do
|
341
|
-
|
342
587
|
module EntitySpec
|
343
588
|
class EmbeddedExample
|
344
589
|
def serializable_hash(opts = {})
|
345
|
-
{ :
|
590
|
+
{ abc: 'def' }
|
346
591
|
end
|
347
592
|
end
|
593
|
+
|
594
|
+
class EmbeddedExampleWithHash
|
595
|
+
def name
|
596
|
+
"abc"
|
597
|
+
end
|
598
|
+
|
599
|
+
def embedded
|
600
|
+
{ a: nil, b: EmbeddedExample.new }
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
348
604
|
class EmbeddedExampleWithMany
|
349
605
|
def name
|
350
606
|
"abc"
|
351
607
|
end
|
608
|
+
|
352
609
|
def embedded
|
353
|
-
[
|
610
|
+
[EmbeddedExample.new, EmbeddedExample.new]
|
354
611
|
end
|
355
612
|
end
|
613
|
+
|
356
614
|
class EmbeddedExampleWithOne
|
357
615
|
def name
|
358
616
|
"abc"
|
359
617
|
end
|
618
|
+
|
360
619
|
def embedded
|
361
620
|
EmbeddedExample.new
|
362
621
|
end
|
363
622
|
end
|
364
623
|
end
|
365
|
-
|
624
|
+
|
366
625
|
it 'serializes embedded objects which respond to #serializable_hash' do
|
367
626
|
fresh_class.expose :name, :embedded
|
368
627
|
presenter = fresh_class.new(EntitySpec::EmbeddedExampleWithOne.new)
|
369
|
-
presenter.serializable_hash.should == {:
|
628
|
+
presenter.serializable_hash.should == { name: "abc", embedded: { abc: "def" } }
|
370
629
|
end
|
371
630
|
|
372
631
|
it 'serializes embedded arrays of objects which respond to #serializable_hash' do
|
373
632
|
fresh_class.expose :name, :embedded
|
374
633
|
presenter = fresh_class.new(EntitySpec::EmbeddedExampleWithMany.new)
|
375
|
-
presenter.serializable_hash.should == {:
|
634
|
+
presenter.serializable_hash.should == { name: "abc", embedded: [{ abc: "def" }, { abc: "def" }] }
|
635
|
+
end
|
636
|
+
|
637
|
+
it 'serializes embedded hashes of objects which respond to #serializable_hash' do
|
638
|
+
fresh_class.expose :name, :embedded
|
639
|
+
presenter = fresh_class.new(EntitySpec::EmbeddedExampleWithHash.new)
|
640
|
+
presenter.serializable_hash.should == { name: "abc", embedded: { a: nil, b: { abc: "def" } } }
|
376
641
|
end
|
377
|
-
|
378
642
|
end
|
379
|
-
|
380
643
|
end
|
381
644
|
|
382
645
|
describe '#value_for' do
|
383
646
|
before do
|
384
647
|
fresh_class.class_eval do
|
385
648
|
expose :name, :email
|
386
|
-
expose :friends, :
|
649
|
+
expose :friends, using: self
|
387
650
|
expose :computed do |_, options|
|
388
651
|
options[:awesome]
|
389
652
|
end
|
390
653
|
|
391
|
-
expose :birthday, :
|
654
|
+
expose :birthday, format_with: :timestamp
|
392
655
|
|
393
656
|
def timestamp(date)
|
394
657
|
date.strftime('%m/%d/%Y')
|
395
658
|
end
|
396
659
|
|
397
|
-
expose :fantasies, :
|
660
|
+
expose :fantasies, format_with: lambda { |f| f.reverse }
|
398
661
|
end
|
399
662
|
end
|
400
663
|
|
@@ -404,54 +667,112 @@ describe Grape::Entity do
|
|
404
667
|
|
405
668
|
it 'instantiates a representation if that is called for' do
|
406
669
|
rep = subject.send(:value_for, :friends)
|
407
|
-
rep.reject{|r| r.is_a?(fresh_class)}.should be_empty
|
670
|
+
rep.reject { |r| r.is_a?(fresh_class) }.should be_empty
|
408
671
|
rep.first.serializable_hash[:name].should == 'Friend 1'
|
409
672
|
rep.last.serializable_hash[:name].should == 'Friend 2'
|
410
673
|
end
|
411
674
|
|
412
675
|
context 'child representations' do
|
413
676
|
it 'disables root key name for child representations' do
|
414
|
-
|
415
677
|
module EntitySpec
|
416
678
|
class FriendEntity < Grape::Entity
|
417
679
|
root 'friends', 'friend'
|
418
680
|
expose :name, :email
|
419
681
|
end
|
420
682
|
end
|
421
|
-
|
683
|
+
|
422
684
|
fresh_class.class_eval do
|
423
|
-
expose :friends, :
|
685
|
+
expose :friends, using: EntitySpec::FriendEntity
|
424
686
|
end
|
425
|
-
|
687
|
+
|
426
688
|
rep = subject.send(:value_for, :friends)
|
427
689
|
rep.should be_kind_of Array
|
428
|
-
rep.reject{|r| r.is_a?(EntitySpec::FriendEntity)}.should be_empty
|
690
|
+
rep.reject { |r| r.is_a?(EntitySpec::FriendEntity) }.should be_empty
|
429
691
|
rep.first.serializable_hash[:name].should == 'Friend 1'
|
430
692
|
rep.last.serializable_hash[:name].should == 'Friend 2'
|
431
693
|
end
|
432
694
|
|
695
|
+
it "passes through the proc which returns an array of objects with custom options(:using)" do
|
696
|
+
module EntitySpec
|
697
|
+
class FriendEntity < Grape::Entity
|
698
|
+
root 'friends', 'friend'
|
699
|
+
expose :name, :email
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
fresh_class.class_eval do
|
704
|
+
expose :custom_friends, using: EntitySpec::FriendEntity do |user, options|
|
705
|
+
user.friends
|
706
|
+
end
|
707
|
+
end
|
708
|
+
|
709
|
+
rep = subject.send(:value_for, :custom_friends)
|
710
|
+
rep.should be_kind_of Array
|
711
|
+
rep.reject { |r| r.is_a?(EntitySpec::FriendEntity) }.should be_empty
|
712
|
+
rep.first.serializable_hash.should == { name: 'Friend 1', email: 'friend1@example.com' }
|
713
|
+
rep.last.serializable_hash.should == { name: 'Friend 2', email: 'friend2@example.com' }
|
714
|
+
end
|
715
|
+
|
716
|
+
it "passes through the proc which returns single object with custom options(:using)" do
|
717
|
+
module EntitySpec
|
718
|
+
class FriendEntity < Grape::Entity
|
719
|
+
root 'friends', 'friend'
|
720
|
+
expose :name, :email
|
721
|
+
end
|
722
|
+
end
|
723
|
+
|
724
|
+
fresh_class.class_eval do
|
725
|
+
expose :first_friend, using: EntitySpec::FriendEntity do |user, options|
|
726
|
+
user.friends.first
|
727
|
+
end
|
728
|
+
end
|
729
|
+
|
730
|
+
rep = subject.send(:value_for, :first_friend)
|
731
|
+
rep.should be_kind_of EntitySpec::FriendEntity
|
732
|
+
rep.serializable_hash.should == { name: 'Friend 1', email: 'friend1@example.com' }
|
733
|
+
end
|
734
|
+
|
735
|
+
it "passes through the proc which returns empty with custom options(:using)" do
|
736
|
+
module EntitySpec
|
737
|
+
class FriendEntity < Grape::Entity
|
738
|
+
root 'friends', 'friend'
|
739
|
+
expose :name, :email
|
740
|
+
end
|
741
|
+
end
|
742
|
+
|
743
|
+
fresh_class.class_eval do
|
744
|
+
expose :first_friend, using: EntitySpec::FriendEntity do |user, options|
|
745
|
+
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
rep = subject.send(:value_for, :first_friend)
|
750
|
+
rep.should be_kind_of EntitySpec::FriendEntity
|
751
|
+
rep.serializable_hash.should be_nil
|
752
|
+
end
|
753
|
+
|
433
754
|
it 'passes through custom options' do
|
434
755
|
module EntitySpec
|
435
756
|
class FriendEntity < Grape::Entity
|
436
757
|
root 'friends', 'friend'
|
437
758
|
expose :name
|
438
|
-
expose :email, :
|
759
|
+
expose :email, if: { user_type: :admin }
|
439
760
|
end
|
440
761
|
end
|
441
|
-
|
762
|
+
|
442
763
|
fresh_class.class_eval do
|
443
|
-
expose :friends, :
|
764
|
+
expose :friends, using: EntitySpec::FriendEntity
|
444
765
|
end
|
445
|
-
|
766
|
+
|
446
767
|
rep = subject.send(:value_for, :friends)
|
447
768
|
rep.should be_kind_of Array
|
448
|
-
rep.reject{|r| r.is_a?(EntitySpec::FriendEntity)}.should be_empty
|
769
|
+
rep.reject { |r| r.is_a?(EntitySpec::FriendEntity) }.should be_empty
|
449
770
|
rep.first.serializable_hash[:email].should be_nil
|
450
771
|
rep.last.serializable_hash[:email].should be_nil
|
451
772
|
|
452
|
-
rep = subject.send(:value_for, :friends,
|
773
|
+
rep = subject.send(:value_for, :friends, user_type: :admin)
|
453
774
|
rep.should be_kind_of Array
|
454
|
-
rep.reject{|r| r.is_a?(EntitySpec::FriendEntity)}.should be_empty
|
775
|
+
rep.reject { |r| r.is_a?(EntitySpec::FriendEntity) }.should be_empty
|
455
776
|
rep.first.serializable_hash[:email].should == 'friend1@example.com'
|
456
777
|
rep.last.serializable_hash[:email].should == 'friend2@example.com'
|
457
778
|
end
|
@@ -461,25 +782,24 @@ describe Grape::Entity do
|
|
461
782
|
class FriendEntity < Grape::Entity
|
462
783
|
root 'friends', 'friend'
|
463
784
|
expose :name
|
464
|
-
expose :email, :
|
785
|
+
expose :email, if: { collection: true }
|
465
786
|
end
|
466
787
|
end
|
467
|
-
|
788
|
+
|
468
789
|
fresh_class.class_eval do
|
469
|
-
expose :friends, :
|
790
|
+
expose :friends, using: EntitySpec::FriendEntity
|
470
791
|
end
|
471
|
-
|
472
|
-
rep = subject.send(:value_for, :friends,
|
792
|
+
|
793
|
+
rep = subject.send(:value_for, :friends, collection: false)
|
473
794
|
rep.should be_kind_of Array
|
474
|
-
rep.reject{|r| r.is_a?(EntitySpec::FriendEntity)}.should be_empty
|
795
|
+
rep.reject { |r| r.is_a?(EntitySpec::FriendEntity) }.should be_empty
|
475
796
|
rep.first.serializable_hash[:email].should == 'friend1@example.com'
|
476
797
|
rep.last.serializable_hash[:email].should == 'friend2@example.com'
|
477
798
|
end
|
478
|
-
|
479
799
|
end
|
480
800
|
|
481
801
|
it 'calls through to the proc if there is one' do
|
482
|
-
subject.send(:value_for, :computed, :
|
802
|
+
subject.send(:value_for, :computed, awesome: 123).should == 123
|
483
803
|
end
|
484
804
|
|
485
805
|
it 'returns a formatted value if format_with is passed' do
|
@@ -489,6 +809,58 @@ describe Grape::Entity do
|
|
489
809
|
it 'returns a formatted value if format_with is passed a lambda' do
|
490
810
|
subject.send(:value_for, :fantasies).should == ['Nessy', 'Double Rainbows', 'Unicorns']
|
491
811
|
end
|
812
|
+
|
813
|
+
it "tries instance methods on the entity first" do
|
814
|
+
module EntitySpec
|
815
|
+
class DelegatingEntity < Grape::Entity
|
816
|
+
root 'friends', 'friend'
|
817
|
+
expose :name
|
818
|
+
expose :email
|
819
|
+
|
820
|
+
private
|
821
|
+
|
822
|
+
def name
|
823
|
+
"cooler name"
|
824
|
+
end
|
825
|
+
end
|
826
|
+
end
|
827
|
+
|
828
|
+
friend = double("Friend", name: "joe", email: "joe@example.com")
|
829
|
+
rep = EntitySpec::DelegatingEntity.new(friend)
|
830
|
+
rep.send(:value_for, :name).should == "cooler name"
|
831
|
+
rep.send(:value_for, :email).should == "joe@example.com"
|
832
|
+
end
|
833
|
+
|
834
|
+
context "using" do
|
835
|
+
before do
|
836
|
+
module EntitySpec
|
837
|
+
class UserEntity < Grape::Entity
|
838
|
+
expose :name, :email
|
839
|
+
end
|
840
|
+
end
|
841
|
+
end
|
842
|
+
it "string" do
|
843
|
+
fresh_class.class_eval do
|
844
|
+
expose :friends, using: "EntitySpec::UserEntity"
|
845
|
+
end
|
846
|
+
|
847
|
+
rep = subject.send(:value_for, :friends)
|
848
|
+
rep.should be_kind_of Array
|
849
|
+
rep.size.should == 2
|
850
|
+
rep.all? { |r| r.is_a?(EntitySpec::UserEntity) }.should be_true
|
851
|
+
end
|
852
|
+
|
853
|
+
it 'class' do
|
854
|
+
fresh_class.class_eval do
|
855
|
+
expose :friends, using: EntitySpec::UserEntity
|
856
|
+
end
|
857
|
+
|
858
|
+
rep = subject.send(:value_for, :friends)
|
859
|
+
rep.should be_kind_of Array
|
860
|
+
rep.size.should == 2
|
861
|
+
rep.all? { |r| r.is_a?(EntitySpec::UserEntity) }.should be_true
|
862
|
+
end
|
863
|
+
end
|
492
864
|
end
|
493
865
|
|
494
866
|
describe '#documentation' do
|
@@ -499,89 +871,98 @@ describe Grape::Entity do
|
|
499
871
|
end
|
500
872
|
|
501
873
|
it 'returns each defined documentation hash' do
|
502
|
-
doc = {:
|
503
|
-
fresh_class.expose :name, :
|
504
|
-
fresh_class.expose :email, :
|
874
|
+
doc = { type: "foo", desc: "bar" }
|
875
|
+
fresh_class.expose :name, documentation: doc
|
876
|
+
fresh_class.expose :email, documentation: doc
|
877
|
+
fresh_class.expose :birthday
|
878
|
+
|
879
|
+
subject.documentation.should == { name: doc, email: doc }
|
880
|
+
end
|
881
|
+
|
882
|
+
it 'returns each defined documentation hash with :as param considering' do
|
883
|
+
doc = { type: "foo", desc: "bar" }
|
884
|
+
fresh_class.expose :name, documentation: doc, as: :label
|
885
|
+
fresh_class.expose :email, documentation: doc
|
505
886
|
fresh_class.expose :birthday
|
506
887
|
|
507
|
-
subject.documentation.should == {:
|
888
|
+
subject.documentation.should == { label: doc, email: doc }
|
508
889
|
end
|
509
890
|
end
|
510
891
|
|
511
892
|
describe '#key_for' do
|
512
893
|
it 'returns the attribute if no :as is set' do
|
513
894
|
fresh_class.expose :name
|
514
|
-
subject.send(:key_for, :name).should == :name
|
895
|
+
subject.class.send(:key_for, :name).should == :name
|
515
896
|
end
|
516
897
|
|
517
898
|
it 'returns a symbolized version of the attribute' do
|
518
899
|
fresh_class.expose :name
|
519
|
-
subject.send(:key_for, 'name').should == :name
|
900
|
+
subject.class.send(:key_for, 'name').should == :name
|
520
901
|
end
|
521
902
|
|
522
903
|
it 'returns the :as alias if one exists' do
|
523
|
-
fresh_class.expose :name, :
|
524
|
-
subject.send(:key_for, 'name').should == :nombre
|
904
|
+
fresh_class.expose :name, as: :nombre
|
905
|
+
subject.class.send(:key_for, 'name').should == :nombre
|
525
906
|
end
|
526
907
|
end
|
527
908
|
|
528
909
|
describe '#conditions_met?' do
|
529
910
|
it 'only passes through hash :if exposure if all attributes match' do
|
530
|
-
exposure_options = {:
|
911
|
+
exposure_options = { if: { condition1: true, condition2: true } }
|
531
912
|
|
532
913
|
subject.send(:conditions_met?, exposure_options, {}).should be_false
|
533
|
-
subject.send(:conditions_met?, exposure_options, :
|
534
|
-
subject.send(:conditions_met?, exposure_options, :
|
535
|
-
subject.send(:conditions_met?, exposure_options, :
|
536
|
-
subject.send(:conditions_met?, exposure_options, :
|
914
|
+
subject.send(:conditions_met?, exposure_options, condition1: true).should be_false
|
915
|
+
subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true).should be_true
|
916
|
+
subject.send(:conditions_met?, exposure_options, condition1: false, condition2: true).should be_false
|
917
|
+
subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true, other: true).should be_true
|
537
918
|
end
|
538
919
|
|
539
920
|
it 'looks for presence/truthiness if a symbol is passed' do
|
540
|
-
exposure_options = {:
|
921
|
+
exposure_options = { if: :condition1 }
|
541
922
|
|
542
923
|
subject.send(:conditions_met?, exposure_options, {}).should be_false
|
543
|
-
subject.send(:conditions_met?, exposure_options,
|
544
|
-
subject.send(:conditions_met?, exposure_options,
|
545
|
-
subject.send(:conditions_met?, exposure_options,
|
924
|
+
subject.send(:conditions_met?, exposure_options, condition1: true).should be_true
|
925
|
+
subject.send(:conditions_met?, exposure_options, condition1: false).should be_false
|
926
|
+
subject.send(:conditions_met?, exposure_options, condition1: nil).should be_false
|
546
927
|
end
|
547
928
|
|
548
929
|
it 'looks for absence/falsiness if a symbol is passed' do
|
549
|
-
exposure_options = {:
|
930
|
+
exposure_options = { unless: :condition1 }
|
550
931
|
|
551
932
|
subject.send(:conditions_met?, exposure_options, {}).should be_true
|
552
|
-
subject.send(:conditions_met?, exposure_options,
|
553
|
-
subject.send(:conditions_met?, exposure_options,
|
554
|
-
subject.send(:conditions_met?, exposure_options,
|
933
|
+
subject.send(:conditions_met?, exposure_options, condition1: true).should be_false
|
934
|
+
subject.send(:conditions_met?, exposure_options, condition1: false).should be_true
|
935
|
+
subject.send(:conditions_met?, exposure_options, condition1: nil).should be_true
|
555
936
|
end
|
556
937
|
|
557
938
|
it 'only passes through proc :if exposure if it returns truthy value' do
|
558
|
-
exposure_options = {:
|
939
|
+
exposure_options = { if: lambda { |_, opts| opts[:true] } }
|
559
940
|
|
560
|
-
subject.send(:conditions_met?, exposure_options, :
|
561
|
-
subject.send(:conditions_met?, exposure_options, :
|
941
|
+
subject.send(:conditions_met?, exposure_options, true: false).should be_false
|
942
|
+
subject.send(:conditions_met?, exposure_options, true: true).should be_true
|
562
943
|
end
|
563
944
|
|
564
945
|
it 'only passes through hash :unless exposure if any attributes do not match' do
|
565
|
-
exposure_options = {:
|
946
|
+
exposure_options = { unless: { condition1: true, condition2: true } }
|
566
947
|
|
567
948
|
subject.send(:conditions_met?, exposure_options, {}).should be_true
|
568
|
-
subject.send(:conditions_met?, exposure_options, :
|
569
|
-
subject.send(:conditions_met?, exposure_options, :
|
570
|
-
subject.send(:conditions_met?, exposure_options, :
|
571
|
-
subject.send(:conditions_met?, exposure_options, :
|
572
|
-
subject.send(:conditions_met?, exposure_options, :
|
949
|
+
subject.send(:conditions_met?, exposure_options, condition1: true).should be_false
|
950
|
+
subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true).should be_false
|
951
|
+
subject.send(:conditions_met?, exposure_options, condition1: false, condition2: true).should be_false
|
952
|
+
subject.send(:conditions_met?, exposure_options, condition1: true, condition2: true, other: true).should be_false
|
953
|
+
subject.send(:conditions_met?, exposure_options, condition1: false, condition2: false).should be_true
|
573
954
|
end
|
574
955
|
|
575
956
|
it 'only passes through proc :unless exposure if it returns falsy value' do
|
576
|
-
exposure_options = {:
|
957
|
+
exposure_options = { unless: lambda { |_, options| options[:true] == true } }
|
577
958
|
|
578
|
-
subject.send(:conditions_met?, exposure_options, :
|
579
|
-
subject.send(:conditions_met?, exposure_options, :
|
959
|
+
subject.send(:conditions_met?, exposure_options, true: false).should be_true
|
960
|
+
subject.send(:conditions_met?, exposure_options, true: true).should be_false
|
580
961
|
end
|
581
962
|
end
|
582
963
|
|
583
964
|
describe '::DSL' do
|
584
|
-
subject{ Class.new }
|
965
|
+
subject { Class.new }
|
585
966
|
|
586
967
|
it 'creates an Entity class when called' do
|
587
968
|
subject.should_not be_const_defined :Entity
|
@@ -590,7 +971,7 @@ describe Grape::Entity do
|
|
590
971
|
end
|
591
972
|
|
592
973
|
context 'pre-mixed' do
|
593
|
-
before{ subject.send(:include, Grape::Entity::DSL) }
|
974
|
+
before { subject.send(:include, Grape::Entity::DSL) }
|
594
975
|
|
595
976
|
it 'is able to define entity traits through DSL' do
|
596
977
|
subject.entity do
|
@@ -613,7 +994,7 @@ describe Grape::Entity do
|
|
613
994
|
end
|
614
995
|
|
615
996
|
context 'instance' do
|
616
|
-
let(:instance){ subject.new }
|
997
|
+
let(:instance) { subject.new }
|
617
998
|
|
618
999
|
describe '#entity' do
|
619
1000
|
it 'is an instance of the entity class' do
|
@@ -624,8 +1005,8 @@ describe Grape::Entity do
|
|
624
1005
|
instance.entity.object.should == instance
|
625
1006
|
end
|
626
1007
|
|
627
|
-
it '
|
628
|
-
instance.entity(:
|
1008
|
+
it 'instantiates with options if provided' do
|
1009
|
+
instance.entity(awesome: true).options.should == { awesome: true }
|
629
1010
|
end
|
630
1011
|
end
|
631
1012
|
end
|