fun_with_flags v0.4.0 FunWithFlags.Actor protocol
Implement this protocol to provide actors.
Actor gates allows you to enable or disable a flag for one or more entities. This can be useful to showcase a work-in-progress feature to someone, to gradually rollout a functionality (e.g. your actor could be a country), or to dynamically disable some features in some contexts (e.g. you realize that a critical error is only raised in one specific country).
Actor gates take precendence over the others, both when they’re enabled and when they’re disabled. They can be considered as toggle overrides.
In order to be used as an actor, an entity must implement
the FunWithFlags.Actor
protocol. This is a plain Elixir protocol and can
be implemented for custom structs or literally any other type.
Examples
This protocol is typically implemented for some application structure.
defmodule MyApp.User do
defstruct [:id, :name]
end
defimpl FunWithFlags.Actor, for: MyApp.User do
def id(user) do
"user:#{user.id}"
end
end
bruce = %User{id: 1, name: "Bruce"}
FunWithFlags.enable(:batmobile, for_actor: bruce)
but it can also be implemented for the builtin types:
defimpl FunWithFlags.Actor, for: Map do
def id(%{actor_id: actor_id}) do
"map:#{actor_id}"
end
def id(map) do
map
|> inspect()
|> (&:crypto.hash(:md5, &1)).()
|> Base.encode16
|> (&"map:#{&1}").()
end
end
defimpl FunWithFlags.Actor, for: BitString do
def id(str) do
"string:#{str}"
end
end
FunWithFlags.disable(:foobar, for_actor: %{actor_id: "just a map"})
FunWithFlags.enable(:foobar, for_actor: "just a string")
Actor identifiers must be globally unique binaries. A common technique to support multiple kinds of actors is to namespace the IDs:
defimpl FunWithFlags.Actor, for: MyApp.User do
def id(user) do
"user:#{user.id}"
end
end
defimpl FunWithFlags.Actor, for: MyApp.Country do
def id(country) do
"country:#{country.iso3166}"
end
end