Packages

fnord

0.8.89

AI code archaeology

Current section

Files

Jump to
fnord lib settings frobs.ex
Raw

lib/settings/frobs.ex

defmodule Settings.Frobs do
@moduledoc """
Manage frob enablement in settings.json using approvals-style arrays.
Schema:
- Global: ["frobs"] :: [string]
- Per-project: ["projects", pn, "frobs"] :: [string]
Effective enablement is the union of global and current project's frobs.
All mutations are performed via Settings APIs that provide cross-process locking
and atomic writes.
"""
@type scope :: :global | :project | {:project, String.t()}
@doc """
List enabled frobs for the given scope.
"""
@spec list(scope) :: [String.t()]
def list(:global) do
Settings.get(Settings.new(), "frobs", [])
|> sanitize_list()
end
def list(:project) do
case Settings.get_selected_project() do
{:ok, pn} -> list({:project, pn})
_ -> []
end
end
def list({:project, pn}) when is_binary(pn) do
settings = Settings.new()
project = Settings.get_project_data(settings, pn) || %{}
Map.get(project, "frobs", []) |> sanitize_list()
end
@doc """
Enable a frob in the given scope. Idempotent.
"""
@spec enable(scope, String.t()) :: :ok
def enable(scope, name) when is_binary(name) and byte_size(name) > 0 do
names =
list(scope)
|> List.wrap()
|> Kernel.++([name])
|> Enum.filter(&is_binary/1)
|> Enum.uniq()
|> Enum.sort()
set_list(scope, names)
end
@doc """
Disable a frob in the given scope. Idempotent.
"""
@spec disable(scope, String.t()) :: :ok
def disable(scope, name) when is_binary(name) do
names =
list(scope)
|> Enum.reject(&(&1 == name))
set_list(scope, names)
end
@doc """
Return the effective set of enabled frobs for the current project context
(union of global and project lists).
"""
@spec effective_enabled() :: MapSet.t(String.t())
def effective_enabled() do
global = list(:global)
project =
case Settings.get_selected_project() do
{:ok, _} -> list(:project)
_ -> []
end
MapSet.new(global ++ project)
end
@doc """
Is the given frob enabled (effective union)?
"""
@spec enabled?(String.t()) :: boolean()
def enabled?(name) when is_binary(name) do
MapSet.member?(effective_enabled(), name)
end
@doc """
Prune missing frobs from settings based on the given list of present frob names.
This removes any frob names that are not found in `present_names` from:
- the global `frobs` array, and
- the currently selected project's `frobs` array (if a project is selected)
Returns the list of names that were retained.
"""
@spec prune_missing!([String.t()]) :: [String.t()]
def prune_missing!(present_names) when is_list(present_names) do
set =
present_names
|> Enum.filter(&is_binary/1)
|> MapSet.new()
# Prune global list atomically
Settings.update(
Settings.new(),
"frobs",
fn current ->
current_list = if is_list(current), do: current, else: []
current_list
|> Enum.filter(&MapSet.member?(set, &1))
|> Enum.uniq()
|> Enum.sort()
end,
[]
)
# Prune currently selected project's list, if any
case Settings.get_selected_project() do
{:ok, pn} ->
settings = Settings.new()
project = Settings.get_project_data(settings, pn) || %{}
pruned =
project
|> Map.get("frobs", [])
|> Enum.filter(&MapSet.member?(set, &1))
|> Enum.uniq()
|> Enum.sort()
_ = Settings.set_project_data(settings, pn, Map.put(project, "frobs", pruned))
:ok
_ ->
:ok
end
# Return the list of names that were not removed (i.e., kept)
present_names
|> Enum.filter(&is_binary/1)
|> Enum.uniq()
|> Enum.sort()
end
# ----------------------------------------------------------------------------
# Internals
# ----------------------------------------------------------------------------
defp sanitize_list(list) when is_list(list) do
list
|> Enum.filter(&is_binary/1)
|> Enum.uniq()
|> Enum.sort()
end
defp sanitize_list(_), do: []
defp set_list(:global, names) when is_list(names) do
Settings.update(Settings.new(), "frobs", fn _ -> names end, [])
:ok
end
defp set_list(:project, names) when is_list(names) do
case Settings.get_selected_project() do
{:ok, pn} ->
settings = Settings.new()
project = Settings.get_project_data(settings, pn) || %{}
Settings.set_project_data(settings, pn, Map.put(project, "frobs", names))
:ok
_ ->
:ok
end
end
defp set_list({:project, pn}, names) when is_list(names) and is_binary(pn) do
settings = Settings.new()
project = Settings.get_project_data(settings, pn) || %{}
Settings.set_project_data(settings, pn, Map.put(project, "frobs", names))
:ok
end
end