class Marcel::MimeType

def extend(type, extensions: [], parents: [], magic: nil)

def extend(type, extensions: [], parents: [], magic: nil)
  extensions = (Array(extensions) + Array(Marcel::TYPE_EXTS[type])).uniq
  parents = (Array(parents) + Array(Marcel::TYPE_PARENTS[type])).uniq
  Magic.add(type, extensions: extensions, magic: magic, parents: parents)
end

def for(pathname_or_io = nil, name: nil, extension: nil, declared_type: nil)

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

* type declared by the first of file name, file extension, or declared MIME type
* type declared by binary magic number data
The most appropriate type is determined by the following:

* +declared_type+: MIME type, if known
* +extension+: file extension, if known
* +name+: file name, if known
Optional parameters:

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

Returns the most appropriate content type for the given file.
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

def for_data(pathname_or_io)

def for_data(pathname_or_io)
  if pathname_or_io
    with_io(pathname_or_io) do |io|
      if magic = Marcel::Magic.by_magic(io)
        magic.type.downcase
      end
    end
  end
end

def for_declared_type(declared_type)

def for_declared_type(declared_type)
  type = parse_media_type(declared_type)
  # application/octet-stream is treated as an undeclared/missing type,
  # allowing the type to be inferred from the filename. If there's no
  # filename extension, then the type falls back to binary anyway.
  type unless type == BINARY
end

def for_extension(extension)

def for_extension(extension)
  if extension
    if magic = Marcel::Magic.by_extension(extension)
      magic.type.downcase
    end
  end
end

def for_name(name)

def for_name(name)
  if name
    if magic = Marcel::Magic.by_path(name)
      magic.type.downcase
    end
  end
end

def most_specific_type(*candidates)

specific class using either the name or declared_type, we should use that in preference
type with magic, but not the specific subclass. In this situation, if we can get a more
For some document types (notably Microsoft Office) we recognise the main content
def most_specific_type(*candidates)
  candidates.compact.uniq.reduce do |type, candidate|
    Marcel::Magic.child?(candidate, type) ? candidate : type
  end
end

def parse_media_type(content_type)

def parse_media_type(content_type)
  if content_type
    result = content_type.downcase.split(/[;,\s]/, 2).first
    result if result && result.index("/")
  end
end

def with_io(pathname_or_io, &block)

def with_io(pathname_or_io, &block)
  if defined?(Pathname) && pathname_or_io.is_a?(Pathname)
    pathname_or_io.open(&block)
  else
    yield pathname_or_io
  end
end