grape-entity 0.7.1 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31f997094eb9145e0e34541cc1083562afbc7724f68c343d9bb8f897b1af8c5f
4
- data.tar.gz: 271397df6ac51ffdd5e6380a1e4ab47affb3fbb14d805f6d00cc6715084d0f13
3
+ metadata.gz: 619c4d253ef6fbfde4f5c3bff0a0a309a67ef6ce49d408de9f3912bf12c4f690
4
+ data.tar.gz: e4c3f773ba0b6c1751abdbc0642e730c325be409b6d0d55dae1c1b2ce075b7e2
5
5
  SHA512:
6
- metadata.gz: '0916c3b71d39463de13549202659f8e2c60634e6e6951b9999d45a045307c716f7bcada5a86c100066029a8e4f7da7aea5bf296bc8659f9a871162118c196d3d'
7
- data.tar.gz: ed8956de1f403808e504a60b3759e19a0012f9d91db9200fc63891f7d5f5bc29116084619bd47e41d8afce3ef8a98180c620c1f902b3f0dbd4eb42f37d4bb596
6
+ metadata.gz: 8937886f91fe82d37eb9a8eca7b6d4542b8dcb12b8ea241d8b08c4116305e351c3acc980722fe60dead828140c6c56425763854287b6e0736134e994da2b1f5e
7
+ data.tar.gz: 3073993606e0f950e39ed8417bbc33aaff7d21544bbdb3797b3e0325ee01c0c8f71c9a63295630af21006698fae585b0bd1a5139dd6241221e2aac07442f1ac6
@@ -1,37 +1,48 @@
1
- AllCops:
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
- - bin/**/*
9
- - Guardfile
10
-
11
- inherit_from: .rubocop_todo.yml
6
+ - example/**/*
7
+ TargetRubyVersion: 2.7
12
8
 
13
- Gemspec/RequiredRubyVersion:
9
+ Layout/EmptyLinesAroundArguments:
14
10
  Enabled: false
15
11
 
16
- Naming/FileName:
12
+ Layout/FirstHashElementIndentation:
13
+ EnforcedStyle: consistent
14
+
15
+ Layout/LineLength:
16
+ Max: 120
17
17
  Exclude:
18
- - 'Gemfile'
19
- - 'Rakefile'
20
- - 'grape-entity.gemspec'
21
- - 'lib/grape-entity.rb'
18
+ - spec/**/*
22
19
 
23
- Style/Documentation:
24
- Enabled: false
20
+ Metrics/AbcSize:
21
+ Max: 25
25
22
 
26
- Style/MultilineIfModifier:
27
- Enabled: false
23
+ Metrics/BlockLength:
24
+ Exclude:
25
+ - spec/**/*
28
26
 
29
- Style/RaiseArgs:
30
- Enabled: false
27
+ Metrics/CyclomaticComplexity:
28
+ Max: 10
29
+
30
+ Metrics/ClassLength:
31
+ Max: 300
31
32
 
32
- Lint/BooleanSymbol:
33
+ Metrics/MethodLength:
34
+ Max: 26
33
35
  Exclude:
34
- - 'spec/grape_entity/exposure_spec.rb'
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
- Lint/UnneededDisable:
47
+ Style/RegexpLiteral:
37
48
  Enabled: false
@@ -1,47 +1,29 @@
1
1
  # This configuration was generated by
2
2
  # `rubocop --auto-gen-config`
3
- # on 2018-01-11 18:20:10 +0100 using RuboCop version 0.52.1.
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
- Lint/AmbiguousBlockAssociation:
10
+ # Configuration parameters: Include.
11
+ # Include: **/*.gemspec
12
+ Gemspec/RequiredRubyVersion:
11
13
  Exclude:
12
- - 'spec/grape_entity/exposure/represent_exposure_spec.rb'
14
+ - 'grape-entity.gemspec'
13
15
 
14
16
  # Offense count: 6
