Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85629908
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
6 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Aug 9, 7:01 AM (1 d, 15 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1722908
Default Alt Text
(6 KB)
Attached To
Mode
R20 majic
Attached
Detach File
Event Timeline
Log In to Comment