MobDev.MobExs (mob_dev v0.7.9)

Copy Markdown View Source

Text edits to a project's committed mob.exs and its gitignored mob.local.exs override file.

mob.exs holds project config (plugin activation, plugin trust, styles) and is committed; a clone without it activates no plugins. Machine paths (a local mob_dir checkout) go in mob.local.exs, which the last statement of mob.exs imports when present — so local values win.

Config deep-merges keyword lists but replaces every other value (maps, plain lists), so a stanza written after that import would silently beat the local override. Writers that add a stanza to mob.exs go through insert_config/2, which places it above the import.

The import is found by walking the parsed file, not by matching text: import_config "mob.local.exs" with or without parens, bare or under an if (one line or do/end), all count. Importing the same file twice makes Config.Reader raise, so a missed variant is not harmless.

See decisions/2026-09-30-mob-local-exs-overrides.md.

Summary

Functions

Adds a mob.local.exs entry to .gitignore content unless one is there. Other entries — including an old mob.exs line — are left alone.

Appends the mob.local.exs import to mob.exs content unless it already imports that file.

Adds stanza (one or more lines of config) to mob.exs content: directly above the top-level statement that imports mob.local.exs when there is one, otherwise at the end.

Full content for a new mob.local.exs setting mob_dev_config under config :mob_dev. Same header mob.new --local writes.

The conditional import line that ends a generated mob.exs.

Writes mob_dev_config to project_dir/mob.local.exs, makes sure mob.exs imports it, and makes sure .gitignore ignores it.

Functions

ensure_gitignored(content)

@spec ensure_gitignored(String.t()) :: String.t()

Adds a mob.local.exs entry to .gitignore content unless one is there. Other entries — including an old mob.exs line — are left alone.

ensure_local_import(content)

@spec ensure_local_import(String.t()) :: String.t()

Appends the mob.local.exs import to mob.exs content unless it already imports that file.

insert_config(content, stanza)

@spec insert_config(String.t(), String.t()) :: String.t()

Adds stanza (one or more lines of config) to mob.exs content: directly above the top-level statement that imports mob.local.exs when there is one, otherwise at the end.

local_content(mob_dev_config)

@spec local_content(keyword()) :: String.t()

Full content for a new mob.local.exs setting mob_dev_config under config :mob_dev. Same header mob.new --local writes.

local_import()

@spec local_import() :: String.t()

The conditional import line that ends a generated mob.exs.

put_local_config(project_dir, mob_dev_config)

@spec put_local_config(
  Path.t(),
  keyword()
) :: :ok

Writes mob_dev_config to project_dir/mob.local.exs, makes sure mob.exs imports it, and makes sure .gitignore ignores it.

An existing mob.local.exs keeps everything it has: the new values are appended as a later config :mob_dev call, which wins over earlier ones for the same keys. mob.exs only gains the import line (or is created holding just that when absent).