Skip to content

Commit

Permalink
🌅
Browse files Browse the repository at this point in the history
  • Loading branch information
naps62 committed Jun 23, 2020
0 parents commit 041ead0
Show file tree
Hide file tree
Showing 10 changed files with 155 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}"]
]
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 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").
fsmx-*.tar

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

**TODO: Add description**

## Installation

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

```elixir
def deps do
[
{:fsmx, "~> 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/fsmx](https://hexdocs.pm/fsmx).

23 changes: 23 additions & 0 deletions lib/fsmx.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
defmodule Fsmx do
@type state_t :: binary

def transition(%mod{state: state} = struct, new_state) do
transitions = mod.__fsmx__(:transitions)

if valid_transition?(state, new_state, transitions) do
{:ok, %{struct | state: new_state}}
else
{:error, "invalid transition of #{mod} from #{state} to #{new_state}"}
end
end

defp valid_transition?(state, new_state, transitions) do
transitions
|> Map.get(state, [])
|> is_or_contains?(new_state)
end

defp is_or_contains?(state, state), do: true
defp is_or_contains?(states, state) when is_list(states), do: Enum.member?(states, state)
defp is_or_contains?(_, _), do: false
end
7 changes: 7 additions & 0 deletions lib/fsmx/struct.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule Fsmx.Struct do
defmacro __using__(opts) do
quote do
def __fsmx__(:transitions), do: Keyword.fetch!(unquote(opts), :transitions)
end
end
end
28 changes: 28 additions & 0 deletions mix.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule Fsmx.MixProject do
use Mix.Project

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

# Run "mix help compile.app" to learn about applications.
def application do
[
extra_applications: [:logger]
]
end

defp deps do
[]
end

defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
end
33 changes: 33 additions & 0 deletions test/fsmx_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
defmodule FsmxTest do
use ExUnit.Case
doctest Fsmx

alias Fsmx.TestStructs.{Simple, WithCallbacks}

describe "transition/2" do
test "can do simple transitions" do
one = %Simple{state: "1"}

{:ok, two} = Fsmx.transition(one, "2")

assert %Simple{state: "2"} = two

{:ok, three} = Fsmx.transition(two, "3")

assert %Simple{state: "3"} = three
end

test "fails to perform invalid transitions" do
one = %Simple{state: "1"}

assert {:error, msg} = Fsmx.transition(one, "3")

assert msg == "invalid transition of Elixir.Fsmx.TestStructs.Simple from 1 to 3"
end
end

describe "transition/2 with callbacks" do
test "calls before_transition/2 on struct" do
end
end
end
5 changes: 5 additions & 0 deletions test/support/test_structs/simple.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
defmodule Fsmx.TestStructs.Simple do
defstruct [:state]

use Fsmx.Struct, transitions: %{"1" => ["2"], "2" => ["3"]}
end
9 changes: 9 additions & 0 deletions test/support/test_structs/with_callbacks.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule Fsmx.TestStructs.WithCallbacks do
defstruct [:state]

use Fsmx.Struct, transitions: %{"1" => ["2"], "2" => ["3"]}

def before_transition(struct, state) do
IO.inspect(struct, state)
end
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 041ead0

Please sign in to comment.