ForgeCredoChecks.OneModulePerFile (forge_credo_checks v0.8.0)

Copy Markdown View Source

Basics

This check is disabled by default.

Learn how to enable it via .credo.exs.

This check has a base priority of normal and works with any version of Elixir.

Explanation

Define at most one module in each source file.

Why

A one-module-per-file layout makes a module's source location predictable, keeps ownership boundaries visible, and prevents unrelated modules from accumulating behind a filename that describes only the first one. Nested defmodule declarations count too: a nested name still defines a separate module and should live in its own file.

Bad

defmodule MyApp.Parser do
end

defmodule MyApp.Formatter do
end

Good

# lib/my_app/parser.ex
defmodule MyApp.Parser do
end

# lib/my_app/formatter.ex
defmodule MyApp.Formatter do
end

Configuration

excluded_paths lists path patterns (regexes or substrings) that the check skips. By default, files under a test/ directory and files ending in _test.exs are excluded because tests sometimes need a small nested module as a fixture. Set excluded_paths: [] to enforce the rule in tests too, or replace the defaults with project-specific exclusions.

The check counts literal defmodule declarations, including nested and reopened modules. A defmodule inside quote is ignored because it is AST emitted by a macro rather than a module defined by the source file itself. defprotocol and defimpl are separate constructs and are outside this check's scope.

Check-Specific Parameters

Use the following parameters to configure this check:

:excluded_paths

Paths skipped entirely (default: test/ directories and *_test.exs files).

This parameter defaults to [~r/(^|[\\\/])test[\\\/]/, ~r/_test\.exs$/].

General Parameters

Like with all checks, general params can be applied.

Parameters can be configured via the .credo.exs config file.