View Source FunWithFlags (fun_with_flags v1.12.0)

FunWithFlags, the Elixir feature flag library.

This module provides the public interface to the library and its API is made of three simple methods to enable, disable and query feature flags.

In their simplest form, flags can be toggled on and off globally.

More advanced rules or "gates" are available, and they can be set and queried for any term that implements these protocols:

  • The FunWithFlags.Actor protocol can be implemented for types and structs that should have specific rules. For example, in web applications it's common to use a %User{} struct or equivalent as an actor, or perhaps the current country of the request.

  • The FunWithFlags.Group protocol can be implemented for types and structs that should belong to groups for which one wants to enable and disable some flags. For example, one could implement the protocol for a %User{} struct to identify administrators.

See the Usage notes for a more detailed explanation.

Summary

Functions

Returns a list of all flag names currently configured, as atoms.

Returns a list of all the flags currently configured, as data structures.

Clears the data of a feature flag.

Disables a feature flag.

Enables a feature flag.

Checks if a flag is enabled.

Returns a FunWithFlags.Flag struct for the given name, or nil if no flag is found.

Types

@type options() :: Keyword.t()

Functions

@spec all_flag_names() :: {:ok, [atom()]} | {:error, any()}

Returns a list of all flag names currently configured, as atoms.

This can be useful for debugging or for display purposes, but it's not meant to be used at runtime. Undefined flags, for example, will be considered disabled.

@spec all_flags() :: {:ok, [FunWithFlags.Flag.t()]} | {:error, any()}

Returns a list of all the flags currently configured, as data structures.

