View Source SimpleStruct (SimpleStruct v0.1.0)

SimpleStruct is a library to create structs in a concise way.

This is not meant as a replacement of Elixir's defstruct. In fact, it uses it. It's meant to be used as a way to make it easier to define several structs inside a module.

And if your struct needs to "graduate" at some point, you can easily extract it and expand it.

Example

Take an example where you want to define a bunch of events in your application.

Ideally, you want each event to be a struct. That is our first-class data structure in Elixir, and it allows things like safety when constructing it and better pattern matching.

You have 2 options:

  1. You have an explosion of files, each with a simple defmodule + defstruct in it, OR
  2. You have a really large module with tons of nested modules!

Both seem overkill for different reasons. So, maybe you take secret option (3) and you don't make them into structs! :(

With SimpleStruct, it's simple.

Just import SimpleStruct and define all the structs you want in one place:

defmodule MyApp.Events do
  import SimpleStruct

  defdata UserLoggedIn, [:user_id, action: "logged in"]
  defdata OrderPlaced, [:user_id, :order_id, required: true]
  defdata OrderCancelled, [:user_id, :order_id, required: [:order_id]]
end

Summary

Functions

Creates a module and defines a struct inside it with then given fields.

Functions

Link to this macro

defdata(name, fields, opts \\ [])

View Source (macro)

Creates a module and defines a struct inside it with then given fields.

Options

  • required: defaults to empty. You can pass a list of keys that are required or true to require all keys.

Examples

defmodule MyApp.Events do
  import SimpleStruct

  defdata UserLoggedIn, [:user_id, action: "logged in"]
  defdata OrderPlaced, [:user_id, :order_id, required: true]
  defdata OrderCancelled, [:user_id, :order_id, required: [:order_id]]
end

That will create three structs: %Myapp.Events.UserLoggedIn{}, %Myapp.Events.OrderPlaced{}, and %Myapp.Events.OrderCancelled{}.

  • UserLoggedIn will have a default action of "logged in",
  • OrderPlaced will enforce that both :user_id and :order_id keys are provided when creating the struct, and
  • OrderCancelled will only enforce :order_id

In addition, all modules will have a new/1 helper function that can be used to create the structs by passing keyword lists.

UserLoggedIn.new(user_id: 1)
# => %Myapp.Events.UserLoggedIn{user_id: 1, action: "logged in"}

In other words, it's the equivalent of doing this:

defmodule MyApp.Events do
  defmodule UserLoggedIn do
    defstruct [:user_id, action: "logged in"]

    def new(attrs) do
      struct!(__MODULE__, attrs)
    end
  end

  defmodule OrderPlaced  do
    @enforce_keys [:user_id, :order_id]
    defstruct [:user_id, :order_id]

    def new(attrs) do
      struct!(__MODULE__, attrs)
    end
  end

  defmodule OrderCancelled do
    @enforce_keys [:order_id]
    defstruct [:user_id, :order_id]

    def new(attrs) do
      struct!(__MODULE__, attrs)
    end
  end
end