grape 1.7.0 → 1.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.
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