This function is provided for debugging and to build more complex functionality (e.g. it's used in the web GUI), but it is not meant to be used at runtime to check if a flag is enabled.

To query the value of a flag, please use the enabled?2 function instead.

Link to this function

clear(flag_name, options \\ [])

View Source
@spec clear(atom(), options()) :: :ok | {:error, any()}

Clears the data of a feature flag.

Clears the data for an entire feature flag or for a specific Actor or Group gate. Clearing a boolean gate is not supported because a missing boolean gate is equivalent to a disabled boolean gate.

Sometimes enabling or disabling a gate is not what you want, and you need to remove that gate's rules instead. For example, if you don't need anymore to explicitly enable or disable a flag for an actor, and the default state should be used instead, you'll want to clear the gate.

It's also possible to clear the entire flag, by not passing any option.

Options

  • for_actor: an_actor - used to clear the flag for a specific term only. The value can be any term that implements the Actor protocol.
  • for_group: a_group_name - used to clear the flag for a specific group only. The value should be a binary or an atom (It's internally converted to a binary and it's stored and retrieved as a binary. Atoms are supported for retro-compatibility with versions <= 0.9)
  • boolean: true - used to clear the boolean gate.
  • for_percentage: true - used to clear any percentage gate.

Examples

iex> alias FunWithFlags.TestUser, as: User
iex> harry = %User{id: 1, name: "Harry Potter", groups: ["wizards", "gryffindor"]}
iex> hagrid = %User{id: 2, name: "Rubeus Hagrid", groups: ["wizards", "gamekeeper"]}
iex> dudley = %User{id: 3, name: "Dudley Dursley", groups: ["muggles"]}
iex> FunWithFlags.disable(:wands)
iex> FunWithFlags.enable(:wands, for_group: "wizards")
iex> FunWithFlags.disable(:wands, for_actor: hagrid)
iex>
iex> FunWithFlags.enabled?(:wands)
false
iex> FunWithFlags.enabled?(:wands, for: harry)
true
iex> FunWithFlags.enabled?(:wands, for: hagrid)
false
iex> FunWithFlags.enabled?(:wands, for: dudley)
false
iex>
iex> FunWithFlags.clear(:wands, for_actor: hagrid)
:ok
iex> FunWithFlags.enabled?(:wands, for: hagrid)
true
iex>
iex> FunWithFlags.clear(:wands)
:ok
iex> FunWithFlags.enabled?(:wands)
false
iex> FunWithFlags.enabled?(:wands, for: harry)
false
iex> FunWithFlags.enabled?(:wands, for: hagrid)
false
iex> FunWithFlags.enabled?(:wands, for: dudley)
false
Link to this function

disable(flag_name, options \\ [])

View Source
@spec disable(atom(), options()) :: {:ok, boolean()} | {:error, any()}

Disables a feature flag.

Options

  • :for_actor - used to disable the flag for a specific term only. The value can be any term that implements the Actor protocol.
  • :for_group - used to disable the flag for a specific group only. The value should be a binary or an atom (It's internally converted to a binary and it's stored and retrieved as a binary. Atoms are supported for retro-compatibility with versions <= 0.9)
  • :for_percentage_of - used to disable the flag for a percentage of time or actors, expressed as {:time, float} or {:actors, float}, where float is in the range 0.0 < x < 1.0.

Examples

Disable globally

iex> FunWithFlags.enable(:random_koala_gifs)
iex> FunWithFlags.enabled?(:random_koala_gifs)
true
iex> FunWithFlags.disable(:random_koala_gifs)
{:ok, false}
iex> FunWithFlags.enabled?(:random_koala_gifs)
false

Disable for an actor

iex> FunWithFlags.enable(:spider_sense)
{:ok, true}
iex> villain = %{name: "Venom"}
iex> FunWithFlags.disable(:spider_sense, for_actor: villain)
{:ok, false}
iex> FunWithFlags.enabled?(:spider_sense)
true
iex> FunWithFlags.enabled?(:spider_sense, for: villain)
false

Disable for a group

This example relies on the reference implementation used in the tests.

iex> alias FunWithFlags.TestUser, as: User
iex> harry = %User{name: "Harry Potter", groups: ["wizards", "gryffindor"]}
iex> dudley = %User{name: "Dudley Dursley", groups: ["muggles"]}
iex> FunWithFlags.enable(:hogwarts)
{:ok, true}
iex> FunWithFlags.disable(:hogwarts, for_group: "muggles")
{:ok, false}
iex> FunWithFlags.enabled?(:hogwarts)
true
iex> FunWithFlags.enabled?(:hogwarts, for: harry)
true
iex> FunWithFlags.enabled?(:hogwarts, for: dudley)
false

Disable for a percentage of the time

iex> FunWithFlags.clear(:random_glitch)
:ok
iex> FunWithFlags.disable(:random_glitch, for_percentage_of: {:time, 0.999999999})
{:ok, false}
iex> FunWithFlags.enabled?(:random_glitch)
false
iex> FunWithFlags.disable(:random_glitch, for_percentage_of: {:time, 0.000000001})
{:ok, false}
iex> FunWithFlags.enabled?(:random_glitch)
true

Disable for a percentage of the actors

iex> FunWithFlags.disable(:new_ui, for_percentage_of: {:actors, 0.3})
{:ok, false}
Link to this function

enable(flag_name, options \\ [])

View Source
@spec enable(atom(), options()) :: {:ok, true} | {:error, any()}

Enables a feature flag.

Options

  • :for_actor - used to enable the flag for a specific term only. The value can be any term that implements the Actor protocol.
  • :for_group - used to enable the flag for a specific group only. The value should be a binary or an atom (It's internally converted to a binary and it's stored and retrieved as a binary. Atoms are supported for retro-compatibility with versions <= 0.9)
  • :for_percentage_of - used to enable the flag for a percentage of time or actors, expressed as {:time, float} or {:actors, float}, where float is in the range 0.0 < x < 1.0.

Examples

Enable globally

iex> FunWithFlags.enabled?(:super_shrink_ray)
false
iex> FunWithFlags.enable(:super_shrink_ray)
{:ok, true}
iex> FunWithFlags.enabled?(:super_shrink_ray)
true

Enable for an actor

iex> FunWithFlags.disable(:warp_drive)
{:ok, false}
iex> FunWithFlags.enable(:warp_drive, for_actor: "Scotty")
{:ok, true}
iex> FunWithFlags.enabled?(:warp_drive)
false
iex> FunWithFlags.enabled?(:warp_drive, for: "Scotty")
true

Enable for a group

This example relies on the reference implementation used in the tests.

iex> alias FunWithFlags.TestUser, as: User
iex> marty = %User{name: "Marty McFly", groups: ["students", "time_travelers"]}
iex> doc = %User{name: "Emmet Brown", groups: ["scientists", "time_travelers"]}
iex> buford = %User{name: "Buford Tannen", groups: ["gunmen", "bandits"]}
iex> FunWithFlags.enable(:delorean, for_group: "time_travelers")
{:ok, true}
iex> FunWithFlags.enabled?(:delorean)
false
iex> FunWithFlags.enabled?(:delorean, for: buford)
false
iex> FunWithFlags.enabled?(:delorean, for: marty)
true
iex> FunWithFlags.enabled?(:delorean, for: doc)
true

Enable for a percentage of the time

iex> FunWithFlags.disable(:random_glitch)
iex> FunWithFlags.enable(:random_glitch, for_percentage_of: {:time, 0.999999999})
iex> FunWithFlags.enabled?(:random_glitch)
true
iex> FunWithFlags.enable(:random_glitch, for_percentage_of: {:time, 0.000000001})
iex> FunWithFlags.enabled?(:random_glitch)
false

Enable for a percentage of the actors

This example is based on the fact that the actor score for the actor-flag pair marty + :new_ui is lower than 50%, and for the buford + :new_ui is higher.

iex> FunWithFlags.disable(:new_ui)
iex> FunWithFlags.enable(:new_ui, for_percentage_of: {:actors, 0.5})
iex> FunWithFlags.enabled?(:new_ui)
false
iex> alias FunWithFlags.TestUser, as: User
iex> marty = %User{id: 42, name: "Marty McFly"}
iex> buford = %User{id: 2, name: "Buford Tannen"}
iex> FunWithFlags.enabled?(:new_ui, for: marty)
true
iex> FunWithFlags.enabled?(:new_ui, for: buford)
false
Link to this function

enabled?(flag_name, options \\ [])

View Source
@spec enabled?(atom(), options()) :: boolean()

Checks if a flag is enabled.

It can be invoked with just the flag name, as an atom, to check the general status of a flag (i.e. the boolean gate).

Options

  • :for - used to provide a term for which the flag could have a specific value. The passed term should implement the Actor or Group protocol, or both.

Examples

This example relies on the reference implementation used in the tests.

iex> alias FunWithFlags.TestUser, as: User
iex> harry = %User{id: 1, name: "Harry Potter", groups: ["wizards", "gryffindor"]}
iex> FunWithFlags.disable(:elder_wand)
iex> FunWithFlags.enable(:elder_wand, for_actor: harry)
iex> FunWithFlags.enabled?(:elder_wand)
false
iex> FunWithFlags.enabled?(:elder_wand, for: harry)
true
iex> voldemort = %User{id: 7, name: "Tom Riddle", groups: ["wizards", "slytherin"]}
iex> FunWithFlags.enabled?(:elder_wand, for: voldemort)
false
iex> filch = %User{id: 88, name: "Argus Filch", groups: ["staff"]}
iex> FunWithFlags.enable(:magic_wands, for_group: "wizards")
iex> FunWithFlags.enabled?(:magic_wands, for: harry)
true
iex> FunWithFlags.enabled?(:magic_wands, for: voldemort)
true
iex> FunWithFlags.enabled?(:magic_wands, for: filch)
false
@spec get_flag(atom()) :: FunWithFlags.Flag.t() | nil | {:error, any()}

Returns a FunWithFlags.Flag struct for the given name, or nil if no flag is found.

Useful for debugging.