MapBot v1.3.0 MapBot View Source

Elixir.MapBot builds Elixir Maps/Structs based on factory definitions and attributes.

Let's see how to use this library by examples:

Examples setup:

defmodule MyApp.Car do
  @moduledoc false
  defstruct id: nil, color: nil, model: nil
end

defmodule MyApp.House do
  @moduledoc false
  defstruct id: nil, color: nil, style: nil

  def changeset(%__MODULE__{} = schema, attrs) do
    Map.merge(schema, attrs)
  end
end

defmodule MyApp.Repo do
  @moduledoc false
  def insert(schema), do: {:ok, schema}
  def insert!(schema), do: schema
end

defmodule MyApp.FactoryWithNoRepo do
  @moduledoc false
  use MapBot

  deffactory(MyApp.Car) do
    %MyApp.Car{
      id: & &1,
      color: color(),
      model: ~w(Truck SUV Hatch) |> Enum.random()
    }
  end

  deffactory(:tomato) do
    %{
      name: &"Tomato-#{&1}",
      color: color()
    }
  end

  defp color(), do: ~w(red white black blue green)a |> Enum.random()
end

defmodule MyApp.FactoryWithRepo do
  @moduledoc false
  use MapBot, repo: MyApp.Repo

  deffactory(MyApp.Car) do
    %MyApp.Car{
      id: & &1,
      color: color(),
      model: ~w(Truck SUV Hatch) |> Enum.random()
    }
  end

  defp color(), do: ~w(red white black blue green)a |> Enum.random()
end

defmodule MyApp.FactoryWithRepoAndChangeset do
  @moduledoc false
  use MapBot, repo: MyApp.Repo, changeset: true

  deffactory(MyApp.House) do
    %MyApp.House{
      id: & &1,
      color: color(),
      style: ~w(Asian Mediterranean Colonial American Modern) |> Enum.random()
    }
  end

  defp color(), do: ~w(red white black blue green)a |> Enum.random()
end

Examples

attrs/2:

iex> Elixir.MapBot.Sequence.reset(5)
iex> :rand.seed(:exsplus, {1, 2, 3})
...>
iex> MyApp.FactoryWithNoRepo.attrs(MyApp.Car)
%{id: 5, model: "Truck", color: :green}
...>
iex> MyApp.FactoryWithNoRepo.attrs(MyApp.Car, color: :yellow)
%{id: 6, model: "Hatch", color: :yellow}
...>
iex> MyApp.FactoryWithNoRepo.attrs(MyApp.Car, %{color: :purple})
%{id: 7, model: "Hatch", color: :purple}
...>
iex> MyApp.FactoryWithNoRepo.attrs(:tomato)
%{name: "Tomato-8", color: :blue}
...>
iex> MyApp.FactoryWithNoRepo.attrs(:tomato, color: :white)
%{name: "Tomato-9", color: :white}
...>
iex> MyApp.FactoryWithNoRepo.attrs(:tomato, %{color: :pink})
%{name: "Tomato-10", color: :pink}

build/2:

iex> Elixir.MapBot.Sequence.reset(5)
iex> :rand.seed(:exsplus, {1, 2, 3})
...>
iex> MyApp.FactoryWithNoRepo.build(MyApp.Car)
%MyApp.Car{id: 5, model: "Truck", color: :green}
...>
iex> MyApp.FactoryWithNoRepo.build(MyApp.Car, color: :yellow)
%MyApp.Car{id: 6, model: "Hatch", color: :yellow}
...>
iex> MyApp.FactoryWithNoRepo.build(MyApp.Car, %{color: :purple})
%MyApp.Car{id: 7, model: "Hatch", color: :purple}
...>
iex> MyApp.FactoryWithNoRepo.build(:tomato)
%{name: "Tomato-8", color: :blue}
...>
iex> MyApp.FactoryWithNoRepo.build(:tomato, color: :white)
%{name: "Tomato-9", color: :white}
...>
iex> MyApp.FactoryWithNoRepo.build(:tomato, %{color: :pink})
%{name: "Tomato-10", color: :pink}

