Skip to content

Commit f1f446c

Browse files
zmillmanJon Yurek
authored and
Jon Yurek
committed
Add documentation of content-type detection strategy
Also refactored to make the strategy hierarchy clearer
1 parent d42adb8 commit f1f446c

File tree

1 file changed

+35
-16
lines changed

1 file changed

+35
-16
lines changed

lib/paperclip/content_type_detector.rb

+35-16
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,40 @@
11
module Paperclip
22
class ContentTypeDetector
3+
# The content-type detection strategy is as follows:
4+
#
5+
# 1. Blank/Empty files: If there's no filename or the file is empty, provide a sensible default
6+
# (application/octet-stream or inode/x-empty)
7+
#
8+
# 2. Uploaded file: Use the uploaded file's content type if it is in the list of mime-types
9+
# for the file's extension
10+
#
11+
# 3. Standard types: Return the first standard (without an x- prefix) entry in the list of
12+
# mime-types
13+
#
14+
# 4. Experimental types: If there were no standard types in the mime-types list, try to return
15+
# the first experimental one
16+
#
17+
# 5. Unrecognized extension: Use the file's content type or a sensible default if there are
18+
# no entries in mime-types for the extension
19+
#
20+
321
EMPTY_TYPE = "inode/x-empty"
422
SENSIBLE_DEFAULT = "application/octet-stream"
523

624
def initialize(filename)
725
@filename = filename
826
end
927

28+
# Returns a String describing the file's content type
1029
def detect
1130
if blank_name?
1231
SENSIBLE_DEFAULT
1332
elsif empty_file?
1433
EMPTY_TYPE
15-
elsif !match?
16-
type_from_file_command
17-
elsif !multiple?
18-
possible_types.first
34+
elsif best_from_possible_types
35+
best_from_possible_types.content_type
1936
else
20-
best_type_match
37+
type_from_file_command || SENSIBLE_DEFAULT
2138
end.to_s
2239
end
2340

@@ -30,23 +47,25 @@ def empty_file?
3047
def blank_name?
3148
@filename.nil? || @filename.empty?
3249
end
50+
51+
def empty?
52+
File.exists?(@filename) && File.size(@filename) == 0
53+
end
3354

3455
def possible_types
3556
@possible_types ||= MIME::Types.type_for(@filename)
3657
end
37-
38-
def match?
39-
possible_types.length > 0
58+
59+
def official_types
60+
@official_types ||= possible_types.reject {|type| type.content_type.match(/\/x-/) }
4061
end
41-
42-
def multiple?
43-
possible_types.length > 1
62+
63+
def types_matching_file
64+
possible_types.select{|type| type.content_type == type_from_file_command}
4465
end
45-
46-
def best_type_match
47-
types_matching_file = possible_types.select {|type| type.content_type == type_from_file_command}
48-
official_types = possible_types.reject {|type| type.content_type.match(/\/x-/) }
49-
(types_matching_file.first || official_types.first || possible_types.first).content_type
66+
67+
def best_from_possible_types
68+
@best_from_possible_types ||= (types_matching_file.first || official_types.first || possible_types.first)
5069
end
5170

5271
def type_from_file_command

0 commit comments

Comments
 (0)