grape-entity 0.1.0
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.
- data/.gitignore +37 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/.yardopts +2 -0
- data/CHANGELOG.markdown +8 -0
- data/Gemfile +16 -0
- data/Guardfile +15 -0
- data/LICENSE +20 -0
- data/README.markdown +210 -0
- data/Rakefile +51 -0
- data/grape-entity.gemspec +35 -0
- data/lib/grape-entity.rb +1 -0
- data/lib/grape_entity.rb +5 -0
- data/lib/grape_entity/entity.rb +389 -0
- data/lib/grape_entity/version.rb +3 -0
- data/spec/grape_entity/entity_spec.rb +579 -0
- data/spec/spec_helper.rb +12 -0
- data/tmp/rspec_guard_result +1 -0
- metadata +154 -0
@@ -0,0 +1,579 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe GrapeEntity::Entity do
|
4
|
+
let(:fresh_class) { Class.new(GrapeEntity::Entity) }
|
5
|
+
|
6
|
+
context 'class methods' do
|
7
|
+
subject { fresh_class }
|
8
|
+
|
9
|
+
describe '.expose' do
|
10
|
+
context 'multiple attributes' do
|
11
|
+
it 'is able to add multiple exposed attributes with a single call' do
|
12
|
+
subject.expose :name, :email, :location
|
13
|
+
subject.exposures.size.should == 3
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'sets the same options for all exposures passed' do
|
17
|
+
subject.expose :name, :email, :location, :foo => :bar
|
18
|
+
subject.exposures.values.each{|v| v.should == {:foo => :bar}}
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'option validation' do
|
23
|
+
it 'makes sure that :as only works on single attribute calls' do
|
24
|
+
expect{ subject.expose :name, :email, :as => :foo }.to raise_error(ArgumentError)
|
25
|
+
expect{ subject.expose :name, :as => :foo }.not_to raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'makes sure that :format_with as a proc can not be used with a block' do
|
29
|
+
expect { subject.expose :name, :format_with => Proc.new {} do |_| end }.to raise_error(ArgumentError)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context 'with a block' do
|
34
|
+
it 'errors out if called with multiple attributes' do
|
35
|
+
expect{ subject.expose(:name, :email) do
|
36
|
+
true
|
37
|
+
end }.to raise_error(ArgumentError)
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'sets the :proc option in the exposure options' do
|
41
|
+
block = lambda{|_| true }
|
42
|
+
subject.expose :name, &block
|
43
|
+
subject.exposures[:name][:proc].should == block
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'inherited exposures' do
|
48
|
+
it 'returns exposures from an ancestor' do
|
49
|
+
subject.expose :name, :email
|
50
|
+
child_class = Class.new(subject)
|
51
|
+
|
52
|
+
child_class.exposures.should eq(subject.exposures)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'returns exposures from multiple ancestor' do
|
56
|
+
subject.expose :name, :email
|
57
|
+
parent_class = Class.new(subject)
|
58
|
+
child_class = Class.new(parent_class)
|
59
|
+
|
60
|
+
child_class.exposures.should eq(subject.exposures)
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'returns descendant exposures as a priority' do
|
64
|
+
subject.expose :name, :email
|
65
|
+
child_class = Class.new(subject)
|
66
|
+
child_class.expose :name do |_|
|
67
|
+
'foo'
|
68
|
+
end
|
69
|
+
|
70
|
+
subject.exposures[:name].should_not have_key :proc
|
71
|
+
child_class.exposures[:name].should have_key :proc
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'register formatters' do
|
76
|
+
let(:date_formatter) { lambda {|date| date.strftime('%m/%d/%Y') }}
|
77
|
+
|
78
|
+
it 'registers a formatter' do
|
79
|
+
subject.format_with :timestamp, &date_formatter
|
80
|
+
|
81
|
+
subject.formatters[:timestamp].should_not be_nil
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'inherits formatters from ancestors' do
|
85
|
+
subject.format_with :timestamp, &date_formatter
|
86
|
+
child_class = Class.new(subject)
|
87
|
+
|
88
|
+
child_class.formatters.should == subject.formatters
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'does not allow registering a formatter without a block' do
|
92
|
+
expect{ subject.format_with :foo }.to raise_error(ArgumentError)
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'formats an exposure with a registered formatter' do
|
96
|
+
subject.format_with :timestamp do |date|
|
97
|
+
date.strftime('%m/%d/%Y')
|
98
|
+
end
|
99
|
+
|
100
|
+
subject.expose :birthday, :format_with => :timestamp
|
101
|
+
|
102
|
+
model = { :birthday => Time.gm(2012, 2, 27) }
|
103
|
+
subject.new(mock(model)).as_json[:birthday].should == '02/27/2012'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '.represent' do
|
109
|
+
it 'returns a single entity if called with one object' do
|
110
|
+
subject.represent(Object.new).should be_kind_of(subject)
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'returns a single entity if called with a hash' do
|
114
|
+
subject.represent(Hash.new).should be_kind_of(subject)
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'returns multiple entities if called with a collection' do
|
118
|
+
representation = subject.represent(4.times.map{Object.new})
|
119
|
+
representation.should be_kind_of Array
|
120
|
+
representation.size.should == 4
|
121
|
+
representation.reject{|r| r.kind_of?(subject)}.should be_empty
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'adds the :collection => true option if called with a collection' do
|
125
|
+
representation = subject.represent(4.times.map{Object.new})
|
126
|
+
representation.each{|r| r.options[:collection].should be_true}
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '.root' do
|
131
|
+
context 'with singular and plural root keys' do
|
132
|
+
before(:each) do
|
133
|
+
subject.root 'things', 'thing'
|
134
|
+
end
|
135
|
+
|
136
|
+
context 'with a single object' do
|
137
|
+
it 'allows a root element name to be specified' do
|
138
|
+
representation = subject.represent(Object.new)
|
139
|
+
representation.should be_kind_of Hash
|
140
|
+
representation.should have_key 'thing'
|
141
|
+
representation['thing'].should be_kind_of(subject)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'with an array of objects' do
|
146
|
+
it 'allows a root element name to be specified' do
|
147
|
+
representation = subject.represent(4.times.map{Object.new})
|
148
|
+
representation.should be_kind_of Hash
|
149
|
+
representation.should have_key 'things'
|
150
|
+
representation['things'].should be_kind_of Array
|
151
|
+
representation['things'].size.should == 4
|
152
|
+
representation['things'].reject{|r| r.kind_of?(subject)}.should be_empty
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
context 'it can be overridden' do
|
157
|
+
it 'can be disabled' do
|
158
|
+
representation = subject.represent(4.times.map{Object.new}, :root=>false)
|
159
|
+
representation.should be_kind_of Array
|
160
|
+
representation.size.should == 4
|
161
|
+
representation.reject{|r| r.kind_of?(subject)}.should be_empty
|
162
|
+
end
|
163
|
+
it 'can use a different name' do
|
164
|
+
representation = subject.represent(4.times.map{Object.new}, :root=>'others')
|
165
|
+
representation.should be_kind_of Hash
|
166
|
+
representation.should have_key 'others'
|
167
|
+
representation['others'].should be_kind_of Array
|
168
|
+
representation['others'].size.should == 4
|
169
|
+
representation['others'].reject{|r| r.kind_of?(subject)}.should be_empty
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
context 'with singular root key' do
|
175
|
+
before(:each) do
|
176
|
+
subject.root nil, 'thing'
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'with a single object' do
|
180
|
+
it 'allows a root element name to be specified' do
|
181
|
+
representation = subject.represent(Object.new)
|
182
|
+
representation.should be_kind_of Hash
|
183
|
+
representation.should have_key 'thing'
|
184
|
+
representation['thing'].should be_kind_of(subject)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
context 'with an array of objects' do
|
189
|
+
it 'allows a root element name to be specified' do
|
190
|
+
representation = subject.represent(4.times.map{Object.new})
|
191
|
+
representation.should be_kind_of Array
|
192
|
+
representation.size.should == 4
|
193
|
+
representation.reject{|r| r.kind_of?(subject)}.should be_empty
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
context 'with plural root key' do
|
199
|
+
before(:each) do
|
200
|
+
subject.root 'things'
|
201
|
+
end
|
202
|
+
|
203
|
+
context 'with a single object' do
|
204
|
+
it 'allows a root element name to be specified' do
|
205
|
+
subject.represent(Object.new).should be_kind_of(subject)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'with an array of objects' do
|
210
|
+
it 'allows a root element name to be specified' do
|
211
|
+
representation = subject.represent(4.times.map{Object.new})
|
212
|
+
representation.should be_kind_of Hash
|
213
|
+
representation.should have_key('things')
|
214
|
+
representation['things'].should be_kind_of Array
|
215
|
+
representation['things'].size.should == 4
|
216
|
+
representation['things'].reject{|r| r.kind_of?(subject)}.should be_empty
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe '#initialize' do
|
223
|
+
it 'takes an object and an optional options hash' do
|
224
|
+
expect{ subject.new(Object.new) }.not_to raise_error
|
225
|
+
expect{ subject.new }.to raise_error(ArgumentError)
|
226
|
+
expect{ subject.new(Object.new, {}) }.not_to raise_error
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'has attribute readers for the object and options' do
|
230
|
+
entity = subject.new('abc', {})
|
231
|
+
entity.object.should == 'abc'
|
232
|
+
entity.options.should == {}
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
context 'instance methods' do
|
238
|
+
|
239
|
+
let(:model){ mock(attributes) }
|
240
|
+
|
241
|
+
let(:attributes) { {
|
242
|
+
:name => 'Bob Bobson',
|
243
|
+
:email => 'bob@example.com',
|
244
|
+
:birthday => Time.gm(2012, 2, 27),
|
245
|
+
:fantasies => ['Unicorns', 'Double Rainbows', 'Nessy'],
|
246
|
+
:friends => [
|
247
|
+
mock(:name => "Friend 1", :email => 'friend1@example.com', :fantasies => [], :birthday => Time.gm(2012, 2, 27), :friends => []),
|
248
|
+
mock(:name => "Friend 2", :email => 'friend2@example.com', :fantasies => [], :birthday => Time.gm(2012, 2, 27), :friends => [])
|
249
|
+
]
|
250
|
+
} }
|
251
|
+
|
252
|
+
subject{ fresh_class.new(model) }
|
253
|
+
|
254
|
+
describe '#serializable_hash' do
|
255
|
+
|
256
|
+
it 'does not throw an exception if a nil options object is passed' do
|
257
|
+
expect{ fresh_class.new(model).serializable_hash(nil) }.not_to raise_error
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'does not blow up when the model is nil' do
|
261
|
+
fresh_class.expose :name
|
262
|
+
expect{ fresh_class.new(nil).serializable_hash }.not_to raise_error
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'does not throw an exception when an attribute is not found on the object' do
|
266
|
+
fresh_class.expose :name, :nonexistent_attribute
|
267
|
+
expect{ fresh_class.new(model).serializable_hash }.not_to raise_error
|
268
|
+
end
|
269
|
+
|
270
|
+
it "does not expose attributes that don't exist on the object" do
|
271
|
+
fresh_class.expose :email, :nonexistent_attribute, :name
|
272
|
+
|
273
|
+
res = fresh_class.new(model).serializable_hash
|
274
|
+
res.should have_key :email
|
275
|
+
res.should_not have_key :nonexistent_attribute
|
276
|
+
res.should have_key :name
|
277
|
+
end
|
278
|
+
|
279
|
+
it "does not expose attributes that don't exist on the object, even with criteria" do
|
280
|
+
fresh_class.expose :email
|
281
|
+
fresh_class.expose :nonexistent_attribute, :if => lambda { false }
|
282
|
+
fresh_class.expose :nonexistent_attribute2, :if => lambda { true }
|
283
|
+
|
284
|
+
res = fresh_class.new(model).serializable_hash
|
285
|
+
res.should have_key :email
|
286
|
+
res.should_not have_key :nonexistent_attribute
|
287
|
+
res.should_not have_key :nonexistent_attribute2
|
288
|
+
end
|
289
|
+
|
290
|
+
it "exposes attributes that don't exist on the object only when they are generated by a block" do
|
291
|
+
fresh_class.expose :nonexistent_attribute do |model, _|
|
292
|
+
"well, I do exist after all"
|
293
|
+
end
|
294
|
+
res = fresh_class.new(model).serializable_hash
|
295
|
+
res.should have_key :nonexistent_attribute
|
296
|
+
end
|
297
|
+
|
298
|
+
it "does not expose attributes that are generated by a block but have not passed criteria" do
|
299
|
+
fresh_class.expose :nonexistent_attribute, :proc => lambda {|model, _|
|
300
|
+
"I exist, but it is not yet my time to shine"
|
301
|
+
}, :if => lambda { |model, _| false }
|
302
|
+
res = fresh_class.new(model).serializable_hash
|
303
|
+
res.should_not have_key :nonexistent_attribute
|
304
|
+
end
|
305
|
+
|
306
|
+
context '#serializable_hash' do
|
307
|
+
|
308
|
+
module EntitySpec
|
309
|
+
class EmbeddedExample
|
310
|
+
def serializable_hash(opts = {})
|
311
|
+
{ :abc => 'def' }
|
312
|
+
end
|
313
|
+
end
|
314
|
+
class EmbeddedExampleWithMany
|
315
|
+
def name
|
316
|
+
"abc"
|
317
|
+
end
|
318
|
+
def embedded
|
319
|
+
[ EmbeddedExample.new, EmbeddedExample.new ]
|
320
|
+
end
|
321
|
+
end
|
322
|
+
class EmbeddedExampleWithOne
|
323
|
+
def name
|
324
|
+
"abc"
|
325
|
+
end
|
326
|
+
def embedded
|
327
|
+
EmbeddedExample.new
|
328
|
+
end
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'serializes embedded objects which respond to #serializable_hash' do
|
333
|
+
fresh_class.expose :name, :embedded
|
334
|
+
presenter = fresh_class.new(EntitySpec::EmbeddedExampleWithOne.new)
|
335
|
+
presenter.serializable_hash.should == {:name => "abc", :embedded => {:abc => "def"}}
|
336
|
+
end
|
337
|
+
|
338
|
+
it 'serializes embedded arrays of objects which respond to #serializable_hash' do
|
339
|
+
fresh_class.expose :name, :embedded
|
340
|
+
presenter = fresh_class.new(EntitySpec::EmbeddedExampleWithMany.new)
|
341
|
+
presenter.serializable_hash.should == {:name => "abc", :embedded => [{:abc => "def"}, {:abc => "def"}]}
|
342
|
+
end
|
343
|
+
|
344
|
+
end
|
345
|
+
|
346
|
+
end
|
347
|
+
|
348
|
+
describe '#value_for' do
|
349
|
+
before do
|
350
|
+
fresh_class.class_eval do
|
351
|
+
expose :name, :email
|
352
|
+
expose :friends, :using => self
|
353
|
+
expose :computed do |_, options|
|
354
|
+
options[:awesome]
|
355
|
+
end
|
356
|
+
|
357
|
+
expose :birthday, :format_with => :timestamp
|
358
|
+
|
359
|
+
def timestamp(date)
|
360
|
+
date.strftime('%m/%d/%Y')
|
361
|
+
end
|
362
|
+
|
363
|
+
expose :fantasies, :format_with => lambda {|f| f.reverse }
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
it 'passes through bare expose attributes' do
|
368
|
+
subject.send(:value_for, :name).should == attributes[:name]
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'instantiates a representation if that is called for' do
|
372
|
+
rep = subject.send(:value_for, :friends)
|
373
|
+
rep.reject{|r| r.is_a?(fresh_class)}.should be_empty
|
374
|
+
rep.first.serializable_hash[:name].should == 'Friend 1'
|
375
|
+
rep.last.serializable_hash[:name].should == 'Friend 2'
|
376
|
+
end
|
377
|
+
|
378
|
+
context 'child representations' do
|
379
|
+
it 'disables root key name for child representations' do
|
380
|
+
|
381
|
+
module EntitySpec
|
382
|
+
class FriendEntity < GrapeEntity::Entity
|
383
|
+
root 'friends', 'friend'
|
384
|
+
expose :name, :email
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
fresh_class.class_eval do
|
389
|
+
expose :friends, :using => EntitySpec::FriendEntity
|
390
|
+
end
|
391
|
+
|
392
|
+
rep = subject.send(:value_for, :friends)
|
393
|
+
rep.should be_kind_of Array
|
394
|
+
rep.reject{|r| r.is_a?(EntitySpec::FriendEntity)}.should be_empty
|
395
|
+
rep.first.serializable_hash[:name].should == 'Friend 1'
|
396
|
+
rep.last.serializable_hash[:name].should == 'Friend 2'
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'passes through custom options' do
|
400
|
+
module EntitySpec
|
401
|
+
class FriendEntity < GrapeEntity::Entity
|
402
|
+
root 'friends', 'friend'
|
403
|
+
expose :name
|
404
|
+
expose :email, :if => { :user_type => :admin }
|
405
|
+
end
|
406
|
+
end
|
407
|
+
|
408
|
+
fresh_class.class_eval do
|
409
|
+
expose :friends, :using => EntitySpec::FriendEntity
|
410
|
+
end
|
411
|
+
|
412
|
+
rep = subject.send(:value_for, :friends)
|
413
|
+
rep.should be_kind_of Array
|
414
|
+
rep.reject{|r| r.is_a?(EntitySpec::FriendEntity)}.should be_empty
|
415
|
+
rep.first.serializable_hash[:email].should be_nil
|
416
|
+
rep.last.serializable_hash[:email].should be_nil
|
417
|
+
|
418
|
+
rep = subject.send(:value_for, :friends, { :user_type => :admin })
|
419
|
+
rep.should be_kind_of Array
|
420
|
+
rep.reject{|r| r.is_a?(EntitySpec::FriendEntity)}.should be_empty
|
421
|
+
rep.first.serializable_hash[:email].should == 'friend1@example.com'
|
422
|
+
rep.last.serializable_hash[:email].should == 'friend2@example.com'
|
423
|
+
end
|
424
|
+
|
425
|
+
it 'ignores the :collection parameter in the source options' do
|
426
|
+
module EntitySpec
|
427
|
+
class FriendEntity < GrapeEntity::Entity
|
428
|
+
root 'friends', 'friend'
|
429
|
+
expose :name
|
430
|
+
expose :email, :if => { :collection => true }
|
431
|
+
end
|
432
|
+
end
|
433
|
+
|
434
|
+
fresh_class.class_eval do
|
435
|
+
expose :friends, :using => EntitySpec::FriendEntity
|
436
|
+
end
|
437
|
+
|
438
|
+
rep = subject.send(:value_for, :friends, { :collection => false })
|
439
|
+
rep.should be_kind_of Array
|
440
|
+
rep.reject{|r| r.is_a?(EntitySpec::FriendEntity)}.should be_empty
|
441
|
+
rep.first.serializable_hash[:email].should == 'friend1@example.com'
|
442
|
+
rep.last.serializable_hash[:email].should == 'friend2@example.com'
|
443
|
+
end
|
444
|
+
|
445
|
+
end
|
446
|
+
|
447
|
+
it 'calls through to the proc if there is one' do
|
448
|
+
subject.send(:value_for, :computed, :awesome => 123).should == 123
|
449
|
+
end
|
450
|
+
|
451
|
+
it 'returns a formatted value if format_with is passed' do
|
452
|
+
subject.send(:value_for, :birthday).should == '02/27/2012'
|
453
|
+
end
|
454
|
+
|
455
|
+
it 'returns a formatted value if format_with is passed a lambda' do
|
456
|
+
subject.send(:value_for, :fantasies).should == ['Nessy', 'Double Rainbows', 'Unicorns']
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
describe '#documentation' do
|
461
|
+
it 'returns an empty hash is no documentation is provided' do
|
462
|
+
fresh_class.expose :name
|
463
|
+
|
464
|
+
subject.documentation.should == {}
|
465
|
+
end
|
466
|
+
|
467
|
+
it 'returns each defined documentation hash' do
|
468
|
+
doc = {:type => "foo", :desc => "bar"}
|
469
|
+
fresh_class.expose :name, :documentation => doc
|
470
|
+
fresh_class.expose :email, :documentation => doc
|
471
|
+
fresh_class.expose :birthday
|
472
|
+
|
473
|
+
subject.documentation.should == {:name => doc, :email => doc}
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
describe '#key_for' do
|
478
|
+
it 'returns the attribute if no :as is set' do
|
479
|
+
fresh_class.expose :name
|
480
|
+
subject.send(:key_for, :name).should == :name
|
481
|
+
end
|
482
|
+
|
483
|
+
it 'returns a symbolized version of the attribute' do
|
484
|
+
fresh_class.expose :name
|
485
|
+
subject.send(:key_for, 'name').should == :name
|
486
|
+
end
|
487
|
+
|
488
|
+
it 'returns the :as alias if one exists' do
|
489
|
+
fresh_class.expose :name, :as => :nombre
|
490
|
+
subject.send(:key_for, 'name').should == :nombre
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
describe '#conditions_met?' do
|
495
|
+
it 'only passes through hash :if exposure if all attributes match' do
|
496
|
+
exposure_options = {:if => {:condition1 => true, :condition2 => true}}
|
497
|
+
|
498
|
+
subject.send(:conditions_met?, exposure_options, {}).should be_false
|
499
|
+
subject.send(:conditions_met?, exposure_options, :condition1 => true).should be_false
|
500
|
+
subject.send(:conditions_met?, exposure_options, :condition1 => true, :condition2 => true).should be_true
|
501
|
+
subject.send(:conditions_met?, exposure_options, :condition1 => false, :condition2 => true).should be_false
|
502
|
+
subject.send(:conditions_met?, exposure_options, :condition1 => true, :condition2 => true, :other => true).should be_true
|
503
|
+
end
|
504
|
+
|
505
|
+
it 'only passes through proc :if exposure if it returns truthy value' do
|
506
|
+
exposure_options = {:if => lambda{|_,opts| opts[:true]}}
|
507
|
+
|
508
|
+
subject.send(:conditions_met?, exposure_options, :true => false).should be_false
|
509
|
+
subject.send(:conditions_met?, exposure_options, :true => true).should be_true
|
510
|
+
end
|
511
|
+
|
512
|
+
it 'only passes through hash :unless exposure if any attributes do not match' do
|
513
|
+
exposure_options = {:unless => {:condition1 => true, :condition2 => true}}
|
514
|
+
|
515
|
+
subject.send(:conditions_met?, exposure_options, {}).should be_true
|
516
|
+
subject.send(:conditions_met?, exposure_options, :condition1 => true).should be_false
|
517
|
+
subject.send(:conditions_met?, exposure_options, :condition1 => true, :condition2 => true).should be_false
|
518
|
+
subject.send(:conditions_met?, exposure_options, :condition1 => false, :condition2 => true).should be_false
|
519
|
+
subject.send(:conditions_met?, exposure_options, :condition1 => true, :condition2 => true, :other => true).should be_false
|
520
|
+
subject.send(:conditions_met?, exposure_options, :condition1 => false, :condition2 => false).should be_true
|
521
|
+
end
|
522
|
+
|
523
|
+
it 'only passes through proc :unless exposure if it returns falsy value' do
|
524
|
+
exposure_options = {:unless => lambda{|_,options| options[:true] == true}}
|
525
|
+
|
526
|
+
subject.send(:conditions_met?, exposure_options, :true => false).should be_true
|
527
|
+
subject.send(:conditions_met?, exposure_options, :true => true).should be_false
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
describe '::DSL' do
|
532
|
+
subject{ Class.new }
|
533
|
+
|
534
|
+
it 'creates an Entity class when called' do
|
535
|
+
subject.should_not be_const_defined :Entity
|
536
|
+
subject.send(:include, GrapeEntity::Entity::DSL)
|
537
|
+
subject.should be_const_defined :Entity
|
538
|
+
end
|
539
|
+
|
540
|
+
context 'pre-mixed' do
|
541
|
+
before{ subject.send(:include, GrapeEntity::Entity::DSL) }
|
542
|
+
|
543
|
+
it 'is able to define entity traits through DSL' do
|
544
|
+
subject.entity do
|
545
|
+
expose :name
|
546
|
+
end
|
547
|
+
|
548
|
+
subject.entity_class.exposures.should_not be_empty
|
549
|
+
end
|
550
|
+
|
551
|
+
it 'is able to expose straight from the class' do
|
552
|
+
subject.entity :name, :email
|
553
|
+
subject.entity_class.exposures.size.should == 2
|
554
|
+
end
|
555
|
+
|
556
|
+
it 'is able to mix field and advanced exposures' do
|
557
|
+
subject.entity :name, :email do
|
558
|
+
expose :third
|
559
|
+
end
|
560
|
+
subject.entity_class.exposures.size.should == 3
|
561
|
+
end
|
562
|
+
|
563
|
+
context 'instance' do
|
564
|
+
let(:instance){ subject.new }
|
565
|
+
|
566
|
+
describe '#entity' do
|
567
|
+
it 'is an instance of the entity class' do
|
568
|
+
instance.entity.should be_kind_of(subject.entity_class)
|
569
|
+
end
|
570
|
+
|
571
|
+
it 'has an object of itself' do
|
572
|
+
instance.entity.object.should == instance
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|
576
|
+
end
|
577
|
+
end
|
578
|
+
end
|
579
|
+
end
|