grape-entity 0.9.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 040fece8639b5fd085e4c77f1c88172e686e2655adf5e1cbb80aa0bb06c46faf
4
- data.tar.gz: f688469ee710ac98ed822d41c3724f47d1ec8b6f9aa067eead52c07662c45121
3
+ metadata.gz: 7c0080bab47d3cd3667c29ef580dcca4977ba5572d95c56304dd55cc444456fc
4
+ data.tar.gz: 40b564ee118de1a2a5b36dcff7526ca6bb1c54d738b7ac2191b1a208a583add1
5
5
  SHA512:
6
- metadata.gz: 3f14751f855805e0ea16f5c232a67c70c76d7523075a93ad442de9a31c9eb04816c1deae576d0e68671f6126790e7ca7d96bc8a7da4aa7c61d06f00385863c69
7
- data.tar.gz: 2d683f2414287de225b0d47e615f91563daf3b73c74e674c24cd2a1c6c2a417098ce0118e23d7272bf165d2895cb09fab824d52dfcb069dbfd8ea6e860b03b63
6
+ metadata.gz: 06564de07c6a909a3dbd4c3839902f529c5c44291f1a0669bcbc3dca7ea1e015db71887ca9f46132ef5bf4bb01fd10fced74b09ac392f3678903d39875816b63
7
+ data.tar.gz: 3e22b1382012b543d50a256e1792f9f79e3b02d49e42420353a351d49f549f021cd3dede90c576f657f0e61df862c0d8879cfb9c0a1d4578ef77a5648845ff6e
data/CHANGELOG.md CHANGED
@@ -9,6 +9,17 @@
9
9
  * Your contribution here.
10
10
 
11
11
 
