grape 1.7.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -0
  3. data/CONTRIBUTING.md +31 -1
  4. data/README.md +38 -8
  5. data/grape.gemspec +2 -2
  6. data/lib/grape/api.rb +2 -2
  7. data/lib/grape/content_types.rb +2 -8
  8. data/lib/grape/dsl/desc.rb +3 -2
  9. data/lib/grape/dsl/inside_route.rb +6 -6
  10. data/lib/grape/dsl/parameters.rb +6 -1
  11. data/lib/grape/dsl/request_response.rb +3 -2
  12. data/lib/grape/dsl/settings.rb +2 -6
  13. data/lib/grape/endpoint.rb +21 -19
  14. data/lib/grape/error_formatter/base.rb +1 -1
  15. data/lib/grape/exceptions/base.rb +4 -3
  16. data/lib/grape/exceptions/missing_group_type.rb +1 -6
  17. data/lib/grape/exceptions/unsupported_group_type.rb +1 -6
  18. data/lib/grape/exceptions/validation_errors.rb +1 -6
  19. data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +3 -3
  20. data/lib/grape/extensions/hash.rb +4 -7
  21. data/lib/grape/extensions/hashie/mash.rb +3 -3
  22. data/lib/grape/formatter/serializable_hash.rb +7 -7
  23. data/lib/grape/middleware/auth/base.rb +1 -1
  24. data/lib/grape/middleware/error.rb +1 -1
  25. data/lib/grape/middleware/formatter.rb +1 -1
  26. data/lib/grape/middleware/stack.rb +1 -1
  27. data/lib/grape/middleware/versioner/header.rb +11 -19
  28. data/lib/grape/request.rb +1 -1
  29. data/lib/grape/router/attribute_translator.rb +1 -1
  30. data/lib/grape/router/route.rb +1 -3
  31. data/lib/grape/types/invalid_value.rb +8 -0
  32. data/lib/grape/util/cache.rb +1 -1
  33. data/lib/grape/util/lazy_value.rb +3 -11
  34. data/lib/grape/util/strict_hash_configuration.rb +3 -4
  35. data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
  36. data/lib/grape/validations/params_scope.rb +9 -3
  37. data/lib/grape/validations/single_attribute_iterator.rb +3 -1
  38. data/lib/grape/validations/types/custom_type_coercer.rb +2 -16
  39. data/lib/grape/validations/types/invalid_value.rb +0 -7
  40. data/lib/grape/validations/validators/base.rb +9 -20
  41. data/lib/grape/validations/validators/default_validator.rb +2 -20
  42. data/lib/grape/validations/validators/multiple_params_base.rb +4 -8
  43. data/lib/grape/validations/validators/values_validator.rb +14 -5
  44. data/lib/grape/version.rb +1 -1
  45. data/lib/grape.rb +19 -3
  46. data/spec/grape/api/custom_validations_spec.rb +14 -57
  47. data/spec/grape/api_remount_spec.rb +36 -0
  48. data/spec/grape/api_spec.rb +15 -21
  49. data/spec/grape/dsl/desc_spec.rb +84 -85
  50. data/spec/grape/dsl/inside_route_spec.rb +6 -10
  51. data/spec/grape/dsl/request_response_spec.rb +21 -2
  52. data/spec/grape/endpoint_spec.rb +11 -10
  53. data/spec/grape/exceptions/body_parse_errors_spec.rb +40 -0
  54. data/spec/grape/exceptions/invalid_accept_header_spec.rb +3 -0
  55. data/spec/grape/exceptions/missing_group_type_spec.rb +5 -9
  56. data/spec/grape/exceptions/unsupported_group_type_spec.rb +5 -9
  57. data/spec/grape/grape_spec.rb +9 -0
  58. data/spec/grape/integration/rack_spec.rb +6 -5
  59. data/spec/grape/middleware/base_spec.rb +7 -5
  60. data/spec/grape/middleware/formatter_spec.rb +7 -7
  61. data/spec/grape/request_spec.rb +4 -14
  62. data/spec/grape/validations/multiple_attributes_iterator_spec.rb +6 -8
  63. data/spec/grape/validations/single_attribute_iterator_spec.rb +8 -9
  64. data/spec/grape/validations/validators/base_spec.rb +38 -0
  65. data/spec/grape/validations/validators/values_spec.rb +56 -0
  66. data/spec/grape/validations_spec.rb +36 -12
  67. data/spec/shared/deprecated_class_examples.rb +16 -0
  68. metadata +112 -114
  69. data/lib/grape/config.rb +0 -34
  70. data/lib/grape/extensions/deep_mergeable_hash.rb +0 -21
  71. data/lib/grape/extensions/deep_symbolize_hash.rb +0 -32
  72. data/spec/grape/config_spec.rb +0 -17
  73. data/spec/grape/dsl/configuration_spec.rb +0 -14
  74. data/spec/grape/validations/attributes_iterator_spec.rb +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c13bf4d5de206b76e7cccbe4ffa454512986457b8f5d055cde0cfac5d4f164a9
