# `ArchTest.ModuleSet`
[🔗](https://github.com/yoavgeva/arch_test/blob/v0.2.0/lib/arch_test/module_set.ex#L1)

Represents a lazy selection of modules for use in architecture rules.

A `ModuleSet` is created with one or more include patterns and optional
exclude patterns. Actual module resolution is deferred until
`resolve/2` is called with a dependency graph.

## Building a ModuleSet

    import ArchTest

    modules_matching("MyApp.Orders.*")
    modules_matching("MyApp.Orders.**")
    modules_in("MyApp.Orders")
    all_modules()

## Composing ModuleSets

    modules_matching("**.*Controller")
    |> excluding("MyApp.Web.ErrorController")

    modules_matching("**.*Service")
    |> union(modules_matching("**.*View"))

    modules_matching("MyApp.**")
    |> intersection(modules_matching("**.*Schema"))

# `t`

```elixir
@type t() :: %ArchTest.ModuleSet{
  app: atom() | nil,
  custom_filter: (module() -&gt; boolean()) | nil,
  exclude_patterns: [String.t()],
  include_patterns: [String.t()]
}
```

# `all`

```elixir
@spec all() :: t()
```

Creates a `ModuleSet` that matches all modules.

# `excluding`

```elixir
@spec excluding(t(), String.t() | [String.t()]) :: t()
```

Adds exclude patterns to a `ModuleSet`.

# `in_namespace`

```elixir
@spec in_namespace(String.t()) :: t()
```

Creates a `ModuleSet` for all direct children of `namespace`.

Equivalent to `modules_matching("Namespace.*")`.

# `intersection`

```elixir
@spec intersection(t(), t()) :: t()
```

Returns a new `ModuleSet` matching modules in *both* sets (intersection / AND).

A module is included only if it matches both set `a` AND set `b`.

# `new`

```elixir
@spec new(String.t() | [String.t()]) :: t()
```

Creates a `ModuleSet` matching the given glob pattern.

## Examples

    iex> import ArchTest
    iex> ms = modules_matching("MyApp.Orders.*")
    iex> %ArchTest.ModuleSet{include_patterns: ["MyApp.Orders.*"]} = ms

# `resolve`

```elixir
@spec resolve(t(), ArchTest.Collector.graph()) :: [module()]
```

Resolves the `ModuleSet` against the given dependency graph.

Returns the list of actual module atoms that match the set's patterns.

# `satisfying`

```elixir
@spec satisfying((module() -&gt; boolean())) :: t()
```

Creates a `ModuleSet` using a custom filter function.

The function receives a module atom and returns `true` to include it.

## Example

    modules_satisfying(fn mod ->
      function_exported?(mod, :__schema__, 1)
    end)

# `union`

```elixir
@spec union(t(), t()) :: t()
```

Returns a new `ModuleSet` matching modules in *either* set (union / OR).

A module is included if it matches set `a` OR set `b` (with each set's
own include/exclude/custom_filter applied independently).

---

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