Last active
May 23, 2017 15:36
-
-
Save Arkham/bc0e4c13d9035049e021ad3a9289a750 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Enchainer.Command do | |
@callback do_call(term) :: {:ok, term} | {:error, term} | |
@callback on_success(term, term) :: term | |
@callback on_failure(term, term) :: term | |
@callback on_revert(term) :: term | |
defmacro __using__(_params) do | |
quote do | |
@behaviour Enchainer.Command | |
def call(context) do | |
case do_call(context) do | |
{:ok, value} -> on_success(value, context) | |
{:error, reason} -> on_failure(reason, context) | |
{:revert, reason} -> {:revert, reason} | |
end | |
end | |
def do_call(context) do | |
{:ok, :success} | |
end | |
def on_success(_value, context) do | |
context | |
end | |
def on_failure(_reason, context) do | |
context | |
end | |
def on_revert(context) do | |
context | |
end | |
defoverridable [call: 1, do_call: 1, on_success: 2, on_failure: 2, on_revert: 1] | |
end | |
end | |
end | |
defmodule First do | |
use Enchainer.Command | |
def do_call(_context), do: {:ok, true} | |
def on_success(_result, context) do | |
IO.puts "First succeeded" | |
context | |
end | |
def on_failure(_reason, context) do | |
IO.puts "First failed" | |
context | |
end | |
def on_revert(context) do | |
IO.puts "First reverted" | |
context | |
end | |
end | |
defmodule Second do | |
use Enchainer.Command | |
def do_call(_context), do: {:error, :unknown} | |
def on_success(_result, context) do | |
IO.puts "Second succeeded" | |
context | |
end | |
def on_failure(reason, context) do | |
IO.puts "Second failed" | |
Map.put(context, :reason, reason) | |
end | |
def on_revert(context) do | |
IO.puts "Second reverted" | |
context | |
end | |
end | |
defmodule Enchainer do | |
def chain(commands) do | |
initial_state = %{context: %{}, processed: []} | |
final_state = Enum.reduce_while(commands, initial_state, fn(command, state) -> | |
%{context: context, processed: processed} = state | |
case command.call(context) do | |
{:revert, _reason} -> {:halt, state} | |
result -> {:cont, %{result | processed: [command|processed]}} | |
end | |
end) | |
case final_state do | |
%{context: context, processed: ^commands} -> context | |
%{context: initial_context, processed: processed} -> Enum.reduce(processed, initial_context, fn command, context -> | |
command.on_revert(context) | |
end) | |
end | |
end | |
def test do | |
chain([First, Second]) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment