Commit f1f446c2 by Zach Millman Committed by Jon Yurek

Add documentation of content-type detection strategy

Also refactored to make the strategy hierarchy clearer
parent d42adb8a
module Paperclip module Paperclip
class ContentTypeDetector class ContentTypeDetector
# The content-type detection strategy is as follows:
#
# 1. Blank/Empty files: If there's no filename or the file is empty, provide a sensible default
# (application/octet-stream or inode/x-empty)
#
# 2. Uploaded file: Use the uploaded file's content type if it is in the list of mime-types
# for the file's extension
#
# 3. Standard types: Return the first standard (without an x- prefix) entry in the list of
# mime-types
#
# 4. Experimental types: If there were no standard types in the mime-types list, try to return
# the first experimental one
#
# 5. Unrecognized extension: Use the file's content type or a sensible default if there are
# no entries in mime-types for the extension
#
EMPTY_TYPE = "inode/x-empty" EMPTY_TYPE = "inode/x-empty"
SENSIBLE_DEFAULT = "application/octet-stream" SENSIBLE_DEFAULT = "application/octet-stream"
...@@ -7,17 +25,16 @@ module Paperclip ...@@ -7,17 +25,16 @@ module Paperclip
@filename = filename @filename = filename
end end
# Returns a String describing the file's content type
def detect def detect
if blank_name? if blank_name?
SENSIBLE_DEFAULT SENSIBLE_DEFAULT
elsif empty_file? elsif empty_file?
EMPTY_TYPE EMPTY_TYPE
elsif !match? elsif best_from_possible_types
type_from_file_command best_from_possible_types.content_type
elsif !multiple?
possible_types.first
else else
best_type_match type_from_file_command || SENSIBLE_DEFAULT
end.to_s end.to_s
end end
...@@ -30,23 +47,25 @@ module Paperclip ...@@ -30,23 +47,25 @@ module Paperclip
def blank_name? def blank_name?
@filename.nil? || @filename.empty? @filename.nil? || @filename.empty?
end end
def empty?
File.exists?(@filename) && File.size(@filename) == 0
end
def possible_types def possible_types
@possible_types ||= MIME::Types.type_for(@filename) @possible_types ||= MIME::Types.type_for(@filename)
end end
def match? def official_types
possible_types.length > 0 @official_types ||= possible_types.reject {|type| type.content_type.match(/\/x-/) }
end end
def multiple? def types_matching_file
possible_types.length > 1 possible_types.select{|type| type.content_type == type_from_file_command}
end end
def best_type_match def best_from_possible_types
types_matching_file = possible_types.select {|type| type.content_type == type_from_file_command} @best_from_possible_types ||= (types_matching_file.first || official_types.first || possible_types.first)
official_types = possible_types.reject {|type| type.content_type.match(/\/x-/) }
(types_matching_file.first || official_types.first || possible_types.first).content_type
end end
def type_from_file_command def type_from_file_command
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment