Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
hpopp committed Jan 13, 2020
0 parents commit c9c8353
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .formatter.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]
25 changes: 25 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# The directory Mix will write compiled artifacts to.
/_build/

# If you run "mix test --cover", coverage assets end up here.
/cover/

# The directory Mix downloads your dependencies sources to.
/deps/

# Where third-party dependencies like ExDoc output generated docs.
/doc/

# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch

# If the VM crashes, it generates a dump, let's ignore it too.
erl_crash.dump

# Also ignore archive artifacts (built via "mix archive.build").
*.ez

# Ignore package tarball (built via "mix hex.build").
commandex-*.tar

.iex.exs
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Commandex

**TODO: Add description**

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `commandex` to your list of dependencies in `mix.exs`:

```elixir
def deps do
[
{:commandex, "~> 0.1.0"}
]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at [https://hexdocs.pm/commandex](https://hexdocs.pm/commandex).

81 changes: 81 additions & 0 deletions lib/commandex.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
defmodule Commandex do
@moduledoc """
Documentation for Commandex.
"""

@doc false
defmacro __using__(_opts) do
prelude =
quote do
# @after_compile Commandex
Module.register_attribute(__MODULE__, :struct_fields, accumulate: true)
Module.put_attribute(__MODULE__, :struct_fields, {:success, false})
Module.put_attribute(__MODULE__, :struct_fields, {:error, nil})
Module.put_attribute(__MODULE__, :struct_fields, {:halted, false})
end

postlude =
quote unquote: false do
params = for key <- Module.get_attribute(__MODULE__, :params), into: %{}, do: {key, nil}
data = for key <- Module.get_attribute(__MODULE__, :data), into: %{}, do: {key, nil}

Module.put_attribute(__MODULE__, :struct_fields, {:params, params})
Module.put_attribute(__MODULE__, :struct_fields, {:data, data})
defstruct @struct_fields
import Commandex
end

quote do
unquote(prelude)
unquote(postlude)

def new(opts) do
Commandex.parse_params(%__MODULE__{}, opts)
end

def run(command) do
pipeline()
|> Enum.reduce_while(command, fn fun, acc ->
case acc do
%{halted: false} -> {:cont, fun.(acc, acc.params, acc.data)}
_ -> {:halt, acc}
end
end)
|> Commandex.maybe_mark_successful()
end
end
end

def maybe_mark_successful(%{halted: false} = command), do: %{command | success: true}
def maybe_mark_successful(command), do: command

@doc false
def parse_params(%{params: p} = struct, params) when is_list(params) do
params = for {key, _} <- p, into: %{}, do: {key, Keyword.get(params, key)}
%{struct | params: params}
end

def parse_params(%{params: p} = struct, %{} = params) do
params = for {key, _} <- p, into: %{}, do: {key, get_param(params, key)}
%{struct | params: params}
end

defp get_param(params, key) do
case Map.get(params, key) do
nil -> Map.get(params, to_string(key))
val -> val
end
end

def put_data(%{data: data} = command, key, val) do
%{command | data: Map.put(data, key, val)}
end

def put_error(command, error) do
%{command | error: error}
end

def halt(command) do
%{command | halted: true}
end
end
27 changes: 27 additions & 0 deletions lib/register_user.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
defmodule Commandex.RegisterUser do
@params ~w(email password)a
@data ~w(user auth)a

use Commandex

def pipeline do
[
&create_user/3,
&record_auth_attempt/3
]
end

def create_user(command, %{password: nil} = _params, data) do
command
|> put_error(:no_password)
|> halt()
end

def create_user(command, %{email: email} = _params, data) do
put_data(command, :user, %{email: email})
end

def record_auth_attempt(command, _params, _data) do
put_data(command, :auth, true)
end
end
21 changes: 21 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
defmodule Commandex.MixProject do
use Mix.Project

@version "0.1.0"

def project do
[
app: :commandex,
deps: [],
elixir: "~> 1.9",
start_permanent: Mix.env() == :prod,
version: @version
]
end

def application do
[
extra_applications: [:logger]
]
end
end
4 changes: 4 additions & 0 deletions test/commandex_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
defmodule CommandexTest do
use ExUnit.Case
doctest Commandex
end
1 change: 1 addition & 0 deletions test/test_helper.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ExUnit.start()

0 comments on commit c9c8353

Please sign in to comment.