Metaprogramming in Elixir: MIME-Type Conversion (need help fixing a func)

Task: to create functional API for our MIME converter, which can convert from MIME to extensions list
and extension to MIME
in short we have:

mimes.txt

Summary
application/vnd.hzn-3d-crossword	.x3d
video/3gpp	.3gp
video/3gpp2	.3g2
application/vnd.mseq	.mseq
application/vnd.3gpp2.tcap	.tcap
application/x-7z-compressed	.7z
audio/x-aac	.aac
application/vnd.audiograph	.aep
image/vnd.dxf	.dxf
model/vnd.dwf	.dwf
text/plain-bas	.par
application/x-bcpio	.bcpio
application/octet-stream	.bin
image/bmp	.bmp
application/atom+xml	.atom, .xml
application/rss+xml	.rss, .xml
application/xml	.xml

etc.... more than 600...

my code:

mimes.ex

Summary
Code.require_file("mime.exs", "lib")

defmodule Mimes do
  require Mime

  @doc """
  Provides a list of extensions for the specific mimetype

  Mimes.extensions_from_type("application/atom+xml") :: [".atom", ".xml"]
  Mimes.extensions_from_type("application/x-texinfo")
  Mimes.extensions_from_type("text/n3")

  """
  @spec extensions_from_type(String.t()) :: [String.t()]
  def extensions_from_type(mimetype) do
    Mime.exts_from_type(mimetype)
  end

  @doc """
  Provides ability to fetch mimetype information about specific extension
  Examples:
    Mimes.mimetype_for_extension(".torrent) :: "application/x-bittorrent"
    Mimes.mimetype_for_extension(".psb) ...
    Mimes.mimetype_for_extension(".m4v") ...
  """
  @spec mimetype_for_extension(String.t()) :: String.t() | nil
  def mimetype_for_extension(extension) do
    Mime.type_from_ext(extension)
  end

  @spec mimetype_valid?(String.t()) :: boolean
  def mimetype_valid?(mime), do: Mime.valid_type?(mime)
end

mime.exs

Summary
defmodule Mime do

  @external_resource mimes_path = Path.join(["mimes.txt"])

  for line <- File.stream!(mimes_path, [], :line) do
    [type, rest] = line |> String.split("\t") |> Enum.map(&String.strip(&1))
    extensions = String.split(rest, ~r/,\s?/)

    def exts_from_type(unquote(type)), do: unquote(extensions)
    def type_from_ext(ext) when ext in unquote(extensions), do: unquote(type)
  end

  def exts_from_type(_type), do: []
  def type_from_ext(_ext), do: nil
  def valid_type?(type), do: exts_from_type(type) |> Enum.any?
end

example of a few tests

Summary
test "extensions from type for JSON" do
    assert Mimes.extensions_from_type("application/json") == [".json"]
  end

  test "type from extensions" do
    assert Mimes.mimetype_for_extension(".jpg") == "image/jpeg"
  end

  test "validation type true" do
    assert Mimes.mimetype_valid?("text/html") == true
  end

Now in the test if I return .xml it takes only the first of the list in mimes.txt for example this application/atom+xml .atom, .xml and I need to make it return all three that are in the list mimes.txt

Can you please help me fix this function def type_from_ext(ext) when ext in unquote(extensions), do: unquote(type) in

mime.exs

to return :

application/atom+xml .atom, .xml
application/rss+xml .rss, .xml
application/xml .xml
1 Like

This won’t agree with callsites like mimetype_for_extension which expect either a String or nil, so this is a bigger problem than just “fix type_from_ext”.

You’ll also need to entirely rework how type_from_ext is defined since a single head (def type_from_ext(".xml") for instance) will need information from multiple lines in mimes.txt.

1 Like