insert/2:

iex> Elixir.MapBot.Sequence.reset(5)
iex> :rand.seed(:exsplus, {1, 2, 3})
...>
iex> MyApp.FactoryWithRepo.insert(MyApp.Car)
{:ok, %MyApp.Car{id: 5, model: "Truck", color: :green}}
...>
iex> MyApp.FactoryWithRepo.insert(MyApp.Car, color: :yellow)
{:ok, %MyApp.Car{id: 6, model: "Hatch", color: :yellow}}
...>
iex> MyApp.FactoryWithRepo.insert(MyApp.Car, %{color: :purple})
{:ok, %MyApp.Car{id: 7, model: "Hatch", color: :purple}}
...>
iex> MyApp.FactoryWithRepoAndChangeset.insert(MyApp.House)
{:ok, %MyApp.House{id: 8, style: "Asian", color: :blue}}
...>
iex> MyApp.FactoryWithRepoAndChangeset.insert(MyApp.House, color: :yellow)
{:ok, %MyApp.House{id: 9, style: "Asian", color: :yellow}}
...>
iex> MyApp.FactoryWithRepoAndChangeset.insert(MyApp.House, %{color: :purple})
{:ok, %MyApp.House{id: 10, style: "American", color: :purple}}

insert!/2:

iex> Elixir.MapBot.Sequence.reset(5)
iex> :rand.seed(:exsplus, {1, 2, 3})
...>
iex> MyApp.FactoryWithRepo.insert!(MyApp.Car)
%MyApp.Car{id: 5, model: "Truck", color: :green}
...>
iex> MyApp.FactoryWithRepo.insert!(MyApp.Car, color: :yellow)
%MyApp.Car{id: 6, model: "Hatch", color: :yellow}
...>
iex> MyApp.FactoryWithRepo.insert!(MyApp.Car, %{color: :purple})
%MyApp.Car{id: 7, model: "Hatch", color: :purple}
...>
iex> MyApp.FactoryWithRepoAndChangeset.insert!(MyApp.House)
%MyApp.House{id: 8, style: "Asian", color: :blue}
...>
iex> MyApp.FactoryWithRepoAndChangeset.insert!(MyApp.House, color: :yellow)
%MyApp.House{id: 9, style: "Asian", color: :yellow}
...>
iex> MyApp.FactoryWithRepoAndChangeset.insert!(MyApp.House, %{color: :purple})
%MyApp.House{id: 10, style: "American", color: :purple}

Link to this section Summary

Functions

Use __MODULE__ with the following options

Macro that defines a factory for the name argument.

Link to this section Types

Link to this type

use_option() View Source
use_option() :: {:repo, module()} | {:changeset, boolean()}

Link to this section Functions

Link to this macro

__using__(opts) View Source (macro)
__using__([use_option()]) :: any()

Use __MODULE__ with the following options:

  • :repo => Repository module to delegate calls on insert/1 and insert!/1
  • :changeset => If true a changeset/2 function will be called when inserting into the Repo

Examples

iex> MyApp.FactoryWithNoRepo.__info__(:functions)
[attrs: 1, attrs: 2, build: 1, build: 2]

iex> MyApp.FactoryWithRepo.__info__(:functions)
[attrs: 1, attrs: 2, build: 1, build: 2, insert: 1, insert: 2, insert!: 1, insert!: 2]

iex> MyApp.FactoryWithRepoAndChangeset.__info__(:functions)
[attrs: 1, attrs: 2, build: 1, build: 2, insert: 1, insert: 2, insert!: 1, insert!: 2, validate: 2]
Link to this macro

deffactory(name, list) View Source (macro)
deffactory(atom(), [{:do, any()}]) :: any()

Macro that defines a factory for the name argument.