15
- Metrics/AbcSize:
16
- Max: 32
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
- Style/EvalWithLocation:
22
+ # Configuration parameters: EnforcedStyle.
23
+ # SupportedStyles: inline, group
24
+ Style/AccessModifierDeclarations:
43
25
  Exclude:
44
- - 'lib/grape_entity/exposure/nesting_exposure/nested_exposures.rb'
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
@@ -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.0
15
- - 2.4.3
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.3.6
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.3.6
23
+ - rvm: 2.4.9
28
24
  - rvm: ruby-head
29
25
  - rvm: jruby-head
30
- - rvm: rbx-2
@@ -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
- * [#292](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).
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.51', require: false
8
+ gem 'rubocop', '~> 0.79.0', require: false
9
9
  end
10
10
 
11
11
  group :test do
12
- gem 'coveralls', require: false
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$}) { |m| "spec/#{m[1]}_spec.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') { 'spec/' }
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 always access to the presented instance with `object`
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 < UserData
268
+ class Employee < User
269
269
  expose :name, as: :employee_name, override: true
270
270
  end
271
271
  ```
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- $LOAD_PATH.push File.expand_path('../lib', __FILE__)
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.3'
17
+ s.required_ruby_version = '>= 2.4'
18
18
 
19
- s.rubyforge_project = 'grape-entity'
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.0'
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")
@@ -4,7 +4,7 @@ module Grape
4
4
  class Entity
5
5
  module Delegator
6
6
  class FetchableObject < Base
7
- def delegate(attribute)
7
+ def delegate(attribute, **)
8
8
  object.fetch attribute
9
9
  end
10
10
  end
@@ -4,8 +4,8 @@ module Grape
4
4
  class Entity
5
5
  module Delegator
6
6
  class HashObject < Base
7
- def delegate(attribute)
8
- object[attribute]
7
+ def delegate(attribute, hash_access: :to_sym)
8
+ object[attribute.send(hash_access)]
9
9
  end
10
10
  end
11
11
  end
@@ -4,7 +4,7 @@ module Grape
4
4
  class Entity
5
5
  module Delegator
6
6
  class OpenStructObject < Base
7
- def delegate(attribute)
7
+ def delegate(attribute, **)
8
8
  object.send attribute
9
9
  end
10
10
  end
@@ -4,7 +4,7 @@ module Grape
4
4
  class Entity
5
5
  module Delegator
6
6
  class PlainObject < Base
7
- def delegate(attribute)
7
+ def delegate(attribute, **)
8
8
  object.send attribute
9
9
  end
10
10
 
@@ -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 respond_to?(attribute, true) && Grape::Entity > method(attribute).owner
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 && options.respond_to?(:to_h)
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 && options.respond_to?(:to_h)
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 as if unless using with proc documentation format_with safe attr_path if_extras unless_extras merge expose_nil override
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 { |object, _options| Delegator.new(object).delegate(attribute).nil? }
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(NoMethodError, "#{entity.class.name} missing attribute `#{@attribute}' on #{entity.object}")
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
 
@@ -87,6 +87,7 @@ module Grape
87
87
  exposure.should_expose?(entity, options)
88
88
  end
89
89
  next unless should_expose
90
+
90
91
  output[exposure.key(entity)] ||= []
91
92
  output[exposure.key(entity)] << exposure
92
93
  end
@@ -49,7 +49,7 @@ module Grape
49
49
  length
50
50
  empty?
51
51
  ].each do |name|
52
- class_eval <<-RUBY, __FILE__, __LINE__
52
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
53
53
  def #{name}(*args, &block)
54
54
  @exposures.#{name}(*args, &block)
55
55
  end
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GrapeEntity
4
- VERSION = '0.7.1'
4
+ VERSION = '0.8.0'
5
5
  end
@@ -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 { exposure.using_class_name }.to(using_class_name)
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 { exposure.subexposure }.to(subexposure)
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 { exposure.using_class }
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
 
@@ -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.7.1
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: 2018-01-30 00:00:00.000000000 Z
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: '4.0'
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: '4.0'
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.0'
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.0'
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.3'
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
- rubyforge_project: grape-entity
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.