Skip to content

Reduce boilerplate by generating struct new and put functions, and validate your structs when they are created and updated.

Notifications You must be signed in to change notification settings

dylan-chong/ex_structable

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

93 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ExStructable

Build Status Coverage Status

Reduce boilerplate by generating struct new and put functions, and validate your structs when they are created and updated.

Optionally uses ExConstructor to "make it easier to instantiate struts from external data".

Installation

The package can be installed by adding ex_structable to your list of dependencies in mix.exs:

def deps do
  [
    {:ex_structable, "~> 0.3.0"},
  ]
end

The Problem

If you want to write some validation for your struct, you need to write the boilerplate new and put methods manually.

defmodule Point do
  @enforce_keys [:x, :y]
  defstruct [:x, :y, :z]

  def new(args) do
    args = Keyword.new(args)

    __MODULE__
    |> Kernel.struct!(args)
    |> validate_struct()
  end

  def put(struct, args) do
    args = Keyword.new(args)

    struct
    |> Kernel.struct!(args)
    |> validate_struct()
  end

  def validate_struct(struct) do
    if struct.x < 0 or struct.y < 0 or struct.z < 0 do
      raise ArgumentError
    end

    struct
  end
end

Point.new(x: 1, y: 2)
# => %Point{x: 1, y: 2, z: nil}
Point.new(x: -1, y: 2)
# Fails validation, as expected

And you have to write this boilerplate for every module you have! That can be a lot of boilerplate!

A Solution

By the magic of Elixir macros, we can remove the boilerplate!

defmodule Point do
  @enforce_keys [:x, :y]
  defstruct [:x, :y, :z]

  use ExStructable # Adds `new` and `put` dynamically

  # Optional hook
  @impl true
  def validate_struct(struct, _options) do
    if struct.x < 0 or struct.y < 0 or struct.z < 0 do
      raise ArgumentError
    end

    struct
  end
end

Point.new(x: 1, y: 2)
# => %Point{x: 1, y: 2, z: nil} # Still works!
Point.new(x: -1, y: 2)
# Fails validation, as expected

And if you don't need validation yet, you might want to still add new and put methods to be consistent (or to make it easier to add validation later). In that case, you can just leave out the validate_struct/2 implementation.

defmodule Point do
  @enforce_keys [:x, :y]
  defstruct [:x, :y, :z]

  use ExStructable # Adds `new` and `put` dynamically
end

More Info

For more detailed API documentation, see HexDocs.

Contributing

Pull requests are welcomed! Please do discuss suggestions in an issue before implementing them.

Making a new release

  1. git checkout master
  2. Make sure tests pass mix test
  3. Update version in mix.exs
  4. Ensure your user has been registered mix hex.user register
  5. Run mix hex.publish (see for more information https://hex.pm/docs/publish)
  6. git tag <VERSION>
  7. git push origin <VERSION>

About

Reduce boilerplate by generating struct new and put functions, and validate your structs when they are created and updated.

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages