grape 1.8.0 → 4.0.1
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 +517 -1
- data/CONTRIBUTING.md +19 -11
- data/README.md +841 -545
- data/UPGRADING.md +1553 -7
- data/grape.gemspec +11 -14
- data/lib/grape/api/instance.rb +77 -160
- data/lib/grape/api.rb +75 -107
- data/lib/grape/content_types.rb +67 -9
- 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 +8 -58
- data/lib/grape/dsl/declared.rb +35 -0
- data/lib/grape/dsl/desc.rb +25 -63
- data/lib/grape/dsl/entity.rb +106 -0
- data/lib/grape/dsl/headers.rb +2 -2
- data/lib/grape/dsl/helpers.rb +83 -64
- data/lib/grape/dsl/inside_route.rb +69 -296
- data/lib/grape/dsl/logger.rb +4 -9
- data/lib/grape/dsl/middleware.rb +22 -40
- data/lib/grape/dsl/parameters.rb +88 -94
- data/lib/grape/dsl/request_response.rb +143 -147
- data/lib/grape/dsl/rescue_options.rb +25 -0
- data/lib/grape/dsl/routing.rb +333 -191
- 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 +25 -0
- data/lib/grape/endpoint.rb +319 -269
- data/lib/grape/{util/env.rb → env.rb} +8 -8
- data/lib/grape/error_formatter/base.rb +57 -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 +9 -25
- data/lib/grape/exceptions/base.rb +22 -58
- data/lib/grape/exceptions/error_response.rb +48 -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_error_formatter.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 +28 -11
- 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 +5 -6
- data/lib/grape/formatter/serializable_hash.rb +7 -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 +44 -42
- data/lib/grape/middleware/auth/base.rb +11 -33
- data/lib/grape/middleware/auth/dsl.rb +12 -34
- data/lib/grape/middleware/auth/strategies.rb +1 -2
- data/lib/grape/middleware/base.rb +56 -33
- data/lib/grape/middleware/error.rb +290 -91
- data/lib/grape/middleware/formatter.rb +164 -106
- data/lib/grape/middleware/precomputed_content_types.rb +51 -0
- data/lib/grape/middleware/stack.rb +38 -40
- data/lib/grape/middleware/versioner/accept_version_header.rb +6 -33
- data/lib/grape/middleware/versioner/base.rb +66 -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 +48 -25
- data/lib/grape/middleware/versioner.rb +7 -14
- data/lib/grape/mountable.rb +22 -0
- data/lib/grape/namespace.rb +21 -14
- 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 +8 -94
- data/lib/grape/precompiled_json.rb +50 -0
- data/lib/grape/railtie.rb +9 -0
- data/lib/grape/request.rb +200 -26
- data/lib/grape/router/base_route.rb +85 -0
- data/lib/grape/router/greedy_route.rb +30 -0
- data/lib/grape/router/mustermann_pattern.rb +44 -0
- data/lib/grape/router/pattern/path.rb +78 -0
- data/lib/grape/router/pattern.rb +77 -35
- data/lib/grape/router/route.rb +79 -60
- data/lib/grape/router.rb +128 -104
- data/lib/grape/serve_stream/file_body.rb +7 -0
- data/lib/grape/serve_stream/sendfile_response.rb +3 -5
- data/lib/grape/serve_stream/stream_response.rb +7 -0
- data/lib/grape/testing.rb +33 -0
- data/lib/grape/util/api_description.rb +67 -0
- data/lib/grape/util/cache.rb +22 -5
- data/lib/grape/util/deep_freeze.rb +34 -0
- data/lib/grape/util/endpoint_configuration.rb +1 -1
- data/lib/grape/util/freeze_on_new.rb +20 -0
- data/lib/grape/util/header.rb +13 -0
- data/lib/grape/util/inheritable_setting.rb +777 -39
- 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 +74 -0
- data/lib/grape/util/path_normalizer.rb +37 -0
- data/lib/grape/util/registry.rb +37 -0
- data/lib/grape/util/shadowed_rescue_handlers.rb +49 -0
- data/lib/grape/util/stackable_values.rb +40 -16
- data/lib/grape/util/translation.rb +42 -0
- data/lib/grape/validations/attributes_iterator.rb +61 -28
- data/lib/grape/validations/coerce_options.rb +21 -0
- data/lib/grape/validations/contract_scope.rb +29 -0
- data/lib/grape/validations/multiple_attributes_iterator.rb +1 -1
- data/lib/grape/validations/oneof_collector.rb +35 -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 +223 -306
- data/lib/grape/validations/shared_options.rb +19 -0
- data/lib/grape/validations/single_attribute_iterator.rb +6 -4
- data/lib/grape/validations/types/array_coercer.rb +7 -12
- data/lib/grape/validations/types/custom_type_coercer.rb +47 -85
- data/lib/grape/validations/types/custom_type_collection_coercer.rb +1 -1
- data/lib/grape/validations/types/dry_type_coercer.rb +17 -28
- data/lib/grape/validations/types/json.rb +1 -5
- data/lib/grape/validations/types/multiple_type_coercer.rb +5 -3
- data/lib/grape/validations/types/primitive_coercer.rb +14 -35
- data/lib/grape/validations/types/set_coercer.rb +1 -4
- data/lib/grape/validations/types/variant_collection_coercer.rb +16 -3
- 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 +118 -37
- data/lib/grape/validations/validators/coerce_validator.rb +26 -38
- data/lib/grape/validations/validators/contract_scope_validator.rb +46 -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 +50 -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 +51 -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 +7 -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 +96 -288
- metadata +83 -294
- 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/base_inheritable.rb +0 -43
- data/lib/grape/util/inheritable_values.rb +0 -31
- 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/reverse_stackable_values.rb +0 -20
- 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,37 +1,41 @@
|
|
|
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
|
-
|
|
26
|
+
def to_s
|
|
27
|
+
@base&.to_s || super
|
|
18
28
|
end
|
|
19
29
|
|
|
20
|
-
|
|
21
|
-
evaluate_as_instance_with_configuration(block, lazy: true)
|
|
22
|
-
end
|
|
30
|
+
attr_reader :base
|
|
23
31
|
|
|
24
32
|
def base=(grape_api)
|
|
25
33
|
@base = grape_api
|
|
26
34
|
grape_api.instances << self
|
|
27
35
|
end
|
|
28
36
|
|
|
29
|
-
def to_s
|
|
30
|
-
base&.to_s || super
|
|
31
|
-
end
|
|
32
|
-
|
|
33
37
|
def base_instance?
|
|
34
|
-
self == base.base_instance
|
|
38
|
+
self == @base.base_instance
|
|
35
39
|
end
|
|
36
40
|
|
|
37
41
|
# A class-level lock to ensure the API is not compiled by multiple
|
|
@@ -45,91 +49,32 @@ module Grape
|
|
|
45
49
|
reset_validations!
|
|
46
50
|
end
|
|
47
51
|
|
|
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
52
|
# This is the interface point between Rack and Grape; it accepts a request
|
|
60
53
|
# from Rack and ultimately returns an array of three values: the status,
|
|
61
54
|
# the headers, and the body. See [the rack specification]
|
|
62
55
|
# (http://www.rubydoc.info/github/rack/rack/master/file/SPEC) for more.
|
|
63
56
|
def call(env)
|
|
64
|
-
compile
|
|
65
|
-
call!(env)
|
|
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
|
|
57
|
+
compile!.call(env)
|
|
80
58
|
end
|
|
81
59
|
|
|
60
|
+
# Returns the compiled instance, so callers serve the one they
|
|
61
|
+
# compiled rather than re-reading @instance — +change!+ can nil it
|
|
62
|
+
# between the two reads (see #call / #recognize_path).
|
|
82
63
|
def compile!
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
LOCK.synchronize { compile unless instance }
|
|
64
|
+
@instance || LOCK.synchronize { @instance ||= new }
|
|
86
65
|
end
|
|
87
66
|
|
|
88
67
|
# see Grape::Router#recognize_path
|
|
89
68
|
def recognize_path(path)
|
|
90
|
-
compile
|
|
91
|
-
instance.router.recognize_path(path)
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
protected
|
|
95
|
-
|
|
96
|
-
def prepare_routes
|
|
97
|
-
endpoints.map(&:routes).flatten
|
|
69
|
+
compile!.router.recognize_path(path)
|
|
98
70
|
end
|
|
99
71
|
|
|
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
|
|
72
|
+
# Wipe the compiled API so we can recompile after changes were made.
|
|
73
|
+
def change!
|
|
74
|
+
@instance = nil
|
|
127
75
|
end
|
|
128
76
|
|
|
129
|
-
|
|
130
|
-
subclass.reset!
|
|
131
|
-
subclass.logger = logger.clone
|
|
132
|
-
end
|
|
77
|
+
protected
|
|
133
78
|
|
|
134
79
|
def inherit_settings(other_settings)
|
|
135
80
|
top_level_setting.inherit_from other_settings.point_in_time_copy
|
|
@@ -137,12 +82,20 @@ module Grape
|
|
|
137
82
|
# Propagate any inherited params down to our endpoints, and reset any
|
|
138
83
|
# compiled routes.
|
|
139
84
|
endpoints.each do |e|
|
|
140
|
-
e.inherit_settings(top_level_setting
|
|
85
|
+
e.inherit_settings(top_level_setting)
|
|
141
86
|
e.reset_routes!
|
|
142
87
|
end
|
|
143
88
|
|
|
144
89
|
reset_routes!
|
|
145
90
|
end
|
|
91
|
+
|
|
92
|
+
private
|
|
93
|
+
|
|
94
|
+
def inherited(subclass)
|
|
95
|
+
super
|
|
96
|
+
subclass.reset!
|
|
97
|
+
subclass.logger logger.clone
|
|
98
|
+
end
|
|
146
99
|
end
|
|
147
100
|
|
|
148
101
|
attr_reader :router
|
|
@@ -158,13 +111,23 @@ module Grape
|
|
|
158
111
|
|
|
159
112
|
@router.compile!
|
|
160
113
|
@router.freeze
|
|
114
|
+
@cascade = resolve_cascade
|
|
161
115
|
end
|
|
162
116
|
|
|
163
117
|
# Handle a request. See Rack documentation for what `env` is.
|
|
164
118
|
def call(env)
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
119
|
+
status, headers, response = @router.call(env)
|
|
120
|
+
unless @cascade
|
|
121
|
+
# +merge!+, not +merge+: the latter is a `dup` plus a `merge!`, so the
|
|
122
|
+
# Header built on this line would be allocated only to be discarded.
|
|
123
|
+
# The copy stays because +headers+ can come from a mounted Rack app,
|
|
124
|
+
# which is free to hand back a frozen or shared Hash that the delete
|
|
125
|
+
# below must not reach into.
|
|
126
|
+
headers = Grape::Util::Header.new.merge!(headers)
|
|
127
|
+
headers.delete('X-Cascade')
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
[status, headers, response]
|
|
168
131
|
end
|
|
169
132
|
|
|
170
133
|
# Some requests may return a HTTP 404 error if grape cannot find a matching
|
|
@@ -175,11 +138,13 @@ module Grape
|
|
|
175
138
|
# In some applications (e.g. mounting grape on rails), one might need to trap
|
|
176
139
|
# errors from reaching upstream. This is effectivelly done by unsetting
|
|
177
140
|
# X-Cascade. Default :cascade is true.
|
|
141
|
+
#
|
|
142
|
+
# Resolved in the constructor rather than per request: answering it walks
|
|
143
|
+
# the whole scope chain twice, and it reads the same settings the routes
|
|
144
|
+
# were compiled and frozen from -- changing those has to go through
|
|
145
|
+
# +change!+, which discards this instance.
|
|
178
146
|
def cascade?
|
|
179
|
-
|
|
180
|
-
return self.class.namespace_inheritable(:version_options)[:cascade] if self.class.namespace_inheritable(:version_options)&.key?(:cascade)
|
|
181
|
-
|
|
182
|
-
true
|
|
147
|
+
@cascade
|
|
183
148
|
end
|
|
184
149
|
|
|
185
150
|
reset!
|
|
@@ -191,88 +156,40 @@ module Grape
|
|
|
191
156
|
# will return an HTTP 405 response for any HTTP method that the resource
|
|
192
157
|
# cannot handle.
|
|
193
158
|
def add_head_not_allowed_methods_and_options_methods
|
|
194
|
-
versioned_route_configs = collect_route_config_per_pattern
|
|
195
159
|
# The paths we collected are prepared (cf. Path#prepare), so they
|
|
196
160
|
# contain already versioning information when using path versioning.
|
|
197
|
-
|
|
198
|
-
# informations again.
|
|
199
|
-
without_root_prefix do
|
|
200
|
-
without_versioning do
|
|
201
|
-
versioned_route_configs.each do |config|
|
|
202
|
-
next if config[:options][:matching_wildchar]
|
|
203
|
-
|
|
204
|
-
allowed_methods = config[:methods].dup
|
|
205
|
-
|
|
206
|
-
allowed_methods |= [Grape::Http::Headers::HEAD] if !self.class.namespace_inheritable(:do_not_route_head) && allowed_methods.include?(Grape::Http::Headers::GET)
|
|
161
|
+
all_routes = self.class.endpoints.flat_map(&:routes)
|
|
207
162
|
|
|
208
|
-
|
|
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
|
|
163
|
+
collect_route_config_per_pattern(all_routes)
|
|
217
164
|
end
|
|
218
165
|
|
|
219
|
-
def collect_route_config_per_pattern
|
|
220
|
-
|
|
221
|
-
routes_by_regexp = all_routes.group_by
|
|
166
|
+
def collect_route_config_per_pattern(all_routes)
|
|
167
|
+
setting = self.class.inheritable_setting
|
|
168
|
+
routes_by_regexp = all_routes.group_by(&:pattern_regexp)
|
|
222
169
|
|
|
223
170
|
# 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
|
|
237
|
-
|
|
238
|
-
# Generate a route that returns an HTTP 405 response for a user defined
|
|
239
|
-
# path on methods not specified
|
|
240
|
-
def generate_not_allowed_method(pattern, allowed_methods: [], **attributes)
|
|
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
|
|
171
|
+
routes_by_regexp.each_value do |routes|
|
|
172
|
+
next if routes.any? { |route| route.request_method == '*' }
|
|
250
173
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
old_version = self.class.namespace_inheritable(:version)
|
|
255
|
-
old_version_options = self.class.namespace_inheritable(:version_options)
|
|
174
|
+
last_route = routes.last # Most of the configuration is taken from the last endpoint
|
|
175
|
+
allowed_methods = routes.map(&:request_method)
|
|
176
|
+
allowed_methods |= [Rack::HEAD] if !setting.do_not_route_head? && allowed_methods.include?(Rack::GET)
|
|
256
177
|
|
|
257
|
-
|
|
258
|
-
|
|
178
|
+
allow_header = setting.do_not_route_options? ? allowed_methods : [Rack::OPTIONS] | allowed_methods
|
|
179
|
+
last_route.app.options_route_enabled = true unless setting.do_not_route_options? || allowed_methods.include?(Rack::OPTIONS)
|
|
259
180
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
self.class.namespace_inheritable(:version_options, old_version_options)
|
|
181
|
+
greedy_route = Grape::Router::GreedyRoute.new(last_route.pattern, endpoint: last_route.app, allow_header:)
|
|
182
|
+
@router.associate_routes(greedy_route)
|
|
183
|
+
end
|
|
264
184
|
end
|
|
265
185
|
|
|
266
|
-
#
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
186
|
+
# Backs {#cascade?}; called once, from the constructor.
|
|
187
|
+
def resolve_cascade
|
|
188
|
+
setting = self.class.inheritable_setting
|
|
189
|
+
return setting.cascade if setting.cascade_defined?
|
|
190
|
+
return setting.version_options.cascade if setting.version_options
|
|
270
191
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
yield
|
|
274
|
-
|
|
275
|
-
self.class.namespace_inheritable(:root_prefix, old_prefix)
|
|
192
|
+
true
|
|
276
193
|
end
|
|
277
194
|
end
|
|
278
195
|
end
|
data/lib/grape/api.rb
CHANGED
|
@@ -1,49 +1,51 @@
|
|
|
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= 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
|
+
#
|
|
39
|
+
# +inherit_settings+ is left out: it is protected on the base instance, so
|
|
40
|
+
# a delegator would raise NoMethodError just as the missing one does.
|
|
41
|
+
def_delegators :base_instance, :new, :configuration, :call, :change!, :compile!, :recognize_path, :routes,
|
|
42
|
+
:base, :base=, :base_instance?, :reset!, :top_level_setting
|
|
41
43
|
|
|
42
44
|
# Initialize the instance variables on the remountable class, and the base_instance
|
|
43
45
|
# an instance that will be used to create the set up but will not be mounted
|
|
44
46
|
def initial_setup(base_instance_parent)
|
|
45
47
|
@instances = []
|
|
46
|
-
@setup =
|
|
48
|
+
@setup = []
|
|
47
49
|
@base_parent = base_instance_parent
|
|
48
50
|
@base_instance = mount_instance
|
|
49
51
|
end
|
|
@@ -51,8 +53,8 @@ module Grape
|
|
|
51
53
|
# Redefines all methods so that are forwarded to add_setup and be recorded
|
|
52
54
|
def override_all_methods!
|
|
53
55
|
(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,
|
|
56
|
+
define_singleton_method(method_override) do |*args, **kwargs, &block|
|
|
57
|
+
add_setup(method: method_override, args:, kwargs:, block:)
|
|
56
58
|
end
|
|
57
59
|
end
|
|
58
60
|
end
|
|
@@ -64,138 +66,104 @@ module Grape
|
|
|
64
66
|
# `configuration` as normal.
|
|
65
67
|
def configure
|
|
66
68
|
config = @base_instance.configuration
|
|
67
|
-
|
|
68
|
-
yield config
|
|
69
|
-
self
|
|
70
|
-
else
|
|
71
|
-
config
|
|
72
|
-
end
|
|
73
|
-
end
|
|
69
|
+
return config unless block_given?
|
|
74
70
|
|
|
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
|
|
71
|
+
yield config
|
|
72
|
+
self
|
|
91
73
|
end
|
|
92
74
|
|
|
93
75
|
# The remountable class can have a configuration hash to provide some dynamic class-level variables.
|
|
94
76
|
# For instance, a description could be done using: `desc configuration[:description]` if it may vary
|
|
95
77
|
# depending on where the endpoint is mounted. Use with care, if you find yourself using configuration
|
|
96
78
|
# too much, you may actually want to provide a new API rather than remount it.
|
|
97
|
-
def mount_instance(
|
|
79
|
+
def mount_instance(configuration: nil)
|
|
98
80
|
instance = Class.new(@base_parent)
|
|
99
|
-
instance.configuration = Grape::Util::EndpointConfiguration.new(
|
|
81
|
+
instance.configuration = Grape::Util::EndpointConfiguration.new(configuration || {})
|
|
100
82
|
instance.base = self
|
|
101
83
|
replay_setup_on(instance)
|
|
102
84
|
instance
|
|
103
85
|
end
|
|
104
86
|
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
# When inherited, will create a list of all instances (times the API was mounted)
|
|
90
|
+
# It will listen to the setup required to mount that endpoint, and replicate it on any new instance
|
|
91
|
+
def inherited(api)
|
|
92
|
+
super
|
|
93
|
+
|
|
94
|
+
api.initial_setup(self == Grape::API ? Grape::API::Instance : @base_instance)
|
|
95
|
+
api.override_all_methods!
|
|
96
|
+
end
|
|
97
|
+
|
|
105
98
|
# Replays the set up to produce an API as defined in this class, can be called
|
|
106
99
|
# on classes that inherit from Grape::API
|
|
107
100
|
def replay_setup_on(instance)
|
|
108
101
|
@setup.each do |setup_step|
|
|
109
|
-
replay_step_on(instance, setup_step)
|
|
102
|
+
replay_step_on(instance, **setup_step)
|
|
110
103
|
end
|
|
111
104
|
end
|
|
112
105
|
|
|
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
|
|
106
|
+
# Adds a new stage to the set up require to get a Grape::API up and running
|
|
107
|
+
def add_setup(**step)
|
|
108
|
+
@setup << step
|
|
109
|
+
last_response = nil
|
|
110
|
+
@instances.each do |instance|
|
|
111
|
+
last_response = replay_step_on(instance, **step)
|
|
127
112
|
end
|
|
128
|
-
end
|
|
129
113
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
instance_for_rack.compile! # See API::Instance.compile!
|
|
114
|
+
refresh_mount_step if step[:method] != :mount
|
|
115
|
+
last_response
|
|
133
116
|
end
|
|
134
117
|
|
|
135
|
-
|
|
118
|
+
# Updating all previously mounted classes in the case that new methods have been executed.
|
|
119
|
+
def refresh_mount_step
|
|
120
|
+
@setup.each do |setup_step|
|
|
121
|
+
next if setup_step[:method] != :mount
|
|
136
122
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
123
|
+
refresh_mount_step = setup_step.merge(method: :refresh_mounted_api)
|
|
124
|
+
@setup << refresh_mount_step
|
|
125
|
+
@instances.each do |instance|
|
|
126
|
+
replay_step_on(instance, **refresh_mount_step)
|
|
127
|
+
end
|
|
142
128
|
end
|
|
143
129
|
end
|
|
144
130
|
|
|
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
|
|
131
|
+
def replay_step_on(instance, method:, args:, kwargs:, block:)
|
|
132
|
+
return if skip_immediate_run?(instance, args, kwargs)
|
|
155
133
|
|
|
156
|
-
|
|
157
|
-
|
|
134
|
+
eval_args = evaluate_arguments(instance.configuration, *args)
|
|
135
|
+
eval_kwargs = kwargs.deep_transform_values { |v| evaluate_arguments(instance.configuration, v).first }
|
|
136
|
+
response = instance.__send__(method, *eval_args, **eval_kwargs, &block)
|
|
158
137
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
response
|
|
163
|
-
else
|
|
164
|
-
evaluate_arguments(instance.configuration, response).first
|
|
165
|
-
end
|
|
138
|
+
return response if skip_immediate_run?(instance, [response], kwargs)
|
|
139
|
+
|
|
140
|
+
evaluate_arguments(instance.configuration, response).first
|
|
166
141
|
end
|
|
167
142
|
|
|
168
143
|
# Skips steps that contain arguments to be lazily executed (on re-mount time)
|
|
169
|
-
def skip_immediate_run?(instance, args)
|
|
144
|
+
def skip_immediate_run?(instance, args, kwargs)
|
|
170
145
|
instance.base_instance? &&
|
|
171
|
-
(any_lazy?(args) || args.any? { |arg| arg.is_a?(Hash) && any_lazy?(arg.values) })
|
|
146
|
+
(any_lazy?(args) || args.any? { |arg| arg.is_a?(Hash) && any_lazy?(arg.values) } || any_lazy?(kwargs.values))
|
|
172
147
|
end
|
|
173
148
|
|
|
174
149
|
def any_lazy?(args)
|
|
175
|
-
args.any?
|
|
150
|
+
args.any?(Grape::Util::Lazy::Base)
|
|
176
151
|
end
|
|
177
152
|
|
|
178
153
|
def evaluate_arguments(configuration, *args)
|
|
179
154
|
args.map do |argument|
|
|
180
|
-
|
|
155
|
+
case argument
|
|
156
|
+
when Grape::Util::Lazy::Base
|
|
181
157
|
argument.evaluate_from(configuration)
|
|
182
|
-
|
|
158
|
+
when Hash
|
|
183
159
|
argument.transform_values { |value| evaluate_arguments(configuration, value).first }
|
|
184
|
-
|
|
160
|
+
when Array
|
|
185
161
|
evaluate_arguments(configuration, *argument)
|
|
186
162
|
else
|
|
187
163
|
argument
|
|
188
164
|
end
|
|
189
165
|
end
|
|
190
166
|
end
|
|
191
|
-
|
|
192
|
-
def never_mounted?
|
|
193
|
-
mounted_instances.empty?
|
|
194
|
-
end
|
|
195
|
-
|
|
196
|
-
def mounted_instances
|
|
197
|
-
instances - [base_instance]
|
|
198
|
-
end
|
|
199
167
|
end
|
|
200
168
|
end
|
|
201
169
|
end
|