In RuboCop, what is the difference between rubocop -a and rubocop -A, and how do a cop's Safe and SafeAutoCorrect settings decide what -a changes?
answer
- -a is --autocorrect, -A is --autocorrect-all
- Safe: false means possible false positives
- SafeAutoCorrect: false means the fix may change behaviour
- -a needs both to be true
- -x fixes Layout only
basics
~20 srubocop -a applies only corrections RuboCop marks safe; rubocop -A also applies unsafe ones that may change behaviour. A correction counts as safe only when the cop has both Safe and SafeAutoCorrect true, which is the default.
solid answer
~40 s`-a` (`--autocorrect`) applies **safe** corrections; `-A` (`--autocorrect-all`) applies every correction a cop offers, including **unsafe** ones. Safety comes from two cop settings, both `true` unless a cop's default config says otherwise. `Safe: false` means the cop can flag code that is fine by design: `Style/SymbolProc` turns `map { |x| x.name }` into `map(&:name)`, but a `Symbol#to_proc` proc checks arity like a lambda, so the rewrite is not always equivalent. `SafeAutoCorrect: false` means the offense is real but the fix can change behaviour: `Style/FrozenStringLiteralComment` adds `# frozen_string_literal: true`, after which a later `<<` on a literal raises `FrozenError`. With `-a`, RuboCop corrects only when both settings are true; with `-A` it ignores them. `-x` (`--fix-layout`) corrects `Layout` cops only. A project can mark a cop unsafe by setting `SafeAutoCorrect: false` for it in `.rubocop.yml`.
code
ruby · 12 lines# before `rubocop -A` (no magic comment: literals are chilled)
buffer = ""
buffer << "header\n" # works; warns only with deprecation warnings on
# after Style/FrozenStringLiteralComment's unsafe correction:
# frozen_string_literal: true
buffer = ""
buffer << "header\n" # raises FrozenError
# the manual fix
buffer = +""
buffer << "header\n"go deeper
Recall that -a applies safe corrections, -A applies unsafe ones as well, and -x touches only Layout; read the diff after either.
Explain Safe versus SafeAutoCorrect with one example each, such as Style/SymbolProc and Style/FrozenStringLiteralComment, and why -a needs both true.
Show how you would run -A on a real codebase: one cop at a time, tests between steps, and SafeAutoCorrect: false for cops whose fixes your code cannot take.
Frame the choice as a trust contract: tooling that rewrites code without review must stay on -a, while -A belongs in reviewed, reversible clean-up changes.
## Three autocorrect modes RuboCop can rewrite code to remove the offenses it finds. Which rewrites it performs depends on the flag: | Flag | Long form | What it corrects | |---|---|---| | `-a` | `--autocorrect` | only corrections marked **safe** | | `-A` | `--autocorrect-all` | every correction, **safe and unsafe** | | `-x` | `--fix-layout` | only cops in the `Layout` department | The old spellings `--auto-correct`, `--safe-auto-correct` and `--auto-correct-all` still work but print a deprecation warning pointing to the new names. In normal output, an offense RuboCop can fix carries a `[Correctable]` tag. ## What "safe" means: two settings Every cop has two booleans in its configuration, and both default to `true` when a cop's entry does not set them. - **`Safe`** - whether the cop can yield **false positives by design**. A cop with `Safe: false` may flag code that is actually correct, because it cannot know enough from the syntax alone. If a cop is unsafe, its correction is unsafe too. - **`SafeAutoCorrect`** - whether the **correction preserves behaviour**. A cop can be right that an offense exists while its fix still changes what the program does. `-a` corrects an offense only when both are `true`. `-A` applies the correction regardless. The `--safe` flag goes further and runs only cops with `Safe` true at all. ## Examples from RuboCop's defaults 1. **`Style/SymbolProc`** (`Safe: false`). It suggests `names.map(&:upcase)` for `names.map { |n| n.upcase }`. A proc made by `Symbol#to_proc` behaves like a lambda and raises `ArgumentError` when called with the wrong number of arguments, while a block-made proc does not, so the two are not always interchangeable. 2. **`Style/ZeroLengthPredicate`** (`Safe: false`). It prefers `empty?` to `length == 0`, which is only equivalent when the receiver's `empty?` is defined in terms of `length`. 3. **`Style/FrozenStringLiteralComment`** (`SafeAutoCorrect: false`). The offense is real: the magic comment is missing. But inserting `# frozen_string_literal: true` freezes every literal in the file, so code that appends to a literal (`buffer = ""; buffer << line`) starts raising `FrozenError`. In Ruby 4.0, literals without the comment are only *chilled*: mutating one warns when deprecation warnings are on, and still succeeds. 4. **`Style/SafeNavigation`** (`SafeAutoCorrect: false`). Rewriting `user && user.name` to `user&.name` differs when `user` is `false`: the first returns `false`, the second raises `NoMethodError`. 5. **`Style/MutableConstant`** (`SafeAutoCorrect: false`). Appending `.freeze` to a constant's literal turns any later mutation of it into a `FrozenError`. ## How the markers surface - In a generated `.rubocop_todo.yml`, each entry says either `This cop supports safe autocorrection (--autocorrect).` or `This cop supports unsafe autocorrection (--autocorrect-all).` - A project can override a cop's safety in `.rubocop.yml`, for example `SafeAutoCorrect: false` on a cop whose fix broke something locally, so `-a` stops applying it. - The `AutoCorrect` key (`always`, `contextual`, `disabled`) switches a cop's correction off entirely, whatever the flag. ## One file, three flags Take a file with a missing magic comment, a `map { |u| u.email }`, a `user && user.name`, and a line indented with three spaces: - **`rubocop -x`** fixes the indentation only. Nothing else in the file is a `Layout` offense. - **`rubocop -a`** fixes the indentation and every other safe offense, but leaves the magic comment, the `map` block and the `&&` chain alone, because their cops are marked unsafe; they stay in the report as correctable offenses. - **`rubocop -A`** fixes all four: it adds `# frozen_string_literal: true`, rewrites the block to `map(&:email)` and the chain to `user&.name`. Whether the program still behaves the same now depends on what the rest of the file does with those literals and whether `user` can be `false`. After `-a`, the offenses left over are exactly the ones a human should decide. ## Choosing a flag - **Editors and pre-commit hooks:** `-a`, because nobody reviews each change. - **A deliberate clean-up:** `-A`, one cop at a time, with the test suite run and the diff read before committing. - **Formatting only:** `-x`, when a pull request should touch whitespace and nothing else. `-A` is not "more thorough -a"; it is a different contract. `-a` promises not to change behaviour, within what the cop authors know; `-A` promises only that the code will satisfy the cops.
- How do you stop -a from applying a correction that broke code in your project, without disabling the cop?Set `SafeAutoCorrect: false` for that cop in `.rubocop.yml`. RuboCop keeps reporting the offense, but `-a` treats the correction as unsafe and skips it; only `-A` applies it. To forbid the correction under every flag, set `AutoCorrect: disabled` instead.
- What is the difference between Safe: false and SafeAutoCorrect: false on a RuboCop cop?`Safe: false` says the cop itself can be wrong: it may flag code that is fine, so both its offense and its correction are suspect. `SafeAutoCorrect: false` says the offense is trustworthy but the rewrite can change behaviour. `-a` skips the correction in both cases, and `--safe` additionally skips cops with `Safe: false` entirely.
saying these in an interview costs you the question
- rubocop -A is just a more thorough -a and never changes behaviour.
- A cop marked Safe: false is broken and should be disabled.
- rubocop -a applies every correction a cop offers.
- SafeAutoCorrect: false means the cop's offense is a false positive.
- rubocop -x corrects Lint and Style offenses too.