Page MenuHomePhorge

No OneTemporary

Size
6 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/majic/extension.ex b/lib/majic/extension.ex
index 3bbdeba..e112b99 100644
--- a/lib/majic/extension.ex
+++ b/lib/majic/extension.ex
@@ -1,112 +1,115 @@
defmodule Majic.Extension do
@moduledoc """
Helper module to fix extensions. Uses [MIME](https://hexdocs.pm/mime/MIME.html).
"""
@typedoc """
If an extension is defined for a given MIME type, append it to the previous extension.
If no extension could be found for the MIME type, and `subtype_as_extension: false`, the returned filename will have no extension.
"""
@type option_append :: {:append, false | true}
@typedoc "If no extension is defined for a given MIME type, use the subtype as its extension."
@type option_subtype_as_extension :: {:subtype_as_extension, false | true}
@spec fix(Path.t(), Majic.Result.t() | String.t(), [
option_append() | option_subtype_as_extension()
]) :: Path.t()
@doc """
Fix `name`'s extension according to `result_or_mime_type`.
```elixir
iex(1)> {:ok, result} = Majic.perform("cat.jpeg", once: true)
{:ok, %Majic.Result{mime_type: "image/webp", ...}}
iex(1)> Majic.Extension.fix("cat.jpeg", result)
"cat.webp"
```
The `append: true` option will append the correct extension to the user-provided one, if there's an extension for the
type:
```
iex(1)> Majic.Extension.fix("cat.jpeg", result, append: true)
"cat.jpeg.webp"
iex(2)> Majic.Extension.fix("Makefile.txt", "text/x-makefile", append: true)
"Makefile"
```
The `subtype_as_extension: true` option will use the subtype part of the MIME type as an extension for the ones that
don't have any:
```elixir
iex(1)> Majic.Extension.fix("Makefile.txt", "text/x-makefile", subtype_as_extension: true)
"Makefile.x-makefile"
iex(1)> Majic.Extension.fix("Makefile.txt", "text/x-makefile", subtype_as_extension: true, append: true)
"Makefile.txt.x-makefile"
```
"""
def fix(name, result_or_mime_type, options \\ [])
def fix(name, %Majic.Result{mime_type: mime_type}, options) do
do_fix(name, mime_type, options)
end
def fix(name, mime_type, options) do
do_fix(name, mime_type, options)
end
defp do_fix(name, mime_type, options) do
append? = Keyword.get(options, :append, false)
subtype? = Keyword.get(options, :subtype_as_extension, false)
ext_candidates = MIME.extensions(mime_type)
- old_ext = String.downcase(Path.extname(name))
- old_ext_bare = String.trim_leading(old_ext, ".")
+ old_ext = Path.extname(name)
+ old_ext_bare = String.trim_leading(String.downcase(old_ext), ".")
+ dir = Path.dirname(name)
basename = Path.basename(name, old_ext)
+ full_basename = Path.basename(name)
+
+ join = fn filename ->
+ case dir do
+ "." -> filename
+ _ -> Path.join(dir, filename)
+ end
+ end
cond do
- # extension already in candidate list, so no-op
old_ext_bare in ext_candidates ->
name
- # has extension, append the subtype
not match?("", old_ext) && append? && subtype? ->
- Enum.join([name, subtype_extension(subtype?, mime_type)], ".")
+ join.(Enum.join([full_basename, subtype_extension(subtype?, mime_type)], "."))
- # has extension, change to subtype
not match?("", old_ext) && subtype? ->
- Enum.join([basename, subtype_extension(subtype?, mime_type)], ".")
+ join.(Enum.join([basename, subtype_extension(subtype?, mime_type)], "."))
+
+ match?("", old_ext) && append? && not Enum.empty?(ext_candidates) ->
+ join.(Enum.join([basename, List.first(ext_candidates)], "."))
- # no extension, append
match?("", old_ext) && append? ->
- Enum.join([basename, List.first(ext_candidates)], ".")
+ name
- # no candidates, so strip extension
match?([], ext_candidates) ->
- basename
+ join.(basename)
- # no extension but no appending, so no-op
match?("", old_ext) ->
name
- # append first candidate
not Enum.empty?(ext_candidates) && append? ->
- Enum.join([name, List.first(ext_candidates)], ".")
+ join.(Enum.join([full_basename, List.first(ext_candidates)], "."))
- # change extension to first candidate
not Enum.empty?(ext_candidates) ->
- Enum.join([basename, List.first(ext_candidates)], ".")
+ join.(Enum.join([basename, List.first(ext_candidates)], "."))
- # do nothing
true ->
name
end
end
defp subtype_extension(true, type) do
[_type, sub] = String.split(type, "/", parts: 2)
[sub]
end
defp subtype_extension(_, _), do: []
end
diff --git a/test/majic/extension_test.exs b/test/majic/extension_test.exs
index be9c644..20468df 100644
--- a/test/majic/extension_test.exs
+++ b/test/majic/extension_test.exs
@@ -1,41 +1,60 @@
defmodule Majic.ExtensionTest do
use ExUnit.Case
alias Majic.Extension
test "it fixes extensions" do
assert "Makefile" == Extension.fix("Makefile.txt", "text/x-makefile")
assert "cat.webp" == Extension.fix("cat.jpeg", "image/webp")
end
test "it appends extensions" do
assert "Makefile" == Extension.fix("Makefile.txt", "text/x-makefile", append: true)
assert "cat.jpeg.webp" == Extension.fix("cat.jpeg", "image/webp", append: true)
end
test "it appends extensions if none exist" do
assert "webpage.html" == Extension.fix("webpage", "text/html", append: true)
end
test "it does not append extension if none exist when appending not requested" do
assert "webpage" == Extension.fix("webpage", "text/html")
end
test "it uses subtype as extension" do
assert "Makefile.x-makefile" ==
Extension.fix("Makefile.txt", "text/x-makefile", subtype_as_extension: true)
assert "cat.webp" == Extension.fix("cat.jpeg", "image/webp", subtype_as_extension: true)
end
test "it appends and use subtype" do
assert "Makefile.txt.x-makefile" ==
Extension.fix("Makefile.txt", "text/x-makefile",
subtype_as_extension: true,
append: true
)
assert "cat.jpeg.webp" ==
Extension.fix("cat.jpeg", "image/webp", subtype_as_extension: true, append: true)
end
+
+ test "preserves directory path" do
+ assert "dir/cat.webp" == Extension.fix("dir/cat.jpeg", "image/webp")
+ assert "dir/sub/cat.webp" == Extension.fix("dir/sub/cat.jpeg", "image/webp")
+ end
+
+ test "handles uppercase extensions" do
+ assert "cat.webp" == Extension.fix("cat.JPEG", "image/webp")
+ assert "cat.webp" == Extension.fix("cat.Jpg", "image/webp")
+ end
+
+ test "no trailing dot when no extension candidates exist" do
+ assert "Makefile" == Extension.fix("Makefile.txt", "text/x-makefile")
+ assert "cat" == Extension.fix("cat.txt", "text/x-makefile")
+ end
+
+ test "preserves directory path with append" do
+ assert "dir/cat.jpeg.webp" == Extension.fix("dir/cat.jpeg", "image/webp", append: true)
+ end
end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Aug 8, 5:05 AM (14 h, 6 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1722908
Default Alt Text
(6 KB)

Event Timeline