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 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.