SimpleAgent
SimpleAgent is a simplification/abstraction layer around the base Elixir Agent
module.
Often times, Agents are used to store a simple value, such as an atom or an integer. This is used as a flag
or a count which multiple processes can access/update. In these cases, the full Agent
module is used with
boilerplate closure code that is repetative, adds noise to the code, and can be eliminated. For example,
to create an agent, update the value, then retrieve that code, you would run:
{:ok, agent} = Agent.start_link(fn -> nil end)
Agent.update(agent, fn _ -> :completed end)
completed = Agent.get(agent, fn val -> val != nil end)
SimpleAgent
boils these calls down to a more readable:
agent = SimpleAgent.start!
SimpleAgent.update! agent, :completed
completed = SimpleAgent.equals? agent, :completed
For Integer manipulation, SimpleAgent
takes this code:
{:ok, agent} = Agent.start_link(fn -> 0 end)
IO.puts Agent.get_and_update(fn val -> {val + 1, val + 1} end)
IO.puts Agent.get_and_update(fn val -> {val - 1, val - 1} end)
IO.puts Agent.get_and_update(fn val -> {val + 1, val + 1} end)
IO.puts Agent.get_and_update(fn val -> {val + 1, val + 1} end)
and boils it down to the more readable:
agent = SimpleAgent.start! 0
IO.puts SimpleAgent.increment! agent
IO.puts SimpleAgent.decrement! agent
IO.puts SimpleAgent.increment! agent
IO.puts SimpleAgent.increment! agent
SimpleAgent
is very useful in testing. For example:
test "foo calls bar 3 times" do
bar_call_agent = SimpleAgent.start! 0
:meck.new(Bar)
:meck.expect(Bar, :bar, fn -> SimpleAgent.increment!(bar_call_agent) end)
Foo.foo()
assert SimpleAgent.get?(bar_call_agent) == 3
end
Why only simple types?
When a complex state such as a map or a dict is in use, the correct way to manipulate the complex state is in
the Agent server via a closure. This prevents the entire state from being copied from the Agent Server to the
Client (see the Agent docs for more information on this). For states with these complex types, you should use
the full Agent
module. SimpleAgent
is for those cases where the “entire state” is a single simple Integer,
String, or Atom (including nil, true, and false).
Features:
- Simple types and updates reduce chances of errors, so all calls raise exceptions instead of requiring boilerplate
pattern matching, and
start!/2
is available instead of start_link No closures are required.
nil support
increment!/1
anddecrement!/1
allow for simple manipulation of integer states.
Summary↑
clear(agent) | Resets the current state to nil |
decrement!(agent) | Decreases the value of the current state by 1. Raises error if current state is not an integer |
equals?(agent, val) | Returns true or false if the current state of the specified agent is the specified value |
get!(agent) | Returns the current state of the agent. If the agent has an invalid type, raises an exception |
increment!(agent) | Increases the value of the current state by 1. Raises error if current state is not an integer |
nil?(agent) | Returns true or false if the current state is nil |
start!(initial_state \\ nil, options \\ []) | Starts an agent with the specified initial value, or nil by default. Second optional parameter is the standard GenServer options list |
update!(agent, val) | Updates the state to the new value. Returns the new value |
Types ↑
valid_types :: Atom | Integer | String.t
agent :: Agent.agent
Functions
Specs:
- clear(agent) :: :ok
Resets the current state to nil
Specs:
- decrement!(agent) :: Integer
Decreases the value of the current state by 1. Raises error if current state is not an integer
Specs:
- equals?(agent, valid_types) :: boolean
Returns true or false if the current state of the specified agent is the specified value
Specs:
- get!(agent) :: valid_types
Returns the current state of the agent. If the agent has an invalid type, raises an exception
Specs:
- increment!(agent) :: Integer
Increases the value of the current state by 1. Raises error if current state is not an integer
Specs:
- nil?(agent) :: boolean
Returns true or false if the current state is nil
Specs:
- start!(valid_types, GenServer.options) :: pid
Starts an agent with the specified initial value, or nil by default. Second optional parameter is the standard GenServer options list.
Return values
Returns the pid of the server to be used in subsequent calls to other SimpleAgent
functions.
Specs:
- update!(agent, valid_types) :: valid_types
Updates the state to the new value. Returns the new value.