= Source Code Directives

RuboCop can be controlled within your source code using special comments.
These directives let you disable or enable cops for specific sections of a file,
without changing your `.rubocop.yml` configuration.

== Disabling Cops within Source Code

One or more individual cops can be disabled locally in a section of a
file by adding a comment such as

[source,ruby]
----
# rubocop:disable Layout/LineLength, Style/StringLiterals
[...]
# rubocop:enable Layout/LineLength, Style/StringLiterals
----

You can also disable entire departments by giving a department name in the comment.

[source,ruby]
----
# rubocop:disable Metrics, Layout/LineLength
[...]
# rubocop:enable Metrics, Layout/LineLength
----

You can also disable _all_ cops with

[source,ruby]
----
# rubocop:disable all
[...]
# rubocop:enable all
----

In cases where you want to differentiate intentionally-disabled cops vs. cops
you'd like to revisit later, you can use `rubocop:todo` as an alias of
`rubocop:disable`.

[source,ruby]
----
# rubocop:todo Layout/LineLength, Style/StringLiterals
[...]
# rubocop:enable Layout/LineLength, Style/StringLiterals
----

One or more cops can be disabled on a single line with an end-of-line
comment.

[source,ruby]
----
for x in (0..19) # rubocop:disable Style/For
----

If you want to disable a cop that inspects comments, you can do so by
adding an "inner comment" on the comment line.

[source,ruby]
----
# coding: utf-8 # rubocop:disable Style/Encoding
----

Running `rubocop --autocorrect --disable-uncorrectable` will
create comments to disable all offenses that can't be automatically
corrected.

You can add a comment to the disabling/enabling directive by prefixing it with `--`. For example:

[source,ruby]
----
# rubocop:disable Layout/LineLength -- A comment explaining why the cop is disabled
----

The syntax of directives can be checked using the cop `Lint/CopDirectiveSyntax`.

== Temporarily Enabling Cops in Source Code

In a similar way to disabling cops within source code, you can also temporarily enable specific
cops if you want to enforce specific rules for part of a file.

Let's use the cop `Style/AsciiComments`, which is by default `Enabled: false`. Say you want a
specific file to have ASCII-only comments to be compatible with some post-processing tool:

[source,ruby]
----
# rubocop:enable Style/AsciiComments
# If applicable, leave a comment to others explaining the rationale:
# We need the comments to remain ASCII only for compatibility with lib/post_processor.rb

class Restaurant
  # This comment has to be ASCII-only because of the rubocop:enable directive
  def menu
    return dishes.map(&:humanize)
  end
end
----

You can also enforce the same for part of a file by disabling the cop afterwards

[source,ruby]
----
class Dish
  def humanize
    return [
      "Delicious #{self.name}"
      *ingredients
    ].join("\n")
  end
end

# rubocop:enable Style/AsciiComments
# If applicable, leave a comment to others explaining the rationale:
# We need the comments to remain ASCII only for compatibility with lib/post_processor.rb

class Restaurant
  # This comment has to be ASCII-only because of the rubocop:enable directive
  def menu
    return dishes.map(&:humanize)
  end
end

# rubocop:disable Style/AsciiComments

class Ingredient
  # Notice how the comment below is non-ASCII
  # Gets rid of odd characters like 😀, ͸
  def sanitize
    self.name.gsub(/[^a-z]/, '')
  end
end
----

NOTE: If a file is excluded via configuration (e.g., in `.rubocop.yml` or `.rubocop_todo.yml`),
`rubocop:enable` comments within that file will have no effect. Configuration-based exclusions take
precedence over in-source opt-in directives.

== Scoped Disabling with Push/Pop Directives

When you want to temporarily change cop settings for a specific section of code
and then automatically restore the previous state, you can use `rubocop:push` and
`rubocop:pop` directives. This is particularly useful when you need to disable
cops for a block of code without affecting the rest of the file.

=== Basic Push/Pop Usage

The `push` directive saves the current state of all cop settings, and `pop`
restores them:

[source,ruby]
----
def process_data(input)
  result = input.upcase
  # rubocop:push
  # rubocop:disable Style/GuardClause
  if result.present?
    return result.strip
  end
  # rubocop:pop
  nil
end
----

After `pop`, the `Style/GuardClause` cop is automatically re-enabled, returning
to its state before `push`.

=== Inline Push Arguments

For convenience, you can combine `push` with enable/disable operations using
inline arguments. Use `-` to disable a cop and `+` to enable a cop:

[source,ruby]
----
def process_data(input)
  result = input.upcase
  # rubocop:push -Style/GuardClause
  if result.present?
    return result.strip
  end
  # rubocop:pop
  nil
end
----

You can specify multiple cops with different operations:

[source,ruby]
----
# rubocop:disable Style/For
for x in [1, 2, 3]
  puts x
end
# rubocop:push +Style/For -Style/GuardClause
for y in [4, 5, 6]  # Style/For is re-enabled here
  if y > 0
    return y        # Style/GuardClause is disabled here
  end
end
# rubocop:pop
# Back to original state: Style/For disabled, Style/GuardClause enabled
----

=== Nested Push/Pop

Push/pop directives can be nested for complex scenarios:

[source,ruby]
----
# rubocop:disable Metrics/MethodLength
def complex_method
  step1
  # rubocop:push
  # rubocop:enable Metrics/MethodLength
  # rubocop:disable Style/GuardClause
  def helper_method
    # rubocop:push
    # rubocop:enable Style/GuardClause
    if condition
      return value
    end
    # rubocop:pop
    other_code
  end
  # rubocop:pop
  step2
end
----

Each `pop` restores the state to what it was at the corresponding `push`.
