grape-entity 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +34 -23
- data/.rubocop_todo.yml +12 -36
- data/.travis.yml +7 -12
- data/CHANGELOG.md +16 -1
- data/Gemfile +2 -2
- data/Guardfile +4 -2
- data/README.md +4 -4
- data/grape-entity.gemspec +4 -6
- data/lib/grape_entity/delegator/fetchable_object.rb +1 -1
- data/lib/grape_entity/delegator/hash_object.rb +2 -2
- data/lib/grape_entity/delegator/openstruct_object.rb +1 -1
- data/lib/grape_entity/delegator/plain_object.rb +1 -1
- data/lib/grape_entity/entity.rb +53 -8
- data/lib/grape_entity/exposure.rb +9 -3
- data/lib/grape_entity/exposure/base.rb +4 -1
- data/lib/grape_entity/exposure/nesting_exposure.rb +1 -0
- data/lib/grape_entity/exposure/nesting_exposure/nested_exposures.rb +1 -1
- data/lib/grape_entity/exposure/nesting_exposure/output_builder.rb +1 -0
- data/lib/grape_entity/version.rb +1 -1
- data/spec/grape_entity/entity_spec.rb +32 -0
- data/spec/grape_entity/exposure/represent_exposure_spec.rb +3 -3
- data/spec/grape_entity/hash_spec.rb +36 -1
- data/spec/spec_helper.rb +6 -0
- metadata +8 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 619c4d253ef6fbfde4f5c3bff0a0a309a67ef6ce49d408de9f3912bf12c4f690
|
4
|
+
data.tar.gz: e4c3f773ba0b6c1751abdbc0642e730c325be409b6d0d55dae1c1b2ce075b7e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8937886f91fe82d37eb9a8eca7b6d4542b8dcb12b8ea241d8b08c4116305e351c3acc980722fe60dead828140c6c56425763854287b6e0736134e994da2b1f5e
|
7
|
+
data.tar.gz: 3073993606e0f950e39ed8417bbc33aaff7d21544bbdb3797b3e0325ee01c0c8f71c9a63295630af21006698fae585b0bd1a5139dd6241221e2aac07442f1ac6
|
data/.rubocop.yml
CHANGED
@@ -1,37 +1,48 @@
|
|
1
|
-
|
2
|
-
TargetRubyVersion: 2.4
|
3
|
-
Include:
|
4
|
-
- Dangerfile
|
1
|
+
inherit_from: .rubocop_todo.yml
|
5
2
|
|
3
|
+
AllCops:
|
6
4
|
Exclude:
|
7
5
|
- vendor/**/*
|
8
|
-
-
|
9
|
-
|
10
|
-
|
11
|
-
inherit_from: .rubocop_todo.yml
|
6
|
+
- example/**/*
|
7
|
+
TargetRubyVersion: 2.7
|
12
8
|
|
13
|
-
|
9
|
+
Layout/EmptyLinesAroundArguments:
|
14
10
|
Enabled: false
|
15
11
|
|
16
|
-
|
12
|
+
Layout/FirstHashElementIndentation:
|
13
|
+
EnforcedStyle: consistent
|
14
|
+
|
15
|
+
Layout/LineLength:
|
16
|
+
Max: 120
|
17
17
|
Exclude:
|
18
|
-
-
|
19
|
-
- 'Rakefile'
|
20
|
-
- 'grape-entity.gemspec'
|
21
|
-
- 'lib/grape-entity.rb'
|
18
|
+
- spec/**/*
|
22
19
|
|
23
|
-
|
24
|
-
|
20
|
+
Metrics/AbcSize:
|
21
|
+
Max: 25
|
25
22
|
|
26
|
-
|
27
|
-
|
23
|
+
Metrics/BlockLength:
|
24
|
+
Exclude:
|
25
|
+
- spec/**/*
|
28
26
|
|
29
|
-
|
30
|
-
|
27
|
+
Metrics/CyclomaticComplexity:
|
28
|
+
Max: 10
|
29
|
+
|
30
|
+
Metrics/ClassLength:
|
31
|
+
Max: 300
|
31
32
|
|
32
|
-
|
33
|
+
Metrics/MethodLength:
|
34
|
+
Max: 26
|
33
35
|
Exclude:
|
34
|
-
-
|
36
|
+
- spec/**/*
|
37
|
+
|
38
|
+
Metrics/PerceivedComplexity:
|
39
|
+
Max: 11
|
40
|
+
|
41
|
+
Naming:
|
42
|
+
Enabled: false
|
43
|
+
|
44
|
+
Style/Documentation:
|
45
|
+
Enabled: false
|
35
46
|
|
36
|
-
|
47
|
+
Style/RegexpLiteral:
|
37
48
|
Enabled: false
|
data/.rubocop_todo.yml
CHANGED
@@ -1,47 +1,29 @@
|
|
1
1
|
# This configuration was generated by
|
2
2
|
# `rubocop --auto-gen-config`
|
3
|
-
# on
|
3
|
+
# on 2020-02-18 16:38:42 +0100 using RuboCop version 0.79.0.
|
4
4
|
# The point is for the user to remove these configuration records
|
5
5
|
# one by one as the offenses are removed from the code base.
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
8
8
|
|
9
9
|
# Offense count: 1
|
10
|
-
|
10
|
+
# Configuration parameters: Include.
|
11
|
+
# Include: **/*.gemspec
|
12
|
+
Gemspec/RequiredRubyVersion:
|
11
13
|
Exclude:
|
12
|
-
- '
|
14
|
+
- 'grape-entity.gemspec'
|
13
15
|
|
14
16
|
# Offense count: 6
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
# Offense count: 35
|
19
|
-
# Configuration parameters: CountComments, ExcludedMethods.
|
20
|
-
Metrics/BlockLength:
|
21
|
-
Max: 1632
|
22
|
-
|
23
|
-
# Offense count: 2
|
24
|
-
# Configuration parameters: CountComments.
|
25
|
-
Metrics/ClassLength:
|
26
|
-
Max: 210
|
27
|
-
|
28
|
-
# Offense count: 2
|
29
|
-
Metrics/CyclomaticComplexity:
|
30
|
-
Max: 11
|
31
|
-
|
32
|
-
# Offense count: 7
|
33
|
-
# Configuration parameters: CountComments.
|
34
|
-
Metrics/MethodLength:
|
35
|
-
Max: 28
|
36
|
-
|
37
|
-
# Offense count: 2
|
38
|
-
Metrics/PerceivedComplexity:
|
39
|
-
Max: 13
|
17
|
+
Lint/BooleanSymbol:
|
18
|
+
Exclude:
|
19
|
+
- 'spec/grape_entity/exposure_spec.rb'
|
40
20
|
|
41
21
|
# Offense count: 1
|
42
|
-
|
22
|
+
# Configuration parameters: EnforcedStyle.
|
23
|
+
# SupportedStyles: inline, group
|
24
|
+
Style/AccessModifierDeclarations:
|
43
25
|
Exclude:
|
44
|
-
- '
|
26
|
+
- 'spec/grape_entity/entity_spec.rb'
|
45
27
|
|
46
28
|
# Offense count: 1
|
47
29
|
# Cop supports --auto-correct.
|
@@ -50,9 +32,3 @@ Style/EvalWithLocation:
|
|
50
32
|
Style/SymbolProc:
|
51
33
|
Exclude:
|
52
34
|
- 'spec/grape_entity/entity_spec.rb'
|
53
|
-
|
54
|
-
# Offense count: 250
|
55
|
-
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns.
|
56
|
-
# URISchemes: http, https
|
57
|
-
Metrics/LineLength:
|
58
|
-
Max: 146
|
data/.travis.yml
CHANGED
@@ -1,30 +1,25 @@
|
|
1
|
-
sudo: false
|
2
|
-
|
3
1
|
language: ruby
|
4
2
|
|
5
3
|
before_install:
|
6
|
-
- gem update --system
|
7
4
|
- gem install bundler
|
8
5
|
|
9
6
|
after_success:
|
10
|
-
- coveralls
|
11
7
|
- bundle exec danger
|
12
8
|
|
13
9
|
rvm:
|
14
|
-
- 2.5.
|
15
|
-
- 2.
|
10
|
+
- 2.5.7
|
11
|
+
- 2.6.5
|
12
|
+
- 2.7.0
|
13
|
+
- ruby-head
|
14
|
+
- jruby-head
|
16
15
|
|
17
16
|
matrix:
|
18
17
|
fast_finish: true
|
19
18
|
|
20
19
|
include:
|
21
|
-
- rvm: 2.
|
22
|
-
- rvm: ruby-head
|
23
|
-
- rvm: jruby-head
|
24
|
-
- rvm: rbx-2
|
20
|
+
- rvm: 2.4.9
|
25
21
|
|
26
22
|
allow_failures:
|
27
|
-
- rvm: 2.
|
23
|
+
- rvm: 2.4.9
|
28
24
|
- rvm: ruby-head
|
29
25
|
- rvm: jruby-head
|
30
|
-
- rvm: rbx-2
|
data/CHANGELOG.md
CHANGED
@@ -8,11 +8,26 @@
|
|
8
8
|
|
9
9
|
* Your contribution here.
|
10
10
|
|
11
|
+
### 0.9.0 (2020-02-18)
|
12
|
+
|
13
|
+
#### Features
|
14
|
+
|
15
|
+
* [#307](https://github.com/ruby-grape/grape-entity/pull/307): Allow exposures to call methods defined in modules included in an entity - [@robertoz-01](https://github.com/robertoz-01).
|
16
|
+
* [#319](https://github.com/ruby-grape/grape-entity/pull/319): Support hashes with string keys - [@mhenrixon](https://github.com/mhenrixon).
|
17
|
+
* [#300](https://github.com/ruby-grape/grape-entity/pull/300): Loosens activesupport to 3 - [@ericschultz](https://github.com/ericschultz).
|
18
|
+
|
19
|
+
#### Fixes
|
20
|
+
|
21
|
+
* [#330](https://github.com/ruby-grape/grape-entity/pull/330): CI: use Ruby 2.5.7, 2.6.5, 2.7.0 - [@budnik](https://github.com/budnik).
|
22
|
+
* [#329](https://github.com/ruby-grape/grape-entity/pull/329): Option expose_nil doesn't work when block is passed - [@serbiant](https://github.com/serbiant).
|
23
|
+
* [#320](https://github.com/ruby-grape/grape-entity/pull/320): Gemspec: drop eol'd property rubyforge_project - [@olleolleolle](https://github.com/olleolleolle).
|
24
|
+
* [#307](https://github.com/ruby-grape/grape-entity/pull/307): Allow exposures to call methods defined in modules included in an entity - [@robertoz-01](https://github.com/robertoz-01).
|
25
|
+
|
11
26
|
### 0.7.1 (2018-01-30)
|
12
27
|
|
13
28
|
#### Features
|
14
29
|
|
15
|
-
* [#
|
30
|
+
* [#297](https://github.com/ruby-grape/grape-entity/pull/297): Introduce `override` option for expose (fixes [#286](https://github.com/ruby-grape/grape-entity/issues/296)) - [@DmitryTsepelev](https://github.com/DmitryTsepelev).
|
16
31
|
|
17
32
|
### 0.7.0 (2018-01-25)
|
18
33
|
|
data/Gemfile
CHANGED
@@ -5,11 +5,11 @@ source 'http://rubygems.org'
|
|
5
5
|
gemspec
|
6
6
|
|
7
7
|
group :development, :test do
|
8
|
-
gem 'rubocop', '~> 0.
|
8
|
+
gem 'rubocop', '~> 0.79.0', require: false
|
9
9
|
end
|
10
10
|
|
11
11
|
group :test do
|
12
|
-
gem '
|
12
|
+
gem 'coveralls_reborn', require: false
|
13
13
|
gem 'growl'
|
14
14
|
gem 'guard'
|
15
15
|
gem 'guard-bundler'
|
data/Guardfile
CHANGED
@@ -1,11 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# A sample Guardfile
|
2
4
|
# More info at https://github.com/guard/guard#readme
|
3
5
|
|
4
6
|
guard 'rspec', version: 2 do
|
5
7
|
watch(%r{^spec/.+_spec\.rb$})
|
6
|
-
watch(%r{^lib/(.+)\.rb$})
|
8
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
7
9
|
watch(%r{^spec/support/shared_versioning_examples.rb$}) { |_m| 'spec/' }
|
8
|
-
watch('spec/spec_helper.rb')
|
10
|
+
watch('spec/spec_helper.rb') { 'spec/' }
|
9
11
|
end
|
10
12
|
|
11
13
|
guard 'bundler' do
|
data/README.md
CHANGED
@@ -3,7 +3,6 @@
|
|
3
3
|
[![Gem Version](http://img.shields.io/gem/v/grape-entity.svg)](http://badge.fury.io/rb/grape-entity)
|
4
4
|
[![Build Status](http://img.shields.io/travis/ruby-grape/grape-entity.svg)](https://travis-ci.org/ruby-grape/grape-entity)
|
5
5
|
[![Coverage Status](https://coveralls.io/repos/github/ruby-grape/grape-entity/badge.svg?branch=master)](https://coveralls.io/github/ruby-grape/grape-entity?branch=master)
|
6
|
-
[![Dependency Status](https://gemnasium.com/ruby-grape/grape-entity.svg)](https://gemnasium.com/ruby-grape/grape-entity)
|
7
6
|
[![Code Climate](https://codeclimate.com/github/ruby-grape/grape-entity.svg)](https://codeclimate.com/github/ruby-grape/grape-entity)
|
8
7
|
|
9
8
|
## Introduction
|
@@ -221,7 +220,8 @@ class ExampleEntity < Grape::Entity
|
|
221
220
|
end
|
222
221
|
```
|
223
222
|
|
224
|
-
You have
|
223
|
+
You always have access to the presented instance (`object`) and the top-level
|
224
|
+
entity options (`options`).
|
225
225
|
|
226
226
|
```ruby
|
227
227
|
class ExampleEntity < Grape::Entity
|
@@ -230,7 +230,7 @@ class ExampleEntity < Grape::Entity
|
|
230
230
|
private
|
231
231
|
|
232
232
|
def formatted_value
|
233
|
-
"+ X #{object.value}"
|
233
|
+
"+ X #{object.value} #{options[:y]}"
|
234
234
|
end
|
235
235
|
end
|
236
236
|
```
|
@@ -265,7 +265,7 @@ class User < Grape::Entity
|
|
265
265
|
expose :name
|
266
266
|
end
|
267
267
|
|
268
|
-
class Employee <
|
268
|
+
class Employee < User
|
269
269
|
expose :name, as: :employee_name, override: true
|
270
270
|
end
|
271
271
|
```
|
data/grape-entity.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
$LOAD_PATH.push File.expand_path('
|
3
|
+
$LOAD_PATH.push File.expand_path('lib', __dir__)
|
4
4
|
require 'grape_entity/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
@@ -14,11 +14,9 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.description = 'Extracted from Grape, A Ruby framework for rapid API development with great conventions.'
|
15
15
|
s.license = 'MIT'
|
16
16
|
|
17
|
-
s.required_ruby_version = '>= 2.
|
17
|
+
s.required_ruby_version = '>= 2.4'
|
18
18
|
|
19
|
-
s.
|
20
|
-
|
21
|
-
s.add_runtime_dependency 'activesupport', '>=4.0'
|
19
|
+
s.add_runtime_dependency 'activesupport', '>= 3.0.0'
|
22
20
|
# FIXME: remove dependecy
|
23
21
|
s.add_runtime_dependency 'multi_json', '>= 1.3.2'
|
24
22
|
|
@@ -28,7 +26,7 @@ Gem::Specification.new do |s|
|
|
28
26
|
s.add_development_dependency 'pry-byebug' unless RUBY_PLATFORM.eql?('java') || RUBY_ENGINE.eql?('rbx')
|
29
27
|
s.add_development_dependency 'rack-test'
|
30
28
|
s.add_development_dependency 'rake'
|
31
|
-
s.add_development_dependency 'rspec', '~> 3.
|
29
|
+
s.add_development_dependency 'rspec', '~> 3.9'
|
32
30
|
s.add_development_dependency 'yard'
|
33
31
|
|
34
32
|
s.files = `git ls-files`.split("\n")
|
data/lib/grape_entity/entity.rb
CHANGED
@@ -114,6 +114,22 @@ module Grape
|
|
114
114
|
end
|
115
115
|
|
116
116
|
attr_writer :formatters
|
117
|
+
|
118
|
+
def hash_access
|
119
|
+
@hash_access ||= :to_sym
|
120
|
+
end
|
121
|
+
|
122
|
+
def hash_access=(value)
|
123
|
+
@hash_access =
|
124
|
+
case value
|
125
|
+
when :to_s, :str, :string
|
126
|
+
:to_s
|
127
|
+
when :to_sym, :sym, :symbol
|
128
|
+
:to_sym
|
129
|
+
else
|
130
|
+
:to_sym
|
131
|
+
end
|
132
|
+
end
|
117
133
|
end
|
118
134
|
|
119
135
|
@formatters = {}
|
@@ -168,18 +184,23 @@ module Grape
|
|
168
184
|
# @option options :documentation Define documenation for an exposed
|
169
185
|
# field, typically the value is a hash with two fields, type and desc.
|
170
186
|
# @option options :merge This option allows you to merge an exposed field to the root
|
187
|
+
#
|
188
|
+
# rubocop:disable Layout/LineLength
|
171
189
|
def self.expose(*args, &block)
|
172
190
|
options = merge_options(args.last.is_a?(Hash) ? args.pop : {})
|
173
191
|
|
174
192
|
if args.size > 1
|
193
|
+
|
175
194
|
raise ArgumentError, 'You may not use the :as option on multi-attribute exposures.' if options[:as]
|
176
195
|
raise ArgumentError, 'You may not use the :expose_nil on multi-attribute exposures.' if options.key?(:expose_nil)
|
177
196
|
raise ArgumentError, 'You may not use block-setting on multi-attribute exposures.' if block_given?
|
178
197
|
end
|
179
198
|
|
180
|
-
raise ArgumentError, 'You may not use block-setting when also using format_with' if block_given? && options[:format_with].respond_to?(:call)
|
181
|
-
|
182
199
|
if block_given?
|
200
|
+
if options[:format_with].respond_to?(:call)
|
201
|
+
raise ArgumentError, 'You may not use block-setting when also using format_with'
|
202
|
+
end
|
203
|
+
|
183
204
|
if block.parameters.any?
|
184
205
|
options[:proc] = block
|
185
206
|
else
|
@@ -191,6 +212,7 @@ module Grape
|
|
191
212
|
@nesting_stack ||= []
|
192
213
|
args.each { |attribute| build_exposure_for_attribute(attribute, @nesting_stack, options, block) }
|
193
214
|
end
|
215
|
+
# rubocop:enable Layout/LineLength
|
194
216
|
|
195
217
|
def self.build_exposure_for_attribute(attribute, nesting_stack, options, block)
|
196
218
|
exposure_list = nesting_stack.empty? ? root_exposures : nesting_stack.last.nested_exposures
|
@@ -291,6 +313,7 @@ module Grape
|
|
291
313
|
#
|
292
314
|
def self.format_with(name, &block)
|
293
315
|
raise ArgumentError, 'You must pass a block for formatters' unless block_given?
|
316
|
+
|
294
317
|
formatters[name.to_sym] = block
|
295
318
|
end
|
296
319
|
|
@@ -454,8 +477,8 @@ module Grape
|
|
454
477
|
|
455
478
|
def initialize(object, options = {})
|
456
479
|
@object = object
|
457
|
-
@delegator = Delegator.new(object)
|
458
480
|
@options = options.is_a?(Options) ? options : Options.new(options)
|
481
|
+
@delegator = Delegator.new(object)
|
459
482
|
end
|
460
483
|
|
461
484
|
def root_exposures
|
@@ -506,28 +529,50 @@ module Grape
|
|
506
529
|
end
|
507
530
|
|
508
531
|
def delegate_attribute(attribute)
|
509
|
-
if
|
532
|
+
if is_defined_in_entity?(attribute)
|
510
533
|
send(attribute)
|
511
534
|
else
|
512
|
-
delegator.delegate(attribute)
|
535
|
+
delegator.delegate(attribute, hash_access: self.class.hash_access)
|
513
536
|
end
|
514
537
|
end
|
515
538
|
|
539
|
+
def is_defined_in_entity?(attribute)
|
540
|
+
return false unless respond_to?(attribute, true)
|
541
|
+
|
542
|
+
ancestors = self.class.ancestors
|
543
|
+
ancestors.index(Grape::Entity) > ancestors.index(method(attribute).owner)
|
544
|
+
end
|
545
|
+
|
516
546
|
alias as_json serializable_hash
|
517
547
|
|
518
548
|
def to_json(options = {})
|
519
|
-
options = options.to_h if options
|
549
|
+
options = options.to_h if options&.respond_to?(:to_h)
|
520
550
|
MultiJson.dump(serializable_hash(options))
|
521
551
|
end
|
522
552
|
|
523
553
|
def to_xml(options = {})
|
524
|
-
options = options.to_h if options
|
554
|
+
options = options.to_h if options&.respond_to?(:to_h)
|
525
555
|
serializable_hash(options).to_xml(options)
|
526
556
|
end
|
527
557
|
|
528
558
|
# All supported options.
|
529
559
|
OPTIONS = %i[
|
530
|
-
rewrite
|
560
|
+
rewrite
|
561
|
+
as
|
562
|
+
if
|
563
|
+
unless
|
564
|
+
using
|
565
|
+
with
|
566
|
+
proc
|
567
|
+
documentation
|
568
|
+
format_with
|
569
|
+
safe
|
570
|
+
attr_path
|
571
|
+
if_extras
|
572
|
+
unless_extras
|
573
|
+
merge
|
574
|
+
expose_nil
|
575
|
+
override
|
531
576
|
].to_set.freeze
|
532
577
|
|
533
578
|
# Merges the given options with current block options.
|
@@ -47,14 +47,20 @@ module Grape
|
|
47
47
|
options[:unless]
|
48
48
|
].compact.flatten.map { |cond| Condition.new_unless(cond) }
|
49
49
|
|
50
|
-
unless_conditions << expose_nil_condition(attribute) if options[:expose_nil] == false
|
50
|
+
unless_conditions << expose_nil_condition(attribute, options) if options[:expose_nil] == false
|
51
51
|
|
52
52
|
if_conditions + unless_conditions
|
53
53
|
end
|
54
54
|
|
55
|
-
def expose_nil_condition(attribute)
|
55
|
+
def expose_nil_condition(attribute, options)
|
56
56
|
Condition.new_unless(
|
57
|
-
proc
|
57
|
+
proc do |object, _options|
|
58
|
+
if options[:proc].nil?
|
59
|
+
Delegator.new(object).delegate(attribute).nil?
|
60
|
+
else
|
61
|
+
exec_with_object(options, &options[:proc]).nil?
|
62
|
+
end
|
63
|
+
end
|
58
64
|
)
|
59
65
|
end
|
60
66
|
|
@@ -54,7 +54,10 @@ module Grape
|
|
54
54
|
if @is_safe
|
55
55
|
is_delegatable
|
56
56
|
else
|
57
|
-
is_delegatable || raise(
|
57
|
+
is_delegatable || raise(
|
58
|
+
NoMethodError,
|
59
|
+
"#{entity.class.name} missing attribute `#{@attribute}' on #{entity.object}"
|
60
|
+
)
|
58
61
|
end
|
59
62
|
end
|
60
63
|
|
@@ -19,6 +19,7 @@ module Grape
|
|
19
19
|
# If we have an array which should not be merged - save it with a key as a hash
|
20
20
|
# If we have hash which should be merged - save it without a key (merge)
|
21
21
|
return unless result
|
22
|
+
|
22
23
|
@output_hash.merge! result, &merge_strategy(exposure.for_merge)
|
23
24
|
else
|
24
25
|
@output_hash[exposure.key(@entity)] = result
|
data/lib/grape_entity/version.rb
CHANGED
@@ -126,6 +126,26 @@ describe Grape::Entity do
|
|
126
126
|
expect { subject.expose(:a, :b, :c, expose_nil: false) }.to raise_error ArgumentError
|
127
127
|
end
|
128
128
|
end
|
129
|
+
|
130
|
+
context 'when expose_nil option is false and block passed' do
|
131
|
+
it 'does not expose if block returns nil' do
|
132
|
+
subject.expose(:a, expose_nil: false) do |_obj, _options|
|
133
|
+
nil
|
134
|
+
end
|
135
|
+
subject.expose(:b)
|
136
|
+
subject.expose(:c)
|
137
|
+
expect(subject.represent(model).serializable_hash).to eq(b: nil, c: 'value')
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'exposes is block returns a value' do
|
141
|
+
subject.expose(:a, expose_nil: false) do |_obj, _options|
|
142
|
+
100
|
143
|
+
end
|
144
|
+
subject.expose(:b)
|
145
|
+
subject.expose(:c)
|
146
|
+
expect(subject.represent(model).serializable_hash).to eq(a: 100, b: nil, c: 'value')
|
147
|
+
end
|
148
|
+
end
|
129
149
|
end
|
130
150
|
|
131
151
|
context 'when model is a hash' do
|
@@ -1376,6 +1396,18 @@ describe Grape::Entity do
|
|
1376
1396
|
expect(res).to have_key :nonexistent_attribute
|
1377
1397
|
end
|
1378
1398
|
|
1399
|
+
it 'exposes attributes defined through module inclusion' do
|
1400
|
+
module SharedAttributes
|
1401
|
+
def a_value
|
1402
|
+
3.14
|
1403
|
+
end
|
1404
|
+
end
|
1405
|
+
fresh_class.include(SharedAttributes)
|
1406
|
+
fresh_class.expose :a_value
|
1407
|
+
res = fresh_class.new(model).serializable_hash
|
1408
|
+
expect(res[:a_value]).to eq(3.14)
|
1409
|
+
end
|
1410
|
+
|
1379
1411
|
it 'does not expose attributes that are generated by a block but have not passed criteria' do
|
1380
1412
|
fresh_class.expose :nonexistent_attribute,
|
1381
1413
|
proc: ->(_, _) { 'I exist, but it is not yet my time to shine' },
|
@@ -12,11 +12,11 @@ describe Grape::Entity::Exposure::RepresentExposure do
|
|
12
12
|
let(:subexposure) { double(:subexposure) }
|
13
13
|
|
14
14
|
it 'sets using_class_name' do
|
15
|
-
expect { subject }.to change
|
15
|
+
expect { subject }.to change(exposure, :using_class_name).to(using_class_name)
|
16
16
|
end
|
17
17
|
|
18
18
|
it 'sets subexposure' do
|
19
|
-
expect { subject }.to change
|
19
|
+
expect { subject }.to change(exposure, :subexposure).to(subexposure)
|
20
20
|
end
|
21
21
|
|
22
22
|
context 'when using_class is set' do
|
@@ -25,7 +25,7 @@ describe Grape::Entity::Exposure::RepresentExposure do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
it 'resets using_class' do
|
28
|
-
expect { subject }.to change
|
28
|
+
expect { subject }.to change(exposure, :using_class)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Grape::Entity do
|
6
|
-
it 'except option for nested entity' do
|
6
|
+
it 'except option for nested entity', :aggregate_failures do
|
7
7
|
module EntitySpec
|
8
8
|
class Address < Grape::Entity
|
9
9
|
expose :post, if: :full
|
@@ -12,6 +12,14 @@ describe Grape::Entity do
|
|
12
12
|
expose :house
|
13
13
|
end
|
14
14
|
|
15
|
+
class AddressWithString < Grape::Entity
|
16
|
+
self.hash_access = :string
|
17
|
+
expose :post, if: :full
|
18
|
+
expose :city
|
19
|
+
expose :street
|
20
|
+
expose :house
|
21
|
+
end
|
22
|
+
|
15
23
|
class Company < Grape::Entity
|
16
24
|
expose :full_name, if: :full
|
17
25
|
expose :name
|
@@ -19,6 +27,15 @@ describe Grape::Entity do
|
|
19
27
|
Address.represent c[:address], Grape::Entity::Options.new(o.opts_hash.except(:full))
|
20
28
|
end
|
21
29
|
end
|
30
|
+
|
31
|
+
class CompanyWithString < Grape::Entity
|
32
|
+
self.hash_access = :string
|
33
|
+
expose :full_name, if: :full
|
34
|
+
expose :name
|
35
|
+
expose :address do |c, o|
|
36
|
+
AddressWithString.represent c['address'], Grape::Entity::Options.new(o.opts_hash.except(:full))
|
37
|
+
end
|
38
|
+
end
|
22
39
|
end
|
23
40
|
|
24
41
|
company = {
|
@@ -33,6 +50,24 @@ describe Grape::Entity do
|
|
33
50
|
}
|
34
51
|
}
|
35
52
|
|
53
|
+
company_with_string = {
|
54
|
+
'full_name' => 'full_name',
|
55
|
+
'name' => 'name',
|
56
|
+
'address' => {
|
57
|
+
'post' => '123456',
|
58
|
+
'city' => 'city',
|
59
|
+
'street' => 'street',
|
60
|
+
'house' => 'house',
|
61
|
+
'something_else' => 'something_else'
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
expect(EntitySpec::CompanyWithString.represent(company_with_string).serializable_hash).to eq \
|
66
|
+
company.slice(:name).merge(address: company[:address].slice(:city, :street, :house))
|
67
|
+
|
68
|
+
expect(EntitySpec::CompanyWithString.represent(company_with_string, full: true).serializable_hash).to eq \
|
69
|
+
company.slice(:full_name, :name).merge(address: company[:address].slice(:city, :street, :house))
|
70
|
+
|
36
71
|
expect(EntitySpec::Company.represent(company).serializable_hash).to eq \
|
37
72
|
company.slice(:name).merge(address: company[:address].slice(:city, :street, :house))
|
38
73
|
|
data/spec/spec_helper.rb
CHANGED
@@ -3,6 +3,12 @@
|
|
3
3
|
require 'simplecov'
|
4
4
|
require 'coveralls'
|
5
5
|
|
6
|
+
# This works around the hash extensions not being automatically included in ActiveSupport < 4
|
7
|
+
require 'active_support/version'
|
8
|
+
require 'active_support/core_ext/hash' if ActiveSupport::VERSION &&
|
9
|
+
ActiveSupport::VERSION::MAJOR &&
|
10
|
+
ActiveSupport::VERSION::MAJOR < 4
|
11
|
+
|
6
12
|
SimpleCov.start do
|
7
13
|
add_filter 'spec/'
|
8
14
|
end
|
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.
|
4
|
+
version: 0.8.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:
|
11
|
+
date: 2020-02-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 3.0.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 3.0.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: multi_json
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: '3.
|
131
|
+
version: '3.9'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: '3.
|
138
|
+
version: '3.9'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: yard
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -222,15 +222,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
222
222
|
requirements:
|
223
223
|
- - ">="
|
224
224
|
- !ruby/object:Gem::Version
|
225
|
-
version: '2.
|
225
|
+
version: '2.4'
|
226
226
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
227
227
|
requirements:
|
228
228
|
- - ">="
|
229
229
|
- !ruby/object:Gem::Version
|
230
230
|
version: '0'
|
231
231
|
requirements: []
|
232
|
-
|
233
|
-
rubygems_version: 2.7.3
|
232
|
+
rubygems_version: 3.1.2
|
234
233
|
signing_key:
|
235
234
|
specification_version: 4
|
236
235
|
summary: A simple facade for managing the relationship between your model and API.
|