diff --git a/.credo.exs b/.credo.exs new file mode 100644 index 0000000..a6c4b79 --- /dev/null +++ b/.credo.exs @@ -0,0 +1,15 @@ +%{ + configs: [ + %{ + name: "default", + files: %{ + included: ["lib/", "test/", "config/"], + excluded: [] + }, + checks: [ + {Credo.Check.Refactor.MapInto, false}, + {Credo.Check.Warning.LazyLogging, false} + ] + } + ] +} diff --git a/Makefile b/Makefile index 91ef65e..52abdaa 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,17 @@ -.PHONY: all build clean install start test +.PHONY: all build clean install lint start test -build: install test clean +build: install lint test clean docker build -t shortnr:latest . clean: - mix clean --deps + mix clean install: mix deps.get -install-prod: - mix deps.get --only prod +lint: + mix dialyzer + mix credo --strict start: iex -S mix run --no-halt diff --git a/config/config.exs b/config/config.exs index 0a76b38..f875974 100644 --- a/config/config.exs +++ b/config/config.exs @@ -16,3 +16,9 @@ config :logger, :console, :prod -> :info _ -> :debug end).(Mix.env()) + +config :credo, + checks: [ + {Credo.Check.Refactor.MapInto, false}, + {Credo.Check.Warning.LazyLogging, false} + ] diff --git a/lib/router.ex b/lib/router.ex index e62c785..5becef8 100644 --- a/lib/router.ex +++ b/lib/router.ex @@ -1,10 +1,14 @@ defmodule Shortnr.Router do + @moduledoc """ + This module contains the Router for the Shortnr application. Do not import, other than + Application entry. + """ use Plug.ErrorHandler use Plug.Router require Logger - alias Shortnr.Transport.{Text, HTTP} + alias Shortnr.Transport.{HTTP, Text} alias Shortnr.URL plug(Plug.Logger, log: :debug) diff --git a/lib/shortnr.ex b/lib/shortnr.ex index 96257d1..5ebb732 100644 --- a/lib/shortnr.ex +++ b/lib/shortnr.ex @@ -1,6 +1,6 @@ defmodule Shortnr do @moduledoc """ - Documentation for Shortnr. + The Shortnr application entry point. Check README for usage documenation. """ use Application diff --git a/lib/transport/http.ex b/lib/transport/http.ex index f976db4..aa81d69 100644 --- a/lib/transport/http.ex +++ b/lib/transport/http.ex @@ -1,8 +1,13 @@ defmodule Shortnr.Transport.HTTP do + @moduledoc """ + This module contains functions that can be used to handle HTTP requests and send responses, by + manipulating Plug.Conn. + """ + import Plug.Conn - @type ok_error :: {:ok, term(), Plug.Conn.t()} | error() @type error :: {:error, {atom(), String.t()}, Plug.Conn.t()} + @type ok_error :: {:ok, term(), Plug.Conn.t()} | error() @spec handle(ok_error(), (... -> ok_error())) :: ok_error() def handle(error = {:error, _sub_error, _conn}, _func), do: error diff --git a/lib/transport/json.ex b/lib/transport/json.ex deleted file mode 100644 index cfcd704..0000000 --- a/lib/transport/json.ex +++ /dev/null @@ -1,28 +0,0 @@ -defmodule Shortnr.Transport.Json do - import Plug.Conn - alias Shortnr.Transport.HTTP - - @spec decode_request(Plug.Conn.t(), module()) :: HTTP.ok_error() - def decode_request(conn, struct_module) do - {:ok, body, conn} = read_body(conn) - {:ok, params} = Jason.decode(body) - - params_list = - params - |> Map.to_list() - |> Enum.map(fn {key, value} -> {String.to_atom(key), value} end) - - {:ok, struct(struct_module, params_list), conn} - end - - @spec encode_response(HTTP.ok_error()) :: HTTP.ok_error() - def encode_response({:error, {status, response}, conn}) do - {:ok, json_body} = Jason.encode(%{data: response}) - {:error, {status, json_body}, conn} - end - - def encode_response({:ok, response, conn}) do - {:ok, json_body} = Jason.encode(%{data: response}) - {:ok, json_body, conn} - end -end diff --git a/lib/transport/text.ex b/lib/transport/text.ex index dd00f01..4ce481f 100644 --- a/lib/transport/text.ex +++ b/lib/transport/text.ex @@ -1,4 +1,8 @@ defmodule Shortnr.Transport.Text do + @moduledoc """ + This modules contains functions to decode and encode text formatted http requests and responses. + """ + import Plug.Conn alias Shortnr.Transport.HTTP alias Shortnr.URL diff --git a/lib/transport/transport.ex b/lib/transport/transport.ex index c890166..34665f5 100644 --- a/lib/transport/transport.ex +++ b/lib/transport/transport.ex @@ -1,4 +1,7 @@ defmodule Shortnr.Transport do + @moduledoc """ + This module houses generic Transport types. + """ @type error :: {:error, {atom(), String.t()}} @type ok_error :: {:ok, term()} | error() end diff --git a/lib/url/repo/ets.ex b/lib/url/repo/ets.ex index 9820eb6..ec5bf1b 100644 --- a/lib/url/repo/ets.ex +++ b/lib/url/repo/ets.ex @@ -1,4 +1,8 @@ defmodule Shortnr.URL.Repo.ETS do + @moduledoc """ + This module is an implemention of the Repo behaviour using the Erlang ETS library. + """ + @behaviour Shortnr.URL.Repo @impl true @@ -16,7 +20,7 @@ defmodule Shortnr.URL.Repo.ETS do end @impl true - def list() do + def list do resp = ets().select(:urls, [{:"$1", [], [:"$1"]}]) {:ok, resp |> Enum.map(&elem(&1, 1))} end diff --git a/lib/url/repo/repo.ex b/lib/url/repo/repo.ex index c77d46c..598cbe3 100644 --- a/lib/url/repo/repo.ex +++ b/lib/url/repo/repo.ex @@ -1,6 +1,11 @@ defmodule Shortnr.URL.Repo do - alias Shortnr.URL + @moduledoc """ + This module defines the Repo behaviour for the URL service. All Repos must implement this + entire behaviour. + """ + alias Shortnr.Transport + alias Shortnr.URL @callback put(URL.t()) :: :ok | Transport.error() @callback get(String.t()) :: {:ok, URL.t()} | Transport.error() diff --git a/lib/url/url.ex b/lib/url/url.ex index 47730f3..a74ed93 100644 --- a/lib/url/url.ex +++ b/lib/url/url.ex @@ -1,6 +1,9 @@ defmodule Shortnr.URL do + @moduledoc """ + This module represents both the URL data object, in the form of a struct, and the URL business + domain service. + """ alias Shortnr.Transport - alias Shortnr.URL alias Shortnr.URL.Util defstruct id: "", @@ -17,7 +20,7 @@ defmodule Shortnr.URL do @spec create(String.t(), module()) :: {:ok, String.t()} | Transport.error() def create(url, repo) do - url_struct = %URL{id: Util.gen_id(), url: URI.parse(url)} + url_struct = %__MODULE__{id: Util.gen_id(), url: URI.parse(url)} {:ok, extant_url} = repo.get(url_struct.id) @@ -29,17 +32,17 @@ defmodule Shortnr.URL do end end - @spec get(String.t(), module()) :: {:ok, URL.t()} | Transport.error() + @spec get(String.t(), module()) :: {:ok, t()} | Transport.error() def get(key, repo) do {:ok, _} = repo.get(key) end - @spec list(module()) :: {:ok, list(URL.t())} | Transport.error() + @spec list(module()) :: {:ok, list(t())} | Transport.error() def list(repo) do {:ok, _} = repo.list end - @spec delete(String.t(), module()) :: {:ok, :ignore} | Tranpsport.error() + @spec delete(String.t(), module()) :: {:ok, String.t()} | Transport.error() def delete(key, repo) do :ok = repo.delete(key) {:ok, "Success"} diff --git a/lib/url/util.ex b/lib/url/util.ex index 8919e9e..73fd350 100644 --- a/lib/url/util.ex +++ b/lib/url/util.ex @@ -1,4 +1,7 @@ defmodule Shortnr.URL.Util do + @moduledoc """ + URL module utility functions. + """ @id_chars String.codepoints("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXWYZ0123456789") @spec gen_id() :: String.t() def gen_id do diff --git a/mix.exs b/mix.exs index 558b2db..c0f5ba1 100644 --- a/mix.exs +++ b/mix.exs @@ -24,7 +24,9 @@ defmodule Shortnr.MixProject do [ {:plug_cowboy, "~> 2.0"}, {:elixir_uuid, "~> 1.2"}, - {:jason, "~> 1.1"} + {:jason, "~> 1.1"}, + {:dialyxir, "~> 0.5.1", only: [:dev], runtime: false}, + {:credo, "~> 1.1.5", only: [:dev, :test], runtime: false} # {:dep_from_hexpm, "~> 0.3.0"}, # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"} ] diff --git a/mix.lock b/mix.lock index 5daf03f..87e63d8 100644 --- a/mix.lock +++ b/mix.lock @@ -1,6 +1,9 @@ %{ + "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, "cowboy": {:hex, :cowboy, "2.7.0", "91ed100138a764355f43316b1d23d7ff6bdb0de4ea618cb5d8677c93a7a2f115", [:rebar3], [{:cowlib, "~> 2.8.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm"}, "cowlib": {:hex, :cowlib, "2.8.0", "fd0ff1787db84ac415b8211573e9a30a3ebe71b5cbff7f720089972b2319c8a4", [:rebar3], [], "hexpm"}, + "credo": {:hex, :credo, "1.1.5", "caec7a3cadd2e58609d7ee25b3931b129e739e070539ad1a0cd7efeeb47014f4", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, + "dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm"}, "elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm"}, "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},