Class: Marcel::MimeType

Inherits:
Object
  • Object
show all
Defined in:
lib/marcel/mime_type.rb

Constant Summary collapse

BINARY =
"application/octet-stream"
MAX_DECLARED_TYPE_BYTES =
8 * 1024
TOKEN =
"[!#$%&'*+\\-.^_`|~0-9A-Za-z]+"
QUOTED_STRING =
'"(?:[\t\x20\x21\x23-\x5B\x5D-\x7E\x80-\xFF]|\\\\[\t\x20-\x7E\x80-\xFF])*"'
MEDIA_TYPE =
%r{\A(#{TOKEN}/#{TOKEN})(?:[ \t]*;[ \t]*#{TOKEN}=(?:#{TOKEN}|#{QUOTED_STRING}))*(?:[ \t]*;[ \t]*)?\z}n

Class Method Summary collapse

Class Method Details

.canonicalize(type, instead_of:) ⇒ Object



12
13
14
# File 'lib/marcel/mime_type.rb', line 12

def canonicalize(type, instead_of:)
  Magic.canonicalize type, instead_of: instead_of
end

.extend(type, extensions: nil, aliases: nil, parents: nil, magic: nil) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/marcel/mime_type.rb', line 16

def extend(type, extensions: nil, aliases: nil, parents: nil, magic: nil)
  type = type.downcase

  if canonical = Marcel::TYPE_ALIASES[type]
    warn "#{type} is an alias; extending its canonical type #{canonical} instead"
    type = canonical
  end

  extensions = Array(extensions)
  if extensions.any? && extensions.sort == Array(Marcel::TYPE_EXTS[type]).sort
    warn "#{type} already has extensions #{extensions.inspect}"
  end
  extensions |= Array(Marcel::TYPE_EXTS[type])

  aliases = Array(aliases)
  existing_aliases = Marcel::TYPE_ALIASES.select { |_, existing| existing == type }.keys
  if aliases.any? && aliases.sort == existing_aliases.sort
    warn "#{type} already has aliases #{aliases.inspect}"
  end
  aliases |= existing_aliases

  parents = Array(parents)
  if parents.any? && parents.sort == Array(Marcel::TYPE_PARENTS[type]).sort
    warn "#{type} already has parents #{parents.inspect}"
  end
  parents |= Array(Marcel::TYPE_PARENTS[type])

  # No duplicate-magic warning: matcher order determines precedence, so re-registering
  # an existing matcher legitimately promotes it ahead of the generated tables.
  Magic.add(type, extensions: extensions, magic: magic, aliases: aliases, parents: parents)
end

.for(pathname_or_io = nil, name: nil, extension: nil, declared_type: nil) ⇒ Object

Returns the most appropriate content type for the given file.

The first argument should be a Pathname or an IO. If it is a Pathname, the specified file will be opened first.

Optional parameters:

  • name: file name, if known
  • extension: file extension, if known
  • declared_type: MIME type, if known

The most appropriate type is determined by the following:

  • type declared by binary magic number data
  • valid declared MIME type, unless it is application/octet-stream
  • type inferred from the file name or extension

A later candidate is used only if it is more specific than the type already found.

The result is a best-effort label, not validation that the file is safe or conforms to the returned type. Treat name and declared_type as hints from their respective sources.

If no type can be determined, then application/octet-stream is returned.



69
70
71
72
# File 'lib/marcel/mime_type.rb', line 69

def for(pathname_or_io = nil, name: nil, extension: nil, declared_type: nil)
  filename_type = for_name(name) || for_extension(extension)
  most_specific_type for_data(pathname_or_io), for_declared_type(declared_type), filename_type, BINARY
end