Current section
Files
Jump to
Current section
Files
lib/ex_fabricators.ex
defmodule ExFabricators do
@moduledoc false
alias ExFabricators.FabricatorsRepo
@typep fabricators :: Keyword.t
@doc """
Runs the process to gathering all defined fabricators and provides them for to be able to build.
So in `test/test_helper.exs` you must to add the next line:
ExFabricators.take_all!(Path.join(File.cwd!, "test/fabricators"))
"""
@spec take_all!(String.t) :: any
def take_all!(fabricators_path) do
fabricators_path
|> fetch_and_merge_all_builders
|> start_and_populate_agent
end
@doc """
Entry points to run some specific fabricator with custom properties
## Examples
Build some `Team` struct with default properties:
ExFabricators.build(:team) # => %YourApp.Structs.Team{...}
Build team with some custom properties:
ExFabricators.build(:team, %{a: 1}) # => %YourApp.Structs.Team{a: 1, ...}
"""
@spec build(:atom, map) :: struct
def build(name, options \\ %{}) do
FabricatorsRepo.get
|> Keyword.get(name)
|> instantiate_struct(options)
end
@doc """
Validates new fabricators entries for doubling. So if there are some new entries with names that
already contained in registry of fabricators RuntimeError will be raised.
## Examples
When try to validate fully uniq new entries:
ExFabricators.validate!([team: {..., ...}], [team1: {..., ...}] # => :ok
When try to validate new entries that some one from them is not uniq:
ExFabricators.validate!([team: {..., ...}], [team: {..., ...}]
# => RuntimeError
"""
@spec validate!(fabricators, fabricators) :: :ok | none
def validate!(fabricators, new_fabricators) do
new_fabricators
|> Keyword.keys
|> Enum.each(fn(key) ->
if Keyword.has_key?(fabricators, key) do
raise RuntimeError,
"Fabricator for `#{Atom.to_string(key)}` already defined!"
end
end)
:ok
end
defp fetch_and_merge_all_builders(fabricators_path) do
fabricators_path
|> Path.join("*_fabricator.exs")
|> Path.wildcard
|> Enum.map(&read_file!(&1))
|> Enum.reduce([], fn(fabricators, acc) ->
validate!(acc, fabricators)
Keyword.merge(acc, fabricators)
end)
end
defp start_and_populate_agent(fabricators) do
FabricatorsRepo.start_link
FabricatorsRepo.update(fabricators)
end
defp read_file!(file) do
try do
{fabricators, binding} = Code.eval_file(file)
fabricators = case List.keyfind(binding, {:builder_agent, ExFabricators.Builder}, 0) do
{_, agent} -> get_fabricators_and_stop_agent(agent)
nil -> fabricators
end
fabricators
rescue
e in [LoadError] -> reraise(e, System.stacktrace)
e -> reraise(LoadError, [file: file, error: e], System.stacktrace)
end
end
defp get_fabricators_and_stop_agent(agent) do
fabricators = ExFabricators.Builder.Agent.get(agent)
ExFabricators.Builder.Agent.stop(agent)
fabricators
end
defp instantiate_struct({struct, default_options_fn}, options) do
struct
|> Kernel.struct(default_options_fn.())
|> Map.merge(options)
end
end