 
   import Serum.Payload
   import Serum.Util
-
-  @type dirname   :: binary
-  @type ok_result :: {:ok, dirname}
+  alias Serum.Error
 
   @doc """
   Initializes a new Serum project into the given directory `dir`.

    |> Enum.each(fn k ->
      fwrite "#{dir}includes/#{k}.html.eex", include(k)
    end)
    IO.puts "Generated includes into `#{dir}includes/`."
    {:ok, dir}
  end

  # Generates the initial `.gitignore` file.
  @spec init_gitignore(ok_result) :: ok_result
  defp init_gitignore({:ok, dir}) do
    fwrite "#{dir}.gitignore", "site\n"
    IO.puts "Generated `#{dir}.gitignore`."
    {:ok, dir}
  end
end

  **NOTE:** If the directory `dir` is not empty, some contents in that
  directory may be overwritten *without a question*.
  """
  @spec init(binary) :: Error.result

  def init(dir) do
    dir = if String.ends_with?(dir, "/"), do: dir, else: dir <> "/"

    with :ok <- check_dir(dir),
         :ok <- create_dir(dir)
    do
      create_info dir
      create_index dir
      create_templates dir
      create_gitignore dir
      finish dir
    else
      {:error, _, _} = error ->
        Error.show error
        IO.puts """

        Could not initialize a new project.
        Make sure the target directory is writable.
        """
    end
  end

  # Checks if the specified directory already exists.
  # Prints a warning message if so.
  @spec check_dir(binary) :: Error.result

  defp check_dir(dir) do
    if File.exists? dir do
      warn "The directory `#{dir}` already exists and might not be empty."
    end
    :ok
  end

  # Creates necessary directory structure under the specified directory.
  @spec create_dir(binary) :: Error.result

  defp create_dir(dir) do
    dirs =
      ["posts", "pages", "media", "templates", "includes",
       "assets/css", "assets/js", "assets/images"]
    mkdir_result =
      dirs
      |> Enum.map(fn x ->
        dirname = dir <> x
        {dirname, File.mkdir_p(dirname)}
      end)
    case Enum.reject(mkdir_result, fn {_, x} -> x == :ok end) do
      [] ->
        Enum.each mkdir_result, fn {dirname, _} ->
          IO.puts "Created directory `#{dirname}`."
        end
        :ok
      [{dirname, {:error, reason}}|_] ->
        {:error, :file_error, {reason, dirname, 0}}
    end
  end

  # Generates default project metadata files.
  @spec create_info(binary) :: :ok

  defp create_info(dir) do
    projinfo =
      %{site_name: "New Website",
        site_description: "Welcome to my website!",
