This library is designed to provide an easy way to initialize global flags in Erlang/Elixir, without having to be linked to a main application tree.
This is useful for libraries which require a certain state, regardless of the state of the parent application. It's aimed at use cases where it's considered overhead to jump to an other process, and it's wasteful to have an ETS table (for example).
This library is tiny, so you can include it with minimal overhead. It uses the atom table to store flags, and as such it's not possible to unset a flag after it's set.
Follow the instructons found here to configure your Rebar setup to use Hex as a dependency source, then you can grab it directly:
{deps,[
% pulls the latest version
global_flags,
% to pull the latest version from github
{global_flags, {git, "git://github.com/whitfin/global-flags.git"}}
]}.
To install it for your project, you can pull it directly from Hex. Rather than use the version shown below, you can use the latest version from Hex (shown at the top of this README).
def deps do
[{:global_flags, "~> 1.0"}]
end
% manually set a flag (typically unused)
1> global_flags:set("my-flag")
% will run only the first time it's hit (and then sets the provided flag)
2> global_flags:once("app:init", fun() -> erlang:display("this will run once") end).
% won't run because the call above it set the "app:init" flag
3> global_flags:once("app:init", fun() -> erlang:display("same flag, so will never run") end).
% only runs when the flag has been set
4> global_flags:with("app:init", fun() -> erlang:display("will only run when set") end).
% only runs when the flag has been not been set
5> global_flags:without("app:init", fun() -> erlang:display("will only run when unset") end).
# manually set a flag (typically unused)
iex(1)> :global_flags.set("my-flag")
# will run only the first time it's hit (and then sets the provided flag)
iex(2)> :global_flags.once("app:init", fn -> IO.puts("this will run once") end)
# won't run because the call above it set the "app:init" flag
iex(3)> :global_flags.once("app:init", fn -> IO.puts("same flag, so will never run") end)
# only runs when the flag has been set
iex(4)> :global_flags.with("app:init", fn -> IO.puts("will only run when set") end)
# only runs when the flag has been not been set
iex(5)> :global_flags.without("app:init", fn -> IO.puts("will only run when unset") end)
This example is in Elixir, but it should be fairly understandable for those coming from both languages. It contains a counter that's global to the entire runtime, which creates itself on the first call. This is useful because all applications using this counter would increment atomically, even if they're not explicitly linked directly.
defmodule GlobalCounter do
@doc """
Retrieves the next integer in the global counter.
"""
def next_int do
# initializes the Agent only the first time called
:global_flags.once("global_counter:init", fn ->
Agent.start(fn -> 1 end, [ name: :global_counter ])
end)
# guaranteed to now have a started Agent
Agent.get_and_update(:global_counter, fn count ->
{count, count + 1}
end)
end
end