# `Adze.Rename`
[🔗](https://github.com/matthewlehner/adze/blob/v0.1.0/lib/adze/rename.ex#L1)

`rename` / `rename!` — globally rename a module across the project.

Wraps `Igniter.Refactors.Rename.rename_module/3` via
`Adze.ProjectRewrite`. Updates `defmodule`, every `alias` /
`use` / `import` / `require`, all call sites, the corresponding test
module (if any), and string literals mentioning the module. The
module's file is moved to its canonical location (derived from the
new name).

## CLI

    mix adze rename  --from MyApp.Old --to MyApp.New
    mix adze rename! --from MyApp.Old --to MyApp.New

Dry-run by default: prints a diff for every touched file. `rename!`
also writes.

## Programmatic

    Adze.Rename.rename(from: "MyApp.Old", to: "MyApp.New")
    #=> {:ok, %{diffs: %{path => diff}, moves: %{old_path => new_path},
    #          warnings: [...], notices: [...]}}

    Adze.Rename.rename!(from: "MyApp.Old", to: "MyApp.New")

Both accept `mix_root:` (defaults to the current directory) and
`files:` for in-memory test fixtures (delegates to
`Adze.ProjectRewrite.new/1`).

## Short-ref fix-up

When Igniter's same-namespace rename leaves bare `OldShort.fun(...)`
call sites un-rewritten (an upstream bug — string substitution
rewrites the alias declaration before the AST pass runs, so bare
refs no longer resolve back to the old aliases list), adze patches
them itself in files that had a non-`as:` alias to the renamed
module. Patched locations come back as `{:rewritten_short_refs,
refs}` in `notices:`. Locations that couldn't be safely patched (no
qualifying alias declaration in pre-rewrite content) come back as
`{:surviving_references, refs}` in `warnings:`, and `rename!/1`
refuses to write unless `force: true`.

## Limitations (inherited from Igniter)

  * Dynamic refs (`apply/3`, `Module.concat/2` with variables) are
    not rewritten.
  * `alias Foo.Old, as: B` keeps the `as:` binding; only the alias
    declaration is updated. `B.*` call sites are correct since they
    resolve through `as:`.
  * String-literal substitution is a plain substring replace over
    raw file content — it also rewrites occurrences inside comments
    and unrelated strings. Grep after.

# `opts`

```elixir
@type opts() :: [
  from: String.t() | module(),
  to: String.t() | module(),
  mix_root: Path.t(),
  files: %{required(Path.t()) =&gt; String.t()},
  app_name: atom(),
  force: boolean()
]
```

# `result`

```elixir
@type result() :: %{
  from: module(),
  to: module(),
  diffs: %{required(Path.t()) =&gt; String.t()},
  moves: %{required(Path.t()) =&gt; Path.t()},
  warnings: list(),
  notices: list()
}
```

# `rename`

```elixir
@spec rename(opts()) :: {:ok, result()} | {:error, term()}
```

# `rename!`

```elixir
@spec rename!(opts()) :: {:ok, result()} | {:error, term()}
```

---

*Consult [api-reference.md](api-reference.md) for complete listing*
