grape 1.8.0 → 3.3.5
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 +4 -4
- data/CHANGELOG.md +391 -1
- data/CONTRIBUTING.md +3 -11
- data/README.md +648 -552
- data/UPGRADING.md +803 -7
- data/grape.gemspec +11 -14
- data/lib/grape/api/instance.rb +68 -158
- data/lib/grape/api.rb +71 -107
- data/lib/grape/content_types.rb +23 -11
- data/lib/grape/cookies.rb +28 -25
- data/lib/grape/declared_params_handler.rb +116 -0
- data/lib/grape/dry_types.rb +48 -6
- data/lib/grape/dsl/callbacks.rb +14 -58
- data/lib/grape/dsl/declared.rb +35 -0
- data/lib/grape/dsl/desc.rb +15 -63
- data/lib/grape/dsl/entity.rb +88 -0
- data/lib/grape/dsl/headers.rb +2 -2
- data/lib/grape/dsl/helpers.rb +83 -64
- data/lib/grape/dsl/inside_route.rb +56 -295
- data/lib/grape/dsl/logger.rb +4 -9
- data/lib/grape/dsl/middleware.rb +22 -40
- data/lib/grape/dsl/parameters.rb +50 -82
- data/lib/grape/dsl/request_response.rb +144 -146
- data/lib/grape/dsl/rescue_options.rb +24 -0
- data/lib/grape/dsl/routing.rb +261 -186
- data/lib/grape/dsl/settings.rb +29 -135
- data/lib/grape/dsl/validations.rb +39 -32
- data/lib/grape/dsl/version_options.rb +23 -0
- data/lib/grape/endpoint/options.rb +19 -0
- data/lib/grape/endpoint.rb +277 -250
- data/lib/grape/{util/env.rb → env.rb} +1 -8
- data/lib/grape/error_formatter/base.rb +56 -21
- data/lib/grape/error_formatter/json.rb +13 -15
- data/lib/grape/error_formatter/serializable_hash.rb +7 -0
- data/lib/grape/error_formatter/txt.rb +12 -18
- data/lib/grape/error_formatter/xml.rb +3 -13
- data/lib/grape/error_formatter.rb +5 -25
- data/lib/grape/exceptions/base.rb +22 -58
- data/lib/grape/exceptions/error_response.rb +45 -0
- data/lib/grape/exceptions/incompatible_option_values.rb +1 -1
- data/lib/grape/exceptions/internal_server_error.rb +16 -0
- data/lib/grape/exceptions/invalid_accept_header.rb +1 -1
- data/lib/grape/exceptions/invalid_formatter.rb +1 -1
- data/lib/grape/exceptions/invalid_message_body.rb +1 -1
- data/lib/grape/exceptions/invalid_version_header.rb +1 -1
- data/lib/grape/exceptions/invalid_versioner_option.rb +1 -1
- data/lib/grape/exceptions/method_not_allowed.rb +1 -1
- data/lib/grape/exceptions/missing_group_type.rb +0 -2
- data/lib/grape/exceptions/missing_mime_type.rb +1 -1
- data/lib/grape/exceptions/request_error.rb +11 -0
- data/lib/grape/exceptions/unknown_auth_strategy.rb +11 -0
- data/lib/grape/exceptions/unknown_parameter.rb +1 -1
- data/lib/grape/exceptions/unknown_params_builder.rb +11 -0
- data/lib/grape/exceptions/unknown_validator.rb +1 -1
- data/lib/grape/exceptions/unsupported_group_type.rb +0 -2
- data/lib/grape/exceptions/validation.rb +25 -9
- data/lib/grape/exceptions/validation_array_errors.rb +5 -0
- data/lib/grape/exceptions/validation_errors.rb +22 -26
- data/lib/grape/formatter/base.rb +16 -0
- data/lib/grape/formatter/json.rb +4 -6
- data/lib/grape/formatter/serializable_hash.rb +6 -10
- data/lib/grape/formatter/txt.rb +3 -5
- data/lib/grape/formatter/xml.rb +4 -6
- data/lib/grape/formatter.rb +7 -25
- data/lib/grape/json.rb +46 -0
- data/lib/grape/locale/en.yml +43 -42
- data/lib/grape/middleware/auth/base.rb +11 -33
- data/lib/grape/middleware/auth/dsl.rb +37 -31
- data/lib/grape/middleware/auth/strategies.rb +1 -2
- data/lib/grape/middleware/base.rb +56 -33
- data/lib/grape/middleware/deprecated_options_hash_access.rb +19 -0
- data/lib/grape/middleware/error.rb +183 -91
- data/lib/grape/middleware/formatter.rb +94 -105
- data/lib/grape/middleware/precomputed_content_types.rb +46 -0
- data/lib/grape/middleware/stack.rb +27 -38
- data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
- data/lib/grape/middleware/versioner/base.rb +72 -0
- data/lib/grape/middleware/versioner/header.rb +44 -129
- data/lib/grape/middleware/versioner/param.rb +4 -25
- data/lib/grape/middleware/versioner/path.rb +13 -32
- data/lib/grape/middleware/versioner.rb +7 -14
- data/lib/grape/mountable.rb +22 -0
- data/lib/grape/namespace.rb +18 -12
- data/lib/grape/params_builder/base.rb +20 -0
- data/lib/grape/params_builder/hash.rb +11 -0
- data/lib/grape/params_builder/hash_with_indifferent_access.rb +11 -0
- data/lib/grape/params_builder/hashie_mash.rb +11 -0
- data/lib/grape/params_builder.rb +15 -0
- data/lib/grape/parser/base.rb +16 -0
- data/lib/grape/parser/json.rb +6 -8
- data/lib/grape/parser/xml.rb +6 -8
- data/lib/grape/parser.rb +5 -23
- data/lib/grape/path.rb +38 -63
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +168 -26
- data/lib/grape/router/base_route.rb +48 -0
- data/lib/grape/router/greedy_route.rb +26 -0
- data/lib/grape/router/mustermann_pattern.rb +44 -0
- data/lib/grape/router/pattern.rb +30 -34
- data/lib/grape/router/route.rb +28 -61
- data/lib/grape/router.rb +71 -86
- data/lib/grape/serve_stream/file_body.rb +1 -0
- data/lib/grape/serve_stream/sendfile_response.rb +3 -5
- data/lib/grape/serve_stream/stream_response.rb +1 -0
- data/lib/grape/testing.rb +33 -0
- data/lib/grape/util/api_description.rb +58 -0
- data/lib/grape/util/base_inheritable.rb +14 -14
- data/lib/grape/util/cache.rb +1 -3
- data/lib/grape/util/deep_freeze.rb +35 -0
- data/lib/grape/util/endpoint_configuration.rb +1 -1
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_setting.rb +51 -27
- data/lib/grape/util/inheritable_values.rb +7 -5
- data/lib/grape/util/lazy/base.rb +16 -0
- data/lib/grape/util/lazy/block.rb +22 -0
- data/lib/grape/util/lazy/value.rb +31 -0
- data/lib/grape/util/lazy/value_array.rb +21 -0
- data/lib/grape/util/lazy/value_enumerable.rb +31 -0
- data/lib/grape/util/lazy/value_hash.rb +21 -0
- data/lib/grape/util/media_type.rb +67 -0
- data/lib/grape/util/path_normalizer.rb +34 -0
- data/lib/grape/util/registry.rb +27 -0
- data/lib/grape/util/reverse_stackable_values.rb +1 -6
- data/lib/grape/util/stackable_values.rb +12 -14
- data/lib/grape/util/translation.rb +42 -0
- data/lib/grape/validations/attributes_iterator.rb +43 -27
- data/lib/grape/validations/coerce_options.rb +21 -0
- data/lib/grape/validations/contract_scope.rb +28 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/oneof_collector.rb +39 -0
- data/lib/grape/validations/param_scope_tracker.rb +62 -0
- data/lib/grape/validations/params_documentation.rb +52 -0
- data/lib/grape/validations/params_scope.rb +180 -303
- data/lib/grape/validations/shared_options.rb +19 -0
- data/lib/grape/validations/single_attribute_iterator.rb +2 -2
- data/lib/grape/validations/types/array_coercer.rb +4 -7
- data/lib/grape/validations/types/custom_type_coercer.rb +41 -85
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +1 -1
- data/lib/grape/validations/types/dry_type_coercer.rb +15 -28
- data/lib/grape/validations/types/json.rb +0 -2
- data/lib/grape/validations/types/primitive_coercer.rb +11 -35
- data/lib/grape/validations/types/set_coercer.rb +1 -4
- data/lib/grape/validations/types/variant_collection_coercer.rb +11 -0
- data/lib/grape/validations/types.rb +29 -54
- data/lib/grape/validations/validations_spec.rb +164 -0
- data/lib/grape/validations/validators/all_or_none_of_validator.rb +6 -3
- data/lib/grape/validations/validators/allow_blank_validator.rb +10 -5
- data/lib/grape/validations/validators/at_least_one_of_validator.rb +5 -2
- data/lib/grape/validations/validators/base.rb +120 -36
- data/lib/grape/validations/validators/coerce_validator.rb +18 -36
- data/lib/grape/validations/validators/contract_scope_validator.rb +45 -0
- data/lib/grape/validations/validators/default_validator.rb +13 -16
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +10 -3
- data/lib/grape/validations/validators/except_values_validator.rb +15 -5
- data/lib/grape/validations/validators/length_validator.rb +48 -0
- data/lib/grape/validations/validators/multiple_params_base.rb +12 -9
- data/lib/grape/validations/validators/{mutual_exclusion_validator.rb → mutually_exclusive_validator.rb} +4 -2
- data/lib/grape/validations/validators/oneof_validator.rb +49 -0
- data/lib/grape/validations/validators/presence_validator.rb +4 -2
- data/lib/grape/validations/validators/regexp_validator.rb +11 -3
- data/lib/grape/validations/validators/same_as_validator.rb +6 -15
- data/lib/grape/validations/validators/values_validator.rb +36 -65
- data/lib/grape/validations.rb +8 -21
- data/lib/grape/version.rb +1 -2
- data/lib/grape/xml.rb +17 -0
- data/lib/grape.rb +75 -288
- metadata +79 -291
- data/lib/grape/api/helpers.rb +0 -9
- data/lib/grape/dsl/api.rb +0 -19
- data/lib/grape/dsl/configuration.rb +0 -15
- data/lib/grape/eager_load.rb +0 -20
- data/lib/grape/exceptions/empty_message_body.rb +0 -11
- data/lib/grape/exceptions/missing_option.rb +0 -11
- data/lib/grape/exceptions/too_many_multipart_files.rb +0 -11
- data/lib/grape/exceptions/unknown_options.rb +0 -11
- data/lib/grape/extensions/active_support/hash_with_indifferent_access.rb +0 -27
- data/lib/grape/extensions/hash.rb +0 -22
- data/lib/grape/extensions/hashie/mash.rb +0 -26
- data/lib/grape/http/headers.rb +0 -61
- data/lib/grape/middleware/globals.rb +0 -16
- data/lib/grape/middleware/helpers.rb +0 -12
- data/lib/grape/middleware/versioner/parse_media_type_patch.rb +0 -24
- data/lib/grape/router/attribute_translator.rb +0 -63
- data/lib/grape/types/invalid_value.rb +0 -8
- data/lib/grape/util/json.rb +0 -12
- data/lib/grape/util/lazy_block.rb +0 -27
- data/lib/grape/util/lazy_object.rb +0 -43
- data/lib/grape/util/lazy_value.rb +0 -91
- data/lib/grape/util/registrable.rb +0 -15
- data/lib/grape/util/strict_hash_configuration.rb +0 -108
- data/lib/grape/util/xml.rb +0 -10
- data/lib/grape/validations/attributes_doc.rb +0 -58
- data/lib/grape/validations/types/build_coercer.rb +0 -94
- data/lib/grape/validations/validator_factory.rb +0 -15
- data/spec/grape/api/custom_validations_spec.rb +0 -213
- data/spec/grape/api/deeply_included_options_spec.rb +0 -56
- data/spec/grape/api/defines_boolean_in_params_spec.rb +0 -38
- data/spec/grape/api/documentation_spec.rb +0 -59
- data/spec/grape/api/inherited_helpers_spec.rb +0 -114
- data/spec/grape/api/instance_spec.rb +0 -103
- data/spec/grape/api/invalid_format_spec.rb +0 -45
- data/spec/grape/api/namespace_parameters_in_route_spec.rb +0 -38
- data/spec/grape/api/nested_helpers_spec.rb +0 -50
- data/spec/grape/api/optional_parameters_in_route_spec.rb +0 -43
- data/spec/grape/api/parameters_modification_spec.rb +0 -41
- data/spec/grape/api/patch_method_helpers_spec.rb +0 -79
- data/spec/grape/api/recognize_path_spec.rb +0 -21
- data/spec/grape/api/required_parameters_in_route_spec.rb +0 -37
- data/spec/grape/api/required_parameters_with_invalid_method_spec.rb +0 -26
- data/spec/grape/api/routes_with_requirements_spec.rb +0 -59
- data/spec/grape/api/shared_helpers_exactly_one_of_spec.rb +0 -41
- data/spec/grape/api/shared_helpers_spec.rb +0 -36
- data/spec/grape/api_remount_spec.rb +0 -509
- data/spec/grape/api_spec.rb +0 -4356
- data/spec/grape/dsl/callbacks_spec.rb +0 -45
- data/spec/grape/dsl/desc_spec.rb +0 -98
- data/spec/grape/dsl/headers_spec.rb +0 -62
- data/spec/grape/dsl/helpers_spec.rb +0 -100
- data/spec/grape/dsl/inside_route_spec.rb +0 -531
- data/spec/grape/dsl/logger_spec.rb +0 -24
- data/spec/grape/dsl/middleware_spec.rb +0 -60
- data/spec/grape/dsl/parameters_spec.rb +0 -180
- data/spec/grape/dsl/request_response_spec.rb +0 -225
- data/spec/grape/dsl/routing_spec.rb +0 -275
- data/spec/grape/dsl/settings_spec.rb +0 -261
- data/spec/grape/dsl/validations_spec.rb +0 -55
- data/spec/grape/endpoint/declared_spec.rb +0 -846
- data/spec/grape/endpoint_spec.rb +0 -1085
- data/spec/grape/entity_spec.rb +0 -336
- data/spec/grape/exceptions/base_spec.rb +0 -81
- data/spec/grape/exceptions/body_parse_errors_spec.rb +0 -185
- data/spec/grape/exceptions/invalid_accept_header_spec.rb +0 -358
- data/spec/grape/exceptions/invalid_formatter_spec.rb +0 -15
- data/spec/grape/exceptions/invalid_response_spec.rb +0 -11
- data/spec/grape/exceptions/invalid_versioner_option_spec.rb +0 -15
- data/spec/grape/exceptions/missing_group_type_spec.rb +0 -17
- data/spec/grape/exceptions/missing_mime_type_spec.rb +0 -17
- data/spec/grape/exceptions/missing_option_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_options_spec.rb +0 -15
- data/spec/grape/exceptions/unknown_validator_spec.rb +0 -15
- data/spec/grape/exceptions/unsupported_group_type_spec.rb +0 -19
- data/spec/grape/exceptions/validation_errors_spec.rb +0 -92
- data/spec/grape/exceptions/validation_spec.rb +0 -19
- data/spec/grape/extensions/param_builders/hash_spec.rb +0 -83
- data/spec/grape/extensions/param_builders/hash_with_indifferent_access_spec.rb +0 -105
- data/spec/grape/extensions/param_builders/hashie/mash_spec.rb +0 -79
- data/spec/grape/grape_spec.rb +0 -9
- data/spec/grape/integration/global_namespace_function_spec.rb +0 -29
- data/spec/grape/integration/rack_sendfile_spec.rb +0 -48
- data/spec/grape/integration/rack_spec.rb +0 -51
- data/spec/grape/loading_spec.rb +0 -44
- data/spec/grape/middleware/auth/base_spec.rb +0 -31
- data/spec/grape/middleware/auth/dsl_spec.rb +0 -60
- data/spec/grape/middleware/auth/strategies_spec.rb +0 -120
- data/spec/grape/middleware/base_spec.rb +0 -221
- data/spec/grape/middleware/error_spec.rb +0 -85
- data/spec/grape/middleware/exception_spec.rb +0 -294
- data/spec/grape/middleware/formatter_spec.rb +0 -461
- data/spec/grape/middleware/globals_spec.rb +0 -30
- data/spec/grape/middleware/stack_spec.rb +0 -155
- data/spec/grape/middleware/versioner/accept_version_header_spec.rb +0 -122
- data/spec/grape/middleware/versioner/header_spec.rb +0 -345
- data/spec/grape/middleware/versioner/param_spec.rb +0 -171
- data/spec/grape/middleware/versioner/path_spec.rb +0 -62
- data/spec/grape/middleware/versioner_spec.rb +0 -21
- data/spec/grape/named_api_spec.rb +0 -19
- data/spec/grape/parser_spec.rb +0 -86
- data/spec/grape/path_spec.rb +0 -252
- data/spec/grape/presenters/presenter_spec.rb +0 -71
- data/spec/grape/request_spec.rb +0 -126
- data/spec/grape/util/inheritable_setting_spec.rb +0 -242
- data/spec/grape/util/inheritable_values_spec.rb +0 -79
- data/spec/grape/util/reverse_stackable_values_spec.rb +0 -134
- data/spec/grape/util/stackable_values_spec.rb +0 -128
- data/spec/grape/util/strict_hash_configuration_spec.rb +0 -38
- data/spec/grape/validations/attributes_doc_spec.rb +0 -153
- data/spec/grape/validations/instance_behaivour_spec.rb +0 -43
- data/spec/grape/validations/multiple_attributes_iterator_spec.rb +0 -38
- data/spec/grape/validations/params_scope_spec.rb +0 -1420
- data/spec/grape/validations/single_attribute_iterator_spec.rb +0 -56
- data/spec/grape/validations/types/array_coercer_spec.rb +0 -33
- data/spec/grape/validations/types/primitive_coercer_spec.rb +0 -150
- data/spec/grape/validations/types/set_coercer_spec.rb +0 -32
- data/spec/grape/validations/types_spec.rb +0 -111
- data/spec/grape/validations/validators/all_or_none_spec.rb +0 -162
- data/spec/grape/validations/validators/allow_blank_spec.rb +0 -575
- data/spec/grape/validations/validators/at_least_one_of_spec.rb +0 -205
- data/spec/grape/validations/validators/base_spec.rb +0 -38
- data/spec/grape/validations/validators/coerce_spec.rb +0 -1261
- data/spec/grape/validations/validators/default_spec.rb +0 -463
- data/spec/grape/validations/validators/exactly_one_of_spec.rb +0 -233
- data/spec/grape/validations/validators/except_values_spec.rb +0 -192
- data/spec/grape/validations/validators/mutual_exclusion_spec.rb +0 -214
- data/spec/grape/validations/validators/presence_spec.rb +0 -315
- data/spec/grape/validations/validators/regexp_spec.rb +0 -161
- data/spec/grape/validations/validators/same_as_spec.rb +0 -57
- data/spec/grape/validations/validators/values_spec.rb +0 -733
- data/spec/grape/validations/validators/zh-CN.yml +0 -10
- data/spec/grape/validations_spec.rb +0 -2030
- data/spec/integration/eager_load/eager_load_spec.rb +0 -15
- data/spec/integration/multi_json/json_spec.rb +0 -7
- data/spec/integration/multi_xml/xml_spec.rb +0 -7
- data/spec/shared/deprecated_class_examples.rb +0 -16
- data/spec/shared/versioning_examples.rb +0 -215
- data/spec/spec_helper.rb +0 -52
- data/spec/support/basic_auth_encode_helpers.rb +0 -11
- data/spec/support/chunks.rb +0 -14
- data/spec/support/content_type_helpers.rb +0 -15
- data/spec/support/endpoint_faker.rb +0 -25
- data/spec/support/file_streamer.rb +0 -13
- data/spec/support/integer_helpers.rb +0 -13
- data/spec/support/versioned_helpers.rb +0 -55
data/grape.gemspec
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
require 'grape/version'
|
|
3
|
+
require_relative 'lib/grape/version'
|
|
5
4
|
|
|
6
5
|
Gem::Specification.new do |s|
|
|
7
6
|
s.name = 'grape'
|
|
@@ -17,20 +16,18 @@ Gem::Specification.new do |s|
|
|
|
17
16
|
'bug_tracker_uri' => 'https://github.com/ruby-grape/grape/issues',
|
|
18
17
|
'changelog_uri' => "https://github.com/ruby-grape/grape/blob/v#{s.version}/CHANGELOG.md",
|
|
19
18
|
'documentation_uri' => "https://www.rubydoc.info/gems/grape/#{s.version}",
|
|
20
|
-
'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}"
|
|
19
|
+
'source_code_uri' => "https://github.com/ruby-grape/grape/tree/v#{s.version}",
|
|
20
|
+
'rubygems_mfa_required' => 'true'
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
s.
|
|
24
|
-
s.
|
|
25
|
-
s.
|
|
26
|
-
s.
|
|
27
|
-
s.
|
|
28
|
-
s.
|
|
23
|
+
s.add_dependency 'activesupport', '>= 7.2'
|
|
24
|
+
s.add_dependency 'dry-configurable', '>= 1.0'
|
|
25
|
+
s.add_dependency 'dry-types', '>= 1.1'
|
|
26
|
+
s.add_dependency 'mustermann', '>= 4.0'
|
|
27
|
+
s.add_dependency 'rack', '>= 2.2.4'
|
|
28
|
+
s.add_dependency 'zeitwerk', '>= 2.6'
|
|
29
29
|
|
|
30
|
-
s.files
|
|
31
|
-
s.files += %w[grape.gemspec]
|
|
32
|
-
s.files += Dir['lib/**/*']
|
|
33
|
-
s.test_files = Dir['spec/**/*']
|
|
30
|
+
s.files = Dir['lib/**/*', 'CHANGELOG.md', 'CONTRIBUTING.md', 'README.md', 'grape.png', 'UPGRADING.md', 'LICENSE', 'grape.gemspec']
|
|
34
31
|
s.require_paths = ['lib']
|
|
35
|
-
s.required_ruby_version = '>=
|
|
32
|
+
s.required_ruby_version = '>= 3.3'
|
|
36
33
|
end
|
data/lib/grape/api/instance.rb
CHANGED
|
@@ -1,24 +1,30 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'grape/router'
|
|
4
|
-
|
|
5
3
|
module Grape
|
|
6
4
|
class API
|
|
7
5
|
# The API Instance class, is the engine behind Grape::API. Each class that inherits
|
|
8
6
|
# from this will represent a different API instance
|
|
9
7
|
class Instance
|
|
10
|
-
|
|
8
|
+
# Marks this and every mounted instance as a mountable Grape app (see Grape::Mountable).
|
|
9
|
+
extend Grape::Mountable
|
|
10
|
+
extend Grape::DSL::Settings
|
|
11
|
+
extend Grape::DSL::Desc
|
|
12
|
+
extend Grape::DSL::Validations
|
|
13
|
+
extend Grape::DSL::Callbacks
|
|
14
|
+
extend Grape::DSL::Logger
|
|
15
|
+
extend Grape::DSL::Middleware
|
|
16
|
+
extend Grape::DSL::RequestResponse
|
|
17
|
+
extend Grape::DSL::Routing
|
|
18
|
+
extend Grape::DSL::Helpers
|
|
19
|
+
extend Grape::Middleware::Auth::DSL
|
|
20
|
+
|
|
21
|
+
Boolean = Grape::API::Boolean
|
|
11
22
|
|
|
12
23
|
class << self
|
|
13
|
-
attr_reader :instance, :base
|
|
14
24
|
attr_accessor :configuration
|
|
15
25
|
|
|
16
|
-
def
|
|
17
|
-
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def mounted(&block)
|
|
21
|
-
evaluate_as_instance_with_configuration(block, lazy: true)
|
|
26
|
+
def to_s
|
|
27
|
+
@base&.to_s || super
|
|
22
28
|
end
|
|
23
29
|
|
|
24
30
|
def base=(grape_api)
|
|
@@ -26,12 +32,8 @@ module Grape
|
|
|
26
32
|
grape_api.instances << self
|
|
27
33
|
end
|
|
28
34
|
|
|
29
|
-
def to_s
|
|
30
|
-
base&.to_s || super
|
|
31
|
-
end
|
|
32
|
-
|
|
33
35
|
def base_instance?
|
|
34
|
-
self == base.base_instance
|
|
36
|
+
self == @base.base_instance
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
# A class-level lock to ensure the API is not compiled by multiple
|
|
@@ -45,91 +47,33 @@ module Grape
|
|
|
45
47
|
reset_validations!
|
|
46
48
|
end
|
|
47
49
|
|
|
48
|
-
# Parses the API's definition and compiles it into an instance of
|
|
49
|
-
# Grape::API.
|
|
50
|
-
def compile
|
|
51
|
-
@instance ||= new
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
# Wipe the compiled API so we can recompile after changes were made.
|
|
55
|
-
def change!
|
|
56
|
-
@instance = nil
|
|
57
|
-
end
|
|
58
|
-
|
|
59
50
|
# This is the interface point between Rack and Grape; it accepts a request
|
|
60
51
|
# from Rack and ultimately returns an array of three values: the status,
|
|
61
52
|
# the headers, and the body. See [the rack specification]
|
|
62
53
|
# (http://www.rubydoc.info/github/rack/rack/master/file/SPEC) for more.
|
|
63
54
|
def call(env)
|
|
64
55
|
compile!
|
|
65
|
-
call
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# A non-synchronized version of ::call.
|
|
69
|
-
def call!(env)
|
|
70
|
-
instance.call(env)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# (see #cascade?)
|
|
74
|
-
def cascade(value = nil)
|
|
75
|
-
if value.nil?
|
|
76
|
-
inheritable_setting.namespace_inheritable.key?(:cascade) ? !namespace_inheritable(:cascade).nil? : true
|
|
77
|
-
else
|
|
78
|
-
namespace_inheritable(:cascade, value)
|
|
79
|
-
end
|
|
56
|
+
@instance.call(env)
|
|
80
57
|
end
|
|
81
58
|
|
|
82
59
|
def compile!
|
|
83
|
-
return if instance
|
|
60
|
+
return if @instance
|
|
84
61
|
|
|
85
|
-
LOCK.synchronize {
|
|
62
|
+
LOCK.synchronize { @instance ||= new }
|
|
86
63
|
end
|
|
87
64
|
|
|
88
65
|
# see Grape::Router#recognize_path
|
|
89
66
|
def recognize_path(path)
|
|
90
67
|
compile!
|
|
91
|
-
instance.router.recognize_path(path)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
protected
|
|
95
|
-
|
|
96
|
-
def prepare_routes
|
|
97
|
-
endpoints.map(&:routes).flatten
|
|
68
|
+
@instance.router.recognize_path(path)
|
|
98
69
|
end
|
|
99
70
|
|
|
100
|
-
#
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def nest(*blocks, &block)
|
|
104
|
-
blocks.compact!
|
|
105
|
-
if blocks.any?
|
|
106
|
-
evaluate_as_instance_with_configuration(block) if block
|
|
107
|
-
blocks.each { |b| evaluate_as_instance_with_configuration(b) }
|
|
108
|
-
reset_validations!
|
|
109
|
-
else
|
|
110
|
-
instance_eval(&block)
|
|
111
|
-
end
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
def evaluate_as_instance_with_configuration(block, lazy: false)
|
|
115
|
-
lazy_block = Grape::Util::LazyBlock.new do |configuration|
|
|
116
|
-
value_for_configuration = configuration
|
|
117
|
-
self.configuration = value_for_configuration.evaluate if value_for_configuration.respond_to?(:lazy?) && value_for_configuration.lazy?
|
|
118
|
-
response = instance_eval(&block)
|
|
119
|
-
self.configuration = value_for_configuration
|
|
120
|
-
response
|
|
121
|
-
end
|
|
122
|
-
if base && base_instance? && lazy
|
|
123
|
-
lazy_block
|
|
124
|
-
else
|
|
125
|
-
lazy_block.evaluate_from(configuration)
|
|
126
|
-
end
|
|
71
|
+
# Wipe the compiled API so we can recompile after changes were made.
|
|
72
|
+
def change!
|
|
73
|
+
@instance = nil
|
|
127
74
|
end
|
|
128
75
|
|
|
129
|
-
|
|
130
|
-
subclass.reset!
|
|
131
|
-
subclass.logger = logger.clone
|
|
132
|
-
end
|
|
76
|
+
protected
|
|
133
77
|
|
|
134
78
|
def inherit_settings(other_settings)
|
|
135
79
|
top_level_setting.inherit_from other_settings.point_in_time_copy
|
|
@@ -143,6 +87,14 @@ module Grape
|
|
|
143
87
|
|
|
144
88
|
reset_routes!
|
|
145
89
|
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def inherited(subclass)
|
|
94
|
+
super
|
|
95
|
+
subclass.reset!
|
|
96
|
+
subclass.logger logger.clone
|
|
97
|
+
end
|
|
146
98
|
end
|
|
147
99
|
|
|
148
100
|
attr_reader :router
|
|
@@ -162,9 +114,13 @@ module Grape
|
|
|
162
114
|
|
|
163
115
|
# Handle a request. See Rack documentation for what `env` is.
|
|
164
116
|
def call(env)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
117
|
+
status, headers, response = @router.call(env)
|
|
118
|
+
unless cascade?
|
|
119
|
+
headers = Grape::Util::Header.new.merge(headers)
|
|
120
|
+
headers.delete('X-Cascade')
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
[status, headers, response]
|
|
168
124
|
end
|
|
169
125
|
|
|
170
126
|
# Some requests may return a HTTP 404 error if grape cannot find a matching
|
|
@@ -176,8 +132,9 @@ module Grape
|
|
|
176
132
|
# errors from reaching upstream. This is effectivelly done by unsetting
|
|
177
133
|
# X-Cascade. Default :cascade is true.
|
|
178
134
|
def cascade?
|
|
179
|
-
|
|
180
|
-
return
|
|
135
|
+
namespace_inheritable = self.class.inheritable_setting.namespace_inheritable
|
|
136
|
+
return namespace_inheritable[:cascade] if namespace_inheritable.key?(:cascade)
|
|
137
|
+
return namespace_inheritable[:version_options].cascade if namespace_inheritable[:version_options]
|
|
181
138
|
|
|
182
139
|
true
|
|
183
140
|
end
|
|
@@ -191,89 +148,42 @@ module Grape
|
|
|
191
148
|
# will return an HTTP 405 response for any HTTP method that the resource
|
|
192
149
|
# cannot handle.
|
|
193
150
|
def add_head_not_allowed_methods_and_options_methods
|
|
194
|
-
versioned_route_configs = collect_route_config_per_pattern
|
|
195
151
|
# The paths we collected are prepared (cf. Path#prepare), so they
|
|
196
152
|
# contain already versioning information when using path versioning.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
allow_header = (self.class.namespace_inheritable(:do_not_route_options) ? allowed_methods : [Grape::Http::Headers::OPTIONS] | allowed_methods)
|
|
209
|
-
|
|
210
|
-
config[:endpoint].options[:options_route_enabled] = true unless self.class.namespace_inheritable(:do_not_route_options) || allowed_methods.include?(Grape::Http::Headers::OPTIONS)
|
|
211
|
-
|
|
212
|
-
attributes = config.merge(allowed_methods: allowed_methods, allow_header: allow_header)
|
|
213
|
-
generate_not_allowed_method(config[:pattern], **attributes)
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
end
|
|
153
|
+
all_routes = self.class.endpoints.flat_map(&:routes)
|
|
154
|
+
|
|
155
|
+
# Read the settings the helper routes need from a *copy* with the
|
|
156
|
+
# root-prefix/versioning keys stripped, so adding these routes won't
|
|
157
|
+
# prepend versioning information again. This used to delete those keys
|
|
158
|
+
# from the shared class-level settings and restore them in an ensure;
|
|
159
|
+
# a request served concurrently on another instance during a runtime
|
|
160
|
+
# recompile could observe the missing keys (e.g. via #cascade?). A
|
|
161
|
+
# local copy keeps that mutation off the shared object.
|
|
162
|
+
namespace_inheritable = self.class.inheritable_setting.namespace_inheritable.to_hash.except(*ROOT_PREFIX_VERSIONING_KEYS)
|
|
163
|
+
collect_route_config_per_pattern(all_routes, namespace_inheritable)
|
|
217
164
|
end
|
|
218
165
|
|
|
219
|
-
def collect_route_config_per_pattern
|
|
220
|
-
|
|
221
|
-
routes_by_regexp = all_routes.group_by { |route| route.pattern.to_regexp }
|
|
166
|
+
def collect_route_config_per_pattern(all_routes, namespace_inheritable)
|
|
167
|
+
routes_by_regexp = all_routes.group_by(&:pattern_regexp)
|
|
222
168
|
|
|
223
169
|
# Build the configuration based on the first endpoint and the collection of methods supported.
|
|
224
|
-
routes_by_regexp.
|
|
225
|
-
|
|
226
|
-
matching_wildchar = routes.any? { |route| route.request_method == '*' }
|
|
227
|
-
{
|
|
228
|
-
options: { matching_wildchar: matching_wildchar },
|
|
229
|
-
pattern: last_route.pattern,
|
|
230
|
-
requirements: last_route.requirements,
|
|
231
|
-
path: last_route.origin,
|
|
232
|
-
endpoint: last_route.app,
|
|
233
|
-
methods: matching_wildchar ? Grape::Http::Headers::SUPPORTED_METHODS : routes.map(&:request_method)
|
|
234
|
-
}
|
|
235
|
-
end
|
|
236
|
-
end
|
|
170
|
+
routes_by_regexp.each_value do |routes|
|
|
171
|
+
next if routes.any? { |route| route.request_method == '*' }
|
|
237
172
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
supported_methods =
|
|
242
|
-
if self.class.namespace_inheritable(:do_not_route_options)
|
|
243
|
-
Grape::Http::Headers::SUPPORTED_METHODS
|
|
244
|
-
else
|
|
245
|
-
Grape::Http::Headers::SUPPORTED_METHODS_WITHOUT_OPTIONS
|
|
246
|
-
end
|
|
247
|
-
not_allowed_methods = supported_methods - allowed_methods
|
|
248
|
-
@router.associate_routes(pattern, not_allowed_methods: not_allowed_methods, **attributes)
|
|
249
|
-
end
|
|
173
|
+
last_route = routes.last # Most of the configuration is taken from the last endpoint
|
|
174
|
+
allowed_methods = routes.map(&:request_method)
|
|
175
|
+
allowed_methods |= [Rack::HEAD] if !namespace_inheritable[:do_not_route_head] && allowed_methods.include?(Rack::GET)
|
|
250
176
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
def without_versioning(&_block)
|
|
254
|
-
old_version = self.class.namespace_inheritable(:version)
|
|
255
|
-
old_version_options = self.class.namespace_inheritable(:version_options)
|
|
177
|
+
allow_header = namespace_inheritable[:do_not_route_options] ? allowed_methods : [Rack::OPTIONS] | allowed_methods
|
|
178
|
+
last_route.app.options_route_enabled = true unless namespace_inheritable[:do_not_route_options] || allowed_methods.include?(Rack::OPTIONS)
|
|
256
179
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
yield
|
|
261
|
-
|
|
262
|
-
self.class.namespace_inheritable(:version, old_version)
|
|
263
|
-
self.class.namespace_inheritable(:version_options, old_version_options)
|
|
180
|
+
greedy_route = Grape::Router::GreedyRoute.new(last_route.pattern, endpoint: last_route.app, allow_header:)
|
|
181
|
+
@router.associate_routes(greedy_route)
|
|
182
|
+
end
|
|
264
183
|
end
|
|
265
184
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
def without_root_prefix(&_block)
|
|
269
|
-
old_prefix = self.class.namespace_inheritable(:root_prefix)
|
|
270
|
-
|
|
271
|
-
self.class.namespace_inheritable_to_nil(:root_prefix)
|
|
272
|
-
|
|
273
|
-
yield
|
|
274
|
-
|
|
275
|
-
self.class.namespace_inheritable(:root_prefix, old_prefix)
|
|
276
|
-
end
|
|
185
|
+
ROOT_PREFIX_VERSIONING_KEYS = %i[version version_options root_prefix].freeze
|
|
186
|
+
private_constant :ROOT_PREFIX_VERSIONING_KEYS
|
|
277
187
|
end
|
|
278
188
|
end
|
|
279
189
|
end
|
data/lib/grape/api.rb
CHANGED
|
@@ -1,49 +1,47 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'grape/router'
|
|
4
|
-
require 'grape/api/instance'
|
|
5
|
-
|
|
6
3
|
module Grape
|
|
7
4
|
# The API class is the primary entry point for creating Grape APIs. Users
|
|
8
5
|
# should subclass this class in order to build an API.
|
|
9
6
|
class API
|
|
7
|
+
# Marks this and every subclass as a mountable Grape app (see Grape::Mountable).
|
|
8
|
+
extend Grape::Mountable
|
|
9
|
+
|
|
10
10
|
# Class methods that we want to call on the API rather than on the API object
|
|
11
|
-
NON_OVERRIDABLE = %i[call
|
|
11
|
+
NON_OVERRIDABLE = %i[base= base_instance? call change! configuration compile! inherit_settings recognize_path reset! routes top_level_setting= top_level_setting].freeze
|
|
12
|
+
|
|
13
|
+
Helpers = Grape::DSL::Helpers::BaseHelper
|
|
12
14
|
|
|
13
15
|
class Boolean
|
|
16
|
+
VALUES = [true, false].freeze
|
|
17
|
+
private_constant :VALUES
|
|
18
|
+
|
|
14
19
|
def self.build(val)
|
|
15
|
-
return
|
|
20
|
+
return unless VALUES.include?(val)
|
|
16
21
|
|
|
17
22
|
new
|
|
18
23
|
end
|
|
19
24
|
end
|
|
20
25
|
|
|
21
|
-
class Instance
|
|
22
|
-
Boolean = Grape::API::Boolean
|
|
23
|
-
end
|
|
24
|
-
|
|
25
26
|
class << self
|
|
26
|
-
|
|
27
|
+
extend Forwardable
|
|
27
28
|
|
|
28
|
-
|
|
29
|
-
def new(*args, &block)
|
|
30
|
-
base_instance.new(*args, &block)
|
|
31
|
-
end
|
|
29
|
+
attr_accessor :base_instance, :instances
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
# It will listen to the setup required to mount that endpoint, and replicate it on any new instance
|
|
35
|
-
def inherited(api)
|
|
36
|
-
super
|
|
31
|
+
delegate_missing_to :base_instance
|
|
37
32
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
33
|
+
# This is the interface point between Rack and Grape; it accepts a request
|
|
34
|
+
# from Rack and ultimately returns an array of three values: the status,
|
|
35
|
+
# the headers, and the body. See [the rack specification]
|
|
36
|
+
# (https://github.com/rack/rack/blob/main/SPEC.rdoc) for more.
|
|
37
|
+
# NOTE: This will only be called on an API directly mounted on RACK
|
|
38
|
+
def_delegators :base_instance, :new, :configuration, :call, :change!, :compile!, :recognize_path, :routes
|
|
41
39
|
|
|
42
40
|
# Initialize the instance variables on the remountable class, and the base_instance
|
|
43
41
|
# an instance that will be used to create the set up but will not be mounted
|
|
44
42
|
def initial_setup(base_instance_parent)
|
|
45
43
|
@instances = []
|
|
46
|
-
@setup =
|
|
44
|
+
@setup = []
|
|
47
45
|
@base_parent = base_instance_parent
|
|
48
46
|
@base_instance = mount_instance
|
|
49
47
|
end
|
|
@@ -51,8 +49,8 @@ module Grape
|
|
|
51
49
|
# Redefines all methods so that are forwarded to add_setup and be recorded
|
|
52
50
|
def override_all_methods!
|
|
53
51
|
(base_instance.methods - Class.methods - NON_OVERRIDABLE).each do |method_override|
|
|
54
|
-
define_singleton_method(method_override) do |*args, &block|
|
|
55
|
-
add_setup(method_override,
|
|
52
|
+
define_singleton_method(method_override) do |*args, **kwargs, &block|
|
|
53
|
+
add_setup(method: method_override, args:, kwargs:, block:)
|
|
56
54
|
end
|
|
57
55
|
end
|
|
58
56
|
end
|
|
@@ -64,138 +62,104 @@ module Grape
|
|
|
64
62
|
# `configuration` as normal.
|
|
65
63
|
def configure
|
|
66
64
|
config = @base_instance.configuration
|
|
67
|
-
|
|
68
|
-
yield config
|
|
69
|
-
self
|
|
70
|
-
else
|
|
71
|
-
config
|
|
72
|
-
end
|
|
73
|
-
end
|
|
65
|
+
return config unless block_given?
|
|
74
66
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
# the headers, and the body. See [the rack specification]
|
|
78
|
-
# (http://www.rubydoc.info/github/rack/rack/master/file/SPEC) for more.
|
|
79
|
-
# NOTE: This will only be called on an API directly mounted on RACK
|
|
80
|
-
def call(*args, &block)
|
|
81
|
-
instance_for_rack.call(*args, &block)
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Alleviates problems with autoloading by tring to search for the constant
|
|
85
|
-
def const_missing(*args)
|
|
86
|
-
if base_instance.const_defined?(*args)
|
|
87
|
-
base_instance.const_get(*args)
|
|
88
|
-
else
|
|
89
|
-
super
|
|
90
|
-
end
|
|
67
|
+
yield config
|
|
68
|
+
self
|
|
91
69
|
end
|
|
92
70
|
|
|
93
71
|
# The remountable class can have a configuration hash to provide some dynamic class-level variables.
|
|
94
72
|
# For instance, a description could be done using: `desc configuration[:description]` if it may vary
|
|
95
73
|
# depending on where the endpoint is mounted. Use with care, if you find yourself using configuration
|
|
96
74
|
# too much, you may actually want to provide a new API rather than remount it.
|
|
97
|
-
def mount_instance(
|
|
75
|
+
def mount_instance(configuration: nil)
|
|
98
76
|
instance = Class.new(@base_parent)
|
|
99
|
-
instance.configuration = Grape::Util::EndpointConfiguration.new(
|
|
77
|
+
instance.configuration = Grape::Util::EndpointConfiguration.new(configuration || {})
|
|
100
78
|
instance.base = self
|
|
101
79
|
replay_setup_on(instance)
|
|
102
80
|
instance
|
|
103
81
|
end
|
|
104
82
|
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
# When inherited, will create a list of all instances (times the API was mounted)
|
|
86
|
+
# It will listen to the setup required to mount that endpoint, and replicate it on any new instance
|
|
87
|
+
def inherited(api)
|
|
88
|
+
super
|
|
89
|
+
|
|
90
|
+
api.initial_setup(self == Grape::API ? Grape::API::Instance : @base_instance)
|
|
91
|
+
api.override_all_methods!
|
|
92
|
+
end
|
|
93
|
+
|
|
105
94
|
# Replays the set up to produce an API as defined in this class, can be called
|
|
106
95
|
# on classes that inherit from Grape::API
|
|
107
96
|
def replay_setup_on(instance)
|
|
108
97
|
@setup.each do |setup_step|
|
|
109
|
-
replay_step_on(instance, setup_step)
|
|
98
|
+
replay_step_on(instance, **setup_step)
|
|
110
99
|
end
|
|
111
100
|
end
|
|
112
101
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def method_missing(method, *args, &block)
|
|
122
|
-
# If there's a missing method, it may be defined on the base_instance instead.
|
|
123
|
-
if respond_to_missing?(method)
|
|
124
|
-
base_instance.send(method, *args, &block)
|
|
125
|
-
else
|
|
126
|
-
super
|
|
102
|
+
# Adds a new stage to the set up require to get a Grape::API up and running
|
|
103
|
+
def add_setup(**step)
|
|
104
|
+
@setup << step
|
|
105
|
+
last_response = nil
|
|
106
|
+
@instances.each do |instance|
|
|
107
|
+
last_response = replay_step_on(instance, **step)
|
|
127
108
|
end
|
|
128
|
-
end
|
|
129
109
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
instance_for_rack.compile! # See API::Instance.compile!
|
|
110
|
+
refresh_mount_step if step[:method] != :mount
|
|
111
|
+
last_response
|
|
133
112
|
end
|
|
134
113
|
|
|
135
|
-
|
|
114
|
+
# Updating all previously mounted classes in the case that new methods have been executed.
|
|
115
|
+
def refresh_mount_step
|
|
116
|
+
@setup.each do |setup_step|
|
|
117
|
+
next if setup_step[:method] != :mount
|
|
136
118
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
119
|
+
refresh_mount_step = setup_step.merge(method: :refresh_mounted_api)
|
|
120
|
+
@setup << refresh_mount_step
|
|
121
|
+
@instances.each do |instance|
|
|
122
|
+
replay_step_on(instance, **refresh_mount_step)
|
|
123
|
+
end
|
|
142
124
|
end
|
|
143
125
|
end
|
|
144
126
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
setup_step = { method: method, args: args, block: block }
|
|
148
|
-
@setup += [setup_step]
|
|
149
|
-
last_response = nil
|
|
150
|
-
@instances.each do |instance|
|
|
151
|
-
last_response = replay_step_on(instance, setup_step)
|
|
152
|
-
end
|
|
153
|
-
last_response
|
|
154
|
-
end
|
|
127
|
+
def replay_step_on(instance, method:, args:, kwargs:, block:)
|
|
128
|
+
return if skip_immediate_run?(instance, args, kwargs)
|
|
155
129
|
|
|
156
|
-
|
|
157
|
-
|
|
130
|
+
eval_args = evaluate_arguments(instance.configuration, *args)
|
|
131
|
+
eval_kwargs = kwargs.deep_transform_values { |v| evaluate_arguments(instance.configuration, v).first }
|
|
132
|
+
response = instance.__send__(method, *eval_args, **eval_kwargs, &block)
|
|
158
133
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
response
|
|
163
|
-
else
|
|
164
|
-
evaluate_arguments(instance.configuration, response).first
|
|
165
|
-
end
|
|
134
|
+
return response if skip_immediate_run?(instance, [response], kwargs)
|
|
135
|
+
|
|
136
|
+
evaluate_arguments(instance.configuration, response).first
|
|
166
137
|
end
|
|
167
138
|
|
|
168
139
|
# Skips steps that contain arguments to be lazily executed (on re-mount time)
|
|
169
|
-
def skip_immediate_run?(instance, args)
|
|
140
|
+
def skip_immediate_run?(instance, args, kwargs)
|
|
170
141
|
instance.base_instance? &&
|
|
171
|
-
(any_lazy?(args) || args.any? { |arg| arg.is_a?(Hash) && any_lazy?(arg.values) })
|
|
142
|
+
(any_lazy?(args) || args.any? { |arg| arg.is_a?(Hash) && any_lazy?(arg.values) } || any_lazy?(kwargs.values))
|
|
172
143
|
end
|
|
173
144
|
|
|
174
145
|
def any_lazy?(args)
|
|
175
|
-
args.any?
|
|
146
|
+
args.any?(Grape::Util::Lazy::Base)
|
|
176
147
|
end
|
|
177
148
|
|
|
178
149
|
def evaluate_arguments(configuration, *args)
|
|
179
150
|
args.map do |argument|
|
|
180
|
-
|
|
151
|
+
case argument
|
|
152
|
+
when Grape::Util::Lazy::Base
|
|
181
153
|
argument.evaluate_from(configuration)
|
|
182
|
-
|
|
154
|
+
when Hash
|
|
183
155
|
argument.transform_values { |value| evaluate_arguments(configuration, value).first }
|
|
184
|
-
|
|
156
|
+
when Array
|
|
185
157
|
evaluate_arguments(configuration, *argument)
|
|
186
158
|
else
|
|
187
159
|
argument
|
|
188
160
|
end
|
|
189
161
|
end
|
|
190
162
|
end
|
|
191
|
-
|
|
192
|
-
def never_mounted?
|
|
193
|
-
mounted_instances.empty?
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def mounted_instances
|
|
197
|
-
instances - [base_instance]
|
|
198
|
-
end
|
|
199
163
|
end
|
|
200
164
|
end
|
|
201
165
|
end
|
data/lib/grape/content_types.rb
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'grape/util/registrable'
|
|
4
|
-
|
|
5
3
|
module Grape
|
|
6
4
|
module ContentTypes
|
|
7
|
-
|
|
5
|
+
module_function
|
|
8
6
|
|
|
9
7
|
# Content types are listed in order of preference.
|
|
10
|
-
|
|
8
|
+
DEFAULTS = {
|
|
11
9
|
xml: 'application/xml',
|
|
12
10
|
serializable_hash: 'application/json',
|
|
13
11
|
json: 'application/json',
|
|
@@ -15,14 +13,28 @@ module Grape
|
|
|
15
13
|
txt: 'text/plain'
|
|
16
14
|
}.freeze
|
|
17
15
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
MIME_TYPES = Grape::ContentTypes::DEFAULTS.except(:serializable_hash).invert.freeze
|
|
17
|
+
|
|
18
|
+
def content_types_for(from_settings)
|
|
19
|
+
from_settings.presence || DEFAULTS
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def mime_types_for(from_settings)
|
|
23
|
+
return MIME_TYPES if from_settings == Grape::ContentTypes::DEFAULTS
|
|
24
|
+
|
|
25
|
+
from_settings.invert.transform_keys! { |k| media_type(k) }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# The media type of a content-type header: the part before any `;`
|
|
29
|
+
# parameters, with surrounding whitespace removed
|
|
30
|
+
# (e.g. `'text/html'` for `'text/html; charset=utf-8'`). Returns nil for a
|
|
31
|
+
# nil content type. Skips the split (and its allocation) when there are no
|
|
32
|
+
# parameters, which is the common case.
|
|
33
|
+
def media_type(content_type)
|
|
34
|
+
return if content_type.nil?
|
|
22
35
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
36
|
+
base = content_type.include?(';') ? content_type.split(';', 2).first : content_type
|
|
37
|
+
base.strip
|
|
26
38
|
end
|
|
27
39
|
end
|
|
28
40
|
end
|