4
- data.tar.gz: 1177df9af2a24d80e01366f3d705f29e4180898f4cc1ac7e0221e8412e36dcf1
3
+ metadata.gz: ac7bd232782ed265b59ec7f4ea0dec03a0896b328694ebe1507cf9680e1bee41
4
+ data.tar.gz: b81cb45c2b6daab5b413af0df615a542907c9fbf1732e3fc46347321dedc4f65
5
5
  SHA512:
6
- metadata.gz: 32a0d1d9ae7d16b9760f8919814b2aa362ec95a666159a6dc8314946e8a9fd2461d8c074f705ac7afa21939d2a43bec4196a8b7803efdae967b2d01acd1ae77a
7
- data.tar.gz: 5ca9d54a6db6bc63107c2bd0b17cb747f293ec72bc3c0d57a7f7514f0c1122774bce82c5411f4fa19f1c7b435d2c3d1d87102e3f83ff5c31aa8a0dc531817e4d
6
+ metadata.gz: 1929a95447ec3923443e908a8240195e7e4a0f5a3113f8679e947cc3813e800f45f35c928dfef9495ff277a983bf3bdcb4ca358ab889e28224d890a3d078d7de
7
+ data.tar.gz: 4d5141c1f331ee07eaa78bd89e1b76f99b6cbcb7d6f0dda3f12f9e6b900c977c9a0757c0d912a6cd53ea5ef9bce8409a211c4a77c4b78a0f5e607ecd1e055480
data/CHANGELOG.md CHANGED
@@ -1,3 +1,49 @@
1
+ ### 1.8.0 (2023/08/30)
2
+
3
+ #### Features
4
+
5
+ * [#2326](https://github.com/ruby-grape/grape/pull/2326): Use ActiveSupport extensions - [@ericproulx](https://github.com/ericproulx).
6
+ * [#2327](https://github.com/ruby-grape/grape/pull/2327): Use ActiveSupport deprecation - [@ericproulx](https://github.com/ericproulx).
7
+ * [#2330](https://github.com/ruby-grape/grape/pull/2330): Use ActiveSupport inflector - [@ericproulx](https://github.com/ericproulx).
8
+ * [#2331](https://github.com/ruby-grape/grape/pull/2331): Memory optimization when running validators - [@ericproulx](https://github.com/ericproulx).
9
+ * [#2332](https://github.com/ruby-grape/grape/pull/2332): Use ActiveSupport configurable - [@ericproulx](https://github.com/ericproulx).
10
+ * [#2333](https://github.com/ruby-grape/grape/pull/2333): Use custom messages in parameter validation with arity 1 - [@thedevjoao](https://github.com/TheDevJoao).
11
+ * [#2341](https://github.com/ruby-grape/grape/pull/2341): Stop yielding skip value - [@ericproulx](https://github.com/ericproulx).
12
+ * [#2342](https://github.com/ruby-grape/grape/pull/2342): Allow specifying a handler for grape_exceptions - [@mscrivo](https://github.com/mscrivo).
13
+ * [#2338](https://github.com/ruby-grape/grape/pull/2338): Fix unknown validator when using requires/optional with entity - [@mscrivo](https://github.com/mscrivo).
14
+
15
+ #### Fixes
16
+
17
+ * [#2339](https://github.com/ruby-grape/grape/pull/2339): Documentation and specs for remountable configuration in params - [@myxoh](https://github.com/myxoh).
18
+ * [#2328](https://github.com/ruby-grape/grape/pull/2328): Don't cache Class.instance_methods - [@byroot](https://github.com/byroot).
19
+ * [#2337](https://github.com/ruby-grape/grape/pull/2337): Fix: allow custom validators that do not end with _validator - [@ericproulx](https://github.com/ericproulx).
20
+ * [#2346](https://github.com/ruby-grape/grape/pull/2346): Adjust test expectations to conform to rack 3 - [@kbarrette](https://github.com/kbarrette).
21
+
22
+ ## 1.7.1 (2023/05/14)
23
+
24
+ #### Features
25
+
26
+ * [#2288](https://github.com/ruby-grape/grape/pull/2288): Droped support for Ruby 2.5 - [@ericproulx](https://github.com/ericproulx).
27
+ * [#2288](https://github.com/ruby-grape/grape/pull/2288): Updated rubocop to 1.41.0 - [@ericproulx](https://github.com/ericproulx).
28
+ * [#2296](https://github.com/ruby-grape/grape/pull/2296): Fix cops and enables some - [@ericproulx](https://github.com/ericproulx).
29
+ * [#2302](https://github.com/ruby-grape/grape/pull/2302): Rack < 3 and update rack-test - [@ericproulx](https://github.com/ericproulx).
30
+ * [#2303](https://github.com/ruby-grape/grape/pull/2302): Rack >= 1.3.0 - [@ericproulx](https://github.com/ericproulx).
31
+ * [#2301](https://github.com/ruby-grape/grape/pull/2301): Revisit GH workflows - [@ericproulx](https://github.com/ericproulx).
32
+ * [#2311](https://github.com/ruby-grape/grape/pull/2311): Fix tests by pinning rack-test to < 2.1 - [@duffn](https://github.com/duffn).
33
+ * [#2310](https://github.com/ruby-grape/grape/pull/2310): Fix YARD docs markdown rendering - [@duffn](https://github.com/duffn).
34
+ * [#2317](https://github.com/ruby-grape/grape/pull/2317): Remove maruku and rubocop-ast as direct development/testing dependencies - [@ericproulx](https://github.com/ericproulx).
35
+ * [#2292](https://github.com/ruby-grape/grape/pull/2292): Introduce Docker to local development - [@ericproulx](https://github.com/ericproulx).
36
+ * [#2325](https://github.com/ruby-grape/grape/pull/2325): Change edge test workflows only run on demand - [@dblock](https://github.com/dblock).
37
+ * [#2324](https://github.com/ruby-grape/grape/pull/2324): Expose default in the description dsl - [@dhruvCW](https://github.com/dhruvCW).
38
+
39
+ #### Fixes
40
+
41
+ * [#2299](https://github.com/ruby-grape/grape/pull/2299): Fix, do not use kwargs for empty args - [@dm1try](https://github.com/dm1try).
42
+ * [#2307](https://github.com/ruby-grape/grape/pull/2307): Fixed autoloading of InvalidValue - [@fixlr](https://github.com/fixlr).
43
+ * [#2315](https://github.com/ruby-grape/grape/pull/2315): Update rspec - [@ericproulx](https://github.com/ericproulx).
44
+ * [#2319](https://github.com/ruby-grape/grape/pull/2319): Update rubocop - [@ericproulx](https://github.com/ericproulx).
45
+ * [#2323](https://github.com/ruby-grape/grape/pull/2323): Fix using endless ranges for values parameter - [@dhruvCW](https://github.com/dhruvCW).
46
+
1
47
  ### 1.7.0 (2022/12/20)
2
48
 
3
49
  #### Features
data/CONTRIBUTING.md CHANGED
@@ -23,6 +23,34 @@ git pull upstream master
23
23
  git checkout -b my-feature-branch
24
24
  ```
25
25
 
26
+ ### Docker
27
+
28
+ If you're familiar with [Docker](https://www.docker.com/), you can run everything through the following command:
29
+
30
+ ```
31
+ docker-compose run --rm --build grape <command_and_parameters>
32
+ ```
33
+
34
+ About the execution process:
35
+ - displays Ruby, Rubygems, Bundle and Gemfile version when starting:
36
+ ```
37
+ ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux-musl]
38
+ rubygems 3.4.12
39
+ Bundler version 2.4.1 (2022-12-24 commit f3175f033c)
40
+ Running default Gemfile
41
+ ```
42
+ - keeps the gems to the latest possible version
43
+ - executes under `bundle exec`
44
+
45
+ Here are some examples:
46
+
47
+ - running all specs `docker-compose run --rm --build grape rspec`
48
+ - running rspec on a specific file `docker-compose run --rm --build grape rspec spec/:file_path`
49
+ - running task `docker-compose run --rm --build grape rake <task_name>`
50
+ - running rubocop `docker-compose run --rm --build grape rubocop`
51
+ - running all specs on a specific ruby version (e.g 2.7.7) `RUBY_VERSION=2.7.7 docker-compose run --rm --build grape rspec`
52
+ - running specs on a specific gemfile (e.g rails_7_0.gemfile) `docker-compose run -e GEMFILE=rails_7_0 --rm --build grape rspec`
53
+
26
54
  #### Bundle Install and Test
27
55
 
28
56
  Ensure that you can build the project and run tests.
@@ -58,6 +86,8 @@ Make sure that `bundle exec rake` completes without errors.
58
86
 
59
87
  Document any external behavior in the [README](README.md).
60
88
 
89
+ You should also document code as necessary, using current code as examples. This project uses [YARD](https://yardoc.org/). You can run and preview the docs locally by [installing `yard`](https://yardoc.org/), running `yard server --reload` and view the docs at http://localhost:8808.
90
+
61
91
  #### Update Changelog
62
92
 
63
93
  Add a line to [CHANGELOG](CHANGELOG.md) under *Next Release*. Make it look like every other line, including your name and link to your Github account.
@@ -115,7 +145,7 @@ git push origin my-feature-branch -f
115
145
 
116
146
  #### Check on Your Pull Request
117
147
 
118
- Go back to your pull request after a few minutes and see whether it passed muster with Travis-CI. Everything should look green, otherwise fix issues and amend your commit as described above.
148
+ Go back to your pull request after a few minutes and see whether it passed muster with CI. Everything should look green, otherwise fix issues and amend your commit as described above.
119
149
 
120
150
  #### Be Patient
121
151
 
data/README.md CHANGED
@@ -159,7 +159,7 @@ content negotiation, versioning and much more.
159
159
 
160
160
  ## Stable Release
161
161
 
162
- You're reading the documentation for the stable release of Grape, 1.7.0.
162
+ You're reading the documentation for the stable release of Grape, **1.8.0**.
163
163
  Please read [UPGRADING](UPGRADING.md) when upgrading from a previous version.
164
164
 
165
165
  ## Project Resources
@@ -524,26 +524,26 @@ end
524
524
  ```ruby
525
525
  class BasicAPI < Grape::API
526
526
  desc 'Statuses index' do
527
- params: mounted { configuration[:entity] || API::Entities::Status }.documentation
527
+ params: (configuration[:entity] || API::Entities::Status).documentation
528
528
  end
529
529
  params do
530
- requires :all, using: mounted { configuration[:entity] || API::Entities::Status }.documentation
530
+ requires :all, using: (configuration[:entity] || API::Entities::Status).documentation
531
531
  end
532
532
  get '/statuses' do
533
533
  statuses = Status.all
534
534
  type = current_user.admin? ? :full : :default
535
- present statuses, with: mounted { configuration[:entity] || API::Entities::Status }, type: type
535
+ present statuses, with: (configuration[:entity] || API::Entities::Status), type: type
536
536
  end
537
537
  end
538
538
 
539
539
  class V1 < Grape::API
540
540
  version 'v1'
541
- mount BasicAPI, with: { entity: mounted { configuration[:entity] || API::Enitities::Status } }
541
+ mount BasicAPI, with: { entity: mounted { configuration[:entity] || API::Entities::Status } }
542
542
  end
543
543
 
544
544
  class V2 < Grape::API
545
545
  version 'v2'
546
- mount BasicAPI, with: { entity: mounted { configuration[:entity] || API::Enitities::V2::Status } }
546
+ mount BasicAPI, with: { entity: mounted { configuration[:entity] || API::Entities::V2::Status } }
547
547
  end
548
548
  ```
549
549
 
@@ -638,6 +638,7 @@ desc 'Returns your public timeline.' do
638
638
  params API::Entities::Status.documentation
639
639
  success API::Entities::Entity
640
640
  failure [[401, 'Unauthorized', 'Entities::Error']]
641
+ default { code: 500, message: 'InvalidRequest', model: Entities::Error }
641
642
  named 'My named route'
642
643
  headers XAuthToken: {
643
644
  description: 'Validates your identity',
@@ -662,8 +663,9 @@ end
662
663
 
663
664
  * `detail`: A more enhanced description
664
665
  * `params`: Define parameters directly from an `Entity`
665
- * `success`: (former entity) The `Entity` to be used to present by default this route
666
- * `failure`: (former http_codes) A definition of the used failure HTTP Codes and Entities
666
+ * `success`: (former entity) The `Entity` to be used to present the success response for this route.
667
+ * `failure`: (former http_codes) A definition of the used failure HTTP Codes and Entities.
668
+ * `default`: The definition and `Entity` used to present the default response for this route.
667
669
  * `named`: A helper to give a route a name and find it with this name in the documentation Hash
668
670
  * `headers`: A definition of the used Headers
669
671
  * Other options can be found in [grape-swagger][grape-swagger]
@@ -1586,6 +1588,15 @@ params do
1586
1588
  end
1587
1589
  ```
1588
1590
 
1591
+ Note endless ranges are also supported with ActiveSupport >= 6.0, but they require that the type be provided.
1592
+
1593
+ ```ruby
1594
+ params do
1595
+ requires :minimum, type: Integer, values: 10..
1596
+ optional :maximum, type: Integer, values: ..10
1597
+ end
1598
+ ```
1599
+
1589
1600
  Note that *both* range endpoints have to be a `#kind_of?` your `:type` option (if you don't supply the `:type` option, it will be guessed to be equal to the class of the range's first endpoint). So the following is invalid:
1590
1601
 
1591
1602
  ```ruby
@@ -2613,6 +2624,14 @@ class Twitter::API < Grape::API
2613
2624
  end
2614
2625
  ```
2615
2626
 
2627
+ If you want to customize the shape of grape exceptions returned to the user, to match your `:all` handler for example, you can pass a block to `rescue_from :grape_exceptions`.
2628
+
2629
+ ```ruby
2630
+ rescue_from :grape_exceptions do |e|
2631
+ error!(e, e.status)
2632
+ end
2633
+ ```
2634
+
2616
2635
  You can also rescue specific exceptions.
2617
2636
 
2618
2637
  ```ruby
@@ -3340,6 +3359,17 @@ end
3340
3359
 
3341
3360
  Use `body false` to return `204 No Content` without any data or content-type.
3342
3361
 
3362
+ If you want to empty the body with an HTTP status code other than `204 No Content`, you can override the status code after specifying `body false` as follows
3363
+
3364
+ ```ruby
3365
+ class API < Grape::API
3366
+ get '/' do
3367
+ body false
3368
+ status 304
3369
+ end
3370
+ end
3371
+ ```
3372
+
3343
3373
  You can also set the response to a file with `sendfile`. This works with the
3344
3374
  [Rack::Sendfile](https://www.rubydoc.info/gems/rack/Rack/Sendfile) middleware to optimally send
3345
3375
  the file through your web server software.
data/grape.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}"
21
21
  }
22
22
 
23
- s.add_runtime_dependency 'activesupport'
23
+ s.add_runtime_dependency 'activesupport', '>= 5'
24
24
  s.add_runtime_dependency 'builder'
25
25
  s.add_runtime_dependency 'dry-types', '>= 1.1'
26
26
  s.add_runtime_dependency 'mustermann-grape', '~> 1.0.0'
@@ -32,5 +32,5 @@ Gem::Specification.new do |s|
32
32
  s.files += Dir['lib/**/*']
33
33
  s.test_files = Dir['spec/**/*']
34
34
  s.require_paths = ['lib']
35
- s.required_ruby_version = '>= 2.5.0'
35
+ s.required_ruby_version = '>= 2.6.0'
36
36
  end
data/lib/grape/api.rb CHANGED
@@ -8,7 +8,7 @@ module Grape
8
8
  # should subclass this class in order to build an API.
9
9
  class API
10
10
  # Class methods that we want to call on the API rather than on the API object
11
- NON_OVERRIDABLE = (Class.new.methods + %i[call call! configuration compile! inherited]).freeze
11
+ NON_OVERRIDABLE = %i[call call! configuration compile! inherited].freeze
12
12
 
13
13
  class Boolean
14
14
  def self.build(val)
@@ -50,7 +50,7 @@ module Grape
50
50
 
51
51
  # Redefines all methods so that are forwarded to add_setup and be recorded
52
52
  def override_all_methods!
53
- (base_instance.methods - NON_OVERRIDABLE).each do |method_override|
53
+ (base_instance.methods - Class.methods - NON_OVERRIDABLE).each do |method_override|
54
54
  define_singleton_method(method_override) do |*args, &block|
55
55
  add_setup(method_override, *args, &block)
56
56
  end
@@ -17,17 +17,11 @@ module Grape
17
17
 
18
18
  class << self
19
19
  def content_types_for_settings(settings)
20
- return if settings.blank?
21
-
22
- settings.each_with_object({}) { |value, result| result.merge!(value) }
20
+ settings&.inject(:merge!)
23
21
  end
24
22
 
25
23
  def content_types_for(from_settings)
26
- if from_settings.present?
27
- from_settings
28
- else
29
- Grape::ContentTypes::CONTENT_TYPES.merge(default_elements)
30
- end
24
+ from_settings.presence || Grape::ContentTypes::CONTENT_TYPES.merge(default_elements)
31
25
  end
32
26
  end
33
27
  end
@@ -68,7 +68,7 @@ module Grape
68
68
  end
69
69
 
70
70
  config_class.configure(&config_block)
71
- warn '[DEPRECATION] Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.' unless options.empty?
71
+ ActiveSupport::Deprecation.warn('Passing a options hash and a block to `desc` is deprecated. Move all hash options to block.') if options.any?
72
72
  options = config_class.settings
73
73
  else
74
74
  options = options.merge(description: description)
@@ -98,7 +98,8 @@ module Grape
98
98
  :produces,
99
99
  :consumes,
100
100
  :security,
101
- :tags
101
+ :tags,
102
+ :default
102
103
  )
103
104
  config_context.define_singleton_method(:configuration) do
104
105
  endpoint_configuration
@@ -95,7 +95,7 @@ module Grape
95
95
  return yield if has_passed_children
96
96
 
97
97
  key = params_nested_path[0]
98
- key += "[#{params_nested_path[1..-1].join('][')}]" if params_nested_path.size > 1
98
+ key += "[#{params_nested_path[1..].join('][')}]" if params_nested_path.size > 1
99
99
 
100
100
  route_options_params = options[:route_options][:params] || {}
101
101
  type = route_options_params.dig(key, :type)
@@ -103,7 +103,7 @@ module Grape
103
103
 
104
104
  if type == 'Hash' && !has_children
105
105
  {}
106
- elsif type == 'Array' || (type&.start_with?('[') && !type&.include?(','))
106
+ elsif type == 'Array' || (type&.start_with?('[') && type&.exclude?(','))
107
107
  []
108
108
  elsif type == 'Set' || type&.start_with?('#<Set')
109
109
  Set.new
@@ -280,13 +280,13 @@ module Grape
280
280
  # Deprecated method to send files to the client. Use `sendfile` or `stream`
281
281
  def file(value = nil)
282
282
  if value.is_a?(String)
283
- warn '[DEPRECATION] Use sendfile or stream to send files.'
283
+ ActiveSupport::Deprecation.warn('Use sendfile or stream to send files.')
284
284
  sendfile(value)
285
285
  elsif !value.is_a?(NilClass)
286
- warn '[DEPRECATION] Use stream to use a Stream object.'
286
+ ActiveSupport::Deprecation.warn('Use stream to use a Stream object.')
287
287
  stream(value)
288
288
  else
289
- warn '[DEPRECATION] Use sendfile or stream to send files.'
289
+ ActiveSupport::Deprecation.warn('Use sendfile or stream to send files.')
290
290
  sendfile
291
291
  end
292
292
  end
@@ -433,7 +433,7 @@ module Grape
433
433
  # the given entity_class.
434
434
  def entity_representation_for(entity_class, object, options)
435
435
  embeds = { env: env }
436
- embeds[:version] = env[Grape::Env::API_VERSION] if env[Grape::Env::API_VERSION]
436
+ embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
437
437
  entity_class.represent(object, **embeds.merge(options))
438
438
  end
439
439
  end
@@ -62,7 +62,12 @@ module Grape
62
62
  params_block = named_params.fetch(name) do
63
63
  raise "Params :#{name} not found!"
64
64
  end
65
- instance_exec(**options, &params_block)
65
+
66
+ if options.empty?
67
+ instance_exec(options, &params_block)
68
+ else
69
+ instance_exec(**options, &params_block)
70
+ end
66
71
  end
67
72
  end
68
73
  alias use_scope use
@@ -112,10 +112,11 @@ module Grape
112
112
 
113
113
  if args.include?(:all)
114
114
  namespace_inheritable(:rescue_all, true)
115
- namespace_inheritable :all_rescue_handler, handler
115
+ namespace_inheritable(:all_rescue_handler, handler)
116
116
  elsif args.include?(:grape_exceptions)
117
117
  namespace_inheritable(:rescue_all, true)
118
118
  namespace_inheritable(:rescue_grape_exceptions, true)
119
+ namespace_inheritable(:grape_exceptions_rescue_handler, handler)
119
120
  else
120
121
  handler_type =
121
122
  case options[:rescue_subclasses]
@@ -125,7 +126,7 @@ module Grape
125
126
  :base_only_rescue_handlers
126
127
  end
127
128
 
128
- namespace_reverse_stackable handler_type, args.map { |arg| [arg, handler] }.to_h
129
+ namespace_reverse_stackable(handler_type, args.to_h { |arg| [arg, handler] })
129
130
  end
130
131
 
131
132
  namespace_stackable(:rescue_options, options)
@@ -109,13 +109,9 @@ module Grape
109
109
  settings = get_or_set :namespace_reverse_stackable, key, nil
110
110
  return if settings.blank?
111
111
 
112
- result = {}
113
- settings.each do |setting|
114
- setting.each do |field, value|
115
- result[field] ||= value
116
- end
112
+ settings.each_with_object({}) do |setting, result|
113
+ result.merge!(setting) { |_k, s1, _s2| s1 }
117
114
  end
118
- result
119
115
  end
120
116
 
121
117
  # (see #unset_global_setting)
@@ -171,10 +171,9 @@ module Grape
171
171
  end
172
172
 
173
173
  def prepare_routes_requirements
174
- endpoint_requirements = options[:route_options][:requirements] || {}
175
- all_requirements = (namespace_stackable(:namespace).map(&:requirements) << endpoint_requirements)
176
- all_requirements.reduce({}) do |base_requirements, single_requirements|
177
- base_requirements.merge!(single_requirements)
174
+ {}.merge!(*namespace_stackable(:namespace).map(&:requirements)).tap do |requirements|
175
+ endpoint_requirements = options.dig(:route_options, :requirements)
176
+ requirements.merge!(endpoint_requirements) if endpoint_requirements
178
177
  end
179
178
  end
180
179
 
@@ -293,13 +292,14 @@ module Grape
293
292
  rescue_options: namespace_stackable_with_hash(:rescue_options) || {},
294
293
  rescue_handlers: namespace_reverse_stackable_with_hash(:rescue_handlers) || {},
295
294
  base_only_rescue_handlers: namespace_stackable_with_hash(:base_only_rescue_handlers) || {},
296
- all_rescue_handler: namespace_inheritable(:all_rescue_handler)
295
+ all_rescue_handler: namespace_inheritable(:all_rescue_handler),
296
+ grape_exceptions_rescue_handler: namespace_inheritable(:grape_exceptions_rescue_handler)
297
297
 
298
298
  stack.concat namespace_stackable(:middleware)
299
299
 
300
300
  if namespace_inheritable(:version)
301
301
  stack.use Grape::Middleware::Versioner.using(namespace_inheritable(:version_options)[:using]),
302
- versions: namespace_inheritable(:version) ? namespace_inheritable(:version).flatten : nil,
302
+ versions: namespace_inheritable(:version)&.flatten,
303
303
  version_options: namespace_inheritable(:version_options),
304
304
  prefix: namespace_inheritable(:root_prefix),
305
305
  mount_path: namespace_stackable(:mount_path).first
@@ -318,14 +318,14 @@ module Grape
318
318
  end
319
319
 
320
320
  def build_helpers
321
- helpers = namespace_stackable(:helpers) || []
322
- Module.new { helpers.each { |mod_to_include| include mod_to_include } }
321
+ helpers = namespace_stackable(:helpers)
322
+ Module.new { helpers&.each { |mod_to_include| include mod_to_include } }
323
323
  end
324
324
 
325
325
  private :build_stack, :build_helpers
326
326
 
327
327
  def execute
328
- @block ? @block.call(self) : nil
328
+ @block&.call(self)
329
329
  end
330
330
 
331
331
  def helpers
@@ -345,11 +345,9 @@ module Grape
345
345
  end
346
346
  end
347
347
 
348
- def run_validators(validator_factories, request)
348
+ def run_validators(validators, request)
349
349
  validation_errors = []
350
350
 
351
- validators = validator_factories.map { |options| Grape::Validations::ValidatorFactory.create_validator(**options) }
352
-
353
351
  ActiveSupport::Notifications.instrument('endpoint_run_validators.grape', endpoint: self, validators: validators, request: request) do
354
352
  validators.each do |validator|
355
353
  validator.validate(request)
@@ -367,34 +365,38 @@ module Grape
367
365
 
368
366
  def run_filters(filters, type = :other)
369
367
  ActiveSupport::Notifications.instrument('endpoint_run_filters.grape', endpoint: self, filters: filters, type: type) do
370
- (filters || []).each { |filter| instance_eval(&filter) }
368
+ filters&.each { |filter| instance_eval(&filter) }
371
369
  end
372
370
  post_extension = DSL::InsideRoute.post_filter_methods(type)
373
371
  extend post_extension if post_extension
374
372
  end
375
373
 
376
374
  def befores
377
- namespace_stackable(:befores) || []
375
+ namespace_stackable(:befores)
378
376
  end
379
377
 
380
378
  def before_validations
381
- namespace_stackable(:before_validations) || []
379
+ namespace_stackable(:before_validations)
382
380
  end
383
381
 
384
382
  def after_validations
385
- namespace_stackable(:after_validations) || []
383
+ namespace_stackable(:after_validations)
386
384
  end
387
385
 
388
386
  def afters
389
- namespace_stackable(:afters) || []
387
+ namespace_stackable(:afters)
390
388
  end
391
389
 
392
390
  def finallies
393
- namespace_stackable(:finallies) || []
391
+ namespace_stackable(:finallies)
394
392
  end
395
393
 
396
394
  def validations
397
- route_setting(:saved_validations) || []
395
+ return enum_for(:validations) unless block_given?
396
+
397
+ route_setting(:saved_validations)&.each do |saved_validation|
398
+ yield Grape::Validations::ValidatorFactory.create_validator(**saved_validation)
399
+ end
398
400
  end
399
401
 
400
402
  def options?
@@ -27,7 +27,7 @@ module Grape
27
27
 
28
28
  if presenter
29
29
  embeds = { env: env }
30
- embeds[:version] = env[Grape::Env::API_VERSION] if env[Grape::Env::API_VERSION]
30
+ embeds[:version] = env[Grape::Env::API_VERSION] if env.key?(Grape::Env::API_VERSION)
31
31
  presented_message = presenter.represent(presented_message, embeds).serializable_hash
32
32
  end
33
33
 
@@ -10,9 +10,10 @@ module Grape
10
10
  attr_reader :status, :headers
11
11
 
12
12
  def initialize(status: nil, message: nil, headers: nil, **_options)
13
+ super(message)
14
+
13
15
  @status = status
14
16
  @headers = headers
15
- super(message)
16
17
  end
17
18
 
18
19
  def [](index)
@@ -72,11 +73,11 @@ module Grape
72
73
  options = options.dup
73
74
  options[:default] &&= options[:default].to_s
74
75
  message = ::I18n.translate(key, **options)
75
- message.present? ? message : fallback_message(key, **options)
76
+ message.presence || fallback_message(key, **options)
76
77
  end
77
78
 
78
79
  def fallback_message(key, **options)
79
- if ::I18n.enforce_available_locales && !::I18n.available_locales.include?(FALLBACK_LOCALE)
80
+ if ::I18n.enforce_available_locales && ::I18n.available_locales.exclude?(FALLBACK_LOCALE)
80
81
  key
81
82
  else
82
83
  ::I18n.translate(key, locale: FALLBACK_LOCALE, **options)
@@ -10,9 +10,4 @@ module Grape
10
10
  end
11
11
  end
12
12
 
13
- Grape::Exceptions::MissingGroupTypeError = Class.new(Grape::Exceptions::MissingGroupType) do
14
- def initialize(*)
15
- super
16
- warn '[DEPRECATION] `Grape::Exceptions::MissingGroupTypeError` is deprecated. Use `Grape::Exceptions::MissingGroupType` instead.'
17
- end
18
- end
13
+ Grape::Exceptions::MissingGroupTypeError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Grape::Exceptions::MissingGroupTypeError', 'Grape::Exceptions::MissingGroupType')
@@ -10,9 +10,4 @@ module Grape
10
10
  end
11
11
  end
12
12
 
13
- Grape::Exceptions::UnsupportedGroupTypeError = Class.new(Grape::Exceptions::UnsupportedGroupType) do
14
- def initialize(*)
15
- super
16
- warn '[DEPRECATION] `Grape::Exceptions::UnsupportedGroupTypeError` is deprecated. Use `Grape::Exceptions::UnsupportedGroupType` instead.'
17
- end
18
- end
13
+ Grape::Exceptions::UnsupportedGroupTypeError = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('Grape::Exceptions::UnsupportedGroupTypeError', 'Grape::Exceptions::UnsupportedGroupType')
@@ -13,12 +13,7 @@ module Grape
13
13
  attr_reader :errors
14
14
 
15
15
  def initialize(errors: [], headers: {}, **_options)
16
- @errors = {}
17
- errors.each do |validation_error|
18
- @errors[validation_error.params] ||= []
19
- @errors[validation_error.params] << validation_error
20
- end
21
-
16
+ @errors = errors.group_by(&:params)
22
17
  super message: full_messages.join(', '), status: 400, headers: headers
23
18
  end
24
19
 
@@ -16,9 +16,9 @@ module Grape
16
16
  end
17
17
 
18
18
  def build_params
19
- params = ::ActiveSupport::HashWithIndifferentAccess.new(rack_params)
20
- params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
21
- params
19
+ ::ActiveSupport::HashWithIndifferentAccess.new(rack_params).tap do |params|
20
+ params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
21
+ end
22
22
  end
23
23
  end
24
24
  end
@@ -11,13 +11,10 @@ module Grape
11
11
  end
12
12
 
13
13
  def build_params
14
- params = Grape::Extensions::DeepMergeableHash[rack_params]
15
- params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
16
- post_process_params(params)
17
- end
18
-
19
- def post_process_params(params)
20
- Grape::Extensions::DeepSymbolizeHash.deep_symbolize_keys_in(params)
14
+ rack_params.deep_dup.tap do |params|
15
+ params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
16
+ params.deep_symbolize_keys!
17
+ end
21
18
  end
22
19
  end
23
20
  end
@@ -15,9 +15,9 @@ module Grape
15
15
  end
16
16
 
17
17
  def build_params
18
- params = ::Hashie::Mash.new(rack_params)
19
- params.deep_merge!(grape_routing_args) if env[Grape::Env::GRAPE_ROUTING_ARGS]
20
- params
18
+ ::Hashie::Mash.new(rack_params).tap do |params|
19
+ params.deep_merge!(grape_routing_args) if env.key?(Grape::Env::GRAPE_ROUTING_ARGS)
20
+ end
21
21
  end
22
22
  end
23
23
  end