Skip to content

Commit fb67ea9

Browse files
authored
Remove Grape::Util::Registrable + Small refactors (#2475)
* Refactor ErrorFormatter, Parser and Formatter Remove Grape::Util::Registrable Add Grape::MimeTypes + spec Small refactors * Add CHANGELOG.md
1 parent 5671969 commit fb67ea9

14 files changed

+183
-214
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
#### Features
44

5+
* [#2475](https://github.com/ruby-grape/grape/pull/2475): Remove Grape::Util::Registrable - [@ericproulx](https://github.com/ericproulx).
56
* Your contribution here.
67

78
#### Fixes
89

910
* [#2471](https://github.com/ruby-grape/grape/pull/2471): Fix absence of original_exception and/or backtrace even if passed in error! - [@numbata](https://github.com/numbata).
11+
* Your contribution here.
1012

1113
### 2.1.3 (2024-07-13)
1214

lib/grape/content_types.rb

+13-8
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,29 @@
22

33
module Grape
44
module ContentTypes
5-
extend Util::Registrable
5+
module_function
66

77
# Content types are listed in order of preference.
8-
CONTENT_TYPES = {
8+
DEFAULTS = {
99
xml: 'application/xml',
1010
serializable_hash: 'application/json',
1111
json: 'application/json',
1212
binary: 'application/octet-stream',
1313
txt: 'text/plain'
1414
}.freeze
1515

16-
class << self
17-
def content_types_for_settings(settings)
18-
settings&.inject(:merge!)
19-
end
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
2024

21-
def content_types_for(from_settings)
22-
from_settings.presence || Grape::ContentTypes::CONTENT_TYPES.merge(default_elements)
25+
from_settings.each_with_object({}) do |(k, v), types_without_params|
26+
# remove optional parameter
27+
types_without_params[v.split(';', 2).first] = k
2328
end
2429
end
2530
end

lib/grape/dsl/request_response.rb

+14-18
Original file line numberDiff line numberDiff line change
@@ -17,18 +17,16 @@ def default_format(new_format = nil)
1717
# Specify the format for the API's serializers.
1818
# May be `:json`, `:xml`, `:txt`, etc.
1919
def format(new_format = nil)
20-
if new_format
21-
namespace_inheritable(:format, new_format.to_sym)
22-
# define the default error formatters
23-
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(new_format, **{}))
24-
# define a single mime type
25-
mime_type = content_types[new_format.to_sym]
26-
raise Grape::Exceptions::MissingMimeType.new(new_format) unless mime_type
27-
28-
namespace_stackable(:content_types, new_format.to_sym => mime_type)
29-
else
30-
namespace_inheritable(:format)
31-
end
20+
return namespace_inheritable(:format) unless new_format
21+
22+
symbolic_new_format = new_format.to_sym
23+
namespace_inheritable(:format, symbolic_new_format)
24+
namespace_inheritable(:default_error_formatter, Grape::ErrorFormatter.formatter_for(symbolic_new_format))
25+
26+
content_type = content_types[symbolic_new_format]
27+
raise Grape::Exceptions::MissingMimeType.new(new_format) unless content_type
28+
29+
namespace_stackable(:content_types, symbolic_new_format => content_type)
3230
end
3331

3432
# Specify a custom formatter for a content-type.
@@ -43,12 +41,10 @@ def parser(content_type, new_parser)
4341

4442
# Specify a default error formatter.
4543
def default_error_formatter(new_formatter_name = nil)
46-
if new_formatter_name
47-
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name, **{})
48-
namespace_inheritable(:default_error_formatter, new_formatter)
49-
else
50-
namespace_inheritable(:default_error_formatter)
51-
end
44+
return namespace_inheritable(:default_error_formatter) unless new_formatter_name
45+
46+
new_formatter = Grape::ErrorFormatter.formatter_for(new_formatter_name)
47+
namespace_inheritable(:default_error_formatter, new_formatter)
5248
end
5349

5450
def error_formatter(format, options)

lib/grape/error_formatter.rb

+13-25
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,22 @@
22

33
module Grape
44
module ErrorFormatter
5-
extend Util::Registrable
5+
module_function
66

7-
class << self
8-
def builtin_formatters
9-
@builtin_formatters ||= {
10-
serializable_hash: Grape::ErrorFormatter::Json,
11-
json: Grape::ErrorFormatter::Json,
12-
jsonapi: Grape::ErrorFormatter::Json,
13-
txt: Grape::ErrorFormatter::Txt,
14-
xml: Grape::ErrorFormatter::Xml
15-
}
16-
end
7+
DEFAULTS = {
8+
serializable_hash: Grape::ErrorFormatter::Json,
9+
json: Grape::ErrorFormatter::Json,
10+
jsonapi: Grape::ErrorFormatter::Json,
11+
txt: Grape::ErrorFormatter::Txt,
12+
xml: Grape::ErrorFormatter::Xml
13+
}.freeze
1714

18-
def formatters(**options)
19-
builtin_formatters.merge(default_elements).merge!(options[:error_formatters] || {})
20-
end
15+
def formatter_for(format, error_formatters = nil, default_error_formatter = nil)
16+
select_formatter(error_formatters, format) || default_error_formatter || DEFAULTS[:txt]
17+
end
2118

22-
def formatter_for(api_format, **options)
23-
spec = formatters(**options)[api_format]
24-
case spec
25-
when nil
26-
options[:default_error_formatter] || Grape::ErrorFormatter::Txt
27-
when Symbol
28-
method(spec)
29-
else
30-
spec
31-
end
32-
end
19+
def select_formatter(error_formatters, format)
20+
error_formatters&.key?(format) ? error_formatters[format] : DEFAULTS[format]
3321
end
3422
end
3523
end

lib/grape/formatter.rb

+15-25
Original file line numberDiff line numberDiff line change
@@ -2,34 +2,24 @@
22

33
module Grape
44
module Formatter
5-
extend Util::Registrable
5+
module_function
66

7-
class << self
8-
def builtin_formatters
9-
@builtin_formatters ||= {
10-
json: Grape::Formatter::Json,
11-
jsonapi: Grape::Formatter::Json,
12-
serializable_hash: Grape::Formatter::SerializableHash,
13-
txt: Grape::Formatter::Txt,
14-
xml: Grape::Formatter::Xml
15-
}
16-
end
7+
DEFAULTS = {
8+
json: Grape::Formatter::Json,
9+
jsonapi: Grape::Formatter::Json,
10+
serializable_hash: Grape::Formatter::SerializableHash,
11+
txt: Grape::Formatter::Txt,
12+
xml: Grape::Formatter::Xml
13+
}.freeze
1714

18-
def formatters(**options)
19-
builtin_formatters.merge(default_elements).merge!(options[:formatters] || {})
20-
end
15+
DEFAULT_LAMBDA_FORMATTER = ->(obj, _env) { obj }
2116

22-
def formatter_for(api_format, **options)
23-
spec = formatters(**options)[api_format]
24-
case spec
25-
when nil
26-
->(obj, _env) { obj }
27-
when Symbol
28-
method(spec)
29-
else
30-
spec
31-
end
32-
end
17+
def formatter_for(api_format, formatters)
18+
select_formatter(formatters, api_format) || DEFAULT_LAMBDA_FORMATTER
19+
end
20+
21+
def select_formatter(formatters, api_format)
22+
formatters&.key?(api_format) ? formatters[api_format] : DEFAULTS[api_format]
3323
end
3424
end
3525
end

lib/grape/middleware/base.rb

+12-10
Original file line numberDiff line numberDiff line change
@@ -61,22 +61,20 @@ def response
6161
@app_response = Rack::Response.new(@app_response[2], @app_response[0], @app_response[1])
6262
end
6363

64-
def content_type_for(format)
65-
HashWithIndifferentAccess.new(content_types)[format]
64+
def content_types
65+
@content_types ||= Grape::ContentTypes.content_types_for(options[:content_types])
6666
end
6767

68-
def content_types
69-
ContentTypes.content_types_for(options[:content_types])
68+
def mime_types
69+
@mime_types ||= Grape::ContentTypes.mime_types_for(content_types)
7070
end
7171

72-
def content_type
73-
content_type_for(env[Grape::Env::API_FORMAT] || options[:format]) || TEXT_HTML
72+
def content_type_for(format)
73+
content_types_indifferent_access[format]
7474
end
7575

76-
def mime_types
77-
@mime_types ||= content_types.each_pair.with_object({}) do |(k, v), types_without_params|
78-
types_without_params[v.split(';').first] = k
79-
end
76+
def content_type
77+
content_type_for(env[Grape::Env::API_FORMAT] || options[:format]) || TEXT_HTML
8078
end
8179

8280
private
@@ -89,6 +87,10 @@ def merge_headers(response)
8987
when Array then response[1].merge!(headers)
9088
end
9189
end
90+
91+
def content_types_indifferent_access
92+
@content_types_indifferent_access ||= content_types.with_indifferent_access
93+
end
9294
end
9395
end
9496
end

lib/grape/middleware/error.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def rack_response(status, headers, message)
4545

4646
def format_message(message, backtrace, original_exception = nil)
4747
format = env[Grape::Env::API_FORMAT] || options[:format]
48-
formatter = Grape::ErrorFormatter.formatter_for(format, **options)
48+
formatter = Grape::ErrorFormatter.formatter_for(format, options[:error_formatters], options[:default_error_formatter])
4949
return formatter.call(message, backtrace, options, env, original_exception) if formatter
5050

5151
throw :error,

lib/grape/middleware/formatter.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ def build_formatted_response(status, headers, bodies)
5454

5555
def fetch_formatter(headers, options)
5656
api_format = mime_types[headers[Rack::CONTENT_TYPE]] || env[Grape::Env::API_FORMAT]
57-
Grape::Formatter.formatter_for(api_format, **options)
57+
Grape::Formatter.formatter_for(api_format, options[:formatters])
5858
end
5959

6060
# Set the content type header for the API format if it is not already present.
@@ -97,7 +97,7 @@ def read_rack_input(body)
9797
fmt = request.media_type ? mime_types[request.media_type] : options[:default_format]
9898

9999
throw :error, status: 415, message: "The provided content-type '#{request.media_type}' is not supported." unless content_type_for(fmt)
100-
parser = Grape::Parser.parser_for fmt, **options
100+
parser = Grape::Parser.parser_for fmt, options[:parsers]
101101
if parser
102102
begin
103103
body = (env[Grape::Env::API_REQUEST_BODY] = parser.call(body, env))

lib/grape/parser.rb

+8-24
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,16 @@
22

33
module Grape
44
module Parser
5-
extend Util::Registrable
5+
module_function
66

7-
class << self
8-
def builtin_parsers
9-
@builtin_parsers ||= {
10-
json: Grape::Parser::Json,
11-
jsonapi: Grape::Parser::Json,
12-
xml: Grape::Parser::Xml
13-
}
14-
end
7+
DEFAULTS = {
8+
json: Grape::Parser::Json,
9+
jsonapi: Grape::Parser::Json,
10+
xml: Grape::Parser::Xml
11+
}.freeze
1512

16-
def parsers(**options)
17-
builtin_parsers.merge(default_elements).merge!(options[:parsers] || {})
18-
end
19-
20-
def parser_for(api_format, **options)
21-
spec = parsers(**options)[api_format]
22-
case spec
23-
when nil
24-
nil
25-
when Symbol
26-
method(spec)
27-
else
28-
spec
29-
end
30-
end
13+
def parser_for(format, parsers = nil)
14+
parsers&.key?(format) ? parsers[format] : DEFAULTS[format]
3115
end
3216
end
3317
end

lib/grape/util/accept_header_handler.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def initialize(accept_header:, versions:, **options)
1313
@cascade = options.fetch(:cascade, true)
1414
end
1515

16-
def match_best_quality_media_type!(content_types: Grape::ContentTypes::CONTENT_TYPES, allowed_methods: nil)
16+
def match_best_quality_media_type!(content_types: Grape::ContentTypes::DEFAULTS, allowed_methods: nil)
1717
return unless vendor
1818

1919
strict_header_checks!

lib/grape/util/registrable.rb

-15
This file was deleted.

0 commit comments

Comments
 (0)