grape 2.4.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 +351 -0
- data/CONTRIBUTING.md +18 -10
- data/README.md +457 -228
- data/UPGRADING.md +1240 -1
- data/grape.gemspec +7 -7
- data/lib/grape/api/instance.rb +65 -116
- data/lib/grape/api.rb +53 -62
- data/lib/grape/content_types.rb +58 -3
- data/lib/grape/cookies.rb +2 -6
- data/lib/grape/declared_params_handler.rb +116 -0
- data/lib/grape/dry_types.rb +48 -4
- data/lib/grape/dsl/callbacks.rb +8 -58
- data/lib/grape/dsl/declared.rb +35 -0
- data/lib/grape/dsl/desc.rb +24 -67
- data/lib/grape/dsl/entity.rb +106 -0
- data/lib/grape/dsl/helpers.rb +80 -65
- data/lib/grape/dsl/inside_route.rb +56 -296
- data/lib/grape/dsl/logger.rb +4 -9
- data/lib/grape/dsl/middleware.rb +22 -40
- data/lib/grape/dsl/parameters.rb +86 -93
- data/lib/grape/dsl/request_response.rb +139 -139
- data/lib/grape/dsl/rescue_options.rb +25 -0
- data/lib/grape/dsl/routing.rb +328 -203
- data/lib/grape/dsl/settings.rb +29 -135
- data/lib/grape/dsl/validations.rb +38 -44
- data/lib/grape/dsl/version_options.rb +23 -0
- data/lib/grape/endpoint/options.rb +25 -0
- data/lib/grape/endpoint.rb +285 -245
- data/lib/grape/env.rb +8 -3
- data/lib/grape/error_formatter/base.rb +27 -21
- data/lib/grape/error_formatter/json.rb +6 -0
- data/lib/grape/error_formatter/txt.rb +10 -10
- data/lib/grape/error_formatter.rb +6 -2
- data/lib/grape/exceptions/base.rb +20 -44
- 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 +1 -1
- 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 +1 -1
- 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 -7
- data/lib/grape/exceptions/validation_array_errors.rb +4 -0
- data/lib/grape/exceptions/validation_errors.rb +21 -23
- data/lib/grape/formatter/json.rb +1 -0
- data/lib/grape/formatter/serializable_hash.rb +6 -9
- data/lib/grape/json.rb +38 -2
- data/lib/grape/locale/en.yml +3 -5
- data/lib/grape/middleware/auth/base.rb +4 -3
- data/lib/grape/middleware/auth/dsl.rb +9 -23
- data/lib/grape/middleware/base.rb +41 -36
- data/lib/grape/middleware/error.rb +271 -73
- data/lib/grape/middleware/formatter.rb +152 -63
- data/lib/grape/middleware/precomputed_content_types.rb +51 -0
- data/lib/grape/middleware/stack.rb +20 -11
- data/lib/grape/middleware/versioner/accept_version_header.rb +3 -3
- data/lib/grape/middleware/versioner/base.rb +40 -48
- data/lib/grape/middleware/versioner/header.rb +5 -23
- data/lib/grape/middleware/versioner/param.rb +2 -2
- data/lib/grape/middleware/versioner/path.rb +54 -7
- data/lib/grape/mountable.rb +22 -0
- data/lib/grape/namespace.rb +19 -11
- data/lib/grape/params_builder/base.rb +2 -0
- data/lib/grape/params_builder/hash_with_indifferent_access.rb +1 -1
- data/lib/grape/params_builder.rb +2 -19
- data/lib/grape/parser/json.rb +1 -1
- data/lib/grape/path.rb +8 -72
- data/lib/grape/precompiled_json.rb +50 -0
- data/lib/grape/request.rb +57 -20
- data/lib/grape/router/base_route.rb +53 -7
- data/lib/grape/router/greedy_route.rb +16 -6
- data/lib/grape/router/mustermann_pattern.rb +44 -0
- data/lib/grape/router/pattern/path.rb +78 -0
- data/lib/grape/router/pattern.rb +65 -37
- data/lib/grape/router/route.rb +66 -18
- data/lib/grape/router.rb +126 -115
- 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 -2
- data/lib/grape/util/deep_freeze.rb +34 -0
- data/lib/grape/util/freeze_on_new.rb +20 -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 +2 -9
- data/lib/grape/util/lazy/value.rb +2 -9
- data/lib/grape/util/lazy/value_enumerable.rb +13 -16
- data/lib/grape/util/media_type.rb +13 -9
- data/lib/grape/util/path_normalizer.rb +37 -0
- data/lib/grape/util/registry.rb +13 -3
- data/lib/grape/util/shadowed_rescue_handlers.rb +49 -0
- data/lib/grape/util/stackable_values.rb +39 -10
- data/lib/grape/util/translation.rb +42 -0
- data/lib/grape/validations/attributes_iterator.rb +61 -29
- data/lib/grape/validations/coerce_options.rb +21 -0
- data/lib/grape/validations/contract_scope.rb +8 -13
- 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 +217 -304
- 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 -10
- 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 +10 -15
- data/lib/grape/validations/types/json.rb +1 -3
- data/lib/grape/validations/types/multiple_type_coercer.rb +5 -3
- data/lib/grape/validations/types/primitive_coercer.rb +14 -33
- data/lib/grape/validations/types/set_coercer.rb +1 -1
- data/lib/grape/validations/types/variant_collection_coercer.rb +16 -3
- data/lib/grape/validations/types.rb +29 -51
- 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 -34
- data/lib/grape/validations/validators/coerce_validator.rb +25 -37
- data/lib/grape/validations/validators/contract_scope_validator.rb +10 -5
- data/lib/grape/validations/validators/default_validator.rb +13 -20
- data/lib/grape/validations/validators/exactly_one_of_validator.rb +10 -3
- data/lib/grape/validations/validators/except_values_validator.rb +14 -4
- data/lib/grape/validations/validators/length_validator.rb +23 -22
- 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 +34 -26
- data/lib/grape/version.rb +1 -2
- data/lib/grape/xml.rb +8 -1
- data/lib/grape.rb +58 -31
- metadata +62 -39
- data/lib/grape/api/helpers.rb +0 -9
- data/lib/grape/dsl/api.rb +0 -17
- data/lib/grape/dsl/configuration.rb +0 -15
- data/lib/grape/exceptions/conflicting_types.rb +0 -11
- data/lib/grape/exceptions/empty_message_body.rb +0 -11
- data/lib/grape/exceptions/invalid_parameters.rb +0 -11
- data/lib/grape/exceptions/missing_option.rb +0 -11
- data/lib/grape/exceptions/too_deep_parameters.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 -24
- data/lib/grape/extensions/hash.rb +0 -27
- data/lib/grape/extensions/hashie/mash.rb +0 -24
- data/lib/grape/middleware/globals.rb +0 -14
- 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 -29
- data/lib/grape/util/reverse_stackable_values.rb +0 -15
- data/lib/grape/util/strict_hash_configuration.rb +0 -108
- data/lib/grape/validations/attributes_doc.rb +0 -60
- data/lib/grape/validations/validator_factory.rb +0 -15
|
@@ -18,6 +18,13 @@ module Grape
|
|
|
18
18
|
def ==(other)
|
|
19
19
|
stream == other.stream
|
|
20
20
|
end
|
|
21
|
+
alias eql? ==
|
|
22
|
+
|
|
23
|
+
# Mirrors #==, which keys on the stream alone and does not check the
|
|
24
|
+
# class, so the class must stay out of the hash too.
|
|
25
|
+
def hash
|
|
26
|
+
stream.hash
|
|
27
|
+
end
|
|
21
28
|
end
|
|
22
29
|
end
|
|
23
30
|
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Testing
|
|
5
|
+
module RunBeforeEach
|
|
6
|
+
def run
|
|
7
|
+
self.class.run_before_each(self)
|
|
8
|
+
super
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
module ClassMethods
|
|
13
|
+
def before_each(&block)
|
|
14
|
+
raise ArgumentError, 'a block is required' unless block
|
|
15
|
+
|
|
16
|
+
@before_each ||= []
|
|
17
|
+
@before_each << block
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def reset_before_each
|
|
21
|
+
@before_each&.clear
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def run_before_each(endpoint)
|
|
25
|
+
superclass.run_before_each(endpoint) unless self == Grape::Endpoint
|
|
26
|
+
@before_each&.each { |blk| blk.call(endpoint) }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
Grape::Endpoint.prepend(RunBeforeEach)
|
|
31
|
+
Grape::Endpoint.extend(ClassMethods)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Util
|
|
5
|
+
class ApiDescription
|
|
6
|
+
DSL_METHODS = %i[
|
|
7
|
+
body_name
|
|
8
|
+
consumes
|
|
9
|
+
default_response
|
|
10
|
+
deprecated
|
|
11
|
+
detail
|
|
12
|
+
entity
|
|
13
|
+
headers
|
|
14
|
+
hidden
|
|
15
|
+
http_codes
|
|
16
|
+
is_array
|
|
17
|
+
named
|
|
18
|
+
nickname
|
|
19
|
+
params
|
|
20
|
+
produces
|
|
21
|
+
security
|
|
22
|
+
summary
|
|
23
|
+
tags
|
|
24
|
+
].freeze
|
|
25
|
+
|
|
26
|
+
def initialize(description, endpoint_configuration, &)
|
|
27
|
+
@endpoint_configuration = endpoint_configuration
|
|
28
|
+
@attributes = { description: }
|
|
29
|
+
instance_eval(&)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
DSL_METHODS.each do |attribute|
|
|
33
|
+
define_method attribute do |value|
|
|
34
|
+
@attributes[attribute] = value
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
alias success entity
|
|
39
|
+
alias failure http_codes
|
|
40
|
+
|
|
41
|
+
# @deprecated Use {#default_response}. The description is read back
|
|
42
|
+
# through an ActiveSupport::OrderedOptions, where +default+ is
|
|
43
|
+
# +Hash#default+ rather than a key lookup, and grape-swagger has always
|
|
44
|
+
# asked the route for +default_response+.
|
|
45
|
+
def default(value)
|
|
46
|
+
Grape.deprecator.warn('`default` in a `desc` block is deprecated. Use `default_response` instead.')
|
|
47
|
+
default_response(value)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def configuration
|
|
51
|
+
@configuration ||= eval_endpoint_config(@endpoint_configuration)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def settings
|
|
55
|
+
@attributes
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def eval_endpoint_config(configuration)
|
|
61
|
+
return configuration if configuration.is_a?(Hash)
|
|
62
|
+
|
|
63
|
+
configuration.evaluate
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/grape/util/cache.rb
CHANGED
|
@@ -2,15 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
module Grape
|
|
4
4
|
module Util
|
|
5
|
+
# Base class for the lazily-filled lookup caches (coercers, dry-types,
|
|
6
|
+
# path parts, ...). Subclasses assign a default-block +Hash+ to +@cache+
|
|
7
|
+
# in their +initialize+.
|
|
8
|
+
#
|
|
9
|
+
# Lookups are synchronized: caches are written at API *definition* time
|
|
10
|
+
# (a +params+ block runs when the class body is evaluated), which is not
|
|
11
|
+
# covered by the compile-time +Grape::API::Instance::LOCK+ and can happen
|
|
12
|
+
# concurrently — e.g. parallel eager loading, or two threads autoloading
|
|
13
|
+
# different API files. A +Monitor+ (reentrant) rather than a +Mutex+,
|
|
14
|
+
# because a cache miss may re-enter the same cache: building a
|
|
15
|
+
# multiple-type coercer through +Types::CoercerCache+ builds its member
|
|
16
|
+
# coercers through +Types.build_coercer+, which lands in the same cache.
|
|
5
17
|
class Cache
|
|
6
18
|
include Singleton
|
|
7
19
|
|
|
8
20
|
attr_reader :cache
|
|
9
21
|
|
|
22
|
+
def initialize
|
|
23
|
+
@monitor = Monitor.new
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def [](key)
|
|
27
|
+
@monitor.synchronize { @cache[key] }
|
|
28
|
+
end
|
|
29
|
+
|
|
10
30
|
class << self
|
|
11
31
|
extend Forwardable
|
|
12
|
-
|
|
13
|
-
def_delegators :instance, :cache
|
|
32
|
+
|
|
33
|
+
def_delegators :instance, :[], :cache
|
|
14
34
|
end
|
|
15
35
|
end
|
|
16
36
|
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Util
|
|
5
|
+
module DeepFreeze
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
# Recursively freezes Hash (keys and values), Array (elements), and String
|
|
9
|
+
# objects. All other types are returned as-is.
|
|
10
|
+
#
|
|
11
|
+
# Intentionally left unfrozen:
|
|
12
|
+
# - Procs / lambdas — may be deferred DB-backed callables
|
|
13
|
+
# - Classes / Modules — shared constants that must remain open
|
|
14
|
+
# - Coercers and ParamsScope — self-freeze at construction
|
|
15
|
+
def deep_freeze(obj)
|
|
16
|
+
case obj
|
|
17
|
+
when Hash
|
|
18
|
+
obj.each do |k, v|
|
|
19
|
+
deep_freeze(k)
|
|
20
|
+
deep_freeze(v)
|
|
21
|
+
end
|
|
22
|
+
obj.freeze
|
|
23
|
+
when Array
|
|
24
|
+
obj.each { |v| deep_freeze(v) }
|
|
25
|
+
obj.freeze
|
|
26
|
+
when String
|
|
27
|
+
obj.freeze
|
|
28
|
+
else
|
|
29
|
+
obj
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Grape
|
|
4
|
+
module Util
|
|
5
|
+
# Extend into a class whose instances are shared across requests:
|
|
6
|
+
# +new+ returns a frozen instance, so any later ivar write — e.g.
|
|
7
|
+
# request-time memoization — raises FrozenError instead of being a
|
|
8
|
+
# latent data race.
|
|
9
|
+
#
|
|
10
|
+
# Must stay a +new+ wrapper (never an +initialize+ wrapper): the freeze
|
|
11
|
+
# runs after the entire initialize chain, so subclasses may assign ivars
|
|
12
|
+
# after +super+. Extending a hierarchy base covers its subclasses —
|
|
13
|
+
# singleton classes inherit along the class hierarchy.
|
|
14
|
+
module FreezeOnNew
|
|
15
|
+
def new(...)
|
|
16
|
+
super.freeze
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|