Mutare.Mutator.Families (mutare v0.1.0)

Copy Markdown View Source

A declarative family catalog for a family-rich mutator's configuration.

A plugin that emits many mutation kinds under one mutator module usually exposes a families: option so users can narrow the catalog. This module generates that option's selection-and-validation machinery from one declaration, so every such plugin parses the same grammar — the one Mutare's own {:builtins, except: […]} uses — and fails loudly in the same shapes:

defmodule MyPlugin.Config do
  use Mutare.Mutator.Families,
    plugin: "MyPlugin",
    all: ~w(comparison connective null_predicate string_literal)a,
    opt_in: ~w(string_literal)a
end

use options:

  • :all (required) — every family the mutator can emit, ordered; duplicates rejected.
  • :opt_in (default []) — the subset excluded from the default set; each must be in :all.
  • :plugin (default the using module's name) — the name error messages blame, e.g. "Mutare.Ecto".

The declaration generates, all overridable:

  • all_families/0 — the :all list;
  • default_families/0all -- opt_in, the set used when families: is unset;
  • parse_families!/1 — a configured families: value (:default, :all, an explicit list, or {:all | :default, except: […]}) to the enabled MapSet, raising ArgumentError on an unknown family or a malformed except:;
  • family_enabled?/2 — whether a family is in a parsed set, or in the set a raw keyword list's families: value parses to;
  • @type family — the union of the declared family atoms.

Only selection and validation are generated. What each family means — notes, variant labels, delivery — stays the plugin's, typically alongside this use in its config module. Parse once per run by calling parse_families!/1 from the mutator's Mutare.Mutator.init/1 and reading the result back from context.config; then apply the selection once, in Mutare.Mutator.finalize/2 — Mutare runs it on every produced mutation, on both delivery paths, so producers stay pure and no delivery site can forget the filter.

Summary

Types

The catalog a use Mutare.Mutator.Families declaration compiles to — the value the generated functions close over and the runtime faces (parse!/2, enabled?/3) take.

Functions

Whether family is enabled — the runtime behind the generated family_enabled?/2. A MapSet is an already-parsed selection; a keyword list is raw options, whose families: value (default :default) is parsed first.

Parses a families: value against catalog — the runtime behind the generated parse_families!/1, kept here so the grammar and its error messages are owned once.

Types

catalog()

@type catalog() :: %{plugin: String.t(), all: [atom()], default: [atom()]}

The catalog a use Mutare.Mutator.Families declaration compiles to — the value the generated functions close over and the runtime faces (parse!/2, enabled?/3) take.

Functions

enabled?(enabled, family, catalog)

@spec enabled?(MapSet.t(atom()) | keyword(), atom(), catalog()) :: boolean()

Whether family is enabled — the runtime behind the generated family_enabled?/2. A MapSet is an already-parsed selection; a keyword list is raw options, whose families: value (default :default) is parsed first.

parse!(families, catalog)

@spec parse!(term(), catalog()) :: MapSet.t(atom())

Parses a families: value against catalog — the runtime behind the generated parse_families!/1, kept here so the grammar and its error messages are owned once.