defmodule Serum.Project do
@moduledoc """
This module defines a struct for storing Serum project metadata.
"""
import Serum.IOProxy, only: [put_err: 2]
alias Serum.Plugin
alias Serum.Theme
@default_date_format "{YYYY}-{0M}-{0D}"
@default_list_title_tag "Posts Tagged ~s"
@default_posts_source "posts"
defstruct site_name: "",
site_description: "",
server_root: "",
base_url: "",
author: "",
author_email: "",
date_format: @default_date_format,
list_title_all: "All Posts",
list_title_tag: @default_list_title_tag,
pagination: false,
posts_per_page: 5,
preview_length: 200,
posts_source: @default_posts_source,
posts_path: @default_posts_source,
tags_path: "tags",
src: nil,
dest: nil,
plugins: [],
theme: %Theme{module: nil},
pretty_urls: false
@type t :: %__MODULE__{
src: binary(),
dest: binary(),
site_name: binary(),
site_description: binary(),
server_root: binary(),
base_url: binary(),
author: binary(),
author_email: binary(),
date_format: binary(),
list_title_all: binary(),
list_title_tag: binary(),
pagination: boolean(),
posts_per_page: pos_integer(),
preview_length: non_neg_integer(),
posts_source: binary(),
posts_path: binary(),
tags_path: binary(),
plugins: [Plugin.plugin_spec()],
theme: Theme.t(),
pretty_urls: pretty_urls()
}
@typedoc """
Accepted value for the `pretty_urls` option
- `false` disables pretty URLs.
- `true` is currently the same as `:posts`.
- `:posts` enables pretty URLs only for blog posts.
"""
@type pretty_urls() :: boolean() | :posts
@spec default_date_format() :: binary()
def default_date_format, do: @default_date_format
@spec default_list_title_tag() :: binary()
def default_list_title_tag, do: @default_list_title_tag
@doc "Creates a new Project struct using the given `map`."
@spec new(map()) :: t()
def new(map) do
checked_map =
map
|> check_date_format()
|> check_list_title_format()
|> set_default_posts_path()
struct(__MODULE__, checked_map)
end
@spec check_date_format(map()) :: map()
defp check_date_format(map) do
case map[:date_format] do
nil ->
map
fmt when is_binary(fmt) ->
case Timex.validate_format(fmt) do
:ok ->
map
{:error, message} ->
msg = """
Invalid date format string `date_format`:
#{message}
The default format string will be used instead.
"""
put_err(:warn, String.trim(msg))
Map.delete(map, :date_format)
end
end
end
@spec check_list_title_format(map()) :: map()
defp check_list_title_format(map) do
case map[:list_title_tag] do
nil ->
map
fmt when is_binary(fmt) ->
:io_lib.format(fmt, ["test"])
map
end
rescue
ArgumentError ->
msg = """
Invalid post list title format string `list_title_tag`.
The default format string will be used instead.
"""
put_err(:warn, String.trim(msg))
Map.delete(map, :list_title_tag)
end
@spec set_default_posts_path(map()) :: map()
defp set_default_posts_path(map) do
case map[:posts_path] do
posts_path when is_binary(posts_path) -> map
_ -> Map.put(map, :posts_path, map[:posts_source] || @default_posts_source)
end
end
end