Skip to content

Commit

Permalink
Creates the Hanami::Action::MIME_TYPES constant (#191)
Browse files Browse the repository at this point in the history
We will use this (hugely) trimmed version of Rack::Mime::MIME_TYPES
That should result in faster format resolution and less weird bugs
(see issue #663).

- Mime#format_to_mime solves while looking at Action::Mime: It's needed
so the UnknownFormatError exception is raised when set to a format we don't map
by default.

- Documentation: Fix references to Rack::Mime under PERFORMANCE in mime.rb
- Dry::Validation removed format? from HINTS, resulting in it's error message
not appearing when the value is not filled

- Reordering of the MIME_TYPES hash for faster lookups.
  • Loading branch information
mereghost authored and jodosha committed Jan 10, 2017
1 parent eab53ca commit fe955b5
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 26 deletions.
71 changes: 64 additions & 7 deletions lib/hanami/action/mime.rb
Expand Up @@ -41,6 +41,64 @@ module Mime
# @api private
DEFAULT_CHARSET = 'utf-8'.freeze

# Most commom mime types used for responses
#
# @since 0.9.0
# @api private
MIME_TYPES = {
txt: 'text/plain',
html: 'text/html',
json: 'application/json',
manifest: 'text/cache-manifest',
atom: 'application/atom+xml',
avi: 'video/x-msvideo',
bmp: 'image/bmp',
bz: 'application/x-bzip',
bz2: 'application/x-bzip2',
chm: 'application/vnd.ms-htmlhelp',
css: 'text/css',
csv: 'text/csv',
flv: 'video/x-flv',
gif: 'image/gif',
gz: 'application/x-gzip',
h264: 'video/h264',
ico: 'image/vnd.microsoft.icon',
ics: 'text/calendar',
jpg: 'image/jpeg',
js: 'application/javascript',
mp4: 'video/mp4',
mov: 'video/quicktime',
mp3: 'audio/mpeg',
mp4a: 'audio/mp4',
mpg: 'video/mpeg',
oga: 'audio/ogg',
ogg: 'application/ogg',
ogv: 'video/ogg',
pdf: 'application/pdf',
pgp: 'application/pgp-encrypted',
png: 'image/png',
psd: 'image/vnd.adobe.photoshop',
rtf: 'application/rtf',
sh: 'application/x-sh',
svg: 'image/svg+xml',
swf: 'application/x-shockwave-flash',
tar: 'application/x-tar',
torrent: 'application/x-bittorrent',
tsv: 'text/tab-separated-values',
uri: 'text/uri-list',
vcs: 'text/x-vcalendar',
wav: 'audio/x-wav',
webm: 'video/webm',
wmv: 'video/x-ms-wmv',
woff: 'application/font-woff',
woff2: 'application/font-woff2',
wsdl: 'application/wsdl+xml',
xhtml: 'application/xhtml+xml',
xml: 'application/xml',
xslt: 'application/xslt+xml',
yml: 'text/yaml',
zip: 'application/zip' }.freeze

# Override Ruby's hook for modules.
# It includes Mime types logic
#
Expand All @@ -62,7 +120,7 @@ module ClassMethods
# @api private
def format_to_mime_type(format)
configuration.mime_type_for(format) ||
::Rack::Mime.mime_type(".#{ format }", nil) or
MIME_TYPES[format] or
raise Hanami::Controller::UnknownFormatError.new(format)
end

Expand Down Expand Up @@ -298,12 +356,12 @@ def finish
# When the format is set, the framework searches for a corresponding mime
# type to be set as the `Content-Type` header of the response.
# This lookup is performed first in the configuration, and then in
# `Rack::Mime::MIME_TYPES`. If the lookup fails, it raises an error.
# `Hanami::Action::Mime::MIME_TYPES`. If the lookup fails, it raises an error.
#
# PERFORMANCE: Because `Hanami::Controller::Configuration#formats` is
# smaller and looked up first than `Rack::Mime::MIME_TYPES`, we suggest to
# configure the most common mime types used by your application, **even
# if they are already present in that Rack constant**.
# smaller and looked up first than `Hanami::Action::Mime::MIME_TYPES`,
# we suggest to configure the most common mime types used by your
# application, **even if they are already present in that Rack constant**.
#
# @param format [#to_sym] the format
#
Expand Down Expand Up @@ -482,8 +540,7 @@ def default_content_type
# @since 0.2.0
# @api private
def detect_format
configuration.format_for(content_type) ||
::Rack::Mime::MIME_TYPES.key(content_type).gsub(/\A\./, '').to_sym
configuration.format_for(content_type) || MIME_TYPES.key(content_type)
end

# @since 0.3.0
Expand Down
2 changes: 1 addition & 1 deletion lib/hanami/controller/configuration.rb
Expand Up @@ -423,7 +423,7 @@ def format(hash)
def mime_types
@mime_types ||= begin
((@formats.keys - DEFAULT_FORMATS.keys) +
::Rack::Mime::MIME_TYPES.values).freeze
Hanami::Action::Mime::MIME_TYPES.values).freeze
end
end

Expand Down
22 changes: 7 additions & 15 deletions test/action/format_test.rb
Expand Up @@ -18,11 +18,11 @@ def call(params)
self.format = params[:format]
end
end

class Configuration
include Hanami::Action

configuration.default_request_format :jpeg
configuration.default_request_format :jpg

def call(params)
self.body = format
Expand Down Expand Up @@ -75,18 +75,12 @@ def call(params)
action = FormatController::Configuration.new
status, headers, _ = action.call({ 'HTTP_ACCEPT' => '*/*' })

action.format.must_equal :jpeg
action.format.must_equal :jpg
headers['Content-Type'].must_equal 'image/jpeg; charset=utf-8'
status.must_equal 200
end

mime_types = ['application/octet-stream', 'text/html']
Rack::Mime::MIME_TYPES.each do |format, mime_type|
next if mime_types.include?(mime_type)
mime_types.push mime_type

format = format.gsub(/\A\./, '').to_sym

Hanami::Action::Mime::MIME_TYPES.each do |format, mime_type|
it "accepts '#{ mime_type }' and returns :#{ format }" do
status, headers, _ = @action.call({ 'HTTP_ACCEPT' => mime_type })

Expand Down Expand Up @@ -127,13 +121,11 @@ def call(params)
end
end

Rack::Mime::MIME_TYPES.each do |format, mime_type|
format = format.gsub(/\A\./, '')

it "sets :#{ format } and returns '#{ mime_type }'" do
Hanami::Action::Mime::MIME_TYPES.each do |format, mime_type|
it "sets #{ format } and returns '#{ mime_type }'" do
_, headers, _ = @action.call({ format: format })

@action.format.must_equal format.to_sym
@action.format.must_equal format
headers['Content-Type'].must_equal "#{mime_type}; charset=utf-8"
end
end
Expand Down
6 changes: 3 additions & 3 deletions test/configuration_test.rb
Expand Up @@ -194,15 +194,15 @@ def hash

it 'returns all known MIME types' do
all = ["custom/format"]
@configuration.mime_types.must_equal(all + ::Rack::Mime::MIME_TYPES.values)
@configuration.mime_types.must_equal(all + Hanami::Action::Mime::MIME_TYPES.values)
end

it 'returns correct values even after the value is cached' do
@configuration.mime_types
@configuration.format electroneering: 'custom/electroneering'

all = ["custom/format", "custom/electroneering"]
@configuration.mime_types.must_equal(all + ::Rack::Mime::MIME_TYPES.values)
@configuration.mime_types.must_equal(all + Hanami::Action::Mime::MIME_TYPES.values)
end
end

Expand Down Expand Up @@ -441,7 +441,7 @@ def hash
@configuration.action_module.must_equal(::Hanami::Action)
@configuration.modules.must_equal([])
@configuration.send(:formats).must_equal(Hanami::Controller::Configuration::DEFAULT_FORMATS)
@configuration.mime_types.must_equal(Rack::Mime::MIME_TYPES.values)
@configuration.mime_types.must_equal(Hanami::Action::Mime::MIME_TYPES.values)
@configuration.default_request_format.must_be_nil
@configuration.default_response_format.must_be_nil
@configuration.default_charset.must_be_nil
Expand Down

0 comments on commit fe955b5

Please sign in to comment.