# Naming

Naming rules check the shape and consistency of the methods a component defines. They start from `methods`, select some of those methods by name, then assert something about them. Every check is name-based and exact, so it reports at `high` confidence.

Rules judge a component's own **defined, public** methods. Inherited methods, methods generated by a gem, and private or protected methods are left alone.

## Selecting Methods

`matching` selects methods whose name matches a regex:

```ruby
models.methods.matching(/\A(get|set)_/)
```

Pass `scope: :class` to select class methods instead of instance methods:

```ruby
models.methods(scope: :class).matching(/\Afind_/)
```

A named capture in the regex, such as `(?<base>.+)`, is available to `requires`.

## Forbid Names

```ruby
models.methods.matching(/\A(get|set)_/).forbidden(because: "use attr readers or plain names")
```

Rule id: `naming.forbidden`

Every selected method fails. Use it to ban a naming style outright. The `because:` text is appended to the message.

## Require a Sibling

```ruby
chat.methods.matching(/\Awith_(?<base>.+)/).requires("without_%{base}")
```

Rule id: `naming.requires`

For each selected method, a sibling named by the template must exist. The template interpolates the named captures from the selector, so `with_model` requires `without_model` and `with_tools` requires `without_tools`. A method without its sibling fails.

The sibling is looked up in the same component by default. Pass `on:` to require it in another component, and `scope:` to require it as a class method:

```ruby
chat.methods.matching(/\Awith_(?<base>.+)/).requires("%{base}", on: agent, scope: :class)
```

This reads: every `with_x` instance method on `chat` must have a matching `x` class method on `agent`. The sibling counts whatever its visibility.

Other pairings follow the same shape:

```ruby
accounts.methods.matching(/(?<base>.+)!\z/).requires("%{base}")
```

## Allowlisting

Every rule takes `except:`, a reviewed list of method names to skip:

```ruby
models.methods.matching(/\Ais_/).forbidden(except: %i[is_a is_haml])
```

Keep the list in `Archspec.rb` where it is reviewed, rather than reaching for an inline suppression.

## Scope

`scope:` on `methods` selects which methods a rule judges: `:instance` (the default) or `:class`. On `requires`, `scope:` instead sets the scope of the required sibling.
