Skip to content

Commit

Permalink
Allow setting sequence starting point (#414)
Browse files Browse the repository at this point in the history
What changed?
============

We introduce `ExMachina.sequence/3` that allows for passing the
`start_at` option to set a starting point for a sequence.

This is meant to be used in a factory definition:

```elixir
def money_factory do
  %{
    cents: sequence(:cents, &"#{&1}", start_at: 60)
  }
end
```

Then, the following would increment starting at 60:

```elixir
build(:money)
// => %{cents: "60"}

build(:money)
// => %{cents: "61"}
```
  • Loading branch information
germsvel authored Mar 1, 2021
1 parent e0dab4b commit eaa4b9b
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 5 deletions.
25 changes: 23 additions & 2 deletions lib/ex_machina.ex
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,13 @@ defmodule ExMachina do
@before_compile unquote(__MODULE__)

import ExMachina,
only: [sequence: 1, sequence: 2, merge_attributes: 2, evaluate_lazy_attributes: 1]
only: [
sequence: 1,
sequence: 2,
sequence: 3,
merge_attributes: 2,
evaluate_lazy_attributes: 1
]

def build(factory_name, attrs \\ %{}) do
ExMachina.build(__MODULE__, factory_name, attrs)
Expand Down Expand Up @@ -142,10 +148,25 @@ defmodule ExMachina do
}
end
"""

@spec sequence(any, (integer -> any) | nonempty_list) :: any
def sequence(name, formatter), do: ExMachina.Sequence.next(name, formatter)

@doc """
Similar to `sequence/2` but it allows for passing a `start_at` option
to the sequence generation.
## Examples
def user_factory do
%{
# Will generate "[email protected]" then "[email protected]", etc.
email: sequence(:email, &"me-\#{&1}@foo.com", start_at: 100),
}
end
"""
@spec sequence(any, (integer -> any) | nonempty_list, start_at: non_neg_integer) :: any
def sequence(name, formatter, opts), do: ExMachina.Sequence.next(name, formatter, opts)

@doc """
Builds a single factory.
Expand Down
6 changes: 4 additions & 2 deletions lib/ex_machina/sequence.ex
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,11 @@ defmodule ExMachina.Sequence do
end

@doc false
def next(sequence_name, formatter) do
def next(sequence_name, formatter, opts \\ []) do
start_at = Keyword.get(opts, :start_at, 0)

Agent.get_and_update(__MODULE__, fn sequences ->
current_value = Map.get(sequences, sequence_name, 0)
current_value = Map.get(sequences, sequence_name, start_at)
new_sequences = Map.put(sequences, sequence_name, current_value + 1)
{formatter.(current_value), new_sequences}
end)
Expand Down
7 changes: 6 additions & 1 deletion test/ex_machina/sequence_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@ defmodule ExMachina.SequenceTest do
assert 1 == Sequence.next(:month, & &1)
end

test "let's you quickly create sequences" do
test "can optionally set starting integer" do
assert "100" == Sequence.next(:dollars_in_cents, &"#{&1}", start_at: 100)
assert "101" == Sequence.next(:dollars_in_cents, &"#{&1}")
end

test "lets you quickly create sequences" do
assert "Comment Body0" == Sequence.next("Comment Body")
assert "Comment Body1" == Sequence.next("Comment Body")
end
Expand Down
11 changes: 11 additions & 0 deletions test/ex_machina_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ defmodule ExMachinaTest do
%{floor: floor_number} = attrs
sequence(:room_number, &"#{floor_number}0#{&1}")
end

def money_factory do
%{
cents: sequence(:cents, &"#{&1}", start_at: 600)
}
end
end

describe "sequence" do
Expand All @@ -82,6 +88,11 @@ defmodule ExMachinaTest do
assert "Post Title0" == Factory.build(:article).title
assert "Post Title1" == Factory.build(:article).title
end

test "sequence/3 allows for setting a starting value" do
assert "600" == Factory.build(:money).cents
assert "601" == Factory.build(:money).cents
end
end

describe "build/2" do
Expand Down

0 comments on commit eaa4b9b

Please sign in to comment.