12
+ ### 0.10.0 (2021-09-15)
13
+
14
+ #### Features
15
+
16
+ * [#352](https://github.com/ruby-grape/grape-entity/pull/352): Add Default value option - [@ahmednaguib](https://github.com/ahmednaguib).
17
+
18
+ #### Fixes
19
+
20
+ * [#355](https://github.com/ruby-grape/grape-entity/pull/355): Fix infinite loop problem with the `NameErrors` in block exposures - [@meinac](https://github.com/meinac).
21
+
22
+
12
23
  ### 0.9.0 (2021-03-20)
13
24
 
14
25
  #### Features
data/README.md CHANGED
@@ -24,6 +24,7 @@
24
24
  - [Aliases](#aliases)
25
25
  - [Format Before Exposing](#format-before-exposing)
26
26
  - [Expose Nil](#expose-nil)
27
+ - [Default Value](#default-value)
27
28
  - [Documentation](#documentation)
28
29
  - [Options Hash](#options-hash)
29
30
  - [Passing Additional Option To Nested Exposure](#passing-additional-option-to-nested-exposure)
@@ -482,6 +483,19 @@ module Entities
482
483
  end
483
484
  ```
484
485
 
486
+ #### Default Value
487
+
488
+ This option can be used to provide a default value in case the return value is nil or empty.
489
+
490
+ ```ruby
491
+ module Entities
492
+ class MyModel < Grape::Entity
493
+ expose :name, default: ''
494
+ expose :age, default: 60
495
+ end
496
+ end
497
+ ```
498
+
485
499
  #### Documentation
486
500
 
487
501
  Expose documentation with the field. Gets bubbled up when used with Grape and various API documentation systems.
@@ -153,7 +153,7 @@ module Grape
153
153
  #
154
154
  # @example as: a proc or lambda
155
155
  #
156
- # object = OpenStruct(awesomness: 'awesome_key', awesome: 'not-my-key', other: 'other-key' )
156
+ # object = OpenStruct(awesomeness: 'awesome_key', awesome: 'not-my-key', other: 'other-key' )
157
157
  #
158
158
  # class MyEntity < Grape::Entity
159
159
  # expose :awesome, as: proc { object.awesomeness }
@@ -527,7 +527,7 @@ module Grape
527
527
  # it handles: https://github.com/ruby/ruby/blob/v3_0_0_preview1/NEWS.md#language-changes point 3, Proc
528
528
  raise Grape::Entity::Deprecated.new e.message, 'in ruby 3.0' if e.is_a?(ArgumentError)
529
529
 
530
- raise e.class, e.message
530
+ raise e
531
531
  end
532
532
 
533
533
  def exec_with_attribute(attribute, &block)
@@ -585,6 +585,7 @@ module Grape
585
585
  merge
586
586
  expose_nil
587
587
  override
588
+ default
588
589
  ].to_set.freeze
589
590
 
590
591
  # Merges the given options with current block options.
@@ -16,6 +16,7 @@ module Grape
16
16
  key = options[:as] || attribute
17
17
  @key = key.respond_to?(:to_sym) ? key.to_sym : key
18
18
  @is_safe = options[:safe]
19
+ @default_value = options[:default]
19
20
  @for_merge = options[:merge]
20
21
  @attr_path_proc = options[:attr_path]
21
22
  @documentation = options[:documentation]
@@ -82,7 +83,10 @@ module Grape
82
83
  end
83
84
 
84
85
  def valid_value(entity, options)
85
- value(entity, options) if valid?(entity)
86
+ return unless valid?(entity)
87
+
88
+ output = value(entity, options)
89
+ output.blank? && @default_value.present? ? @default_value : output
86
90
  end
87
91
 
88
92
  def should_return_key?(options)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GrapeEntity
4
- VERSION = '0.9.0'
4
+ VERSION = '0.10.0'
5
5
  end
@@ -30,9 +30,7 @@ describe Grape::Entity do
30
30
 
31
31
  it 'makes sure that :format_with as a proc cannot be used with a block' do
32
32
  # rubocop:disable Style/BlockDelimiters
33
- # rubocop:disable Lint/EmptyBlock
34
33
  expect { subject.expose :name, format_with: proc {} do p 'hi' end }.to raise_error ArgumentError
35
- # rubocop:enable Lint/EmptyBlock
36
34
  # rubocop:enable Style/BlockDelimiters
37
35
  end
38
36
 
@@ -214,6 +212,130 @@ describe Grape::Entity do
214
212
  end
215
213
  end
216
214
 
215
+ context 'with :default option' do
216
+ let(:a) { nil }
217
+ let(:b) { nil }
218
+ let(:c) { 'value' }
219
+
220
+ context 'when model is a PORO' do
221
+ let(:model) { Model.new(a, b, c) }
222
+
223
+ before do
224
+ stub_const 'Model', Class.new
225
+ Model.class_eval do
226
+ attr_accessor :a, :b, :c
227
+
228
+ def initialize(a, b, c)
229
+ @a = a
230
+ @b = b
231
+ @c = c
232
+ end
233
+ end
234
+ end
235
+
236
+ context 'when default option is not provided' do
237
+ it 'exposes attributes values' do
238
+ subject.expose(:a)
239
+ subject.expose(:b)
240
+ subject.expose(:c)
241
+ expect(subject.represent(model).serializable_hash).to eq(a: nil, b: nil, c: 'value')
242
+ end
243
+ end
244
+
245
+ context 'when default option is set' do
246
+ it 'exposes default values for attributes' do
247
+ subject.expose(:a, default: 'a')
248
+ subject.expose(:b, default: 'b')
249
+ subject.expose(:c, default: 'c')
250
+ expect(subject.represent(model).serializable_hash).to eq(a: 'a', b: 'b', c: 'value')
251
+ end
252
+ end
253
+
254
+ context 'when default option is set and block passed' do
255
+ it 'return default value if block returns nil' do
256
+ subject.expose(:a, default: 'a') do |_obj, _options|
257
+ nil
258
+ end
259
+ subject.expose(:b)
260
+ subject.expose(:c)
261
+ expect(subject.represent(model).serializable_hash).to eq(a: 'a', b: nil, c: 'value')
262
+ end
263
+
264
+ it 'return value from block if block returns a value' do
265
+ subject.expose(:a, default: 'a') do |_obj, _options|
266
+ 100
267
+ end
268
+ subject.expose(:b)
269
+ subject.expose(:c)
270
+ expect(subject.represent(model).serializable_hash).to eq(a: 100, b: nil, c: 'value')
271
+ end
272
+ end
273
+ end
274
+
275
+ context 'when model is a hash' do
276
+ let(:model) { { a: a, b: b, c: c } }
277
+
278
+ context 'when expose_nil option is not provided' do
279
+ it 'exposes nil attributes' do
280
+ subject.expose(:a)
281
+ subject.expose(:b)
282
+ subject.expose(:c)
283
+ expect(subject.represent(model).serializable_hash).to eq(a: nil, b: nil, c: 'value')
284
+ end
285
+ end
286
+
287
+ context 'when expose_nil option is true' do
288
+ it 'exposes nil attributes' do
289
+ subject.expose(:a, expose_nil: true)
290
+ subject.expose(:b, expose_nil: true)
291
+ subject.expose(:c)
292
+ expect(subject.represent(model).serializable_hash).to eq(a: nil, b: nil, c: 'value')
293
+ end
294
+ end
295
+
296
+ context 'when expose_nil option is false' do
297
+ it 'does not expose nil attributes' do
298
+ subject.expose(:a, expose_nil: false)
299
+ subject.expose(:b, expose_nil: false)
300
+ subject.expose(:c)
301
+ expect(subject.represent(model).serializable_hash).to eq(c: 'value')
302
+ end
303
+
304
+ it 'is only applied per attribute' do
305
+ subject.expose(:a, expose_nil: false)
306
+ subject.expose(:b)
307
+ subject.expose(:c)
308
+ expect(subject.represent(model).serializable_hash).to eq(b: nil, c: 'value')
309
+ end
310
+
311
+ it 'raises an error when applied to multiple attribute exposures' do
312
+ expect { subject.expose(:a, :b, :c, expose_nil: false) }.to raise_error ArgumentError
313
+ end
314
+ end
315
+ end
316
+
317
+ context 'with nested structures' do
318
+ let(:model) { { a: a, b: b, c: { d: nil, e: nil, f: { g: nil, h: nil } } } }
319
+
320
+ context 'when expose_nil option is false' do
321
+ it 'does not expose nil attributes' do
322
+ subject.expose(:a, expose_nil: false)
323
+ subject.expose(:b)
324
+ subject.expose(:c) do
325
+ subject.expose(:d, expose_nil: false)
326
+ subject.expose(:e)
327
+ subject.expose(:f) do
328
+ subject.expose(:g, expose_nil: false)
329
+ subject.expose(:h)
330
+ end
331
+ end
332
+
333
+ expect(subject.represent(model).serializable_hash).to eq(b: nil, c: { e: nil, f: { h: nil } })
334
+ end
335
+ end
336
+ end
337
+ end
338
+
217
339
  context 'with a block' do
218
340
  it 'errors out if called with multiple attributes' do
219
341
  expect { subject.expose(:name, :email) { true } }.to raise_error ArgumentError
@@ -1137,6 +1259,18 @@ describe Grape::Entity do
1137
1259
  expect(representation).to eq(id: nil, name: nil, user: { id: nil, name: nil, email: nil })
1138
1260
  end
1139
1261
  end
1262
+
1263
+ context 'when NameError happens in a parameterized block_exposure' do
1264
+ before do
1265
+ subject.expose :raise_no_method_error do |_|
1266
+ foo
1267
+ end
1268
+ end
1269
+
1270
+ it 'does not cause infinite loop' do
1271
+ expect { subject.represent({}, serializable: true) }.to raise_error(NameError)
1272
+ end
1273
+ end
1140
1274
  end
1141
1275
  end
1142
1276
 
@@ -1581,7 +1715,7 @@ describe Grape::Entity do
1581
1715
  end
1582
1716
 
1583
1717
  fresh_class.class_eval do
1584
- expose :characteristics, using: EntitySpec::NoPathCharacterEntity, attr_path: proc { nil }
1718
+ expose :characteristics, using: EntitySpec::NoPathCharacterEntity, attr_path: proc {}
1585
1719
  end
1586
1720
 
1587
1721
  expect(subject.serializable_hash).to eq(
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grape-entity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Bleigh
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-03-20 00:00:00.000000000 Z
11
+ date: 2021-09-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -232,7 +232,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
232
232
  - !ruby/object:Gem::Version
233
233
  version: '0'
234
234
  requirements: []
235
- rubygems_version: 3.2.3
235
+ rubygems_version: 3.2.22
236
236
  signing_key:
237
237
  specification_version: 4
238
238
  summary: A simple facade for managing the relationship between your model and API.