Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
defmodule Estate do
defmacro machine(column_name, events) do
Enum.each(events, fn ({event_name, transitions}) ->
quote do
Enum.each(unquote(transitions), fn ({from, to}) ->
def unquote(:"before_#{event_name}")(%{unquote(column_name) => from} = record) do
record
end
def unquote(:"after_#{event_name}")(%{unquote(column_name) => to} = record) do
record
end
def unquote(event_name)(%{unquote(column_name) => from} = record) do
record
|> unquote(:"before_#{event_name}")()
|> __MODULE__.changset(%{unquote(column_name) => to})
|> unquote(:"after_#{event_name}")()
end
end)
end
end)
end
end
defmodule Poutineer.Models.Review do
import Estate, only: [machine: 2]
machine(:moderation_state,
approve: [draft: :published],
reject: [draft: :rejected],
kill: [published: :killed],
archive: [published: :archived]
)
end
iex(1)> Poutineer.Models.Review.approve(%{:moderation_state => "draft"})
** (UndefinedFunctionError) function Poutineer.Models.Review.approve/1 is undefined or private
(poutineer) Poutineer.Models.Review.approve(%{moderation_state: "draft"})
@kipcole9

This comment has been minimized.

Copy link

kipcole9 commented Dec 31, 2019

Just in case, here's a version that does what I think you intend:

defmodule Estate do
  defmacro machine(column_name, events) do
    Enum.map(events, fn ({event_name, transitions}) ->
      Enum.map(transitions, fn ({from, to}) ->
        quote do
          def unquote(:"before_#{event_name}")(%{unquote(column_name) => unquote(from)} = record) do
            record
          end

          def unquote(:"after_#{event_name}")(%{unquote(column_name) => unquote(to)} = record) do
            record
          end

          def unquote(event_name)(%{unquote(column_name) => unquote(from)} = record) do
            record
              |>  unquote(:"before_#{event_name}")()
              |> __MODULE__.changeset(%{unquote(column_name) => unquote(to)})
              |>  unquote(:"after_#{event_name}")()
          end
        end
      end)
    end)
  end
end
@kipcole9

This comment has been minimized.

Copy link

kipcole9 commented Dec 31, 2019

You might also consider get_statem which is built into OTP. And there is a new lib called StatesLanguage that makes declaring state machines very cool.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.