diff --git a/.circleci/config.yml b/.circleci/config.yml index d32aebde7f19..650832912a04 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,3 +1,5 @@ +### +# Please keep /.mergify.yml synced! version: 2 jruby_env: &jruby_env @@ -40,56 +42,10 @@ rubocop_steps: &rubocop_steps name: Check requiring libraries successfully # See https://github.com/rubocop-hq/rubocop/pull/4523#issuecomment-309136113 command: | - ruby -I lib -r rubocop -e 'exit 0' + ruby -I lib -r bundler/setup -r rubocop -e 'exit 0' jobs: - # Ruby 2.2 - ruby-2.2-spec: - docker: - - image: circleci/ruby:2.2 - environment: - <<: *common_env - steps: - *spec_steps - ruby-2.2-ascii_spec: - docker: - - image: circleci/ruby:2.2 - environment: - <<: *common_env - steps: - *ascii_spec_steps - ruby-2.2-rubocop: - docker: - - image: circleci/ruby:2.2 - environment: - <<: *common_env - steps: - *rubocop_steps - - # Ruby 2.3 - ruby-2.3-spec: - docker: - - image: circleci/ruby:2.3 - environment: - <<: *common_env - steps: - *spec_steps - ruby-2.3-ascii_spec: - docker: - - image: circleci/ruby:2.3 - environment: - <<: *common_env - steps: - *ascii_spec_steps - ruby-2.3-rubocop: - docker: - - image: circleci/ruby:2.3 - environment: - <<: *common_env - steps: - *rubocop_steps - # Ruby 2.4 ruby-2.4-spec: docker: @@ -159,43 +115,48 @@ jobs: steps: *rubocop_steps - # ruby-head (nightly snapshot build) - ruby-head-spec: + # Ruby 2.7 + ruby-2.7-spec: docker: - - image: rubocophq/circleci-ruby-snapshot:latest + - image: circleci/ruby:2.7 environment: <<: *common_env steps: *spec_steps - ruby-head-ascii_spec: + ruby-2.7-ascii_spec: docker: - - image: rubocophq/circleci-ruby-snapshot:latest + - image: circleci/ruby:2.7 environment: <<: *common_env steps: *ascii_spec_steps - ruby-head-rubocop: + ruby-2.7-rubocop: docker: - - image: rubocophq/circleci-ruby-snapshot:latest + - image: circleci/ruby:2.7 environment: <<: *common_env steps: *rubocop_steps - # With JIT compiler enabled! - ruby-head-spec-with-jit: + # ruby-head (nightly snapshot build) + ruby-head-spec: docker: - image: rubocophq/circleci-ruby-snapshot:latest environment: - RUBYOPT: '--jit' <<: *common_env steps: *spec_steps - ruby-head-rubocop-with-jit: + ruby-head-ascii_spec: + docker: + - image: rubocophq/circleci-ruby-snapshot:latest + environment: + <<: *common_env + steps: + *ascii_spec_steps + ruby-head-rubocop: docker: - image: rubocophq/circleci-ruby-snapshot:latest environment: - RUBYOPT: '--jit' <<: *common_env steps: *rubocop_steps @@ -258,7 +219,7 @@ jobs: - run: name: Upload coverage results to Code Climate command: | - ./tmp/cc-test-reporter sum-coverage tmp/codeclimate.*.json --parts 6 --output tmp/codeclimate.total.json + ./tmp/cc-test-reporter sum-coverage tmp/codeclimate.*.json --parts 5 --output tmp/codeclimate.total.json ./tmp/cc-test-reporter upload-coverage --input tmp/codeclimate.total.json # Miscellaneous tasks @@ -274,8 +235,8 @@ jobs: name: Check documentation syntax command: bundle exec rake documentation_syntax_check - run: - name: Build documentation and check that manual files are in sync - command: bundle exec rake generate_cops_documentation + name: Build documentation and verify that doc files are in sync + command: bundle exec rake verify_cops_documentation workflows: version: 2 @@ -283,16 +244,6 @@ workflows: jobs: - documentation-checks - cc-setup - - ruby-2.2-spec: - requires: - - cc-setup - - ruby-2.2-ascii_spec - - ruby-2.2-rubocop - - ruby-2.3-spec: - requires: - - cc-setup - - ruby-2.3-ascii_spec - - ruby-2.3-rubocop - ruby-2.4-spec: requires: - cc-setup @@ -308,15 +259,16 @@ workflows: - cc-setup - ruby-2.6-ascii_spec - ruby-2.6-rubocop - - ruby-head-spec: + - ruby-2.7-spec: requires: - cc-setup - - ruby-head-spec-with-jit: + - ruby-2.7-ascii_spec + - ruby-2.7-rubocop + - ruby-head-spec: requires: - cc-setup - ruby-head-ascii_spec - ruby-head-rubocop - - ruby-head-rubocop-with-jit - jruby-9.2-spec: requires: - cc-setup @@ -325,9 +277,8 @@ workflows: - cc-upload-coverage: requires: - - ruby-2.2-spec - - ruby-2.3-spec - ruby-2.4-spec - ruby-2.5-spec - ruby-2.6-spec + - ruby-2.7-spec - jruby-9.2-spec diff --git a/.dir-locals.el b/.dir-locals.el new file mode 100644 index 000000000000..515b86c74ab8 --- /dev/null +++ b/.dir-locals.el @@ -0,0 +1,12 @@ +;;; Directory Local Variables +;;; For more information see (info "(emacs) Directory Variables") + +((ruby-mode + (bug-reference-url-format . "https://github.com/rubocop-hq/rubocop/issues/%s") + (bug-reference-bug-regexp . "#\\(?2:[[:digit:]]+\\)") + (indent-tabs-mode . nil) + (fill-column . 100))) + +;; To use the bug-reference stuff, do: +;; (add-hook 'text-mode-hook #'bug-reference-mode) +;; (add-hook 'prog-mode-hook #'bug-reference-prog-mode) diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000000..826c9ea2455a --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,7 @@ +# These are supported funding model platforms + +github: [bbatsov, koic] +patreon: bbatsov +open_collective: rubocop +tidelift: "rubygems/rubocop" +custom: https://www.paypal.me/bbatsov diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 41271f78a9b9..adbd06c4efc3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -23,6 +23,7 @@ Describe here how you expected RuboCop to behave in this particular situation. ## Actual behavior Describe here what actually happened. +Please use `rubocop --debug` when pasting rubocop output as it contains additional information. ## Steps to reproduce the problem @@ -35,5 +36,5 @@ Include the output of `rubocop -V` or `bundle exec rubocop -V` if using Bundler. ``` $ [bundle exec] rubocop -V -0.66.0 (using Parser 2.5.1.2, running on ruby 2.5.1 x86_64-linux) +0.93.1 (using Parser 2.5.1.2, running on ruby 2.5.1 x86_64-linux) ``` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 0a797194d8ac..0b738d8c4676 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -11,8 +11,7 @@ Before submitting the PR make sure the following are checked: * [ ] Squashed related commits together. * [ ] Added tests. * [ ] Added an entry to the [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md) if the new code introduces user-observable changes. See [changelog entry format](https://github.com/rubocop-hq/rubocop/blob/master/CONTRIBUTING.md#changelog-entry-format). -* [ ] The PR relates to *only* one subject with a clear title - and description in grammatically correct, complete sentences. +* [ ] The PR relates to *only* one subject with a clear title and description in grammatically correct, complete sentences. * [ ] Run `bundle exec rake default`. It executes all tests and RuboCop for itself, and generates the documentation. [1]: https://chris.beams.io/posts/git-commit/ diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000000..c1da94f77a0c --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,62 @@ +# Configuration for probot-stale - https://github.com/probot/stale + +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 180 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 90 + +# Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - "high priority" + - "good first issue" + - "pinned" + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: true + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: true + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contribution and understanding! + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +closeComment: > + This issues been automatically closed due to lack of activity. Feel free to re-open it + if you ever come back to it. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed diff --git a/.github/workflows/rubocop.yml b/.github/workflows/rubocop.yml new file mode 100644 index 000000000000..7ad60f6164c2 --- /dev/null +++ b/.github/workflows/rubocop.yml @@ -0,0 +1,47 @@ +### +# Please keep /.mergify.yml synced! +name: CI + +on: [push, pull_request] + +jobs: + main: + name: >- + ${{ matrix.os }} ${{ matrix.ruby }} + runs-on: ${{ matrix.os }}-latest + env: + # See https://github.com/tmm1/test-queue#environment-variables + TEST_QUEUE_WORKERS: 2 + strategy: + fail-fast: false + matrix: + # [ ubuntu, macos, windows ] + os: [ windows ] + ruby: [ 2.4, 2.5, 2.6, 2.7, head ] + include: + - { os: windows, ruby: mingw } + exclude: + - { os: windows, ruby: head } + + steps: + - name: windows misc + if: matrix.os == 'windows' + run: | + # set TMPDIR, git core.autocrlf + echo "::set-env name=TMPDIR::$env:RUNNER_TEMP" + git config --system core.autocrlf false + - name: checkout + uses: actions/checkout@v2 + - name: set up Ruby + uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + + - name: install dependencies + run: bundle install --jobs 3 --retry 3 + - name: spec + run: bundle exec rake spec + - name: ascii_spec + run: bundle exec rake ascii_spec + - name: internal_investigation + run: bundle exec rake internal_investigation diff --git a/.gitignore b/.gitignore index b9dc26c85146..b90a35666a1a 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,9 @@ pkg # etags TAGS +# byebug +.byebug_history + # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: # # * Create a file at ~/.gitignore @@ -59,3 +62,10 @@ TAGS # For rubinius: #*.rbc + +# For bundle binstubs +bin/* +!bin/rubocop-profile + +# For stackprof or others +tmp/* diff --git a/.mergify.yml b/.mergify.yml new file mode 100644 index 000000000000..1d48a061a007 --- /dev/null +++ b/.mergify.yml @@ -0,0 +1,43 @@ +pull_request_rules: + - name: automatic merge for master when reviewed and CI passes + actions: + merge: + method: rebase + conditions: + - base=master + - label=auto-merge + - "#review-requested=0" + - "#changes-requested-reviews-by=0" + - "status-success=windows 2.4" + - "status-success=windows 2.5" + - "status-success=windows 2.6" + - "status-success=windows 2.7" + - "status-success=windows mingw" + - "status-success=ci/circleci: cc-setup" + - "status-success=ci/circleci: cc-upload-coverage" + - "status-success=ci/circleci: documentation-checks" + - "status-success=ci/circleci: jruby-9.2-ascii_spec" + - "status-success=ci/circleci: jruby-9.2-rubocop" + - "status-success=ci/circleci: jruby-9.2-spec" + - "status-success=ci/circleci: ruby-2.4-ascii_spec" + - "status-success=ci/circleci: ruby-2.4-rubocop" + - "status-success=ci/circleci: ruby-2.4-spec" + - "status-success=ci/circleci: ruby-2.5-ascii_spec" + - "status-success=ci/circleci: ruby-2.5-rubocop" + - "status-success=ci/circleci: ruby-2.5-spec" + - "status-success=ci/circleci: ruby-2.6-ascii_spec" + - "status-success=ci/circleci: ruby-2.6-rubocop" + - "status-success=ci/circleci: ruby-2.6-spec" + - "status-success=ci/circleci: ruby-2.7-ascii_spec" + - "status-success=ci/circleci: ruby-2.7-rubocop" + - "status-success=ci/circleci: ruby-2.7-spec" + - "status-success=ci/circleci: ruby-head-ascii_spec" + - "status-success=ci/circleci: ruby-head-rubocop" + - "status-success=ci/circleci: ruby-head-spec" + - name: delete head branch after auto-merge + conditions: + - merged + - label=auto-merge + actions: + delete_head_branch: {} + diff --git a/.rubocop.yml b/.rubocop.yml index c419966d2568..4a8e63e46866 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,14 +3,18 @@ inherit_from: .rubocop_todo.yml require: - rubocop/cop/internal_affairs + - rubocop-performance - rubocop-rspec AllCops: + NewCops: enable Exclude: - 'vendor/**/*' - 'spec/fixtures/**/*' - 'tmp/**/*' - TargetRubyVersion: 2.2 + - '.git/**/*' + - 'bin/*' + TargetRubyVersion: 2.4 Naming/PredicateName: # Method define macros for dynamically generated method. @@ -20,8 +24,10 @@ Naming/PredicateName: - def_node_matcher - def_node_search -Style/FrozenStringLiteralComment: - EnforcedStyle: always +Style/AccessorGrouping: + Exclude: + - lib/rubocop/formatter/base_formatter.rb + - lib/rubocop/cop/offense.rb Style/FormatStringToken: # Because we parse a lot of source codes from strings. Percent arrays @@ -53,17 +59,26 @@ Layout/ClassStructure: - protected_methods - private_methods -Layout/IndentHeredoc: - EnforcedStyle: powerpack - -# Trailing white space is meaningful in code examples Layout/TrailingWhitespace: - AllowInHeredoc: true + AllowInHeredoc: false Lint/AmbiguousBlockAssociation: Exclude: - 'spec/**/*.rb' +Layout/HashAlignment: + EnforcedHashRocketStyle: + - key + - table + EnforcedColonStyle: + - key + - table + +Layout/LineLength: + Max: 100 + IgnoredPatterns: + - !ruby/regexp /\A +(it|describe|context|shared_examples|include_examples|it_behaves_like) ["']/ + Lint/InterpolationCheck: Exclude: - 'spec/**/*.rb' @@ -83,16 +98,23 @@ Metrics/BlockLength: - 'spec/**/*.rb' - '**/*.gemspec' +Metrics/ClassLength: + Exclude: + - lib/rubocop/config_obsoletion.rb + Metrics/ModuleLength: Exclude: - 'spec/**/*.rb' -Performance/Caller: +RSpec/FilePath: Exclude: - - spec/rubocop/cop/performance/caller_spec.rb + - spec/rubocop/formatter/junit_formatter_spec.rb RSpec/PredicateMatcher: EnforcedStyle: explicit +RSpec/MessageSpies: + EnforcedStyle: receive + RSpec/NestedGroups: Max: 7 diff --git a/.rubocop_todo.yml b/.rubocop_todo.yml index b2f056c283f3..3f72042d1eb4 100644 --- a/.rubocop_todo.yml +++ b/.rubocop_todo.yml @@ -1,74 +1,70 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2019-01-03 17:29:56 +0800 using RuboCop version 0.62.0. +# on 2020-06-12 17:42:47 UTC using RuboCop version 0.85.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new # versions of RuboCop, may require this file to be generated again. -# Offense count: 77 -Metrics/AbcSize: - Max: 17 +# Offense count: 79 +InternalAffairs/NodeDestructuring: + Enabled: false -# Offense count: 52 +# Offense count: 48 # Configuration parameters: CountComments. Metrics/ClassLength: - Max: 181 + Max: 186 -# Offense count: 222 +# Offense count: 198 # Configuration parameters: CountComments, ExcludedMethods. Metrics/MethodLength: Max: 14 -# Offense count: 5 +# Offense count: 8 # Configuration parameters: CountComments. Metrics/ModuleLength: - Max: 141 + Max: 132 -# Offense count: 12 +# Offense count: 10 RSpec/AnyInstance: Exclude: - 'spec/rubocop/cli_spec.rb' - 'spec/rubocop/cop/lint/duplicate_methods_spec.rb' - - 'spec/rubocop/runner_spec.rb' + - 'spec/rubocop/cop/team_spec.rb' - 'spec/rubocop/target_finder_spec.rb' -# Offense count: 1071 +# Offense count: 981 # Configuration parameters: Prefixes. # Prefixes: when, with, without RSpec/ContextWording: Enabled: false -# Offense count: 3313 +# Offense count: 3810 # Configuration parameters: Max. RSpec/ExampleLength: Enabled: false -# Offense count: 42 +# Offense count: 38 RSpec/ExpectOutput: Exclude: - 'spec/rubocop/cli/cli_auto_gen_config_spec.rb' - 'spec/rubocop/cli/cli_options_spec.rb' - 'spec/rubocop/config_spec.rb' - 'spec/rubocop/cop/cop_spec.rb' - - 'spec/rubocop/formatter/base_formatter_spec.rb' - 'spec/rubocop/formatter/disabled_config_formatter_spec.rb' - 'spec/rubocop/formatter/formatter_set_spec.rb' - 'spec/rubocop/options_spec.rb' - 'spec/rubocop/rake_task_spec.rb' - 'spec/rubocop/result_cache_spec.rb' - 'spec/rubocop/target_finder_spec.rb' - - 'spec/support/cli_spec_behavior.rb' -# Offense count: 528 -# Configuration parameters: AggregateFailuresByDefault. +# Offense count: 434 RSpec/MultipleExpectations: Max: 25 -# Offense count: 11 +# Offense count: 5 RSpec/SubjectStub: Exclude: - 'spec/rubocop/config_spec.rb' - - 'spec/rubocop/cop/cop_spec.rb' - 'spec/rubocop/formatter/json_formatter_spec.rb' - 'spec/rubocop/formatter/progress_formatter_spec.rb' diff --git a/.simplecov b/.simplecov index 869c7c0db8bd..8f9fa266e0c6 100644 --- a/.simplecov +++ b/.simplecov @@ -1,3 +1,5 @@ +# frozen_string_literal: true + SimpleCov.start do add_filter '/spec/' add_filter '/vendor/bundle/' diff --git a/CHANGELOG.md b/CHANGELOG.md index d7e0e495b8f8..6b09e1597ec4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,1012 @@ ## master (unreleased) +## 0.93.1 (2020-10-12) + +### Bug fixes + +* [#8782](https://github.com/rubocop-hq/rubocop/issues/8782): Fix incorrect autocorrection for `Style/TernaryParentheses` with `defined?`. ([@dvandersluis][]) +* [#8867](https://github.com/rubocop-hq/rubocop/issues/8867): Rework `Lint/RedundantSafeNavigation` to be more safe. ([@fatkodima][]) +* [#8864](https://github.com/rubocop-hq/rubocop/issues/8864): Fix false positive for `Style/RedundantBegin` with a postfix `while` or `until`. ([@dvandersluis][]) +* [#8869](https://github.com/rubocop-hq/rubocop/issues/8869): Fix a false positive for `Style/RedundantBegin` when using `begin` for or assignment and method call. ([@koic][]) +* [#8862](https://github.com/rubocop-hq/rubocop/issues/8862): Fix an error for `Lint/AmbiguousRegexpLiteral` when using regexp without method calls in nested structure. ([@koic][]) +* [#8872](https://github.com/rubocop-hq/rubocop/issues/8872): Fix an error for `Metrics/ClassLength` when multiple assignments to constants. ([@koic][]) +* [#8871](https://github.com/rubocop-hq/rubocop/issues/8871): Fix a false positive for `Style/RedundantBegin` when using `begin` for method argument or part of conditions. ([@koic][]) +* [#8875](https://github.com/rubocop-hq/rubocop/issues/8875): Fix an incorrect auto-correct for `Style/ClassEqualityComparison` when comparing class name. ([@koic][]) +* [#8880](https://github.com/rubocop-hq/rubocop/issues/8880): Fix an error for `Style/ClassLength` when overlapping constant assignments. ([@koic][]) + +## 0.93.0 (2020-10-08) + +### New features + +* [#8796](https://github.com/rubocop-hq/rubocop/pull/8796): Add new `Lint/HashCompareByIdentity` cop. ([@fatkodima][]) +* [#8833](https://github.com/rubocop-hq/rubocop/pull/8833): Add new `Style/ClassEqualityComparison` cop. ([@fatkodima][]) +* [#8668](https://github.com/rubocop-hq/rubocop/pull/8668): Add new `Lint/RedundantSafeNavigation` cop. ([@fatkodima][]) +* [#8842](https://github.com/rubocop-hq/rubocop/issues/8842): Add notification about cache being used to debug mode. ([@hatkyinc2][]) +* [#8822](https://github.com/rubocop-hq/rubocop/pull/8822): Make `Style/RedundantBegin` aware of `begin` without `rescue` or `ensure`. ([@koic][]) + +### Bug fixes + +* [#8810](https://github.com/rubocop-hq/rubocop/pull/8810): Fix multiple offense detection for `Style/RaiseArgs`. ([@pbernays][]) +* [#8151](https://github.com/rubocop-hq/rubocop/issues/8151): Fix a false positive for `Lint/BooleanSymbol` when used within `%i[...]`. ([@fatkodima][]) +* [#8809](https://github.com/rubocop-hq/rubocop/pull/8809): Fix multiple offense detection for `Style/For`. ([@pbernays][]) +* [#8801](https://github.com/rubocop-hq/rubocop/issues/8801): Fix `Layout/SpaceAroundEqualsInParameterDefault` only registered once in a line. ([@rdunlop][]) +* [#8514](https://github.com/rubocop-hq/rubocop/issues/8514): Correct multiple `Style/MethodDefParentheses` per file. ([@rdunlop][]) +* [#8825](https://github.com/rubocop-hq/rubocop/issues/8825): Fix crash in `Style/ExplicitBlockArgument` when code is called outside of a method. ([@ghiculescu][]) +* [#8718](https://github.com/rubocop-hq/rubocop/issues/8718): Fix undefined methods of pseudo location. ([@ybiquitous][]) +* [#8354](https://github.com/rubocop-hq/rubocop/issues/8354): Detect regexp named captures in `Style/CaseLikeIf` cop. ([@dsavochkin][]) +* [#8821](https://github.com/rubocop-hq/rubocop/issues/8821): Fix an incorrect autocorrect for `Style/NestedTernaryOperator` when using a nested ternary operator expression with no parentheses on the outside. ([@koic][]) +* [#8834](https://github.com/rubocop-hq/rubocop/issues/8834): Fix a false positive for `Style/ParenthesesAsGroupedExpression` when method argument parentheses are omitted and hash argument key is enclosed in parentheses. ([@koic][]) +* [#8830](https://github.com/rubocop-hq/rubocop/issues/8830): Fix bad autocorrect of `Style/StringConcatenation` when string includes double quotes. ([@tleish][]) +* [#8807](https://github.com/rubocop-hq/rubocop/pull/8807): Fix a false positive for `Style/RedundantCondition` when using assignment by hash key access. ([@koic][]) +* [#8848](https://github.com/rubocop-hq/rubocop/issues/8848): Fix a false positive for `Style/CombinableLoops` when using the same method with different arguments. ([@dvandersluis][]) +* [#8843](https://github.com/rubocop-hq/rubocop/issues/8843): Fix an incorrect autocorrect for `Lint/AmbiguousRegexpLiteral` when sending method to regexp literal receiver. ([@koic][]) +* [#8842](https://github.com/rubocop-hq/rubocop/issues/8842): Save actual status to cache, except corrected. ([@hatkyinc2][]) +* [#8835](https://github.com/rubocop-hq/rubocop/issues/8835): Fix an incorrect autocorrect for `Style/RedundantInterpolation` when using string interpolation for non-operator methods. ([@koic][]) +* [#7495](https://github.com/rubocop-hq/rubocop/issues/7495): Example for `Lint/AmbiguousBlockAssociation` cop. ([@AllanSiqueira][]) +* [#8855](https://github.com/rubocop-hq/rubocop/issues/8855): Fix an error for `Layout/EmptyLinesAroundAccessModifier` and `Style/AccessModifierDeclarations` when using only access modifier. ([@koic][]) + +### Changes + +* [#8803](https://github.com/rubocop-hq/rubocop/pull/8803): **(Breaking)** `RegexpNode#parsed_tree` now processes regexps including interpolation (by blanking the interpolation before parsing, rather than skipping). ([@owst][]) +* [#8625](https://github.com/rubocop-hq/rubocop/pull/8625): Improve `Style/RedundantRegexpCharacterClass` and `Style/RedundantRegexpEscape` by using `regexp_parser` gem. ([@owst][]) +* [#8646](https://github.com/rubocop-hq/rubocop/issues/8646): Faster find of all files in `TargetFinder` class which improves initial startup speed. ([@tleish][]) +* [#8102](https://github.com/rubocop-hq/rubocop/issues/8102): Consider class length instead of block length for `Struct.new`. ([@tejasbubane][]) +* [#7408](https://github.com/rubocop-hq/rubocop/issues/7408): Make `Gemspec/RequiredRubyVersion` cop aware of `Gem::Requirement`. ([@tejasbubane][]) + +## 0.92.0 (2020-09-25) + +### New features + +* [#8778](https://github.com/rubocop-hq/rubocop/pull/8778): Add command line option `--regenerate-todo`. ([@dvandersluis][]) +* [#8790](https://github.com/rubocop-hq/rubocop/pull/8790): Add `AllowedMethods` option to `Style/OptionalBooleanParameter` cop. ([@fatkodima][]) +* [#8738](https://github.com/rubocop-hq/rubocop/issues/8738): Add autocorrection to `Style/DateTime`. ([@dvandersluis][]) + +### Bug fixes + +* [#8774](https://github.com/rubocop-hq/rubocop/issues/8774): Fix a false positive for `Layout/ArrayAlignment` with parallel assignment. ([@dvandersluis][]) + +### Changes + +* [#8785](https://github.com/rubocop-hq/rubocop/pull/8785): Update TargetRubyVersion 2.8 to 3.0 (experimental). ([@koic][]) +* [#8650](https://github.com/rubocop-hq/rubocop/issues/8650): Faster find of hidden files in `TargetFinder` class which improves rubocop initial startup speed. ([@tleish][]) +* [#8783](https://github.com/rubocop-hq/rubocop/pull/8783): Disable `Style/ArrayCoercion` cop by default. ([@koic][]) + +## 0.91.1 (2020-09-23) + +### Bug fixes + +* [#8720](https://github.com/rubocop-hq/rubocop/issues/8720): Fix an error for `Lint/IdentityComparison` when calling `object_id` method without receiver in LHS or RHS. ([@koic][]) +* [#8767](https://github.com/rubocop-hq/rubocop/issues/8767): Fix a false positive for `Style/RedundantReturn` when a rescue has an else clause. ([@fatkodima][]) +* [#8710](https://github.com/rubocop-hq/rubocop/issues/8710): Fix a false positive for `Layout/RescueEnsureAlignment` when `Layout/BeginEndAlignment` cop is not enabled status. ([@koic][]) +* [#8726](https://github.com/rubocop-hq/rubocop/issues/8726): Fix a false positive for `Naming/VariableNumber` when naming multibyte character variable name. ([@koic][]) +* [#8730](https://github.com/rubocop-hq/rubocop/issues/8730): Fix an error for `Lint/UselessTimes` when there is a blank line in the method definition. ([@koic][]) +* [#8740](https://github.com/rubocop-hq/rubocop/issues/8740): Fix a false positive for `Style/HashAsLastArrayItem` when the hash is in an implicit array. ([@dvandersluis][]) +* [#8739](https://github.com/rubocop-hq/rubocop/issues/8739): Fix an error for `Lint/UselessTimes` when using empty block argument. ([@koic][]) +* [#8742](https://github.com/rubocop-hq/rubocop/issues/8742): Fix some assignment counts for `Metrics/AbcSize`. ([@marcandre][]) +* [#8750](https://github.com/rubocop-hq/rubocop/pull/8750): Fix an incorrect auto-correct for `Style/MultilineWhenThen` when line break for multiple condidate values of `when` statement. ([@koic][]) +* [#8754](https://github.com/rubocop-hq/rubocop/pull/8754): Fix an error for `Style/RandomWithOffset` when using a range with non-integer bounds. ([@eugeneius][]) +* [#8756](https://github.com/rubocop-hq/rubocop/issues/8756): Fix an infinite loop error for `Layout/EmptyLinesAroundAccessModifier` with `Layout/EmptyLinesAroundBlockBody` when using access modifier with block argument. ([@koic][]) +* [#8372](https://github.com/rubocop-hq/rubocop/issues/8372): Fix `Lint/RedundantCopEnableDirective` autocorrection to not leave orphaned empty `# rubocop:enable` comments. ([@dvandersluis][]) +* [#8372](https://github.com/rubocop-hq/rubocop/issues/8372): Fix `Lint/RedundantCopDisableDirective` autocorrection. ([@dvandersluis][]) +* [#8764](https://github.com/rubocop-hq/rubocop/issues/8764): Fix `Layout/CaseIndentation` not showing the cop name in output messages. ([@dvandersluis][]) +* [#8771](https://github.com/rubocop-hq/rubocop/issues/8771): Fix an error for `Style/OneLineConditional` when using `if-then-elsif-then-end`. ([@koic][]) +* [#8576](https://github.com/rubocop-hq/rubocop/issues/8576): Fix `Style/IfUnlessModifier` to ignore cop disable comment directives when considering conversion to the modifier form. ([@dsavochkin][]) + +### Changes + +* [#8489](https://github.com/rubocop-hq/rubocop/issues/8489): Exclude method `respond_to_missing?` from `OptionalBooleanParameter` cop. ([@em-gazelle][]) +* [#7914](https://github.com/rubocop-hq/rubocop/issues/7914): `Style/SafeNavigation` marked as having unsafe auto-correction. ([@marcandre][]) +* [#8749](https://github.com/rubocop-hq/rubocop/issues/8749): Disable `Style/IpAddresses` by default in `Gemfile` and gemspec files. ([@dvandersluis][]) + +## 0.91.0 (2020-09-15) + +### New features + +* New option `--cache-root` and support for the `RUBOCOP_CACHE_ROOT` environment variable. Both can be used to override the `AllCops: CacheRootDirectory` config, especially in a CI setting. ([@sascha-wolf][]) +* [#8582](https://github.com/rubocop-hq/rubocop/issues/8582): Add new `Layout/BeginEndAlignment` cop. ([@koic][]) +* [#8699](https://github.com/rubocop-hq/rubocop/pull/8699): Add new `Lint/IdentityComparison` cop. ([@koic][]) +* Add new `Lint/UselessTimes` cop. ([@dvandersluis][]) +* [#8707](https://github.com/rubocop-hq/rubocop/pull/8707): Add new `Lint/ConstantDefinitionInBlock` cop. ([@eugeneius][]) + +### Bug fixes + +* [#8627](https://github.com/rubocop-hq/rubocop/issues/8627): Fix a false positive for `Lint/DuplicateRequire` when same feature argument but different require method. ([@koic][]) +* [#8674](https://github.com/rubocop-hq/rubocop/issues/8674): Fix an error for `Layout/EmptyLineAfterMultilineCondition` when conditional is at the top level. ([@fatkodima][]) +* [#8658](https://github.com/rubocop-hq/rubocop/pull/8658): Fix a false positive for `Style/RedundantSelfAssignment` when calling coercion methods. ([@fatkodima][]) +* [#8669](https://github.com/rubocop-hq/rubocop/issues/8669): Fix an offense creation for `Lint/EmptyFile`. ([@fatkodima][]) +* [#8607](https://github.com/rubocop-hq/rubocop/issues/8607): Fix a false positive for `Lint/UnreachableLoop` when conditional branch includes continue statement preceding break statement. ([@fatkodima][]) +* [#8572](https://github.com/rubocop-hq/rubocop/issues/8572): Fix a false positive for `Style/RedundantParentheses` when parentheses are used like method argument parentheses. ([@koic][]) +* [#8630](https://github.com/rubocop-hq/rubocop/issues/8630): Fix some false positives for `Style/HashTransformKeys` and `Style/HashTransformValues` when the receiver is an array. ([@eugeneius][]) +* [#8653](https://github.com/rubocop-hq/rubocop/pull/8653): Fix a false positive for `Layout/DefEndAlignment` when using refinements and `private def`. ([@koic][]) +* [#8655](https://github.com/rubocop-hq/rubocop/pull/8655): Fix a false positive for `Style/ClassAndModuleChildren` when using cbase class name. ([@koic][]) +* [#8654](https://github.com/rubocop-hq/rubocop/pull/8654): Fix a false positive for `Style/SafeNavigation` when checking `foo&.empty?` in a conditional. ([@koic][]) +* [#8660](https://github.com/rubocop-hq/rubocop/pull/8660): Fix a false positive for `Style/ClassAndModuleChildren` when using cbase module name. ([@koic][]) +* [#8664](https://github.com/rubocop-hq/rubocop/issues/8664): Fix a false positive for `Naming/BinaryOperatorParameterName` when naming multibyte character method name. ([@koic][]) +* [#8604](https://github.com/rubocop-hq/rubocop/issues/8604): Fix a false positive for `Bundler/DuplicatedGem` when gem is duplciated in condition. ([@tejasbubane][]) +* [#8671](https://github.com/rubocop-hq/rubocop/issues/8671): Fix an error for `Style/ExplicitBlockArgument` when using safe navigation method call. ([@koic][]) +* [#8681](https://github.com/rubocop-hq/rubocop/pull/8681): Fix an error for `Style/HashAsLastArrayItem` with `no_braces` for empty hash. ([@fsateler][]) +* [#8682](https://github.com/rubocop-hq/rubocop/pull/8682): Fix a positive for `Style/HashTransformKeys` and `Style/HashTransformValues` when the `each_with_object` hash is used in the transformed key or value. ([@eugeneius][]) +* [#8688](https://github.com/rubocop-hq/rubocop/issues/8688): Mark `Style/GlobalStdStream` as unsafe autocorrection. ([@marcandre][]) +* [#8642](https://github.com/rubocop-hq/rubocop/issues/8642): Fix a false negative for `Style/SpaceInsideHashLiteralBraces` when a correct empty hash precedes the incorrect hash. ([@dvandersluis][]) +* [#8683](https://github.com/rubocop-hq/rubocop/issues/8683): Make naming cops work with non-ascii characters. ([@tejasbubane][]) +* [#8626](https://github.com/rubocop-hq/rubocop/issues/8626): Fix false negatives for `Lint/UselessMethodDefinition`. ([@marcandre][]) +* [#8698](https://github.com/rubocop-hq/rubocop/pull/8698): Fix cache to avoid encoding exception. ([@marcandre][]) +* [#8704](https://github.com/rubocop-hq/rubocop/issues/8704): Fix an error for `Lint/AmbiguousOperator` when using safe navigation operator with a unary operator. ([@koic][]) +* [#8661](https://github.com/rubocop-hq/rubocop/pull/8661): Fix an incorrect auto-correct for `Style/MultilineTernaryOperator` when returning a multiline ternary operator expression. ([@koic][]) +* [#8526](https://github.com/rubocop-hq/rubocop/pull/8526): Fix a false positive for `Style/CaseEquality` cop when the receiver is not a camel cased constant. ([@koic][]) +* [#8673](https://github.com/rubocop-hq/rubocop/issues/8673): Fix the JSON parse error when specifying `--format=json` and `--stdin` options. ([@koic][]) + +### Changes + +* [#8470](https://github.com/rubocop-hq/rubocop/issues/8470): Do not autocorrect `Style/StringConcatenation` when parts of the expression are too complex. ([@dvandersluis][]) +* [#8561](https://github.com/rubocop-hq/rubocop/issues/8561): Fix `Lint/UselessMethodDefinition` to not register an offense when method definition includes optional arguments. ([@fatkodima][]) +* [#8617](https://github.com/rubocop-hq/rubocop/issues/8617): Fix `Style/HashAsLastArrayItem` to not register an offense when all items in an array are hashes. ([@dvandersluis][]) +* [#8500](https://github.com/rubocop-hq/rubocop/issues/8500): Add `in?` to AllowedMethods for `Lint/SafeNavigationChain` cop. ([@tejasbubane][]) +* [#8629](https://github.com/rubocop-hq/rubocop/pull/8629): Fix the cache being reusable in CI by using crc32 to calculate file hashes rather than `mtime`, which changes each CI build. ([@dvandersluis][]) +* [#8663](https://github.com/rubocop-hq/rubocop/issues/8663): Fix multiple autocorrection bugs with `Style/ClassMethodsDefinitions`. ([@dvandersluis][]) +* [#8621](https://github.com/rubocop-hq/rubocop/issues/8621): Add helpful Infinite Loop error message. ([@iSarCasm][]) + +## 0.90.0 (2020-09-01) + +### New features + +* [#8451](https://github.com/rubocop-hq/rubocop/issues/8451): Add new `Style/RedundantSelfAssignment` cop. ([@fatkodima][]) +* [#8384](https://github.com/rubocop-hq/rubocop/issues/8384): Add new `Layout/EmptyLineAfterMultilineCondition` cop. ([@fatkodima][]) +* [#8390](https://github.com/rubocop-hq/rubocop/pull/8390): Add new `Style/SoleNestedConditional` cop. ([@fatkodima][]) +* [#8563](https://github.com/rubocop-hq/rubocop/pull/8563): Add new `Style/KeywordParametersOrder` cop. ([@fatkodima][]) +* [#8486](https://github.com/rubocop-hq/rubocop/pull/8486): Add new `Style/CombinableLoops` cop. ([@fatkodima][]) +* [#8381](https://github.com/rubocop-hq/rubocop/pull/8381): Add new `Style/ClassMethodsDefinitions` cop. ([@fatkodima][]) +* [#8474](https://github.com/rubocop-hq/rubocop/pull/8474): Add new `Lint/DuplicateRequire` cop. ([@fatkodima][]) +* [#8472](https://github.com/rubocop-hq/rubocop/issues/8472): Add new `Lint/UselessMethodDefinition` cop. ([@fatkodima][]) +* [#8531](https://github.com/rubocop-hq/rubocop/issues/8531): Add new `Lint/EmptyFile` cop. ([@fatkodima][]) +* Add new `Lint/TrailingCommaInAttributeDeclaration` cop. ([@drenmi][]) +* [#8578](https://github.com/rubocop-hq/rubocop/pull/8578): Add `:restore_registry` context and `stub_cop_class` helper class. ([@marcandre][]) +* [#8579](https://github.com/rubocop-hq/rubocop/pull/8579): Add `Cop.documentation_url`. ([@marcandre][]) +* [#8510](https://github.com/rubocop-hq/rubocop/pull/8510): Add `RegexpNode#each_capture` and `parsed_tree`. ([@marcandre][]) +* [#8365](https://github.com/rubocop-hq/rubocop/pull/8365): Cops defining `on_send` can be optimized by defining the constant `RESTRICT_ON_SEND` with a list of acceptable method names. ([@marcandre][]) + +### Bug fixes + +* [#8508](https://github.com/rubocop-hq/rubocop/pull/8508): Fix a false positive for `Style/CaseLikeIf` when conditional contains comparison with a class. Mark `Style/CaseLikeIf` as not safe. ([@fatkodima][]) +* [#8618](https://github.com/rubocop-hq/rubocop/issues/8618): Fix an infinite loop error for `Layout/EmptyLineBetweenDefs`. ([@fatkodima][]) +* [#8534](https://github.com/rubocop-hq/rubocop/issues/8534): Fix `Lint/BinaryOperatorWithIdenticalOperands` for binary operators used as unary operators. ([@marcandre][]) +* [#8537](https://github.com/rubocop-hq/rubocop/pull/8537): Allow a trailing comment as a description comment for `Bundler/GemComment`. ([@pocke][]) +* [#8507](https://github.com/rubocop-hq/rubocop/issues/8507): Fix `Style/RescueModifier` to handle parentheses around rescue modifiers. ([@dsavochkin][]) +* [#8527](https://github.com/rubocop-hq/rubocop/pull/8527): Prevent an incorrect auto-correction for `Style/CaseEquality` cop when comparing with `===` against a regular expression receiver. ([@koic][]) +* [#8524](https://github.com/rubocop-hq/rubocop/issues/8524): Fix `Layout/EmptyLinesAroundClassBody` and `Layout/EmptyLinesAroundModuleBody` to correctly handle an access modifier as a first child. ([@dsavochkin][]) +* [#8518](https://github.com/rubocop-hq/rubocop/issues/8518): Fix `Lint/ConstantResolution` cop reporting offense for `module` and `class` definitions. ([@tejasbubane][]) +* [#8158](https://github.com/rubocop-hq/rubocop/issues/8158): Fix `Style/MultilineWhenThen` cop to correctly handle cases with multiline body. ([@dsavochkin][]) +* [#7705](https://github.com/rubocop-hq/rubocop/issues/7705): Fix `Style/OneLineConditional` cop to handle if/then/elsif/then/else/end cases. Add `AlwaysCorrectToMultiline` config option to this cop to always convert offenses to the multi-line form (false by default). ([@Lykos][], [@dsavochkin][]) +* [#8590](https://github.com/rubocop-hq/rubocop/issues/8590): Fix an error when auto-correcting encoding mismatch file. ([@koic][]) +* [#8321](https://github.com/rubocop-hq/rubocop/issues/8321): Enable auto-correction for `Layout/{Def}EndAlignment`, `Lint/EmptyEnsure`, `Style/ClassAndModuleChildren`. ([@marcandre][]) +* [#8583](https://github.com/rubocop-hq/rubocop/issues/8583): Fix `Style/RedundantRegexpEscape` false positive for line continuations. ([@owst][]) +* [#8593](https://github.com/rubocop-hq/rubocop/issues/8593): Fix `Style/RedundantRegexpCharacterClass` false positive for interpolated multi-line expressions. ([@owst][]) +* [#8624](https://github.com/rubocop-hq/rubocop/pull/8624): Fix an error with the `Style/CaseLikeIf` cop where it does not properly handle overridden equality methods with no arguments. ([@Skipants][]) + +### Changes + +* [#8413](https://github.com/rubocop-hq/rubocop/issues/8413): Pending cops warning now contains snippet that can be directly copied into `.rubocop.yml` as well as a notice about `NewCops: enable` config option. ([@colszowka][]) +* [#8362](https://github.com/rubocop-hq/rubocop/issues/8362): Add numbers of correctable offenses to summary. ([@nguyenquangminh0711][]) +* [#8513](https://github.com/rubocop-hq/rubocop/pull/8513): Clarify the ruby warning mentioned in the `Lint/ShadowingOuterLocalVariable` documentation. ([@chocolateboy][]) +* [#8517](https://github.com/rubocop-hq/rubocop/pull/8517): Make `Style/HashTransformKeys` and `Style/HashTransformValues` aware of `to_h` with block. ([@eugeneius][]) +* [#8529](https://github.com/rubocop-hq/rubocop/pull/8529): Mark `Style/FrozenStringLiteralComment` as `Safe`, but with unsafe auto-correction. ([@marcandre][]) +* [#8602](https://github.com/rubocop-hq/rubocop/pull/8602): Fix usage of `to_enum(:scan, regexp)` to work on TruffleRuby. ([@jaimerave][]) + +## 0.89.1 (2020-08-10) + +### Bug fixes + +* [#8463](https://github.com/rubocop-hq/rubocop/pull/8463): Fix false positives for `Lint/OutOfRangeRegexpRef` when a regexp is defined and matched in separate steps. ([@eugeneius][]) +* [#8464](https://github.com/rubocop-hq/rubocop/pull/8464): Handle regexps matched with `when`, `grep`, `gsub`, `gsub!`, `sub`, `sub!`, `[]`, `slice`, `slice!`, `scan`, `index`, `rindex`, `partition`, `rpartition`, `start_with?`, and `end_with?` in `Lint/OutOfRangeRegexpRef`. ([@eugeneius][]) +* [#8466](https://github.com/rubocop-hq/rubocop/issues/8466): Fix a false positive for `Lint/UriRegexp` when using `regexp` method without receiver. ([@koic][]) +* [#8478](https://github.com/rubocop-hq/rubocop/issues/8478): Relax `Lint/BinaryOperatorWithIdenticalOperands` for mathematical operations. ([@marcandre][]) +* [#8480](https://github.com/rubocop-hq/rubocop/issues/8480): Tweak callback list of `Lint/MissingSuper`. ([@marcandre][]) +* [#8481](https://github.com/rubocop-hq/rubocop/pull/8481): Fix autocorrect for elements with newlines in `Style/SymbolArray` and `Style/WordArray`. ([@biinari][]) +* [#8475](https://github.com/rubocop-hq/rubocop/issues/8475): Fix a false positive for `Style/HashAsLastArrayItem` when there are duplicate hashes in the array. ([@wcmonty][]) +* [#8497](https://github.com/rubocop-hq/rubocop/issues/8497): Fix `Style/IfUnlessModifier` to add parentheses when converting if-end condition inside a parenthesized method argument list. ([@dsavochkin][]) + +### Changes + +* [#8487](https://github.com/rubocop-hq/rubocop/pull/8487): Detect `<` and `>` as comparison operators in `Style/ConditionalAssignment` cop. ([@biinari][]) + +## 0.89.0 (2020-08-05) + +### New features + +* [#8322](https://github.com/rubocop-hq/rubocop/pull/8322): Support autocorrect for `Style/CaseEquality` cop. ([@fatkodima][]) +* [#7876](https://github.com/rubocop-hq/rubocop/issues/7876): Enhance `Gemspec/RequiredRubyVersion` cop with check that `required_ruby_version` is specified. ([@fatkodima][]) +* [#8291](https://github.com/rubocop-hq/rubocop/pull/8291): Add new `Lint/SelfAssignment` cop. ([@fatkodima][]) +* [#8389](https://github.com/rubocop-hq/rubocop/pull/8389): Add new `Lint/DuplicateRescueException` cop. ([@fatkodima][]) +* [#8433](https://github.com/rubocop-hq/rubocop/pull/8433): Add new `Lint/BinaryOperatorWithIdenticalOperands` cop. ([@fatkodima][]) +* [#8430](https://github.com/rubocop-hq/rubocop/pull/8430): Add new `Lint/UnreachableLoop` cop. ([@fatkodima][]) +* [#8412](https://github.com/rubocop-hq/rubocop/pull/8412): Add new `Style/OptionalBooleanParameter` cop. ([@fatkodima][]) +* [#8432](https://github.com/rubocop-hq/rubocop/pull/8432): Add new `Lint/FloatComparison` cop. ([@fatkodima][]) +* [#8376](https://github.com/rubocop-hq/rubocop/pull/8376): Add new `Lint/MissingSuper` cop. ([@fatkodima][]) +* [#8415](https://github.com/rubocop-hq/rubocop/pull/8415): Add new `Style/ExplicitBlockArgument` cop. ([@fatkodima][]) +* [#8383](https://github.com/rubocop-hq/rubocop/pull/8383): Support autocorrect for `Lint/Loop` cop. ([@fatkodima][]) +* [#8339](https://github.com/rubocop-hq/rubocop/pull/8339): Add `Config#for_badge` as an efficient way to get a cop's config merged with its department's. ([@marcandre][]) +* [#5067](https://github.com/rubocop-hq/rubocop/issues/5067): Add new `Style/StringConcatenation` cop. ([@fatkodima][]) +* [#7425](https://github.com/rubocop-hq/rubocop/pull/7425): Add new `Lint/TopLevelReturnWithArgument` cop. ([@iamravitejag][]) +* [#8417](https://github.com/rubocop-hq/rubocop/pull/8417): Add new `Style/GlobalStdStream` cop. ([@fatkodima][]) +* [#7949](https://github.com/rubocop-hq/rubocop/issues/7949): Add new `Style/SingleArgumentDig` cop. ([@volfgox][]) +* [#8341](https://github.com/rubocop-hq/rubocop/pull/8341): Add new `Lint/EmptyConditionalBody` cop. ([@fatkodima][]) +* [#7755](https://github.com/rubocop-hq/rubocop/issues/7755): Add new `Lint/OutOfRangeRegexpRef` cop. ([@sonalinavlakhe][]) + +### Bug fixes + +* [#8346](https://github.com/rubocop-hq/rubocop/pull/8346): Allow parentheses in single-line inheritance with `Style/MethodCallWithArgsParentheses` `EnforcedStyle: omit_parentheses` to fix invalid Ruby auto-correction. ([@gsamokovarov][]) +* [#8324](https://github.com/rubocop-hq/rubocop/issues/8324): Fix crash for `Layout/SpaceAroundMethodCallOperator` when using `Proc#call` shorthand syntax. ([@fatkodima][]) +* [#8332](https://github.com/rubocop-hq/rubocop/pull/8332): Fix auto-correct in `Style/ConditionalAssignment` to preserve constant namespace. ([@biinari][]) +* [#8344](https://github.com/rubocop-hq/rubocop/issues/8344): Fix crash for `Style/CaseLikeIf` when checking against `equal?` and `match?` without a receiver. ([@fatkodima][]) +* [#8323](https://github.com/rubocop-hq/rubocop/issues/8323): Fix a false positive for `Style/HashAsLastArrayItem` when hash is not a last array item. ([@fatkodima][]) +* [#8299](https://github.com/rubocop-hq/rubocop/issues/8299): Fix an incorrect auto-correct for `Style/RedundantCondition` when using `raise`, `rescue`, or `and` without argument parentheses in `else`. ([@koic][]) +* [#8335](https://github.com/rubocop-hq/rubocop/issues/8335): Fix incorrect character class detection for nested or POSIX bracket character classes in `Style/RedundantRegexpEscape`. ([@owst][]) +* [#8347](https://github.com/rubocop-hq/rubocop/issues/8347): Fix an incorrect auto-correct for `EnforcedStyle: hash_rockets` of `Style/HashSyntax` with `Layout/HashAlignment`. ([@koic][]) +* [#8375](https://github.com/rubocop-hq/rubocop/pull/8375): Fix an infinite loop error for `Style/EmptyMethod`. ([@koic][]) +* [#8385](https://github.com/rubocop-hq/rubocop/pull/8385): Remove auto-correction for `Lint/EnsureReturn`. ([@marcandre][]) +* [#8391](https://github.com/rubocop-hq/rubocop/issues/8391): Mark `Style/ArrayCoercion` as not safe. ([@marcandre][]) +* [#8406](https://github.com/rubocop-hq/rubocop/issues/8406): Improve `Style/AccessorGrouping`'s auto-correction to remove redundant blank lines. ([@koic][]) +* [#8330](https://github.com/rubocop-hq/rubocop/issues/8330): Fix a false positive for `Style/MissingRespondToMissing` when defined method with inline access modifier. ([@koic][]) +* [#8422](https://github.com/rubocop-hq/rubocop/issues/8422): Fix an error for `Lint/SelfAssignment` when using or-assignment for constant. ([@koic][]) +* [#8423](https://github.com/rubocop-hq/rubocop/issues/8423): Fix an error for `Style/SingleArgumentDig` when without a receiver. ([@koic][]) +* [#8424](https://github.com/rubocop-hq/rubocop/issues/8424): Fix an error for `Lint/IneffectiveAccessModifier` when there is `begin...end` before a method definition. ([@koic][]) +* [#8006](https://github.com/rubocop-hq/rubocop/issues/8006): Fix line length calculation for `Style/IfUnlessModifier` to correctly take into account code before the if condition when considering conversation to a single-line form. ([@dsavochkin][]) +* [#8283](https://github.com/rubocop-hq/rubocop/issues/8283): Fix line length calculation for `Style/IfUnlessModifier` to correctly take into account a comment on the first line when considering conversation to a single-line form. ([@dsavochkin][]) +* [#7957](https://github.com/rubocop-hq/rubocop/issues/7957): Fix line length calculation for `Style/IfUnlessModifier` to correctly take into account code on the last line after the end keyword when considering conversion to a single-line form. ([@dsavochkin][]) +* [#8226](https://github.com/rubocop-hq/rubocop/issues/8226): Fix `Style/IfUnlessModifier` to add parentheses when converting if-end condition inside an array or a hash to a single-line form. ([@dsavochkin][]) +* [#8443](https://github.com/rubocop-hq/rubocop/pull/8443): Fix an incorrect auto-correct for `Style/StructInheritance` when there is a comment before class declaration. ([@koic][]) +* [#8444](https://github.com/rubocop-hq/rubocop/issues/8444): Fix an error for `Layout/FirstMethodArgumentLineBreak` when using kwargs in `super`. ([@koic][]) +* [#8448](https://github.com/rubocop-hq/rubocop/pull/8448): Fix `Style/NestedParenthesizedCalls` to include line continuations in whitespace for auto-correct. ([@biinari][]) + +### Changes + +* [#8376](https://github.com/rubocop-hq/rubocop/pull/8376): `Style/MethodMissingSuper` cop is removed in favor of new `Lint/MissingSuper` cop. ([@fatkodima][]) +* [#8433](https://github.com/rubocop-hq/rubocop/pull/8433): `Lint/UselessComparison` cop is removed in favor of new `Lint/BinaryOperatorWithIdenticalOperands` cop. ([@fatkodima][]) +* [#8350](https://github.com/rubocop-hq/rubocop/pull/8350): Set default max line length to 120 for `Style/MultilineMethodSignature`. ([@koic][]) +* [#8338](https://github.com/rubocop-hq/rubocop/pull/8338): **potentially breaking**. Config#for_department now returns only the config specified for that department; the 'Enabled' attribute is no longer calculated. ([@marcandre][]) +* [#8037](https://github.com/rubocop-hq/rubocop/pull/8037): **(Breaking)** Cop `Metrics/AbcSize` now counts ||=, &&=, multiple assignments, for, yield, iterating blocks. `&.` now count as conditions too (unless repeated on the same variable). Default bumped from 15 to 17. Consider using `rubocop -a --disable-uncorrectable` to ease transition. ([@marcandre][]) +* [#8276](https://github.com/rubocop-hq/rubocop/issues/8276): Cop `Metrics/CyclomaticComplexity` not longer counts `&.` when repeated on the same variable. ([@marcandre][]) +* [#8204](https://github.com/rubocop-hq/rubocop/pull/8204): **(Breaking)** Cop `Metrics/PerceivedComplexity` now counts `else` in `case` statements, `&.`, `||=`, `&&=` and blocks known to iterate. Default bumped from 7 to 8. Consider using `rubocop -a --disable-uncorrectable` to ease transition. ([@marcandre][]) +* [#8416](https://github.com/rubocop-hq/rubocop/issues/8416): Cop `Lint/InterpolationCheck` marked as unsafe. ([@marcandre][]) +* [#8442](https://github.com/rubocop-hq/rubocop/pull/8442): Remove `RuboCop::Cop::ParserDiagnostic` mixin module. ([@koic][]) + +## 0.88.0 (2020-07-13) + +### New features + +* [#8279](https://github.com/rubocop-hq/rubocop/pull/8279): Recognise require method passed as argument in `Lint/NonDeterministicRequireOrder` cop. ([@biinari][]) +* [#7333](https://github.com/rubocop-hq/rubocop/issues/7333): Add new `Style/RedundantFileExtensionInRequire` cop. ([@fatkodima][]) +* [#8316](https://github.com/rubocop-hq/rubocop/pull/8316): Support autocorrect for `Lint/DisjunctiveAssignmentInConstructor` cop. ([@fatkodima][]) +* [#8242](https://github.com/rubocop-hq/rubocop/pull/8242): Internal profiling available with `bin/rubocop-profile` and rake tasks. ([@marcandre][]) +* [#8295](https://github.com/rubocop-hq/rubocop/pull/8295): Add new `Style/ArrayCoercion` cop. ([@fatkodima][]) +* [#8293](https://github.com/rubocop-hq/rubocop/pull/8293): Add new `Lint/DuplicateElsifCondition` cop. ([@fatkodima][]) +* [#7736](https://github.com/rubocop-hq/rubocop/issues/7736): Add new `Style/CaseLikeIf` cop. ([@fatkodima][]) +* [#4286](https://github.com/rubocop-hq/rubocop/issues/4286): Add new `Style/HashAsLastArrayItem` cop. ([@fatkodima][]) +* [#8247](https://github.com/rubocop-hq/rubocop/issues/8247): Add new `Style/HashLikeCase` cop. ([@fatkodima][]) +* [#8286](https://github.com/rubocop-hq/rubocop/issues/8286): Internal method `expect_offense` allows abbreviated offense messages. ([@marcandre][]) + +### Bug fixes + +* [#8232](https://github.com/rubocop-hq/rubocop/issues/8232): Fix a false positive for `Layout/EmptyLinesAroundAccessModifier` when `end` immediately after access modifier. ([@koic][]) +* [#7777](https://github.com/rubocop-hq/rubocop/issues/7777): Fix crash for `Layout/MultilineArrayBraceLayout` when comment is present after last element. ([@shekhar-patil][]) +* [#7776](https://github.com/rubocop-hq/rubocop/issues/7776): Fix crash for `Layout/MultilineMethodCallBraceLayout` when comment is present before closing braces. ([@shekhar-patil][]) +* [#8282](https://github.com/rubocop-hq/rubocop/issues/8282): Fix `Style/IfUnlessModifier` bad precedence detection. ([@tejasbubane][]) +* [#8289](https://github.com/rubocop-hq/rubocop/issues/8289): Fix `Style/AccessorGrouping` to not register offense for accessor with comment. ([@tejasbubane][]) +* [#8310](https://github.com/rubocop-hq/rubocop/pull/8310): Handle major version requirements in `Gemspec/RequiredRubyVersion`. ([@eugeneius][]) +* [#8315](https://github.com/rubocop-hq/rubocop/pull/8315): Fix crash for `Style/PercentLiteralDelimiters` when the source contains invalid characters. ([@eugeneius][]) +* [#8239](https://github.com/rubocop-hq/rubocop/pull/8239): Don't load `.rubocop.yml` files at all outside of the current project, unless they are personal configuration files and the project has no configuration. ([@deivid-rodriguez][]) + +### Changes + +* [#8021](https://github.com/rubocop-hq/rubocop/issues/8021): Rewrite `Layout/SpaceAroundMethodCallOperator` cop to make it faster. ([@fatkodima][]) +* [#8294](https://github.com/rubocop-hq/rubocop/pull/8294): Add `of` to `AllowedNames` of `MethodParameterName` cop. ([@AlexWayfer][]) + +## 0.87.1 (2020-07-07) + +### Bug fixes + +* [#8189](https://github.com/rubocop-hq/rubocop/issues/8189): Fix an error for `Layout/MultilineBlockLayout` where spaces for a new line where not considered. ([@knejad][]) +* [#8252](https://github.com/rubocop-hq/rubocop/issues/8252): Fix a command line option name from `--safe-autocorrect` to `--safe-auto-correct`, which is compatible with RuboCop 0.86 and lower. ([@koic][]) +* [#8259](https://github.com/rubocop-hq/rubocop/issues/8259): Fix false positives for `Style/BisectedAttrAccessor` when accessors have different access modifiers. ([@fatkodima][]) +* [#8253](https://github.com/rubocop-hq/rubocop/issues/8253): Fix false positives for `Style/AccessorGrouping` when accessors have different access modifiers. ([@fatkodima][]) +* [#8257](https://github.com/rubocop-hq/rubocop/issues/8257): Fix an error for `Style/BisectedAttrAccessor` when using `attr_reader` and `attr_writer` with splat arguments. ([@fatkodima][]) +* [#8239](https://github.com/rubocop-hq/rubocop/pull/8239): Don't load `.rubocop.yml` from personal folders to check for exclusions if given a custom configuration file. ([@deivid-rodriguez][]) +* [#8256](https://github.com/rubocop-hq/rubocop/issues/8256): Fix an error for `--auto-gen-config` when running a cop who do not support auto-correction. ([@koic][]) +* [#8262](https://github.com/rubocop-hq/rubocop/pull/8262): Fix `Lint/DeprecatedOpenSSLConstant` auto-correction of `OpenSSL::Cipher` to use lower case, as some Linux-based systems do not accept upper cased cipher names. ([@bdewater][]) + +## 0.87.0 (2020-07-06) + +### New features + +* [#7868](https://github.com/rubocop-hq/rubocop/pull/7868): `Cop::Base` is the new recommended base class for cops. ([@marcandre][]) +* [#3983](https://github.com/rubocop-hq/rubocop/issues/3983): Add new `Style/AccessorGrouping` cop. ([@fatkodima][]) +* [#8244](https://github.com/rubocop-hq/rubocop/pull/8244): Add new `Style/BisectedAttrAccessor` cop. ([@fatkodima][]) +* [#7458](https://github.com/rubocop-hq/rubocop/issues/7458): Add new `AsciiConstants` option for `Naming/AsciiIdentifiers`. ([@fatkodima][]) +* [#7373](https://github.com/rubocop-hq/rubocop/issues/7373): Add new `Style/RedundantAssignment` cop. ([@fatkodima][]) +* [#8213](https://github.com/rubocop-hq/rubocop/pull/8213): Permit to specify TargetRubyVersion 2.8 (experimental). ([@koic][]) +* [#8159](https://github.com/rubocop-hq/rubocop/pull/8159): Add new `CountAsOne` option for code length related `Metric` cops. ([@fatkodima][]) +* [#8164](https://github.com/rubocop-hq/rubocop/pull/8164): Support auto-correction for `Lint/InterpolationCheck`. ([@koic][]) +* [#8223](https://github.com/rubocop-hq/rubocop/pull/8223): Support auto-correction for `Style/IfUnlessModifierOfIfUnless`. ([@koic][]) +* [#8172](https://github.com/rubocop-hq/rubocop/pull/8172): Support auto-correction for `Lint/SafeNavigationWithEmpty`. ([@koic][]) + +### Bug fixes + +* [#8039](https://github.com/rubocop-hq/rubocop/pull/8039): Fix false positives for `Lint/ParenthesesAsGroupedExpression` in when using operators or chain functions. ([@CamilleDrapier][]) +* [#8196](https://github.com/rubocop-hq/rubocop/issues/8196): Fix a false positive for `Style/RedundantFetchBlock` when using with `Rails.cache`. ([@fatkodima][]) +* [#8195](https://github.com/rubocop-hq/rubocop/issues/8195): Fix an error for `Style/RedundantFetchBlock` when using `#fetch` with empty block. ([@koic][]) +* [#8193](https://github.com/rubocop-hq/rubocop/issues/8193): Fix a false positive for `Style/RedundantRegexpCharacterClass` when using `[\b]`. ([@owst][]) +* [#8205](https://github.com/rubocop-hq/rubocop/issues/8205): Fix a false positive for `Style/RedundantRegexpCharacterClass` when using a leading escaped `]`. ([@owst][]) +* [#8208](https://github.com/rubocop-hq/rubocop/issues/8208): Fix `Style/RedundantParentheses` with hash literal as first argument to `yield`. ([@karlwithak][]) +* [#8176](https://github.com/rubocop-hq/rubocop/pull/8176): Don't load `.rubocop.yml` from personal folders to check for exclusions if there's a project configuration. ([@deivid-rodriguez][]) + +### Changes + +* [#7868](https://github.com/rubocop-hq/rubocop/pull/7868): **(Breaking)** Extensive refactoring of internal classes `Team`, `Commissioner`, `Corrector`. `Cop::Cop#corrections` not completely compatible. See Upgrade Notes. ([@marcandre][]) +* [#8156](https://github.com/rubocop-hq/rubocop/issues/8156): **(Breaking)** `rubocop -a / --autocorrect` no longer run unsafe corrections; `rubocop -A / --autocorrect-all` run both safe and unsafe corrections. Options `--safe-autocorrect` is deprecated. ([@marcandre][]) +* [#8207](https://github.com/rubocop-hq/rubocop/pull/8207): **(Breaking)** Order for gems names now disregards underscores and dashes unless `ConsiderPunctuation` setting is set to `true`. ([@marcandre][]) +* [#8211](https://github.com/rubocop-hq/rubocop/pull/8211): `Style/ClassVars` cop now detects `class_variable_set`. ([@biinari][]) +* [#8245](https://github.com/rubocop-hq/rubocop/pull/8245): Detect top-level constants like `::Const` in various cops. ([@biinari][]) + +## 0.86.0 (2020-06-22) + +### New features + +* [#8147](https://github.com/rubocop-hq/rubocop/pull/8147): Add new `Style/RedundantFetchBlock` cop. ([@fatkodima][]) +* [#8111](https://github.com/rubocop-hq/rubocop/pull/8111): Add auto-correct for `Style/StructInheritance`. ([@tejasbubane][]) +* [#8113](https://github.com/rubocop-hq/rubocop/pull/8113): Let `expect_offense` templates add variable-length whitespace with `_{foo}`. ([@eugeneius][]) +* [#8148](https://github.com/rubocop-hq/rubocop/pull/8148): Support auto-correction for `Style/MultilineTernaryOperator`. ([@koic][]) +* [#8151](https://github.com/rubocop-hq/rubocop/pull/8151): Support auto-correction for `Style/NestedTernaryOperator`. ([@koic][]) +* [#8142](https://github.com/rubocop-hq/rubocop/pull/8142): Add `Lint/ConstantResolution` cop. ([@robotdana][]) +* [#8170](https://github.com/rubocop-hq/rubocop/pull/8170): Support auto-correction for `Lint/RegexpAsCondition`. ([@koic][]) +* [#8169](https://github.com/rubocop-hq/rubocop/pull/8169): Support auto-correction for `Lint/RaiseException`. ([@koic][]) + +### Bug fixes + +* [#8132](https://github.com/rubocop-hq/rubocop/issues/8132): Fix the problem with `Naming/MethodName: EnforcedStyle: camelCase` and `_` or `i` variables. ([@avrusanov][]) +* [#8115](https://github.com/rubocop-hq/rubocop/issues/8115): Fix false negative for `Lint::FormatParameterMismatch` when argument contains formatting. ([@andrykonchin][]) +* [#8131](https://github.com/rubocop-hq/rubocop/pull/8131): Fix false positive for `Style/RedundantRegexpEscape` with escaped delimiters. ([@owst][]) +* [#8124](https://github.com/rubocop-hq/rubocop/issues/8124): Fix a false positive for `Lint/FormatParameterMismatch` when using named parameters with escaped `%`. ([@koic][]) +* [#7979](https://github.com/rubocop-hq/rubocop/issues/7979): Fix "uninitialized constant DidYouMean::SpellChecker" exception. ([@bquorning][]) +* [#8098](https://github.com/rubocop-hq/rubocop/issues/8098): Fix a false positive for `Style/RedundantRegexpCharacterClass` when using interpolations. ([@owst][]) +* [#8150](https://github.com/rubocop-hq/rubocop/pull/8150): Fix a false positive for `Layout/EmptyLinesAroundAttributeAccessor` when using attribute accessors in `if` ... `else` branches. ([@koic][]) +* [#8179](https://github.com/rubocop-hq/rubocop/issues/8179): Fix an infinite correction loop error for `Layout/MultilineBlockLayout` when missing newline before opening parenthesis `(` for block body. ([@koic][]) +* [#8185](https://github.com/rubocop-hq/rubocop/issues/8185): Fix a false positive for `Style/YodaCondition` when interpolation is used on the left hand side. ([@koic][]) + +### Changes + +* [#8149](https://github.com/rubocop-hq/rubocop/pull/8149): **(Breaking)** Cop `Metrics/CyclomaticComplexity` now counts `&.`, `||=`, `&&=` and blocks known to iterate. Default bumped from 6 to 7. Consider using `rubocop -a --disable-uncorrectable` to ease transition. ([@marcandre][]) +* [#8146](https://github.com/rubocop-hq/rubocop/pull/8146): Use UTC in RuboCop todo file generation. ([@mauro-oto][]) +* [#8178](https://github.com/rubocop-hq/rubocop/pull/8178): Mark unsafe for `Lint/RaiseException`. ([@koic][]) + +## 0.85.1 (2020-06-07) + +### Bug fixes + +* [#8083](https://github.com/rubocop-hq/rubocop/issues/8083): Fix an error for `Lint/MixedRegexpCaptureTypes` cop when using a regular expression that cannot be processed by regexp_parser gem. ([@koic][]) +* [#8081](https://github.com/rubocop-hq/rubocop/issues/8081): Fix a false positive for `Lint/SuppressedException` when empty rescue block in `do` block. ([@koic][]) +* [#8096](https://github.com/rubocop-hq/rubocop/issues/8096): Fix a false positive for `Lint/SuppressedException` when empty rescue block in defs. ([@koic][]) +* [#8108](https://github.com/rubocop-hq/rubocop/issues/8108): Fix infinite loop in `Layout/HeredocIndentation` auto-correct. ([@jonas054][]) +* [#8042](https://github.com/rubocop-hq/rubocop/pull/8042): Fix raising error in `Lint::FormatParameterMismatch` when it handles invalid format strings and add new offense. ([@andrykonchin][]) + +## 0.85.0 (2020-06-01) + +### New features + +* [#6289](https://github.com/rubocop-hq/rubocop/issues/6289): Add new `CheckDefinitionPathHierarchy` option for `Naming/FileName`. ([@jschneid][]) +* [#8055](https://github.com/rubocop-hq/rubocop/pull/8055): Add new `Style/RedundantRegexpCharacterClass` cop. ([@owst][]) +* [#8069](https://github.com/rubocop-hq/rubocop/issues/8069): New option for `expect_offense` to help format offense templates. ([@marcandre][]) +* [#7908](https://github.com/rubocop-hq/rubocop/pull/7908): Add new `Style/RedundantRegexpEscape` cop. ([@owst][]) +* [#7978](https://github.com/rubocop-hq/rubocop/pull/7978): Add new option `OnlyFor` to the `Bundler/GemComment` cop. ([@ric2b][]) +* [#8063](https://github.com/rubocop-hq/rubocop/issues/8063): Add new `AllowedNames` option for `Naming/ClassAndModuleCamelCase`. ([@tejasbubane][]) +* [#8050](https://github.com/rubocop-hq/rubocop/pull/8050): New option `--display-only-failed` that can be used with `--format junit`. Speeds up test report processing for large codebases and helps address the sorts of concerns raised at [mikian/rubocop-junit-formatter #18](https://github.com/mikian/rubocop-junit-formatter/issues/18). ([@burnettk][]) +* [#7746](https://github.com/rubocop-hq/rubocop/issues/7746): Add new `Lint/MixedRegexpCaptureTypes` cop. ([@pocke][]) + +### Bug fixes + +* [#8008](https://github.com/rubocop-hq/rubocop/issues/8008): Fix an error for `Lint/SuppressedException` when empty rescue block in `def`. ([@koic][]) +* [#8012](https://github.com/rubocop-hq/rubocop/issues/8012): Fix an incorrect auto-correct for `Lint/DeprecatedOpenSSLConstant` when deprecated OpenSSL constant is used in a block. ([@koic][]) +* [#8017](https://github.com/rubocop-hq/rubocop/pull/8017): Fix a false positive for `Lint/SuppressedException` when empty rescue with comment in `def`. ([@koic][]) +* [#7990](https://github.com/rubocop-hq/rubocop/issues/7990): Fix resolving `inherit_gem` in remote configs. ([@CvX][]) +* [#8035](https://github.com/rubocop-hq/rubocop/issues/8035): Fix a false positive for `Lint/DeprecatedOpenSSLConstant` when using double quoted string argument. ([@koic][]) +* [#7971](https://github.com/rubocop-hq/rubocop/issues/7971): Fix an issue where `--disable-uncorrectable` would not update uncorrected code with `rubocop:todo`. ([@rrosenblum][]) +* [#8035](https://github.com/rubocop-hq/rubocop/issues/8035): Fix a false positive for `Lint/DeprecatedOpenSSLConstant` when argument is a variable, method, or consntant. ([@koic][]) + +### Changes + +* [#8056](https://github.com/rubocop-hq/rubocop/pull/8056): **(Breaking)** Remove support for unindent/active_support/powerpack from `Layout/HeredocIndentation`, so it only recommends using squiggy heredoc. ([@bquorning][]) + +## 0.84.0 (2020-05-21) + +### New features + +* [#7735](https://github.com/rubocop-hq/rubocop/issues/7735): `NodePattern` and `AST` classes have been moved to the [`rubocop-ast` gem](https://github.com/rubocop-hq/rubocop-ast). ([@marcandre][]) +* [#7950](https://github.com/rubocop-hq/rubocop/pull/7950): Add new `Lint/DeprecatedOpenSSLConstant` cop. ([@bdewater][]) +* [#7976](https://github.com/rubocop-hq/rubocop/issues/7976): Add `AllowAliasSyntax` and `AllowedMethods` options for `Layout/EmptyLinesAroundAttributeAccessor`. ([@koic][]) +* [#7984](https://github.com/rubocop-hq/rubocop/pull/7984): New `rake` task "check_commit" will run `rspec` and `rubocop` on files touched by the last commit. Currently available when developing from the main repository only. ([@marcandre][]) + +### Bug fixes + +* [#7953](https://github.com/rubocop-hq/rubocop/issues/7953): Fix an error for `Lint/AmbiguousOperator` when a method with no arguments is used in advance. ([@koic][]) +* [#7962](https://github.com/rubocop-hq/rubocop/issues/7962): Fix a false positive for `Lint/ParenthesesAsGroupedExpression` when heredoc has a space between the same string as the method name and `(`. ([@koic][]) +* [#7967](https://github.com/rubocop-hq/rubocop/pull/7967): `Style/SlicingWithRange` cop now supports any expression as its first index. ([@zverok][]) +* [#7972](https://github.com/rubocop-hq/rubocop/issues/7972): Fix an incorrect autocrrect for `Style/HashSyntax` when using a return value uses `return`. ([@koic][]) +* [#7886](https://github.com/rubocop-hq/rubocop/issues/7886): Fix a bug in `AllowComments` logic in `Lint/SuppressedException`. ([@jonas054][]) +* [#7991](https://github.com/rubocop-hq/rubocop/issues/7991): Fix an error for `Layout/EmptyLinesAroundAttributeAccessor` when attribute method is method chained. ([@koic][]) +* [#7993](https://github.com/rubocop-hq/rubocop/issues/7993): Fix a false positive for `Migration/DepartmentName` when a disable comment contains an unexpected character for department name. ([@koic][]) +* [#7983](https://github.com/rubocop-hq/rubocop/pull/7983): Make the config loader Bundler-aware. ([@CvX][]) + +### Changes + +* [#7952](https://github.com/rubocop-hq/rubocop/pull/7952): **(Breaking)** Change the max line length of `Layout/LineLength` to 120 by default. ([@koic][]) +* [#7959](https://github.com/rubocop-hq/rubocop/pull/7959): Change enforced style to conditionals for `Style/AndOr`. ([@koic][]) +* [#7985](https://github.com/rubocop-hq/rubocop/pull/7985): Add `EnforcedStyle` for `Style/DoubleNegation` cop and allow double nagation in contexts that use boolean as a return value. ([@koic][]) + +## 0.83.0 (2020-05-11) + +### New features + +* [#7951](https://github.com/rubocop-hq/rubocop/pull/7951): Include `rakefile` file by default. ([@jethrodaniel][]) +* [#7921](https://github.com/rubocop-hq/rubocop/pull/7921): Add new `Style/SlicingWithRange` cop. ([@zverok][]) +* [#7895](https://github.com/rubocop-hq/rubocop/pull/7895): Include `.simplecov` file by default. ([@robotdana][]) +* [#7916](https://github.com/rubocop-hq/rubocop/pull/7916): Support auto-correction for `Lint/AmbiguousRegexpLiteral`. ([@koic][]) +* [#7917](https://github.com/rubocop-hq/rubocop/pull/7917): Support auto-correction for `Lint/UselessAccessModifier`. ([@koic][]) +* [#595](https://github.com/rubocop-hq/rubocop/issues/595): Add ERB pre-processing for configuration files. ([@jonas054][]) +* [#7918](https://github.com/rubocop-hq/rubocop/pull/7918): Support auto-correction for `Lint/AmbiguousOperator`. ([@koic][]) +* [#7937](https://github.com/rubocop-hq/rubocop/pull/7937): Support auto-correction for `Style/IfWithSemicolon`. ([@koic][]) +* [#3696](https://github.com/rubocop-hq/rubocop/issues/3696): Add `AllowComments` option to `Lint/EmptyWhen` cop. ([@koic][]) +* [#7910](https://github.com/rubocop-hq/rubocop/pull/7910): Support auto-correction for `Lint/ParenthesesAsGroupedExpression`. ([@koic][]) +* [#7925](https://github.com/rubocop-hq/rubocop/pull/7925): Support auto-correction for `Layout/ConditionPosition`. ([@koic][]) +* [#7934](https://github.com/rubocop-hq/rubocop/pull/7934): Support auto-correction for `Lint/EnsureReturn`. ([@koic][]) +* [#7922](https://github.com/rubocop-hq/rubocop/pull/7922): Add new `Layout/EmptyLineAroundAttributeAccessor` cop. ([@koic][]) + +### Bug fixes + +* [#7929](https://github.com/rubocop-hq/rubocop/issues/7929): Fix `Style/FrozenStringLiteralComment` to accept frozen_string_literal anywhere in leading comment lines. ([@jeffcarbs][]) +* [#7882](https://github.com/rubocop-hq/rubocop/pull/7882): Fix `Style/CaseEquality` when `AllowOnConstant` is `true` and the method receiver is implicit. ([@rafaelfranca][]) +* [#7790](https://github.com/rubocop-hq/rubocop/issues/7790): Fix `--parallel` and `--ignore-parent-exclusion` combination. ([@jonas054][]) +* [#7881](https://github.com/rubocop-hq/rubocop/issues/7881): Fix `--parallel` and `--force-default-config` combination. ([@jonas054][]) +* [#7635](https://github.com/rubocop-hq/rubocop/issues/7635): Fix a false positive for `Style/MultilineWhenThen` when `then` required for a body of `when` is used. ([@koic][]) +* [#7905](https://github.com/rubocop-hq/rubocop/pull/7905): Fix an error when running `rubocop --only` or `rubocop --except` options without cop name argument. ([@koic][]) +* [#7903](https://github.com/rubocop-hq/rubocop/pull/7903): Fix an incorrect auto-correct for `Style/HashTransformKeys` and `Style/HashTransformValues` cops when line break before `to_h` method. ([@diogoosorio][], [@koic][]) +* [#7899](https://github.com/rubocop-hq/rubocop/issues/7899): Fix an infinite loop error for `Layout/SpaceAroundOperators` with `Layout/ExtraSpacing` when using `ForceEqualSignAlignment: true`. ([@koic][]) +* [#7885](https://github.com/rubocop-hq/rubocop/issues/7885): Fix `Style/IfUnlessModifier` logic when tabs are used for indentation. ([@jonas054][]) +* [#7909](https://github.com/rubocop-hq/rubocop/pull/7909): Fix a false positive for `Lint/ParenthesesAsGroupedExpression` when using an intended grouped parentheses. ([@koic][]) +* [#7913](https://github.com/rubocop-hq/rubocop/pull/7913): Fix a false positive for `Lint/LiteralAsCondition` when using `true` literal in `while` and similar cases. ([@koic][]) +* [#7928](https://github.com/rubocop-hq/rubocop/issues/7928): Fix a false message for `Style/GuardClause` when using `and` or `or` operators for guard clause in `then` or `else` branches. ([@koic][]) +* [#7928](https://github.com/rubocop-hq/rubocop/issues/7928): Fix a false positive for `Style/GuardClause` when assigning the result of a guard condition with `else`. ([@koic][]) + +### Changes + +* [#7860](https://github.com/rubocop-hq/rubocop/issues/7860): Change `AllowInHeredoc` option of `Layout/TrailingWhitespace` to `true` by default. ([@koic][]) +* [#7094](https://github.com/rubocop-hq/rubocop/issues/7094): Clarify alignment in `Layout/MultilineOperationIndentation`. ([@jonas054][]) +* [#4245](https://github.com/rubocop-hq/rubocop/issues/4245): **(Breaking)** Inspect all files given on command line unless `--only-recognized-file-types` is given. ([@jonas054][]) +* [#7390](https://github.com/rubocop-hq/rubocop/issues/7390): **(Breaking)** Enabling a cop overrides disabling its department. ([@jonas054][]) +* [#7936](https://github.com/rubocop-hq/rubocop/issues/7936): Mark `Lint/BooleanSymbol` as unsafe. ([@laurmurclar][]) +* [#7948](https://github.com/rubocop-hq/rubocop/pull/7948): Mark unsafe for `Style/OptionalArguments`. ([@koic][]) +* [#7931](https://github.com/rubocop-hq/rubocop/pull/7931): Remove dependency on the `jaro_winkler` gem, instead depending on `did_you_mean`. This may be a breaking change for RuboCop libraries calling `NameSimilarity#find_similar_name`. ([@bquorning][]) + +## 0.82.0 (2020-04-16) + +### New features + +* [#7867](https://github.com/rubocop-hq/rubocop/pull/7867): Add support for tabs in indentation. ([@DracoAter][]) +* [#7863](https://github.com/rubocop-hq/rubocop/issues/7863): Corrector now accepts nodes in addition to ranges. ([@marcandre][]) +* [#7862](https://github.com/rubocop-hq/rubocop/issues/7862): Corrector now has a `wrap` method. ([@marcandre][]) +* [#7850](https://github.com/rubocop-hq/rubocop/issues/7850): Make it possible to enable/disable pending cops. ([@koic][]) +* [#7861](https://github.com/rubocop-hq/rubocop/issues/7861): Make it to allow `Style/CaseEquality` when the receiver is a constant. ([@rafaelfranca][]) +* [#7851](https://github.com/rubocop-hq/rubocop/pull/7851): Add a new `Style/ExponentialNotation` cop. ([@tdeo][]) +* [#7384](https://github.com/rubocop-hq/rubocop/pull/7384): Add new `Style/DisableCopsWithinSourceCodeDirective` cop. ([@egze][]) +* [#7826](https://github.com/rubocop-hq/rubocop/issues/7826): Add new `Layout/SpaceAroundMethodCallOperator` cop. ([@saurabhmaurya15][]) + +### Bug fixes + +* [#7871](https://github.com/rubocop-hq/rubocop/pull/7871): Fix an auto-correction bug in `Lint/BooleanSymbol`. ([@knu][]) +* [#7842](https://github.com/rubocop-hq/rubocop/issues/7842): Fix a false positive for `Lint/RaiseException` when raising Exception with explicit namespace. ([@koic][]) +* [#7834](https://github.com/rubocop-hq/rubocop/issues/7834): Fix `Lint/UriRegexp` to register offense with array arguments. ([@tejasbubane][]) +* [#7841](https://github.com/rubocop-hq/rubocop/issues/7841): Fix an error for `Style/TrailingCommaInBlockArgs` when lambda literal (`->`) has multiple arguments. ([@koic][]) +* [#7842](https://github.com/rubocop-hq/rubocop/issues/7842): Fix a false positive for `Lint/RaiseException` when Exception without cbase specified under the namespace `Gem` by adding `AllowedImplicitNamespaces` option. ([@koic][]) +* `Style/IfUnlessModifier` does not infinite-loop when auto-correcting long lines which use if/unless modifiers and have multiple statements separated by semicolons. ([@alexdowad][]) +* [rubocop-hq/rubocop-rails#127](https://github.com/rubocop-hq/rubocop-rails/issues/127): Use `ConfigLoader.default_configuration` for the default config. ([@hanachin][]) + +### Changes + +* [#7867](https://github.com/rubocop-hq/rubocop/pull/7867): **(Breaking)** Renamed `Layout/Tab` cop to `Layout/IndentationStyle`. ([@DracoAter][]) +* [#7869](https://github.com/rubocop-hq/rubocop/pull/7869): **(Breaking)** Drop support for Ruby 2.3. ([@koic][]) + +## 0.81.0 (2020-04-01) + +### New features + +* [#7299](https://github.com/rubocop-hq/rubocop/issues/7299): Add new `Lint/RaiseException` cop. ([@denys281][]) +* [#7793](https://github.com/rubocop-hq/rubocop/pull/7793): Prefer `include?` over `member?` in `Style/CollectionMethods`. ([@dmolesUC][]) +* [#7654](https://github.com/rubocop-hq/rubocop/issues/7654): Support `with_fixed_indentation` option for `Layout/ArrayAlignment` cop. ([@nikitasakov][]) +* [#7783](https://github.com/rubocop-hq/rubocop/pull/7783): Support Ruby 2.7's numbered parameter for `Style/RedundantSort`. ([@koic][]) +* [#7795](https://github.com/rubocop-hq/rubocop/issues/7795): Make `Layout/EmptyLineAfterGuardClause` aware of case where `and` or `or` is used before keyword that break control (e.g. `and return`). ([@koic][]) +* [#7786](https://github.com/rubocop-hq/rubocop/pull/7786): Support Ruby 2.7's pattern match for `Layout/ElseAlignment` cop. ([@koic][]) +* [#7784](https://github.com/rubocop-hq/rubocop/pull/7784): Support Ruby 2.7's numbered parameter for `Lint/SafeNavigationChain`. ([@koic][]) +* [#7331](https://github.com/rubocop-hq/rubocop/issues/7331): Add `forbidden` option to `Style/ModuleFunction` cop. ([@weh][]) +* [#7699](https://github.com/rubocop-hq/rubocop/pull/7699): Add new `Lint/StructNewOverride` cop. ([@ybiquitous][]) +* [#7637](https://github.com/rubocop-hq/rubocop/pull/7637): Add new `Style/TrailingCommaInBlockArgs` cop. ([@pawptart][]) +* [#7809](https://github.com/rubocop-hq/rubocop/pull/7809): Add auto-correction for `Style/EndBlock` cop. ([@tejasbubane][]) +* [#7739](https://github.com/rubocop-hq/rubocop/pull/7739): Add `IgnoreNotImplementedMethods` configuration to `Lint/UnusedMethodArgument`. ([@tejasbubane][]) +* [#7740](https://github.com/rubocop-hq/rubocop/issues/7740): Add `AllowModifiersOnSymbols` configuration to `Style/AccessModifierDeclarations`. ([@tejasbubane][]) +* [#7812](https://github.com/rubocop-hq/rubocop/pull/7812): Add auto-correction for `Lint/BooleanSymbol` cop. ([@tejasbubane][]) +* [#7823](https://github.com/rubocop-hq/rubocop/pull/7823): Add `IgnoredMethods` configuration in `Metrics/AbcSize`, `Metrics/CyclomaticComplexity`, and `Metrics/PerceivedComplexity` cops. ([@drenmi][]) +* [#7816](https://github.com/rubocop-hq/rubocop/pull/7816): Support Ruby 2.7's numbered parameter for `Style/Lambda`. ([@koic][]) +* [#7829](https://github.com/rubocop-hq/rubocop/issues/7829): Fix an error for `Style/OneLineConditional` when one of the branches contains `next` keyword. ([@koic][]) + +### Bug fixes + +* [#7236](https://github.com/rubocop-hq/rubocop/pull/7236): Mark `Style/InverseMethods` auto-correct as incompatible with `Style/SymbolProc`. ([@drenmi][]) +* [#7144](https://github.com/rubocop-hq/rubocop/issues/7144): Fix `Style/Documentation` constant visibility declaration in namespace. ([@AdrienSldy][]) +* [#7779](https://github.com/rubocop-hq/rubocop/issues/7779): Fix a false positive for `Style/MultilineMethodCallIndentation` when using Ruby 2.7's numbered parameter. ([@koic][]) +* [#7733](https://github.com/rubocop-hq/rubocop/issues/7733): Fix rubocop-junit-formatter imcompatibility XML for JUnit formatter. ([@koic][]) +* [#7767](https://github.com/rubocop-hq/rubocop/issues/7767): Skip array literals in `Style/HashTransformValues` and `Style/HashTransformKeys`. ([@tejasbubane][]) +* [#7791](https://github.com/rubocop-hq/rubocop/issues/7791): Fix an error on auto-correction for `Layout/BlockEndNewline` when `}` of multiline block without processing is not on its own line. ([@koic][]) +* [#7778](https://github.com/rubocop-hq/rubocop/issues/7778): Fix a false positive for `Layout/EndAlignment` when a non-whitespace is used before the `end` keyword. ([@koic][]) +* [#7806](https://github.com/rubocop-hq/rubocop/pull/7806): Fix an error for `Lint/ErbNewArguments` cop when inspecting `ActionView::Template::Handlers::ERB.new`. ([@koic][]) +* [#7814](https://github.com/rubocop-hq/rubocop/issues/7814): Fix a false positive for `Migrate/DepartmentName` cop when inspecting an unexpected disabled comment format. ([@koic][]) +* [#7728](https://github.com/rubocop-hq/rubocop/issues/7728): Fix an error for `Style/OneLineConditional` when one of the branches contains a self keyword. ([@koic][]) +* [#7825](https://github.com/rubocop-hq/rubocop/issues/7825): Fix crash for `Layout/MultilineMethodCallIndentation` with key access to hash. ([@tejasbubane][]) +* [#7831](https://github.com/rubocop-hq/rubocop/issues/7831): Fix a false positive for `Style/HashEachMethods` when receiver is implicit. ([@koic][]) + +### Changes + +* [#7797](https://github.com/rubocop-hq/rubocop/pull/7797): Allow unicode-display_width dependency version 1.7.0. ([@yuritomanek][]) +* [#7805](https://github.com/rubocop-hq/rubocop/pull/7805): Change `AllowComments` option of `Lint/SuppressedException` to true by default. ([@koic][]) +* [#7320](https://github.com/rubocop-hq/rubocop/issues/7320): `Naming/MethodName` now flags `attr_reader/attr_writer/attr_accessor/attr`. ([@denys281][]) +* [#7813](https://github.com/rubocop-hq/rubocop/issues/7813): **(Breaking)** Remove `Lint/EndInMethod` cop. ([@tejasbubane][]) + +## 0.80.1 (2020-02-29) + +### Bug fixes + +* [#7719](https://github.com/rubocop-hq/rubocop/issues/7719): Fix `Style/NestedParenthesizedCalls` cop for newline. ([@tejasbubane][]) +* [#7709](https://github.com/rubocop-hq/rubocop/issues/7709): Fix correction of `Style/RedundantCondition` when the else branch contains a range. ([@rrosenblum][]) +* [#7682](https://github.com/rubocop-hq/rubocop/issues/7682): Fix `Style/InverseMethods` autofix leaving parenthesis. ([@tejasbubane][]) +* [#7745](https://github.com/rubocop-hq/rubocop/issues/7745): Suppress a pending cop warnings when pending cop's department is disabled. ([@koic][]) +* [#7759](https://github.com/rubocop-hq/rubocop/issues/7759): Fix an error for `Layout/LineLength` cop when using lambda syntax that argument is not enclosed in parentheses. ([@koic][]) + +### Changes + +* [#7765](https://github.com/rubocop-hq/rubocop/pull/7765): When warning about a pending cop, display the version with the cop added. ([@koic][]) + +## 0.80.0 (2020-02-18) + +### New features + +* [#7693](https://github.com/rubocop-hq/rubocop/pull/7693): NodePattern: Add `` ` `` for descendant search. ([@marcandre][]) +* [#7577](https://github.com/rubocop-hq/rubocop/pull/7577): Add `AllowGemfileRubyComment` configuration on `Layout/LeadingCommentSpace`. ([@cetinajero][]) +* [#7663](https://github.com/rubocop-hq/rubocop/pull/7663): Add new `Style/HashTransformKeys` and `Style/HashTransformValues` cops. ([@djudd][], [@eugeneius][]) +* [#7619](https://github.com/rubocop-hq/rubocop/issues/7619): Support auto-correct of legacy cop names for `Migration/DepartmentName`. ([@koic][]) +* [#7659](https://github.com/rubocop-hq/rubocop/pull/7659): `Layout/LineLength` auto-correct now breaks up long lines with blocks. ([@maxh][]) +* [#7677](https://github.com/rubocop-hq/rubocop/pull/7677): Add new `Style/HashEachMethods` cop for `Hash#each_key` and `Hash#each_value`. ([@jemmaissroff][]) +* Add `BracesRequiredMethods` parameter to `Style/BlockDelimiters` to require braces for specific methods such as Sorbet's `sig`. ([@maxh][]) +* [#7686](https://github.com/rubocop-hq/rubocop/pull/7686): Add new `JUnitFormatter` formatter based on `rubocop-junit-formatter` gem. ([@koic][]) +* [#7715](https://github.com/rubocop-hq/rubocop/pull/7715): Add `Steepfile` to default `Include` list. ([@ybiquitous][]) + +### Bug fixes + +* [#7644](https://github.com/rubocop-hq/rubocop/issues/7644): Fix patterns with named wildcards in unions. ([@marcandre][]) +* [#7639](https://github.com/rubocop-hq/rubocop/pull/7639): Fix logical operator edge case in `omit_parentheses` style of `Style/MethodCallWithArgsParentheses`. ([@gsamokovarov][]) +* [#7661](https://github.com/rubocop-hq/rubocop/pull/7661): Fix to return correct info from multi-line regexp. ([@Tietew][]) +* [#7655](https://github.com/rubocop-hq/rubocop/issues/7655): Fix an error when processing a regexp with a line break at the start of capture parenthesis. ([@koic][]) +* [#7647](https://github.com/rubocop-hq/rubocop/issues/7647): Fix an `undefined method on_numblock` error when using Ruby 2.7's numbered parameters. ([@hanachin][]) +* [#7675](https://github.com/rubocop-hq/rubocop/issues/7675): Fix a false negative for `Layout/SpaceBeforeFirstArg` when a vertical argument positions are aligned. ([@koic][]) +* [#7688](https://github.com/rubocop-hq/rubocop/issues/7688): Fix a bug in `Style/MethodCallWithArgsParentheses` that made `--auto-gen-config` crash. ([@buehmann][]) +* [#7203](https://github.com/rubocop-hq/rubocop/issues/7203): Fix an infinite loop error for `Style/TernaryParentheses` with `Style/RedundantParentheses` when using `EnforcedStyle: require_parentheses_when_complex`. ([@koic][]) +* [#7708](https://github.com/rubocop-hq/rubocop/issues/7708): Make it possible to use EOL `rubocop:disable` comments on comment lines. ([@jonas054][]) +* [#7712](https://github.com/rubocop-hq/rubocop/issues/7712): Fix an incorrect auto-correct for `Style/OrAssignment` when using `elsif` branch. ([@koic][]) + +### Changes + +* [#7636](https://github.com/rubocop-hq/rubocop/issues/7636): Remove `console` from `Lint/Debugger` to prevent false positives. ([@gsamokovarov][]) +* [#7641](https://github.com/rubocop-hq/rubocop/issues/7641): **(Breaking)** Remove `Style/BracesAroundHashParameters` cop. ([@pocke][]) +* Add the method name to highlight area of `Layout/EmptyLineBetweenDefs` to help provide more context. ([@rrosenblum][]) +* [#7652](https://github.com/rubocop-hq/rubocop/pull/7652): Allow `pp` to allowed names of `Naming/MethodParameterName` cop in default config. ([@masarakki][]) +* [#7309](https://github.com/rubocop-hq/rubocop/pull/7309): Mark `Lint/UselessSetterCall` an "not safe" and improve documentation. ([@jonas054][]) +* [#7723](https://github.com/rubocop-hq/rubocop/pull/7723): Enable `Migration/DepartmentName` cop by default. ([@koic][]) + +## 0.79.0 (2020-01-06) + +### New features + +* [#7296](https://github.com/rubocop-hq/rubocop/issues/7296): Recognize `console` and `binding.console` ([rails/web-console](https://github.com/rails/web-console)) calls in `Lint/Debuggers`. ([@gsamokovarov][]) +* [#7567](https://github.com/rubocop-hq/rubocop/pull/7567): Introduce new `pending` status for new cops. ([@Darhazer][], [@pirj][]) +* [#7426](https://github.com/rubocop-hq/rubocop/issues/7426): Add `always_true` style to Style/FrozenStringLiteralComment. ([@parkerfinch][], [@gfyoung][]) + +### Bug fixes + +* [#7193](https://github.com/rubocop-hq/rubocop/issues/7193): Prevent `Style/PercentLiteralDelimiters` from changing `%i` literals that contain escaped delimiters. ([@buehmann][]) +* [#7590](https://github.com/rubocop-hq/rubocop/issues/7590): Fix an error for `Layout/SpaceBeforeBlockBraces` when using with `EnforcedStyle: line_count_based` of `Style/BlockDelimiters` cop. ([@koic][]) +* [#7569](https://github.com/rubocop-hq/rubocop/issues/7569): Make `Style/YodaCondition` accept `__FILE__ == $0`. ([@koic][]) +* [#7576](https://github.com/rubocop-hq/rubocop/issues/7576): Fix an error for `Gemspec/OrderedDependencies` when using a local variable in an argument of dependent gem. ([@koic][]) +* [#7595](https://github.com/rubocop-hq/rubocop/issues/7595): Make `Style/NumericPredicate` aware of ignored methods when specifying ignored methods. ([@koic][]) +* [#7607](https://github.com/rubocop-hq/rubocop/issues/7607): Fix `Style/FrozenStringLiteralComment` infinite loop when magic comments are newline-separated. ([@pirj][]) +* [#7602](https://github.com/rubocop-hq/rubocop/pull/7602): Ensure proper handling of Ruby 2.7 syntax. ([@drenmi][]) +* [#7620](https://github.com/rubocop-hq/rubocop/issues/7620): Fix a false positive for `Migration/DepartmentName` when a disable comment contains a plain comment. ([@koic][]) +* [#7616](https://github.com/rubocop-hq/rubocop/issues/7616): Fix an incorrect auto-correct for `Style/MultilineWhenThen` for when statement with then is an array or a hash. ([@koic][]) +* [#7628](https://github.com/rubocop-hq/rubocop/issues/7628): Fix an incorrect auto-correct for `Layout/MultilineBlockLayout` removing trailing comma with single argument. ([@pawptart][]) +* [#7627](https://github.com/rubocop-hq/rubocop/issues/7627): Fix a false negative for `Migration/DepartmentName` when there is space around `:` (e.g. `# rubocop : disable`). ([@koic][]) + +### Changes + +* [#7287](https://github.com/rubocop-hq/rubocop/issues/7287): `Style/FrozenStringLiteralComment` is now considered unsafe. ([@buehmann][]) + +## 0.78.0 (2019-12-18) + +### New features + +* [#7528](https://github.com/rubocop-hq/rubocop/pull/7528): Add new `Lint/NonDeterministicRequireOrder` cop. ([@mangara][]) +* [#7559](https://github.com/rubocop-hq/rubocop/pull/7559): Add `EnforcedStyleForExponentOperator` parameter to `Layout/SpaceAroundOperators` cop. ([@khiav223577][]) + +### Bug fixes + +* [#7530](https://github.com/rubocop-hq/rubocop/issues/7530): Typo in `Style/TrivialAccessors`'s `AllowedMethods`. ([@movermeyer][]) +* [#7532](https://github.com/rubocop-hq/rubocop/issues/7532): Fix an error for `Style/TrailingCommaInArguments` when using an anonymous function with multiple line arguments with `EnforcedStyleForMultiline: consistent_comma`. ([@koic][]) +* [#7534](https://github.com/rubocop-hq/rubocop/issues/7534): Fix an incorrect auto-correct for `Style/BlockDelimiters` cop and `Layout/SpaceBeforeBlockBraces` cop with `EnforcedStyle: no_space` when using multiline braces. ([@koic][]) +* [#7231](https://github.com/rubocop-hq/rubocop/issues/7231): Fix the exit code to be `2` rather when `0` when the config file contains an unknown cop. ([@jethroo][]) +* [#7513](https://github.com/rubocop-hq/rubocop/issues/7513): Fix abrupt error on auto-correcting with `--disable-uncorrectable`. ([@tejasbubane][]) +* [#7537](https://github.com/rubocop-hq/rubocop/issues/7537): Fix a false positive for `Layout/SpaceAroundOperators` when using a Rational literal with `/` (e.g. `2/3r`). ([@koic][]) +* [#7029](https://github.com/rubocop-hq/rubocop/issues/7029): Make `Style/Attr` not flag offense for custom `attr` method. ([@tejasbubane][]) +* [#7574](https://github.com/rubocop-hq/rubocop/issues/7574): Fix a corner case that made `Style/GuardClause` crash. ([@buehmann][]) + +### Changes + +* [#7514](https://github.com/rubocop-hq/rubocop/pull/7514): Expose correctable status on offense and in formatters. ([@tyler-ball][]) +* [#7542](https://github.com/rubocop-hq/rubocop/pull/7542): **(Breaking)** Move `LineLength` cop from `Metrics` department to `Layout` department. ([@koic][]) + +## 0.77.0 (2019-11-27) + +### Bug fixes + +* [#7493](https://github.com/rubocop-hq/rubocop/issues/7493): Fix `Style/RedundantReturn` to inspect conditional constructs that are preceded by other statements. ([@buehmann][]) +* [#7509](https://github.com/rubocop-hq/rubocop/issues/7509): Fix `Layout/SpaceInsideArrayLiteralBrackets` to correct empty lines. ([@ayacai115][]) +* [#7517](https://github.com/rubocop-hq/rubocop/issues/7517): `Style/SpaceAroundKeyword` allows `::` after `super`. ([@ozydingo][]) +* [#7515](https://github.com/rubocop-hq/rubocop/issues/7515): Fix a false negative for `Style/RedundantParentheses` when calling a method with safe navigation operator. ([@koic][]) +* [#7477](https://github.com/rubocop-hq/rubocop/issues/7477): Fix line length auto-correct for semicolons in string literals. ([@maxh][]) +* [#7522](https://github.com/rubocop-hq/rubocop/pull/7522): Fix a false-positive edge case (`n % 2 == 2`) for `Style/EvenOdd`. ([@buehmann][]) +* [#7506](https://github.com/rubocop-hq/rubocop/issues/7506): Make `Style/IfUnlessModifier` respect all settings in `Metrics/LineLength`. ([@jonas054][]) + +### Changes + +* [#7077](https://github.com/rubocop-hq/rubocop/issues/7077): **(Breaking)** Further standardisation of cop names. ([@scottmatthewman][]) +* [#7469](https://github.com/rubocop-hq/rubocop/pull/7469): **(Breaking)** Replace usages of the terms `Whitelist` and `Blacklist` with better alternatives. ([@koic][]) +* [#7502](https://github.com/rubocop-hq/rubocop/pull/7502): Remove `SafeMode` module. ([@koic][]) + +## 0.76.0 (2019-10-28) + +### Bug fixes + +* [#7439](https://github.com/rubocop-hq/rubocop/issues/7439): Make `Style/FormatStringToken` ignore percent escapes (`%%`). ([@buehmann][]) +* [#7438](https://github.com/rubocop-hq/rubocop/issues/7438): Fix assignment edge-cases in `Layout/MultilineAssignmentLayout`. ([@gsamokovarov][]) +* [#7449](https://github.com/rubocop-hq/rubocop/pull/7449): Make `Style/IfUnlessModifier` respect `rubocop:disable` comments for `Metrics/LineLength`. ([@jonas054][]) +* [#7442](https://github.com/rubocop-hq/rubocop/issues/7442): Fix an incorrect auto-correct for `Style/SafeNavigation` when an object check followed by a method call with a comment at EOL. ([@koic][]) +* [#7434](https://github.com/rubocop-hq/rubocop/issues/7434): Fix an incorrect auto-correct for `Style/MultilineWhenThen` when the body of `when` branch starts with `then`. ([@koic][]) +* [#7464](https://github.com/rubocop-hq/rubocop/pull/7464): Let `Performance/StartWith` and `Performance/EndWith` correct regexes that contain forward slashes. ([@eugeneius][]) + +### Changes + +* [#7465](https://github.com/rubocop-hq/rubocop/pull/7465): Add `os` to allowed names of `Naming/UncommunicativeMethodParamName` cop in default config. ([@nijikon][]) +* [#7446](https://github.com/rubocop-hq/rubocop/issues/7446): Add `merge` to list of non-mutating methods. ([@cstyles][]) +* [#7077](https://github.com/rubocop-hq/rubocop/issues/7077): **(Breaking)** Rename `Unneeded*` cops to `Redundant*` (e.g., `Style/UnneededPercentQ` becomes `Style/RedundantPercentQ`). ([@scottmatthewman][]) +* [#7396](https://github.com/rubocop-hq/rubocop/issues/7396): Display assignments, branches, and conditions values with the offense. ([@avmnu-sng][]) + +## 0.75.1 (2019-10-14) + +### Bug fixes + +* [#7391](https://github.com/rubocop-hq/rubocop/issues/7391): Support pacman formatter on Windows. ([@laurenball][]) +* [#7407](https://github.com/rubocop-hq/rubocop/issues/7407): Make `Style/FormatStringToken` work inside hashes. ([@buehmann][]) +* [#7389](https://github.com/rubocop-hq/rubocop/issues/7389): Fix an issue where passing a formatter might result in an error depending on what character it started with. ([@jfhinchcliffe][]) +* [#7397](https://github.com/rubocop-hq/rubocop/issues/7397): Fix extra comments being added to the correction of `Style/SafeNavigation`. ([@rrosenblum][]) +* [#7378](https://github.com/rubocop-hq/rubocop/pull/7378): Fix heredoc edge cases in `Layout/EmptyLineAfterGuardClause`. ([@gsamokovarov][]) +* [#7404](https://github.com/rubocop-hq/rubocop/issues/7404): Fix a false negative for `Layout/IndentAssignment` when multiple assignment with line breaks on each line. ([@koic][]) + +### Changes + +* [#7410](https://github.com/rubocop-hq/rubocop/issues/7410): `Style/FormatStringToken` now finds unannotated format sequences in `printf` arguments. ([@buehmann][]) +* [#6964](https://github.com/rubocop-hq/rubocop/issues/6964): Set default `IgnoreCopDirectives` to `true` for `Metrics/LineLength`. ([@jdkaplan][]) + +## 0.75.0 (2019-09-30) + +### New features + +* [#7274](https://github.com/rubocop-hq/rubocop/issues/7274): Add new `Lint/SendWithMixinArgument` cop. ([@koic][]) +* [#7272](https://github.com/rubocop-hq/rubocop/pull/7272): Show warning message if passed string to `Enabled`, `Safe`, `SafeAuto-Correct`, and `Auto-Correct` keys in .rubocop.yml. ([@unasuke][]) +* [#7295](https://github.com/rubocop-hq/rubocop/pull/7295): Make it possible to set `StyleGuideBaseURL` per department. ([@koic][]) +* [#7301](https://github.com/rubocop-hq/rubocop/pull/7301): Add check for calls to `remote_byebug` to `Lint/Debugger` cop. ([@riley-klingler][]) +* [#7321](https://github.com/rubocop-hq/rubocop/issues/7321): Allow YAML aliases in `.rubocop.yml`. ([@raymondfallon][]) +* [#7317](https://github.com/rubocop-hq/rubocop/pull/7317): Add new formatter `pacman`. ([@crojasaragonez][]) +* [#6075](https://github.com/rubocop-hq/rubocop/issues/6075): Support `IgnoredPatterns` option for `Naming/MethodName` cop. ([@koic][]) +* [#7335](https://github.com/rubocop-hq/rubocop/pull/7335): Add todo as an alias to disable. `--disable-uncorrectable` will now disable cops using `rubocop:todo` instead of `rubocop:disable`. ([@desheikh][]) + +### Bug fixes + +* [#7391](https://github.com/rubocop-hq/rubocop/issues/7391): Support pacman formatter on Windows. ([@laurenball][]) +* [#7256](https://github.com/rubocop-hq/rubocop/issues/7256): Fix an error of `Style/RedundantParentheses` on method calls where the first argument begins with a hash literal. ([@halfwhole][]) +* [#7263](https://github.com/rubocop-hq/rubocop/issues/7263): Make `Layout/SpaceInsideArrayLiteralBrackets` properly handle tab-indented arrays. ([@buehmann][]) +* [#7252](https://github.com/rubocop-hq/rubocop/issues/7252): Prevent infinite loops by making `Layout/SpaceInsideStringInterpolation` skip over interpolations that start or end with a line break. ([@buehmann][]) +* [#7262](https://github.com/rubocop-hq/rubocop/issues/7262): `Lint/FormatParameterMismatch` did not recognize named format sequences like `%.2f` where the name appears after some modifiers. ([@buehmann][]) +* [#7253](https://github.com/rubocop-hq/rubocop/issues/7253): Fix an error for `Lint/NumberConversion` when `#to_i` called without a receiver. ([@koic][]) +* [#7271](https://github.com/rubocop-hq/rubocop/issues/7271), [#6498](https://github.com/rubocop-hq/rubocop/issues/6498): Fix an interference between `Style/TrailingCommaIn*Literal` and `Layout/Multiline*BraceLayout` for arrays and hashes. ([@buehmann][]) +* [#7241](https://github.com/rubocop-hq/rubocop/issues/7241): Make `Style/FrozenStringLiteralComment` match only true & false. ([@tejasbubane][]) +* [#7290](https://github.com/rubocop-hq/rubocop/issues/7290): Handle inner conditional inside `else` in `Style/ConditionalAssignment`. ([@jonas054][]) +* [#5788](https://github.com/rubocop-hq/rubocop/issues/5788): Allow block arguments on separate lines if line would be too long in `Layout/MultilineBlockLayout`. ([@jonas054][]) +* [#7305](https://github.com/rubocop-hq/rubocop/issues/7305): Register `Style/BlockDelimiters` offense when block result is assigned to an attribute. ([@mvz][]) +* [#4802](https://github.com/rubocop-hq/rubocop/issues/4802): Don't leave any `Lint/UnneededCopEnableDirective` offenses undetected/uncorrected. ([@jonas054][]) +* [#7326](https://github.com/rubocop-hq/rubocop/issues/7326): Fix a false positive for `Style/AccessModifierDeclarations` when access modifier name is used for hash literal value. ([@koic][]) +* [#3591](https://github.com/rubocop-hq/rubocop/issues/3591): Handle modifier `if`/`unless` correctly in `Lint/UselessAssignment`. ([@jonas054][]) +* [#7161](https://github.com/rubocop-hq/rubocop/issues/7161): Fix `Style/SafeNavigation` cop for preserve comments inside if expression. ([@tejasbubane][]) +* [#5212](https://github.com/rubocop-hq/rubocop/issues/5212): Avoid false positive for braces that are needed to preserve semantics in `Style/BracesAroundHashParameters`. ([@jonas054][]) +* [#7353](https://github.com/rubocop-hq/rubocop/issues/7353): Fix a false positive for `Style/RedundantSelf` when receiver and multiple assigned lvalue have the same name. ([@koic][]) +* [#7353](https://github.com/rubocop-hq/rubocop/issues/7353): Fix a false positive for `Style/RedundantSelf` when a self receiver is used as a method argument. ([@koic][]) +* [#7358](https://github.com/rubocop-hq/rubocop/issues/7358): Fix an incorrect auto-correct for `Style/NestedModifier` when parentheses are required in method arguments. ([@koic][]) +* [#7361](https://github.com/rubocop-hq/rubocop/issues/7361): Fix a false positive for `Style/TernaryParentheses` when only the closing parenthesis is used in the last line of condition. ([@koic][]) +* [#7369](https://github.com/rubocop-hq/rubocop/issues/7369): Fix an infinite loop error for `Layout/IndentAssignment` with `Layout/IndentFirstArgument` when using multiple assignment. ([@koic][]) +* [#7177](https://github.com/rubocop-hq/rubocop/issues/7177), [#7370](https://github.com/rubocop-hq/rubocop/issues/7370): When correcting alignment, do not insert spaces into string literals. ([@buehmann][]) +* [#7367](https://github.com/rubocop-hq/rubocop/issues/7367): Fix an error for `Style/OrAssignment` cop when `then` branch body is empty. ([@koic][]) +* [#7363](https://github.com/rubocop-hq/rubocop/issues/7363): Fix an incorrect auto-correct for `Layout/SpaceInsideBlockBraces` and `Style/BlockDelimiters` when using multiline empty braces. ([@koic][]) +* [#7212](https://github.com/rubocop-hq/rubocop/issues/7212): Fix a false positive for `Layout/EmptyLinesAroundAccessModifier` and `UselessAccessModifier` when using method with the same name as access modifier around a method definition. ([@koic][]) + +### Changes + +* [#7312](https://github.com/rubocop-hq/rubocop/pull/7312): Mark `Style/StringHashKeys` as unsafe. ([@prathamesh-sonpatki][]) +* [#7275](https://github.com/rubocop-hq/rubocop/issues/7275): Make `Style/VariableName` aware argument names when invoking a method. ([@koic][]) +* [#3534](https://github.com/rubocop-hq/rubocop/issues/3534): Make `Style/IfUnlessModifier` report and auto-correct modifier lines that are too long. ([@jonas054][]) +* [#7261](https://github.com/rubocop-hq/rubocop/issues/7261): `Style/FrozenStringLiteralComment` no longer inserts an empty line after the comment. This is left to `Layout/EmptyLineAfterMagicComment`. ([@buehmann][]) +* [#7091](https://github.com/rubocop-hq/rubocop/issues/7091): `Style/FormatStringToken` now detects format sequences with flags and modifiers. ([@buehmann][]) +* [#7319](https://github.com/rubocop-hq/rubocop/pull/7319): Rename `IgnoredMethodPatterns` option to `IgnoredPatterns` option for `Style/MethodCallWithArgsParentheses`. ([@koic][]) +* [#7345](https://github.com/rubocop-hq/rubocop/issues/7345): Mark unsafe for `Style/YodaCondition`. ([@koic][]) + +## 0.74.0 (2019-07-31) + +### New features + +* [#7219](https://github.com/rubocop-hq/rubocop/issues/7219): Support auto-correct for `Lint/ErbNewArguments`. ([@koic][]) + +### Bug fixes + +* [#7217](https://github.com/rubocop-hq/rubocop/pull/7217): Make `Style/TrailingMethodEndStatement` work on more than the first `def`. ([@buehmann][]) +* [#7190](https://github.com/rubocop-hq/rubocop/issues/7190): Support lower case drive letters on Windows. ([@jonas054][]) +* Fix the auto-correction of `Lint/UnneededSplatExpansion` when the splat expansion of `Array.new` with a block is assigned to a variable. ([@rrosenblum][]) +* [#5628](https://github.com/rubocop-hq/rubocop/issues/5628): Fix an error of `Layout/SpaceInsideStringInterpolation` on interpolations with multiple statements. ([@buehmann][]) +* [#7128](https://github.com/rubocop-hq/rubocop/issues/7128): Make `Metrics/LineLength` aware of shebang. ([@koic][]) +* [#6861](https://github.com/rubocop-hq/rubocop/issues/6861): Fix a false positive for `Layout/IndentationWidth` when using `EnforcedStyle: outdent` of `Layout/AccessModifierIndentation`. ([@koic][]) +* [#7235](https://github.com/rubocop-hq/rubocop/issues/7235): Fix an error where `Style/ConditionalAssignment` would swallow a nested `if` condition. ([@buehmann][]) +* [#7242](https://github.com/rubocop-hq/rubocop/issues/7242): Make `Style/ConstantVisibility` work on non-trivial class and module bodies. ([@buehmann][]) + +### Changes + +* [#5265](https://github.com/rubocop-hq/rubocop/issues/5265): Improved `Layout/ExtraSpacing` cop to handle nested consecutive assignments. ([@jfelchner][]) +* [#7215](https://github.com/rubocop-hq/rubocop/issues/7215): Make it clear what's wrong in the message from `Style/GuardClause`. ([@jonas054][]) +* [#7245](https://github.com/rubocop-hq/rubocop/pull/7245): Make cops detect string interpolations in more contexts: inside of backticks, regular expressions, and symbols. ([@buehmann][]) +* Deprecate the `SafeMode` option. Users will need to upgrade `rubocop-performance` to 1.15.0+ before the `SafeMode` module is removed. ([@rrosenblum][]) + +## 0.73.0 (2019-07-16) + +### New features + +* Add `AllowDoxygenCommentStyle` configuration on `Layout/LeadingCommentSpace`. ([@anthony-robin][]) +* [#7114](https://github.com/rubocop-hq/rubocop/pull/7114): Add `MultilineWhenThen` cop. ([@okuramasafumi][]) +* [#4127](https://github.com/rubocop-hq/rubocop/pull/4127): Add `--disable-uncorrectable` flag to generate `rubocop:disable` comments. ([@vergenzt][], [@jonas054][]) + +### Bug fixes + +* [#7170](https://github.com/rubocop-hq/rubocop/issues/7170): Fix a false positive for `Layout/RescueEnsureAlignment` when def line is preceded with `private_class_method`. ([@tatsuyafw][]) +* [#7186](https://github.com/rubocop-hq/rubocop/issues/7186): Fix a false positive for `Style/MixinUsage` when using inside multiline block and `if` condition is after `include`. ([@koic][]) +* [#7099](https://github.com/rubocop-hq/rubocop/issues/7099): Fix an error of `Layout/RescueEnsureAlignment` on assigned blocks. ([@tatsuyafw][]) +* [#5088](https://github.com/rubocop-hq/rubocop/issues/5088): Fix an error of `Layout/MultilineMethodCallIndentation` on method chains inside an argument. ([@buehmann][]) +* [#4719](https://github.com/rubocop-hq/rubocop/issues/4719): Make `Layout/Tab` detect tabs between string literals. ([@buehmann][]) +* [#7203](https://github.com/rubocop-hq/rubocop/pull/7203): Fix an infinite loop error for `Layout/SpaceInsideBlockBraces` when `EnforcedStyle: no_space` with `SpaceBeforeBlockParameters: false` are set in multiline block. ([@koic][]) +* [#6653](https://github.com/rubocop-hq/rubocop/issues/6653): Fix a bug where `Layout/IndentHeredoc` would remove empty lines when auto-correcting heredocs. ([@buehmann][]) + +### Changes + +* [#7181](https://github.com/rubocop-hq/rubocop/pull/7181): Sort analyzed file alphabetically. ([@pocke][]) +* [#7188](https://github.com/rubocop-hq/rubocop/pull/7188): Include inspected file location in auto-correction error. ([@pocke][]) + +## 0.72.0 (2019-06-25) + +### New features + +* [#7137](https://github.com/rubocop-hq/rubocop/issues/7137): Add new `Gemspec/RubyVersionGlobalsUsage` cop. ([@malyshkosergey][]) +* [#7150](https://github.com/rubocop-hq/rubocop/pull/7150): Add `AllowIfModifier` option to `Style/IfInsideElse` cop. ([@koic][]) +* [#7153](https://github.com/rubocop-hq/rubocop/pull/7153): Add new cop `Style/FloatDivision` that checks coercion. ([@tejasbubane][]) + +### Bug fixes + +* [#7121](https://github.com/rubocop-hq/rubocop/pull/7121): Fix `Style/TernaryParentheses` cop to allow safe navigation operator without parentheses. ([@timon][]) +* [#7063](https://github.com/rubocop-hq/rubocop/issues/7063): Fix auto-correct in `Style/TernaryParentheses` cop. ([@parkerfinch][]) +* [#7106](https://github.com/rubocop-hq/rubocop/issues/7106): Fix an error for `Lint/NumberConversion` when `#to_i` called on a variable on a hash. ([@koic][]) +* [#7107](https://github.com/rubocop-hq/rubocop/issues/7107): Fix parentheses offence for numeric arguments with an operator in `Style/MethodCallWithArgsParentheses`. ([@gsamokovarov][]) +* [#7119](https://github.com/rubocop-hq/rubocop/pull/7119): Fix cache with non UTF-8 offense message. ([@pocke][]) +* [#7118](https://github.com/rubocop-hq/rubocop/pull/7118): Fix `Style/WordArray` with `encoding: binary` magic comment and non-ASCII string. ([@pocke][]) +* [#7159](https://github.com/rubocop-hq/rubocop/issues/7159): Fix an error for `Lint/DuplicatedKey` when using endless range. ([@koic][]) +* [#7151](https://github.com/rubocop-hq/rubocop/issues/7151): Fix `Style/WordArray` to also consider words containing hyphens. ([@fwitzke][]) +* [#6893](https://github.com/rubocop-hq/rubocop/issues/6893): Handle implicit rescue correctly in `Naming/RescuedExceptionsVariableName`. ([@pocke][], [@anthony-robin][]) +* [#7165](https://github.com/rubocop-hq/rubocop/issues/7165): Fix an auto-correct error for `Style/ConditionalAssignment` when without `else` branch'. ([@koic][]) +* [#7171](https://github.com/rubocop-hq/rubocop/issues/7171): Fix an error for `Style/SafeNavigation` when using `unless nil?` as a safeguarded'. ([@koic][]) +* [#7130](https://github.com/rubocop-hq/rubocop/pull/7130): Skip auto-correct in `Style/FormatString` if second argument to `String#%` is a variable. ([@tejasbubane][]) +* [#7171](https://github.com/rubocop-hq/rubocop/issues/7171): Fix an error for `Style/SafeNavigation` when using `unless nil?` as a safeguarded'. ([@koic][]) + +### Changes + +* [#5976](https://github.com/rubocop-hq/rubocop/issues/5976): Remove Rails cops. ([@koic][]) +* [#5976](https://github.com/rubocop-hq/rubocop/issues/5976): Remove `rubocop -R/--rails` option. ([@koic][]) +* [#7113](https://github.com/rubocop-hq/rubocop/pull/7113): Rename `EnforcedStyle: rails` to `EnabledStyle: indented_internal_methods` for `Layout/IndentationConsistency`. ([@koic][]) + +## 0.71.0 (2019-05-30) + +### New features + +* [#7084](https://github.com/rubocop-hq/rubocop/pull/7084): Permit to specify TargetRubyVersion 2.7. ([@koic][]) +* [#7092](https://github.com/rubocop-hq/rubocop/pull/7092): Node patterns can now use `*`, `+` and `?` for repetitions. ([@marcandre][]) + +### Bug fixes + +* [#7066](https://github.com/rubocop-hq/rubocop/issues/7066): Fix `Layout/AlignHash` when mixed Hash styles are used. ([@rmm5t][]) +* [#7073](https://github.com/rubocop-hq/rubocop/issues/7073): Fix false positive in `Naming/RescuedExceptionsVariableName` cop. ([@tejasbubane][]) +* [#7090](https://github.com/rubocop-hq/rubocop/pull/7090): Fix `Layout/EmptyLinesAroundBlockBody` for multi-line method calls. ([@eugeneius][]) +* [#6936](https://github.com/rubocop-hq/rubocop/issues/6936): Fix `Layout/MultilineMethodArgumentLineBreaks` when bracket hash assignment on multiple lines. ([@maxh][]) +* Mark `Layout/HeredocArgumentClosingParenthesis` incompatible with `Style/TrailingCommaInArguments`. ([@maxh][]) + +### Changes + +* [#5976](https://github.com/rubocop-hq/rubocop/issues/5976): Warn for Rails Cops. ([@koic][]) +* [#5976](https://github.com/rubocop-hq/rubocop/issues/5976): Warn for `rubocop -R/--rails` option. ([@koic][]) +* [#7078](https://github.com/rubocop-hq/rubocop/issues/7078): Mark `Lint/PercentStringArray` as unsafe. ([@mikegee][]) + +## 0.70.0 (2019-05-21) + +### New features + +* [#6649](https://github.com/rubocop-hq/rubocop/pull/6649): `Layout/AlignHash` supports list of options. ([@stoivo][]) +* Add `IgnoreMethodPatterns` config option to `Style/MethodCallWithArgsParentheses`. ([@tejasbubane][]) +* [#7059](https://github.com/rubocop-hq/rubocop/pull/7059): Add `EnforcedStyle` to `Layout/EmptyLinesAroundAccessModifier`. ([@koic][]) +* [#7052](https://github.com/rubocop-hq/rubocop/issues/7052): Add `AllowComments` option to ` Lint/HandleExceptions`. ([@tejasbubane][]) + +### Bug fixes + +* [#7013](https://github.com/rubocop-hq/rubocop/pull/7013): Respect DisabledByDefault for custom cops. ([@XrXr][]) +* [#7043](https://github.com/rubocop-hq/rubocop/issues/7043): Prevent RDoc error when installing RuboCop 0.69.0 on Ubuntu. ([@koic][]) +* [#7023](https://github.com/rubocop-hq/rubocop/issues/7023): Auto-Correction for `Lint/NumberConversion`. ([@Bhacaz][]) + +### Changes + +* [#6359](https://github.com/rubocop-hq/rubocop/issues/6359): Mark `Style/PreferredHashMethods` as unsafe. ([@tejasbubane][]) + +## 0.69.0 (2019-05-13) + +### New features + +* Add support for subclassing using `Class.new` to `Lint/InheritException`. ([@houli][]) +* [#6779](https://github.com/rubocop-hq/rubocop/issues/6779): Add new cop `Style/NegatedUnless` that checks for unless with negative condition. ([@tejasbubane][]) + +### Bug fixes + +* [#6900](https://github.com/rubocop-hq/rubocop/issues/6900): Fix `Rails/TimeZone` auto-correct `Time.current` to `Time.zone.now`. ([@vfonic][]) +* [#6900](https://github.com/rubocop-hq/rubocop/issues/6900): Fix `Rails/TimeZone` to prefer `Time.zone.#{method}` over other acceptable corrections. ([@vfonic][]) +* [#7007](https://github.com/rubocop-hq/rubocop/pull/7007): Fix `Style/BlockDelimiters` with `braces_for_chaining` style false positive, when chaining using safe navigation. ([@Darhazer][]) +* [#6880](https://github.com/rubocop-hq/rubocop/issues/6880): Fix `.rubocop` file parsing. ([@hoshinotsuyoshi][]) +* [#5782](https://github.com/rubocop-hq/rubocop/issues/5782): Do not auto-correct `Lint/UnifiedInteger` if `TargetRubyVersion < 2.4`. ([@lavoiesl][]) +* [#6387](https://github.com/rubocop-hq/rubocop/issues/6387): Prevent `Lint/NumberConversion` from reporting error with `Time`/`DateTime`. ([@tejasbubane][]) +* [#6980](https://github.com/rubocop-hq/rubocop/issues/6980): Fix `Style/StringHashKeys` to allow string as keys for hash arguments to gsub methods. ([@tejasbubane][]) +* [#6969](https://github.com/rubocop-hq/rubocop/issues/6969): Fix a false positive with block methods in `Style/InverseMethods`. ([@dduugg][]) +* [#6729](https://github.com/rubocop-hq/rubocop/pull/6729): Handle array spread for `change_column_default` in `Rails/ReversibleMigration` cop. ([@tejasbubane][]) +* [#7033](https://github.com/rubocop-hq/rubocop/issues/7033): Fix an error for `Layout/EmptyLineAfterGuardClause` when guard clause is a ternary operator. ([@koic][]) +* Replace `Time.zone.current` with `Time.zone.today` on `Rails::Date` cop message. ([@vfonic][]) + +### Changes + +* [#6945](https://github.com/rubocop-hq/rubocop/issues/6945): Drop support for Ruby 2.2. ([@koic][]) +* [#6945](https://github.com/rubocop-hq/rubocop/issues/6945): Set default `EnforcedStyle` to `squiggly` option for `Layout/IndentHeredoc` and `auto_detection` option is removed. ([@koic][]) +* [#6945](https://github.com/rubocop-hq/rubocop/issues/6945): Set default `EnforcedStyle` to `always` option for `Style/FrozenStringLiteralComment` and `when_needed` option is removed. ([@koic][]) +* [#7027](https://github.com/rubocop-hq/rubocop/pull/7027): Allow `unicode/display_width` dependency version 1.6.0. ([@tagliala][]) + +## 0.68.1 (2019-04-30) + +### Bug fixes + +* [#6993](https://github.com/rubocop-hq/rubocop/pull/6993): Allowing for empty if blocks, preventing `Style/SafeNavigation` from crashing. ([@RicardoTrindade][]) +* [#6995](https://github.com/rubocop-hq/rubocop/pull/6995): Fix an incorrect auto-correct for `Style/RedundantParentheses` when enclosed in parentheses at `while-post` or `until-post`. ([@koic][]) +* [#6996](https://github.com/rubocop-hq/rubocop/pull/6996): Fix a false positive for `Style/RedundantFreeze` when freezing the result of `String#*`. ([@bquorning][]) +* [#6998](https://github.com/rubocop-hq/rubocop/pull/6998): Fix auto-correct of `Naming/RescuedExceptionsVariableName` to also rename all references to the variable. ([@Darhazer][]) +* [#6992](https://github.com/rubocop-hq/rubocop/pull/6992): Fix unknown default configuration for `Layout/IndentFirstParameter` cop. ([@drenmi][]) +* [#6972](https://github.com/rubocop-hq/rubocop/issues/6972): Fix a false positive for `Style/MixinUsage` when using inside block and `if` condition is after `include`. ([@koic][]) +* [#6738](https://github.com/rubocop-hq/rubocop/issues/6738): Prevent auto-correct conflict of `Style/Next` and `Style/SafeNavigation`. ([@hoshinotsuyoshi][]) +* [#6847](https://github.com/rubocop-hq/rubocop/pull/6847): Fix `Style/BlockDelimiters` to properly check if the node is chained when `braces_for_chaining` is set. ([@att14][]) + + +## 0.68.0 (2019-04-29) + +### New features + +* [#6973](https://github.com/rubocop-hq/rubocop/pull/6973): Add `always_braces` to `Style/BlockDelimiter`. ([@iGEL][]) +* [#6841](https://github.com/rubocop-hq/rubocop/issues/6841): Node patterns can now match children in any order using `<>`. ([@marcandre][]) +* [#6928](https://github.com/rubocop-hq/rubocop/pull/6928): Add `--init` option for generate `.rubocop.yml` file in the current directory. ([@koic][]) +* Add new `Layout/HeredocArgumentClosingParenthesis` cop. ([@maxh][]) +* [#6895](https://github.com/rubocop-hq/rubocop/pull/6895): Add support for XDG config home for user-config. ([@Mange][], [@tejasbubane][]) +* Add initial auto-correction support to `Metrics/LineLength`. ([@maxh][]) +* Add `Layout/IndentFirstParameter`. ([@maxh][]) +* [#6974](https://github.com/rubocop-hq/rubocop/issues/6974): Make `Layout/FirstMethodArgumentLineBreak` aware of calling using `super`. ([@koic][]) +* Add new `Lint/HeredocMethodCallPosition` cop. ([@maxh][]) + + +### Bug fixes + +* Do not annotate message with cop name in JSON output. ([@elebow][]) +* [#6914](https://github.com/rubocop-hq/rubocop/issues/6914): Fix an error for `Rails/RedundantAllowNil` when with interpolations. ([@Blue-Pix][]) +* [#6888](https://github.com/rubocop-hq/rubocop/issues/6888): Fix an error for `Rails/ActiveRecordOverride ` when no `parent_class` present. ([@diachini][]) +* [#6941](https://github.com/rubocop-hq/rubocop/issues/6941): Add missing absence validations to `Rails/Validation`. ([@jmanian][]) +* [#6926](https://github.com/rubocop-hq/rubocop/issues/6926): Allow nil values to unset config defaults. ([@dduugg][]) +* [#6946](https://github.com/rubocop-hq/rubocop/pull/6946): Allow `Rails/ReflectionClassName` to use string interpolation for `class_name`. ([@r7kamura][]) +* [#6778](https://github.com/rubocop-hq/rubocop/issues/6778): Fix a false positive in `Style/HashSyntax` cop when a hash key is an interpolated string and EnforcedStyle is ruby19_no_mixed_keys. ([@tatsuyafw][]) +* [#6902](https://github.com/rubocop-hq/rubocop/issues/6902): Fix a bug where `Naming/RescuedExceptionsVariableName` would handle an only first rescue for multiple rescue groups. ([@tatsuyafw][]) +* [#6860](https://github.com/rubocop-hq/rubocop/issues/6860): Prevent auto-correct conflict of `Style/InverseMethods` and `Style/Not`. ([@hoshinotsuyoshi][]) +* [#6935](https://github.com/rubocop-hq/rubocop/issues/6935): `Layout/AccessModifierIndentation` should ignore access modifiers that apply to specific methods. ([@deivid-rodriguez][]) +* [#6956](https://github.com/rubocop-hq/rubocop/issues/6956): Prevent auto-correct confliction of `Lint/Lambda` and `Lint/UnusedBlockArgument`. ([@koic][]) +* [#6915](https://github.com/rubocop-hq/rubocop/issues/6915): Fix false positive in `Style/SafeNavigation` when a modifier if is safe guarding a method call being passed to `break`, `fail`, `next`, `raise`, `return`, `throw`, and `yield`. ([@rrosenblum][]) +* [#6822](https://github.com/rubocop-hq/rubocop/issues/6822): Fix Lint/LiteralInInterpolation auto-correction for single quotes. ([@hoshinotsuyoshi][]) +* [#6985](https://github.com/rubocop-hq/rubocop/issues/6985): Fix an incorrect auto-correct for `Lint/LiteralInInterpolation` if contains array percent literal. ([@yakout][]) +* [#7003](https://github.com/rubocop-hq/rubocop/pull/7003): Fix an incorrect auto-correct for `Style/InverseMethods` when using `BasicObject#!`. ([@koic][]) + +### Changes + +* [#6966](https://github.com/rubocop-hq/rubocop/pull/6966): Mark Rails/TimeZone as unsafe. ([@vfonic][]) +* [#5977](https://github.com/rubocop-hq/rubocop/issues/5977): Remove Performance cops. ([@koic][]) +* Add auto-correction to `Naming/RescuedExceptionsVariableName`. ([@anthony-robin][]) +* [#6903](https://github.com/rubocop-hq/rubocop/issues/6903): Handle variables prefixed with `_` in `Naming/RescuedExceptionsVariableName` cop. ([@anthony-robin][]) +* [#6917](https://github.com/rubocop-hq/rubocop/issues/6917): Bump Bundler dependency to >= 1.15.0. ([@koic][]) +* Add `--auto-gen-only-exclude` to the command outputted in `rubocop_todo.yml` if the option is specified. ([@dvandersluis][]) +* [#6887](https://github.com/rubocop-hq/rubocop/pull/6887): Allow `Lint/UnderscorePrefixedVariableName` cop to be configured to allow use of block keyword args. ([@dduugg][]) +* [#6885](https://github.com/rubocop-hq/rubocop/pull/6885): Revert adding psych >= 3.1 as runtime dependency. ([@andreaseger][]) +* Rename `Layout/FirstParameterIndentation` to `Layout/IndentFirstArgument`. ([@maxh][]) +* Extract method call argument alignment behavior from `Layout/AlignParameters` into `Layout/AlignArguments`. ([@maxh][]) +* Rename `IndentArray` and `IndentHash` to `IndentFirstArrayElement` and `IndentFirstHashElement`. ([@maxh][]) + +## 0.67.2 (2019-04-05) + +### Bug fixes + +* [#6882](https://github.com/rubocop-hq/rubocop/issues/6882): Fix an error for `Rails/RedundantAllowNil` when not using both `allow_nil` and `allow_blank`. ([@koic][]) + +## 0.67.1 (2019-04-04) + +### Changes + +* [#6881](https://github.com/rubocop-hq/rubocop/pull/6881): Set default `PreferredName` to `e` for `Naming/RescuedExceptionsVariableName`. ([@koic][]) + +## 0.67.0 (2019-04-04) + +### New features + +* [#5184](https://github.com/rubocop-hq/rubocop/issues/5184): Add new multiline element line break cops. ([@maxh][]) +* Add new cop `Rails/ActiveRecordOverride` that checks for overriding Active Record methods instead of using callbacks. ([@elebow][]) +* Add new cop `Rails/RedundantAllowNil` that checks for cases when `allow_blank` makes `allow_nil` unnecessary in model validations. ([@elebow][]) +* Add new `Naming/RescuedExceptionsVariableName` cop. ([@AdrienSldy][]) + +### Bug fixes + +* [#6761](https://github.com/rubocop-hq/rubocop/issues/6761): Make `Naming/UncommunicativeMethodParamName` account for param names prefixed with underscores. ([@thomthom][]) +* [#6855](https://github.com/rubocop-hq/rubocop/pull/6855): Fix an exception in `Rails/RedundantReceiverInWithOptions` when the body is empty. ([@ericsullivan][]) +* [#6856](https://github.com/rubocop-hq/rubocop/pull/6856): Fix auto-correction for `Style/BlockComments` when the file is missing a trailing blank line. ([@ericsullivan][]) +* [#6858](https://github.com/rubocop-hq/rubocop/issues/6858): Fix an incorrect auto-correct for `Lint/ToJSON` when there are no `to_json` arguments. ([@koic][]) +* [#6865](https://github.com/rubocop-hq/rubocop/pull/6865): Fix deactivated `StyleGuideBaseURL` for `Layout/ClassStructure`. ([@aeroastro][]) +* [#6868](https://github.com/rubocop-hq/rubocop/pull/6868): Fix `Rails/LinkToBlank` auto-correct bug when using symbol for target. ([@r7kamura][]) +* [#6869](https://github.com/rubocop-hq/rubocop/pull/6869): Fix false positive for `Rails/LinkToBlank` when rel is a symbol value. ([@r7kamura][]) +* Add `IncludedMacros` param to default rubocop config for `Style/MethodCallWithArgsParentheses`. ([@maxh][]) +* [#6785](https://github.com/rubocop-hq/rubocop/issues/6785): Do not register an offense for `Rails/Present` or `Rails/Blank` in an `unless else` context when `Style/UnlessElse` is enabled. ([@rrosenblum][]) + +### Changes + +* [#6854](https://github.com/rubocop-hq/rubocop/pull/6854): Mark Rails/LexicallyScopedActionFilter as unsafe and document risks. ([@urbanautomaton][]) +* [#5977](https://github.com/rubocop-hq/rubocop/issues/5977): Warn for Performance Cops. ([@koic][]) +* [#6637](https://github.com/rubocop-hq/rubocop/issues/6637): Move `LstripRstrip` from `Performance` to `Style` department and rename it to `Strip`. ([@anuja-joshi][]) +* [#6875](https://github.com/rubocop-hq/rubocop/pull/6875): Mention block form of `Struct.new` in ` Style/StructInheritance`. ([@XrXr][]) +* [#6871](https://github.com/rubocop-hq/rubocop/issues/6871): Move `Performance/RedundantSortBy`, `Performance/UnneededSort` and `Performance/Sample` to the Style department. ([@bbatsov][]) + ## 0.66.0 (2019-03-18) ### New features @@ -65,7 +1071,7 @@ * [#6766](https://github.com/rubocop-hq/rubocop/pull/6766): Drop support for Ruby 2.2.0 and 2.2.1. ([@pocke][]) * [#6733](https://github.com/rubocop-hq/rubocop/pull/6733): Warn duplicated keys in `.rubocop.yml`. ([@pocke][]) -* [#6613](https://github.com/rubocop-hq/rubocop/pull/6613): Mark `Style/ModuleFunction` as `SafeAutocorrect: false` and disable autocorrect by default. ([@dduugg][]) +* [#6613](https://github.com/rubocop-hq/rubocop/pull/6613): Mark `Style/ModuleFunction` as `SafeAuto-Correct: false` and disable auto-correct by default. ([@dduugg][]) ## 0.64.0 (2019-02-10) @@ -80,7 +1086,7 @@ * [#6648](https://github.com/rubocop-hq/rubocop/issues/6648): Fix auto-correction of `Style/EmptyLiteral` when `Hash.new` is passed as the first argument to `super`. ([@rrosenblum][]) * [#6351](https://github.com/rubocop-hq/rubocop/pull/6351): Fix a false positive for `Layout/ClosingParenthesisIndentation` when first argument is multiline. ([@antonzaytsev][]) * [#6689](https://github.com/rubocop-hq/rubocop/pull/6689): Support more complex argument patterns on `Rails/Validation` auto-correction. ([@r7kamura][]) -* [#6668](https://github.com/rubocop-hq/rubocop/issues/6668): Fix autocorrection for `Style/UnneededCondition` when conditional has the `unless` form. ([@mvz][]) +* [#6668](https://github.com/rubocop-hq/rubocop/issues/6668): Fix auto-correction for `Style/UnneededCondition` when conditional has the `unless` form. ([@mvz][]) * [#6382](https://github.com/rubocop-hq/rubocop/issues/6382): Fix `Layout/IndentationWidth` with `Layout/EndAlignment` set to start_of_line. ([@dischorde][], [@siegfault][], [@mhelmetag][]) * [#6710](https://github.com/rubocop-hq/rubocop/issues/6710): Fix `Naming/MemoizedInstanceVariableName` on method starts with underscore. ([@pocke][]) * [#6722](https://github.com/rubocop-hq/rubocop/issues/6722): Fix an error for `Style/OneLineConditional` when `then` branch has no body. ([@koic][]) @@ -117,6 +1123,7 @@ ### Bug fixes * [#6627](https://github.com/rubocop-hq/rubocop/pull/6627): Fix handling of hashes in trailing comma. ([@abrom][]) +* [#6638](https://github.com/rubocop-hq/rubocop/pull/6638): Fix `Rails/LinkToBlank` dectection to allow `rel: 'noreferer`. ([@fwininger][]) * [#6623](https://github.com/rubocop-hq/rubocop/pull/6623): Fix heredoc detection in trailing comma. ([@palkan][]) * [#6100](https://github.com/rubocop-hq/rubocop/issues/6100): Fix a false positive in `Naming/ConstantName` cop when rhs is a conditional expression. ([@tatsuyafw][]) * [#6526](https://github.com/rubocop-hq/rubocop/issues/6526): Fix a wrong line highlight in `Lint/ShadowedException` cop. ([@tatsuyafw][]) @@ -142,7 +1149,7 @@ ### New features * [#6580](https://github.com/rubocop-hq/rubocop/pull/6580): New cop `Rails/LinkToBlank` checks for `link_to` calls with `target: '_blank'` and no `rel: 'noopener'`. ([@Intrepidd][]) -* [#6586](https://github.com/rubocop-hq/rubocop/issues/6586): New cop `Style/DisjunctiveAssignmentInConstructor` checks constructors for disjunctive assignments that should be plain assignments. ([@jaredbeck][]) +* [#6586](https://github.com/rubocop-hq/rubocop/issues/6586): New cop `Lint/DisjunctiveAssignmentInConstructor` checks constructors for disjunctive assignments that should be plain assignments. ([@jaredbeck][]) ### Bug fixes @@ -168,7 +1175,7 @@ ### Changes * [#595](https://github.com/rubocop-hq/rubocop/issues/595): Exclude files ignored by `git`. ([@AlexWayfer][]) -* [#6429](https://github.com/rubocop-hq/rubocop/issues/6429): Fix autocorrect in Rails/Validation to not wrap hash options with braces in an extra set of braces. ([@bquorning][]) +* [#6429](https://github.com/rubocop-hq/rubocop/issues/6429): Fix auto-correct in Rails/Validation to not wrap hash options with braces in an extra set of braces. ([@bquorning][]) * [#6533](https://github.com/rubocop-hq/rubocop/issues/6533): Improved warning message for unrecognized cop parameters to include Supported parameters. ([@MagedMilad][]) ## 0.61.1 (2018-12-06) @@ -194,7 +1201,7 @@ * [#5970](https://github.com/rubocop-hq/rubocop/issues/5970): Make running `--auto-gen-config` in a subdirectory work. ([@jonas054][]) * [#6412](https://github.com/rubocop-hq/rubocop/issues/6412): Fix an `unknown keywords` error when using `Psych.safe_load` with Ruby 2.6.0-preview2. ([@koic][]) * [#6436](https://github.com/rubocop-hq/rubocop/pull/6436): Fix exit status code to be 130 when rubocop is interrupted. ([@deivid-rodriguez][]) -* [#6443](https://github.com/rubocop-hq/rubocop/pull/6443): Fix an incorrect autocorrect for `Style/BracesAroundHashParameters` when the opening brace is before the first hash element at same line. ([@koic][]) +* [#6443](https://github.com/rubocop-hq/rubocop/pull/6443): Fix an incorrect auto-correct for `Style/BracesAroundHashParameters` when the opening brace is before the first hash element at same line. ([@koic][]) * [#6445](https://github.com/rubocop-hq/rubocop/pull/6445): Treat `yield` and `super` like regular method calls in `Style/AlignHash`. ([@mvz][]) * [#3301](https://github.com/rubocop-hq/rubocop/issues/3301): Don't suggest or make semantic changes to the code in `Style/InfiniteLoop`. ([@jonas054][]) * [#3586](https://github.com/rubocop-hq/rubocop/issues/3586): Handle single argument spanning multiple lines in `Style/TrailingCommaInArguments`. ([@jonas054][]) @@ -277,7 +1284,7 @@ * [#6261](https://github.com/rubocop-hq/rubocop/pull/6261): Fix undefined method error for `Style/RedundantBegin` when calling `super` with a block. ([@eitoball][]) * [#6263](https://github.com/rubocop-hq/rubocop/issues/6263): Fix an error `Layout/EmptyLineAfterGuardClause` when guard clause is after heredoc including string interpolation. ([@koic][]) * [#6281](https://github.com/rubocop-hq/rubocop/pull/6281): Fix false negative in `Style/MultilineMethodSignature`. ([@drenmi][]) -* [#6264](https://github.com/rubocop-hq/rubocop/issues/6264): Fix an incorrect autocorrect for `Layout/EmptyLineAfterGuardClause` cop when `if` condition is after heredoc. ([@koic][]) +* [#6264](https://github.com/rubocop-hq/rubocop/issues/6264): Fix an incorrect auto-correct for `Layout/EmptyLineAfterGuardClause` cop when `if` condition is after heredoc. ([@koic][]) ### Changes @@ -293,7 +1300,7 @@ * [#6109](https://github.com/rubocop-hq/rubocop/pull/6109): Add new `Bundler/GemComment` cop. ([@sunny][]) * [#6148](https://github.com/rubocop-hq/rubocop/pull/6148): Add `IgnoredMethods` option to `Style/NumericPredicate` cop. ([@AlexWayfer][]) * [#6174](https://github.com/rubocop-hq/rubocop/pull/6174): Add `--display-only-fail-level-offenses` to only output offenses at or above the fail level. ([@robotdana][]) -* Add autocorrect to `Style/For`. ([@rrosenblum][]) +* Add auto-correct to `Style/For`. ([@rrosenblum][]) * [#6173](https://github.com/rubocop-hq/rubocop/pull/6173): Add `AllowImplicitReturn` option to `Rails/SaveBang` cop. ([@robotdana][]) * [#6218](https://github.com/rubocop-hq/rubocop/pull/6218): Add `comparison` style to `Style/NilComparison`. ([@khiav223577][]) * Add new `Style/MultilineMethodSignature` cop. ([@drenmi][]) @@ -311,13 +1318,13 @@ * [#6152](https://github.com/rubocop-hq/rubocop/pull/6152): Fix a false negative for `Layout/AccessModifierIndentation` when using access modifiers with arguments within nested classes. ([@gmalette][]) * [#6124](https://github.com/rubocop-hq/rubocop/issues/6124): Fix `Style/IfUnlessModifier` cop for disabled `Layout/Tab` cop when there is no `IndentationWidth` config. ([@AlexWayfer][]) * [#6133](https://github.com/rubocop-hq/rubocop/pull/6133): Fix `AllowURI` option of `Metrics/LineLength` cop for files with tabs indentation. ([@AlexWayfer][]) -* [#6164](https://github.com/rubocop-hq/rubocop/issues/6164): Fix incorrect autocorrect for `Style/UnneededCondition` when using operator method higher precedence than `||`. ([@koic][]) +* [#6164](https://github.com/rubocop-hq/rubocop/issues/6164): Fix incorrect auto-correct for `Style/UnneededCondition` when using operator method higher precedence than `||`. ([@koic][]) * [#6138](https://github.com/rubocop-hq/rubocop/issues/6138): Fix a false positive for assigning a block local variable in `Lint/ShadowedArgument`. ([@jonas054][]) * [#6022](https://github.com/rubocop-hq/rubocop/issues/6022): Fix `Layout/MultilineHashBraceLayout` and `Layout/MultilineArrayBraceLayout` auto-correct syntax error when there is a comment on the last element. ([@bacchir][]) * [#6175](https://github.com/rubocop-hq/rubocop/issues/6175): Fix `Style/BracesAroundHashParameters` auto-correct syntax error when there is a trailing comma. ([@bacchir][]) * [#6192](https://github.com/rubocop-hq/rubocop/issues/6192): Make `Style/RedundantBegin` aware of stabby lambdas. ([@drenmi][]) * [#6208](https://github.com/rubocop-hq/rubocop/pull/6208): Ignore assignment methods in `Naming/PredicateName`. ([@sunny][]) -* [#6196](https://github.com/rubocop-hq/rubocop/issues/6196): Fix incorrect autocorrect for `Style/EmptyCaseCondition` when using `return` in `when` clause and assigning the return value of `case`. ([@koic][]) +* [#6196](https://github.com/rubocop-hq/rubocop/issues/6196): Fix incorrect auto-correct for `Style/EmptyCaseCondition` when using `return` in `when` clause and assigning the return value of `case`. ([@koic][]) * [#6142](https://github.com/rubocop-hq/rubocop/issues/6142): Ignore keyword arguments in `Rails/Delegate`. ([@sunny][]) * [#6240](https://github.com/rubocop-hq/rubocop/issues/6240): Fix an auto-correct error for `Style/WordArray` when setting `EnforcedStyle: brackets` and using string interpolation in `%W` literal. ([@koic][]) * [#6202](https://github.com/rubocop-hq/rubocop/issues/6202): Fix infinite loop when auto-correcting `Lint/RescueEnsureAlignment` when `end` is misaligned. The alignment and message are now based on the beginning position rather than the `end` position. ([@rrosenblum][]) @@ -329,7 +1336,7 @@ * [#6137](https://github.com/rubocop-hq/rubocop/pull/6137): Allow `db` to allowed names of `Naming/UncommunicativeMethodParamName` cop in default config. ([@mkenyon][]) * Update the highlighting of `Lint/DuplicateMethods` to include the method name. ([@rrosenblum][]) * [#6057](https://github.com/rubocop-hq/rubocop/issues/6057): Return 0 when running `rubocop --auto-gen-conf` if the todo file is successfully created even if there are offenses. ([@MagedMilad][]) -* [#4301](https://github.com/rubocop-hq/rubocop/issues/4301): Turn off autocorrect for `Rails/RelativeDateConstant` by default. ([@koic][]) +* [#4301](https://github.com/rubocop-hq/rubocop/issues/4301): Turn off auto-correct for `Rails/RelativeDateConstant` by default. ([@koic][]) * [#4832](https://github.com/rubocop-hq/rubocop/issues/4832): Change the path pattern (`*`) to match the hidden file. ([@koic][]) * `Style/For` now highlights the entire statement rather than just the keyword. ([@rrosenblum][]) * Disable `Performance/CaseWhenSplat` and its auto-correction by default. ([@rrosenblum][]) @@ -382,7 +1389,7 @@ * Fix exception that occurs when auto-correcting a modifier if statement in `Style/UnneededCondition`. ([@rrosenblum][]) * [#6025](https://github.com/rubocop-hq/rubocop/pull/6025): Fix an incorrect auto-correct for `Lint/UnneededCondition` when using if_branch in `else` branch. ([@koic][]) * [#6029](https://github.com/rubocop-hq/rubocop/issues/6029): Fix a false positive for `Lint/ShadowedArgument` when reassigning to splat variable. ([@koic][]) -* [#6035](https://github.com/rubocop-hq/rubocop/issues/6035): Fix error on autocorrection when `Layout/LeadingBlankLines` is the first cop to act. ([@Vasfed][]) +* [#6035](https://github.com/rubocop-hq/rubocop/issues/6035): Fix error on auto-correction when `Layout/LeadingBlankLines` is the first cop to act. ([@Vasfed][]) * [#6036](https://github.com/rubocop-hq/rubocop/issues/6036): Make `Rails/BulkChangeTable` aware of string table name. ([@wata727][]) * [#5467](https://github.com/rubocop-hq/rubocop/issues/5467): Fix a false negative for `Style/MultipleComparison` when multiple comparison is not part of a conditional. ([@koic][]) * [#6042](https://github.com/rubocop-hq/rubocop/pull/6042): Fix `Lint/RedundantWithObject` error on missing parameter to `each_with_object`. ([@Vasfed][]) @@ -435,7 +1442,7 @@ * [#5897](https://github.com/rubocop-hq/rubocop/issues/5897): Fix `Style/SymbolArray` and `Style/WordArray` not working on arrays of size 1. ([@TikiTDO][]) * [#5894](https://github.com/rubocop-hq/rubocop/pull/5894): Fix `Rails/AssertNot` to allow it to have failure message. ([@koic][]) * [#5888](https://github.com/rubocop-hq/rubocop/issues/5888): Do not register an offense for `headers` or `env` keyword arguments in `Rails/HttpPositionalArguments`. ([@rrosenblum][]) -* Fix the indentation of autocorrected closing squiggly heredocs. ([@garettarrowood][]) +* Fix the indentation of auto-corrected closing squiggly heredocs. ([@garettarrowood][]) * [#5908](https://github.com/rubocop-hq/rubocop/pull/5908): Fix `Style/BracesAroundHashParameters` auto-correct going past the end of the file when the closing curly brace is on the last line of a file. ([@EiNSTeiN-][]) * Fix a bug where `Style/FrozenStringLiteralComment` would be added to the second line if the first line is empty. ([@rrosenblum][]) * [#5914](https://github.com/rubocop-hq/rubocop/issues/5914): Make `Layout/SpaceInsideReferenceBrackets` aware of `no_space` when using nested reference brackets. ([@koic][]) @@ -601,14 +1608,14 @@ * [#4105](https://github.com/rubocop-hq/rubocop/issues/4105): Fix `Lint/IndentationWidth` when `Lint/EndAlignment` is configured with `start_of_line`. ([@brandonweiss][]) * [#5453](https://github.com/rubocop-hq/rubocop/issues/5453): Fix erroneous downcase in `Performance/Casecmp` auto-correction. ([@walinga][]) * [#5343](https://github.com/rubocop-hq/rubocop/issues/5343): Fix offense detection in `Style/TrailingMethodEndStatement`. ([@garettarrowood][]) -* [#5334](https://github.com/rubocop-hq/rubocop/issues/5334): Fix semicolon removal for `Style/TrailingBodyOnMethodDefinition` autocorrection. ([@garettarrowood][]) +* [#5334](https://github.com/rubocop-hq/rubocop/issues/5334): Fix semicolon removal for `Style/TrailingBodyOnMethodDefinition` auto-correction. ([@garettarrowood][]) * [#5350](https://github.com/rubocop-hq/rubocop/issues/5350): Fix `Metric/LineLength` false offenses for URLs in double quotes. ([@garettarrowood][]) * [#5333](https://github.com/rubocop-hq/rubocop/issues/5333): Fix `Layout/EmptyLinesAroundArguments` false positives for inline access modifiers. ([@garettarrowood][]) * [#5339](https://github.com/rubocop-hq/rubocop/issues/5339): Fix `Layout/EmptyLinesAroundArguments` false positives for multiline heredoc arguments. ([@garettarrowood][]) * [#5383](https://github.com/rubocop-hq/rubocop/issues/5383): Fix `Rails/Presence` false detection of receiver for locally defined `blank?` & `present?` methods. ([@garettarrowood][]) * [#5314](https://github.com/rubocop-hq/rubocop/issues/5314): Fix false positives for `Lint/NestedPercentLiteral` when percent characters are nested. ([@asherkach][]) * [#5357](https://github.com/rubocop-hq/rubocop/issues/5357): Fix `Lint/InterpolationCheck` false positives on escaped interpolations. ([@pocke][]) -* [#5409](https://github.com/rubocop-hq/rubocop/issues/5409): Fix multiline indent for `Style/SymbolArray` and `Style/WordArray` autocorrect. ([@flyerhzm][]) +* [#5409](https://github.com/rubocop-hq/rubocop/issues/5409): Fix multiline indent for `Style/SymbolArray` and `Style/WordArray` auto-correct. ([@flyerhzm][]) * [#5393](https://github.com/rubocop-hq/rubocop/issues/5393): Fix `Rails/Delegate`'s false positive with a method call with arguments. ([@pocke][]) * [#5348](https://github.com/rubocop-hq/rubocop/issues/5348): Fix false positive for `Style/SafeNavigation` when safe guarding more comparison methods. ([@rrosenblum][]) * [#4889](https://github.com/rubocop-hq/rubocop/issues/4889): Auto-correcting `Style/SafeNavigation` will add safe navigation to all methods in a method chain. ([@rrosenblum][]) @@ -629,7 +1636,7 @@ * [#5539](https://github.com/rubocop-hq/rubocop/pull/5539): Fix compilation error and ruby code generation when passing args to funcall and predicates. ([@Edouard-chin][]) * [#4669](https://github.com/rubocop-hq/rubocop/issues/4669): Use binary file contents for cache key so changing EOL characters invalidates the cache. ([@jonas054][]) * [#3947](https://github.com/rubocop-hq/rubocop/issues/3947): Fix false positive for `Performance::RegexpMatch` when using `MatchData` before guard clause. ([@koic][]) -* [#5515](https://github.com/rubocop-hq/rubocop/issues/5515): Fix `Style/EmptyElse` autocorrect for nested if and case statements. ([@asherkach][]) +* [#5515](https://github.com/rubocop-hq/rubocop/issues/5515): Fix `Style/EmptyElse` auto-correct for nested if and case statements. ([@asherkach][]) * [#5582](https://github.com/rubocop-hq/rubocop/issues/5582): Fix `end` alignment for variable assignment with line break after `=` in `Layout/EndAlignment`. ([@jonas054][]) * [#5602](https://github.com/rubocop-hq/rubocop/pull/5602): Fix false positive for `Style/ColonMethodCall` when using Java package namespace. ([@koic][]) * [#5603](https://github.com/rubocop-hq/rubocop/pull/5603): Fix falsy offense for `Style/RedundantSelf` with pseudo variables. ([@pocke][]) @@ -676,13 +1683,13 @@ * [#5278](https://github.com/rubocop-hq/rubocop/pull/5278): Fix deprecation check to use `loaded_path` in warning. ([@chrishulton][]) * [#5293](https://github.com/rubocop-hq/rubocop/issues/5293): Fix a regression for `Rails/HasManyOrHasOneDependent` when using a option of `has_many` or `has_one` association. ([@koic][]) * [#5223](https://github.com/rubocop-hq/rubocop/issues/5223): False offences in :unannotated Style/FormatStringToken. ([@nattfodd][]) -* [#5258](https://github.com/rubocop-hq/rubocop/issues/5258): Fix incorrect autocorrection for `Rails/Presence` when the else block is multiline. ([@wata727][]) +* [#5258](https://github.com/rubocop-hq/rubocop/issues/5258): Fix incorrect auto-correction for `Rails/Presence` when the else block is multiline. ([@wata727][]) * [#5297](https://github.com/rubocop-hq/rubocop/pull/5297): Improve inspection for `Rails/InverseOf` when including `through` or `polymorphic` options. ([@wata727][]) * [#5281](https://github.com/rubocop-hq/rubocop/issues/5281): Fix issue where `--auto-gen-config` might fail on invalid YAML. ([@bquorning][]) -* [#5313](https://github.com/rubocop-hq/rubocop/issues/5313): Fix `Style/HashSyntax` from stripping quotes off of symbols during autocorrection for ruby22+. ([@garettarrowood][]) +* [#5313](https://github.com/rubocop-hq/rubocop/issues/5313): Fix `Style/HashSyntax` from stripping quotes off of symbols during auto-correction for ruby22+. ([@garettarrowood][]) * [#5315](https://github.com/rubocop-hq/rubocop/issues/5315): Fix a false positive of `Layout/RescueEnsureAlignment` in Ruby 2.5. ([@pocke][]) * [#5236](https://github.com/rubocop-hq/rubocop/issues/5236): Fix false positives for `Rails/InverseOf` when using `with_options`. ([@wata727][]) -* [#5291](https://github.com/rubocop-hq/rubocop/issues/5291): Fix multiline indent for `Style/BracesAroundHashParameters` autocorrect. ([@flyerhzm][]) +* [#5291](https://github.com/rubocop-hq/rubocop/issues/5291): Fix multiline indent for `Style/BracesAroundHashParameters` auto-correct. ([@flyerhzm][]) * [#3318](https://github.com/rubocop-hq/rubocop/issues/3318): Look for `.ruby-version` in parent directories. ([@ybiquitous][]) ### Changes @@ -727,7 +1734,7 @@ ### Bug fixes -* [#5096](https://github.com/rubocop-hq/rubocop/issues/5096): Fix incorrect detection and autocorrection of multiple extend/include/prepend. ([@marcandre][]) +* [#5096](https://github.com/rubocop-hq/rubocop/issues/5096): Fix incorrect detection and auto-correction of multiple extend/include/prepend. ([@marcandre][]) * [#5219](https://github.com/rubocop-hq/rubocop/issues/5219): Fix incorrect empty line detection for block arguments in `Layout/EmptyLinesAroundArguments`. ([@garettarrowood][]) * [#4662](https://github.com/rubocop-hq/rubocop/issues/4662): Fix incorrect indent level detection when first line of heredoc is blank. ([@sambostock][]) * [#5016](https://github.com/rubocop-hq/rubocop/issues/5016): Fix a false positive for `Style/ConstantName` with constant names using non-ASCII capital letters with accents. ([@timrogers][]) @@ -742,7 +1749,7 @@ * [#4909](https://github.com/rubocop-hq/rubocop/issues/4909): Make `Rails/HasManyOrHasOneDependent` aware of multiple associations in `with_options`. ([@koic][]) * [#4794](https://github.com/rubocop-hq/rubocop/issues/4794): Fix an error in `Layout/MultilineOperationIndentation` when an operation spans multiple lines and contains a ternary expression. ([@rrosenblum][]) * [#4885](https://github.com/rubocop-hq/rubocop/issues/4885): Fix false offense detected by `Style/MixinUsage` cop. ([@koic][]) -* [#3363](https://github.com/rubocop-hq/rubocop/pull/3363): Fix `Style/EmptyElse` autocorrection removes comments from branches. ([@dpostorivo][]) +* [#3363](https://github.com/rubocop-hq/rubocop/pull/3363): Fix `Style/EmptyElse` auto-correction removes comments from branches. ([@dpostorivo][]) * [#5025](https://github.com/rubocop-hq/rubocop/issues/5025): Fix error with Layout/MultilineMethodCallIndentation cop and lambda.(...). ([@dpostorivo][]) * [#4781](https://github.com/rubocop-hq/rubocop/issues/4781): Prevent `Style/UnneededPercentQ` from breaking on strings that are concated with backslash. ([@pocke][]) * [#4363](https://github.com/rubocop-hq/rubocop/issues/4363): Fix `Style/PercentLiteralDelimiters` incorrectly automatically modifies escaped percent literal delimiter. ([@koic][]) @@ -851,7 +1858,7 @@ * [#4552](https://github.com/rubocop-hq/rubocop/pull/4552): Add new `Style/Dir` cop. ([@drenmi][]) * [#4548](https://github.com/rubocop-hq/rubocop/pull/4548): Add new `Style/HeredocDelimiterCase` cop(Note: This cop is renamed to `Naming/HeredocDelimiterCase`). ([@drenmi][]) * [#2943](https://github.com/rubocop-hq/rubocop/pull/2943): Add new `Lint/RescueWithoutErrorClass` cop. ([@drenmi][]) -* [#4568](https://github.com/rubocop-hq/rubocop/pull/4568): Fix autocorrection for `Style/TrailingUnderscoreVariable`. ([@smakagon][]) +* [#4568](https://github.com/rubocop-hq/rubocop/pull/4568): Fix auto-correction for `Style/TrailingUnderscoreVariable`. ([@smakagon][]) * [#4586](https://github.com/rubocop-hq/rubocop/pull/4586): Add new `Performance/UnfreezeString` cop. ([@pocke][]) * [#2976](https://github.com/rubocop-hq/rubocop/issues/2976): Add `Whitelist` configuration option to `Style/NestedParenthesizedCalls` cop. ([@drenmi][]) * [#3965](https://github.com/rubocop-hq/rubocop/issues/3965): Add new `Style/OrAssignment` cop. ([@donjar][]) @@ -873,11 +1880,11 @@ * [#4709](https://github.com/rubocop-hq/rubocop/pull/4709): Use cached remote config on network failure. ([@kristjan][]) * [#4688](https://github.com/rubocop-hq/rubocop/pull/4688): Accept yoda condition which isn't commutative. ([@fujimura][]) * [#4676](https://github.com/rubocop-hq/rubocop/issues/4676): Make `Style/RedundantConditional` cop work with elsif. ([@akhramov][]) -* [#4656](https://github.com/rubocop-hq/rubocop/issues/4656): Modify `Style/ConditionalAssignment` autocorrection to work with unbracketed arrays. ([@akhramov][]) +* [#4656](https://github.com/rubocop-hq/rubocop/issues/4656): Modify `Style/ConditionalAssignment` auto-correction to work with unbracketed arrays. ([@akhramov][]) * [#4615](https://github.com/rubocop-hq/rubocop/pull/4615): Don't consider `<=>` a comparison method. ([@iGEL][]) * [#4664](https://github.com/rubocop-hq/rubocop/pull/4664): Fix typos in Rails/HttpPositionalArguments. ([@JoeCohen][]) * [#4618](https://github.com/rubocop-hq/rubocop/pull/4618): Fix `Lint/FormatParameterMismatch` false positive if format string includes `%%5B` (CGI encoded left bracket). ([@barthez][]) -* [#4604](https://github.com/rubocop-hq/rubocop/pull/4604): Fix `Style/LambdaCall` to autocorrect `obj.call` to `obj.`. ([@iGEL][]) +* [#4604](https://github.com/rubocop-hq/rubocop/pull/4604): Fix `Style/LambdaCall` to auto-correct `obj.call` to `obj.`. ([@iGEL][]) * [#4443](https://github.com/rubocop-hq/rubocop/pull/4443): Prevent `Style/YodaCondition` from breaking `not LITERAL`. ([@pocke][]) * [#4434](https://github.com/rubocop-hq/rubocop/issues/4434): Prevent bad auto-correct in `Style/Alias` for non-literal arguments. ([@drenmi][]) * [#4451](https://github.com/rubocop-hq/rubocop/issues/4451): Make `Style/AndOr` cop aware of comparison methods. ([@drenmi][]) @@ -904,7 +1911,7 @@ * [#4646](https://github.com/rubocop-hq/rubocop/issues/4646): Make `Lint/Debugger` aware of `Kernel` and cbase. ([@pocke][]) * [#4643](https://github.com/rubocop-hq/rubocop/issues/4643): Modify `Style/InverseMethods` to not register a separate offense for an inverse method nested inside of the block of an inverse method offense. ([@rrosenblum][]) * [#4593](https://github.com/rubocop-hq/rubocop/issues/4593): Fix false positive in `Rails/SaveBang` when `save/update_attribute` is used with a `case` statement. ([@theRealNG][]) -* [#4322](https://github.com/rubocop-hq/rubocop/issues/4322): Fix Style/MultilineMemoization from autocorrecting to invalid ruby. ([@dpostorivo][]) +* [#4322](https://github.com/rubocop-hq/rubocop/issues/4322): Fix Style/MultilineMemoization from auto-correcting to invalid ruby. ([@dpostorivo][]) * [#4722](https://github.com/rubocop-hq/rubocop/pull/4722): Fix `rake new_cop` problem that doesn't add `require` line. ([@koic][]) * [#4723](https://github.com/rubocop-hq/rubocop/issues/4723): Fix `RaiseArgs` auto-correction issue for `raise` with 3 arguments. ([@smakagon][]) @@ -958,8 +1965,8 @@ * [#3438](https://github.com/rubocop-hq/rubocop/issues/3438): Add new `Style/FormatStringToken` cop. ([@backus][]) * [#4342](https://github.com/rubocop-hq/rubocop/pull/4342): Add new `Lint/ScriptPermission` cop. ([@yhirano55][]) * [#4145](https://github.com/rubocop-hq/rubocop/issues/4145): Add new `Style/YodaCondition` cop. ([@smakagon][]) -* [#4403](https://github.com/rubocop-hq/rubocop/pull/4403): Add public API `Cop.autocorrect_incompatible_with` for specifying other cops that should not autocorrect together. ([@backus][]) -* [#4354](https://github.com/rubocop-hq/rubocop/pull/4354): Add autocorrect to `Style/FormatString`. ([@hoshinotsuyoshi][]) +* [#4403](https://github.com/rubocop-hq/rubocop/pull/4403): Add public API `Cop.autocorrect_incompatible_with` for specifying other cops that should not auto-correct together. ([@backus][]) +* [#4354](https://github.com/rubocop-hq/rubocop/pull/4354): Add auto-correct to `Style/FormatString`. ([@hoshinotsuyoshi][]) * [#4021](https://github.com/rubocop-hq/rubocop/pull/4021): Add new `Style/MultipleComparison` cop. ([@dabroz][]) * New `Lint/RescueType` cop. ([@rrosenblum][]) * [#4328](https://github.com/rubocop-hq/rubocop/issues/4328): Add `--ignore-parent-exclusion` flag to ignore AllCops/Exclude inheritance. ([@nelsonjr][]) @@ -983,8 +1990,8 @@ * [#4241](https://github.com/rubocop-hq/rubocop/issues/4241): Prevent `Rails/Blank` and `Rails/Present` from breaking when there is no explicit receiver. ([@rrosenblum][]) * [#4249](https://github.com/rubocop-hq/rubocop/issues/4249): Handle multiple assignment in `Rails/RelativeDateConstant`. ([@bbatsov][]) * [#4250](https://github.com/rubocop-hq/rubocop/issues/4250): Improve a bit the Ruby code detection config. ([@bbatsov][]) -* [#4283](https://github.com/rubocop-hq/rubocop/issues/4283): Fix `Style/EmptyCaseCondition` autocorrect bug - when first `when` branch includes comma-delimited alternatives. ([@ilansh][]) -* [#4268](https://github.com/rubocop-hq/rubocop/issues/4268): Handle end-of-line comments when autocorrecting Style/EmptyLinesAroundAccessModifier. ([@vergenzt][]) +* [#4283](https://github.com/rubocop-hq/rubocop/issues/4283): Fix `Style/EmptyCaseCondition` auto-correct bug - when first `when` branch includes comma-delimited alternatives. ([@ilansh][]) +* [#4268](https://github.com/rubocop-hq/rubocop/issues/4268): Handle end-of-line comments when auto-correcting Style/EmptyLinesAroundAccessModifier. ([@vergenzt][]) * [#4275](https://github.com/rubocop-hq/rubocop/issues/4275): Prevent `Style/MethodCallWithArgsParentheses` from blowing up on `yield`. ([@drenmi][]) * [#3969](https://github.com/rubocop-hq/rubocop/issues/3969): Handle multiline method call alignment for arguments to methods. ([@jonas054][]) * [#4304](https://github.com/rubocop-hq/rubocop/pull/4304): Allow enabling whole departments when `DisabledByDefault` is `true`. ([@jonas054][]) @@ -1024,7 +2031,7 @@ * [#4152](https://github.com/rubocop-hq/rubocop/pull/4152): Make `Style/MethodCallWithArgsParentheses` not require parens on setter methods. ([@drenmi][]) * [#4226](https://github.com/rubocop-hq/rubocop/pull/4226): Show in `--help` output that `--stdin` takes a file name argument. ([@jonas054][]) * [#4217](https://github.com/rubocop-hq/rubocop/pull/4217): Fix false positive in `Rails/FilePath` cop with non string argument. ([@soutaro][]) -* [#4106](https://github.com/rubocop-hq/rubocop/pull/4106): Make `Style/TernaryParentheses` unsafe autocorrect detector aware of literals and constants. ([@drenmi][]) +* [#4106](https://github.com/rubocop-hq/rubocop/pull/4106): Make `Style/TernaryParentheses` unsafe auto-correct detector aware of literals and constants. ([@drenmi][]) * [#4228](https://github.com/rubocop-hq/rubocop/pull/4228): Fix false positive in `Lint/AmbiguousBlockAssociation` cop. ([@smakagon][]) * [#4234](https://github.com/rubocop-hq/rubocop/pull/4234): Fix false positive in `Rails/RelativeDate` for lambdas and procs. ([@smakagon][]) @@ -1045,7 +2052,7 @@ * [#3984](https://github.com/rubocop-hq/rubocop/pull/3984): Add new `Style/EmptyLinesAroundBeginBody` cop. ([@pocke][]) * [#3995](https://github.com/rubocop-hq/rubocop/pull/3995): Add new `Style/EmptyLinesAroundExceptionHandlingKeywords` cop. ([@pocke][]) * [#4019](https://github.com/rubocop-hq/rubocop/pull/4019): Make configurable `Style/MultilineMemoization` cop. ([@pocke][]) -* [#4018](https://github.com/rubocop-hq/rubocop/pull/4018): Add autocorrect `Lint/EmptyEnsure` cop. ([@pocke][]) +* [#4018](https://github.com/rubocop-hq/rubocop/pull/4018): Add auto-correct `Lint/EmptyEnsure` cop. ([@pocke][]) * [#4028](https://github.com/rubocop-hq/rubocop/pull/4028): Add new `Style/IndentHeredoc` cop. ([@pocke][]) * [#3931](https://github.com/rubocop-hq/rubocop/issues/3931): Add new `Lint/AmbiguousBlockAssociation` cop. ([@smakagon][]) * Add new `Style/InverseMethods` cop. ([@rrosenblum][]) @@ -1079,7 +2086,7 @@ * [#3923](https://github.com/rubocop-hq/rubocop/issues/3923): Allow asciibetical sorting in `Bundler/OrderedGems`. ([@mikegee][]) * [#3855](https://github.com/rubocop-hq/rubocop/issues/3855): Make `Lint/NonLocalExitFromIterator` aware of method definitions. ([@drenmi][]) * [#2643](https://github.com/rubocop-hq/rubocop/issues/2643): Allow uppercase and dashes in `MagicComment`. ([@mikegee][]) -* [#3959](https://github.com/rubocop-hq/rubocop/issues/3959): Don't wrap "percent arrays" with extra brackets when autocorrecting `Style/MutableConstant`. ([@mikegee][]) +* [#3959](https://github.com/rubocop-hq/rubocop/issues/3959): Don't wrap "percent arrays" with extra brackets when auto-correcting `Style/MutableConstant`. ([@mikegee][]) * [#3978](https://github.com/rubocop-hq/rubocop/pull/3978): Fix false positive in `Performance/RegexpMatch` with `English` module. ([@pocke][]) * [#3242](https://github.com/rubocop-hq/rubocop/issues/3242): Ignore `Errno::ENOENT` during cache cleanup from `File.mtime` too. ([@mikegee][]) * [#3958](https://github.com/rubocop-hq/rubocop/issues/3958): `Style/SpaceInsideHashLiteralBraces` doesn't add and offence when checking an hash where a value is a left brace string (e.g. { k: '{' }). ([@nodo][]) @@ -1214,7 +2221,7 @@ ### New features -* [#3615](https://github.com/rubocop-hq/rubocop/pull/3615): Add autocorrection for `Lint/EmptyInterpolation`. ([@pocke][]) +* [#3615](https://github.com/rubocop-hq/rubocop/pull/3615): Add auto-correction for `Lint/EmptyInterpolation`. ([@pocke][]) * Make `PercentLiteralDelimiters` enforce delimiters around `%I()` too. ([@bronson][]) * [#3408](https://github.com/rubocop-hq/rubocop/issues/3408): Add check for repeated values in case conditionals. ([@swcraig][]) * [#3646](https://github.com/rubocop-hq/rubocop/pull/3646): Add new `Lint/EmptyWhen` cop. ([@drenmi][]) @@ -1281,7 +2288,7 @@ * [#3516](https://github.com/rubocop-hq/rubocop/issues/3516): Make `Style/VariableNumber` cop not register an offense when valid normal case variable names have an integer in the middle. ([@b-t-g][]) * [#3436](https://github.com/rubocop-hq/rubocop/issues/3436): Make `Rails/SaveBang` cop not register an offense when return value of a non-bang method is returned by the parent method. ([@coorasse][]) * [#3540](https://github.com/rubocop-hq/rubocop/issues/3540): Fix `Style/GuardClause` to register offense for instance and singleton methods. ([@tejasbubane][]) -* [#3311](https://github.com/rubocop-hq/rubocop/issues/3311): Detect incompatibilities with the external encoding to prevent bad autocorrections in `Style/StringLiterals`. ([@deivid-rodriguez][]) +* [#3311](https://github.com/rubocop-hq/rubocop/issues/3311): Detect incompatibilities with the external encoding to prevent bad auto-corrections in `Style/StringLiterals`. ([@deivid-rodriguez][]) * [#3499](https://github.com/rubocop-hq/rubocop/issues/3499): Ensure `Lint/UnusedBlockArgument` doesn't make recommendations that would change arity for methods defined using `#define_method`. ([@drenmi][]) * [#3430](https://github.com/rubocop-hq/rubocop/issues/3430): Fix exception in `Performance/RedundantMerge` when inspecting a `#merge!` with implicit receiver. ([@drenmi][]) * [#3411](https://github.com/rubocop-hq/rubocop/issues/3411): Avoid auto-correction crash for single `when` in `Performance/CaseWhenSplat`. ([@jonas054][]) @@ -1293,15 +2300,15 @@ * [#3577](https://github.com/rubocop-hq/rubocop/issues/3577): Fix `Style/RaiseArgs` not allowing compact raise with splatted args. ([@savef][]) * [#3578](https://github.com/rubocop-hq/rubocop/issues/3578): Fix safe navigation method call counting in `Metrics/AbcSize`. ([@savef][]) * [#3592](https://github.com/rubocop-hq/rubocop/issues/3592): Fix `Style/RedundantParentheses` for indexing with literals. ([@thegedge][]) -* [#3597](https://github.com/rubocop-hq/rubocop/issues/3597): Fix the autocorrect of `Performance/CaseWhenSplat` when trying to rearange splat expanded variables to the end of a when condition. ([@rrosenblum][]) +* [#3597](https://github.com/rubocop-hq/rubocop/issues/3597): Fix the auto-correct of `Performance/CaseWhenSplat` when trying to rearange splat expanded variables to the end of a when condition. ([@rrosenblum][]) ### Changes * [#3512](https://github.com/rubocop-hq/rubocop/issues/3512): Change error message of `Lint/UnneededSplatExpansion` for array in method parameters. ([@tejasbubane][]) * [#3510](https://github.com/rubocop-hq/rubocop/issues/3510): Fix some issues with `Style/SafeNavigation`. Fix auto-correct of multiline if expressions, and do not register an offense for scenarios using `||` and ternary expression. ([@rrosenblum][]) * [#3503](https://github.com/rubocop-hq/rubocop/issues/3503): Change misleading message of `Style/EmptyLinesAroundAccessModifier`. ([@bquorning][]) -* [#3407](https://github.com/rubocop-hq/rubocop/issues/3407): Turn off autocorrect for unsafe rules by default. ([@ptarjan][]) -* [#3521](https://github.com/rubocop-hq/rubocop/issues/3521): Turn off autocorrect for `Security/JSONLoad` by default. ([@savef][]) +* [#3407](https://github.com/rubocop-hq/rubocop/issues/3407): Turn off auto-correct for unsafe rules by default. ([@ptarjan][]) +* [#3521](https://github.com/rubocop-hq/rubocop/issues/3521): Turn off auto-correct for `Security/JSONLoad` by default. ([@savef][]) * [#2903](https://github.com/rubocop-hq/rubocop/issues/2903): `Style/RedundantReturn` looks for redundant `return` inside conditional branches. ([@lumeet][]) ## 0.43.0 (2016-09-19) @@ -1324,8 +2331,8 @@ ### Bug fixes * [#3383](https://github.com/rubocop-hq/rubocop/issues/3383): Fix the local variable reset issue with `Style/RedundantSelf` cop. ([@bankair][]) -* [#3445](https://github.com/rubocop-hq/rubocop/issues/3445): Fix bad autocorrect for `Style/AndOr` cop. ([@mikezter][]) -* [#3349](https://github.com/rubocop-hq/rubocop/issues/3349): Fix bad autocorrect for `Style/Lambda` cop. ([@metcalf][]) +* [#3445](https://github.com/rubocop-hq/rubocop/issues/3445): Fix bad auto-correct for `Style/AndOr` cop. ([@mikezter][]) +* [#3349](https://github.com/rubocop-hq/rubocop/issues/3349): Fix bad auto-correct for `Style/Lambda` cop. ([@metcalf][]) * [#3351](https://github.com/rubocop-hq/rubocop/issues/3351): Fix bad auto-correct for `Performance/RedundantMatch` cop. ([@annaswims][]) * [#3347](https://github.com/rubocop-hq/rubocop/issues/3347): Prevent infinite loop in `Style/TernaryParentheses` cop when used together with `Style/RedundantParentheses`. ([@drenmi][]) * [#3209](https://github.com/rubocop-hq/rubocop/issues/3209): Remove faulty line length check from `Style/GuardClause` cop. ([@drenmi][]) @@ -1363,7 +2370,7 @@ ### New features -* [#3306](https://github.com/rubocop-hq/rubocop/issues/3306): Add autocorrection for `Style/EachWithObject`. ([@owst][]) +* [#3306](https://github.com/rubocop-hq/rubocop/issues/3306): Add auto-correction for `Style/EachWithObject`. ([@owst][]) * Add new `Style/TernaryParentheses` cop. ([@drenmi][]) * [#3136](https://github.com/rubocop-hq/rubocop/issues/3136): Add config for `UselessAccessModifier` so it can be made aware of ActiveSupport's `concerning` and `class_methods` methods. ([@maxjacobson][]) * [#3128](https://github.com/rubocop-hq/rubocop/issues/3128): Add new `Rails/SaveBang` cop. ([@QuinnHarris][]) @@ -1428,12 +2435,12 @@ * [#3066](https://github.com/rubocop-hq/rubocop/issues/3066): Add new `Style/ImplicitRuntimeError` cop which advises the use of an explicit exception class when raising an error. ([@alexdowad][]) * [#3018](https://github.com/rubocop-hq/rubocop/issues/3018): Add new `Style/EachForSimpleLoop` cop which advises the use of `Integer#times` for simple loops which iterate a fixed number of times. ([@alexdowad][]) * [#2595](https://github.com/rubocop-hq/rubocop/issues/2595): New `compact` style for `Style/SpaceInsideLiteralHashBraces`. ([@alexdowad][]) -* [#2927](https://github.com/rubocop-hq/rubocop/issues/2927): Add autocorrect for `Rails/Validation` cop. ([@neodelf][]) +* [#2927](https://github.com/rubocop-hq/rubocop/issues/2927): Add auto-correct for `Rails/Validation` cop. ([@neodelf][]) * [#3135](https://github.com/rubocop-hq/rubocop/pull/3135): Add new `Rails/OutputSafety` cop. ([@josh][]) * [#3164](https://github.com/rubocop-hq/rubocop/pull/3164): Add [Fastlane](https://fastlane.tools/)'s Fastfile to the default Includes. ([@jules2689][]) * [#3173](https://github.com/rubocop-hq/rubocop/pull/3173): Make `Style/ModuleFunction` configurable with `module_function` and `extend_self` styles. ([@tjwp][]) * [#3105](https://github.com/rubocop-hq/rubocop/issues/3105): Add new `Rails/RequestReferer` cop. ([@giannileggio][]) -* [#3200](https://github.com/rubocop-hq/rubocop/pull/3200): Add autocorrect for `Style/EachForSimpleLoop` cop. ([@tejasbubane][]) +* [#3200](https://github.com/rubocop-hq/rubocop/pull/3200): Add auto-correct for `Style/EachForSimpleLoop` cop. ([@tejasbubane][]) * [#3058](https://github.com/rubocop-hq/rubocop/issues/3058): Add new `Style/SpaceInsideArrayPercentLiteral` cop. ([@owst][]) * [#3058](https://github.com/rubocop-hq/rubocop/issues/3058): Add new `Style/SpaceInsidePercentLiteralDelimiters` cop. ([@owst][]) * [#3179](https://github.com/rubocop-hq/rubocop/pull/3179): Expose files to support testings Cops using RSpec. ([@tjwp][]) @@ -1517,7 +2524,7 @@ ### Bug fixes * [#3112](https://github.com/rubocop-hq/rubocop/issues/3112): Fix `Style/ClassAndModuleChildren` for nested classes with explicit superclass. ([@jspanjers][]) -* [#3032](https://github.com/rubocop-hq/rubocop/issues/3032): Fix autocorrecting parentheses for predicate methods without space before args. ([@graemeboy][]) +* [#3032](https://github.com/rubocop-hq/rubocop/issues/3032): Fix auto-correcting parentheses for predicate methods without space before args. ([@graemeboy][]) * [#3000](https://github.com/rubocop-hq/rubocop/pull/3000): Fix encoding crash on HTML output. ([@gerrywastaken][]) * [#2983](https://github.com/rubocop-hq/rubocop/pull/2983): `Style/AlignParameters` message was clarified for `with_fixed_indentation` style. ([@dylanahsmith][]) * [#2314](https://github.com/rubocop-hq/rubocop/pull/2314): Ignore `UnusedBlockArgument` for keyword arguments. ([@volkert][]) @@ -1590,7 +2597,7 @@ * `Style/OneLineConditional` cop can auto-correct. ([@lumeet][]) * [#2905](https://github.com/rubocop-hq/rubocop/issues/2905): `Style/ZeroLengthPredicate` flags code like `array.length < 1`, `1 > array.length`, and so on. ([@alexdowad][]) * [#2892](https://github.com/rubocop-hq/rubocop/issues/2892): `Lint/BlockAlignment` cop can be configured to be stricter. ([@ptarjan][]) -* `Style/Not` is able to autocorrect in cases where parentheses must be added to preserve the meaning of an expression. ([@alexdowad][]) +* `Style/Not` is able to auto-correct in cases where parentheses must be added to preserve the meaning of an expression. ([@alexdowad][]) * `Style/Not` auto-corrects comparison expressions by removing `not` and using the opposite comparison. ([@alexdowad][]) ### Bug fixes @@ -1613,7 +2620,7 @@ * [#2834](https://github.com/rubocop-hq/rubocop/issues/2834): When configured as `ConsistentQuotesInMultiline: true`, `Style/StringLiterals` doesn't error out when inspecting a heredoc with differing indentation across multiple lines. ([@alexdowad][]) * [#2876](https://github.com/rubocop-hq/rubocop/issues/2876): `Style/ConditionalAssignment` behaves correctly when assignment statement uses a character which has a special meaning in a regex. ([@alexdowad][]) * [#2877](https://github.com/rubocop-hq/rubocop/issues/2877): `Style/SpaceAroundKeyword` doesn't flag `!super.method`, `!yield.method`, and so on. ([@alexdowad][]) -* [#2631](https://github.com/rubocop-hq/rubocop/issues/2631): `Style/Encoding` can remove unneeded encoding comment when autocorrecting with `when_needed` style. ([@alexdowad][]) +* [#2631](https://github.com/rubocop-hq/rubocop/issues/2631): `Style/Encoding` can remove unneeded encoding comment when auto-correcting with `when_needed` style. ([@alexdowad][]) * [#2860](https://github.com/rubocop-hq/rubocop/issues/2860): Fix false positive in `Rails/Date` when `to_time` is chained with safe method. ([@palkan][]) * [#2898](https://github.com/rubocop-hq/rubocop/issues/2898): `Lint/NestedMethodDefinition` allows methods defined inside `Class.new(S)` blocks. ([@segiddins][]) * [#2894](https://github.com/rubocop-hq/rubocop/issues/2894): Fix auto-correct an unless with a comparison operator. ([@jweir][]) @@ -1631,7 +2638,7 @@ * [#2925](https://github.com/rubocop-hq/rubocop/pull/2925): Bump unicode-display_width dependency to >= 1.0.1. ([@jspanjers][]) * [#2875](https://github.com/rubocop-hq/rubocop/issues/2875): `Style/SignalException` does not flag calls to `fail` if a custom method named `fail` is defined in the same file. ([@alexdowad][]) * [#2923](https://github.com/rubocop-hq/rubocop/issues/2923): `Style/FileName` considers file names which contain a ? or ! character to still be "snake case". ([@alexdowad][]) -* [#2879](https://github.com/rubocop-hq/rubocop/issues/2879): When autocorrecting, `Lint/UnusedMethodArgument` removes unused block arguments rather than simply prefixing them with an underscore. ([@alexdowad][]) +* [#2879](https://github.com/rubocop-hq/rubocop/issues/2879): When auto-correcting, `Lint/UnusedMethodArgument` removes unused block arguments rather than simply prefixing them with an underscore. ([@alexdowad][]) ## 0.37.2 (2016-02-11) @@ -1646,7 +2653,7 @@ * `Style/SpaceAroundOperators` ignores aref assignments. ([@alexdowad][]) * `Style/RescueModifier` indents code correctly when auto-correcting. ([@alexdowad][]) * `Style/RedundantMerge` indents code correctly when auto-correcting, even if the corrected hash had multiple keys, and even if the corrected code was indented to start with. ([@alexdowad][]) -* [#2831](https://github.com/rubocop-hq/rubocop/issues/2831): `Performance/RedundantMerge` doesn't break code by autocorrecting a `#merge!` call which occurs at tail position in a block. ([@alexdowad][]) +* [#2831](https://github.com/rubocop-hq/rubocop/issues/2831): `Performance/RedundantMerge` doesn't break code by auto-correcting a `#merge!` call which occurs at tail position in a block. ([@alexdowad][]) ### Changes @@ -1694,7 +2701,7 @@ * [#2761](https://github.com/rubocop-hq/rubocop/pull/2761): New cop `Style/MultilineMethodDefinitionBraceLayout` checks that the closing brace in a method definition is symmetrical with respect to the opening brace and the method parameters. ([@panthomakos][]) * [#2699](https://github.com/rubocop-hq/rubocop/pull/2699): `Performance/Casecmp` can register offenses when `str.downcase` or `str.upcase` are passed to an equality method. ([@rrosenblum][]) * [#2766](https://github.com/rubocop-hq/rubocop/pull/2766): New cop `Style/MultilineMethodCallBraceLayout` checks that the closing brace in a method call is symmetrical with respect to the opening brace and the method arguments. ([@panthomakos][]) -* `Style/Semicolon` can autocorrect useless semicolons at the beginning of a line. ([@alexdowad][]) +* `Style/Semicolon` can auto-correct useless semicolons at the beginning of a line. ([@alexdowad][]) ### Bug fixes @@ -1762,7 +2769,7 @@ * `Lint/Debugger` cop can now auto-correct offenses. ([@alexdowad][]) * [#1677](https://github.com/rubocop-hq/rubocop/issues/1677): Add new `Performance/RedundantMatch` cop. ([@alexdowad][]) * [#1677](https://github.com/rubocop-hq/rubocop/issues/1677): Add new `Performance/RedundantBlockCall` cop. ([@alexdowad][]) -* [#1954](https://github.com/rubocop-hq/rubocop/issues/1954): `Lint/UnneededDisable` can now autocorrect. ([@alexdowad][]) +* [#1954](https://github.com/rubocop-hq/rubocop/issues/1954): `Lint/UnneededDisable` can now auto-correct. ([@alexdowad][]) * [#2501](https://github.com/rubocop-hq/rubocop/issues/2501): Add new `Lint/ImplicitStringConcatenation` cop. ([@alexdowad][]) * Add new `Style/RedundantParentheses` cop. ([@lumeet][]) * [#1346](https://github.com/rubocop-hq/rubocop/issues/1346): `Style/SpecialGlobalVars` can be configured to use either `use_english_names` or `use_perl_names` styles. ([@alexdowad][]) @@ -1806,7 +2813,7 @@ ### Bug Fixes -* [#2594](https://github.com/rubocop-hq/rubocop/issues/2594): `Style/EmptyLiteral` autocorrector respects `Style/StringLiterals:EnforcedStyle` config. ([@DNNX][]) +* [#2594](https://github.com/rubocop-hq/rubocop/issues/2594): `Style/EmptyLiteral` auto-corrector respects `Style/StringLiterals:EnforcedStyle` config. ([@DNNX][]) * [#2411](https://github.com/rubocop-hq/rubocop/issues/2411): Make local inherited configuration override configuration loaded from gems. ([@jonas054][]) * [#2413](https://github.com/rubocop-hq/rubocop/issues/2413): Allow `%Q` for dynamic strings with double quotes inside them. ([@jonas054][]) * [#2404](https://github.com/rubocop-hq/rubocop/issues/2404): `Style/Next` does not remove comments when auto-correcting. ([@lumeet][]) @@ -1820,7 +2827,7 @@ * [#2449](https://github.com/rubocop-hq/rubocop/issues/2449): `Style/StabbyLambdaParentheses` only checks lambdas in the arrow form. ([@lumeet][]) * [#2456](https://github.com/rubocop-hq/rubocop/issues/2456): `Lint/NestedMethodDefinition` doesn't register offenses for method definitions inside an eval block (either `instance_eval`, `class_eval`, or `module_eval`). ([@alexdowad][]) * [#2464](https://github.com/rubocop-hq/rubocop/issues/2464): `Style/ParallelAssignment` understands aref and attribute assignments, and doesn't warn if they can't be correctly rearranged into a series of single assignments. ([@alexdowad][]) -* [#2482](https://github.com/rubocop-hq/rubocop/issues/2482): `Style/AndOr` doesn't raise an exception when trying to autocorrect `!variable or ...`. ([@alexdowad][]) +* [#2482](https://github.com/rubocop-hq/rubocop/issues/2482): `Style/AndOr` doesn't raise an exception when trying to auto-correct `!variable or ...`. ([@alexdowad][]) * [#2446](https://github.com/rubocop-hq/rubocop/issues/2446): `Style/Tab` doesn't register errors for leading tabs which occur inside a string literal (including heredoc). ([@alexdowad][]) * [#2452](https://github.com/rubocop-hq/rubocop/issues/2452): `Style/TrailingComma` incorrectly categorizes single-line hashes in methods calls. ([@panthomakos][]) * [#2441](https://github.com/rubocop-hq/rubocop/issues/2441): `Style/AlignParameters` doesn't crash if it finds nested offenses. ([@alexdowad][]) @@ -1834,13 +2841,13 @@ * [#2518](https://github.com/rubocop-hq/rubocop/issues/2518): `Style/ConditionalAssignment` doesn't think that branches using `<<` and `[]=` should be combined. ([@alexdowad][]) * `CharacterLiteral` auto-corrector now properly corrects `?'`. ([@bfontaine][]) * [#2313](https://github.com/rubocop-hq/rubocop/issues/2313): `Rails/FindEach` doesn't break code which uses `order(...).each`, `limit(...).each`, and so on. ([@alexdowad][]) -* [#1938](https://github.com/rubocop-hq/rubocop/issues/1938): `Rails/FindBy` doesn't autocorrect `where(...).first` to `find_by`, since the returned record is often different. ([@alexdowad][]) +* [#1938](https://github.com/rubocop-hq/rubocop/issues/1938): `Rails/FindBy` doesn't auto-correct `where(...).first` to `find_by`, since the returned record is often different. ([@alexdowad][]) * [#1801](https://github.com/rubocop-hq/rubocop/issues/1801): `EmacsFormatter` strips newlines out of error messages, if there are any. ([@alexdowad][]) * [#2534](https://github.com/rubocop-hq/rubocop/issues/2534): `Style/RescueEnsureAlignment` works on `rescue` nested inside a `class` or `module` block. ([@alexdowad][]) * `Lint/BlockAlignment` does not refer to a block terminator as `end` when it is actually `}`. ([@alexdowad][]) * [#2540](https://github.com/rubocop-hq/rubocop/issues/2540): `Lint/FormatParameterMismatch` understands format specifiers with multiple flags. ([@alexdowad][]) * [#2538](https://github.com/rubocop-hq/rubocop/issues/2538): `Style/SpaceAroundOperators` doesn't eat newlines. ([@alexdowad][]) -* [#2531](https://github.com/rubocop-hq/rubocop/issues/2531): `Style/AndOr` autocorrects in cases where parentheses must be added, even inside a nested begin node. ([@alexdowad][]) +* [#2531](https://github.com/rubocop-hq/rubocop/issues/2531): `Style/AndOr` auto-corrects in cases where parentheses must be added, even inside a nested begin node. ([@alexdowad][]) * [#2450](https://github.com/rubocop-hq/rubocop/issues/2450): `Style/Next` adjusts indentation when auto-correcting, to avoid introducing new offenses. ([@alexdowad][]) * [#2066](https://github.com/rubocop-hq/rubocop/issues/2066): `Style/TrivialAccessors` doesn't flag what appear to be trivial accessor method definitions, if they are nested inside a call to `instance_eval`. ([@alexdowad][]) * `Style/SymbolArray` doesn't flag arrays of symbols if a symbol contains a space character. ([@alexdowad][]) @@ -1850,19 +2857,19 @@ * [#2556](https://github.com/rubocop-hq/rubocop/issues/2556): `Style/SpecialGlobalVariables` generates auto-config correctly. ([@alexdowad][]) * [#2565](https://github.com/rubocop-hq/rubocop/issues/2565): Let `Style/SpaceAroundOperators` leave spacing around `=>` to `Style/AlignHash`. ([@jonas054][]) * [#2569](https://github.com/rubocop-hq/rubocop/issues/2569): `Style/MethodCallParentheses` doesn't register warnings for `object.()` syntax, since it is handled by `Style/LambdaCall`. ([@alexdowad][]) -* [#2570](https://github.com/rubocop-hq/rubocop/issues/2570): `Performance/RedundantMerge` doesn't break code with a modifier `if` when autocorrecting. ([@alexdowad][]) -* `Performance/RedundantMerge` doesn't break code with a modifier `while` or `until` when autocorrecting. ([@alexdowad][]) +* [#2570](https://github.com/rubocop-hq/rubocop/issues/2570): `Performance/RedundantMerge` doesn't break code with a modifier `if` when auto-correcting. ([@alexdowad][]) +* `Performance/RedundantMerge` doesn't break code with a modifier `while` or `until` when auto-correcting. ([@alexdowad][]) * [#2574](https://github.com/rubocop-hq/rubocop/issues/2574): `variable` style for `Lint/EndAlignment` is working again. ([@alexdowad][]) -* `Lint/EndAlignment` can autocorrect offenses on the RHS of an assignment to an instance variable, class variable, constant, and so on; previously, it only worked if the LHS was a local variable. ([@alexdowad][]) -* [#2580](https://github.com/rubocop-hq/rubocop/issues/2580): `Style/StringReplacement` doesn't break code when autocorrection involves a regex with embedded escapes (like /\n/). ([@alexdowad][]) +* `Lint/EndAlignment` can auto-correct offenses on the RHS of an assignment to an instance variable, class variable, constant, and so on; previously, it only worked if the LHS was a local variable. ([@alexdowad][]) +* [#2580](https://github.com/rubocop-hq/rubocop/issues/2580): `Style/StringReplacement` doesn't break code when auto-correction involves a regex with embedded escapes (like /\n/). ([@alexdowad][]) * [#2582](https://github.com/rubocop-hq/rubocop/issues/2582): `Style/AlignHash` doesn't move a key so far left that it goes onto the previous line (in an attempt to align). ([@alexdowad][]) -* [#2588](https://github.com/rubocop-hq/rubocop/issues/2588): `Style/SymbolProc` doesn't break code when autocorrecting a method call with a trailing comma in the argument list. ([@alexdowad][]) +* [#2588](https://github.com/rubocop-hq/rubocop/issues/2588): `Style/SymbolProc` doesn't break code when auto-correcting a method call with a trailing comma in the argument list. ([@alexdowad][]) * [#2448](https://github.com/rubocop-hq/rubocop/issues/2448): `Style/TrailingCommaInArguments` and `Style/TrailingCommaInLiteral` don't special-case single-item lists in a way which contradicts the documentation. ([@alexdowad][]) * Fix for remote config files to only load from on http and https URLs. ([@ptrippett][]) * [#2604](https://github.com/rubocop-hq/rubocop/issues/2604): `Style/FileName` doesn't fail on empty files when `ExpectMatchingDefinition` is true. ([@alexdowad][]) * `Style/RedundantFreeze` registers offences for frozen dynamic symbols. ([@segiddins][]) -* [#2609](https://github.com/rubocop-hq/rubocop/issues/2609): All cops which rely on the `AutocorrectUnlessChangingAST` module can now autocorrect files which contain `__FILE__`. ([@alexdowad][]) -* [#2608](https://github.com/rubocop-hq/rubocop/issues/2608): `Style/ConditionalAssignment` can autocorrect `=~` within a ternary expression. ([@alexdowad][]) +* [#2609](https://github.com/rubocop-hq/rubocop/issues/2609): All cops which rely on the `AutoCorrectUnlessChangingAST` module can now auto-correct files which contain `__FILE__`. ([@alexdowad][]) +* [#2608](https://github.com/rubocop-hq/rubocop/issues/2608): `Style/ConditionalAssignment` can auto-correct `=~` within a ternary expression. ([@alexdowad][]) ### Changes @@ -1871,7 +2878,7 @@ * [#947](https://github.com/rubocop-hq/rubocop/issues/947): `Style/Documentation` considers classes and modules which only define constants to be "namespaces", and doesn't flag them for lack of a documentation comment. ([@alexdowad][]) * [#2467](https://github.com/rubocop-hq/rubocop/issues/2467): Explicitly inheriting configuration from the rubocop gem in .rubocop.yml is not allowed. ([@alexdowad][]) * [#2322](https://github.com/rubocop-hq/rubocop/issues/2322): Output of --auto-gen-config shows content of default config parameters which are Arrays; this is especially useful for SupportedStyles. ([@alexdowad][]) -* [#1566](https://github.com/rubocop-hq/rubocop/issues/1566): When autocorrecting on Windows, line endings are not converted to "\r\n" in untouched portions of the source files; corrected portions may use "\n" rather than "\r\n". ([@alexdowad][]) +* [#1566](https://github.com/rubocop-hq/rubocop/issues/1566): When auto-correcting on Windows, line endings are not converted to "\r\n" in untouched portions of the source files; corrected portions may use "\n" rather than "\r\n". ([@alexdowad][]) * New `rake repl` task can be used for experimentation when working on RuboCop. ([@alexdowad][]) * `Lint/SpaceBeforeFirstArg` cop has been removed, since it just duplicates `Style/SingleSpaceBeforeFirstArg`. ([@alexdowad][]) * `Style/SingleSpaceBeforeFirstArg` cop has been renamed to `Style/SpaceBeforeFirstArg`, which more accurately reflects what it now does. ([@alexdowad][]) @@ -1927,7 +2934,7 @@ * [#1825](https://github.com/rubocop-hq/rubocop/issues/1825): New `NameWhitelist` configuration parameter for `Style/PredicateName` can be used to suppress errors on known-good predicate names. ([@alexdowad][]) * `Style/Documentation` recognizes 'Constant = Class.new' as a class definition. ([@alexdowad][]) * [#1608](https://github.com/rubocop-hq/rubocop/issues/1608): Add new 'align_braces' style for `Style/IndentHash`. ([@alexdowad][]) -* `Style/Next` can autocorrect. ([@alexdowad][]) +* `Style/Next` can auto-correct. ([@alexdowad][]) ### Bug Fixes @@ -1941,7 +2948,7 @@ * [#2280](https://github.com/rubocop-hq/rubocop/issues/2280): Avoid reporting space between hash literal keys and values in `Style/ExtraSpacing`. ([@jonas054][]) * [#2284](https://github.com/rubocop-hq/rubocop/issues/2284): Fix result cache being shared between ruby versions. ([@miquella][]) * [#2285](https://github.com/rubocop-hq/rubocop/issues/2285): Fix `ConfigurableNaming#class_emitter_method?` error when handling singleton class methods. ([@palkan][]) -* [#2295](https://github.com/rubocop-hq/rubocop/issues/2295): Fix Performance/Detect autocorrect to handle rogue newlines. ([@palkan][]) +* [#2295](https://github.com/rubocop-hq/rubocop/issues/2295): Fix Performance/Detect auto-correct to handle rogue newlines. ([@palkan][]) * [#2294](https://github.com/rubocop-hq/rubocop/issues/2294): Do not register an offense in `Performance/StringReplacement` for regex with options. ([@rrosenblum][]) * Fix `Style/UnneededPercentQ` condition for single-quoted literal containing interpolation-like string. ([@eagletmt][]) * [#2324](https://github.com/rubocop-hq/rubocop/issues/2324): Handle `--only Lint/Syntax` and `--except Lint/Syntax` correctly. ([@jonas054][]) @@ -1959,11 +2966,11 @@ * [#2068](https://github.com/rubocop-hq/rubocop/issues/2068): Display warning if `Style/Copyright` is misconfigured. ([@alexdowad][]) * [#2321](https://github.com/rubocop-hq/rubocop/issues/2321): In `Style/EachWithObject`, don't replace reduce with each_with_object if the accumulator parameter is assigned to in the block. ([@alexdowad][]) * [#1981](https://github.com/rubocop-hq/rubocop/issues/1981): `Lint/UselessAssignment` doesn't erroneously identify assignments in identical if branches as useless. ([@alexdowad][]) -* [#2323](https://github.com/rubocop-hq/rubocop/issues/2323): `Style/IfUnlessModifier` cop parenthesizes autocorrected code when necessary due to operator precedence, to avoid changing its meaning. ([@alexdowad][]) +* [#2323](https://github.com/rubocop-hq/rubocop/issues/2323): `Style/IfUnlessModifier` cop parenthesizes auto-corrected code when necessary due to operator precedence, to avoid changing its meaning. ([@alexdowad][]) * [#2003](https://github.com/rubocop-hq/rubocop/issues/2003): Make `Lint/UnneededDisable` work with `--auto-correct`. ([@jonas054][]) * Default RuboCop cache dir moved to per-user folders. ([@br3nda][]) * [#2393](https://github.com/rubocop-hq/rubocop/pull/2393): `Style/MethodCallParentheses` doesn't fail on `obj.method ||= func()`. ([@alexdowad][]) -* [#2344](https://github.com/rubocop-hq/rubocop/pull/2344): When autocorrecting, `Style/ParallelAssignment` reorders assignment statements, if necessary, to avoid breaking code. ([@alexdowad][]) +* [#2344](https://github.com/rubocop-hq/rubocop/pull/2344): When auto-correcting, `Style/ParallelAssignment` reorders assignment statements, if necessary, to avoid breaking code. ([@alexdowad][]) * `Style/MultilineOperationAlignment` does not try to align the receiver and selector of a method call if both are on the LHS of an assignment. ([@alexdowad][]) ### Changes @@ -2101,7 +3108,7 @@ * [#2006](https://github.com/rubocop-hq/rubocop/issues/2006): Fix crash in `Style/FirstParameterIndentation` in case of nested offenses. ([@unmanbearpig][]) * [#2059](https://github.com/rubocop-hq/rubocop/issues/2059): Don't check for trivial accessors in modules. ([@bbatsov][]) * Add proper punctuation to the end of offense messages, where it is missing. ([@lumeet][]) -* [#2071](https://github.com/rubocop-hq/rubocop/pull/2071): Keep line breaks in place on WordArray autocorrect.([@unmanbearpig][]) +* [#2071](https://github.com/rubocop-hq/rubocop/pull/2071): Keep line breaks in place on WordArray auto-correct.([@unmanbearpig][]) * [#2075](https://github.com/rubocop-hq/rubocop/pull/2075): Properly correct `Style/PercentLiteralDelimiters` with escape characters in them. ([@rrosenblum][]) * [#2023](https://github.com/rubocop-hq/rubocop/issues/2023): Avoid auto-correction corruption in `IndentationWidth`. ([@jonas054][]) * [#2080](https://github.com/rubocop-hq/rubocop/issues/2080): Properly parse code in `Performance/Count` when calling `select..count` in a class that extends an enumerable. ([@rrosenblum][]) @@ -2122,7 +3129,7 @@ * [#1955](https://github.com/rubocop-hq/rubocop/issues/1955): Fix false positive for `Style/TrailingComma` cop. ([@mattjmcnaughton][]) * [#1928](https://github.com/rubocop-hq/rubocop/issues/1928): Avoid auto-correcting two alignment offenses in the same area at the same time. ([@jonas054][]) * [#1964](https://github.com/rubocop-hq/rubocop/issues/1964): Fix `RedundantBegin` auto-correct issue with comments by doing a smaller correction. ([@jonas054][]) -* [#1978](https://github.com/rubocop-hq/rubocop/pull/1978): Don't count disabled offences if fail-level is autocorrect. ([@sch1zo][]) +* [#1978](https://github.com/rubocop-hq/rubocop/pull/1978): Don't count disabled offences if fail-level is auto-correct. ([@sch1zo][]) * [#1986](https://github.com/rubocop-hq/rubocop/pull/1986): Fix Date false positives on variables. ([@palkan][]) ### Changes @@ -2159,7 +3166,7 @@ * [#1879](https://github.com/rubocop-hq/rubocop/issues/1879): Avoid auto-correcting hash with trailing comma into invalid code in `BracesAroundHashParameters`. ([@jonas054][]) * [#1868](https://github.com/rubocop-hq/rubocop/issues/1868): Do not register an offense in `Performance/Count` when `select` is called with symbols or strings as the parameters. ([@rrosenblum][]) * `Sample` rewritten to properly handle shuffle randomness source, first/last params and non-literal ranges. ([@chastell][]) -* [#1873](https://github.com/rubocop-hq/rubocop/issues/1873): Modify `ParallelAssignment` to properly autocorrect when the assignment is protected by a modifier statement. ([@rrosenblum][]) +* [#1873](https://github.com/rubocop-hq/rubocop/issues/1873): Modify `ParallelAssignment` to properly auto-correct when the assignment is protected by a modifier statement. ([@rrosenblum][]) * Configure `ParallelAssignment` to work with non-standard `IndentationWidths`. ([@rrosenblum][]) * [#1899](https://github.com/rubocop-hq/rubocop/issues/1899): Be careful about comments when auto-correcting in `BracesAroundHashParameters`. ([@jonas054][]) * [#1897](https://github.com/rubocop-hq/rubocop/issues/1897): Don't report that semicolon separated statements can be converted to modifier form in `IfUnlessModifier` (and don't auto-correct them). ([@jonas054][]) @@ -2194,9 +3201,9 @@ * [#1820](https://github.com/rubocop-hq/rubocop/issues/1820): Correct the logic in `AlignHash` for when to ignore a key because it's not on its own line. ([@jonas054][]) * [#1829](https://github.com/rubocop-hq/rubocop/pull/1829): Fix bug in `Sample` and `FlatMap` that would cause them to report having been auto-corrected when they were not. ([@rrosenblum][]) * [#1832](https://github.com/rubocop-hq/rubocop/pull/1832): Fix bug in `UnusedMethodArgument` that would cause them to report having been auto-corrected when they were not. ([@jonas054][]) -* [#1834](https://github.com/rubocop-hq/rubocop/issues/1834): Support only boolean values for `AutoCorrect` configuration parameter, and remove warning for unknown parameter. ([@jonas054][]) +* [#1834](https://github.com/rubocop-hq/rubocop/issues/1834): Support only boolean values for `Auto-Correct` configuration parameter, and remove warning for unknown parameter. ([@jonas054][]) * [#1843](https://github.com/rubocop-hq/rubocop/issues/1843): Fix crash in `TrailingBlankLines` when a file ends with a block comment without final newline. ([@jonas054][]) -* [#1849](https://github.com/rubocop-hq/rubocop/issues/1849): Fix bug where you can not have nested arrays in the Rake task configuration. ([@rrosenblum][]) +* [#1849](https://github.com/rubocop-hq/rubocop/issues/1849): Fix bug where you cannot have nested arrays in the Rake task configuration. ([@rrosenblum][]) * Fix bug in `MultilineTernaryOperator` where it will not register an offense when only the false branch is on a separate line. ([@rrosenblum][]) * Fix crash in `MultilineBlockLayout` when using new lambda literal syntax without parentheses. ([@hbd225][]) * [#1859](https://github.com/rubocop-hq/rubocop/pull/1859): Fix bugs in `IfUnlessModifier` concerning comments and empty lines. ([@jonas054][]) @@ -2211,7 +3218,7 @@ * [#1773](https://github.com/rubocop-hq/rubocop/pull/1773): Fix typo ('strptime' -> 'strftime') in `Rails/TimeZone`. ([@palkan][]) * [#1777](https://github.com/rubocop-hq/rubocop/pull/1777): Fix offense message from Rails/TimeZone. ([@mzp][]) * [#1784](https://github.com/rubocop-hq/rubocop/pull/1784): Add an explicit error message when config contains an empty section. ([@bankair][]) -* [#1791](https://github.com/rubocop-hq/rubocop/pull/1791): Fix autocorrection of `PercentLiteralDelimiters` with no content. ([@cshaffer][]) +* [#1791](https://github.com/rubocop-hq/rubocop/pull/1791): Fix auto-correction of `PercentLiteralDelimiters` with no content. ([@cshaffer][]) * Fix handling of `while` and `until` with assignment in `IndentationWidth`. ([@lumeet][]) * [#1793](https://github.com/rubocop-hq/rubocop/pull/1793): Fix bug in `TrailingComma` that caused `,` in comment to count as a trailing comma. ([@jonas054][]) * [#1765](https://github.com/rubocop-hq/rubocop/pull/1765): Update 1.9 hash to stop triggering when the symbol is not valid in the 1.9 hash syntax. ([@crimsonknave][]) @@ -2239,7 +3246,7 @@ * [#1602](https://github.com/rubocop-hq/rubocop/issues/1602): Add support for `# :nodoc` in `Documentation`. ([@lumeet][]) * [#1437](https://github.com/rubocop-hq/rubocop/issues/1437): Modify `HashSyntax` cop to allow the use of hash rockets for hashes that have symbol values when using ruby19 syntax. ([@rrosenblum][]) * New cop `Style/SymbolLiteral` makes sure you're not using the string within symbol syntax unless it's needed. ([@bbatsov][]) -* [#1657](https://github.com/rubocop-hq/rubocop/issues/1657): Autocorrect can be turned off on a specific cop via the configuration. ([@jdoconnor][]) +* [#1657](https://github.com/rubocop-hq/rubocop/issues/1657): Auto-Correct can be turned off on a specific cop via the configuration. ([@jdoconnor][]) * New cop `Style/AutoResourceCleanup` suggests the use of block taking versions of methods that do resource cleanup. ([@bbatsov][]) * [#1275](https://github.com/rubocop-hq/rubocop/issues/1275): `WhileUntilModifier` cop does auto-correction. ([@lumeet][]) * New cop `Performance/ReverseEach` to convert `reverse.each` to `reverse_each`. ([@rrosenblum][]) @@ -2269,7 +3276,7 @@ * [#1676](https://github.com/rubocop-hq/rubocop/pull/1676): Fix auto-correct in `Lambda` when a new multi-line lambda is used as an argument. ([@lumeet][]) * [#1656](https://github.com/rubocop-hq/rubocop/issues/1656): Fix bug that would include hidden directories implicitly. ([@jonas054][]) * [#1728](https://github.com/rubocop-hq/rubocop/pull/1728): Fix bug in `LiteralInInterpolation` and `AssignmentInCondition`. ([@ypresto][]) -* [#1735](https://github.com/rubocop-hq/rubocop/issues/1735): Handle trailing space in `LineEndConcatenation` autocorrect. ([@jonas054][]) +* [#1735](https://github.com/rubocop-hq/rubocop/issues/1735): Handle trailing space in `LineEndConcatenation` auto-correct. ([@jonas054][]) * [#1750](https://github.com/rubocop-hq/rubocop/issues/1750): Escape offending code lines output by the HTML formatter in case they contain markup. ([@jonas054][]) * [#1541](https://github.com/rubocop-hq/rubocop/issues/1541): No inspection of text that follows `__END__`. ([@jonas054][]) * Fix comment detection in `Style/Documentation`. ([@lumeet][]) @@ -2299,12 +3306,12 @@ * [#1430](https://github.com/rubocop-hq/rubocop/issues/1430): Add `--except` option for disabling cops on the command line. ([@jonas054][]) * [#1506](https://github.com/rubocop-hq/rubocop/pull/1506): Add auto-correct from `EvenOdd` cop. ([@blainesch][]) * [#1507](https://github.com/rubocop-hq/rubocop/issues/1507): `Debugger` cop now checks for the Capybara debug methods `save_and_open_page` and `save_and_open_screenshot`. ([@rrosenblum][]) -* [#1539](https://github.com/rubocop-hq/rubocop/pull/1539): Implement autocorrection for Rails/ReadWriteAttribute cop. ([@huerlisi][]) +* [#1539](https://github.com/rubocop-hq/rubocop/pull/1539): Implement auto-correction for Rails/ReadWriteAttribute cop. ([@huerlisi][]) * [#1324](https://github.com/rubocop-hq/rubocop/issues/1324): Add `AllCops/DisplayCopNames` configuration option for showing cop names in reports, like `--display-cop-names`. ([@jonas054][]) * [#1271](https://github.com/rubocop-hq/rubocop/issues/1271): `Lambda` cop does auto-correction. ([@lumeet][]) * [#1284](https://github.com/rubocop-hq/rubocop/issues/1284): Support namespaces, e.g. `Lint`, in the arguments to `--only` and `--except`. ([@jonas054][]) * [#1276](https://github.com/rubocop-hq/rubocop/issues/1276): `SelfAssignment` cop does auto-correction. ([@lumeet][]) -* Add autocorrect to `RedundantException`. ([@mattjmcnaughton][]) +* Add auto-correct to `RedundantException`. ([@mattjmcnaughton][]) * [#1571](https://github.com/rubocop-hq/rubocop/pull/1571): New cop `StructInheritance` checks for inheritance from Struct.new. ([@mmozuras][]) * [#1575](https://github.com/rubocop-hq/rubocop/issues/1575): New cop `DuplicateMethods` points out duplicate method name in class and module. ([@d4rk5eed][]) * [#1144](https://github.com/rubocop-hq/rubocop/issues/1144): New cop `FirstParameterIndentation` checks the indentation of the first parameter in a method call. ([@jonas054][]) @@ -2319,7 +3326,7 @@ ### Bugs fixed -* [#1634](https://github.com/rubocop-hq/rubocop/pull/1634): Fix `PerlBackrefs` Cop Autocorrections to Not Raise. ([@cshaffer][]) +* [#1634](https://github.com/rubocop-hq/rubocop/pull/1634): Fix `PerlBackrefs` cop auto-corrections to not raise. ([@cshaffer][]) * [#1553](https://github.com/rubocop-hq/rubocop/pull/1553): Fix bug where `Style/EmptyLinesAroundAccessModifier` interfered with `Style/EmptyLinesAroundBlockBody` when there is and access modifier at the beginning of a block. ([@volkert][]) * Handle element assignment in `Lint/AssignmentInCondition`. ([@jonas054][]) * [#1484](https://github.com/rubocop-hq/rubocop/issues/1484): Fix `EmptyLinesAroundAccessModifier` incorrectly finding a violation inside method calls with names identical to an access modifier. ([@dblock][]) @@ -2329,7 +3336,7 @@ * [#1504](https://github.com/rubocop-hq/rubocop/issues/1504): Fail with a meaningful error if the configuration file is malformed. ([@bquorning][]) * Fix bug where `auto_correct` Rake tasks does not take in the options specified in its parent task. ([@rrosenblum][]) * [#1054](https://github.com/rubocop-hq/rubocop/issues/1054): Handle comments within concatenated strings in `LineEndConcatenation`. ([@yujinakayama][], [@jonas054][]) -* [#1527](https://github.com/rubocop-hq/rubocop/issues/1527): Make autocorrect `BracesAroundHashParameter` leave the correct number of spaces. ([@mattjmcnaughton][]) +* [#1527](https://github.com/rubocop-hq/rubocop/issues/1527): Make auto-correct `BracesAroundHashParameter` leave the correct number of spaces. ([@mattjmcnaughton][]) * [#1547](https://github.com/rubocop-hq/rubocop/issues/1547): Don't print `[Corrected]` when auto-correction was avoided in `Style/Semicolon`. ([@jonas054][]) * [#1573](https://github.com/rubocop-hq/rubocop/issues/1573): Fix assignment-related auto-correction for `BlockAlignment`. ([@lumeet][]) * [#1587](https://github.com/rubocop-hq/rubocop/pull/1587): Exit with exit code 1 if there were errors ("crashing" cops). ([@jonas054][]) @@ -2355,7 +3362,7 @@ * [#801](https://github.com/rubocop-hq/rubocop/issues/801): New style `context_dependent` for `Style/BracesAroundHashParameters` looks at preceding parameter to determine if braces should be used for final parameter. ([@jonas054][]) * [#1427](https://github.com/rubocop-hq/rubocop/issues/1427): Excluding directories on the top level is now done earlier, so that these file trees are not searched, thus saving time when inspecting projects with many excluded files. ([@jonas054][]) -* [#1325](https://github.com/rubocop-hq/rubocop/issues/1325): When running with `--auto-correct`, only offenses *that can not be corrected* will result in a non-zero exit code. ([@jonas054][]) +* [#1325](https://github.com/rubocop-hq/rubocop/issues/1325): When running with `--auto-correct`, only offenses *that cannot be corrected* will result in a non-zero exit code. ([@jonas054][]) * [#1445](https://github.com/rubocop-hq/rubocop/issues/1445): Allow sprockets directive comments (starting with `#=`) in `Style/LeadingCommentSpace`. ([@bbatsov][]) ### Bugs fixed @@ -2365,10 +3372,10 @@ * [#1181](https://github.com/rubocop-hq/rubocop/issues/1181): *(fix again)* `Style/StringLiterals` cop stays away from strings inside interpolated expressions. ([@jonas054][]) * [#1441](https://github.com/rubocop-hq/rubocop/issues/1441): Correct the logic used by `Style/Blocks` and other cops to determine if an auto-correction would alter the meaning of the code. ([@jonas054][]) * [#1449](https://github.com/rubocop-hq/rubocop/issues/1449): Handle the case in `MultilineOperationIndentation` where instances of both correct style and unrecognized (plain wrong) style are detected during an `--auto-gen-config` run. ([@jonas054][]) -* [#1456](https://github.com/rubocop-hq/rubocop/pull/1456): Fix autocorrect in `SymbolProc` when there are multiple offenses on the same line. ([@jcarbo][]) +* [#1456](https://github.com/rubocop-hq/rubocop/pull/1456): Fix auto-correct in `SymbolProc` when there are multiple offenses on the same line. ([@jcarbo][]) * [#1459](https://github.com/rubocop-hq/rubocop/issues/1459): Handle parenthesis around the condition in `--auto-correct` for `NegatedWhile`. ([@jonas054][]) -* [#1465](https://github.com/rubocop-hq/rubocop/issues/1465): Fix autocorrect of code like `#$1` in `PerlBackrefs`. ([@bbatsov][]) -* Fix autocorrect of code like `#$:` in `SpecialGlobalVars`. ([@bbatsov][]) +* [#1465](https://github.com/rubocop-hq/rubocop/issues/1465): Fix auto-correct of code like `#$1` in `PerlBackrefs`. ([@bbatsov][]) +* Fix auto-correct of code like `#$:` in `SpecialGlobalVars`. ([@bbatsov][]) * [#1466](https://github.com/rubocop-hq/rubocop/issues/1466): Allow leading underscore for unused parameters in `SingleLineBlockParams`. ([@jonas054][]) * [#1470](https://github.com/rubocop-hq/rubocop/issues/1470): Handle `elsif` + `else` in `ElseAlignment`. ([@jonas054][]) * [#1474](https://github.com/rubocop-hq/rubocop/issues/1474): Multiline string with both `<<` and `\` caught by `Style/LineEndConcatenation` cop. ([@katieschilling][]) @@ -2411,7 +3418,7 @@ ### Bugs fixed * `AlignHash` no longer skips multiline hashes that contain some elements on the same line. ([@mvz][]) -* [#1349](https://github.com/rubocop-hq/rubocop/issues/1349): `BracesAroundHashParameters` no longer cleans up whitespace in autocorrect, as these extra corrections are likely to interfere with other cops' corrections. ([@jonas054][]) +* [#1349](https://github.com/rubocop-hq/rubocop/issues/1349): `BracesAroundHashParameters` no longer cleans up whitespace in auto-correct, as these extra corrections are likely to interfere with other cops' corrections. ([@jonas054][]) * [#1350](https://github.com/rubocop-hq/rubocop/issues/1350): Guard against `Blocks` cop introducing syntax errors in auto-correct. ([@jonas054][]) * [#1374](https://github.com/rubocop-hq/rubocop/issues/1374): To eliminate interference, auto-correction is now done by one cop at a time, with saving and re-parsing in between. ([@jonas054][]) * [#1388](https://github.com/rubocop-hq/rubocop/issues/1388): Fix a false positive in `FormatString`. ([@bbatsov][]) @@ -2466,7 +3473,7 @@ ### New features -* [#1259](https://github.com/rubocop-hq/rubocop/issues/1259): Allow AndOr cop to autocorrect by adding method call parenthesis. ([@vrthra][]) +* [#1259](https://github.com/rubocop-hq/rubocop/issues/1259): Allow AndOr cop to auto-correct by adding method call parenthesis. ([@vrthra][]) * [#1232](https://github.com/rubocop-hq/rubocop/issues/1232): Add EnforcedStyle option to cop `AndOr` to restrict it to conditionals. ([@vrthra][]) * [#835](https://github.com/rubocop-hq/rubocop/issues/835): New cop `PercentQLiterals` checks if use of `%Q` and `%q` matches configuration. ([@jonas054][]) * [#835](https://github.com/rubocop-hq/rubocop/issues/835): New cop `BarePercentLiterals` checks if usage of `%()` or `%Q()` matches configuration. ([@jonas054][]) @@ -2493,12 +3500,12 @@ * Fix `SpacesInsideBrackets` for `Hash#[]` calls with spaces after left bracket. ([@mcls][]) * [#1210](https://github.com/rubocop-hq/rubocop/issues/1210): Fix false positive in `UnneededPercentQ` for `%Q(\t")`. ([@jonas054][]) * Fix false positive in `UnneededPercentQ` for heredoc strings with `%q`/`%Q`. ([@jonas054][]) -* [#1214](https://github.com/rubocop-hq/rubocop/issues/1214): Don't destroy code in `AlignHash` autocorrect. ([@jonas054][]) +* [#1214](https://github.com/rubocop-hq/rubocop/issues/1214): Don't destroy code in `AlignHash` auto-correct. ([@jonas054][]) * [#1219](https://github.com/rubocop-hq/rubocop/issues/1219): Don't report bad alignment for `end` or `}` in `BlockAlignment` if it doesn't begin its line. ([@jonas054][]) * [#1227](https://github.com/rubocop-hq/rubocop/issues/1227): Don't permanently change yamler as it can affect other apps. ([@jonas054][]) * [#1184](https://github.com/rubocop-hq/rubocop/issues/1184): Fix a false positive in `Output` cop. ([@bbatsov][]) * [#1256](https://github.com/rubocop-hq/rubocop/issues/1256): Ignore block-pass in `TrailingComma`. ([@tamird][]) -* [#1255](https://github.com/rubocop-hq/rubocop/issues/1255): Compare without context in `AutocorrectUnlessChangingAST`. ([@jonas054][]) +* [#1255](https://github.com/rubocop-hq/rubocop/issues/1255): Compare without context in `Auto-CorrectUnlessChangingAST`. ([@jonas054][]) * [#1262](https://github.com/rubocop-hq/rubocop/issues/1262): Handle regexp and backtick literals in `VariableInterpolation`. ([@bbatsov][]) ## 0.24.1 (2014-07-03) @@ -2591,7 +3598,7 @@ ### Changes -* `NonNilCheck` offense reporting and autocorrect are configurable to include semantic changes. ([@hannestyden][]) +* `NonNilCheck` offense reporting and auto-correct are configurable to include semantic changes. ([@hannestyden][]) * The parameters `AllCops/Excludes` and `AllCops/Includes` with final `s` only give a warning and don't halt `rubocop` execution. ([@jonas054][]) * The `GuardClause` cop is no longer ignoring a one-line body by default - see configuration. ([@geniou][]) * [#1050](https://github.com/rubocop-hq/rubocop/issues/1050): Rename `rubocop-todo.yml` file to `.rubocop_todo.yml`. ([@geniou][]) @@ -2805,7 +3812,7 @@ ### Bugs fixed -* Remove double reporting in `EmptyLinesAroundBody` of empty line inside otherwise empty class/module/method that caused crash in autocorrect. ([@jonas054][]) +* Remove double reporting in `EmptyLinesAroundBody` of empty line inside otherwise empty class/module/method that caused crash in auto-correct. ([@jonas054][]) * [#779](https://github.com/rubocop-hq/rubocop/issues/779): Fix a false positive in `LineEndConcatenation`. ([@bbatsov][]) * [#751](https://github.com/rubocop-hq/rubocop/issues/751): Fix `Documentation` cop so that a comment followed by an empty line and then a class definition is not considered to be class documentation. ([@jonas054][]) * [#783](https://github.com/rubocop-hq/rubocop/issues/783): Fix a false positive in `ParenthesesAroundCondition` when the parentheses are actually required. ([@bbatsov][]) @@ -2965,7 +3972,7 @@ * [#567](https://github.com/rubocop-hq/rubocop/pull/567): Register an offence when the last hash parameter has braces in `BracesAroundHashParameters` cop. ([@dblock][]) * `StringLiterals` cop no longer reports errors for character literals such as ?/. That should be done only by the `CharacterLiterals` cop. ([@jonas054][]) * Made auto-correct much less likely to crash due to conflicting corrections ("clobbering"). ([@jonas054][]) -* [#565](https://github.com/rubocop-hq/rubocop/pull/565): `$GLOBAL_VAR from English library` should no longer be inserted when autocorrecting short-form global variables like `$!`. ([@nevir][]) +* [#565](https://github.com/rubocop-hq/rubocop/pull/565): `$GLOBAL_VAR from English library` should no longer be inserted when auto-correcting short-form global variables like `$!`. ([@nevir][]) * [#566](https://github.com/rubocop-hq/rubocop/pull/566): Methods that just assign a splat to an ivar are no longer considered trivial writers. ([@nevir][]) * [#585](https://github.com/rubocop-hq/rubocop/pull/585): `MethodCallParentheses` should allow methods starting with uppercase letter. ([@bbatsov][]) * [#574](https://github.com/rubocop-hq/rubocop/issues/574): Fix error on multiple-assignment with non-array right hand side in `UselessSetterCall`. ([@yujinakayama][]) @@ -3166,7 +4173,7 @@ * Fix bug in favor_modifier.rb regarding missed offences after else etc. * [#393](https://github.com/rubocop-hq/rubocop/issues/393): Retract support for multiline chaining of blocks (which fixed [#346](https://github.com/rubocop-hq/rubocop/issues/346)), thus rejecting issue 346. * [#389](https://github.com/rubocop-hq/rubocop/issues/389): Ignore symbols that are arguments to Module#private_constant in `SymbolName` cop. -* [#387](https://github.com/rubocop-hq/rubocop/issues/387): Do autocorrect in `AndOr` cop only if it does not change the meaning of the code. +* [#387](https://github.com/rubocop-hq/rubocop/issues/387): Do auto-correct in `AndOr` cop only if it does not change the meaning of the code. * [#398](https://github.com/rubocop-hq/rubocop/issues/398): Don't display blank lines in the output of the clang formatter. * [#283](https://github.com/rubocop-hq/rubocop/issues/283): Refine `StringLiterals` string content check. @@ -3704,6 +4711,7 @@ [@sue445]: https://github.com/sue445 [@zverok]: https://github.com/zverok [@backus]: https://github.com/backus +[@AdrienSldy]: https://github.com/adriensldy [@pat]: https://github.com/pat [@sinsoku]: https://github.com/sinsoku [@nodo]: https://github.com/nodo @@ -3878,3 +4886,98 @@ [@elmasantos]: https://github.com/elmasantos [@luciamo]: https://github.com/luciamo [@dirtyharrycallahan]: https://github.com/dirtyharrycallahan +[@ericsullivan]: https://github.com/ericsullivan +[@aeroastro]: https://github.com/aeroastro +[@anuja-joshi]: https://github.com/anuja-joshi +[@XrXr]: https://github.com/XrXr +[@thomthom]: https://github.com/thomthom +[@Blue-Pix]: https://github.com/Blue-Pix +[@diachini]: https://github.com/diachini +[@Mange]: https://github.com/Mange +[@jmanian]: https://github.com/jmanian +[@vfonic]: https://github.com/vfonic +[@andreaseger]: https://github.com/andreaseger +[@yakout]: https://github.com/yakout +[@RicardoTrindade]: https://github.com/RicardoTrindade +[@att14]: https://github.com/att14 +[@houli]: https://github.com/houli +[@lavoiesl]: https://github.com/lavoiesl +[@fwininger]: https://github.com/fwininger +[@stoivo]: https://github.com/stoivo +[@eugeneius]: https://github.com/eugeneius +[@malyshkosergey]: https://github.com/malyshkosergey +[@fwitzke]: https://github.com/fwitzke +[@okuramasafumi]: https://github.com/okuramasafumi +[@buehmann]: https://github.com/buehmann +[@halfwhole]: https://github.com/halfwhole +[@riley-klingler]: https://github.com/riley-klingler +[@prathamesh-sonpatki]: https://github.com/prathamesh-sonpatki +[@raymondfallon]: https://github.com/raymondfallon +[@crojasaragonez]: https://github.com/crojasaragonez +[@desheikh]: https://github.com/desheikh +[@laurenball]: https://github.com/laurenball +[@jfhinchcliffe]: https://github.com/jfhinchcliffe +[@jdkaplan]: https://github.com/jdkaplan +[@cstyles]: https://github.com/cstyles +[@avmnu-sng]: https://github.com/avmnu-sng +[@denys281]: https://github.com/denys281 +[@tyler-ball]: https://github.com/tyler-ball +[@ayacai115]: https://github.com/ayacai115 +[@ozydingo]: https://github.com/ozydingo +[@movermeyer]: https://github.com/movermeyer +[@jethroo]: https://github.com/jethroo +[@mangara]: https://github.com/mangara +[@pirj]: https://github.com/pirj +[@pawptart]: https://github.com/pawptart +[@cetinajero]: https://github.com/cetinajero +[@gfyoung]: https://github.com/gfyoung +[@Tietew]: https://github.com/Tietew +[@hanachin]: https://github.com/hanachin +[@masarakki]: https://github.com/masarakki +[@djudd]: https://github.com/djudd +[@jemmaissroff]: https://github.com/jemmaissroff +[@nikitasakov]: https://github.com/nikitasakov +[@dmolesUC]: https://github.com/dmolesUC +[@yuritomanek]: https://github.com/yuritomanek +[@egze]: https://github.com/egze +[@rafaelfranca]: https://github.com/rafaelfranca +[@knu]: https://github.com/knu +[@saurabhmaurya15]: https://github.com/saurabhmaurya15 +[@DracoAter]: https://github.com/DracoAter +[@diogoosorio]: https://github.com/diogoosorio +[@jeffcarbs]: https://github.com/jeffcarbs +[@laurmurclar]: https://github.com/laurmurclar +[@jethrodaniel]: https://github.com/jethrodaniel +[@CvX]: https://github.com/CvX +[@jschneid]: https://github.com/jschneid +[@ric2b]: https://github.com/ric2b +[@burnettk]: https://github.com/burnettk +[@andrykonchin]: https://github.com/andrykonchin +[@avrusanov]: https://github.com/avrusanov +[@mauro-oto]: https://github.com/mauro-oto +[@fatkodima]: https://github.com/fatkodima +[@karlwithak]: https://github.com/karlwithak +[@CamilleDrapier]: https://github.com/CamilleDrapier +[@shekhar-patil]: https://github.com/shekhar-patil +[@knejad]: https://github.com/knejad +[@iamravitejag]: https://github.com/iamravitejag +[@volfgox]: https://github.com/volfgox +[@colszowka]: https://github.com/colszowka +[@dsavochkin]: https://github.com/dmytro-savochkin +[@sonalinavlakhe]: https://github.com/sonalinavlakhe +[@wcmonty]: https://github.com/wcmonty +[@nguyenquangminh0711]: https://github.com/nguyenquangminh0711 +[@chocolateboy]: https://github.com/chocolateboy +[@Lykos]: https://github.com/Lykos +[@jaimerave]: https://github.com/jaimerave +[@Skipants]: https://github.com/Skipants +[@sascha-wolf]: https://github.com/sascha-wolf +[@fsateler]: https://github.com/fsateler +[@iSarCasm]: https://github.com/iSarCasm +[@em-gazelle]: https://github.com/em-gazelle +[@tleish]: https://github.com/tleish +[@pbernays]: https://github.com/pbernays +[@rdunlop]: https://github.com/rdunlop +[@ghiculescu]: https://github.com/ghiculescu +[@hatkyinc2]: https://github.com/hatkyinc2 +[@AllanSiqueira]: https://github.com/allansiqueira diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000000..859ed96de184 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,14 @@ +# The RuboCop Community Code of Conduct + +**Note:** We have picked the following code of conduct based on [Ruby's own code of conduct](https://www.ruby-lang.org/en/conduct/). + +This document provides a few simple community guidelines for a safe, respectful, +productive, and collaborative place for any person who is willing to contribute +to the RuboCop community. It applies to all "collaborative spaces", which are +defined as community communications channels (such as mailing lists, submitted +patches, commit comments, etc.). + +* Participants will be tolerant of opposing views. +* Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks. +* When interpreting the words and actions of others, participants should always assume good intentions. +* Behaviour which can be reasonably considered harassment will not be tolerated. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index dc6b2f14f0f7..dfa0cf072cb8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,6 +26,7 @@ $ rubocop -V * Read [how to properly contribute to open source projects on GitHub][2]. * Fork the project. +* If you're adding or making changes to cops, read the [Development docs](https://docs.rubocop.org/rubocop/development.html) * Use a topic/feature branch to easily amend a pull request later, if necessary. * Write [good commit messages][3]. * Use the same coding conventions as the rest of the project. @@ -51,12 +52,14 @@ Here are a few examples: ``` * [#716](https://github.com/rubocop-hq/rubocop/issues/716): Fixed a regression in the auto-correction logic of `MethodDefParentheses`. ([@bbatsov][]) * New cop `ElseLayout` checks for odd arrangement of code in the `else` branch of a conditional expression. ([@bbatsov][]) +* [#7542](https://github.com/rubocop-hq/rubocop/pull/7542): **(Breaking)** Move `LineLength` cop from `Metrics` department to `Layout` department. ([@koic][]) ``` * Mark it up in [Markdown syntax][6]. * The entry line should start with `* ` (an asterisk and a space). * If the change has a related GitHub issue (e.g. a bug fix for a reported issue), put a link to the issue as `[#123](https://github.com/rubocop-hq/rubocop/issues/123): `. * Describe the brief of the change. The sentence should end with a punctuation. +* If this is a breaking change, mark it with `**(Breaking)**`. * At the end of the entry, add an implicit link to your GitHub user page as `([@username][])`. * If this is your first contribution to RuboCop project, add a link definition for the implicit link to the bottom of the changelog as `[@username]: https://github.com/username`. diff --git a/Gemfile b/Gemfile index 0cbb3bc77a7c..7cd9ed643ade 100644 --- a/Gemfile +++ b/Gemfile @@ -5,12 +5,17 @@ source 'https://rubygems.org' gemspec gem 'bump', require: false +gem 'memory_profiler', platform: :mri gem 'pry' -gem 'pry-byebug' if RUBY_ENGINE == 'ruby' -gem 'rake', '~> 12.0' +gem 'rake', '~> 13.0' gem 'rspec', '~> 3.7' -gem 'rubocop-rspec', '~> 1.32.0' -gem 'simplecov', '~> 0.10' +gem 'rubocop-performance', '~> 1.7.0' +gem 'rubocop-rspec', '~> 1.39.0' +# Workaround for cc-test-reporter with SimpleCov 0.18. +# Stop upgrading SimpleCov until the following issue will be resolved. +# https://github.com/codeclimate/test-reporter/issues/418 +gem 'simplecov', '~> 0.10', '< 0.18' +gem 'stackprof', platform: :mri gem 'test-queue' gem 'yard', '~> 0.9' @@ -19,5 +24,8 @@ group :test do gem 'webmock', require: false end -local_gemfile = 'Gemfile.local' +local_ast = File.expand_path('../rubocop-ast', __dir__) +gem 'rubocop-ast', path: local_ast if Dir.exist? local_ast + +local_gemfile = File.expand_path('Gemfile.local', __dir__) eval_gemfile local_gemfile if File.exist?(local_gemfile) diff --git a/LICENSE.txt b/LICENSE.txt index 3e26a668b9d2..139a35f2c747 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2012-19 Bozhidar Batsov +Copyright (c) 2012-20 Bozhidar Batsov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index 2ee21d0a4cd6..41f1158bdedf 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,32 @@ +

+ RuboCop Logo +

+ +---------- +[![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop-hq/rubocop) [![Gem Version](https://badge.fury.io/rb/rubocop.svg)](https://badge.fury.io/rb/rubocop) [![CircleCI Status](https://circleci.com/gh/rubocop-hq/rubocop/tree/master.svg?style=svg)](https://circleci.com/gh/rubocop-hq/rubocop/tree/master) -[![AppVeyor Status](https://ci.appveyor.com/api/projects/status/sj3ye7n5690d0nvg?svg=true)](https://ci.appveyor.com/project/bbatsov/rubocop) -[![Coverage Status](https://api.codeclimate.com/v1/badges/ad6e76460499c8c99697/test_coverage)](https://codeclimate.com/github/bbatsov/rubocop) -[![Code Climate](https://codeclimate.com/github/bbatsov/rubocop/badges/gpa.svg)](https://codeclimate.com/github/bbatsov/rubocop) -[![Inline docs](https://inch-ci.org/github/bbatsov/rubocop.svg)](https://inch-ci.org/github/bbatsov/rubocop) +[![Actions Status](https://github.com/rubocop-hq/rubocop/workflows/CI/badge.svg?branch=master)](https://github.com/rubocop-hq/rubocop/actions?query=workflow%3ACI) +[![Test Coverage](https://api.codeclimate.com/v1/badges/d2d67f728e88ea84ac69/test_coverage)](https://codeclimate.com/github/rubocop-hq/rubocop/test_coverage) +[![Maintainability](https://api.codeclimate.com/v1/badges/d2d67f728e88ea84ac69/maintainability)](https://codeclimate.com/github/rubocop-hq/rubocop/maintainability) [![SemVer](https://api.dependabot.com/badges/compatibility_score?dependency-name=rubocop&package-manager=bundler&version-scheme=semver)](https://dependabot.com/compatibility-score.html?dependency-name=rubocop&package-manager=bundler&version-scheme=semver) [![Patreon](https://img.shields.io/badge/patreon-donate-orange.svg)](https://www.patreon.com/bbatsov) -[![Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/bbatsov/donate) [![OpenCollective](https://opencollective.com/rubocop/backers/badge.svg)](#open-collective-backers) [![OpenCollective](https://opencollective.com/rubocop/sponsors/badge.svg)](#open-collective-sponsors) - -

- RuboCop Logo -

+[![Tidelift](https://tidelift.com/badges/package/rubygems/rubocop)](https://tidelift.com/subscription/pkg/rubygems-rubocop?utm_source=rubygems-rubocop&utm_medium=referral&utm_campaign=readme) > Role models are important.
> -- Officer Alex J. Murphy / RoboCop -**RuboCop** is a Ruby static code analyzer and code formatter. Out of -the box it will enforce many of the guidelines outlined in the -community [Ruby Style -Guide](https://github.com/rubocop-hq/ruby-style-guide). +**RuboCop** is a Ruby static code analyzer (a.k.a. `linter`) and code formatter. Out of the box it +will enforce many of the guidelines outlined in the community [Ruby Style +Guide](https://rubystyle.guide). Apart from reporting the problems discovered in your code, +RuboCop can also automatically fix many of them for you. RuboCop is extremely flexible and most aspects of its behavior can be tweaked via various [configuration options](https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml). -Apart from reporting problems in your code, RuboCop can also -automatically fix some of the problems for you. - -[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bbatsov/rubocop?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) - **Please consider [financially supporting its ongoing development](#funding).** ## Installation @@ -41,7 +37,7 @@ automatically fix some of the problems for you. $ gem install rubocop ``` -If you'd rather install RuboCop using `bundler`, don't require it in your `Gemfile`: +If you'd rather install RuboCop using `bundler`, add a line for it in your `Gemfile` (but set the `require` option to `false`, as it is a standalone tool): ```rb gem 'rubocop', require: false @@ -53,7 +49,7 @@ haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you might want to use a conservative version lock in your `Gemfile`: ```rb -gem 'rubocop', '~> 0.66.0', require: false +gem 'rubocop', '~> 0.93.1', require: false ``` ## Quickstart @@ -65,20 +61,26 @@ $ cd my/cool/ruby/project $ rubocop ``` -## Official manual +## Documentation -You can read a ton more about RuboCop in its [official manual](https://docs.rubocop.org). +You can read a lot more about RuboCop in its [official docs](https://docs.rubocop.org). ## Compatibility RuboCop supports the following Ruby implementations: -* MRI 2.2+ -* JRuby 9.0+ +* MRI 2.4+ +* JRuby 9.2+ + +See [compatibility](https://docs.rubocop.org/rubocop/compatibility.html) for further details. + +## Readme Badge + +If you use RuboCop in your project, you can include one of these badges in your readme to let people know that your code is written following the community Ruby Style Guide. -The Rails cops support the following versions: +[![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop-hq/rubocop) -* Rails 4.0+ +[![Ruby Style Guide](https://img.shields.io/badge/code_style-community-brightgreen.svg)](https://rubystyle.guide) ## Team @@ -92,6 +94,8 @@ Here's a list of RuboCop's core developers: * [Masataka Kuwabara](https://github.com/pocke) * [Koichi Ito](https://github.com/koic) * [Maxim Krizhanovski](https://github.com/darhazer) +* [Benjamin Quorning](https://github.com/bquorning) +* [Marc-André Lafortune](https://github.com/marcandre) ## Logo @@ -136,9 +140,9 @@ If you're working in a company that's making significant use of RuboCop we'd app to become a RuboCop sponsor. You can support the development of RuboCop via -[Salt](https://salt.bountysource.com/teams/rubocop), +[GitHub Sponsors](https://github.com/sponsors/bbatsov), [Patreon](https://www.patreon.com/bbatsov), -[Liberapay](https://liberapay.com/bbatsov/donate), +[PayPal](https://paypal.me/bbatsov) and [Open Collective](https://opencollective.com/rubocop). ### Open Collective Backers @@ -217,5 +221,5 @@ RuboCop's changelog is available [here](CHANGELOG.md). ## Copyright -Copyright (c) 2012-2019 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for +Copyright (c) 2012-2020 Bozhidar Batsov. See [LICENSE.txt](LICENSE.txt) for further details. diff --git a/Rakefile b/Rakefile index d169d3d4af86..a6c5ef81b305 100644 --- a/Rakefile +++ b/Rakefile @@ -18,16 +18,10 @@ require 'rubocop/rake_task' Dir['tasks/**/*.rake'].each { |t| load t } -desc 'Deprecated: Run test and RuboCop in parallel' -task :parallel do - warn '`rake parallel` is deprecated. Use `rake default` instead.' - Rake::Task[:default].execute -end - desc 'Run RuboCop over itself' RuboCop::RakeTask.new(:internal_investigation).tap do |task| if RUBY_ENGINE == 'ruby' && - RbConfig::CONFIG['host_os'] !~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/ + !/mswin|msys|mingw|cygwin|bccwin|wince|emc/.match?(RbConfig::CONFIG['host_os']) task.options = %w[--parallel] end end @@ -53,9 +47,9 @@ task :bench_cop, %i[cop srcpath times] do |_task, args| iterations = args[:times] ? Integer(args[:times]) : 1 cop_class = if cop_name.include?('/') - Cop::Cop.all.find { |klass| klass.cop_name == cop_name } + Cop::Registry.all.find { |klass| klass.cop_name == cop_name } else - Cop::Cop.all.find do |klass| + Cop::Registry.all.find do |klass| klass.cop_name[/[a-zA-Z]+$/] == cop_name end end @@ -75,7 +69,7 @@ task :bench_cop, %i[cop srcpath times] do |_task, args| puts "(#{pluralize(iterations, 'iteration')}, " \ "#{pluralize(files.size, 'file')})" - ruby_version = RuboCop::Config::KNOWN_RUBIES.last + ruby_version = RuboCop::TargetRuby.supported_versions.last srcs = files.map { |file| ProcessedSource.from_file(file, ruby_version) } puts 'Finished parsing source, testing inspection...' @@ -90,10 +84,12 @@ end desc 'Syntax check for the documentation comments' task documentation_syntax_check: :yard_for_generate_documentation do require 'parser/ruby25' + require 'parser/ruby26' + require 'parser/ruby27' ok = true YARD::Registry.load! - cops = RuboCop::Cop::Cop.registry + cops = RuboCop::Cop::Registry.global cops.each do |cop| next if %i[RSpec Capybara FactoryBot].include?(cop.department) @@ -107,12 +103,23 @@ task documentation_syntax_check: :yard_for_generate_documentation do begin buffer = Parser::Source::Buffer.new('', 1) buffer.source = example.text - parser = Parser::Ruby25.new(RuboCop::AST::Builder.new) + + # Ruby 2.6 or higher does not support a syntax used in + # `Lint/UselessElseWithoutRescue` cop's example. + parser = if cop == RuboCop::Cop::Lint::UselessElseWithoutRescue + Parser::Ruby25.new(RuboCop::AST::Builder.new) + # Ruby 2.7 raises an syntax error in + # `Lint/CircularArgumentReference` cop's example. + elsif cop == RuboCop::Cop::Lint::CircularArgumentReference + Parser::Ruby26.new(RuboCop::AST::Builder.new) + else + Parser::Ruby27.new(RuboCop::AST::Builder.new) + end parser.diagnostics.all_errors_are_fatal = true parser.parse(buffer) - rescue Parser::SyntaxError => ex + rescue Parser::SyntaxError => e path = example.object.file - puts "#{path}: Syntax Error in an example. #{ex}" + puts "#{path}: Syntax Error in an example. #{e}" ok = false end end diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index 82d585a80d77..000000000000 --- a/appveyor.yml +++ /dev/null @@ -1,23 +0,0 @@ ---- - -version: "{build}" - -install: - - set PATH=C:\Ruby%ruby_version%\bin;%PATH% - - gem update --no-document --system - - gem install bundler --no-document - - bundle install --jobs 3 --retry 3 - -build: off - -# We are intentionally starting Rake a few times here, because we have seen some -# encoding issues when all tasks are run in just one process (`rake default`). -test_script: - - bundle exec rake spec - - bundle exec rake ascii_spec - - bundle exec rake internal_investigation - -environment: - matrix: - - ruby_version: '25' - - ruby_version: 25-x64 diff --git a/bin/console b/bin/console index 4017047705e1..22306174008d 100755 --- a/bin/console +++ b/bin/console @@ -1,6 +1,7 @@ #!/usr/bin/env ruby # frozen_string_literal: true +require 'bundler/setup' require 'pry' require 'rubocop' diff --git a/bin/rubocop-profile b/bin/rubocop-profile new file mode 100755 index 000000000000..fefc31abc227 --- /dev/null +++ b/bin/rubocop-profile @@ -0,0 +1,32 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +if ARGV.include?('-h') || ARGV.include?('--help') + puts "Usage: same as main `rubocop` command but gathers profiling info" + puts "Additional option: `--memory` to print memory usage" + exit(0) +end +with_mem = ARGV.delete('--memory') +ARGV.unshift '--cache', 'false' unless ARGV.include?('--cache') + +require 'stackprof' +if with_mem + require 'memory_profiler' + MemoryProfiler.start +end +StackProf.start +start = Process.clock_gettime(Process::CLOCK_MONOTONIC) +begin + load "#{__dir__}/../exe/rubocop" +ensure + delta = Process.clock_gettime(Process::CLOCK_MONOTONIC) - start + puts "Finished in #{delta.round(1)} seconds" + StackProf.stop + if with_mem + puts "Building memory report..." + report = MemoryProfiler.stop + end + Dir.mkdir('tmp') unless File.exist?('tmp') + StackProf.results('tmp/stackprof.dump') + report&.pretty_print(scale_bytes: true) +end diff --git a/config/default.yml b/config/default.yml index 062897a5cb3b..f57334fa9166 100644 --- a/config/default.yml +++ b/config/default.yml @@ -35,6 +35,7 @@ AllCops: - '**/*.watchr' - '**/.irbrc' - '**/.pryrc' + - '**/.simplecov' - '**/buildfile' - '**/Appraisals' - '**/Berksfile' @@ -53,12 +54,15 @@ AllCops: - '**/Podfile' - '**/Puppetfile' - '**/Rakefile' + - '**/rakefile' - '**/Snapfile' + - '**/Steepfile' - '**/Thorfile' - '**/Vagabondfile' - '**/Vagrantfile' Exclude: - 'node_modules/**/*' + - 'tmp/**/*' - 'vendor/**/*' - '.git/**/*' # Default formatter will be used if no `-f/--format` option is given. @@ -73,7 +77,7 @@ AllCops: DisplayStyleGuide: false # When specifying style guide URLs, any paths and/or fragments will be # evaluated relative to the base URL. - StyleGuideBaseURL: https://github.com/rubocop-hq/ruby-style-guide + StyleGuideBaseURL: https://rubystyle.guide # Extra details are not displayed in offense messages by default. Change # behavior by overriding ExtraDetails, or by giving the # `-E/--extra-details` option. @@ -95,6 +99,14 @@ AllCops: # to true in the same configuration. EnabledByDefault: false DisabledByDefault: false + # New cops introduced between major versions are set to a special pending status + # and are not enabled by default with warning message. + # Change this behavior by overriding either `NewCops: enable` or `NewCops: disable`. + # When `NewCops` is `enable`, pending cops are enabled in bulk. Can be overridden by + # the `--enable-pending-cops` command-line option. + # When `NewCops` is `disable`, pending cops are disabled in bulk. Can be overridden by + # the `--disable-pending-cops` command-line option. + NewCops: pending # Enables the result cache if `true`. Can be overridden by the `--cache` command # line option. UseCache: true @@ -105,6 +117,8 @@ AllCops: # CacheRootDirectory is ~ (nil), which it is by default, the root will be # taken from the environment variable `$XDG_CACHE_HOME` if it is set, or if # `$XDG_CACHE_HOME` is not set, it will be `$HOME/.cache/`. + # The CacheRootDirectory can be overwritten by passing the `--cache-root` command + # line option or by setting `$RUBOCOP_CACHE_ROOT` environment variable. CacheRootDirectory: ~ # It is possible for a malicious user to know the location of RuboCop's cache # directory by looking at CacheRootDirectory, and create a symlink in its @@ -123,16 +137,8 @@ AllCops: # followed by the Gemfile.lock or gems.locked file. (Although the Ruby version # is specified in the Gemfile or gems.rb file, RuboCop reads the final value # from the lock file.) If the Ruby version is still unresolved, RuboCop will - # use the oldest officially supported Ruby version (currently Ruby 2.2). + # use the oldest officially supported Ruby version (currently Ruby 2.4). TargetRubyVersion: ~ - # What version of Rails is the inspected code using? If a value is specified - # for TargetRailsVersion then it is used. Acceptable values are specificed - # as a float (i.e. 5.1); the patch version of Rails should not be included. - # If TargetRailsVersion is not set, RuboCop will parse the Gemfile.lock or - # gems.locked file to find the version of Rails that has been bound to the - # application. If neither of those files exist, RuboCop will use Rails 5.0 - # as the default. - TargetRailsVersion: ~ #################### Bundler ############################### @@ -149,11 +155,13 @@ Bundler/GemComment: Description: 'Add a comment describing each gem.' Enabled: false VersionAdded: '0.59' + VersionChanged: '0.85' Include: - '**/*.gemfile' - '**/Gemfile' - '**/gems.rb' - Whitelist: [] + IgnoredGems: [] + OnlyFor: [] Bundler/InsecureProtocolSource: Description: >- @@ -174,6 +182,9 @@ Bundler/OrderedGems: VersionAdded: '0.46' VersionChanged: '0.47' TreatCommentsAsGroupSeparators: true + # By default, "-" and "_" are ignored for order purposes. + # This can be overridden by setting this parameter to true. + ConsiderPunctuation: false Include: - '**/*.gemfile' - '**/Gemfile' @@ -194,13 +205,25 @@ Gemspec/OrderedDependencies: Enabled: true VersionAdded: '0.51' TreatCommentsAsGroupSeparators: true + # By default, "-" and "_" are ignored for order purposes. + # This can be overridden by setting this parameter to true. + ConsiderPunctuation: false Include: - '**/*.gemspec' Gemspec/RequiredRubyVersion: - Description: 'Checks that `required_ruby_version` of gemspec and `TargetRubyVersion` of .rubocop.yml are equal.' + Description: 'Checks that `required_ruby_version` of gemspec is specified and equal to `TargetRubyVersion` of .rubocop.yml.' Enabled: true VersionAdded: '0.52' + VersionChanged: '0.89' + Include: + - '**/*.gemspec' + +Gemspec/RubyVersionGlobalsUsage: + Description: Checks usage of RUBY_VERSION in gemspec. + StyleGuide: '#no-ruby-version-in-the-gemspec' + Enabled: true + VersionAdded: '0.72' Include: - '**/*.gemspec' @@ -219,118 +242,88 @@ Layout/AccessModifierIndentation: # But it can be overridden by setting this parameter IndentationWidth: ~ -Layout/AlignArray: - Description: >- - Align the elements of an array literal if they span more than - one line. - StyleGuide: '#align-multiline-arrays' - Enabled: true - VersionAdded: '0.49' - -Layout/AlignHash: +Layout/ArgumentAlignment: Description: >- - Align the elements of a hash literal if they span more than - one line. + Align the arguments of a method call if they span more + than one line. + StyleGuide: '#no-double-indent' Enabled: true - VersionAdded: '0.49' - # Alignment of entries using hash rocket as separator. Valid values are: + VersionAdded: '0.68' + VersionChanged: '0.77' + # Alignment of arguments in multi-line method calls. # - # key - left alignment of keys - # 'a' => 2 - # 'bb' => 3 - # separator - alignment of hash rockets, keys are right aligned - # 'a' => 2 - # 'bb' => 3 - # table - left alignment of keys, hash rockets, and values - # 'a' => 2 - # 'bb' => 3 - EnforcedHashRocketStyle: key - SupportedHashRocketStyles: - - key - - separator - - table - # Alignment of entries using colon as separator. Valid values are: + # The `with_first_argument` style aligns the following lines along the same + # column as the first parameter. # - # key - left alignment of keys - # a: 0 - # bb: 1 - # separator - alignment of colons, keys are right aligned - # a: 0 - # bb: 1 - # table - left alignment of keys and values - # a: 0 - # bb: 1 - EnforcedColonStyle: key - SupportedColonStyles: - - key - - separator - - table - # Select whether hashes that are the last argument in a method call should be - # inspected? Valid values are: + # method_call(a, + # b) # - # always_inspect - Inspect both implicit and explicit hashes. - # Registers an offense for: - # function(a: 1, - # b: 2) - # Registers an offense for: - # function({a: 1, - # b: 2}) - # always_ignore - Ignore both implicit and explicit hashes. - # Accepts: - # function(a: 1, - # b: 2) - # Accepts: - # function({a: 1, - # b: 2}) - # ignore_implicit - Ignore only implicit hashes. - # Accepts: - # function(a: 1, - # b: 2) - # Registers an offense for: - # function({a: 1, - # b: 2}) - # ignore_explicit - Ignore only explicit hashes. - # Accepts: - # function({a: 1, - # b: 2}) - # Registers an offense for: - # function(a: 1, - # b: 2) - EnforcedLastArgumentHashStyle: always_inspect - SupportedLastArgumentHashStyles: - - always_inspect - - always_ignore - - ignore_implicit - - ignore_explicit + # The `with_fixed_indentation` style aligns the following lines with one + # level of indentation relative to the start of the line with the method call. + # + # method_call(a, + # b) + EnforcedStyle: with_first_argument + SupportedStyles: + - with_first_argument + - with_fixed_indentation + # By default, the indentation width from Layout/IndentationWidth is used + # But it can be overridden by setting this parameter + IndentationWidth: ~ -Layout/AlignParameters: +Layout/ArrayAlignment: Description: >- - Align the parameters of a method call if they span more - than one line. + Align the elements of an array literal if they span more than + one line. StyleGuide: '#no-double-indent' Enabled: true VersionAdded: '0.49' - # Alignment of parameters in multi-line method calls. + VersionChanged: '0.77' + # Alignment of elements of a multi-line array. # # The `with_first_parameter` style aligns the following lines along the same - # column as the first parameter. + # column as the first element. # - # method_call(a, - # b) + # array = [1, 2, 3, + # 4, 5, 6] # # The `with_fixed_indentation` style aligns the following lines with one - # level of indentation relative to the start of the line with the method call. + # level of indentation relative to the start of the line with start of array. # - # method_call(a, - # b) - EnforcedStyle: with_first_parameter + # array = [1, 2, 3, + # 4, 5, 6] + EnforcedStyle: with_first_element SupportedStyles: - - with_first_parameter + - with_first_element - with_fixed_indentation # By default, the indentation width from Layout/IndentationWidth is used # But it can be overridden by setting this parameter IndentationWidth: ~ +Layout/AssignmentIndentation: + Description: >- + Checks the indentation of the first line of the + right-hand-side of a multi-line assignment. + Enabled: true + VersionAdded: '0.49' + VersionChanged: '0.77' + # By default, the indentation width from `Layout/IndentationWidth` is used + # But it can be overridden by setting this parameter + IndentationWidth: ~ + +Layout/BeginEndAlignment: + Description: 'Align ends corresponding to begins correctly.' + Enabled: pending + VersionAdded: '0.91' + # The value `start_of_line` means that `end` should be aligned the start of the line + # where the `begin` keyword is. + # The value `begin` means that `end` should be aligned with the `begin` keyword. + EnforcedStyleAlignWith: start_of_line + SupportedStylesAlignWith: + - start_of_line + - begin + Severity: warning + Layout/BlockAlignment: Description: 'Align block ends correctly.' Enabled: true @@ -368,7 +361,7 @@ Layout/CaseIndentation: Layout/ClassStructure: Description: 'Enforces a configured order of definitions within a class body.' - StyleGuide: 'https://github.com/rubocop-hq/ruby-style-guide#consistent-classes' + StyleGuide: '#consistent-classes' Enabled: false VersionAdded: '0.52' Categories: @@ -407,6 +400,7 @@ Layout/ConditionPosition: StyleGuide: '#same-line-condition' Enabled: true VersionAdded: '0.53' + VersionChanged: '0.83' Layout/DefEndAlignment: Description: 'Align ends corresponding to defs correctly.' @@ -420,7 +414,6 @@ Layout/DefEndAlignment: SupportedStylesAlignWith: - start_of_line - def - AutoCorrect: false Severity: warning Layout/DotPosition: @@ -457,6 +450,14 @@ Layout/EmptyLineAfterMagicComment: Enabled: true VersionAdded: '0.49' +Layout/EmptyLineAfterMultilineCondition: + Description: 'Enforces empty line after multiline condition.' + # This is disabled, because this style is not very common in practice. + Enabled: false + VersionAdded: '0.90' + Reference: + - https://github.com/airbnb/ruby#multiline-if-newline + Layout/EmptyLineBetweenDefs: Description: 'Use empty lines between defs.' StyleGuide: '#empty-lines-between-methods' @@ -479,12 +480,32 @@ Layout/EmptyLinesAroundAccessModifier: StyleGuide: '#empty-lines-around-access-modifier' Enabled: true VersionAdded: '0.49' + EnforcedStyle: around + SupportedStyles: + - around + - only_before + Reference: + # A reference to `EnforcedStyle: only_before`. + - https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions Layout/EmptyLinesAroundArguments: Description: "Keeps track of empty lines around method arguments." Enabled: true VersionAdded: '0.52' +Layout/EmptyLinesAroundAttributeAccessor: + Description: "Keep blank lines around attribute accessors." + StyleGuide: '#empty-lines-around-attribute-accessor' + Enabled: pending + VersionAdded: '0.83' + VersionChanged: '0.84' + AllowAliasSyntax: true + AllowedMethods: + - alias_method + - public + - protected + - private + Layout/EmptyLinesAroundBeginBody: Description: "Keeps track of empty lines around begin-end bodies." StyleGuide: '#empty-lines-around-bodies' @@ -556,7 +577,6 @@ Layout/EndAlignment: - keyword - variable - start_of_line - AutoCorrect: false Severity: warning Layout/EndOfLine: @@ -588,39 +608,11 @@ Layout/ExtraSpacing: # When true, forces the alignment of `=` in assignments on consecutive lines. ForceEqualSignAlignment: false -Layout/FirstArrayElementLineBreak: - Description: >- - Checks for a line break before the first element in a - multi-line array. - Enabled: false - VersionAdded: '0.49' - -Layout/FirstHashElementLineBreak: - Description: >- - Checks for a line break before the first element in a - multi-line hash. - Enabled: false - VersionAdded: '0.49' - -Layout/FirstMethodArgumentLineBreak: - Description: >- - Checks for a line break before the first argument in a - multi-line method call. - Enabled: false - VersionAdded: '0.49' - -Layout/FirstMethodParameterLineBreak: - Description: >- - Checks for a line break before the first parameter in a - multi-line method parameter definition. - Enabled: false - VersionAdded: '0.49' - -Layout/FirstParameterIndentation: - Description: 'Checks the indentation of the first parameter in a method call.' +Layout/FirstArgumentIndentation: + Description: 'Checks the indentation of the first argument in a method call.' Enabled: true - VersionAdded: '0.49' - VersionChanged: '0.56' + VersionAdded: '0.68' + VersionChanged: '0.77' EnforcedStyle: special_for_inner_method_call_in_parentheses SupportedStyles: # The first parameter should always be indented one step more than the @@ -641,12 +633,13 @@ Layout/FirstParameterIndentation: # But it can be overridden by setting this parameter IndentationWidth: ~ -Layout/IndentArray: +Layout/FirstArrayElementIndentation: Description: >- Checks the indentation of the first element in an array literal. Enabled: true - VersionAdded: '0.49' + VersionAdded: '0.68' + VersionChanged: '0.77' # The value `special_inside_parentheses` means that array literals with # brackets that have their opening bracket on the same line as a surrounding # opening round parenthesis, shall have their first element indented relative @@ -667,20 +660,18 @@ Layout/IndentArray: # But it can be overridden by setting this parameter IndentationWidth: ~ -Layout/IndentAssignment: +Layout/FirstArrayElementLineBreak: Description: >- - Checks the indentation of the first line of the - right-hand-side of a multi-line assignment. - Enabled: true + Checks for a line break before the first element in a + multi-line array. + Enabled: false VersionAdded: '0.49' - # By default, the indentation width from `Layout/IndentationWidth` is used - # But it can be overridden by setting this parameter - IndentationWidth: ~ -Layout/IndentHash: +Layout/FirstHashElementIndentation: Description: 'Checks the indentation of the first key in a hash literal.' Enabled: true - VersionAdded: '0.49' + VersionAdded: '0.68' + VersionChanged: '0.77' # The value `special_inside_parentheses` means that hash literals with braces # that have their opening brace on the same line as a surrounding opening # round parenthesis, shall have their first key indented relative to the @@ -701,99 +692,268 @@ Layout/IndentHash: # But it can be overridden by setting this parameter IndentationWidth: ~ -Layout/IndentHeredoc: - Description: 'This cop checks the indentation of the here document bodies.' - StyleGuide: '#squiggly-heredocs' - Enabled: true - VersionAdded: '0.49' - EnforcedStyle: auto_detection - SupportedStyles: - - auto_detection - - squiggly - - active_support - - powerpack - - unindent - -Layout/IndentationConsistency: - Description: 'Keep indentation straight.' - StyleGuide: '#spaces-indentation' - Enabled: true - VersionAdded: '0.49' - # The difference between `rails` and `normal` is that the `rails` style - # prescribes that in classes and modules the `protected` and `private` - # modifier keywords shall be indented the same as public methods and that - # protected and private members shall be indented one step more than the - # modifiers. Other than that, both styles mean that entities on the same - # logical depth shall have the same indentation. - EnforcedStyle: normal - SupportedStyles: - - normal - - rails - -Layout/IndentationWidth: - Description: 'Use 2 spaces for indentation.' - StyleGuide: '#spaces-indentation' - Enabled: true +Layout/FirstHashElementLineBreak: + Description: >- + Checks for a line break before the first element in a + multi-line hash. + Enabled: false VersionAdded: '0.49' - # Number of spaces for each indentation level. - Width: 2 - IgnoredPatterns: [] -Layout/InitialIndentation: +Layout/FirstMethodArgumentLineBreak: Description: >- - Checks the indentation of the first non-blank non-comment line in a file. - Enabled: true + Checks for a line break before the first argument in a + multi-line method call. + Enabled: false VersionAdded: '0.49' -Layout/LeadingBlankLines: - Description: Check for unnecessary blank lines at the beginning of a file. - Enabled: true - VersionAdded: '0.57' - -Layout/LeadingCommentSpace: - Description: 'Comments should start with a space.' - StyleGuide: '#hash-space' - Enabled: true +Layout/FirstMethodParameterLineBreak: + Description: >- + Checks for a line break before the first parameter in a + multi-line method parameter definition. + Enabled: false VersionAdded: '0.49' -Layout/MultilineArrayBraceLayout: +Layout/FirstParameterIndentation: Description: >- - Checks that the closing brace in an array literal is - either on the same line as the last array element, or - a new line. + Checks the indentation of the first parameter in a + method definition. Enabled: true VersionAdded: '0.49' - EnforcedStyle: symmetrical + VersionChanged: '0.77' + EnforcedStyle: consistent SupportedStyles: - # symmetrical: closing brace is positioned in same way as opening brace - # new_line: closing brace is always on a new line - # same_line: closing brace is always on the same line as last element - - symmetrical - - new_line - - same_line + - consistent + - align_parentheses + # By default, the indentation width from `Layout/IndentationWidth` is used + # But it can be overridden by setting this parameter + IndentationWidth: ~ -Layout/MultilineAssignmentLayout: - Description: 'Check for a newline after the assignment operator in multi-line assignments.' - StyleGuide: '#indent-conditional-assignment' - Enabled: false +Layout/HashAlignment: + Description: >- + Align the elements of a hash literal if they span more than + one line. + Enabled: true + AllowMultipleStyles: true VersionAdded: '0.49' - # The types of assignments which are subject to this rule. - SupportedTypes: - - block - - case - - class - - if - - kwbegin - - module - EnforcedStyle: new_line - SupportedStyles: - # Ensures that the assignment operator and the rhs are on the same line for - # the set of supported types. - - same_line - # Ensures that the assignment operator and the rhs are on separate lines - # for the set of supported types. - - new_line - + VersionChanged: '0.77' + # Alignment of entries using hash rocket as separator. Valid values are: + # + # key - left alignment of keys + # 'a' => 2 + # 'bb' => 3 + # separator - alignment of hash rockets, keys are right aligned + # 'a' => 2 + # 'bb' => 3 + # table - left alignment of keys, hash rockets, and values + # 'a' => 2 + # 'bb' => 3 + EnforcedHashRocketStyle: key + SupportedHashRocketStyles: + - key + - separator + - table + # Alignment of entries using colon as separator. Valid values are: + # + # key - left alignment of keys + # a: 0 + # bb: 1 + # separator - alignment of colons, keys are right aligned + # a: 0 + # bb: 1 + # table - left alignment of keys and values + # a: 0 + # bb: 1 + EnforcedColonStyle: key + SupportedColonStyles: + - key + - separator + - table + # Select whether hashes that are the last argument in a method call should be + # inspected? Valid values are: + # + # always_inspect - Inspect both implicit and explicit hashes. + # Registers an offense for: + # function(a: 1, + # b: 2) + # Registers an offense for: + # function({a: 1, + # b: 2}) + # always_ignore - Ignore both implicit and explicit hashes. + # Accepts: + # function(a: 1, + # b: 2) + # Accepts: + # function({a: 1, + # b: 2}) + # ignore_implicit - Ignore only implicit hashes. + # Accepts: + # function(a: 1, + # b: 2) + # Registers an offense for: + # function({a: 1, + # b: 2}) + # ignore_explicit - Ignore only explicit hashes. + # Accepts: + # function({a: 1, + # b: 2}) + # Registers an offense for: + # function(a: 1, + # b: 2) + EnforcedLastArgumentHashStyle: always_inspect + SupportedLastArgumentHashStyles: + - always_inspect + - always_ignore + - ignore_implicit + - ignore_explicit + +Layout/HeredocArgumentClosingParenthesis: + Description: >- + Checks for the placement of the closing parenthesis in a + method call that passes a HEREDOC string as an argument. + Enabled: false + StyleGuide: '#heredoc-argument-closing-parentheses' + VersionAdded: '0.68' + +Layout/HeredocIndentation: + Description: 'This cop checks the indentation of the here document bodies.' + StyleGuide: '#squiggly-heredocs' + Enabled: true + VersionAdded: '0.49' + VersionChanged: '0.85' + +Layout/IndentationConsistency: + Description: 'Keep indentation straight.' + StyleGuide: '#spaces-indentation' + Enabled: true + VersionAdded: '0.49' + # The difference between `indented` and `normal` is that the `indented_internal_methods` + # style prescribes that in classes and modules the `protected` and `private` + # modifier keywords shall be indented the same as public methods and that + # protected and private members shall be indented one step more than the + # modifiers. Other than that, both styles mean that entities on the same + # logical depth shall have the same indentation. + EnforcedStyle: normal + SupportedStyles: + - normal + - indented_internal_methods + Reference: + # A reference to `EnforcedStyle: indented_internal_methods`. + - https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions + +Layout/IndentationStyle: + Description: 'Consistent indentation either with tabs only or spaces only.' + StyleGuide: '#spaces-indentation' + Enabled: true + VersionAdded: '0.49' + VersionChanged: '0.82' + # By default, the indentation width from Layout/IndentationWidth is used + # But it can be overridden by setting this parameter + # It is used during auto-correction to determine how many spaces should + # replace each tab. + IndentationWidth: ~ + EnforcedStyle: spaces + SupportedStyles: + - spaces + - tabs + +Layout/IndentationWidth: + Description: 'Use 2 spaces for indentation.' + StyleGuide: '#spaces-indentation' + Enabled: true + VersionAdded: '0.49' + # Number of spaces for each indentation level. + Width: 2 + IgnoredPatterns: [] + +Layout/InitialIndentation: + Description: >- + Checks the indentation of the first non-blank non-comment line in a file. + Enabled: true + VersionAdded: '0.49' + +Layout/LeadingCommentSpace: + Description: 'Comments should start with a space.' + StyleGuide: '#hash-space' + Enabled: true + VersionAdded: '0.49' + VersionChanged: '0.73' + AllowDoxygenCommentStyle: false + AllowGemfileRubyComment: false + +Layout/LeadingEmptyLines: + Description: Check for unnecessary blank lines at the beginning of a file. + Enabled: true + VersionAdded: '0.57' + VersionChanged: '0.77' + +Layout/LineLength: + Description: 'Checks that line length does not exceed the configured limit.' + StyleGuide: '#max-line-length' + Enabled: true + VersionAdded: '0.25' + VersionChanged: '0.84' + AutoCorrect: false + Max: 120 + # To make it possible to copy or click on URIs in the code, we allow lines + # containing a URI to be longer than Max. + AllowHeredoc: true + AllowURI: true + URISchemes: + - http + - https + # The IgnoreCopDirectives option causes the LineLength rule to ignore cop + # directives like '# rubocop: enable ...' when calculating a line's length. + IgnoreCopDirectives: true + # The IgnoredPatterns option is a list of !ruby/regexp and/or string + # elements. Strings will be converted to Regexp objects. A line that matches + # any regular expression listed in this option will be ignored by LineLength. + IgnoredPatterns: [] + +Layout/MultilineArrayBraceLayout: + Description: >- + Checks that the closing brace in an array literal is + either on the same line as the last array element, or + a new line. + Enabled: true + VersionAdded: '0.49' + EnforcedStyle: symmetrical + SupportedStyles: + # symmetrical: closing brace is positioned in same way as opening brace + # new_line: closing brace is always on a new line + # same_line: closing brace is always on the same line as last element + - symmetrical + - new_line + - same_line + +Layout/MultilineArrayLineBreaks: + Description: >- + Checks that each item in a multi-line array literal + starts on a separate line. + Enabled: false + VersionAdded: '0.67' + +Layout/MultilineAssignmentLayout: + Description: 'Check for a newline after the assignment operator in multi-line assignments.' + StyleGuide: '#indent-conditional-assignment' + Enabled: false + VersionAdded: '0.49' + # The types of assignments which are subject to this rule. + SupportedTypes: + - block + - case + - class + - if + - kwbegin + - module + EnforcedStyle: new_line + SupportedStyles: + # Ensures that the assignment operator and the rhs are on the same line for + # the set of supported types. + - same_line + # Ensures that the assignment operator and the rhs are on separate lines + # for the set of supported types. + - new_line + Layout/MultilineBlockLayout: Description: 'Ensures newlines after multiline block do statements.' Enabled: true @@ -815,6 +975,20 @@ Layout/MultilineHashBraceLayout: - new_line - same_line +Layout/MultilineHashKeyLineBreaks: + Description: >- + Checks that each item in a multi-line hash literal + starts on a separate line. + Enabled: false + VersionAdded: '0.67' + +Layout/MultilineMethodArgumentLineBreaks: + Description: >- + Checks that each argument in a multi-line method call + starts on a separate line. + Enabled: false + VersionAdded: '0.67' + Layout/MultilineMethodCallBraceLayout: Description: >- Checks that the closing brace in a method call is @@ -876,6 +1050,35 @@ Layout/MultilineOperationIndentation: # But it can be overridden by setting this parameter IndentationWidth: ~ +Layout/ParameterAlignment: + Description: >- + Align the parameters of a method definition if they span more + than one line. + StyleGuide: '#no-double-indent' + Enabled: true + VersionAdded: '0.49' + VersionChanged: '0.77' + # Alignment of parameters in multi-line method calls. + # + # The `with_first_parameter` style aligns the following lines along the same + # column as the first parameter. + # + # def method_foo(a, + # b) + # + # The `with_fixed_indentation` style aligns the following lines with one + # level of indentation relative to the start of the line with the method call. + # + # def method_foo(a, + # b) + EnforcedStyle: with_first_parameter + SupportedStyles: + - with_first_parameter + - with_fixed_indentation + # By default, the indentation width from Layout/IndentationWidth is used + # But it can be overridden by setting this parameter + IndentationWidth: ~ + Layout/RescueEnsureAlignment: Description: 'Align rescues and ensures correctly.' Enabled: true @@ -940,6 +1143,11 @@ Layout/SpaceAroundKeyword: Enabled: true VersionAdded: '0.49' +Layout/SpaceAroundMethodCallOperator: + Description: 'Checks method call operators to not have spaces around them.' + Enabled: pending + VersionAdded: '0.82' + Layout/SpaceAroundOperators: Description: 'Use a single space around operators.' StyleGuide: '#spaces-operators' @@ -949,6 +1157,10 @@ Layout/SpaceAroundOperators: # with an operator on the previous or next line, not counting empty lines # or comment lines. AllowForAlignment: true + EnforcedStyleForExponentOperator: no_space + SupportedStylesForExponentOperator: + - space + - no_space Layout/SpaceBeforeBlockBraces: Description: >- @@ -1044,7 +1256,7 @@ Layout/SpaceInsideBlockBraces: Layout/SpaceInsideHashLiteralBraces: Description: "Use spaces inside hash literal braces - or don't." - StyleGuide: '#spaces-operators' + StyleGuide: '#spaces-braces' Enabled: true VersionAdded: '0.49' EnforcedStyle: space @@ -1106,23 +1318,12 @@ Layout/SpaceInsideStringInterpolation: - space - no_space -Layout/Tab: - Description: 'No hard tabs.' - StyleGuide: '#spaces-indentation' - Enabled: true - VersionAdded: '0.49' - VersionChanged: '0.51' - # By default, the indentation width from Layout/IndentationWidth is used - # But it can be overridden by setting this parameter - # It is used during auto-correction to determine how many spaces should - # replace each tab. - IndentationWidth: ~ - -Layout/TrailingBlankLines: +Layout/TrailingEmptyLines: Description: 'Checks trailing blank lines and final newline.' StyleGuide: '#newline-eof' Enabled: true VersionAdded: '0.49' + VersionChanged: '0.77' EnforcedStyle: final_newline SupportedStyles: - final_newline @@ -1133,8 +1334,8 @@ Layout/TrailingWhitespace: StyleGuide: '#no-trailing-whitespace' Enabled: true VersionAdded: '0.49' - VersionChanged: '0.55' - AllowInHeredoc: false + VersionChanged: '0.83' + AllowInHeredoc: true #################### Lint ################################## ### Warnings @@ -1154,6 +1355,7 @@ Lint/AmbiguousOperator: StyleGuide: '#method-invocation-parens' Enabled: true VersionAdded: '0.17' + VersionChanged: '0.83' Lint/AmbiguousRegexpLiteral: Description: >- @@ -1161,6 +1363,7 @@ Lint/AmbiguousRegexpLiteral: a method invocation without parentheses. Enabled: true VersionAdded: '0.17' + VersionChanged: '0.83' Lint/AssignmentInCondition: Description: "Don't use assignment in conditions." @@ -1174,16 +1377,39 @@ Lint/BigDecimalNew: Enabled: true VersionAdded: '0.53' +Lint/BinaryOperatorWithIdenticalOperands: + Description: 'This cop checks for places where binary operator has identical operands.' + Enabled: pending + Safe: false + VersionAdded: '0.89' + Lint/BooleanSymbol: Description: 'Check for `:true` and `:false` symbols.' Enabled: true + Safe: false VersionAdded: '0.50' + VersionChanged: '0.83' Lint/CircularArgumentReference: Description: "Default values in optional keyword arguments and optional ordinal arguments should not refer back to the name of the argument." Enabled: true VersionAdded: '0.33' +Lint/ConstantDefinitionInBlock: + Description: 'Do not define constants within a block.' + StyleGuide: '#no-constant-definition-in-block' + Enabled: pending + VersionAdded: '0.91' + +Lint/ConstantResolution: + Description: 'Check that constants are fully qualified with `::`.' + Enabled: false + VersionAdded: '0.86' + # Restrict this cop to only looking at certain names + Only: [] + # Restrict this cop from only looking at certain names + Ignore: [] + Lint/Debugger: Description: 'Check for debugger calls.' Enabled: true @@ -1195,26 +1421,48 @@ Lint/DeprecatedClassMethods: Enabled: true VersionAdded: '0.19' +Lint/DeprecatedOpenSSLConstant: + Description: "Don't use algorithm constants for `OpenSSL::Cipher` and `OpenSSL::Digest`." + Enabled: pending + VersionAdded: '0.84' + Lint/DisjunctiveAssignmentInConstructor: Description: 'In constructor, plain assignment is preferred over disjunctive.' Enabled: true Safe: false VersionAdded: '0.62' + VersionChanged: '0.88' Lint/DuplicateCaseCondition: Description: 'Do not repeat values in case conditionals.' Enabled: true VersionAdded: '0.45' +Lint/DuplicateElsifCondition: + Description: 'Do not repeat conditions used in if `elsif`.' + Enabled: 'pending' + VersionAdded: '0.88' + +Lint/DuplicateHashKey: + Description: 'Check for duplicate keys in hash literals.' + Enabled: true + VersionAdded: '0.34' + VersionChanged: '0.77' + Lint/DuplicateMethods: Description: 'Check for duplicate method definitions.' Enabled: true VersionAdded: '0.29' -Lint/DuplicatedKey: - Description: 'Check for duplicate keys in hash literals.' - Enabled: true - VersionAdded: '0.34' +Lint/DuplicateRequire: + Description: 'Check for duplicate `require`s and `require_relative`s.' + Enabled: pending + VersionAdded: '0.90' + +Lint/DuplicateRescueException: + Description: 'Checks that there are no repeated exceptions used in `rescue` expressions.' + Enabled: pending + VersionAdded: '0.89' Lint/EachWithObjectArgument: Description: 'Check for immutable argument given to each_with_object.' @@ -1226,18 +1474,29 @@ Lint/ElseLayout: Enabled: true VersionAdded: '0.17' +Lint/EmptyConditionalBody: + Description: 'This cop checks for the presence of `if`, `elsif` and `unless` branches without a body.' + Enabled: 'pending' + AllowComments: true + VersionAdded: '0.89' + Lint/EmptyEnsure: Description: 'Checks for empty ensure block.' Enabled: true VersionAdded: '0.10' VersionChanged: '0.48' - AutoCorrect: false Lint/EmptyExpression: Description: 'Checks for empty expressions.' Enabled: true VersionAdded: '0.45' +Lint/EmptyFile: + Description: 'Enforces that Ruby source files are not empty.' + Enabled: pending + AllowComments: true + VersionAdded: '0.90' + Lint/EmptyInterpolation: Description: 'Checks for empty string interpolation.' Enabled: true @@ -1247,18 +1506,16 @@ Lint/EmptyInterpolation: Lint/EmptyWhen: Description: 'Checks for `when` branches with empty bodies.' Enabled: true + AllowComments: true VersionAdded: '0.45' - -Lint/EndInMethod: - Description: 'END blocks should not be placed inside method definitions.' - Enabled: true - VersionAdded: '0.9' + VersionChanged: '0.83' Lint/EnsureReturn: Description: 'Do not use return in an ensure block.' StyleGuide: '#no-return-ensure' Enabled: true VersionAdded: '0.9' + VersionChanged: '0.83' Lint/ErbNewArguments: Description: 'Use `:trim_mode` and `:eoutvar` keyword arguments to `ERB.new`.' @@ -1266,11 +1523,17 @@ Lint/ErbNewArguments: VersionAdded: '0.56' Lint/FlipFlop: - Description: 'Checks for flip-flops' + Description: 'Checks for flip-flops.' StyleGuide: '#no-flip-flops' Enabled: true VersionAdded: '0.16' +Lint/FloatComparison: + Description: 'Checks for the presence of precise comparison of floating point numbers.' + StyleGuide: '#float-comparison' + Enabled: pending + VersionAdded: '0.89' + Lint/FloatOutOfRange: Description: >- Catches floating-point literals too large or small for Ruby to @@ -1283,11 +1546,26 @@ Lint/FormatParameterMismatch: Enabled: true VersionAdded: '0.33' -Lint/HandleExceptions: - Description: "Don't suppress exception." - StyleGuide: '#dont-hide-exceptions' - Enabled: true - VersionAdded: '0.9' +Lint/HashCompareByIdentity: + Description: 'Prefer using `Hash#compare_by_identity` than using `object_id` for keys.' + StyleGuide: '#identity-comparison' + Enabled: pending + Safe: false + VersionAdded: '0.93' + +Lint/HeredocMethodCallPosition: + Description: >- + Checks for the ordering of a method call where + the receiver of the call is a HEREDOC. + Enabled: false + StyleGuide: '#heredoc-method-calls' + VersionAdded: '0.68' + +Lint/IdentityComparison: + Description: 'Prefer `equal?` over `==` when comparing `object_id`.' + Enabled: pending + StyleGuide: '#identity-comparison' + VersionAdded: '0.91' Lint/ImplicitStringConcatenation: Description: >- @@ -1314,9 +1592,11 @@ Lint/InheritException: - standard_error Lint/InterpolationCheck: - Description: 'Raise warning for interpolation in single q strs' + Description: 'Raise warning for interpolation in single q strs.' Enabled: true + Safe: false VersionAdded: '0.50' + VersionChanged: '0.87' Lint/LiteralAsCondition: Description: 'Checks of literals used in conditions.' @@ -1336,9 +1616,10 @@ Lint/Loop: StyleGuide: '#loop-with-break' Enabled: true VersionAdded: '0.9' + VersionChanged: '0.89' Lint/MissingCopEnableDirective: - Description: 'Checks for a `# rubocop:enable` after `# rubocop:disable`' + Description: 'Checks for a `# rubocop:enable` after `# rubocop:disable`.' Enabled: true VersionAdded: '0.52' # Maximum number of consecutive lines the cop can be disabled for. @@ -1350,10 +1631,23 @@ Lint/MissingCopEnableDirective: # .inf for any size MaximumRangeSize: .inf -Lint/MultipleCompare: - Description: "Use `&&` operator to compare multiple value." +Lint/MissingSuper: + Description: >- + This cop checks for the presence of constructors and lifecycle callbacks + without calls to `super`'. + Enabled: pending + VersionAdded: '0.89' + +Lint/MixedRegexpCaptureTypes: + Description: 'Do not mix named captures and numbered captures in a Regexp literal.' + Enabled: pending + VersionAdded: '0.85' + +Lint/MultipleComparison: + Description: "Use `&&` operator to compare multiple values." Enabled: true VersionAdded: '0.47' + VersionChanged: '0.77' Lint/NestedMethodDefinition: Description: 'Do not use nested method definitions.' @@ -1373,6 +1667,12 @@ Lint/NextWithoutAccumulator: Enabled: true VersionAdded: '0.36' +Lint/NonDeterministicRequireOrder: + Description: 'Always sort arrays returned by Dir.glob when requiring files.' + Enabled: true + VersionAdded: '0.78' + Safe: false + Lint/NonLocalExitFromIterator: Description: 'Do not use return in iterator to cause non-local exit.' Enabled: true @@ -1382,12 +1682,20 @@ Lint/NumberConversion: Description: 'Checks unsafe usage of number conversion methods.' Enabled: false VersionAdded: '0.53' + VersionChanged: '0.70' + SafeAutoCorrect: false Lint/OrderedMagicComments: Description: 'Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang.' Enabled: true VersionAdded: '0.53' +Lint/OutOfRangeRegexpRef: + Description: 'Checks for out of range reference for Regexp because it always returns nil.' + Enabled: pending + Safe: false + VersionAdded: '0.89' + Lint/ParenthesesAsGroupedExpression: Description: >- Checks for method calls with a space before the opening @@ -1395,11 +1703,13 @@ Lint/ParenthesesAsGroupedExpression: StyleGuide: '#parens-no-spaces' Enabled: true VersionAdded: '0.12' + VersionChanged: '0.83' Lint/PercentStringArray: Description: >- Checks for unwanted commas and quotes in %w/%W literals. Enabled: true + Safe: false VersionAdded: '0.41' Lint/PercentSymbolArray: @@ -1408,6 +1718,16 @@ Lint/PercentSymbolArray: Enabled: true VersionAdded: '0.41' +Lint/RaiseException: + Description: Checks for `raise` or `fail` statements which are raising `Exception` class. + StyleGuide: '#raise-exception' + Enabled: pending + Safe: false + VersionAdded: '0.81' + VersionChanged: '0.86' + AllowedImplicitNamespaces: + - 'Gem' + Lint/RandOne: Description: >- Checks for `rand(1)` calls. Such calls always return `0` @@ -1415,6 +1735,49 @@ Lint/RandOne: Enabled: true VersionAdded: '0.36' +Lint/RedundantCopDisableDirective: + Description: >- + Checks for rubocop:disable comments that can be removed. + Note: this cop is not disabled when disabling all cops. + It must be explicitly disabled. + Enabled: true + VersionAdded: '0.76' + +Lint/RedundantCopEnableDirective: + Description: Checks for rubocop:enable comments that can be removed. + Enabled: true + VersionAdded: '0.76' + +Lint/RedundantRequireStatement: + Description: 'Checks for unnecessary `require` statement.' + Enabled: true + VersionAdded: '0.76' + +Lint/RedundantSafeNavigation: + Description: 'Checks for redundant safe navigation calls.' + Enabled: pending + VersionAdded: '0.93' + AllowedMethods: + - instance_of? + - kind_of? + - is_a? + - eql? + - respond_to? + - equal? + Safe: false + +Lint/RedundantSplatExpansion: + Description: 'Checks for splat unnecessarily being called on literals.' + Enabled: true + VersionAdded: '0.76' + +Lint/RedundantStringCoercion: + Description: 'Checks for Object#to_s usage in string interpolation.' + StyleGuide: '#no-to-s' + Enabled: true + VersionAdded: '0.19' + VersionChanged: '0.77' + Lint/RedundantWithIndex: Description: 'Checks for redundant `with_index`.' Enabled: true @@ -1431,6 +1794,7 @@ Lint/RegexpAsCondition: The regexp literal matches `$_` implicitly. Enabled: true VersionAdded: '0.51' + VersionChanged: '0.86' Lint/RequireParentheses: Description: >- @@ -1460,13 +1824,14 @@ Lint/SafeNavigationChain: Description: 'Do not chain ordinary method call after safe navigation operator.' Enabled: true VersionAdded: '0.47' - VersionChanged: '0.56' - Whitelist: + VersionChanged: '0.77' + AllowedMethods: - present? - blank? - presence - try - try! + - in? Lint/SafeNavigationConsistency: Description: >- @@ -1475,18 +1840,19 @@ Lint/SafeNavigationConsistency: for all method calls on that same object. Enabled: true VersionAdded: '0.55' - Whitelist: + VersionChanged: '0.77' + AllowedMethods: - present? - blank? - presence - try - try! - Lint/SafeNavigationWithEmpty: Description: 'Avoid `foo&.empty?` in conditionals.' Enabled: true VersionAdded: '0.62' + VersionChanged: '0.87' Lint/ScriptPermission: Description: 'Grant script file execute permission.' @@ -1494,6 +1860,16 @@ Lint/ScriptPermission: VersionAdded: '0.49' VersionChanged: '0.50' +Lint/SelfAssignment: + Description: 'Checks for self-assignments.' + Enabled: pending + VersionAdded: '0.89' + +Lint/SendWithMixinArgument: + Description: 'Checks for `send` method when using mixin.' + Enabled: true + VersionAdded: '0.75' + Lint/ShadowedArgument: Description: 'Avoid reassigning arguments before they were used.' Enabled: true @@ -1515,15 +1891,21 @@ Lint/ShadowingOuterLocalVariable: Enabled: true VersionAdded: '0.9' -Lint/StringConversionInInterpolation: - Description: 'Checks for Object#to_s usage in string interpolation.' - StyleGuide: '#no-to-s' +Lint/StructNewOverride: + Description: 'Disallow overriding the `Struct` built-in methods via `Struct.new`.' + Enabled: pending + VersionAdded: '0.81' + +Lint/SuppressedException: + Description: "Don't suppress exceptions." + StyleGuide: '#dont-hide-exceptions' Enabled: true - VersionAdded: '0.19' - VersionChanged: '0.20' + AllowComments: true + VersionAdded: '0.9' + VersionChanged: '0.81' Lint/Syntax: - Description: 'Checks syntax error' + Description: 'Checks syntax error.' Enabled: true VersionAdded: '0.9' @@ -1531,37 +1913,26 @@ Lint/Syntax: Lint/ToJSON: Description: 'Ensure #to_json includes an optional argument.' Enabled: true + VersionAdded: '0.66' + +Lint/TopLevelReturnWithArgument: + Description: 'This cop detects top level return statements with argument.' + Enabled: 'pending' + VersionAdded: '0.89' + +Lint/TrailingCommaInAttributeDeclaration: + Description: 'This cop checks for trailing commas in attribute declarations.' + Enabled: pending + VersionAdded: '0.90' Lint/UnderscorePrefixedVariableName: Description: 'Do not use prefix `_` for a variable that is used.' Enabled: true VersionAdded: '0.21' + AllowKeywordBlockArguments: false Lint/UnifiedInteger: - Description: 'Use Integer instead of Fixnum or Bignum' - Enabled: true - VersionAdded: '0.43' - -Lint/UnneededCopDisableDirective: - Description: >- - Checks for rubocop:disable comments that can be removed. - Note: this cop is not disabled when disabling all cops. - It must be explicitly disabled. - Enabled: true - VersionAdded: '0.53' - -Lint/UnneededCopEnableDirective: - Description: Checks for rubocop:enable comments that can be removed. - Enabled: true - VersionAdded: '0.53' - -Lint/UnneededRequireStatement: - Description: 'Checks for unnecessary `require` statement.' - Enabled: true - VersionAdded: '0.51' - -Lint/UnneededSplatExpansion: - Description: 'Checks for splat unnecessarily being called on literals' + Description: 'Use Integer instead of Fixnum or Bignum.' Enabled: true VersionAdded: '0.43' @@ -1570,6 +1941,11 @@ Lint/UnreachableCode: Enabled: true VersionAdded: '0.9' +Lint/UnreachableLoop: + Description: 'This cop checks for loops that will have at most one iteration.' + Enabled: pending + VersionAdded: '0.89' + Lint/UnusedBlockArgument: Description: 'Checks for unused block arguments.' StyleGuide: '#underscore-unused-vars' @@ -1584,9 +1960,10 @@ Lint/UnusedMethodArgument: StyleGuide: '#underscore-unused-vars' Enabled: true VersionAdded: '0.21' - VersionChanged: '0.35' + VersionChanged: '0.81' AllowUnusedKeywordArguments: false IgnoreEmptyMethods: true + IgnoreNotImplementedMethods: true Lint/UriEscapeUnescape: Description: >- @@ -1608,7 +1985,7 @@ Lint/UselessAccessModifier: Description: 'Checks for useless access modifiers.' Enabled: true VersionAdded: '0.20' - VersionChanged: '0.47' + VersionChanged: '0.83' ContextCreatingMethods: [] MethodCreatingMethods: [] @@ -1618,20 +1995,30 @@ Lint/UselessAssignment: Enabled: true VersionAdded: '0.11' -Lint/UselessComparison: - Description: 'Checks for comparison of something with itself.' - Enabled: true - VersionAdded: '0.11' - Lint/UselessElseWithoutRescue: Description: 'Checks for useless `else` in `begin..end` without `rescue`.' Enabled: true VersionAdded: '0.17' +Lint/UselessMethodDefinition: + Description: 'Checks for useless method definitions.' + Enabled: pending + VersionAdded: '0.90' + Safe: false + AllowComments: true + Lint/UselessSetterCall: Description: 'Checks for useless setter call to a local variable.' Enabled: true VersionAdded: '0.13' + VersionChanged: '0.80' + Safe: false + +Lint/UselessTimes: + Description: 'Checks for useless `Integer#times` calls.' + Enabled: pending + VersionAdded: '0.91' + Safe: false Lint/Void: Description: 'Possible use of operator/literal/variable in void context.' @@ -1647,21 +2034,23 @@ Metrics/AbcSize: branches, and conditions. Reference: - http://c2.com/cgi/wiki?AbcMetric - - https://en.wikipedia.org/wiki/ABC_Software_Metric' + - https://en.wikipedia.org/wiki/ABC_Software_Metric Enabled: true VersionAdded: '0.27' - VersionChanged: '0.66' + VersionChanged: '0.81' # The ABC size is a calculated magnitude, so this number can be an Integer or # a Float. - Max: 15 + IgnoredMethods: [] + Max: 17 Metrics/BlockLength: Description: 'Avoid long blocks with many lines.' Enabled: true VersionAdded: '0.44' - VersionChanged: '0.66' + VersionChanged: '0.87' CountComments: false # count full line comments? Max: 25 + CountAsOne: [] ExcludedMethods: # By default, exclude the `#refine` method, as it tends to have larger # associated blocks. @@ -1670,7 +2059,7 @@ Metrics/BlockLength: - '**/*.gemspec' Metrics/BlockNesting: - Description: 'Avoid excessive block nesting' + Description: 'Avoid excessive block nesting.' StyleGuide: '#three-is-the-number-thou-shalt-count' Enabled: true VersionAdded: '0.25' @@ -1682,8 +2071,10 @@ Metrics/ClassLength: Description: 'Avoid classes longer than 100 lines of code.' Enabled: true VersionAdded: '0.25' + VersionChanged: '0.87' CountComments: false # count full line comments? Max: 100 + CountAsOne: [] # Avoid complex methods. Metrics/CyclomaticComplexity: @@ -1692,46 +2083,29 @@ Metrics/CyclomaticComplexity: of test cases needed to validate a method. Enabled: true VersionAdded: '0.25' - Max: 6 - -Metrics/LineLength: - Description: 'Limit lines to 80 characters.' - StyleGuide: '#80-character-limits' - Enabled: true - VersionAdded: '0.25' - VersionChanged: '0.46' - Max: 80 - # To make it possible to copy or click on URIs in the code, we allow lines - # containing a URI to be longer than Max. - AllowHeredoc: true - AllowURI: true - URISchemes: - - http - - https - # The IgnoreCopDirectives option causes the LineLength rule to ignore cop - # directives like '# rubocop: enable ...' when calculating a line's length. - IgnoreCopDirectives: false - # The IgnoredPatterns option is a list of !ruby/regexp and/or string - # elements. Strings will be converted to Regexp objects. A line that matches - # any regular expression listed in this option will be ignored by LineLength. - IgnoredPatterns: [] + VersionChanged: '0.81' + IgnoredMethods: [] + Max: 7 Metrics/MethodLength: Description: 'Avoid methods longer than 10 lines of code.' StyleGuide: '#short-methods' Enabled: true VersionAdded: '0.25' - VersionChanged: '0.59.2' + VersionChanged: '0.87' CountComments: false # count full line comments? Max: 10 + CountAsOne: [] ExcludedMethods: [] Metrics/ModuleLength: Description: 'Avoid modules longer than 100 lines of code.' Enabled: true VersionAdded: '0.31' + VersionChanged: '0.87' CountComments: false # count full line comments? Max: 100 + CountAsOne: [] Metrics/ParameterLists: Description: 'Avoid parameter lists longer than three or four parameters.' @@ -1747,7 +2121,18 @@ Metrics/PerceivedComplexity: human reader. Enabled: true VersionAdded: '0.25' - Max: 7 + VersionChanged: '0.81' + IgnoredMethods: [] + Max: 8 + +################## Migration ############################# + +Migration/DepartmentName: + Description: >- + Check that cop names in rubocop:disable (etc) comments are + given with department name. + Enabled: true + VersionAdded: '0.75' #################### Naming ############################## @@ -1758,10 +2143,12 @@ Naming/AccessorMethodName: VersionAdded: '0.50' Naming/AsciiIdentifiers: - Description: 'Use only ascii symbols in identifiers.' + Description: 'Use only ascii symbols in identifiers and constants.' StyleGuide: '#english-identifiers' Enabled: true VersionAdded: '0.50' + VersionChanged: '0.87' + AsciiConstants: true Naming/BinaryOperatorParameterName: Description: 'When defining binary operators, name the argument other.' @@ -1769,11 +2156,31 @@ Naming/BinaryOperatorParameterName: Enabled: true VersionAdded: '0.50' +Naming/BlockParameterName: + Description: >- + Checks for block parameter names that contain capital letters, + end in numbers, or do not meet a minimal length. + Enabled: true + VersionAdded: '0.53' + VersionChanged: '0.77' + # Parameter names may be equal to or greater than this value + MinNameLength: 1 + AllowNamesEndingInNumbers: true + # Allowed names that will not register an offense + AllowedNames: [] + # Forbidden names that will register an offense + ForbiddenNames: [] + Naming/ClassAndModuleCamelCase: Description: 'Use CamelCase for classes and modules.' StyleGuide: '#camelcase-classes' Enabled: true VersionAdded: '0.50' + VersionChanged: '0.85' + # Allowed class/module names can be specified here. + # These can be full or part of the name. + AllowedNames: + - module_parent Naming/ConstantName: Description: 'Constants should use SCREAMING_SNAKE_CASE.' @@ -1794,6 +2201,10 @@ Naming/FileName: # It further expects it to be nested inside modules which match the names # of subdirectories in its path. ExpectMatchingDefinition: false + # When `false`, changes the behavior of ExpectMatchingDefinition to match only + # whether each source file's class or module name matches the file name -- + # not whether the nested module hierarchy matches the subdirectory path. + CheckDefinitionPathHierarchy: true # If non-`nil`, expect all source file names to match the following regex. # Only the file name itself is matched, not the entire file path. # Use anchors as necessary if you want to match the entire name rather than @@ -1860,7 +2271,7 @@ Naming/HeredocDelimiterNaming: StyleGuide: '#heredoc-delimiters' Enabled: true VersionAdded: '0.50' - Blacklist: + ForbiddenDelimiters: - !ruby/regexp '/(^|\s)(EO[A-Z]{1}|END)(\s|$)/' Naming/MemoizedInstanceVariableName: @@ -1884,759 +2295,96 @@ Naming/MethodName: SupportedStyles: - snake_case - camelCase + # Method names matching patterns are always allowed. + # + # IgnoredPatterns: + # - '\A\s*onSelectionBulkChange\s*' + # - '\A\s*onSelectionCleared\s*' + # + IgnoredPatterns: [] -Naming/PredicateName: - Description: 'Check the names of predicate methods.' - StyleGuide: '#bool-methods-qmark' - Enabled: true - VersionAdded: '0.50' - VersionChanged: '0.51' - # Predicate name prefixes. - NamePrefix: - - is_ - - has_ - - have_ - # Predicate name prefixes that should be removed. - NamePrefixBlacklist: - - is_ - - has_ - - have_ - # Predicate names which, despite having a blacklisted prefix, or no `?`, - # should still be accepted - NameWhitelist: - - is_a? - # Method definition macros for dynamically generated methods. - MethodDefinitionMacros: - - define_method - - define_singleton_method - # Exclude Rspec specs because there is a strong convention to write spec - # helpers in the form of `have_something` or `be_something`. - Exclude: - - 'spec/**/*' - -Naming/UncommunicativeBlockParamName: - Description: >- - Checks for block parameter names that contain capital letters, - end in numbers, or do not meet a minimal length. - Enabled: true - VersionAdded: '0.53' - # Parameter names may be equal to or greater than this value - MinNameLength: 1 - AllowNamesEndingInNumbers: true - # Whitelisted names that will not register an offense - AllowedNames: [] - # Blacklisted names that will register an offense - ForbiddenNames: [] - -Naming/UncommunicativeMethodParamName: - Description: >- - Checks for method parameter names that contain capital letters, - end in numbers, or do not meet a minimal length. - Enabled: true - VersionAdded: '0.53' - VersionChanged: '0.59' - # Parameter names may be equal to or greater than this value - MinNameLength: 3 - AllowNamesEndingInNumbers: true - # Whitelisted names that will not register an offense - AllowedNames: - - io - - id - - to - - by - - 'on' - - in - - at - - ip - - db - # Blacklisted names that will register an offense - ForbiddenNames: [] - - -Naming/VariableName: - Description: 'Use the configured style when naming variables.' - StyleGuide: '#snake-case-symbols-methods-vars' - Enabled: true - VersionAdded: '0.50' - EnforcedStyle: snake_case - SupportedStyles: - - snake_case - - camelCase - -Naming/VariableNumber: - Description: 'Use the configured style when numbering variables.' - Enabled: true - VersionAdded: '0.50' - EnforcedStyle: normalcase - SupportedStyles: - - snake_case - - normalcase - - non_integer - -#################### Performance ########################### - -Performance/Caller: - Description: >- - Use `caller(n..n)` instead of `caller`. - Enabled: true - VersionAdded: '0.49' - -Performance/CaseWhenSplat: - Description: >- - Reordering `when` conditions with a splat to the end - of the `when` branches can improve performance. - Enabled: false - AutoCorrect: false - SafeAutoCorrect: false - VersionAdded: '0.34' - VersionChanged: '0.59' - -Performance/Casecmp: - Description: >- - Use `casecmp` rather than `downcase ==`, `upcase ==`, `== downcase`, or `== upcase`.. - Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringcasecmp-vs-stringdowncase---code' - Enabled: true - VersionAdded: '0.36' - -Performance/ChainArrayAllocation: - Description: >- - Instead of chaining array methods that allocate new arrays, mutate an - existing array. - Reference: 'https://twitter.com/schneems/status/1034123879978029057' - Enabled: false - VersionAdded: '0.59' - -Performance/CompareWithBlock: - Description: 'Use `sort_by(&:foo)` instead of `sort { |a, b| a.foo <=> b.foo }`.' - Enabled: true - VersionAdded: '0.46' - -Performance/Count: - Description: >- - Use `count` instead of `select...size`, `reject...size`, - `select...count`, `reject...count`, `select...length`, - and `reject...length`. - # This cop has known compatibility issues with `ActiveRecord` and other - # frameworks. ActiveRecord's `count` ignores the block that is passed to it. - # For more information, see the documentation in the cop itself. - # If you understand the known risk, you can disable `SafeMode`. - SafeMode: true - Enabled: true - VersionAdded: '0.31' - VersionChanged: '0.39' - -Performance/Detect: - Description: >- - Use `detect` instead of `select.first`, `find_all.first`, - `select.last`, and `find_all.last`. - Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerabledetect-vs-enumerableselectfirst-code' - # This cop has known compatibility issues with `ActiveRecord` and other - # frameworks. `ActiveRecord` does not implement a `detect` method and `find` - # has its own meaning. Correcting `ActiveRecord` methods with this cop - # should be considered unsafe. - SafeMode: true - Enabled: true - VersionAdded: '0.30' - VersionChanged: '0.39' - -Performance/DoubleStartEndWith: - Description: >- - Use `str.{start,end}_with?(x, ..., y, ...)` - instead of `str.{start,end}_with?(x, ...) || str.{start,end}_with?(y, ...)`. - Enabled: true - VersionAdded: '0.36' - VersionChanged: '0.48' - # Used to check for `starts_with?` and `ends_with?`. - # These methods are defined by `ActiveSupport`. - IncludeActiveSupportAliases: false - -Performance/EndWith: - Description: 'Use `end_with?` instead of a regex match anchored to the end of a string.' - Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringmatch-vs-stringstart_withstringend_with-code-start-code-end' - # This will change to a new method call which isn't guaranteed to be on the - # object. Switching these methods has to be done with knowledge of the types - # of the variables which rubocop doesn't have. - SafeAutoCorrect: false - AutoCorrect: false - Enabled: true - VersionAdded: '0.36' - VersionChanged: '0.44' - -Performance/FixedSize: - Description: 'Do not compute the size of statically sized objects except in constants' - Enabled: true - VersionAdded: '0.35' - -Performance/FlatMap: - Description: >- - Use `Enumerable#flat_map` - instead of `Enumerable#map...Array#flatten(1)` - or `Enumberable#collect..Array#flatten(1)` - Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablemaparrayflatten-vs-enumerableflat_map-code' - Enabled: true - VersionAdded: '0.30' - EnabledForFlattenWithoutParams: false - # If enabled, this cop will warn about usages of - # `flatten` being called without any parameters. - # This can be dangerous since `flat_map` will only flatten 1 level, and - # `flatten` without any parameters can flatten multiple levels. - -Performance/InefficientHashSearch: - Description: 'Use `key?` or `value?` instead of `keys.include?` or `values.include?`' - Reference: 'https://github.com/JuanitoFatas/fast-ruby#hashkey-instead-of-hashkeysinclude-code' - Enabled: true - VersionAdded: '0.56' - Safe: false - -Performance/LstripRstrip: - Description: 'Use `strip` instead of `lstrip.rstrip`.' - Enabled: true - VersionAdded: '0.36' - -Performance/OpenStruct: - Description: 'Use `Struct` instead of `OpenStruct`.' - Enabled: false - VersionAdded: '0.61' - Safe: false - -Performance/RangeInclude: - Description: 'Use `Range#cover?` instead of `Range#include?`.' - Reference: 'https://github.com/JuanitoFatas/fast-ruby#cover-vs-include-code' - Enabled: true - VersionAdded: '0.36' - Safe: false - -Performance/RedundantBlockCall: - Description: 'Use `yield` instead of `block.call`.' - Reference: 'https://github.com/JuanitoFatas/fast-ruby#proccall-and-block-arguments-vs-yieldcode' - Enabled: true - VersionAdded: '0.36' - -Performance/RedundantMatch: - Description: >- - Use `=~` instead of `String#match` or `Regexp#match` in a context where the - returned `MatchData` is not needed. - Enabled: true - VersionAdded: '0.36' - -Performance/RedundantMerge: - Description: 'Use Hash#[]=, rather than Hash#merge! with a single key-value pair.' - Reference: 'https://github.com/JuanitoFatas/fast-ruby#hashmerge-vs-hash-code' - Enabled: true - VersionAdded: '0.36' - # Max number of key-value pairs to consider an offense - MaxKeyValuePairs: 2 - -Performance/RedundantSortBy: - Description: 'Use `sort` instead of `sort_by { |x| x }`.' - Enabled: true - VersionAdded: '0.36' - -Performance/RegexpMatch: - Description: >- - Use `match?` instead of `Regexp#match`, `String#match`, `Symbol#match`, - `Regexp#===`, or `=~` when `MatchData` is not used. - Reference: 'https://github.com/JuanitoFatas/fast-ruby#regexp-vs-stringmatch-vs-string-vs-stringmatch-code-' - Enabled: true - VersionAdded: '0.47' - -Performance/ReverseEach: - Description: 'Use `reverse_each` instead of `reverse.each`.' - Reference: 'https://github.com/JuanitoFatas/fast-ruby#enumerablereverseeach-vs-enumerablereverse_each-code' - Enabled: true - VersionAdded: '0.30' - -Performance/Sample: - Description: >- - Use `sample` instead of `shuffle.first`, - `shuffle.last`, and `shuffle[Integer]`. - Reference: 'https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code' - Enabled: true - VersionAdded: '0.30' - -Performance/Size: - Description: >- - Use `size` instead of `count` for counting - the number of elements in `Array` and `Hash`. - Reference: 'https://github.com/JuanitoFatas/fast-ruby#arraylength-vs-arraysize-vs-arraycount-code' - Enabled: true - VersionAdded: '0.30' - -Performance/StartWith: - Description: 'Use `start_with?` instead of a regex match anchored to the beginning of a string.' - Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringmatch-vs-stringstart_withstringend_with-code-start-code-end' - # This will change to a new method call which isn't guaranteed to be on the - # object. Switching these methods has to be done with knowledge of the types - # of the variables which rubocop doesn't have. - SafeAutoCorrect: false - AutoCorrect: false - Enabled: true - VersionAdded: '0.36' - VersionChanged: '0.44' - -Performance/StringReplacement: - Description: >- - Use `tr` instead of `gsub` when you are replacing the same - number of characters. Use `delete` instead of `gsub` when - you are deleting characters. - Reference: 'https://github.com/JuanitoFatas/fast-ruby#stringgsub-vs-stringtr-code' - Enabled: true - VersionAdded: '0.33' - -Performance/TimesMap: - Description: 'Checks for .times.map calls.' - AutoCorrect: false - Enabled: true - VersionAdded: '0.36' - VersionChanged: '0.50' - SafeAutoCorrect: false # see https://github.com/rubocop-hq/rubocop/issues/4658 - -Performance/UnfreezeString: - Description: 'Use unary plus to get an unfrozen string literal.' - Enabled: true - VersionAdded: '0.50' - -Performance/UnneededSort: - Description: >- - Use `min` instead of `sort.first`, - `max_by` instead of `sort_by...last`, etc. - Enabled: true - VersionAdded: '0.55' - -Performance/UriDefaultParser: - Description: 'Use `URI::DEFAULT_PARSER` instead of `URI::Parser.new`.' - Enabled: true - VersionAdded: '0.50' - -#################### Rails ################################# - -# By default, the rails cops are not run. Override in project or home -# directory .rubocop.yml files, or by giving the -R/--rails option. -Rails: - Enabled: false - -Rails/ActionFilter: - Description: 'Enforces consistent use of action filter methods.' - Enabled: true - VersionAdded: '0.19' - EnforcedStyle: action - SupportedStyles: - - action - - filter - Include: - - app/controllers/**/*.rb - -Rails/ActiveRecordAliases: - Description: >- - Avoid Active Record aliases: - Use `update` instead of `update_attributes`. - Use `update!` instead of `update_attributes!`. - Enabled: true - VersionAdded: '0.53' - -Rails/ActiveSupportAliases: - Description: >- - Avoid ActiveSupport aliases of standard ruby methods: - `String#starts_with?`, `String#ends_with?`, - `Array#append`, `Array#prepend`. - Enabled: true - VersionAdded: '0.48' - -Rails/ApplicationJob: - Description: 'Check that jobs subclass ApplicationJob.' - Enabled: true - VersionAdded: '0.49' - -Rails/ApplicationRecord: - Description: 'Check that models subclass ApplicationRecord.' - Enabled: true - VersionAdded: '0.49' - -Rails/AssertNot: - Description: 'Use `assert_not` instead of `assert !`.' - Enabled: true - VersionAdded: '0.56' - Include: - - '**/test/**/*' - -Rails/BelongsTo: - Description: >- - Use `optional: true` instead of `required: false` for - `belongs_to` relations' - Enabled: true - VersionAdded: '0.62' - -Rails/Blank: - Description: 'Enforces use of `blank?`.' - Enabled: true - VersionAdded: '0.48' - # Convert usages of `nil? || empty?` to `blank?` - NilOrEmpty: true - # Convert usages of `!present?` to `blank?` - NotPresent: true - # Convert usages of `unless present?` to `if blank?` - UnlessPresent: true - -Rails/BulkChangeTable: - Description: 'Check whether alter queries are combinable.' - Enabled: true - VersionAdded: '0.57' - Database: null - SupportedDatabases: - - mysql - - postgresql - Include: - - db/migrate/*.rb - -Rails/CreateTableWithTimestamps: - Description: >- - Checks the migration for which timestamps are not included - when creating a new table. - Enabled: true - VersionAdded: '0.52' - Include: - - db/migrate/*.rb - -Rails/Date: - Description: >- - Checks the correct usage of date aware methods, - such as Date.today, Date.current etc. - Enabled: true - VersionAdded: '0.30' - VersionChanged: '0.33' - # The value `strict` disallows usage of `Date.today`, `Date.current`, - # `Date#to_time` etc. - # The value `flexible` allows usage of `Date.current`, `Date.yesterday`, etc - # (but not `Date.today`) which are overridden by ActiveSupport to handle current - # time zone. - EnforcedStyle: flexible - SupportedStyles: - - strict - - flexible - -Rails/Delegate: - Description: 'Prefer delegate method for delegations.' - Enabled: true - VersionAdded: '0.21' - VersionChanged: '0.50' - # When set to true, using the target object as a prefix of the - # method name without using the `delegate` method will be a - # violation. When set to false, this case is legal. - EnforceForPrefixed: true - -Rails/DelegateAllowBlank: - Description: 'Do not use allow_blank as an option to delegate.' - Enabled: true - VersionAdded: '0.44' - -Rails/DynamicFindBy: - Description: 'Use `find_by` instead of dynamic `find_by_*`.' - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#find_by' - Enabled: true - VersionAdded: '0.44' - Whitelist: - - find_by_sql - -Rails/EnumUniqueness: - Description: 'Avoid duplicate integers in hash-syntax `enum` declaration.' - Enabled: true - VersionAdded: '0.46' - Include: - - app/models/**/*.rb - -Rails/EnvironmentComparison: - Description: "Favor `Rails.env.production?` over `Rails.env == 'production'`" - Enabled: true - VersionAdded: '0.52' - -Rails/Exit: - Description: >- - Favor `fail`, `break`, `return`, etc. over `exit` in - application or library code outside of Rake files to avoid - exits during unit testing or running in production. - Enabled: true - VersionAdded: '0.41' - Include: - - app/**/*.rb - - config/**/*.rb - - lib/**/*.rb - Exclude: - - lib/**/*.rake - -Rails/FilePath: - Description: 'Use `Rails.root.join` for file path joining.' - Enabled: true - VersionAdded: '0.47' - VersionChanged: '0.57' - EnforcedStyle: arguments - SupportedStyles: - - slashes - - arguments - -Rails/FindBy: - Description: 'Prefer find_by over where.first.' - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#find_by' - Enabled: true - VersionAdded: '0.30' - Include: - - app/models/**/*.rb - -Rails/FindEach: - Description: 'Prefer all.find_each over all.find.' - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#find-each' - Enabled: true - VersionAdded: '0.30' - Include: - - app/models/**/*.rb - -Rails/HasAndBelongsToMany: - Description: 'Prefer has_many :through to has_and_belongs_to_many.' - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#has-many-through' - Enabled: true - VersionAdded: '0.12' - Include: - - app/models/**/*.rb - -Rails/HasManyOrHasOneDependent: - Description: 'Define the dependent option to the has_many and has_one associations.' - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#has_many-has_one-dependent-option' - Enabled: true - VersionAdded: '0.50' - Include: - - app/models/**/*.rb - -Rails/HttpPositionalArguments: - Description: 'Use keyword arguments instead of positional arguments in http method calls.' - Enabled: true - VersionAdded: '0.44' - Include: - - 'spec/**/*' - - 'test/**/*' - -Rails/HttpStatus: - Description: 'Enforces use of symbolic or numeric value to define HTTP status.' - Enabled: true - VersionAdded: '0.54' - EnforcedStyle: symbolic - SupportedStyles: - - numeric - - symbolic - -Rails/IgnoredSkipActionFilterOption: - Description: 'Checks that `if` and `only` (or `except`) are not used together as options of `skip_*` action filter.' - Reference: 'https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options' - Enabled: true - VersionAdded: '0.63' - Include: - - app/controllers/**/*.rb - -Rails/InverseOf: - Description: 'Checks for associations where the inverse cannot be determined automatically.' - Enabled: true - VersionAdded: '0.52' - Include: - - app/models/**/*.rb - -Rails/LexicallyScopedActionFilter: - Description: "Checks that methods specified in the filter's `only` or `except` options are explicitly defined in the controller." - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#lexically-scoped-action-filter' - Enabled: true - VersionAdded: '0.52' - Include: - - app/controllers/**/*.rb - -Rails/LinkToBlank: - Description: 'Checks that `link_to` with a `target: "_blank"` have a `rel: "noopener"` option passed to them.' - Reference: https://mathiasbynens.github.io/rel-noopener/ - Enabled: true - VersionAdded: '0.62' - -Rails/NotNullColumn: - Description: 'Do not add a NOT NULL column without a default value' - Enabled: true - VersionAdded: '0.43' - Include: - - db/migrate/*.rb - -Rails/Output: - Description: 'Checks for calls to puts, print, etc.' - Enabled: true - VersionAdded: '0.15' - VersionChanged: '0.19' - Include: - - app/**/*.rb - - config/**/*.rb - - db/**/*.rb - - lib/**/*.rb - -Rails/OutputSafety: - Description: 'The use of `html_safe` or `raw` may be a security risk.' - Enabled: true - VersionAdded: '0.41' - -Rails/PluralizationGrammar: - Description: 'Checks for incorrect grammar when using methods like `3.day.ago`.' - Enabled: true - VersionAdded: '0.35' - -Rails/Presence: - Description: 'Checks code that can be written more easily using `Object#presence` defined by Active Support.' - Enabled: true - VersionAdded: '0.52' - -Rails/Present: - Description: 'Enforces use of `present?`.' - Enabled: true - VersionAdded: '0.48' - # Convert usages of `!nil? && !empty?` to `present?` - NotNilAndNotEmpty: true - # Convert usages of `!blank?` to `present?` - NotBlank: true - # Convert usages of `unless blank?` to `if present?` - UnlessBlank: true - -Rails/ReadWriteAttribute: - Description: >- - Checks for read_attribute(:attr) and - write_attribute(:attr, val). - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#read-attribute' - Enabled: true - VersionAdded: '0.20' - VersionChanged: '0.29' - Include: - - app/models/**/*.rb - -Rails/RedundantReceiverInWithOptions: - Description: 'Checks for redundant receiver in `with_options`.' - Enabled: true - VersionAdded: '0.52' - -Rails/ReflectionClassName: - Description: 'Use a string for `class_name` option value in the definition of a reflection.' - Enabled: true - VersionAdded: '0.64' - -Rails/RefuteMethods: - Description: 'Use `assert_not` methods instead of `refute` methods.' - Enabled: true - VersionAdded: '0.56' - Include: - - '**/test/**/*' - -Rails/RelativeDateConstant: - Description: 'Do not assign relative date to constants.' - Enabled: true - VersionAdded: '0.48' - VersionChanged: '0.59' - AutoCorrect: false - -Rails/RequestReferer: - Description: 'Use consistent syntax for request.referer.' - Enabled: true - VersionAdded: '0.41' - EnforcedStyle: referer - SupportedStyles: - - referer - - referrer - -Rails/ReversibleMigration: - Description: 'Checks whether the change method of the migration file is reversible.' - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#reversible-migration' - Reference: 'https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html' - Enabled: true - VersionAdded: '0.47' - Include: - - db/migrate/*.rb - -Rails/SafeNavigation: - Description: "Use Ruby's safe navigation operator (`&.`) instead of `try!`" - Enabled: true - VersionAdded: '0.43' - # This will convert usages of `try` to use safe navigation as well as `try!`. - # `try` and `try!` work slightly differently. `try!` and safe navigation will - # both raise a `NoMethodError` if the receiver of the method call does not - # implement the intended method. `try` will not raise an exception for this. - ConvertTry: false - -Rails/SaveBang: - Description: 'Identifies possible cases where Active Record save! or related should be used.' - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#save-bang' - Enabled: false - VersionAdded: '0.42' - VersionChanged: '0.59' - AllowImplicitReturn: true - AllowedReceivers: [] - -Rails/ScopeArgs: - Description: 'Checks the arguments of ActiveRecord scopes.' - Enabled: true - VersionAdded: '0.19' - Include: - - app/models/**/*.rb - -Rails/SkipsModelValidations: +Naming/MethodParameterName: Description: >- - Use methods that skips model validations with caution. - See reference for more information. - Reference: 'https://guides.rubyonrails.org/active_record_validations.html#skipping-validations' + Checks for method parameter names that contain capital letters, + end in numbers, or do not meet a minimal length. Enabled: true - VersionAdded: '0.47' - VersionChanged: '0.60' - Blacklist: - - decrement! - - decrement_counter - - increment! - - increment_counter - - toggle! - - touch - - update_all - - update_attribute - - update_column - - update_columns - - update_counters - Whitelist: [] - -Rails/TimeZone: - Description: 'Checks the correct usage of time zone aware methods.' - StyleGuide: 'https://github.com/rubocop-hq/rails-style-guide#time' - Reference: 'http://danilenko.org/2012/7/6/rails_timezones' + VersionAdded: '0.53' + VersionChanged: '0.77' + # Parameter names may be equal to or greater than this value + MinNameLength: 3 + AllowNamesEndingInNumbers: true + # Allowed names that will not register an offense + AllowedNames: + - at + - by + - db + - id + - in + - io + - ip + - of + - 'on' + - os + - pp + - to + # Forbidden names that will register an offense + ForbiddenNames: [] + +Naming/PredicateName: + Description: 'Check the names of predicate methods.' + StyleGuide: '#bool-methods-qmark' Enabled: true - VersionAdded: '0.30' - VersionChanged: '0.33' - # The value `strict` means that `Time` should be used with `zone`. - # The value `flexible` allows usage of `in_time_zone` instead of `zone`. - EnforcedStyle: flexible - SupportedStyles: - - strict - - flexible + VersionAdded: '0.50' + VersionChanged: '0.77' + # Predicate name prefixes. + NamePrefix: + - is_ + - has_ + - have_ + # Predicate name prefixes that should be removed. + ForbiddenPrefixes: + - is_ + - has_ + - have_ + # Predicate names which, despite having a forbidden prefix, or no `?`, + # should still be accepted + AllowedMethods: + - is_a? + # Method definition macros for dynamically generated methods. + MethodDefinitionMacros: + - define_method + - define_singleton_method + # Exclude Rspec specs because there is a strong convention to write spec + # helpers in the form of `have_something` or `be_something`. + Exclude: + - 'spec/**/*' -Rails/UniqBeforePluck: - Description: 'Prefer the use of uniq or distinct before pluck.' +Naming/RescuedExceptionsVariableName: + Description: 'Use consistent rescued exceptions variables naming.' Enabled: true - VersionAdded: '0.40' - VersionChanged: '0.47' - EnforcedStyle: conservative - SupportedStyles: - - conservative - - aggressive - AutoCorrect: false + VersionAdded: '0.67' + VersionChanged: '0.68' + PreferredName: e -Rails/UnknownEnv: - Description: 'Use correct environment name.' +Naming/VariableName: + Description: 'Use the configured style when naming variables.' + StyleGuide: '#snake-case-symbols-methods-vars' Enabled: true - VersionAdded: '0.51' - Environments: - - development - - test - - production + VersionAdded: '0.50' + EnforcedStyle: snake_case + SupportedStyles: + - snake_case + - camelCase -Rails/Validation: - Description: 'Use validates :attribute, hash of validations.' +Naming/VariableNumber: + Description: 'Use the configured style when numbering variables.' Enabled: true - VersionAdded: '0.9' - VersionChanged: '0.41' - Include: - - app/models/**/*.rb + VersionAdded: '0.50' + EnforcedStyle: normalcase + SupportedStyles: + - snake_case + - normalcase + - non_integer #################### Security ############################## @@ -2649,7 +2397,7 @@ Security/JSONLoad: Description: >- Prefer usage of `JSON.parse` over `JSON.load` due to potential security issues. See reference for more information. - Reference: 'https://ruby-doc.org/stdlib-2.3.0/libdoc/json/rdoc/JSON.html#method-i-load' + Reference: 'https://ruby-doc.org/stdlib-2.7.0/libdoc/json/rdoc/JSON.html#method-i-load' Enabled: true VersionAdded: '0.43' VersionChanged: '0.44' @@ -2662,7 +2410,7 @@ Security/MarshalLoad: Description: >- Avoid using of `Marshal.load` or `Marshal.restore` due to potential security issues. See reference for more information. - Reference: 'https://ruby-doc.org/core-2.3.3/Marshal.html#module-Marshal-label-Security+considerations' + Reference: 'https://ruby-doc.org/core-2.7.0/Marshal.html#module-Marshal-label-Security+considerations' Enabled: true VersionAdded: '0.47' @@ -2676,7 +2424,7 @@ Security/YAMLLoad: Description: >- Prefer usage of `YAML.safe_load` over `YAML.load` due to potential security issues. See reference for more information. - Reference: 'https://ruby-doc.org/stdlib-2.3.3/libdoc/yaml/rdoc/YAML.html#module-YAML-label-Security' + Reference: 'https://ruby-doc.org/stdlib-2.7.0/libdoc/yaml/rdoc/YAML.html#module-YAML-label-Security' Enabled: true VersionAdded: '0.47' SafeAutoCorrect: false @@ -2687,14 +2435,27 @@ Style/AccessModifierDeclarations: Description: 'Checks style of how access modifiers are used.' Enabled: true VersionAdded: '0.57' + VersionChanged: '0.81' EnforcedStyle: group SupportedStyles: - inline - group + AllowModifiersOnSymbols: true + +Style/AccessorGrouping: + Description: 'Checks for grouping of accessors in `class` and `module` bodies.' + Enabled: 'pending' + VersionAdded: '0.87' + EnforcedStyle: grouped + SupportedStyles: + # separated: each accessor goes in a separate statement. + # grouped: accessors are grouped into a single statement. + - separated + - grouped Style/Alias: Description: 'Use alias instead of alias_method.' - StyleGuide: '#alias-method' + StyleGuide: '#alias-method-lexically' Enabled: true VersionAdded: '0.9' VersionChanged: '0.36' @@ -2711,11 +2472,20 @@ Style/AndOr: VersionChanged: '0.25' # Whether `and` and `or` are banned only in conditionals (conditionals) # or completely (always). - EnforcedStyle: always + EnforcedStyle: conditionals SupportedStyles: - always - conditionals +Style/ArrayCoercion: + Description: >- + Use Array() instead of explicit Array check or [*var], when dealing + with a variable you want to treat as an Array, but you're not certain it's an array. + StyleGuide: '#array-coercion' + Safe: false + Enabled: false + VersionAdded: '0.88' + Style/ArrayJoin: Description: 'Use Array#join instead of Array#*.' StyleGuide: '#array-join' @@ -2759,6 +2529,13 @@ Style/BeginBlock: Enabled: true VersionAdded: '0.9' +Style/BisectedAttrAccessor: + Description: >- + Checks for places where `attr_reader` and `attr_writer` + for the same method can be combined into single `attr_accessor`. + Enabled: 'pending' + VersionAdded: '0.87' + Style/BlockComments: Description: 'Do not use block comments.' StyleGuide: '#no-block-comments' @@ -2796,6 +2573,8 @@ Style/BlockDelimiters: # return value is being chained with another method (in which case braces # are enforced). - braces_for_chaining + # The `always_braces` style always enforces braces. + - always_braces ProceduralMethods: # Methods that are known to be procedural in nature but look functional from # their usage, e.g. @@ -2867,30 +2646,35 @@ Style/BlockDelimiters: # # also good # collection.each do |element| puts element end AllowBracesOnProceduralOneLiners: false - -Style/BracesAroundHashParameters: - Description: 'Enforce braces style around hash parameters.' - Enabled: true - VersionAdded: '0.14.1' - VersionChanged: '0.28' - EnforcedStyle: no_braces - SupportedStyles: - # The `braces` style enforces braces around all method parameters that are - # hashes. - - braces - # The `no_braces` style checks that the last parameter doesn't have braces - # around it. - - no_braces - # The `context_dependent` style checks that the last parameter doesn't have - # braces around it, but requires braces if the second to last parameter is - # also a hash literal. - - context_dependent + # The BracesRequiredMethods overrides all other configurations except + # IgnoredMethods. It can be used to enforce that all blocks for specific + # methods use braces. For example, you can use this to enforce Sorbet + # signatures use braces even when the rest of your codebase enforces + # the `line_count_based` style. + BracesRequiredMethods: [] Style/CaseEquality: Description: 'Avoid explicit use of the case equality operator(===).' StyleGuide: '#no-case-equality' Enabled: true VersionAdded: '0.9' + VersionChanged: '0.89' + # If AllowOnConstant is enabled, the cop will ignore violations when the receiver of + # the case equality operator is a constant. + # + # # bad + # /string/ === "string" + # + # # good + # String === "string" + AllowOnConstant: false + +Style/CaseLikeIf: + Description: 'This cop identifies places where `if-elsif` constructions can be replaced with `case-when`.' + StyleGuide: '#case-vs-if-else' + Enabled: 'pending' + Safe: false + VersionAdded: '0.88' Style/CharacterLiteral: Description: 'Checks for uses of character literals.' @@ -2907,7 +2691,6 @@ Style/ClassAndModuleChildren: # have the knowledge to perform either operation safely and thus requires # manual oversight. SafeAutoCorrect: false - AutoCorrect: false Enabled: true VersionAdded: '0.19' # @@ -2931,6 +2714,7 @@ Style/ClassAndModuleChildren: Style/ClassCheck: Description: 'Enforces consistent use of `Object#is_a?` or `Object#kind_of?`.' + StyleGuide: '#is-a-vs-kind-of' Enabled: true VersionAdded: '0.24' EnforcedStyle: is_a? @@ -2938,6 +2722,16 @@ Style/ClassCheck: - is_a? - kind_of? +Style/ClassEqualityComparison: + Description: 'Enforces the use of `Object#instance_of?` instead of class comparison for equality.' + StyleGuide: '#instance-of-vs-class-comparison' + Enabled: pending + VersionAdded: '0.93' + IgnoredMethods: + - == + - equal? + - eql? + Style/ClassMethods: Description: 'Use self when defining module/class methods.' StyleGuide: '#def-self-class-methods' @@ -2945,6 +2739,16 @@ Style/ClassMethods: VersionAdded: '0.9' VersionChanged: '0.20' +Style/ClassMethodsDefinitions: + Description: 'Enforces using `def self.method_name` or `class << self` to define class methods.' + StyleGuide: '#def-self-class-methods' + Enabled: false + VersionAdded: '0.89' + EnforcedStyle: def_self + SupportedStyles: + - def_self + - self_class + Style/ClassVars: Description: 'Avoid the use of class variables.' StyleGuide: '#no-class-vars' @@ -2954,7 +2758,7 @@ Style/ClassVars: # Align with the style guide. Style/CollectionMethods: Description: 'Preferred collection methods.' - StyleGuide: '#map-find-select-reduce-size' + StyleGuide: '#map-find-select-reduce-include-size' Enabled: false VersionAdded: '0.9' VersionChanged: '0.27' @@ -2971,6 +2775,7 @@ Style/CollectionMethods: inject: 'reduce' detect: 'find' find_all: 'select' + member?: 'include?' Style/ColonMethodCall: Description: 'Do not use :: for method call.' @@ -2984,6 +2789,14 @@ Style/ColonMethodDefinition: Enabled: true VersionAdded: '0.52' +Style/CombinableLoops: + Description: >- + Checks for places where multiple consecutive loops over the same data + can be combined into a single loop. + Enabled: pending + Safe: false + VersionAdded: '0.90' + Style/CommandLiteral: Description: 'Use `` or %x around command literals.' StyleGuide: '#percent-x' @@ -3043,6 +2856,13 @@ Style/ConditionalAssignment: SingleLineConditionsOnly: true IncludeTernaryExpressions: true +Style/ConstantVisibility: + Description: >- + Check that class- and module constants have + visibility declarations. + Enabled: false + VersionAdded: '0.66' + # Checks that you have put a copyright in a comment before any code. # # You can override the default Notice in your .rubocop.yml file. @@ -3061,13 +2881,6 @@ Style/ConditionalAssignment: # Notice: 'Copyright (\(c\) )?2015 Yahoo! Inc' # AutocorrectNotice: '# Copyright (c) 2015 Yahoo! Inc.' # -Style/ConstantVisibility: - Description: >- - Check that class- and module constants have - visibility declarations. - Enabled: false - VersionAdded: '0.66' - Style/Copyright: Description: 'Include a copyright notice in each file before any code.' Enabled: false @@ -3080,7 +2893,8 @@ Style/DateTime: StyleGuide: '#date--time' Enabled: false VersionAdded: '0.51' - VersionChanged: '0.59' + VersionChanged: '0.92' + SafeAutoCorrect: false AllowCoercion: false Style/DefWithParentheses: @@ -3097,6 +2911,12 @@ Style/Dir: Enabled: true VersionAdded: '0.50' +Style/DisableCopsWithinSourceCodeDirective: + Description: >- + Forbids disabling/enabling cops within source code. + Enabled: false + VersionAdded: '0.82' + Style/Documentation: Description: 'Document classes and non-namespace modules.' Enabled: true @@ -3114,11 +2934,22 @@ Style/DocumentationMethod: - 'test/**/*' RequireForNonPublicMethods: false +Style/DoubleCopDisableDirective: + Description: 'Checks for double rubocop:disable comments on a single line.' + Enabled: true + VersionAdded: '0.73' + Style/DoubleNegation: Description: 'Checks for uses of double negation (!!).' StyleGuide: '#no-bang-bang' Enabled: true VersionAdded: '0.19' + VersionChanged: '0.84' + EnforcedStyle: allowed_in_returns + SafeAutoCorrect: false + SupportedStyles: + - allowed_in_returns + - forbidden Style/EachForSimpleLoop: Description: >- @@ -3191,6 +3022,7 @@ Style/EndBlock: StyleGuide: '#no-END-blocks' Enabled: true VersionAdded: '0.9' + VersionChanged: '0.81' Style/EvalWithLocation: Description: 'Pass `__FILE__` and `__LINE__` to `eval` method, as they are used by backtraces.' @@ -3198,7 +3030,7 @@ Style/EvalWithLocation: VersionAdded: '0.52' Style/EvenOdd: - Description: 'Favor the use of Integer#even? && Integer#odd?' + Description: 'Favor the use of `Integer#even?` && `Integer#odd?`.' StyleGuide: '#predicate-methods' Enabled: true VersionAdded: '0.12' @@ -3209,6 +3041,40 @@ Style/ExpandPathArguments: Enabled: true VersionAdded: '0.53' +Style/ExplicitBlockArgument: + Description: >- + Consider using explicit block argument to avoid writing block literal + that just passes its arguments to another block. + StyleGuide: '#block-argument' + Enabled: pending + # May change the yielding arity. + Safe: false + VersionAdded: '0.89' + +Style/ExponentialNotation: + Description: 'When using exponential notation, favor a mantissa between 1 (inclusive) and 10 (exclusive).' + StyleGuide: '#exponential-notation' + Enabled: pending + VersionAdded: '0.82' + EnforcedStyle: scientific + SupportedStyles: + - scientific + - engineering + - integral + +Style/FloatDivision: + Description: 'For performing float division, coerce one side only.' + StyleGuide: '#float-division' + Reference: 'https://github.com/rubocop-hq/ruby-style-guide/issues/628' + Enabled: true + VersionAdded: '0.72' + EnforcedStyle: single_coerce + SupportedStyles: + - left_coerce + - right_coerce + - single_coerce + - fdiv + Style/For: Description: 'Checks use of for or each in multiline loops.' StyleGuide: '#no-for-loops' @@ -3244,7 +3110,7 @@ Style/FormatStringToken: - template - unannotated VersionAdded: '0.49' - VersionChanged: '0.52' + VersionChanged: '0.75' Style/FrozenStringLiteralComment: Description: >- @@ -3252,20 +3118,28 @@ Style/FrozenStringLiteralComment: to help transition to frozen string literals by default. Enabled: true VersionAdded: '0.36' - VersionChanged: '0.47' - EnforcedStyle: when_needed + VersionChanged: '0.79' + EnforcedStyle: always SupportedStyles: - # `when_needed` will add the frozen string literal comment to files - # only when the `TargetRubyVersion` is set to 2.3+. - - when_needed # `always` will always add the frozen string literal comment to a file # regardless of the Ruby version or if `freeze` or `<<` are called on a - # string literal. If you run code against multiple versions of Ruby, it is - # possible that this will create errors in Ruby 2.3.0+. + # string literal. It is possible that this will create errors. - always + # `always_true` will add the frozen string literal comment to a file, + # similarly to the `always` style, but will also change any disabled + # comments (e.g. `# frozen_string_literal: false`) to be enabled. + - always_true # `never` will enforce that the frozen string literal comment does not # exist in a file. - never + SafeAutoCorrect: false + +Style/GlobalStdStream: + Description: 'Enforces the use of `$stdout/$stderr/$stdin` instead of `STDOUT/STDERR/STDIN`.' + StyleGuide: '#global-stdout' + Enabled: pending + VersionAdded: '0.89' + SafeAutoCorrect: false Style/GlobalVars: Description: 'Do not introduce global variables.' @@ -3277,7 +3151,7 @@ Style/GlobalVars: AllowedVariables: [] Style/GuardClause: - Description: 'Check for conditionals that can be replaced with guard clauses' + Description: 'Check for conditionals that can be replaced with guard clauses.' StyleGuide: '#no-nested-conditionals' Enabled: true VersionAdded: '0.20' @@ -3286,6 +3160,35 @@ Style/GuardClause: # needs to have to trigger this cop MinBodyLength: 1 +Style/HashAsLastArrayItem: + Description: >- + Checks for presence or absence of braces around hash literal as a last + array item depending on configuration. + StyleGuide: '#hash-literal-as-last-array-item' + Enabled: 'pending' + VersionAdded: '0.88' + EnforcedStyle: braces + SupportedStyles: + - braces + - no_braces + +Style/HashEachMethods: + Description: 'Use Hash#each_key and Hash#each_value.' + StyleGuide: '#hash-each' + Enabled: pending + VersionAdded: '0.80' + Safe: false + +Style/HashLikeCase: + Description: >- + Checks for places where `case-when` represents a simple 1:1 + mapping and can be replaced with a hash lookup. + Enabled: 'pending' + VersionAdded: '0.88' + # `MinBranchesCount` defines the number of branches `case` needs to have + # to trigger this cop + MinBranchesCount: 3 + Style/HashSyntax: Description: >- Prefer Ruby 1.9 hash syntax { a: 1, b: 2 } over 1.8 syntax @@ -3309,6 +3212,20 @@ Style/HashSyntax: # Do not suggest { a?: 1 } over { :a? => 1 } in ruby19 style PreferHashRocketsForNonAlnumEndingSymbols: false +Style/HashTransformKeys: + Description: 'Prefer `transform_keys` over `each_with_object`, `map`, or `to_h`.' + Enabled: 'pending' + VersionAdded: '0.80' + VersionChanged: '0.90' + Safe: false + +Style/HashTransformValues: + Description: 'Prefer `transform_values` over `each_with_object`, `map`, or `to_h`.' + Enabled: 'pending' + VersionAdded: '0.80' + VersionChanged: '0.90' + Safe: false + Style/IdenticalConditionalBranches: Description: >- Checks that conditional statements do not have an identical @@ -3320,6 +3237,7 @@ Style/IdenticalConditionalBranches: Style/IfInsideElse: Description: 'Finds if nodes inside else, which can be converted to elsif.' Enabled: true + AllowIfModifier: false VersionAdded: '0.36' Style/IfUnlessModifier: @@ -3336,12 +3254,14 @@ Style/IfUnlessModifierOfIfUnless: Avoid modifier if/unless usage on conditionals. Enabled: true VersionAdded: '0.39' + VersionChanged: '0.87' Style/IfWithSemicolon: Description: 'Do not use if x; .... Use the ternary operator instead.' StyleGuide: '#no-semicolon-ifs' Enabled: true VersionAdded: '0.9' + VersionChanged: '0.83' Style/ImplicitRuntimeError: Description: >- @@ -3394,10 +3314,22 @@ Style/IpAddresses: Description: "Don't include literal IP addresses in code." Enabled: false VersionAdded: '0.58' - # Allow strings to be whitelisted - Whitelist: + VersionChanged: '0.91' + # Allow addresses to be permitted + AllowedAddresses: - "::" # :: is a valid IPv6 address, but could potentially be legitimately in code + Exclude: + - '**/*.gemfile' + - '**/Gemfile' + - '**/gems.rb' + - '**/*.gemspec' + +Style/KeywordParametersOrder: + Description: 'Enforces that optional keyword parameters are placed at the end of the parameters list.' + StyleGuide: '#keyword-parameters-order' + Enabled: pending + VersionAdded: '0.90' Style/Lambda: Description: 'Use the new lambda literal syntax for single-line blocks.' @@ -3415,7 +3347,7 @@ Style/LambdaCall: Description: 'Use lambda.call(...) instead of lambda.(...).' StyleGuide: '#proc-call' Enabled: true - VersionAdded: '0.13.1' + VersionAdded: '0.13' VersionChanged: '0.14' EnforcedStyle: call SupportedStyles: @@ -3439,6 +3371,8 @@ Style/MethodCallWithArgsParentheses: VersionChanged: '0.61' IgnoreMacros: true IgnoredMethods: [] + IgnoredPatterns: [] + IncludedMacros: [] AllowParenthesesInMultilineCall: false AllowParenthesesInChaining: false AllowParenthesesInCamelCaseMethod: false @@ -3475,16 +3409,10 @@ Style/MethodDefParentheses: - require_no_parentheses - require_no_parentheses_except_multiline -Style/MethodMissingSuper: - Description: Checks for `method_missing` to call `super`. - StyleGuide: '#no-method-missing' - Enabled: true - VersionAdded: '0.56' - Style/MinMax: Description: >- Use `Enumerable#minmax` instead of `Enumerable#min` - and `Enumerable#max` in conjunction.' + and `Enumerable#max` in conjunction. Enabled: true VersionAdded: '0.50' @@ -3494,7 +3422,7 @@ Style/MissingElse: If enabled, it is recommended that Style/UnlessElse and Style/EmptyElse be enabled. This will conflict with Style/EmptyElse if - Style/EmptyElse is configured to style "both" + Style/EmptyElse is configured to style "both". Enabled: false VersionAdded: '0.30' VersionChanged: '0.38' @@ -3543,6 +3471,7 @@ Style/ModuleFunction: SupportedStyles: - module_function - extend_self + - forbidden Autocorrect: false SafeAutoCorrect: false @@ -3587,6 +3516,13 @@ Style/MultilineTernaryOperator: StyleGuide: '#no-multiline-ternary' Enabled: true VersionAdded: '0.9' + VersionChanged: '0.86' + +Style/MultilineWhenThen: + Description: 'Do not use then for multi-line when statement.' + StyleGuide: '#no-then' + Enabled: true + VersionAdded: '0.73' Style/MultipleComparison: Description: >- @@ -3628,6 +3564,20 @@ Style/NegatedIf: - prefix - postfix +Style/NegatedUnless: + Description: 'Favor if over unless for negative conditions.' + StyleGuide: '#if-for-negatives' + Enabled: true + VersionAdded: '0.69' + EnforcedStyle: both + SupportedStyles: + # both: prefix and postfix negated `unless` should both use `if` + # prefix: only use `if` for negated `unless` statements positioned before the body of the statement + # postfix: only use `if` for negated `unless` statements positioned after the body of the statement + - both + - prefix + - postfix + Style/NegatedWhile: Description: 'Favor until over while for negative conditions.' StyleGuide: '#until-for-negatives' @@ -3646,8 +3596,8 @@ Style/NestedParenthesizedCalls: argument list of another parenthesized method call. Enabled: true VersionAdded: '0.36' - VersionChanged: '0.50' - Whitelist: + VersionChanged: '0.77' + AllowedMethods: - be - be_a - be_an @@ -3671,6 +3621,7 @@ Style/NestedTernaryOperator: StyleGuide: '#no-nested-ternary' Enabled: true VersionAdded: '0.9' + VersionChanged: '0.86' Style/Next: Description: 'Use `next` to skip iteration instead of a condition at the end.' @@ -3753,7 +3704,6 @@ Style/NumericPredicate: # object. Switching these methods has to be done with knowledge of the types # of the variables which rubocop doesn't have. SafeAutoCorrect: false - AutoCorrect: false Enabled: true VersionAdded: '0.42' VersionChanged: '0.59' @@ -3769,12 +3719,13 @@ Style/NumericPredicate: Style/OneLineConditional: Description: >- - Favor the ternary operator(?:) over - if/then/else/end constructs. + Favor the ternary operator (?:) or multi-line constructs over + single-line if/then/else/end constructs. StyleGuide: '#ternary-operator' Enabled: true + AlwaysCorrectToMultiline: false VersionAdded: '0.9' - VersionChanged: '0.38' + VersionChanged: '0.90' Style/OptionHash: Description: "Don't use option hashes when you can use keyword arguments." @@ -3792,10 +3743,21 @@ Style/OptionHash: Style/OptionalArguments: Description: >- Checks for optional arguments that do not appear at the end - of the argument list + of the argument list. StyleGuide: '#optional-arguments' Enabled: true + Safe: false VersionAdded: '0.33' + VersionChanged: '0.83' + +Style/OptionalBooleanParameter: + Description: 'Use keyword arguments when defining method with boolean argument.' + StyleGuide: '#boolean-keyword-arguments' + Enabled: pending + Safe: false + VersionAdded: '0.89' + AllowedMethods: + - respond_to_missing? Style/OrAssignment: Description: 'Recommend usage of double pipe equals (||=) where applicable.' @@ -3824,7 +3786,7 @@ Style/ParenthesesAroundCondition: AllowInMultilineConditions: false Style/PercentLiteralDelimiters: - Description: 'Use `%`-literal delimiters consistently' + Description: 'Use `%`-literal delimiters consistently.' StyleGuide: '#percent-literal-braces' Enabled: true VersionAdded: '0.19' @@ -3859,8 +3821,9 @@ Style/PreferredHashMethods: Description: 'Checks use of `has_key?` and `has_value?` Hash methods.' StyleGuide: '#hash-key' Enabled: true + Safe: false VersionAdded: '0.41' - VersionChanged: '0.44' + VersionChanged: '0.70' EnforcedStyle: short SupportedStyles: - short @@ -3892,6 +3855,11 @@ Style/RandomWithOffset: Enabled: true VersionAdded: '0.52' +Style/RedundantAssignment: + Description: 'Checks for redundant assignment before returning.' + Enabled: 'pending' + VersionAdded: '0.87' + Style/RedundantBegin: Description: "Don't use begin blocks when they are not needed." StyleGuide: '#begin-implicit' @@ -3899,6 +3867,16 @@ Style/RedundantBegin: VersionAdded: '0.10' VersionChanged: '0.21' +Style/RedundantCapitalW: + Description: 'Checks for %W when interpolation is not needed.' + Enabled: true + VersionAdded: '0.76' + +Style/RedundantCondition: + Description: 'Checks for unnecessary conditional expressions.' + Enabled: true + VersionAdded: '0.76' + Style/RedundantConditional: Description: "Don't return true/false from a conditional." Enabled: true @@ -3911,17 +3889,59 @@ Style/RedundantException: VersionAdded: '0.14' VersionChanged: '0.29' +Style/RedundantFetchBlock: + Description: >- + Use `fetch(key, value)` instead of `fetch(key) { value }` + when value has Numeric, Rational, Complex, Symbol or String type, `false`, `true`, `nil` or is a constant. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#hashfetch-with-argument-vs-hashfetch--block-code' + Enabled: 'pending' + Safe: false + # If enabled, this cop will autocorrect usages of + # `fetch` being called with block returning a constant. + # This can be dangerous since constants will not be defined at that moment. + SafeForConstants: false + VersionAdded: '0.86' + +Style/RedundantFileExtensionInRequire: + Description: >- + Checks for the presence of superfluous `.rb` extension in + the filename provided to `require` and `require_relative`. + StyleGuide: '#no-explicit-rb-to-require' + Enabled: 'pending' + VersionAdded: '0.88' + Style/RedundantFreeze: Description: "Checks usages of Object#freeze on immutable objects." Enabled: true VersionAdded: '0.34' VersionChanged: '0.66' +Style/RedundantInterpolation: + Description: 'Checks for strings that are just an interpolated expression.' + Enabled: true + VersionAdded: '0.76' + Style/RedundantParentheses: Description: "Checks for parentheses that seem not to serve any purpose." Enabled: true VersionAdded: '0.36' +Style/RedundantPercentQ: + Description: 'Checks for %q/%Q when single quotes or double quotes would do.' + StyleGuide: '#percent-q' + Enabled: true + VersionAdded: '0.76' + +Style/RedundantRegexpCharacterClass: + Description: 'Checks for unnecessary single-element Regexp character classes.' + Enabled: pending + VersionAdded: '0.85' + +Style/RedundantRegexpEscape: + Description: 'Checks for redundant escapes in Regexps.' + Enabled: pending + VersionAdded: '0.85' + Style/RedundantReturn: Description: "Don't use return where it's not required." StyleGuide: '#no-explicit-return' @@ -3938,6 +3958,24 @@ Style/RedundantSelf: VersionAdded: '0.10' VersionChanged: '0.13' +Style/RedundantSelfAssignment: + Description: 'Checks for places where redundant assignments are made for in place modification methods.' + Enabled: pending + Safe: false + VersionAdded: '0.90' + +Style/RedundantSort: + Description: >- + Use `min` instead of `sort.first`, + `max_by` instead of `sort_by...last`, etc. + Enabled: true + VersionAdded: '0.76' + +Style/RedundantSortBy: + Description: 'Use `sort` instead of `sort_by { |x| x }`.' + Enabled: true + VersionAdded: '0.36' + Style/RegexpLiteral: Description: 'Use / or %r around regular expressions.' StyleGuide: '#percent-r' @@ -3988,18 +4026,29 @@ Style/SafeNavigation: This cop transforms usages of a method call safeguarded by a check for the existence of the object to safe navigation (`&.`). + Auto-correction is unsafe as it assumes the object will + be `nil` or truthy, but never `false`. Enabled: true VersionAdded: '0.43' - VersionChanged: '0.56' + VersionChanged: '0.77' # Safe navigation may cause a statement to start returning `nil` in addition # to whatever it used to return. ConvertCodeThatCanStartToReturnNil: false - Whitelist: + AllowedMethods: - present? - blank? - presence - try - try! + SafeAutoCorrect: false + +Style/Sample: + Description: >- + Use `sample` instead of `shuffle.first`, + `shuffle.last`, and `shuffle[Integer]`. + Reference: 'https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code' + Enabled: true + VersionAdded: '0.30' Style/SelfAssignment: Description: >- @@ -4037,6 +4086,12 @@ Style/SignalException: - only_fail - semantic +Style/SingleArgumentDig: + Description: 'Avoid using single argument dig method.' + Enabled: pending + VersionAdded: '0.89' + Safe: false + Style/SingleLineBlockParams: Description: 'Enforces the names of some block params.' Enabled: false @@ -4058,6 +4113,20 @@ Style/SingleLineMethods: VersionChanged: '0.19' AllowIfMethodIsEmpty: true +Style/SlicingWithRange: + Description: 'Checks array slicing is done with endless ranges when suitable.' + Enabled: pending + VersionAdded: '0.83' + Safe: false + +Style/SoleNestedConditional: + Description: >- + Finds sole nested conditional nodes + which can be merged into outer conditional node. + Enabled: pending + VersionAdded: '0.89' + AllowModifier: false + Style/SpecialGlobalVars: Description: 'Avoid Perl-style global variables.' StyleGuide: '#no-cryptic-perlisms' @@ -4086,11 +4155,20 @@ Style/StderrPuts: Enabled: true VersionAdded: '0.51' +Style/StringConcatenation: + Description: 'Checks for places where string concatenation can be replaced with string interpolation.' + StyleGuide: '#string-interpolation' + Enabled: pending + Safe: false + VersionAdded: '0.89' + Style/StringHashKeys: Description: 'Prefer symbols instead of strings as hash keys.' StyleGuide: '#symbols-as-keys' Enabled: false VersionAdded: '0.52' + VersionChanged: '0.75' + Safe: false Style/StringLiterals: Description: 'Checks if uses of quotes match the configured preference.' @@ -4131,11 +4209,17 @@ Style/StringMethods: PreferredMethods: intern: to_sym +Style/Strip: + Description: 'Use `strip` instead of `lstrip.rstrip`.' + Enabled: true + VersionAdded: '0.36' + Style/StructInheritance: Description: 'Checks for inheritance from Struct.new.' StyleGuide: '#no-extend-struct-new' Enabled: true VersionAdded: '0.29' + VersionChanged: '0.86' Style/SymbolArray: Description: 'Use %i or %I for arrays of symbols.' @@ -4157,7 +4241,7 @@ Style/SymbolLiteral: Style/SymbolProc: Description: 'Use symbols as procs instead of blocks when possible.' Enabled: true - SafeAutoCorrect: false + Safe: false VersionAdded: '0.26' VersionChanged: '0.64' # A list of method names to be ignored by the check. @@ -4213,22 +4297,29 @@ Style/TrailingCommaInArrayLiteral: StyleGuide: '#no-trailing-array-commas' Enabled: true VersionAdded: '0.53' + # If `comma`, the cop requires a comma after the last item in an array, # but only when each item is on its own line. # If `consistent_comma`, the cop requires a comma after the last item of all - # non-empty array literals. + # non-empty, multiline array literals. EnforcedStyleForMultiline: no_comma SupportedStylesForMultiline: - comma - consistent_comma - no_comma +Style/TrailingCommaInBlockArgs: + Description: 'Checks for useless trailing commas in block arguments.' + Enabled: false + Safe: false + VersionAdded: '0.81' + Style/TrailingCommaInHashLiteral: Description: 'Checks for trailing comma in hash literals.' Enabled: true # If `comma`, the cop requires a comma after the last item in a hash, # but only when each item is on its own line. # If `consistent_comma`, the cop requires a comma after the last item of all - # non-empty hash literals. + # non-empty, multiline hash literals. EnforcedStyleForMultiline: no_comma SupportedStylesForMultiline: - comma @@ -4257,7 +4348,7 @@ Style/TrivialAccessors: StyleGuide: '#attr_family' Enabled: true VersionAdded: '0.9' - VersionChanged: '0.38' + VersionChanged: '0.77' # When set to `false` the cop will suggest the use of accessor methods # in situations like: # @@ -4278,7 +4369,7 @@ Style/TrivialAccessors: # Commonly used in DSLs AllowDSLWriters: false IgnoreClassMethods: false - Whitelist: + AllowedMethods: - to_ary - to_a - to_c @@ -4305,32 +4396,10 @@ Style/UnlessElse: Enabled: true VersionAdded: '0.9' -Style/UnneededCapitalW: - Description: 'Checks for %W when interpolation is not needed.' - Enabled: true - VersionAdded: '0.21' - VersionChanged: '0.24' - -Style/UnneededCondition: - Description: 'Checks for unnecessary conditional expressions.' - Enabled: true - VersionAdded: '0.57' - -Style/UnneededInterpolation: - Description: 'Checks for strings that are just an interpolated expression.' - Enabled: true - VersionAdded: '0.36' - -Style/UnneededPercentQ: - Description: 'Checks for %q/%Q when single quotes or double quotes would do.' - StyleGuide: '#percent-q' - Enabled: true - VersionAdded: '0.24' - Style/UnpackFirst: Description: >- Checks for accessing the first element of `String#unpack` - instead of using `unpack1` + instead of using `unpack1`. Enabled: true VersionAdded: '0.54' @@ -4381,7 +4450,7 @@ Style/WordArray: # whose element count is greater than or equal to `MinSize`. MinSize: 2 # The regular expression `WordRegex` decides what is considered a word. - WordRegex: !ruby/regexp '/\A[\p{Word}\n\t]+\z/' + WordRegex: !ruby/regexp '/\A(?:\p{Word}|\p{Word}-\p{Word}|\n|\t)+\z/' Style/YodaCondition: Description: 'Forbid or enforce yoda conditions.' @@ -4397,8 +4466,9 @@ Style/YodaCondition: - require_for_all_comparison_operators # enforce yoda only for equality operators: `!=` and `==` - require_for_equality_operators_only + Safe: false VersionAdded: '0.49' - VersionChanged: '0.63' + VersionChanged: '0.75' Style/ZeroLengthPredicate: Description: 'Use #empty? when testing for objects of length 0.' diff --git a/docs/antora.yml b/docs/antora.yml new file mode 100644 index 000000000000..5c71227d1ab8 --- /dev/null +++ b/docs/antora.yml @@ -0,0 +1,7 @@ +name: rubocop +title: RuboCop +# We always provide version without patch here (e.g. 1.1), +# as patch versions should not appear in the docs. +version: '0.93' +nav: +- modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc new file mode 100644 index 000000000000..20b9e96683b5 --- /dev/null +++ b/docs/modules/ROOT/nav.adoc @@ -0,0 +1,28 @@ +* xref:index.adoc[Home] +* xref:installation.adoc[Installation] +* xref:compatibility.adoc[Compatibility] +* Usage +** xref:usage/basic_usage.adoc[Basic Usage] +** xref:usage/auto_correct.adoc[Auto-correct] +** xref:usage/caching.adoc[Caching] +* xref:configuration.adoc[Configuration] +* xref:cops.adoc[Cops] +* xref:formatters.adoc[Formatters] +* Cop Documentation +** xref:cops_bundler.adoc[Bundler] +** xref:cops_gemspec.adoc[Gemspec] +** xref:cops_layout.adoc[Layout] +** xref:cops_lint.adoc[Lint] +** xref:cops_metrics.adoc[Metrics] +** xref:cops_migration.adoc[Migration] +** xref:cops_naming.adoc[Naming] +** xref:cops_security.adoc[Security] +** xref:cops_style.adoc[Style] +** xref:v1_upgrade_notes.adoc[Upgrade Notes] +* xref:extensions.adoc[Extensions] +* xref:integration_with_other_tools.adoc[Integration with Other Tools] +* xref:automated_code_review.adoc[Automated Code Review] +* xref:development.adoc[Development] +* xref:contributing.adoc[Contributing] +* xref:support.adoc[Support] +* xref:versioning.adoc[Versioning] diff --git a/docs/modules/ROOT/pages/automated_code_review.adoc b/docs/modules/ROOT/pages/automated_code_review.adoc new file mode 100644 index 000000000000..89d8b9e82f90 --- /dev/null +++ b/docs/modules/ROOT/pages/automated_code_review.adoc @@ -0,0 +1,40 @@ += Automated Code Review + +The section describes SaaS solutions that provide automated code reviews for Ruby based on RuboCop. + +NOTE: The services are listed in alphabetical order. + +== Awesome Code + +https://awesomecode.io[Awesome Code] improves your code readability by git push or sending pull requests, with one click or even fully automated. It's an online `rubocop -a` service. + +== Codacy + +https://www.codacy.com/[Codacy] checks your code from style to security, duplication, complexity, and also integrates with coverage. +Codacy is free for open source, and it provides RuboCop analysis out-of-the-box. + +== Code Climate + +https://codeclimate.com/[Code Climate] provides automated code review for test coverage, complexity, duplication, security, style, and more, and merge with confidence. + +== CodeFactor + +https://www.codefactor.io[CodeFactor] reports various code metrics like duplication, churn, and problems for code style, performance, complexity, and many others. CodeFactor is free for open source. It supports analysis and auto-correction for RuboCop. + +== Hound + +https://houndci.com/[Hound] comments on style violations in GitHub pull requests, allowing you and your team to better review and maintain a clean codebase. +It is open source software. + +== Pronto + +https://github.com/prontolabs/pronto[Pronto] does quick automated code review of your changes. Created to be used on GitHub pull requests, but also works locally and integrates with GitLab and Bitbucket. + +== ReviewDog + +https://github.com/reviewdog/reviewdog[ReviewDog] is similar to Pronto but with better support for GitHub Actions. + +== Sider + +https://sider.review[Sider] improves your team's productivity by automating code analysis. +It supports RuboCop's auto-correction. diff --git a/docs/modules/ROOT/pages/compatibility.adoc b/docs/modules/ROOT/pages/compatibility.adoc new file mode 100644 index 000000000000..ea19baf0aa99 --- /dev/null +++ b/docs/modules/ROOT/pages/compatibility.adoc @@ -0,0 +1,40 @@ += Compatibility + +RuboCop targets Ruby 2.4+.footnote:[As defined by its reference implementation MRI.] + +RuboCop officially supports MRI (a.k.a. CRuby) and JRuby. + +- MRI 2.4+ +- JRuby 9.2+ + +The oldest supported JRuby version is derived from the oldest compatible MRI version. + +NOTE: RuboCop might be working with other Ruby implementations as well, but it's tested only on MRI and JRuby. + +== Support Matrix + +RuboCop generally aims to follow MRI's own support policy - meaning RuboCop would support all officially supported MRI releases.footnote:[Typically the last 3 releases.] To give people extra time for a smooth transition, we've customarily provided support for about one year after EOL of MRI version. +This means that if Ruby 2.4 reaches its EOL in Spring 2020, it would be supported by RuboCop (at least) until Spring 2021.footnote:[At the core team's discretion this policy might be waived aside for MRI releases causing significant maintenance overhead.] + +The following table is the support matrix. + +|=== +| Supported target Ruby version | Last supported RuboCop version + +| 1.9 | 0.41 +| 2.0 | 0.50 +| 2.1 | 0.57 +| 2.2 | 0.68 +| 2.3 | 0.81 +| 2.4 | - +| 2.5 | - +| 2.6 | - +| 2.7 | - +| 3.0 (experimental) | - +|=== + +NOTE: The compatibility xref:configuration.adoc#setting-the-target-ruby-version[target Ruby version mentioned here] is about code analysis (what RuboCop can analyze), not runtime (is RuboCop capable of running on some Ruby or not). + +== Forward Compatibility + +Features may be provided for development version of Ruby. These are all considered experimental, and may change before the stable version of Ruby will be released. diff --git a/manual/configuration.md b/docs/modules/ROOT/pages/configuration.adoc similarity index 54% rename from manual/configuration.md rename to docs/modules/ROOT/pages/configuration.adoc index ef5785395712..58d31335e556 100644 --- a/manual/configuration.md +++ b/docs/modules/ROOT/pages/configuration.adoc @@ -1,34 +1,63 @@ -## Configuration += Configuration The behavior of RuboCop can be controlled via the -[.rubocop.yml](https://github.com/rubocop-hq/rubocop/blob/master/.rubocop.yml) +https://github.com/rubocop-hq/rubocop/blob/master/.rubocop.yml[.rubocop.yml] configuration file. It makes it possible to enable/disable certain cops (checks) and to alter their behavior if they accept any parameters. The file -can be placed either in your home directory or in some project directory. - -RuboCop will start looking for the configuration file in the directory -where the inspected file is and continue its way up to the root directory. +can be placed in your home directory, XDG config directory, or in some project +directory. The file has the following format: -```yaml +[source,yaml] +---- inherit_from: ../.rubocop.yml Style/Encoding: Enabled: false -Metrics/LineLength: +Layout/LineLength: Max: 99 -``` +---- + +NOTE: Qualifying cop name with its type, e.g., `Style`, is recommended, +but not necessary as long as the cop name is unique across all types. + +== Config file locations + +RuboCop will start looking for the configuration file in the directory +where the inspected file is and continue its way up to the root directory. -!!! Note +If it cannot be found until reaching the project's root directory, then it will +be searched for in the user's global config locations, which consists of a +dotfile or a config file inside the https://specifications.freedesktop.org/basedir-spec/latest/index.html[XDG Base Directory +specification]. - Qualifying cop name with its type, e.g., `Style`, is recommended, - but not necessary as long as the cop name is unique across all types. +* `~/.rubocop.yml` +* `$XDG_CONFIG_HOME/rubocop/config.yml` (expands to `~/.config/rubocop/config.yml` +if `$XDG_CONFIG_HOME` is not set) -### Inheritance +If both files exist, the dotfile will be selected. -All configuration inherits from [RuboCop's default configuration][1] (See +As an example, if RuboCop is invoked from inside `/path/to/project/lib/utils`, +then RuboCop will use the config as specified inside the first of the following +files: + +* `/path/to/project/lib/utils/.rubocop.yml` +* `/path/to/project/lib/.rubocop.yml` +* `/path/to/project/.rubocop.yml` +* `/.rubocop.yml` +* `~/.rubocop.yml` +* `~/.config/rubocop/config.yml` +* https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml[RuboCop's default configuration] + +NOTE: All the previous logic does not apply if a specific configuration file is passed +on the command line through the `--config` flag. In that case, the resolved +configuration file will be the one passed to the CLI. + +== Inheritance + +All configuration inherits from https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml[RuboCop's default configuration] (See "Defaults"). RuboCop also supports inheritance in user's configuration files. The most common @@ -38,7 +67,7 @@ Configuration" below). Settings in the child file (that which inherits) override those in the parent (that which is inherited), with the following caveats. -#### Inheritance of hashes vs. other types +=== Inheritance of hashes vs. other types Configuration parameters that are hashes, for example `PreferredMethods` in `Style/CollectionMethods`, are merged with the same parameter in the parent @@ -47,13 +76,14 @@ override the same keys in parent configuration. Giving `~`, YAML's representation of `nil`, as a value cancels the setting of the corresponding key in the parent configuration. For example: -```yaml +[source,yaml] +---- Style/CollectionMethods: Enabled: true PreferredMethods: # No preference for collect, keep all others from default config. collect: ~ -``` +---- Other types, such as `AllCops` / `Include` (an array), are overridden by the child setting. @@ -64,7 +94,7 @@ remove elements in child files. However, advanced users can still merge arrays using the `inherit_mode` setting. See "Merging arrays using inherit_mode" below. -#### Inheriting from another configuration file in the project +=== Inheriting from another configuration file in the project The optional `inherit_from` directive is used to include configuration from one or more files. This makes it possible to have the common @@ -77,13 +107,14 @@ multiple files are included, the first file in the list has the lowest precedence and the last one has the highest. The format for multiple inheritance is: -```yaml +[source,yaml] +---- inherit_from: - ../.rubocop.yml - ../conf/.rubocop.yml -``` +---- -### Inheriting configuration from a remote URL +== Inheriting configuration from a remote URL The optional `inherit_from` directive can contain a full url to a remote file. This makes it possible to have common project settings stored on a http @@ -91,29 +122,30 @@ server and shared between many projects. The remote config file is cached locally and is only updated if: -- The file does not exist. -- The file has not been updated in the last 24 hours. -- The remote copy has a newer modification time than the local copy. +* The file does not exist. +* The file has not been updated in the last 24 hours. +* The remote copy has a newer modification time than the local copy. You can inherit from both remote and local files in the same config and the same inheritance rules apply to remote URLs and inheriting from local files where the first file in the list has the lowest precedence and the last one has the highest. The format for multiple inheritance using URLs is: -```yaml +[source,yaml] +---- inherit_from: - http://www.example.com/rubocop.yml - ../.rubocop.yml -``` +---- -#### Inheriting configuration from a dependency gem +=== Inheriting configuration from a dependency gem The optional `inherit_gem` directive is used to include configuration from one or more gems external to the current project. This makes it possible to inherit a shared dependency's RuboCop configuration that can be used from multiple disparate projects. -Configurations inherited in this way will be essentially *prepended* to the +Configurations inherited in this way will be essentially _prepended_ to the `inherit_from` directive, such that the `inherit_gem` configurations will be loaded first, then the `inherit_from` relative file paths will be loaded (overriding the configurations from the gems), and finally the remaining @@ -124,42 +156,47 @@ have the lowest precedence of inheritance. The directive should be formatted as a YAML Hash using the gem name as the key and the relative path within the gem as the value: -```yaml +[source,yaml] +---- inherit_gem: my-shared-gem: .rubocop.yml cucumber: conf/rubocop.yml -``` +---- An array can also be used as the value to include multiple configuration files from a single gem: -```yaml +[source,yaml] +---- inherit_gem: my-shared-gem: - default.yml - strict.yml -``` +---- -**Note**: If the shared dependency is declared using a [Bundler](https://bundler.io/) +NOTE: If the shared dependency is declared using a https://bundler.io/[Bundler] Gemfile and the gem was installed using `bundle install`, it would be necessary to also invoke RuboCop using Bundler in order to find the dependency's installation path at runtime: -```sh +[source,sh] +---- $ bundle exec rubocop -``` +---- -#### Merging arrays using inherit_mode +=== Merging arrays using inherit_mode The optional directive `inherit_mode` specifies which configuration keys that have array values should be merged together instead of overriding the inherited value. This applies to explicit inheritance using `inherit_from` as well as implicit -inheritance from [the default configuration][1]. +inheritance from https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml[the default configuration]. Given the following config: -```yaml + +[source,yaml] +---- # .rubocop.yml inherit_from: - shared.yml @@ -175,24 +212,25 @@ AllCops: Style/For: Exclude: - bar.rb -``` +---- -```yaml +[source,yaml] +---- # .shared.yml Style/For: Exclude: - foo.rb -``` +---- -The list of `Exclude`s for the `Style/For` cop in this example will be +The list of ``Exclude``s for the `Style/For` cop in this example will be `['foo.rb', 'bar.rb']`. Similarly, the `AllCops:Exclude` list will contain all -the default patterns plus the `generated/**/*.rb` entry that was added locally. +the default patterns plus the `+generated/**/*.rb+` entry that was added locally. The directive can also be used on individual cop configurations to override the global setting. - -```yaml +[source,yaml] +---- inherit_from: - shared.yml @@ -206,20 +244,35 @@ Style/For: - Exclude Exclude: - bar.rb -``` +---- In this example the `Exclude` would only include `bar.rb`. +== Pre-processing + +Configuration files are pre-processed using the ERB templating mechanism. This +makes it possible to add dynamic content that will be evaluated when the +configuation file is read. For example, you could let RuboCop ignore all files +ignored by Git. + +[source,yaml] +---- +AllCops: + Exclude: + <% `git status --ignored --porcelain`.lines.grep(/^!! /).each do |path| %> + - <%= path.sub(/^!! /, '') %> + <% end %> +---- -### Defaults +== Defaults -The file [config/default.yml][1] under the RuboCop home directory contains the +The file https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml[config/default.yml] under the RuboCop home directory contains the default settings that all configurations inherit from. Project and personal -`.rubocop.yml` files need only make settings that are different from the default -ones. If there is no `.rubocop.yml` file in the project or home directory, -`config/default.yml` will be used. +`.rubocop.yml` files need only make settings that are different from the +default ones. If there is no `.rubocop.yml` file in the project, home or XDG +directories, `config/default.yml` will be used. -### Including/Excluding files +== Including/Excluding files RuboCop does a recursive file search starting from the directory it is run in, or directories given as command line arguments. Files that @@ -232,7 +285,8 @@ start with a dot) are not searched by default. Here is an example that might be used for a Rails project: -```yaml +[source,yaml] +---- AllCops: Exclude: - 'db/**/*' @@ -243,9 +297,36 @@ AllCops: # other configuration # ... -``` +---- + +NOTE: When inspecting a certain directory(or file) +given as RuboCop's command line arguments, +patterns listed under `AllCops` / `Exclude` are also inspected. +If you want to apply `AllCops` / `Exclude` rules in this circumstance, +add `--force-exclusion` to the command line argument. + +Here is an example: + +[source,yaml] +---- +# .rubocop.yml +AllCops: + Exclude: + - foo.rb +---- + +If `foo.rb` specified as a RuboCop's command line argument, the result is: + +[source,sh] +---- +# RuboCop inspects foo.rb. +$ bundle exec rubocop foo.rb + +# RuboCop does not inspect foo.rb. +$ bundle exec rubocop --force-exclusion foo.rb +---- -#### Path relativity +=== Path relativity In `.rubocop.yml` and any other configuration file beginning with `.rubocop`, files, and directories are specified relative to the directory where the @@ -253,17 +334,23 @@ configuration file is. In configuration files that don't begin with `.rubocop`, e.g. `our_company_defaults.yml`, paths are relative to the directory where `rubocop` is run. -#### Unusual files, that would not be included by default +This affects cops that have customisable paths: if the default is `db/migrate/*.rb`, +and the cop is enabled in `db/migrate/.rubocop.yml`, the path will need to be +explicitly set as `*.rb`, as the default will look for `db/migrate/db/migrate/*.rb`. +This is unlikely to be what you wanted. + +=== Unusual files, that would not be included by default RuboCop comes with a comprehensive list of common ruby file names and extensions. But, if you'd like RuboCop to check files that are not included by default, you'll need to pass them in on the command line, or to add entries for them under `AllCops`/`Include`. Remember that your configuration files override -[RuboCops's defaults][1]. In the following example, we want to include +https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml[RuboCops's defaults]. In the following example, we want to include `foo.unusual_extension`, but we also must copy any other patterns we need from the overridden `default.yml`. -```yaml +[source,yaml] +---- AllCops: Include: - foo.unusual_extension @@ -274,17 +361,18 @@ AllCops: - '**/*.ru' - '**/Gemfile' - '**/Rakefile' -``` +---- This behavior of `Include` (overriding `default.yml`) was introduced in -[0.56.0](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md#0560-2018-05-14) -via [#5882](https://github.com/rubocop-hq/rubocop/pull/5882). This change allows +https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md#0560-2018-05-14[0.56.0] +via https://github.com/rubocop-hq/rubocop/pull/5882[#5882]. This change allows people to include/exclude precisely what they need to, without the defaults getting in the way. -##### Another example, using `inherit_mode` +==== Another example, using `inherit_mode` -```yaml +[source,yaml] +---- inherit_mode: merge: - Include @@ -292,104 +380,120 @@ inherit_mode: AllCops: Include: - foo.unusual_extension -``` +---- See "Merging arrays using inherit_mode" above. -#### Deprecated patterns +=== Deprecated patterns Patterns that are just a file name, e.g. `Rakefile`, will match that file name in any directory, but this pattern style is deprecated. The correct way to match the file in any directory, including the current, is -`**/Rakefile`. +`+**/Rakefile+`. -The pattern `config/**` will match any file recursively under +The pattern `+config/**+` will match any file recursively under `config`, but this pattern style is deprecated and should be replaced by -`config/**/*`. +`+config/**/*+`. -#### `Include` and `Exclude` are relative to their directory +==== `Include` and `Exclude` are relative to their directory The `Include` and `Exclude` parameters are special. They are valid for the directory tree starting where they are defined. They are not shadowed by the setting of `Include` and `Exclude` in other `.rubocop.yml` files in subdirectories. This is different from all other parameters, who follow RuboCop's general principle that configuration for an inspected file -is taken from the nearest `.rubocop.yml`, searching upwards. _This behavior +is taken from the nearest `.rubocop.yml`, searching upwards. + +NOTE: This behavior will be overridden if you specify the `--ignore-parent-exclusion` command line -argument_. +argument. -#### Cop-specific `Include` and `Exclude` +=== Cop-specific `Include` and `Exclude` Cops can be run only on specific sets of files when that's needed (for instance you might want to run some Rails model checks only on files whose paths match `app/models/*.rb`). All cops support the `Include` param. -```yaml +[source,yaml] +---- Rails/HasAndBelongsToMany: Include: - app/models/*.rb -``` +---- Cops can also exclude only specific sets of files when that's needed (for instance you might want to run some cop only on a specific file). All cops support the `Exclude` param. -```yaml +[source,yaml] +---- Rails/HasAndBelongsToMany: Exclude: - app/models/problematic.rb -``` +---- -### Generic configuration parameters +== Generic configuration parameters In addition to `Include` and `Exclude`, the following parameters are available for every cop. -#### Enabled +=== Enabled Specific cops can be disabled by setting `Enabled` to `false` for that specific cop. -```yaml -Metrics/LineLength: +[source,yaml] +---- +Layout/LineLength: Enabled: false -``` +---- -Most cops are enabled by default. Some cops, configured the above `Enabled: false` -in [config/default.yml](https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml), +Most cops are enabled by default. Cops, introduced or significantly updated +between major versions, are in a special pending status (read more in +xref:versioning.adoc["Versioning"]). Some cops, configured the above `Enabled: false` +in https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml[config/default.yml], are disabled by default. The cop enabling process can be altered by setting `DisabledByDefault` or `EnabledByDefault` (but not both) to `true`. -```yaml +[source,yaml] +---- AllCops: DisabledByDefault: true -``` +---- All cops are then disabled by default. Only cops appearing in user configuration files are enabled. `Enabled: true` does not have to be set for cops in user configuration. They will be enabled anyway. It is also possible to enable entire departments by adding for example -```yaml +[source,yaml] +---- Style: Enabled: true -``` - -The exception to the rule is the `Rails` department, which can not be enabled -in its entirety this way. Setting `Rails: Enabled: true` will have the same -effect as running with the `--rails` command line option, which in the context -of `DisabledByDefault: true` means to make it possible to enable Rails cops -individually. - -```yaml -AllCops: - EnabledByDefault: true -``` +---- All cops are then enabled by default. Only cops explicitly disabled using `Enabled: false` in user configuration files are disabled. -#### Severity +If a department is disabled, cops in that department can still be individually +enabled, and that setting overrides the setting for its department in the same +configuration file and in any inherited file. + +[source,yaml] +---- +inherit_from: config_that_disables_the_metrics_department.yml + +Metrics/MethodLength: + Enabled: true + +Style: + Enabled: false + +Style/Alias: + Enabled: true +---- + +=== Severity Each cop has a default severity level based on which department it belongs to. The level is normally `warning` for `Lint` and `convention` for all the @@ -399,66 +503,73 @@ and `fatal`. There is one exception from the general rule above and that is `Lint/Syntax`, a special cop that checks for syntax errors before the other cops are invoked. It -can not be disabled and its severity (`fatal`) can not be changed in +cannot be disabled and its severity (`fatal`) cannot be changed in configuration. -```yaml +[source,yaml] +---- Lint: Severity: error Metrics/CyclomaticComplexity: Severity: warning -``` +---- -#### Details +=== Details Individual cops can be embellished with extra details in offense messages: -```yaml -Metrics/LineLength: +[source,yaml] +---- +Layout/LineLength: Details: >- If lines are too short, text becomes hard to read because you must constantly jump from one line to the next while reading. If lines are too long, the line jumping becomes too hard because you "lose the line" while going back to the start of the next line. 80 characters is a good compromise. -``` +---- -These details will only be seen when rubocop is run with the `--extra-details` flag or if `ExtraDetails` is set to true in your global rubocop configuration. +These details will only be seen when RuboCop is run with the `--extra-details` flag or if `ExtraDetails` is set to true in your global RuboCop configuration. -#### AutoCorrect +=== AutoCorrect Cops that support the `--auto-correct` option can have that support disabled. For example: -```yaml +[source,yaml] +---- Style/PerlBackrefs: AutoCorrect: false -``` +---- -### Setting the target Ruby version +== Setting the target Ruby version Some checks are dependent on the version of the Ruby interpreter which the -inspected code must run on. For example, enforcing using Ruby 2.3+ safe -navigation operator rather than `try` can help make your code shorter and -more consistent... _unless_ it must run on Ruby 2.2. +inspected code must run on. For example, enforcing using Ruby 2.6+ endless +ranges `foo[n..]` rather than `foo[n..-1]` can help make your code shorter and +more consistent... _unless_ it must run on e.g. Ruby 2.5. -If `.ruby-version` exists in the directory RuboCop is invoked in, RuboCop -will use the version specified by it. Otherwise, users may let RuboCop -know the oldest version of Ruby which your project supports with: +Users may let RuboCop know the oldest version of Ruby which your project +supports with: -```yaml +[source,yaml] +---- AllCops: - TargetRubyVersion: 2.2 -``` + TargetRubyVersion: 2.5 +---- -### Automatically Generated Configuration +Otherwise, RuboCop will then check your project for `.ruby-version` and +use the version specified by it. + +== Automatically Generated Configuration If you have a code base with an overwhelming amount of offenses, it can -be a good idea to use `rubocop --auto-gen-config` and add an -`inherit_from: .rubocop_todo.yml` in your `.rubocop.yml`. The generated -file `.rubocop_todo.yml` contains configuration to disable cops that -currently detect an offense in the code by excluding the offending +be a good idea to use `rubocop --auto-gen-config`, which creates +`.rubocop_todo.yml` and adds `inherit_from: .rubocop_todo.yml` in your +`.rubocop.yml`. The generated file `.rubocop_todo.yml` contains +configuration to disable cops that currently detect an offense in the +code by changing the configuration for the cop, excluding the offending files, or disabling the cop altogether once a file count limit has been reached. @@ -466,9 +577,21 @@ By adding the option `--exclude-limit COUNT`, e.g., `rubocop --auto-gen-config --exclude-limit 5`, you can change how many files are excluded before the cop is entirely disabled. The default COUNT is 15. +The next step is to cut and paste configuration from `.rubocop_todo.yml` +into `.rubocop.yml` for everything that you think is in line with your +(organization's) code style and not a good fit for a todo list. Pay +attention to the comments above each entry. They can reveal configuration +parameters such as `EnforcedStyle`, which can be used to modify the +behavior of a cop instead of disabling it completely. + Then you can start removing the entries in the generated `.rubocop_todo.yml` file one by one as you work through all the offenses -in the code. +in the code. You can also regenerate your `.rubocop_todo.yml` using +the same options by running `rubocop --regenerate-todo`. + +Another way of silencing offense reports, aside from configuration, is +through source code comments. These can be added manually or +automatically. See "Disabling Cops within Source Code" below. The cops in the `Metrics` department will by default get `Max` parameters generated in `.rubocop_todo.yml`. The value of these will be just high enough @@ -477,47 +600,116 @@ prefer to exclude files, like for other cops, add `--auto-gen-only-exclude` when running with `--auto-gen-config`. It will still change the maximum if the number of excluded files is higher than the exclude limit. -### Updating the configuration file +== Updating the configuration file When you update RuboCop version, sometimes you need to change `.rubocop.yml`. -If you use [mry](https://github.com/pocke/mry), you can update `.rubocop.yml` +If you use https://github.com/pocke/mry[mry], you can update `.rubocop.yml` to latest version automatically. - -```sh +[source,sh] +---- $ gem install mry # Update to latest version $ mry .rubocop.yml # Update to specified version $ mry --target=0.48.0 .rubocop.yml -``` +---- -See [https://github.com/pocke/mry](https://github.com/pocke/mry) for more information. +See https://github.com/pocke/mry for more information. -## Disabling Cops within Source Code +== 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 -```ruby -# rubocop:disable Metrics/LineLength, Style/StringLiterals +[source,ruby] +---- +# rubocop:disable Layout/LineLength, Style/StringLiterals [...] -# rubocop:enable Metrics/LineLength, Style/StringLiterals -``` +# rubocop:enable Layout/LineLength, Style/StringLiterals +---- -You can also disable *all* cops with +You can also disable _all_ cops with -```ruby +[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. -```ruby +[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 --[safe-]auto-correct --disable-uncorrectable` will +create comments to disable all offenses that can't be automatically +corrected. + +Do not write anything other than cop name in the disabling comment. E.g.: + +[source,ruby] +---- +# rubocop:disable Layout/LineLength --This is a bad comment that includes other than cop name. +---- + +== Setting the style guide URL + +You can specify the base URL of the style guide using `StyleGuideBaseURL`. +If specified under `AllCops`, all cops are targeted. + +[source,yaml] +---- +AllCops: + StyleGuideBaseURL: https://rubystyle.guide +---- + +`StyleGuideBaseURL` is combined with `StyleGuide` specified to the cop. + +[source,yaml] +---- +Lint/UselessAssignment: + StyleGuide: '#underscore-unused-vars' +---- + +The style guide URL is https://rubystyle.guide#underscore-unused-vars. + +If specified under a specific department, it takes precedence over `AllCops`. +The following is an example of specifying `Rails` department. + +[source,yaml] +---- +Rails: + StyleGuideBaseURL: https://rails.rubystyle.guide +---- + +[source,yaml] +---- +Rails/TimeZone: + StyleGuide: '#time' +---- -[1]: https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml +The style guide URL is https://rails.rubystyle.guide#time. diff --git a/docs/modules/ROOT/pages/contributing.adoc b/docs/modules/ROOT/pages/contributing.adoc new file mode 100644 index 000000000000..1f38e88e8b49 --- /dev/null +++ b/docs/modules/ROOT/pages/contributing.adoc @@ -0,0 +1,103 @@ += Contributing + +== Issues + +Report issues and suggest features and improvements on the +https://github.com/rubocop-hq/rubocop/issues[GitHub issue tracker]. + +If you want to file an issue (bug report or feature request), please provide all +the necessary info listed in our issue reporting template (it's loaded +automatically when you create a new GitHub issue). + +NOTE: Please, don't ask support-like questions on the issue tracker (e.g. "How +can I configure RuboCop to do X?" - use the xref:support.adoc[support channels] +instead. + +== Patches + +Patches in any form are always welcome! GitHub pull requests are even better! :-) + +Before submitting a patch or a pull request make sure all tests are +passing and that your patch is in line with the https://github.com/rubocop-hq/rubocop/blob/master/CONTRIBUTING.md[contribution +guidelines]. + +A handy way to test only the files that you have modified in the last commit +(with `rspec` and `rubocop`) is to use `rake check_commit`. + +Also see the xref:development.adoc[Development section]. + +== Documentation + +Good documentation is just as important as good code. +Please, help us improve RuboCop's documentation. + +You should also check out the +xref:development.adoc#documentation[cop documentation section] of the docs and consider +adding or improving Cop descriptions. + +=== Working on the Docs + +The manual is generated from the AsciiDoc files in the https://github.com/rubocop-hq/rubocop/tree/master/docs[docs] folder of RuboCop's GitHub repo and is published to https://docs.rubocop.org. +https://antora.org[Antora] is used to convert the manual into HTML. +The filesystem layout is described at https://docs.antora.org/antora/2.0/component-structure/. + +To make changes to the manual you simply have to change the files under `doc`. +The manual will be regenerated manually periodically. + +==== Installing Antora + +NOTE: The instructions here assume you already have (the right version of) node.js installed. + +Installing the Antora is super simple: + +[source] +---- +$ npm i -g @antora/cli@2.0 @antora/site-generator-default@2.0 +---- + +Check out https://docs.antora.org/antora/2.0/install/install-antora/[the detailed installation instructions] +if you run into any problems. + +==== Building the Site + +You can build the documentation locally from the https://github.com/rubocop-hq/docs.rubocop.org[docs.rubocop.org] repo. + +[source] +---- +$ cd docs.rubocop.org +$ antora --pull antora-playbook.yml +---- + +After you're done with the initial setup you can use the `deploy` script to push changes to the site: + +[source] +---- +./deploy +---- + +NOTE: You'll need commit access to the repository for this to work. + +To check the generated site you can simply open `docs/index.html` in your favourite browser. + +If you want to make changes to the manual's page structure you'll have to edit +https://github.com/rubocop-hq/rubocop/blob/master/docs/modules/ROOT/nav.adoc[nav.adoc]. + +== Funding + +While RuboCop is free software and will always be, the project would benefit immensely from some funding. +Raising a monthly budget of a couple of thousand dollars would make it possible to pay people to work on +certain complex features, fund other development related stuff (e.g. hardware, conference trips) and so on. +Raising a monthly budget of over $5000 would open the possibility of someone working full-time on the project +which would speed up the pace of development significantly. + +We welcome both individual and corporate sponsors! We also offer a wide array of funding channels to account +for your preferences (although currently https://opencollective.com/rubocop[Open Collective] is our preferred funding platform). + +If you're working in a company that's making significant use of RuboCop we'd appreciate it if you suggest to your company +to become a RuboCop sponsor. + +You can support the development of RuboCop via +https://github.com/sponsors/bbatsov[GitHub Sponsors], +https://www.patreon.com/bbatsov[Patreon], +https://paypal.me/bbatsov[PayPal], +and https://opencollective.com/rubocop[Open Collective]. diff --git a/docs/modules/ROOT/pages/cops.adoc b/docs/modules/ROOT/pages/cops.adoc new file mode 100644 index 000000000000..80a3f3de169c --- /dev/null +++ b/docs/modules/ROOT/pages/cops.adoc @@ -0,0 +1,533 @@ += Cops + +In RuboCop lingo the various checks performed on the code are called cops. +Each cop is responsible for detecting one particular offense. There are several +cop departments, grouping the cops by class of offense. A short description of +the different departments is provided below. + +Many of the Style and Layout cops have configuration options, allowing them to +enforce different coding conventions. + +You can also load xref:extensions.adoc#custom-cops[custom cops]. + +== Style + +Style cops check for stylistic consistency of your code. Many of the them are +based on the https://rubystyle.guide[Ruby Style Guide]. + +== Layout + +Layout cops inspect your code for consistent use of indentation, alignment, +and white space. + +== Lint + +Lint cops check for ambiguities and possible errors in your code. + +RuboCop implements, in a portable way, all built-in MRI lint checks +(`ruby -wc`) and adds a lot of extra lint checks of its own. + +You can run only the Lint cops like this: + +[source,sh] +---- +$ rubocop -l +---- + +The `-l`/`--lint` option can be used together with `--only` to run all the +enabled Lint cops plus a selection of other cops. + +Disabling Lint cops is generally a bad idea. + +== Metrics + +Metrics cops deal with properties of the source code that can be measured, +such as class length, method length, etc. Generally speaking, they have a +configuration parameter called `Max` and when running +`rubocop --auto-gen-config`, this parameter will be set to the highest value +found for the inspected code. + +== Naming + +Naming cops check for naming issue of your code, such as method name, constant +name, file name, etc. + +== Security + +Security cops checks for method calls and constructs which are known to be +associated with potential security issues. + +== Bundler + +Bundler cops check for style and bad practices in Bundler files, e.g. `Gemfile`. + +== Gemspec + +Gemspec cops check for style and bad practices in gemspec files, e.g. `rubocop.gemspec`. + +== Available cops + +In the following section you find all available cops: + +// START_COP_LIST + +=== Department xref:cops_bundler.adoc[Bundler] + +* xref:cops_bundler.adoc#bundlerduplicatedgem[Bundler/DuplicatedGem] +* xref:cops_bundler.adoc#bundlergemcomment[Bundler/GemComment] +* xref:cops_bundler.adoc#bundlerinsecureprotocolsource[Bundler/InsecureProtocolSource] +* xref:cops_bundler.adoc#bundlerorderedgems[Bundler/OrderedGems] + +=== Department xref:cops_gemspec.adoc[Gemspec] + +* xref:cops_gemspec.adoc#gemspecduplicatedassignment[Gemspec/DuplicatedAssignment] +* xref:cops_gemspec.adoc#gemspecordereddependencies[Gemspec/OrderedDependencies] +* xref:cops_gemspec.adoc#gemspecrequiredrubyversion[Gemspec/RequiredRubyVersion] +* xref:cops_gemspec.adoc#gemspecrubyversionglobalsusage[Gemspec/RubyVersionGlobalsUsage] + +=== Department xref:cops_layout.adoc[Layout] + +* xref:cops_layout.adoc#layoutaccessmodifierindentation[Layout/AccessModifierIndentation] +* xref:cops_layout.adoc#layoutargumentalignment[Layout/ArgumentAlignment] +* xref:cops_layout.adoc#layoutarrayalignment[Layout/ArrayAlignment] +* xref:cops_layout.adoc#layoutassignmentindentation[Layout/AssignmentIndentation] +* xref:cops_layout.adoc#layoutbeginendalignment[Layout/BeginEndAlignment] +* xref:cops_layout.adoc#layoutblockalignment[Layout/BlockAlignment] +* xref:cops_layout.adoc#layoutblockendnewline[Layout/BlockEndNewline] +* xref:cops_layout.adoc#layoutcaseindentation[Layout/CaseIndentation] +* xref:cops_layout.adoc#layoutclassstructure[Layout/ClassStructure] +* xref:cops_layout.adoc#layoutclosingheredocindentation[Layout/ClosingHeredocIndentation] +* xref:cops_layout.adoc#layoutclosingparenthesisindentation[Layout/ClosingParenthesisIndentation] +* xref:cops_layout.adoc#layoutcommentindentation[Layout/CommentIndentation] +* xref:cops_layout.adoc#layoutconditionposition[Layout/ConditionPosition] +* xref:cops_layout.adoc#layoutdefendalignment[Layout/DefEndAlignment] +* xref:cops_layout.adoc#layoutdotposition[Layout/DotPosition] +* xref:cops_layout.adoc#layoutelsealignment[Layout/ElseAlignment] +* xref:cops_layout.adoc#layoutemptycomment[Layout/EmptyComment] +* xref:cops_layout.adoc#layoutemptylineafterguardclause[Layout/EmptyLineAfterGuardClause] +* xref:cops_layout.adoc#layoutemptylineaftermagiccomment[Layout/EmptyLineAfterMagicComment] +* xref:cops_layout.adoc#layoutemptylineaftermultilinecondition[Layout/EmptyLineAfterMultilineCondition] +* xref:cops_layout.adoc#layoutemptylinebetweendefs[Layout/EmptyLineBetweenDefs] +* xref:cops_layout.adoc#layoutemptylines[Layout/EmptyLines] +* xref:cops_layout.adoc#layoutemptylinesaroundaccessmodifier[Layout/EmptyLinesAroundAccessModifier] +* xref:cops_layout.adoc#layoutemptylinesaroundarguments[Layout/EmptyLinesAroundArguments] +* xref:cops_layout.adoc#layoutemptylinesaroundattributeaccessor[Layout/EmptyLinesAroundAttributeAccessor] +* xref:cops_layout.adoc#layoutemptylinesaroundbeginbody[Layout/EmptyLinesAroundBeginBody] +* xref:cops_layout.adoc#layoutemptylinesaroundblockbody[Layout/EmptyLinesAroundBlockBody] +* xref:cops_layout.adoc#layoutemptylinesaroundclassbody[Layout/EmptyLinesAroundClassBody] +* xref:cops_layout.adoc#layoutemptylinesaroundexceptionhandlingkeywords[Layout/EmptyLinesAroundExceptionHandlingKeywords] +* xref:cops_layout.adoc#layoutemptylinesaroundmethodbody[Layout/EmptyLinesAroundMethodBody] +* xref:cops_layout.adoc#layoutemptylinesaroundmodulebody[Layout/EmptyLinesAroundModuleBody] +* xref:cops_layout.adoc#layoutendalignment[Layout/EndAlignment] +* xref:cops_layout.adoc#layoutendofline[Layout/EndOfLine] +* xref:cops_layout.adoc#layoutextraspacing[Layout/ExtraSpacing] +* xref:cops_layout.adoc#layoutfirstargumentindentation[Layout/FirstArgumentIndentation] +* xref:cops_layout.adoc#layoutfirstarrayelementindentation[Layout/FirstArrayElementIndentation] +* xref:cops_layout.adoc#layoutfirstarrayelementlinebreak[Layout/FirstArrayElementLineBreak] +* xref:cops_layout.adoc#layoutfirsthashelementindentation[Layout/FirstHashElementIndentation] +* xref:cops_layout.adoc#layoutfirsthashelementlinebreak[Layout/FirstHashElementLineBreak] +* xref:cops_layout.adoc#layoutfirstmethodargumentlinebreak[Layout/FirstMethodArgumentLineBreak] +* xref:cops_layout.adoc#layoutfirstmethodparameterlinebreak[Layout/FirstMethodParameterLineBreak] +* xref:cops_layout.adoc#layoutfirstparameterindentation[Layout/FirstParameterIndentation] +* xref:cops_layout.adoc#layouthashalignment[Layout/HashAlignment] +* xref:cops_layout.adoc#layoutheredocargumentclosingparenthesis[Layout/HeredocArgumentClosingParenthesis] +* xref:cops_layout.adoc#layoutheredocindentation[Layout/HeredocIndentation] +* xref:cops_layout.adoc#layoutindentationconsistency[Layout/IndentationConsistency] +* xref:cops_layout.adoc#layoutindentationstyle[Layout/IndentationStyle] +* xref:cops_layout.adoc#layoutindentationwidth[Layout/IndentationWidth] +* xref:cops_layout.adoc#layoutinitialindentation[Layout/InitialIndentation] +* xref:cops_layout.adoc#layoutleadingcommentspace[Layout/LeadingCommentSpace] +* xref:cops_layout.adoc#layoutleadingemptylines[Layout/LeadingEmptyLines] +* xref:cops_layout.adoc#layoutlinelength[Layout/LineLength] +* xref:cops_layout.adoc#layoutmultilinearraybracelayout[Layout/MultilineArrayBraceLayout] +* xref:cops_layout.adoc#layoutmultilinearraylinebreaks[Layout/MultilineArrayLineBreaks] +* xref:cops_layout.adoc#layoutmultilineassignmentlayout[Layout/MultilineAssignmentLayout] +* xref:cops_layout.adoc#layoutmultilineblocklayout[Layout/MultilineBlockLayout] +* xref:cops_layout.adoc#layoutmultilinehashbracelayout[Layout/MultilineHashBraceLayout] +* xref:cops_layout.adoc#layoutmultilinehashkeylinebreaks[Layout/MultilineHashKeyLineBreaks] +* xref:cops_layout.adoc#layoutmultilinemethodargumentlinebreaks[Layout/MultilineMethodArgumentLineBreaks] +* xref:cops_layout.adoc#layoutmultilinemethodcallbracelayout[Layout/MultilineMethodCallBraceLayout] +* xref:cops_layout.adoc#layoutmultilinemethodcallindentation[Layout/MultilineMethodCallIndentation] +* xref:cops_layout.adoc#layoutmultilinemethoddefinitionbracelayout[Layout/MultilineMethodDefinitionBraceLayout] +* xref:cops_layout.adoc#layoutmultilineoperationindentation[Layout/MultilineOperationIndentation] +* xref:cops_layout.adoc#layoutparameteralignment[Layout/ParameterAlignment] +* xref:cops_layout.adoc#layoutrescueensurealignment[Layout/RescueEnsureAlignment] +* xref:cops_layout.adoc#layoutspaceaftercolon[Layout/SpaceAfterColon] +* xref:cops_layout.adoc#layoutspaceaftercomma[Layout/SpaceAfterComma] +* xref:cops_layout.adoc#layoutspaceaftermethodname[Layout/SpaceAfterMethodName] +* xref:cops_layout.adoc#layoutspaceafternot[Layout/SpaceAfterNot] +* xref:cops_layout.adoc#layoutspaceaftersemicolon[Layout/SpaceAfterSemicolon] +* xref:cops_layout.adoc#layoutspacearoundblockparameters[Layout/SpaceAroundBlockParameters] +* xref:cops_layout.adoc#layoutspacearoundequalsinparameterdefault[Layout/SpaceAroundEqualsInParameterDefault] +* xref:cops_layout.adoc#layoutspacearoundkeyword[Layout/SpaceAroundKeyword] +* xref:cops_layout.adoc#layoutspacearoundmethodcalloperator[Layout/SpaceAroundMethodCallOperator] +* xref:cops_layout.adoc#layoutspacearoundoperators[Layout/SpaceAroundOperators] +* xref:cops_layout.adoc#layoutspacebeforeblockbraces[Layout/SpaceBeforeBlockBraces] +* xref:cops_layout.adoc#layoutspacebeforecomma[Layout/SpaceBeforeComma] +* xref:cops_layout.adoc#layoutspacebeforecomment[Layout/SpaceBeforeComment] +* xref:cops_layout.adoc#layoutspacebeforefirstarg[Layout/SpaceBeforeFirstArg] +* xref:cops_layout.adoc#layoutspacebeforesemicolon[Layout/SpaceBeforeSemicolon] +* xref:cops_layout.adoc#layoutspaceinlambdaliteral[Layout/SpaceInLambdaLiteral] +* xref:cops_layout.adoc#layoutspaceinsidearrayliteralbrackets[Layout/SpaceInsideArrayLiteralBrackets] +* xref:cops_layout.adoc#layoutspaceinsidearraypercentliteral[Layout/SpaceInsideArrayPercentLiteral] +* xref:cops_layout.adoc#layoutspaceinsideblockbraces[Layout/SpaceInsideBlockBraces] +* xref:cops_layout.adoc#layoutspaceinsidehashliteralbraces[Layout/SpaceInsideHashLiteralBraces] +* xref:cops_layout.adoc#layoutspaceinsideparens[Layout/SpaceInsideParens] +* xref:cops_layout.adoc#layoutspaceinsidepercentliteraldelimiters[Layout/SpaceInsidePercentLiteralDelimiters] +* xref:cops_layout.adoc#layoutspaceinsiderangeliteral[Layout/SpaceInsideRangeLiteral] +* xref:cops_layout.adoc#layoutspaceinsidereferencebrackets[Layout/SpaceInsideReferenceBrackets] +* xref:cops_layout.adoc#layoutspaceinsidestringinterpolation[Layout/SpaceInsideStringInterpolation] +* xref:cops_layout.adoc#layouttrailingemptylines[Layout/TrailingEmptyLines] +* xref:cops_layout.adoc#layouttrailingwhitespace[Layout/TrailingWhitespace] + +=== Department xref:cops_lint.adoc[Lint] + +* xref:cops_lint.adoc#lintambiguousblockassociation[Lint/AmbiguousBlockAssociation] +* xref:cops_lint.adoc#lintambiguousoperator[Lint/AmbiguousOperator] +* xref:cops_lint.adoc#lintambiguousregexpliteral[Lint/AmbiguousRegexpLiteral] +* xref:cops_lint.adoc#lintassignmentincondition[Lint/AssignmentInCondition] +* xref:cops_lint.adoc#lintbigdecimalnew[Lint/BigDecimalNew] +* xref:cops_lint.adoc#lintbinaryoperatorwithidenticaloperands[Lint/BinaryOperatorWithIdenticalOperands] +* xref:cops_lint.adoc#lintbooleansymbol[Lint/BooleanSymbol] +* xref:cops_lint.adoc#lintcircularargumentreference[Lint/CircularArgumentReference] +* xref:cops_lint.adoc#lintconstantdefinitioninblock[Lint/ConstantDefinitionInBlock] +* xref:cops_lint.adoc#lintconstantresolution[Lint/ConstantResolution] +* xref:cops_lint.adoc#lintdebugger[Lint/Debugger] +* xref:cops_lint.adoc#lintdeprecatedclassmethods[Lint/DeprecatedClassMethods] +* xref:cops_lint.adoc#lintdeprecatedopensslconstant[Lint/DeprecatedOpenSSLConstant] +* xref:cops_lint.adoc#lintdisjunctiveassignmentinconstructor[Lint/DisjunctiveAssignmentInConstructor] +* xref:cops_lint.adoc#lintduplicatecasecondition[Lint/DuplicateCaseCondition] +* xref:cops_lint.adoc#lintduplicateelsifcondition[Lint/DuplicateElsifCondition] +* xref:cops_lint.adoc#lintduplicatehashkey[Lint/DuplicateHashKey] +* xref:cops_lint.adoc#lintduplicatemethods[Lint/DuplicateMethods] +* xref:cops_lint.adoc#lintduplicaterequire[Lint/DuplicateRequire] +* xref:cops_lint.adoc#lintduplicaterescueexception[Lint/DuplicateRescueException] +* xref:cops_lint.adoc#linteachwithobjectargument[Lint/EachWithObjectArgument] +* xref:cops_lint.adoc#lintelselayout[Lint/ElseLayout] +* xref:cops_lint.adoc#lintemptyconditionalbody[Lint/EmptyConditionalBody] +* xref:cops_lint.adoc#lintemptyensure[Lint/EmptyEnsure] +* xref:cops_lint.adoc#lintemptyexpression[Lint/EmptyExpression] +* xref:cops_lint.adoc#lintemptyfile[Lint/EmptyFile] +* xref:cops_lint.adoc#lintemptyinterpolation[Lint/EmptyInterpolation] +* xref:cops_lint.adoc#lintemptywhen[Lint/EmptyWhen] +* xref:cops_lint.adoc#lintensurereturn[Lint/EnsureReturn] +* xref:cops_lint.adoc#linterbnewarguments[Lint/ErbNewArguments] +* xref:cops_lint.adoc#lintflipflop[Lint/FlipFlop] +* xref:cops_lint.adoc#lintfloatcomparison[Lint/FloatComparison] +* xref:cops_lint.adoc#lintfloatoutofrange[Lint/FloatOutOfRange] +* xref:cops_lint.adoc#lintformatparametermismatch[Lint/FormatParameterMismatch] +* xref:cops_lint.adoc#linthashcomparebyidentity[Lint/HashCompareByIdentity] +* xref:cops_lint.adoc#lintheredocmethodcallposition[Lint/HeredocMethodCallPosition] +* xref:cops_lint.adoc#lintidentitycomparison[Lint/IdentityComparison] +* xref:cops_lint.adoc#lintimplicitstringconcatenation[Lint/ImplicitStringConcatenation] +* xref:cops_lint.adoc#lintineffectiveaccessmodifier[Lint/IneffectiveAccessModifier] +* xref:cops_lint.adoc#lintinheritexception[Lint/InheritException] +* xref:cops_lint.adoc#lintinterpolationcheck[Lint/InterpolationCheck] +* xref:cops_lint.adoc#lintliteralascondition[Lint/LiteralAsCondition] +* xref:cops_lint.adoc#lintliteralininterpolation[Lint/LiteralInInterpolation] +* xref:cops_lint.adoc#lintloop[Lint/Loop] +* xref:cops_lint.adoc#lintmissingcopenabledirective[Lint/MissingCopEnableDirective] +* xref:cops_lint.adoc#lintmissingsuper[Lint/MissingSuper] +* xref:cops_lint.adoc#lintmixedregexpcapturetypes[Lint/MixedRegexpCaptureTypes] +* xref:cops_lint.adoc#lintmultiplecomparison[Lint/MultipleComparison] +* xref:cops_lint.adoc#lintnestedmethoddefinition[Lint/NestedMethodDefinition] +* xref:cops_lint.adoc#lintnestedpercentliteral[Lint/NestedPercentLiteral] +* xref:cops_lint.adoc#lintnextwithoutaccumulator[Lint/NextWithoutAccumulator] +* xref:cops_lint.adoc#lintnondeterministicrequireorder[Lint/NonDeterministicRequireOrder] +* xref:cops_lint.adoc#lintnonlocalexitfromiterator[Lint/NonLocalExitFromIterator] +* xref:cops_lint.adoc#lintnumberconversion[Lint/NumberConversion] +* xref:cops_lint.adoc#lintorderedmagiccomments[Lint/OrderedMagicComments] +* xref:cops_lint.adoc#lintoutofrangeregexpref[Lint/OutOfRangeRegexpRef] +* xref:cops_lint.adoc#lintparenthesesasgroupedexpression[Lint/ParenthesesAsGroupedExpression] +* xref:cops_lint.adoc#lintpercentstringarray[Lint/PercentStringArray] +* xref:cops_lint.adoc#lintpercentsymbolarray[Lint/PercentSymbolArray] +* xref:cops_lint.adoc#lintraiseexception[Lint/RaiseException] +* xref:cops_lint.adoc#lintrandone[Lint/RandOne] +* xref:cops_lint.adoc#lintredundantcopdisabledirective[Lint/RedundantCopDisableDirective] +* xref:cops_lint.adoc#lintredundantcopenabledirective[Lint/RedundantCopEnableDirective] +* xref:cops_lint.adoc#lintredundantrequirestatement[Lint/RedundantRequireStatement] +* xref:cops_lint.adoc#lintredundantsafenavigation[Lint/RedundantSafeNavigation] +* xref:cops_lint.adoc#lintredundantsplatexpansion[Lint/RedundantSplatExpansion] +* xref:cops_lint.adoc#lintredundantstringcoercion[Lint/RedundantStringCoercion] +* xref:cops_lint.adoc#lintredundantwithindex[Lint/RedundantWithIndex] +* xref:cops_lint.adoc#lintredundantwithobject[Lint/RedundantWithObject] +* xref:cops_lint.adoc#lintregexpascondition[Lint/RegexpAsCondition] +* xref:cops_lint.adoc#lintrequireparentheses[Lint/RequireParentheses] +* xref:cops_lint.adoc#lintrescueexception[Lint/RescueException] +* xref:cops_lint.adoc#lintrescuetype[Lint/RescueType] +* xref:cops_lint.adoc#lintreturninvoidcontext[Lint/ReturnInVoidContext] +* xref:cops_lint.adoc#lintsafenavigationchain[Lint/SafeNavigationChain] +* xref:cops_lint.adoc#lintsafenavigationconsistency[Lint/SafeNavigationConsistency] +* xref:cops_lint.adoc#lintsafenavigationwithempty[Lint/SafeNavigationWithEmpty] +* xref:cops_lint.adoc#lintscriptpermission[Lint/ScriptPermission] +* xref:cops_lint.adoc#lintselfassignment[Lint/SelfAssignment] +* xref:cops_lint.adoc#lintsendwithmixinargument[Lint/SendWithMixinArgument] +* xref:cops_lint.adoc#lintshadowedargument[Lint/ShadowedArgument] +* xref:cops_lint.adoc#lintshadowedexception[Lint/ShadowedException] +* xref:cops_lint.adoc#lintshadowingouterlocalvariable[Lint/ShadowingOuterLocalVariable] +* xref:cops_lint.adoc#lintstructnewoverride[Lint/StructNewOverride] +* xref:cops_lint.adoc#lintsuppressedexception[Lint/SuppressedException] +* xref:cops_lint.adoc#lintsyntax[Lint/Syntax] +* xref:cops_lint.adoc#linttojson[Lint/ToJSON] +* xref:cops_lint.adoc#linttoplevelreturnwithargument[Lint/TopLevelReturnWithArgument] +* xref:cops_lint.adoc#linttrailingcommainattributedeclaration[Lint/TrailingCommaInAttributeDeclaration] +* xref:cops_lint.adoc#lintunderscoreprefixedvariablename[Lint/UnderscorePrefixedVariableName] +* xref:cops_lint.adoc#lintunifiedinteger[Lint/UnifiedInteger] +* xref:cops_lint.adoc#lintunreachablecode[Lint/UnreachableCode] +* xref:cops_lint.adoc#lintunreachableloop[Lint/UnreachableLoop] +* xref:cops_lint.adoc#lintunusedblockargument[Lint/UnusedBlockArgument] +* xref:cops_lint.adoc#lintunusedmethodargument[Lint/UnusedMethodArgument] +* xref:cops_lint.adoc#linturiescapeunescape[Lint/UriEscapeUnescape] +* xref:cops_lint.adoc#linturiregexp[Lint/UriRegexp] +* xref:cops_lint.adoc#lintuselessaccessmodifier[Lint/UselessAccessModifier] +* xref:cops_lint.adoc#lintuselessassignment[Lint/UselessAssignment] +* xref:cops_lint.adoc#lintuselesselsewithoutrescue[Lint/UselessElseWithoutRescue] +* xref:cops_lint.adoc#lintuselessmethoddefinition[Lint/UselessMethodDefinition] +* xref:cops_lint.adoc#lintuselesssettercall[Lint/UselessSetterCall] +* xref:cops_lint.adoc#lintuselesstimes[Lint/UselessTimes] +* xref:cops_lint.adoc#lintvoid[Lint/Void] + +=== Department xref:cops_metrics.adoc[Metrics] + +* xref:cops_metrics.adoc#metricsabcsize[Metrics/AbcSize] +* xref:cops_metrics.adoc#metricsblocklength[Metrics/BlockLength] +* xref:cops_metrics.adoc#metricsblocknesting[Metrics/BlockNesting] +* xref:cops_metrics.adoc#metricsclasslength[Metrics/ClassLength] +* xref:cops_metrics.adoc#metricscyclomaticcomplexity[Metrics/CyclomaticComplexity] +* xref:cops_metrics.adoc#metricsmethodlength[Metrics/MethodLength] +* xref:cops_metrics.adoc#metricsmodulelength[Metrics/ModuleLength] +* xref:cops_metrics.adoc#metricsparameterlists[Metrics/ParameterLists] +* xref:cops_metrics.adoc#metricsperceivedcomplexity[Metrics/PerceivedComplexity] + +=== Department xref:cops_migration.adoc[Migration] + +* xref:cops_migration.adoc#migrationdepartmentname[Migration/DepartmentName] + +=== Department xref:cops_naming.adoc[Naming] + +* xref:cops_naming.adoc#namingaccessormethodname[Naming/AccessorMethodName] +* xref:cops_naming.adoc#namingasciiidentifiers[Naming/AsciiIdentifiers] +* xref:cops_naming.adoc#namingbinaryoperatorparametername[Naming/BinaryOperatorParameterName] +* xref:cops_naming.adoc#namingblockparametername[Naming/BlockParameterName] +* xref:cops_naming.adoc#namingclassandmodulecamelcase[Naming/ClassAndModuleCamelCase] +* xref:cops_naming.adoc#namingconstantname[Naming/ConstantName] +* xref:cops_naming.adoc#namingfilename[Naming/FileName] +* xref:cops_naming.adoc#namingheredocdelimitercase[Naming/HeredocDelimiterCase] +* xref:cops_naming.adoc#namingheredocdelimiternaming[Naming/HeredocDelimiterNaming] +* xref:cops_naming.adoc#namingmemoizedinstancevariablename[Naming/MemoizedInstanceVariableName] +* xref:cops_naming.adoc#namingmethodname[Naming/MethodName] +* xref:cops_naming.adoc#namingmethodparametername[Naming/MethodParameterName] +* xref:cops_naming.adoc#namingpredicatename[Naming/PredicateName] +* xref:cops_naming.adoc#namingrescuedexceptionsvariablename[Naming/RescuedExceptionsVariableName] +* xref:cops_naming.adoc#namingvariablename[Naming/VariableName] +* xref:cops_naming.adoc#namingvariablenumber[Naming/VariableNumber] + +=== Department xref:cops_security.adoc[Security] + +* xref:cops_security.adoc#securityeval[Security/Eval] +* xref:cops_security.adoc#securityjsonload[Security/JSONLoad] +* xref:cops_security.adoc#securitymarshalload[Security/MarshalLoad] +* xref:cops_security.adoc#securityopen[Security/Open] +* xref:cops_security.adoc#securityyamlload[Security/YAMLLoad] + +=== Department xref:cops_style.adoc[Style] + +* xref:cops_style.adoc#styleaccessmodifierdeclarations[Style/AccessModifierDeclarations] +* xref:cops_style.adoc#styleaccessorgrouping[Style/AccessorGrouping] +* xref:cops_style.adoc#stylealias[Style/Alias] +* xref:cops_style.adoc#styleandor[Style/AndOr] +* xref:cops_style.adoc#stylearraycoercion[Style/ArrayCoercion] +* xref:cops_style.adoc#stylearrayjoin[Style/ArrayJoin] +* xref:cops_style.adoc#styleasciicomments[Style/AsciiComments] +* xref:cops_style.adoc#styleattr[Style/Attr] +* xref:cops_style.adoc#styleautoresourcecleanup[Style/AutoResourceCleanup] +* xref:cops_style.adoc#stylebarepercentliterals[Style/BarePercentLiterals] +* xref:cops_style.adoc#stylebeginblock[Style/BeginBlock] +* xref:cops_style.adoc#stylebisectedattraccessor[Style/BisectedAttrAccessor] +* xref:cops_style.adoc#styleblockcomments[Style/BlockComments] +* xref:cops_style.adoc#styleblockdelimiters[Style/BlockDelimiters] +* xref:cops_style.adoc#stylecaseequality[Style/CaseEquality] +* xref:cops_style.adoc#stylecaselikeif[Style/CaseLikeIf] +* xref:cops_style.adoc#stylecharacterliteral[Style/CharacterLiteral] +* xref:cops_style.adoc#styleclassandmodulechildren[Style/ClassAndModuleChildren] +* xref:cops_style.adoc#styleclasscheck[Style/ClassCheck] +* xref:cops_style.adoc#styleclassequalitycomparison[Style/ClassEqualityComparison] +* xref:cops_style.adoc#styleclassmethods[Style/ClassMethods] +* xref:cops_style.adoc#styleclassmethodsdefinitions[Style/ClassMethodsDefinitions] +* xref:cops_style.adoc#styleclassvars[Style/ClassVars] +* xref:cops_style.adoc#stylecollectionmethods[Style/CollectionMethods] +* xref:cops_style.adoc#stylecolonmethodcall[Style/ColonMethodCall] +* xref:cops_style.adoc#stylecolonmethoddefinition[Style/ColonMethodDefinition] +* xref:cops_style.adoc#stylecombinableloops[Style/CombinableLoops] +* xref:cops_style.adoc#stylecommandliteral[Style/CommandLiteral] +* xref:cops_style.adoc#stylecommentannotation[Style/CommentAnnotation] +* xref:cops_style.adoc#stylecommentedkeyword[Style/CommentedKeyword] +* xref:cops_style.adoc#styleconditionalassignment[Style/ConditionalAssignment] +* xref:cops_style.adoc#styleconstantvisibility[Style/ConstantVisibility] +* xref:cops_style.adoc#stylecopyright[Style/Copyright] +* xref:cops_style.adoc#styledatetime[Style/DateTime] +* xref:cops_style.adoc#styledefwithparentheses[Style/DefWithParentheses] +* xref:cops_style.adoc#styledir[Style/Dir] +* xref:cops_style.adoc#styledisablecopswithinsourcecodedirective[Style/DisableCopsWithinSourceCodeDirective] +* xref:cops_style.adoc#styledocumentation[Style/Documentation] +* xref:cops_style.adoc#styledocumentationmethod[Style/DocumentationMethod] +* xref:cops_style.adoc#styledoublecopdisabledirective[Style/DoubleCopDisableDirective] +* xref:cops_style.adoc#styledoublenegation[Style/DoubleNegation] +* xref:cops_style.adoc#styleeachforsimpleloop[Style/EachForSimpleLoop] +* xref:cops_style.adoc#styleeachwithobject[Style/EachWithObject] +* xref:cops_style.adoc#styleemptyblockparameter[Style/EmptyBlockParameter] +* xref:cops_style.adoc#styleemptycasecondition[Style/EmptyCaseCondition] +* xref:cops_style.adoc#styleemptyelse[Style/EmptyElse] +* xref:cops_style.adoc#styleemptylambdaparameter[Style/EmptyLambdaParameter] +* xref:cops_style.adoc#styleemptyliteral[Style/EmptyLiteral] +* xref:cops_style.adoc#styleemptymethod[Style/EmptyMethod] +* xref:cops_style.adoc#styleencoding[Style/Encoding] +* xref:cops_style.adoc#styleendblock[Style/EndBlock] +* xref:cops_style.adoc#styleevalwithlocation[Style/EvalWithLocation] +* xref:cops_style.adoc#styleevenodd[Style/EvenOdd] +* xref:cops_style.adoc#styleexpandpatharguments[Style/ExpandPathArguments] +* xref:cops_style.adoc#styleexplicitblockargument[Style/ExplicitBlockArgument] +* xref:cops_style.adoc#styleexponentialnotation[Style/ExponentialNotation] +* xref:cops_style.adoc#stylefloatdivision[Style/FloatDivision] +* xref:cops_style.adoc#stylefor[Style/For] +* xref:cops_style.adoc#styleformatstring[Style/FormatString] +* xref:cops_style.adoc#styleformatstringtoken[Style/FormatStringToken] +* xref:cops_style.adoc#stylefrozenstringliteralcomment[Style/FrozenStringLiteralComment] +* xref:cops_style.adoc#styleglobalstdstream[Style/GlobalStdStream] +* xref:cops_style.adoc#styleglobalvars[Style/GlobalVars] +* xref:cops_style.adoc#styleguardclause[Style/GuardClause] +* xref:cops_style.adoc#stylehashaslastarrayitem[Style/HashAsLastArrayItem] +* xref:cops_style.adoc#stylehasheachmethods[Style/HashEachMethods] +* xref:cops_style.adoc#stylehashlikecase[Style/HashLikeCase] +* xref:cops_style.adoc#stylehashsyntax[Style/HashSyntax] +* xref:cops_style.adoc#stylehashtransformkeys[Style/HashTransformKeys] +* xref:cops_style.adoc#stylehashtransformvalues[Style/HashTransformValues] +* xref:cops_style.adoc#styleidenticalconditionalbranches[Style/IdenticalConditionalBranches] +* xref:cops_style.adoc#styleifinsideelse[Style/IfInsideElse] +* xref:cops_style.adoc#styleifunlessmodifier[Style/IfUnlessModifier] +* xref:cops_style.adoc#styleifunlessmodifierofifunless[Style/IfUnlessModifierOfIfUnless] +* xref:cops_style.adoc#styleifwithsemicolon[Style/IfWithSemicolon] +* xref:cops_style.adoc#styleimplicitruntimeerror[Style/ImplicitRuntimeError] +* xref:cops_style.adoc#styleinfiniteloop[Style/InfiniteLoop] +* xref:cops_style.adoc#styleinlinecomment[Style/InlineComment] +* xref:cops_style.adoc#styleinversemethods[Style/InverseMethods] +* xref:cops_style.adoc#styleipaddresses[Style/IpAddresses] +* xref:cops_style.adoc#stylekeywordparametersorder[Style/KeywordParametersOrder] +* xref:cops_style.adoc#stylelambda[Style/Lambda] +* xref:cops_style.adoc#stylelambdacall[Style/LambdaCall] +* xref:cops_style.adoc#stylelineendconcatenation[Style/LineEndConcatenation] +* xref:cops_style.adoc#stylemethodcallwithargsparentheses[Style/MethodCallWithArgsParentheses] +* xref:cops_style.adoc#stylemethodcallwithoutargsparentheses[Style/MethodCallWithoutArgsParentheses] +* xref:cops_style.adoc#stylemethodcalledondoendblock[Style/MethodCalledOnDoEndBlock] +* xref:cops_style.adoc#stylemethoddefparentheses[Style/MethodDefParentheses] +* xref:cops_style.adoc#styleminmax[Style/MinMax] +* xref:cops_style.adoc#stylemissingelse[Style/MissingElse] +* xref:cops_style.adoc#stylemissingrespondtomissing[Style/MissingRespondToMissing] +* xref:cops_style.adoc#stylemixingrouping[Style/MixinGrouping] +* xref:cops_style.adoc#stylemixinusage[Style/MixinUsage] +* xref:cops_style.adoc#stylemodulefunction[Style/ModuleFunction] +* xref:cops_style.adoc#stylemultilineblockchain[Style/MultilineBlockChain] +* xref:cops_style.adoc#stylemultilineifmodifier[Style/MultilineIfModifier] +* xref:cops_style.adoc#stylemultilineifthen[Style/MultilineIfThen] +* xref:cops_style.adoc#stylemultilinememoization[Style/MultilineMemoization] +* xref:cops_style.adoc#stylemultilinemethodsignature[Style/MultilineMethodSignature] +* xref:cops_style.adoc#stylemultilineternaryoperator[Style/MultilineTernaryOperator] +* xref:cops_style.adoc#stylemultilinewhenthen[Style/MultilineWhenThen] +* xref:cops_style.adoc#stylemultiplecomparison[Style/MultipleComparison] +* xref:cops_style.adoc#stylemutableconstant[Style/MutableConstant] +* xref:cops_style.adoc#stylenegatedif[Style/NegatedIf] +* xref:cops_style.adoc#stylenegatedunless[Style/NegatedUnless] +* xref:cops_style.adoc#stylenegatedwhile[Style/NegatedWhile] +* xref:cops_style.adoc#stylenestedmodifier[Style/NestedModifier] +* xref:cops_style.adoc#stylenestedparenthesizedcalls[Style/NestedParenthesizedCalls] +* xref:cops_style.adoc#stylenestedternaryoperator[Style/NestedTernaryOperator] +* xref:cops_style.adoc#stylenext[Style/Next] +* xref:cops_style.adoc#stylenilcomparison[Style/NilComparison] +* xref:cops_style.adoc#stylenonnilcheck[Style/NonNilCheck] +* xref:cops_style.adoc#stylenot[Style/Not] +* xref:cops_style.adoc#stylenumericliteralprefix[Style/NumericLiteralPrefix] +* xref:cops_style.adoc#stylenumericliterals[Style/NumericLiterals] +* xref:cops_style.adoc#stylenumericpredicate[Style/NumericPredicate] +* xref:cops_style.adoc#styleonelineconditional[Style/OneLineConditional] +* xref:cops_style.adoc#styleoptionhash[Style/OptionHash] +* xref:cops_style.adoc#styleoptionalarguments[Style/OptionalArguments] +* xref:cops_style.adoc#styleoptionalbooleanparameter[Style/OptionalBooleanParameter] +* xref:cops_style.adoc#styleorassignment[Style/OrAssignment] +* xref:cops_style.adoc#styleparallelassignment[Style/ParallelAssignment] +* xref:cops_style.adoc#styleparenthesesaroundcondition[Style/ParenthesesAroundCondition] +* xref:cops_style.adoc#stylepercentliteraldelimiters[Style/PercentLiteralDelimiters] +* xref:cops_style.adoc#stylepercentqliterals[Style/PercentQLiterals] +* xref:cops_style.adoc#styleperlbackrefs[Style/PerlBackrefs] +* xref:cops_style.adoc#stylepreferredhashmethods[Style/PreferredHashMethods] +* xref:cops_style.adoc#styleproc[Style/Proc] +* xref:cops_style.adoc#styleraiseargs[Style/RaiseArgs] +* xref:cops_style.adoc#stylerandomwithoffset[Style/RandomWithOffset] +* xref:cops_style.adoc#styleredundantassignment[Style/RedundantAssignment] +* xref:cops_style.adoc#styleredundantbegin[Style/RedundantBegin] +* xref:cops_style.adoc#styleredundantcapitalw[Style/RedundantCapitalW] +* xref:cops_style.adoc#styleredundantcondition[Style/RedundantCondition] +* xref:cops_style.adoc#styleredundantconditional[Style/RedundantConditional] +* xref:cops_style.adoc#styleredundantexception[Style/RedundantException] +* xref:cops_style.adoc#styleredundantfetchblock[Style/RedundantFetchBlock] +* xref:cops_style.adoc#styleredundantfileextensioninrequire[Style/RedundantFileExtensionInRequire] +* xref:cops_style.adoc#styleredundantfreeze[Style/RedundantFreeze] +* xref:cops_style.adoc#styleredundantinterpolation[Style/RedundantInterpolation] +* xref:cops_style.adoc#styleredundantparentheses[Style/RedundantParentheses] +* xref:cops_style.adoc#styleredundantpercentq[Style/RedundantPercentQ] +* xref:cops_style.adoc#styleredundantregexpcharacterclass[Style/RedundantRegexpCharacterClass] +* xref:cops_style.adoc#styleredundantregexpescape[Style/RedundantRegexpEscape] +* xref:cops_style.adoc#styleredundantreturn[Style/RedundantReturn] +* xref:cops_style.adoc#styleredundantself[Style/RedundantSelf] +* xref:cops_style.adoc#styleredundantselfassignment[Style/RedundantSelfAssignment] +* xref:cops_style.adoc#styleredundantsort[Style/RedundantSort] +* xref:cops_style.adoc#styleredundantsortby[Style/RedundantSortBy] +* xref:cops_style.adoc#styleregexpliteral[Style/RegexpLiteral] +* xref:cops_style.adoc#stylerescuemodifier[Style/RescueModifier] +* xref:cops_style.adoc#stylerescuestandarderror[Style/RescueStandardError] +* xref:cops_style.adoc#stylereturnnil[Style/ReturnNil] +* xref:cops_style.adoc#stylesafenavigation[Style/SafeNavigation] +* xref:cops_style.adoc#stylesample[Style/Sample] +* xref:cops_style.adoc#styleselfassignment[Style/SelfAssignment] +* xref:cops_style.adoc#stylesemicolon[Style/Semicolon] +* xref:cops_style.adoc#stylesend[Style/Send] +* xref:cops_style.adoc#stylesignalexception[Style/SignalException] +* xref:cops_style.adoc#stylesingleargumentdig[Style/SingleArgumentDig] +* xref:cops_style.adoc#stylesinglelineblockparams[Style/SingleLineBlockParams] +* xref:cops_style.adoc#stylesinglelinemethods[Style/SingleLineMethods] +* xref:cops_style.adoc#styleslicingwithrange[Style/SlicingWithRange] +* xref:cops_style.adoc#stylesolenestedconditional[Style/SoleNestedConditional] +* xref:cops_style.adoc#stylespecialglobalvars[Style/SpecialGlobalVars] +* xref:cops_style.adoc#stylestabbylambdaparentheses[Style/StabbyLambdaParentheses] +* xref:cops_style.adoc#stylestderrputs[Style/StderrPuts] +* xref:cops_style.adoc#stylestringconcatenation[Style/StringConcatenation] +* xref:cops_style.adoc#stylestringhashkeys[Style/StringHashKeys] +* xref:cops_style.adoc#stylestringliterals[Style/StringLiterals] +* xref:cops_style.adoc#stylestringliteralsininterpolation[Style/StringLiteralsInInterpolation] +* xref:cops_style.adoc#stylestringmethods[Style/StringMethods] +* xref:cops_style.adoc#stylestrip[Style/Strip] +* xref:cops_style.adoc#stylestructinheritance[Style/StructInheritance] +* xref:cops_style.adoc#stylesymbolarray[Style/SymbolArray] +* xref:cops_style.adoc#stylesymbolliteral[Style/SymbolLiteral] +* xref:cops_style.adoc#stylesymbolproc[Style/SymbolProc] +* xref:cops_style.adoc#styleternaryparentheses[Style/TernaryParentheses] +* xref:cops_style.adoc#styletrailingbodyonclass[Style/TrailingBodyOnClass] +* xref:cops_style.adoc#styletrailingbodyonmethoddefinition[Style/TrailingBodyOnMethodDefinition] +* xref:cops_style.adoc#styletrailingbodyonmodule[Style/TrailingBodyOnModule] +* xref:cops_style.adoc#styletrailingcommainarguments[Style/TrailingCommaInArguments] +* xref:cops_style.adoc#styletrailingcommainarrayliteral[Style/TrailingCommaInArrayLiteral] +* xref:cops_style.adoc#styletrailingcommainblockargs[Style/TrailingCommaInBlockArgs] +* xref:cops_style.adoc#styletrailingcommainhashliteral[Style/TrailingCommaInHashLiteral] +* xref:cops_style.adoc#styletrailingmethodendstatement[Style/TrailingMethodEndStatement] +* xref:cops_style.adoc#styletrailingunderscorevariable[Style/TrailingUnderscoreVariable] +* xref:cops_style.adoc#styletrivialaccessors[Style/TrivialAccessors] +* xref:cops_style.adoc#styleunlesselse[Style/UnlessElse] +* xref:cops_style.adoc#styleunpackfirst[Style/UnpackFirst] +* xref:cops_style.adoc#stylevariableinterpolation[Style/VariableInterpolation] +* xref:cops_style.adoc#stylewhenthen[Style/WhenThen] +* xref:cops_style.adoc#stylewhileuntildo[Style/WhileUntilDo] +* xref:cops_style.adoc#stylewhileuntilmodifier[Style/WhileUntilModifier] +* xref:cops_style.adoc#stylewordarray[Style/WordArray] +* xref:cops_style.adoc#styleyodacondition[Style/YodaCondition] +* xref:cops_style.adoc#stylezerolengthpredicate[Style/ZeroLengthPredicate] + +// END_COP_LIST diff --git a/docs/modules/ROOT/pages/cops_bundler.adoc b/docs/modules/ROOT/pages/cops_bundler.adoc new file mode 100644 index 000000000000..c7e31a16d1e8 --- /dev/null +++ b/docs/modules/ROOT/pages/cops_bundler.adoc @@ -0,0 +1,255 @@ += Bundler + +== Bundler/DuplicatedGem + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.46 +| - +|=== + +A Gem's requirements should be listed only once in a Gemfile. + +=== Examples + +[source,ruby] +---- +# bad +gem 'rubocop' +gem 'rubocop' + +# bad +group :development do + gem 'rubocop' +end + +group :test do + gem 'rubocop' +end + +# good +group :development, :test do + gem 'rubocop' +end + +# good +gem 'rubocop', groups: [:development, :test] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Include +| `+**/*.gemfile+`, `+**/Gemfile+`, `+**/gems.rb+` +| Array +|=== + +== Bundler/GemComment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.59 +| 0.85 +|=== + +Add a comment describing each gem in your Gemfile. + +Optionally, the "OnlyFor" configuration +can be used to only register offenses when the gems +use certain options or have version specifiers. +Add "version_specifiers" and/or the gem option names +you want to check. + +A useful use-case is to enforce a comment when using +options that change the source of a gem: + +- `bitbucket` +- `gist` +- `git` +- `github` +- `source` + +For a full list of options supported by bundler, +you can check the https://bundler.io/man/gemfile.5.html[official documentation]. + +=== Examples + +==== OnlyFor: [] (default) + +[source,ruby] +---- +# bad + +gem 'foo' + +# good + +# Helpers for the foo things. +gem 'foo' +---- + +==== OnlyFor: ['version_specifiers'] + +[source,ruby] +---- +# bad + +gem 'foo', '< 2.1' + +# good + +# Version 2.1 introduces breaking change baz +gem 'foo', '< 2.1' +---- + +==== OnlyFor: ['version_specifiers', 'github'] + +[source,ruby] +---- +# bad + +gem 'foo', github: 'some_account/some_fork_of_foo' + +gem 'bar', '< 2.1' + +# good + +# Using this fork because baz +gem 'foo', github: 'some_account/some_fork_of_foo' + +# Version 2.1 introduces breaking change baz +gem 'bar', '< 2.1' +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Include +| `+**/*.gemfile+`, `+**/Gemfile+`, `+**/gems.rb+` +| Array + +| IgnoredGems +| `[]` +| Array + +| OnlyFor +| `[]` +| Array +|=== + +== Bundler/InsecureProtocolSource + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.50 +| - +|=== + +The symbol argument `:gemcutter`, `:rubygems`, and `:rubyforge` +are deprecated. So please change your source to URL string that +'https://rubygems.org' if possible, or 'http://rubygems.org' if not. + +This autocorrect will replace these symbols with 'https://rubygems.org'. +Because it is secure, HTTPS request is strongly recommended. And in +most use cases HTTPS will be fine. + +However, it don't replace all `sources` of `http://` with `https://`. +For example, when specifying an internal gem server using HTTP on the +intranet, a use case where HTTPS cannot be specified was considered. +Consider using HTTP only if you cannot use HTTPS. + +=== Examples + +[source,ruby] +---- +# bad +source :gemcutter +source :rubygems +source :rubyforge + +# good +source 'https://rubygems.org' # strongly recommended +source 'http://rubygems.org' +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Include +| `+**/*.gemfile+`, `+**/Gemfile+`, `+**/gems.rb+` +| Array +|=== + +== Bundler/OrderedGems + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.46 +| 0.47 +|=== + +Gems should be alphabetically sorted within groups. + +=== Examples + +[source,ruby] +---- +# bad +gem 'rubocop' +gem 'rspec' + +# good +gem 'rspec' +gem 'rubocop' + +# good +gem 'rubocop' + +gem 'rspec' + +# good only if TreatCommentsAsGroupSeparators is true +# For code quality +gem 'rubocop' +# For tests +gem 'rspec' +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| TreatCommentsAsGroupSeparators +| `true` +| Boolean + +| ConsiderPunctuation +| `false` +| Boolean + +| Include +| `+**/*.gemfile+`, `+**/Gemfile+`, `+**/gems.rb+` +| Array +|=== diff --git a/docs/modules/ROOT/pages/cops_gemspec.adoc b/docs/modules/ROOT/pages/cops_gemspec.adoc new file mode 100644 index 000000000000..9c6a8f46d96f --- /dev/null +++ b/docs/modules/ROOT/pages/cops_gemspec.adoc @@ -0,0 +1,261 @@ += Gemspec + +== Gemspec/DuplicatedAssignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.52 +| - +|=== + +An attribute assignment method calls should be listed only once +in a gemspec. + +Assigning to an attribute with the same name using `spec.foo =` will be +an unintended usage. On the other hand, duplication of methods such +as `spec.requirements`, `spec.add_runtime_dependency`, and others are +permitted because it is the intended use of appending values. + +=== Examples + +[source,ruby] +---- +# bad +Gem::Specification.new do |spec| + spec.name = 'rubocop' + spec.name = 'rubocop2' +end + +# good +Gem::Specification.new do |spec| + spec.name = 'rubocop' +end + +# good +Gem::Specification.new do |spec| + spec.requirements << 'libmagick, v6.0' + spec.requirements << 'A good graphics card' +end + +# good +Gem::Specification.new do |spec| + spec.add_runtime_dependency('parallel', '~> 1.10') + spec.add_runtime_dependency('parser', '>= 2.3.3.1', '< 3.0') +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Include +| `+**/*.gemspec+` +| Array +|=== + +== Gemspec/OrderedDependencies + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.51 +| - +|=== + +Dependencies in the gemspec should be alphabetically sorted. + +=== Examples + +[source,ruby] +---- +# bad +spec.add_dependency 'rubocop' +spec.add_dependency 'rspec' + +# good +spec.add_dependency 'rspec' +spec.add_dependency 'rubocop' + +# good +spec.add_dependency 'rubocop' + +spec.add_dependency 'rspec' + +# bad +spec.add_development_dependency 'rubocop' +spec.add_development_dependency 'rspec' + +# good +spec.add_development_dependency 'rspec' +spec.add_development_dependency 'rubocop' + +# good +spec.add_development_dependency 'rubocop' + +spec.add_development_dependency 'rspec' + +# bad +spec.add_runtime_dependency 'rubocop' +spec.add_runtime_dependency 'rspec' + +# good +spec.add_runtime_dependency 'rspec' +spec.add_runtime_dependency 'rubocop' + +# good +spec.add_runtime_dependency 'rubocop' + +spec.add_runtime_dependency 'rspec' + +# good only if TreatCommentsAsGroupSeparators is true +# For code quality +spec.add_dependency 'rubocop' +# For tests +spec.add_dependency 'rspec' +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| TreatCommentsAsGroupSeparators +| `true` +| Boolean + +| ConsiderPunctuation +| `false` +| Boolean + +| Include +| `+**/*.gemspec+` +| Array +|=== + +== Gemspec/RequiredRubyVersion + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.52 +| 0.89 +|=== + +Checks that `required_ruby_version` of gemspec is specified and +equal to `TargetRubyVersion` of .rubocop.yml. +Thereby, RuboCop to perform static analysis working on the version +required by gemspec. + +=== Examples + +[source,ruby] +---- +# When `TargetRubyVersion` of .rubocop.yml is `2.5`. + +# bad +Gem::Specification.new do |spec| + # no `required_ruby_version` specified +end + +# bad +Gem::Specification.new do |spec| + spec.required_ruby_version = '>= 2.4.0' +end + +# bad +Gem::Specification.new do |spec| + spec.required_ruby_version = '>= 2.6.0' +end + +# good +Gem::Specification.new do |spec| + spec.required_ruby_version = '>= 2.5.0' +end + +# good +Gem::Specification.new do |spec| + spec.required_ruby_version = '>= 2.5' +end + +# good +Gem::Specification.new do |spec| + spec.required_ruby_version = ['>= 2.5.0', '< 2.7.0'] +end + +# good +Gem::Specification.new do |spec| + spec.required_ruby_version = '~> 2.5' +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Include +| `+**/*.gemspec+` +| Array +|=== + +== Gemspec/RubyVersionGlobalsUsage + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.72 +| - +|=== + +Checks that `RUBY_VERSION` constant is not used in gemspec. +Using `RUBY_VERSION` is dangerous because value of the +constant is determined by `rake release`. +It's possible to have dependency based on ruby version used +to execute `rake release` and not user's ruby version. + +=== Examples + +[source,ruby] +---- +# bad +Gem::Specification.new do |spec| + if RUBY_VERSION >= '2.5' + spec.add_runtime_dependency 'gem_a' + else + spec.add_runtime_dependency 'gem_b' + end +end + +# good +Gem::Specification.new do |spec| + spec.add_runtime_dependency 'gem_a' +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Include +| `+**/*.gemspec+` +| Array +|=== + +=== References + +* https://rubystyle.guide#no-ruby-version-in-the-gemspec diff --git a/docs/modules/ROOT/pages/cops_layout.adoc b/docs/modules/ROOT/pages/cops_layout.adoc new file mode 100644 index 000000000000..747910d30e27 --- /dev/null +++ b/docs/modules/ROOT/pages/cops_layout.adoc @@ -0,0 +1,6397 @@ += Layout + +== Layout/AccessModifierIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Bare access modifiers (those not applying to specific methods) should be +indented as deep as method definitions, or as deep as the class/module +keyword, depending on configuration. + +=== Examples + +==== EnforcedStyle: indent (default) + +[source,ruby] +---- +# bad +class Plumbus +private + def smooth; end +end + +# good +class Plumbus + private + def smooth; end +end +---- + +==== EnforcedStyle: outdent + +[source,ruby] +---- +# bad +class Plumbus + private + def smooth; end +end + +# good +class Plumbus +private + def smooth; end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `indent` +| `outdent`, `indent` + +| IndentationWidth +| `` +| Integer +|=== + +=== References + +* https://rubystyle.guide#indent-public-private-protected + +== Layout/ArgumentAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.68 +| 0.77 +|=== + +Here we check if the arguments on a multi-line method +definition are aligned. + +=== Examples + +==== EnforcedStyle: with_first_argument (default) + +[source,ruby] +---- +# good + +foo :bar, + :baz + +foo( + :bar, + :baz +) + +# bad + +foo :bar, + :baz + +foo( + :bar, + :baz +) +---- + +==== EnforcedStyle: with_fixed_indentation + +[source,ruby] +---- +# good + +foo :bar, + :baz + +# bad + +foo :bar, + :baz +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `with_first_argument` +| `with_first_argument`, `with_fixed_indentation` + +| IndentationWidth +| `` +| Integer +|=== + +=== References + +* https://rubystyle.guide#no-double-indent + +== Layout/ArrayAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.77 +|=== + +Here we check if the elements of a multi-line array literal are +aligned. + +=== Examples + +==== EnforcedStyle: with_first_element (default) + +[source,ruby] +---- +# good + +array = [1, 2, 3, + 4, 5, 6] +array = ['run', + 'forrest', + 'run'] + +# bad + +array = [1, 2, 3, + 4, 5, 6] +array = ['run', + 'forrest', + 'run'] +---- + +==== EnforcedStyle: with_fixed_indentation + +[source,ruby] +---- +# good + +array = [1, 2, 3, + 4, 5, 6] + +# bad + +array = [1, 2, 3, + 4, 5, 6] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `with_first_element` +| `with_first_element`, `with_fixed_indentation` + +| IndentationWidth +| `` +| Integer +|=== + +=== References + +* https://rubystyle.guide#no-double-indent + +== Layout/AssignmentIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.77 +|=== + +This cop checks the indentation of the first line of the +right-hand-side of a multi-line assignment. + +The indentation of the remaining lines can be corrected with +other cops such as `IndentationConsistency` and `EndAlignment`. + +=== Examples + +[source,ruby] +---- +# bad +value = +if foo + 'bar' +end + +# good +value = + if foo + 'bar' + end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IndentationWidth +| `` +| Integer +|=== + +== Layout/BeginEndAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.91 +| - +|=== + +This cop checks whether the end keyword of `begin` is aligned properly. + +Two modes are supported through the `EnforcedStyleAlignWith` configuration +parameter. If it's set to `start_of_line` (which is the default), the +`end` shall be aligned with the start of the line where the `begin` +keyword is. If it's set to `begin`, the `end` shall be aligned with the +`begin` keyword. + +`Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`) +by default. On the other hand, `||= begin` that this cop targets tends to +align with the start of the line, it defaults to `EnforcedStyleAlignWith: start_of_line`. +These style can be configured by each cop. + +=== Examples + +==== EnforcedStyleAlignWith: start_of_line (default) + +[source,ruby] +---- +# bad +foo ||= begin + do_something + end + +# good +foo ||= begin + do_something +end +---- + +==== EnforcedStyleAlignWith: begin + +[source,ruby] +---- +# bad +foo ||= begin + do_something +end + +# good +foo ||= begin + do_something + end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyleAlignWith +| `start_of_line` +| `start_of_line`, `begin` + +| Severity +| `warning` +| String +|=== + +== Layout/BlockAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +This cop checks whether the end keywords are aligned properly for do +end blocks. + +Three modes are supported through the `EnforcedStyleAlignWith` +configuration parameter: + +`start_of_block` : the `end` shall be aligned with the +start of the line where the `do` appeared. + +`start_of_line` : the `end` shall be aligned with the +start of the line where the expression started. + +`either` (which is the default) : the `end` is allowed to be in either +location. The autofixer will default to `start_of_line`. + +=== Examples + +==== EnforcedStyleAlignWith: either (default) + +[source,ruby] +---- +# bad + +foo.bar + .each do + baz + end + +# good + +variable = lambda do |i| + i +end +---- + +==== EnforcedStyleAlignWith: start_of_block + +[source,ruby] +---- +# bad + +foo.bar + .each do + baz + end + +# good + +foo.bar + .each do + baz + end +---- + +==== EnforcedStyleAlignWith: start_of_line + +[source,ruby] +---- +# bad + +foo.bar + .each do + baz + end + +# good + +foo.bar + .each do + baz +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyleAlignWith +| `either` +| `either`, `start_of_block`, `start_of_line` +|=== + +== Layout/BlockEndNewline + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks whether the end statement of a do..end block +is on its own line. + +=== Examples + +[source,ruby] +---- +# bad +blah do |i| + foo(i) end + +# good +blah do |i| + foo(i) +end + +# bad +blah { |i| + foo(i) } + +# good +blah { |i| + foo(i) +} +---- + +== Layout/CaseIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks how the ``when``s of a `case` expression +are indented in relation to its `case` or `end` keyword. + +It will register a separate offense for each misaligned `when`. + +=== Examples + +[source,ruby] +---- +# If Layout/EndAlignment is set to keyword style (default) +# *case* and *end* should always be aligned to same depth, +# and therefore *when* should always be aligned to both - +# regardless of configuration. + +# bad for all styles +case n + when 0 + x * 2 + else + y / 3 +end + +# good for all styles +case n +when 0 + x * 2 +else + y / 3 +end +---- + +==== EnforcedStyle: case (default) + +[source,ruby] +---- +# if EndAlignment is set to other style such as +# start_of_line (as shown below), then *when* alignment +# configuration does have an effect. + +# bad +a = case n +when 0 + x * 2 +else + y / 3 +end + +# good +a = case n + when 0 + x * 2 + else + y / 3 +end +---- + +==== EnforcedStyle: end + +[source,ruby] +---- +# bad +a = case n + when 0 + x * 2 + else + y / 3 +end + +# good +a = case n +when 0 + x * 2 +else + y / 3 +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `case` +| `case`, `end` + +| IndentOneStep +| `false` +| Boolean + +| IndentationWidth +| `` +| Integer +|=== + +=== References + +* https://rubystyle.guide#indent-when-to-case + +== Layout/ClassStructure + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.52 +| - +|=== + +Checks if the code style follows the ExpectedOrder configuration: + +`Categories` allows us to map macro names into a category. + +Consider an example of code style that covers the following order: + +* Module inclusion (include, prepend, extend) +* Constants +* Associations (has_one, has_many) +* Public attribute macros (attr_accessor, attr_writer, attr_reader) +* Other macros (validates, validate) +* Public class methods +* Initializer +* Public instance methods +* Protected attribute macros (attr_accessor, attr_writer, attr_reader) +* Protected instance methods +* Private attribute macros (attr_accessor, attr_writer, attr_reader) +* Private instance methods + +You can configure the following order: + +[source,yaml] +---- + Layout/ClassStructure: + ExpectedOrder: + - module_inclusion + - constants + - association + - public_attribute_macros + - public_delegate + - macros + - public_class_methods + - initializer + - public_methods + - protected_attribute_macros + - protected_methods + - private_attribute_macros + - private_delegate + - private_methods +---- + +Instead of putting all literals in the expected order, is also +possible to group categories of macros. Visibility levels are handled +automatically. + +[source,yaml] +---- + Layout/ClassStructure: + Categories: + association: + - has_many + - has_one + attribute_macros: + - attr_accessor + - attr_reader + - attr_writer + macros: + - validates + - validate + module_inclusion: + - include + - prepend + - extend +---- + +=== Examples + +[source,ruby] +---- +# bad +# Expect extend be before constant +class Person < ApplicationRecord + has_many :orders + ANSWER = 42 + + extend SomeModule + include AnotherModule +end + +# good +class Person + # extend and include go first + extend SomeModule + include AnotherModule + + # inner classes + CustomError = Class.new(StandardError) + + # constants are next + SOME_CONSTANT = 20 + + # afterwards we have public attribute macros + attr_reader :name + + # followed by other macros (if any) + validates :name + + # then we have public delegate macros + delegate :to_s, to: :name + + # public class methods are next in line + def self.some_method + end + + # initialization goes between class methods and instance methods + def initialize + end + + # followed by other public instance methods + def some_method + end + + # protected attribute macros and methods go next + protected + + attr_reader :protected_name + + def some_protected_method + end + + # private attribute macros, delegate macros and methods + # are grouped near the end + private + + attr_reader :private_name + + delegate :some_private_delegate, to: :name + + def some_private_method + end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Categories +| `{"module_inclusion"=>["include", "prepend", "extend"]}` +| + +| ExpectedOrder +| `module_inclusion`, `constants`, `public_class_methods`, `initializer`, `public_methods`, `protected_methods`, `private_methods` +| Array +|=== + +=== References + +* https://rubystyle.guide#consistent-classes + +== Layout/ClosingHeredocIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.57 +| - +|=== + +Checks the indentation of here document closings. + +=== Examples + +[source,ruby] +---- +# bad +class Foo + def bar + <<~SQL + 'Hi' + SQL + end +end + +# good +class Foo + def bar + <<~SQL + 'Hi' + SQL + end +end + +# bad + +# heredoc contents is before closing heredoc. +foo arg, + <<~EOS + Hi + EOS + +# good +foo arg, + <<~EOS + Hi +EOS + +# good +foo arg, + <<~EOS + Hi + EOS +---- + +== Layout/ClosingParenthesisIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks the indentation of hanging closing parentheses in +method calls, method definitions, and grouped expressions. A hanging +closing parenthesis means `)` preceded by a line break. + +=== Examples + +[source,ruby] +---- +# bad +some_method( + a, + b + ) + +some_method( + a, b + ) + +some_method(a, b, c + ) + +some_method(a, + b, + c + ) + +some_method(a, + x: 1, + y: 2 + ) + +# Scenario 1: When First Parameter Is On Its Own Line + +# good: when first param is on a new line, right paren is *always* +# outdented by IndentationWidth +some_method( + a, + b +) + +# good +some_method( + a, b +) + +# Scenario 2: When First Parameter Is On The Same Line + +# good: when all other params are also on the same line, outdent +# right paren by IndentationWidth +some_method(a, b, c + ) + +# good: when all other params are on multiple lines, but are lined +# up, align right paren with left paren +some_method(a, + b, + c + ) + +# good: when other params are not lined up on multiple lines, outdent +# right paren by IndentationWidth +some_method(a, + x: 1, + y: 2 +) +---- + +== Layout/CommentIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks the indentation of comments. + +=== Examples + +[source,ruby] +---- +# bad + # comment here +def method_name +end + + # comment here +a = 'hello' + +# yet another comment + if true + true + end + +# good +# comment here +def method_name +end + +# comment here +a = 'hello' + +# yet another comment +if true + true +end +---- + +== Layout/ConditionPosition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| 0.83 +|=== + +This cop checks for conditions that are not on the same line as +if/while/until. + +=== Examples + +[source,ruby] +---- +# bad + +if + some_condition + do_something +end +---- + +[source,ruby] +---- +# good + +if some_condition + do_something +end +---- + +=== References + +* https://rubystyle.guide#same-line-condition + +== Layout/DefEndAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +This cop checks whether the end keywords of method definitions are +aligned properly. + +Two modes are supported through the EnforcedStyleAlignWith configuration +parameter. If it's set to `start_of_line` (which is the default), the +`end` shall be aligned with the start of the line where the `def` +keyword is. If it's set to `def`, the `end` shall be aligned with the +`def` keyword. + +=== Examples + +==== EnforcedStyleAlignWith: start_of_line (default) + +[source,ruby] +---- +# bad + +private def foo + end + +# good + +private def foo +end +---- + +==== EnforcedStyleAlignWith: def + +[source,ruby] +---- +# bad + +private def foo + end + +# good + +private def foo + end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyleAlignWith +| `start_of_line` +| `start_of_line`, `def` + +| Severity +| `warning` +| String +|=== + +== Layout/DotPosition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks the . position in multi-line method calls. + +=== Examples + +==== EnforcedStyle: leading (default) + +[source,ruby] +---- +# bad +something. + method + +# good +something + .method +---- + +==== EnforcedStyle: trailing + +[source,ruby] +---- +# bad +something + .method + +# good +something. + method +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `leading` +| `leading`, `trailing` +|=== + +=== References + +* https://rubystyle.guide#consistent-multi-line-chains + +== Layout/ElseAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks the alignment of else keywords. Normally they should +be aligned with an if/unless/while/until/begin/def keyword, but there +are special cases when they should follow the same rules as the +alignment of end. + +=== Examples + +[source,ruby] +---- +# bad +if something + code + else + code +end + +# bad +if something + code + elsif something + code +end + +# good +if something + code +else + code +end +---- + +== Layout/EmptyComment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +This cop checks empty comment. + +=== Examples + +[source,ruby] +---- +# bad + +# +class Foo +end + +# good + +# +# Description of `Foo` class. +# +class Foo +end +---- + +==== AllowBorderComment: true (default) + +[source,ruby] +---- +# good + +def foo +end + +################# + +def bar +end +---- + +==== AllowBorderComment: false + +[source,ruby] +---- +# bad + +def foo +end + +################# + +def bar +end +---- + +==== AllowMarginComment: true (default) + +[source,ruby] +---- +# good + +# +# Description of `Foo` class. +# +class Foo +end +---- + +==== AllowMarginComment: false + +[source,ruby] +---- +# bad + +# +# Description of `Foo` class. +# +class Foo +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowBorderComment +| `true` +| Boolean + +| AllowMarginComment +| `true` +| Boolean +|=== + +== Layout/EmptyLineAfterGuardClause + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.56 +| 0.59 +|=== + +This cop enforces empty line after guard clause + +=== Examples + +[source,ruby] +---- +# bad +def foo + return if need_return? + bar +end + +# good +def foo + return if need_return? + + bar +end + +# good +def foo + return if something? + return if something_different? + + bar +end + +# also good +def foo + if something? + do_something + return if need_return? + end +end +---- + +== Layout/EmptyLineAfterMagicComment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for a newline after the final magic comment. + +=== Examples + +[source,ruby] +---- +# good +# frozen_string_literal: true + +# Some documentation for Person +class Person + # Some code +end + +# bad +# frozen_string_literal: true +# Some documentation for Person +class Person + # Some code +end +---- + +=== References + +* https://rubystyle.guide#separate-magic-comments-from-code + +== Layout/EmptyLineAfterMultilineCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.90 +| - +|=== + +This cop enforces empty line after multiline condition. + +=== Examples + +[source,ruby] +---- +# bad +if multiline && + condition + do_something +end + +# good +if multiline && + condition + + do_something +end + +# bad +case x +when foo, + bar + do_something +end + +# good +case x +when foo, + bar + + do_something +end + +# bad +begin + do_something +rescue FooError, + BarError + handle_error +end + +# good +begin + do_something +rescue FooError, + BarError + + handle_error +end +---- + +=== References + +* https://github.com/airbnb/ruby#multiline-if-newline + +== Layout/EmptyLineBetweenDefs + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks whether method definitions are +separated by one empty line. + +`NumberOfEmptyLines` can be an integer (default is 1) or +an array (e.g. [1, 2]) to specify a minimum and maximum +number of empty lines permitted. + +`AllowAdjacentOneLineDefs` configures whether adjacent +one-line method definitions are considered an offense. + +=== Examples + +[source,ruby] +---- +# bad +def a +end +def b +end +---- + +[source,ruby] +---- +# good +def a +end + +def b +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowAdjacentOneLineDefs +| `false` +| Boolean + +| NumberOfEmptyLines +| `1` +| Integer +|=== + +=== References + +* https://rubystyle.guide#empty-lines-between-methods + +== Layout/EmptyLines + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for two or more consecutive blank lines. + +=== Examples + +[source,ruby] +---- +# bad - It has two empty lines. +some_method +# one empty line +# two empty lines +some_method + +# good +some_method +# one empty line +some_method +---- + +=== References + +* https://rubystyle.guide#two-or-more-empty-lines + +== Layout/EmptyLinesAroundAccessModifier + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Access modifiers should be surrounded by blank lines. + +=== Examples + +==== EnforcedStyle: around (default) + +[source,ruby] +---- +# bad +class Foo + def bar; end + private + def baz; end +end + +# good +class Foo + def bar; end + + private + + def baz; end +end +---- + +==== EnforcedStyle: only_before + +[source,ruby] +---- +# bad +class Foo + def bar; end + private + def baz; end +end + +# good +class Foo + def bar; end + + private + def baz; end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `around` +| `around`, `only_before` +|=== + +=== References + +* https://rubystyle.guide#empty-lines-around-access-modifier +* https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions + +== Layout/EmptyLinesAroundArguments + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| - +|=== + +This cop checks if empty lines exist around the arguments +of a method invocation. + +=== Examples + +[source,ruby] +---- +# bad +do_something( + foo + +) + +process(bar, + + baz: qux, + thud: fred) + +some_method( + + [1,2,3], + x: y +) + +# good +do_something( + foo +) + +process(bar, + baz: qux, + thud: fred) + +some_method( + [1,2,3], + x: y +) +---- + +== Layout/EmptyLinesAroundAttributeAccessor + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.83 +| 0.84 +|=== + +Checks for a newline after an attribute accessor or a group of them. +`alias` syntax and `alias_method`, `public`, `protected`, and `private` methods are allowed +by default. These are customizable with `AllowAliasSyntax` and `AllowedMethods` options. + +=== Examples + +[source,ruby] +---- +# bad +attr_accessor :foo +def do_something +end + +# good +attr_accessor :foo + +def do_something +end + +# good +attr_accessor :foo +attr_reader :bar +attr_writer :baz +attr :qux + +def do_something +end +---- + +==== AllowAliasSyntax: true (default) + +[source,ruby] +---- +# good +attr_accessor :foo +alias :foo? :foo + +def do_something +end +---- + +==== AllowAliasSyntax: false + +[source,ruby] +---- +# bad +attr_accessor :foo +alias :foo? :foo + +def do_something +end + +# good +attr_accessor :foo + +alias :foo? :foo + +def do_something +end +---- + +==== AllowedMethods: ['private'] + +[source,ruby] +---- +# good +attr_accessor :foo +private :foo + +def do_something +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowAliasSyntax +| `true` +| Boolean + +| AllowedMethods +| `alias_method`, `public`, `protected`, `private` +| Array +|=== + +=== References + +* https://rubystyle.guide#empty-lines-around-attribute-accessor + +== Layout/EmptyLinesAroundBeginBody + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks if empty lines exist around the bodies of begin-end +blocks. + +=== Examples + +[source,ruby] +---- +# good + +begin + # ... +end + +# bad + +begin + + # ... + +end +---- + +=== References + +* https://rubystyle.guide#empty-lines-around-bodies + +== Layout/EmptyLinesAroundBlockBody + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks if empty lines around the bodies of blocks match +the configuration. + +=== Examples + +==== EnforcedStyle: empty_lines + +[source,ruby] +---- +# good + +foo do |bar| + + # ... + +end +---- + +==== EnforcedStyle: no_empty_lines (default) + +[source,ruby] +---- +# good + +foo do |bar| + # ... +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `no_empty_lines` +| `empty_lines`, `no_empty_lines` +|=== + +=== References + +* https://rubystyle.guide#empty-lines-around-bodies + +== Layout/EmptyLinesAroundClassBody + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.53 +|=== + +This cop checks if empty lines around the bodies of classes match +the configuration. + +=== Examples + +==== EnforcedStyle: empty_lines + +[source,ruby] +---- +# good + +class Foo + + def bar + # ... + end + +end +---- + +==== EnforcedStyle: empty_lines_except_namespace + +[source,ruby] +---- +# good + +class Foo + class Bar + + # ... + + end +end +---- + +==== EnforcedStyle: empty_lines_special + +[source,ruby] +---- +# good +class Foo + + def bar; end + +end +---- + +==== EnforcedStyle: beginning_only + +[source,ruby] +---- +# good + +class Foo + + def bar + # ... + end +end +---- + +==== EnforcedStyle: ending_only + +[source,ruby] +---- +# good + +class Foo + def bar + # ... + end + +end +---- + +==== EnforcedStyle: no_empty_lines (default) + +[source,ruby] +---- +# good + +class Foo + def bar + # ... + end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `no_empty_lines` +| `empty_lines`, `empty_lines_except_namespace`, `empty_lines_special`, `no_empty_lines`, `beginning_only`, `ending_only` +|=== + +=== References + +* https://rubystyle.guide#empty-lines-around-bodies + +== Layout/EmptyLinesAroundExceptionHandlingKeywords + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks if empty lines exist around the bodies of `begin` +sections. This cop doesn't check empty lines at `begin` body +beginning/end and around method definition body. +`Style/EmptyLinesAroundBeginBody` or `Style/EmptyLinesAroundMethodBody` +can be used for this purpose. + +=== Examples + +[source,ruby] +---- +# good + +begin + do_something +rescue + do_something2 +else + do_something3 +ensure + do_something4 +end + +# good + +def foo + do_something +rescue + do_something2 +end + +# bad + +begin + do_something + +rescue + + do_something2 + +else + + do_something3 + +ensure + + do_something4 +end + +# bad + +def foo + do_something + +rescue + + do_something2 +end +---- + +=== References + +* https://rubystyle.guide#empty-lines-around-bodies + +== Layout/EmptyLinesAroundMethodBody + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks if empty lines exist around the bodies of methods. + +=== Examples + +[source,ruby] +---- +# good + +def foo + # ... +end + +# bad + +def bar + + # ... + +end +---- + +=== References + +* https://rubystyle.guide#empty-lines-around-bodies + +== Layout/EmptyLinesAroundModuleBody + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks if empty lines around the bodies of modules match +the configuration. + +=== Examples + +==== EnforcedStyle: empty_lines + +[source,ruby] +---- +# good + +module Foo + + def bar + # ... + end + +end +---- + +==== EnforcedStyle: empty_lines_except_namespace + +[source,ruby] +---- +# good + +module Foo + module Bar + + # ... + + end +end +---- + +==== EnforcedStyle: empty_lines_special + +[source,ruby] +---- +# good +module Foo + + def bar; end + +end +---- + +==== EnforcedStyle: no_empty_lines (default) + +[source,ruby] +---- +# good + +module Foo + def bar + # ... + end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `no_empty_lines` +| `empty_lines`, `empty_lines_except_namespace`, `empty_lines_special`, `no_empty_lines` +|=== + +=== References + +* https://rubystyle.guide#empty-lines-around-bodies + +== Layout/EndAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +This cop checks whether the end keywords are aligned properly. + +Three modes are supported through the `EnforcedStyleAlignWith` +configuration parameter: + +If it's set to `keyword` (which is the default), the `end` +shall be aligned with the start of the keyword (if, class, etc.). + +If it's set to `variable` the `end` shall be aligned with the +left-hand-side of the variable assignment, if there is one. + +If it's set to `start_of_line`, the `end` shall be aligned with the +start of the line where the matching keyword appears. + +This `Layout/EndAlignment` cop aligns with keywords (e.g. `if`, `while`, `case`) +by default. On the other hand, `Layout/BeginEndAlignment` cop aligns with +`EnforcedStyleAlignWith: start_of_line` by default due to `||= begin` tends +to align with the start of the line. These style can be configured by each cop. + +=== Examples + +==== EnforcedStyleAlignWith: keyword (default) + +[source,ruby] +---- +# bad + +variable = if true + end + +# good + +variable = if true + end + +variable = + if true + end +---- + +==== EnforcedStyleAlignWith: variable + +[source,ruby] +---- +# bad + +variable = if true + end + +# good + +variable = if true +end + +variable = + if true + end +---- + +==== EnforcedStyleAlignWith: start_of_line + +[source,ruby] +---- +# bad + +variable = if true + end + +puts(if true + end) + +# good + +variable = if true +end + +puts(if true +end) + +variable = + if true + end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyleAlignWith +| `keyword` +| `keyword`, `variable`, `start_of_line` + +| Severity +| `warning` +| String +|=== + +== Layout/EndOfLine + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.49 +| - +|=== + +This cop checks for Windows-style line endings in the source code. + +=== Examples + +==== EnforcedStyle: native (default) + +[source,ruby] +---- +# The `native` style means that CR+LF (Carriage Return + Line Feed) is +# enforced on Windows, and LF is enforced on other platforms. + +# bad +puts 'Hello' # Return character is LF on Windows. +puts 'Hello' # Return character is CR+LF on other than Windows. + +# good +puts 'Hello' # Return character is CR+LF on Windows. +puts 'Hello' # Return character is LF on other than Windows. +---- + +==== EnforcedStyle: lf + +[source,ruby] +---- +# The `lf` style means that LF (Line Feed) is enforced on +# all platforms. + +# bad +puts 'Hello' # Return character is CR+LF on all platfoms. + +# good +puts 'Hello' # Return character is LF on all platfoms. +---- + +==== EnforcedStyle: crlf + +[source,ruby] +---- +# The `crlf` style means that CR+LF (Carriage Return + Line Feed) is +# enforced on all platforms. + +# bad +puts 'Hello' # Return character is LF on all platfoms. + +# good +puts 'Hello' # Return character is CR+LF on all platfoms. +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `native` +| `native`, `lf`, `crlf` +|=== + +=== References + +* https://rubystyle.guide#crlf + +== Layout/ExtraSpacing + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for extra/unnecessary whitespace. + +=== Examples + +[source,ruby] +---- +# good if AllowForAlignment is true +name = "RuboCop" +# Some comment and an empty line + +website += "/rubocop-hq/rubocop" unless cond +puts "rubocop" if debug + +# bad for any configuration +set_app("RuboCop") +website = "https://github.com/rubocop-hq/rubocop" + +# good only if AllowBeforeTrailingComments is true +object.method(arg) # this is a comment + +# good even if AllowBeforeTrailingComments is false or not set +object.method(arg) # this is a comment + +# good with either AllowBeforeTrailingComments or AllowForAlignment +object.method(arg) # this is a comment +another_object.method(arg) # this is another comment +some_object.method(arg) # this is some comment +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowForAlignment +| `true` +| Boolean + +| AllowBeforeTrailingComments +| `false` +| Boolean + +| ForceEqualSignAlignment +| `false` +| Boolean +|=== + +== Layout/FirstArgumentIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.68 +| 0.77 +|=== + +This cop checks the indentation of the first argument in a method call. +Arguments after the first one are checked by Layout/ArgumentAlignment, +not by this cop. + +For indenting the first parameter of method _definitions_, check out +Layout/FirstParameterIndentation. + +=== Examples + +[source,ruby] +---- +# bad +some_method( +first_param, +second_param) + +foo = some_method( +first_param, +second_param) + +foo = some_method(nested_call( +nested_first_param), +second_param) + +foo = some_method( +nested_call( +nested_first_param), +second_param) + +some_method nested_call( +nested_first_param), +second_param +---- + +==== EnforcedStyle: consistent + +[source,ruby] +---- +# The first argument should always be indented one step more than the +# preceding line. + +# good +some_method( + first_param, +second_param) + +foo = some_method( + first_param, +second_param) + +foo = some_method(nested_call( + nested_first_param), +second_param) + +foo = some_method( + nested_call( + nested_first_param), +second_param) + +some_method nested_call( + nested_first_param), +second_param +---- + +==== EnforcedStyle: consistent_relative_to_receiver + +[source,ruby] +---- +# The first argument should always be indented one level relative to +# the parent that is receiving the argument + +# good +some_method( + first_param, +second_param) + +foo = some_method( + first_param, +second_param) + +foo = some_method(nested_call( + nested_first_param), +second_param) + +foo = some_method( + nested_call( + nested_first_param), +second_param) + +some_method nested_call( + nested_first_param), +second_params +---- + +==== EnforcedStyle: special_for_inner_method_call + +[source,ruby] +---- +# The first argument should normally be indented one step more than +# the preceding line, but if it's a argument for a method call that +# is itself a argument in a method call, then the inner argument +# should be indented relative to the inner method. + +# good +some_method( + first_param, +second_param) + +foo = some_method( + first_param, +second_param) + +foo = some_method(nested_call( + nested_first_param), +second_param) + +foo = some_method( + nested_call( + nested_first_param), +second_param) + +some_method nested_call( + nested_first_param), +second_param +---- + +==== EnforcedStyle: special_for_inner_method_call_in_parentheses (default) + +[source,ruby] +---- +# Same as `special_for_inner_method_call` except that the special rule +# only applies if the outer method call encloses its arguments in +# parentheses. + +# good +some_method( + first_param, +second_param) + +foo = some_method( + first_param, +second_param) + +foo = some_method(nested_call( + nested_first_param), +second_param) + +foo = some_method( + nested_call( + nested_first_param), +second_param) + +some_method nested_call( + nested_first_param), +second_param +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `special_for_inner_method_call_in_parentheses` +| `consistent`, `consistent_relative_to_receiver`, `special_for_inner_method_call`, `special_for_inner_method_call_in_parentheses` + +| IndentationWidth +| `` +| Integer +|=== + +== Layout/FirstArrayElementIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.68 +| 0.77 +|=== + +This cop checks the indentation of the first element in an array literal +where the opening bracket and the first element are on separate lines. +The other elements' indentations are handled by the ArrayAlignment cop. + +By default, array literals that are arguments in a method call with +parentheses, and where the opening square bracket of the array is on the +same line as the opening parenthesis of the method call, shall have +their first element indented one step (two spaces) more than the +position inside the opening parenthesis. + +Other array literals shall have their first element indented one step +more than the start of the line where the opening square bracket is. + +This default style is called 'special_inside_parentheses'. Alternative +styles are 'consistent' and 'align_brackets'. Here are examples: + +=== Examples + +==== EnforcedStyle: special_inside_parentheses (default) + +[source,ruby] +---- +# The `special_inside_parentheses` style enforces that the first +# element in an array literal where the opening bracket and first +# element are on separate lines is indented one step (two spaces) more +# than the position inside the opening parenthesis. + +#bad +array = [ + :value +] +and_in_a_method_call([ + :no_difference + ]) + +#good +array = [ + :value +] +but_in_a_method_call([ + :its_like_this + ]) +---- + +==== EnforcedStyle: consistent + +[source,ruby] +---- +# The `consistent` style enforces that the first element in an array +# literal where the opening bracket and the first element are on +# separate lines is indented the same as an array literal which is not +# defined inside a method call. + +#bad +# consistent +array = [ + :value +] +but_in_a_method_call([ + :its_like_this +]) + +#good +array = [ + :value +] +and_in_a_method_call([ + :no_difference +]) +---- + +==== EnforcedStyle: align_brackets + +[source,ruby] +---- +# The `align_brackets` style enforces that the opening and closing +# brackets are indented to the same position. + +#bad +# align_brackets +and_now_for_something = [ + :completely_different +] + +#good +# align_brackets +and_now_for_something = [ + :completely_different + ] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `special_inside_parentheses` +| `special_inside_parentheses`, `consistent`, `align_brackets` + +| IndentationWidth +| `` +| Integer +|=== + +== Layout/FirstArrayElementLineBreak + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for a line break before the first element in a +multi-line array. + +=== Examples + +[source,ruby] +---- +# bad +[ :a, + :b] + +# good +[ + :a, + :b] +---- + +== Layout/FirstHashElementIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.68 +| 0.77 +|=== + +This cop checks the indentation of the first key in a hash literal +where the opening brace and the first key are on separate lines. The +other keys' indentations are handled by the HashAlignment cop. + +By default, Hash literals that are arguments in a method call with +parentheses, and where the opening curly brace of the hash is on the +same line as the opening parenthesis of the method call, shall have +their first key indented one step (two spaces) more than the position +inside the opening parenthesis. + +Other hash literals shall have their first key indented one step more +than the start of the line where the opening curly brace is. + +This default style is called 'special_inside_parentheses'. Alternative +styles are 'consistent' and 'align_braces'. Here are examples: + +=== Examples + +==== EnforcedStyle: special_inside_parentheses (default) + +[source,ruby] +---- +# The `special_inside_parentheses` style enforces that the first key +# in a hash literal where the opening brace and the first key are on +# separate lines is indented one step (two spaces) more than the +# position inside the opening parentheses. + +# bad +hash = { + key: :value +} +and_in_a_method_call({ + no: :difference + }) + +# good +special_inside_parentheses +hash = { + key: :value +} +but_in_a_method_call({ + its_like: :this + }) +---- + +==== EnforcedStyle: consistent + +[source,ruby] +---- +# The `consistent` style enforces that the first key in a hash +# literal where the opening brace and the first key are on +# separate lines is indented the same as a hash literal which is not +# defined inside a method call. + +# bad +hash = { + key: :value +} +but_in_a_method_call({ + its_like: :this + }) + +# good +hash = { + key: :value +} +and_in_a_method_call({ + no: :difference +}) +---- + +==== EnforcedStyle: align_braces + +[source,ruby] +---- +# The `align_brackets` style enforces that the opening and closing +# braces are indented to the same position. + +# bad +and_now_for_something = { + completely: :different +} + +# good +and_now_for_something = { + completely: :different + } +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `special_inside_parentheses` +| `special_inside_parentheses`, `consistent`, `align_braces` + +| IndentationWidth +| `` +| Integer +|=== + +== Layout/FirstHashElementLineBreak + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for a line break before the first element in a +multi-line hash. + +=== Examples + +[source,ruby] +---- +# bad +{ a: 1, + b: 2} + +# good +{ + a: 1, + b: 2 } +---- + +== Layout/FirstMethodArgumentLineBreak + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for a line break before the first argument in a +multi-line method call. + +=== Examples + +[source,ruby] +---- +# bad +method(foo, bar, + baz) + +# good +method( + foo, bar, + baz) + +# ignored +method foo, bar, + baz +---- + +== Layout/FirstMethodParameterLineBreak + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for a line break before the first parameter in a +multi-line method parameter definition. + +=== Examples + +[source,ruby] +---- +# bad +def method(foo, bar, + baz) + do_something +end + +# good +def method( + foo, bar, + baz) + do_something +end + +# ignored +def method foo, + bar + do_something +end +---- + +== Layout/FirstParameterIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.77 +|=== + +This cop checks the indentation of the first parameter in a method +definition. Parameters after the first one are checked by +Layout/ParameterAlignment, not by this cop. + +For indenting the first argument of method _calls_, check out +Layout/FirstArgumentIndentation, which supports options related to +nesting that are irrelevant for method _definitions_. + +=== Examples + +[source,ruby] +---- +# bad +def some_method( +first_param, +second_param) + 123 +end +---- + +==== EnforcedStyle: consistent (default) + +[source,ruby] +---- +# The first parameter should always be indented one step more than the +# preceding line. + +# good +def some_method( + first_param, +second_param) + 123 +end +---- + +==== EnforcedStyle: align_parentheses + +[source,ruby] +---- +# The first parameter should always be indented one step more than the +# opening parenthesis. + +# good +def some_method( + first_param, +second_param) + 123 +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `consistent` +| `consistent`, `align_parentheses` + +| IndentationWidth +| `` +| Integer +|=== + +== Layout/HashAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.77 +|=== + +Check that the keys, separators, and values of a multi-line hash +literal are aligned according to configuration. The configuration +options are: + +* key (left align keys, one space before hash rockets and values) +* separator (align hash rockets and colons, right align keys) +* table (left align keys, hash rockets, and values) + +The treatment of hashes passed as the last argument to a method call +can also be configured. The options are: + +* always_inspect +* always_ignore +* ignore_implicit (without curly braces) + +Alternatively you can specify multiple allowed styles. That's done by +passing a list of styles to EnforcedStyles. + +=== Examples + +==== EnforcedHashRocketStyle: key (default) + +[source,ruby] +---- +# bad +{ + :foo => bar, + :ba => baz +} +{ + :foo => bar, + :ba => baz +} + +# good +{ + :foo => bar, + :ba => baz +} +---- + +==== EnforcedHashRocketStyle: separator + +[source,ruby] +---- +# bad +{ + :foo => bar, + :ba => baz +} +{ + :foo => bar, + :ba => baz +} + +# good +{ + :foo => bar, + :ba => baz +} +---- + +==== EnforcedHashRocketStyle: table + +[source,ruby] +---- +# bad +{ + :foo => bar, + :ba => baz +} + +# good +{ + :foo => bar, + :ba => baz +} +---- + +==== EnforcedColonStyle: key (default) + +[source,ruby] +---- +# bad +{ + foo: bar, + ba: baz +} +{ + foo: bar, + ba: baz +} + +# good +{ + foo: bar, + ba: baz +} +---- + +==== EnforcedColonStyle: separator + +[source,ruby] +---- +# bad +{ + foo: bar, + ba: baz +} + +# good +{ + foo: bar, + ba: baz +} +---- + +==== EnforcedColonStyle: table + +[source,ruby] +---- +# bad +{ + foo: bar, + ba: baz +} + +# good +{ + foo: bar, + ba: baz +} +---- + +==== EnforcedLastArgumentHashStyle: always_inspect (default) + +[source,ruby] +---- +# Inspect both implicit and explicit hashes. + +# bad +do_something(foo: 1, + bar: 2) + +# bad +do_something({foo: 1, + bar: 2}) + +# good +do_something(foo: 1, + bar: 2) + +# good +do_something( + foo: 1, + bar: 2 +) + +# good +do_something({foo: 1, + bar: 2}) + +# good +do_something({ + foo: 1, + bar: 2 +}) +---- + +==== EnforcedLastArgumentHashStyle: always_ignore + +[source,ruby] +---- +# Ignore both implicit and explicit hashes. + +# good +do_something(foo: 1, + bar: 2) + +# good +do_something({foo: 1, + bar: 2}) +---- + +==== EnforcedLastArgumentHashStyle: ignore_implicit + +[source,ruby] +---- +# Ignore only implicit hashes. + +# bad +do_something({foo: 1, + bar: 2}) + +# good +do_something(foo: 1, + bar: 2) +---- + +==== EnforcedLastArgumentHashStyle: ignore_explicit + +[source,ruby] +---- +# Ignore only explicit hashes. + +# bad +do_something(foo: 1, + bar: 2) + +# good +do_something({foo: 1, + bar: 2}) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedHashRocketStyle +| `key` +| `key`, `separator`, `table` + +| EnforcedColonStyle +| `key` +| `key`, `separator`, `table` + +| EnforcedLastArgumentHashStyle +| `always_inspect` +| `always_inspect`, `always_ignore`, `ignore_implicit`, `ignore_explicit` +|=== + +== Layout/HeredocArgumentClosingParenthesis + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.68 +| - +|=== + +This cop checks for the placement of the closing parenthesis +in a method call that passes a HEREDOC string as an argument. +It should be placed at the end of the line containing the +opening HEREDOC tag. + +=== Examples + +[source,ruby] +---- +# bad + + foo(<<-SQL + bar + SQL + ) + + foo(<<-SQL, 123, <<-NOSQL, + bar + SQL + baz + NOSQL + ) + + foo( + bar(<<-SQL + baz + SQL + ), + 123, + ) + +# good + + foo(<<-SQL) + bar + SQL + + foo(<<-SQL, 123, <<-NOSQL) + bar + SQL + baz + NOSQL + + foo( + bar(<<-SQL), + baz + SQL + 123, + ) +---- + +=== References + +* https://rubystyle.guide#heredoc-argument-closing-parentheses + +== Layout/HeredocIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.85 +|=== + +This cop checks the indentation of the here document bodies. The bodies +are indented one step. + +Note: When ``Layout/LineLength``'s `AllowHeredoc` is false (not default), + this cop does not add any offenses for long here documents to + avoid `Layout/LineLength`'s offenses. + +=== Examples + +[source,ruby] +---- +# bad +<<-RUBY +something +RUBY + +# good +<<~RUBY + something +RUBY +---- + +=== References + +* https://rubystyle.guide#squiggly-heredocs + +== Layout/IndentationConsistency + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for inconsistent indentation. + +The difference between `indented_internal_methods` and `normal` is +that the `indented_internal_methods` style prescribes that in +classes and modules the `protected` and `private` modifier keywords +shall be indented the same as public methods and that protected and +private members shall be indented one step more than the modifiers. +Other than that, both styles mean that entities on the same logical +depth shall have the same indentation. + +=== Examples + +==== EnforcedStyle: normal (default) + +[source,ruby] +---- +# bad +class A + def test + puts 'hello' + puts 'world' + end +end + +# bad +class A + def test + puts 'hello' + puts 'world' + end + + protected + + def foo + end + + private + + def bar + end +end + +# good +class A + def test + puts 'hello' + puts 'world' + end +end + +# good +class A + def test + puts 'hello' + puts 'world' + end + + protected + + def foo + end + + private + + def bar + end +end +---- + +==== EnforcedStyle: indented_internal_methods + +[source,ruby] +---- +# bad +class A + def test + puts 'hello' + puts 'world' + end +end + +# bad +class A + def test + puts 'hello' + puts 'world' + end + + protected + + def foo + end + + private + + def bar + end +end + +# good +class A + def test + puts 'hello' + puts 'world' + end +end + +# good +class A + def test + puts 'hello' + puts 'world' + end + + protected + + def foo + end + + private + + def bar + end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `normal` +| `normal`, `indented_internal_methods` +|=== + +=== References + +* https://rubystyle.guide#spaces-indentation +* https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#follow-the-coding-conventions + +== Layout/IndentationStyle + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.82 +|=== + +This cop checks that the indentation method is consistent. +Either tabs only or spaces only are used for indentation. + +=== Examples + +==== EnforcedStyle: spaces (default) + +[source,ruby] +---- +# bad +# This example uses a tab to indent bar. +def foo + bar +end + +# good +# This example uses spaces to indent bar. +def foo + bar +end +---- + +==== EnforcedStyle: tabs + +[source,ruby] +---- +# bad +# This example uses spaces to indent bar. +def foo + bar +end + +# good +# This example uses a tab to indent bar. +def foo + bar +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IndentationWidth +| `` +| Integer + +| EnforcedStyle +| `spaces` +| `spaces`, `tabs` +|=== + +=== References + +* https://rubystyle.guide#spaces-indentation + +== Layout/IndentationWidth + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for indentation that doesn't use the specified number +of spaces. + +See also the IndentationConsistency cop which is the companion to this +one. + +=== Examples + +[source,ruby] +---- +# bad +class A + def test + puts 'hello' + end +end + +# good +class A + def test + puts 'hello' + end +end +---- + +==== IgnoredPatterns: ['^\s*module'] + +[source,ruby] +---- +# bad +module A +class B + def test + puts 'hello' + end +end +end + +# good +module A +class B + def test + puts 'hello' + end +end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Width +| `2` +| Integer + +| IgnoredPatterns +| `[]` +| Array +|=== + +=== References + +* https://rubystyle.guide#spaces-indentation + +== Layout/InitialIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for indentation of the first non-blank non-comment +line in a file. + +=== Examples + +[source,ruby] +---- +# bad + class A + def foo; end + end + +# good +class A + def foo; end +end +---- + +== Layout/LeadingCommentSpace + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.73 +|=== + +This cop checks whether comments have a leading space after the +`#` denoting the start of the comment. The leading space is not +required for some RDoc special syntax, like `#++`, `#--`, +`#:nodoc`, `=begin`- and `=end` comments, "shebang" directives, +or rackup options. + +=== Examples + +[source,ruby] +---- +# bad +#Some comment + +# good +# Some comment +---- + +==== AllowDoxygenCommentStyle: false (default) + +[source,ruby] +---- +# bad + +#** +# Some comment +# Another line of comment +#* +---- + +==== AllowDoxygenCommentStyle: true + +[source,ruby] +---- +# good + +#** +# Some comment +# Another line of comment +#* +---- + +==== AllowGemfileRubyComment: false (default) + +[source,ruby] +---- +# bad + +#ruby=2.7.0 +#ruby-gemset=myproject +---- + +==== AllowGemfileRubyComment: true + +[source,ruby] +---- +# good + +#ruby=2.7.0 +#ruby-gemset=myproject +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowDoxygenCommentStyle +| `false` +| Boolean + +| AllowGemfileRubyComment +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#hash-space + +== Layout/LeadingEmptyLines + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.57 +| 0.77 +|=== + +This cop checks for unnecessary leading blank lines at the beginning +of a file. + +=== Examples + +[source,ruby] +---- +# bad +# (start of file) + +class Foo +end + +# bad +# (start of file) + +# a comment + +# good +# (start of file) +class Foo +end + +# good +# (start of file) +# a comment +---- + +== Layout/LineLength + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.25 +| 0.84 +|=== + +This cop checks the length of lines in the source code. +The maximum length is configurable. +The tab size is configured in the `IndentationWidth` +of the `Layout/IndentationStyle` cop. +It also ignores a shebang line by default. + +This cop has some autocorrection capabilities. +It can programmatically shorten certain long lines by +inserting line breaks into expressions that can be safely +split across lines. These include arrays, hashes, and +method calls with argument lists. + +If autocorrection is enabled, the following Layout cops +are recommended to further format the broken lines. +(Many of these are enabled by default.) + +* ArgumentAlignment +* BlockAlignment +* BlockDelimiters +* BlockEndNewline +* ClosingParenthesisIndentation +* FirstArgumentIndentation +* FirstArrayElementIndentation +* FirstHashElementIndentation +* FirstParameterIndentation +* HashAlignment +* IndentationWidth +* MultilineArrayLineBreaks +* MultilineBlockLayout +* MultilineHashBraceLayout +* MultilineHashKeyLineBreaks +* MultilineMethodArgumentLineBreaks +* ParameterAlignment + +Together, these cops will pretty print hashes, arrays, +method calls, etc. For example, let's say the max columns +is 25: + +=== Examples + +[source,ruby] +---- +# bad +{foo: "0000000000", bar: "0000000000", baz: "0000000000"} + +# good +{foo: "0000000000", +bar: "0000000000", baz: "0000000000"} + +# good (with recommended cops enabled) +{ + foo: "0000000000", + bar: "0000000000", + baz: "0000000000", +} +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AutoCorrect +| `false` +| Boolean + +| Max +| `120` +| Integer + +| AllowHeredoc +| `true` +| Boolean + +| AllowURI +| `true` +| Boolean + +| URISchemes +| `http`, `https` +| Array + +| IgnoreCopDirectives +| `true` +| Boolean + +| IgnoredPatterns +| `[]` +| Array +|=== + +=== References + +* https://rubystyle.guide#max-line-length + +== Layout/MultilineArrayBraceLayout + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks that the closing brace in an array literal is either +on the same line as the last array element or on a new line. + +When using the `symmetrical` (default) style: + +If an array's opening brace is on the same line as the first element +of the array, then the closing brace should be on the same line as +the last element of the array. + +If an array's opening brace is on the line above the first element +of the array, then the closing brace should be on the line below +the last element of the array. + +When using the `new_line` style: + +The closing brace of a multi-line array literal must be on the line +after the last element of the array. + +When using the `same_line` style: + +The closing brace of a multi-line array literal must be on the same +line as the last element of the array. + +=== Examples + +==== EnforcedStyle: symmetrical (default) + +[source,ruby] +---- +# bad +[ :a, + :b +] + +# bad +[ + :a, + :b ] + +# good +[ :a, + :b ] + +# good +[ + :a, + :b +] +---- + +==== EnforcedStyle: new_line + +[source,ruby] +---- +# bad +[ + :a, + :b ] + +# bad +[ :a, + :b ] + +# good +[ :a, + :b +] + +# good +[ + :a, + :b +] +---- + +==== EnforcedStyle: same_line + +[source,ruby] +---- +# bad +[ :a, + :b +] + +# bad +[ + :a, + :b +] + +# good +[ + :a, + :b ] + +# good +[ :a, + :b ] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `symmetrical` +| `symmetrical`, `new_line`, `same_line` +|=== + +== Layout/MultilineArrayLineBreaks + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.67 +| - +|=== + +This cop ensures that each item in a multi-line array +starts on a separate line. + +=== Examples + +[source,ruby] +---- +# bad +[ + a, b, + c +] + +# good +[ + a, + b, + c +] +---- + +== Layout/MultilineAssignmentLayout + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks whether the multiline assignments have a newline +after the assignment operator. + +=== Examples + +==== EnforcedStyle: new_line (default) + +[source,ruby] +---- +# bad +foo = if expression + 'bar' +end + +# good +foo = + if expression + 'bar' + end + +# good +foo = + begin + compute + rescue => e + nil + end +---- + +==== EnforcedStyle: same_line + +[source,ruby] +---- +# good +foo = if expression + 'bar' +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `new_line` +| `same_line`, `new_line` +|=== + +=== References + +* https://rubystyle.guide#indent-conditional-assignment + +== Layout/MultilineBlockLayout + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks whether the multiline do end blocks have a newline +after the start of the block. Additionally, it checks whether the block +arguments, if any, are on the same line as the start of the +block. Putting block arguments on separate lines, because the whole +line would otherwise be too long, is accepted. + +=== Examples + +[source,ruby] +---- +# bad +blah do |i| foo(i) + bar(i) +end + +# bad +blah do + |i| foo(i) + bar(i) +end + +# good +blah do |i| + foo(i) + bar(i) +end + +# bad +blah { |i| foo(i) + bar(i) +} + +# good +blah { |i| + foo(i) + bar(i) +} + +# good +blah { | + long_list, + of_parameters, + that_would_not, + fit_on_one_line +| + foo(i) + bar(i) +} +---- + +== Layout/MultilineHashBraceLayout + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks that the closing brace in a hash literal is either +on the same line as the last hash element, or a new line. + +When using the `symmetrical` (default) style: + +If a hash's opening brace is on the same line as the first element +of the hash, then the closing brace should be on the same line as +the last element of the hash. + +If a hash's opening brace is on the line above the first element +of the hash, then the closing brace should be on the line below +the last element of the hash. + +When using the `new_line` style: + +The closing brace of a multi-line hash literal must be on the line +after the last element of the hash. + +When using the `same_line` style: + +The closing brace of a multi-line hash literal must be on the same +line as the last element of the hash. + +=== Examples + +==== EnforcedStyle: symmetrical (default) + +[source,ruby] +---- +# bad +{ a: 1, + b: 2 +} +# bad +{ + a: 1, + b: 2 } + +# good +{ a: 1, + b: 2 } + +# good +{ + a: 1, + b: 2 +} +---- + +==== EnforcedStyle: new_line + +[source,ruby] +---- +# bad +{ + a: 1, + b: 2 } + +# bad +{ a: 1, + b: 2 } + +# good +{ a: 1, + b: 2 +} + +# good +{ + a: 1, + b: 2 +} +---- + +==== EnforcedStyle: same_line + +[source,ruby] +---- +# bad +{ a: 1, + b: 2 +} + +# bad +{ + a: 1, + b: 2 +} + +# good +{ + a: 1, + b: 2 } + +# good +{ a: 1, + b: 2 } +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `symmetrical` +| `symmetrical`, `new_line`, `same_line` +|=== + +== Layout/MultilineHashKeyLineBreaks + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.67 +| - +|=== + +This cop ensures that each key in a multi-line hash +starts on a separate line. + +=== Examples + +[source,ruby] +---- +# bad +{ + a: 1, b: 2, + c: 3 +} + +# good +{ + a: 1, + b: 2, + c: 3 +} +---- + +== Layout/MultilineMethodArgumentLineBreaks + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.67 +| - +|=== + +This cop ensures that each argument in a multi-line method call +starts on a separate line. + +=== Examples + +[source,ruby] +---- +# bad +foo(a, b, + c +) + +# good +foo( + a, + b, + c +) +---- + +== Layout/MultilineMethodCallBraceLayout + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks that the closing brace in a method call is either +on the same line as the last method argument, or a new line. + +When using the `symmetrical` (default) style: + +If a method call's opening brace is on the same line as the first +argument of the call, then the closing brace should be on the same +line as the last argument of the call. + +If an method call's opening brace is on the line above the first +argument of the call, then the closing brace should be on the line +below the last argument of the call. + +When using the `new_line` style: + +The closing brace of a multi-line method call must be on the line +after the last argument of the call. + +When using the `same_line` style: + +The closing brace of a multi-line method call must be on the same +line as the last argument of the call. + +=== Examples + +==== EnforcedStyle: symmetrical (default) + +[source,ruby] +---- +# bad +foo(a, + b +) + +# bad +foo( + a, + b) + +# good +foo(a, + b) + +# good +foo( + a, + b +) +---- + +==== EnforcedStyle: new_line + +[source,ruby] +---- +# bad +foo( + a, + b) + +# bad +foo(a, + b) + +# good +foo(a, + b +) + +# good +foo( + a, + b +) +---- + +==== EnforcedStyle: same_line + +[source,ruby] +---- +# bad +foo(a, + b +) + +# bad +foo( + a, + b +) + +# good +foo( + a, + b) + +# good +foo(a, + b) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `symmetrical` +| `symmetrical`, `new_line`, `same_line` +|=== + +== Layout/MultilineMethodCallIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks the indentation of the method name part in method calls +that span more than one line. + +=== Examples + +==== EnforcedStyle: aligned (default) + +[source,ruby] +---- +# bad +while myvariable +.b + # do something +end + +# good +while myvariable + .b + # do something +end + +# good +Thing.a + .b + .c +---- + +==== EnforcedStyle: indented + +[source,ruby] +---- +# good +while myvariable + .b + + # do something +end +---- + +==== EnforcedStyle: indented_relative_to_receiver + +[source,ruby] +---- +# good +while myvariable + .a + .b + + # do something +end + +# good +myvariable = Thing + .a + .b + .c +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `aligned` +| `aligned`, `indented`, `indented_relative_to_receiver` + +| IndentationWidth +| `` +| Integer +|=== + +== Layout/MultilineMethodDefinitionBraceLayout + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks that the closing brace in a method definition is either +on the same line as the last method parameter, or a new line. + +When using the `symmetrical` (default) style: + +If a method definition's opening brace is on the same line as the +first parameter of the definition, then the closing brace should be +on the same line as the last parameter of the definition. + +If an method definition's opening brace is on the line above the first +parameter of the definition, then the closing brace should be on the +line below the last parameter of the definition. + +When using the `new_line` style: + +The closing brace of a multi-line method definition must be on the line +after the last parameter of the definition. + +When using the `same_line` style: + +The closing brace of a multi-line method definition must be on the same +line as the last parameter of the definition. + +=== Examples + +==== EnforcedStyle: symmetrical (default) + +[source,ruby] +---- +# bad +def foo(a, + b +) +end + +# bad +def foo( + a, + b) +end + +# good +def foo(a, + b) +end + +# good +def foo( + a, + b +) +end +---- + +==== EnforcedStyle: new_line + +[source,ruby] +---- +# bad +def foo( + a, + b) +end + +# bad +def foo(a, + b) +end + +# good +def foo(a, + b +) +end + +# good +def foo( + a, + b +) +end +---- + +==== EnforcedStyle: same_line + +[source,ruby] +---- +# bad +def foo(a, + b +) +end + +# bad +def foo( + a, + b +) +end + +# good +def foo( + a, + b) +end + +# good +def foo(a, + b) +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `symmetrical` +| `symmetrical`, `new_line`, `same_line` +|=== + +== Layout/MultilineOperationIndentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks the indentation of the right hand side operand in +binary operations that span more than one line. + +The `aligned` style checks that operators are aligned if they are part +of an `if` or `while` condition, a `return` statement, etc. In other +contexts, the second operand should be indented regardless of enforced +style. + +=== Examples + +==== EnforcedStyle: aligned (default) + +[source,ruby] +---- +# bad +if a + + b + something && + something_else +end + +# good +if a + + b + something && + something_else +end +---- + +==== EnforcedStyle: indented + +[source,ruby] +---- +# bad +if a + + b + something && + something_else +end + +# good +if a + + b + something && + something_else +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `aligned` +| `aligned`, `indented` + +| IndentationWidth +| `` +| Integer +|=== + +== Layout/ParameterAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.77 +|=== + +Here we check if the parameters on a multi-line method call or +definition are aligned. + +To set the alignment of the first argument, use the cop +FirstParameterIndentation. + +=== Examples + +==== EnforcedStyle: with_first_parameter (default) + +[source,ruby] +---- +# good + +def foo(bar, + baz) + 123 +end + +def foo( + bar, + baz +) + 123 +end + +# bad + +def foo(bar, + baz) + 123 +end + +# bad + +def foo( + bar, + baz) + 123 +end +---- + +==== EnforcedStyle: with_fixed_indentation + +[source,ruby] +---- +# good + +def foo(bar, + baz) + 123 +end + +def foo( + bar, + baz +) + 123 +end + +# bad + +def foo(bar, + baz) + 123 +end + +# bad + +def foo( + bar, + baz) + 123 +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `with_first_parameter` +| `with_first_parameter`, `with_fixed_indentation` + +| IndentationWidth +| `` +| Integer +|=== + +=== References + +* https://rubystyle.guide#no-double-indent + +== Layout/RescueEnsureAlignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks whether the rescue and ensure keywords are aligned +properly. + +=== Examples + +[source,ruby] +---- +# bad +begin + something + rescue + puts 'error' +end + +# good +begin + something +rescue + puts 'error' +end +---- + +== Layout/SpaceAfterColon + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for colon (:) not followed by some kind of space. +N.B. this cop does not handle spaces after a ternary operator, which are +instead handled by Layout/SpaceAroundOperators. + +=== Examples + +[source,ruby] +---- +# bad +def f(a:, b:2); {a:3}; end + +# good +def f(a:, b: 2); {a: 3}; end +---- + +=== References + +* https://rubystyle.guide#spaces-operators + +== Layout/SpaceAfterComma + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for comma (,) not followed by some kind of space. + +=== Examples + +[source,ruby] +---- +# bad +[1,2] +{ foo:bar,} + +# good +[1, 2] +{ foo:bar, } +---- + +=== References + +* https://rubystyle.guide#spaces-operators + +== Layout/SpaceAfterMethodName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for space between a method name and a left parenthesis in defs. + +=== Examples + +[source,ruby] +---- +# bad +def func (x) end +def method= (y) end + +# good +def func(x) end +def method=(y) end +---- + +=== References + +* https://rubystyle.guide#parens-no-spaces + +== Layout/SpaceAfterNot + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for space after `!`. + +=== Examples + +[source,ruby] +---- +# bad +! something + +# good +!something +---- + +=== References + +* https://rubystyle.guide#no-space-bang + +== Layout/SpaceAfterSemicolon + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for semicolon (;) not followed by some kind of space. + +=== Examples + +[source,ruby] +---- +# bad +x = 1;y = 2 + +# good +x = 1; y = 2 +---- + +=== References + +* https://rubystyle.guide#spaces-operators + +== Layout/SpaceAroundBlockParameters + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks the spacing inside and after block parameters pipes. Line breaks +inside parameter pipes are checked by `Layout/MultilineBlockLayout` and +not by this cop. + +=== Examples + +==== EnforcedStyleInsidePipes: no_space (default) + +[source,ruby] +---- +# bad +{}.each { | x, y |puts x } +->( x, y ) { puts x } + +# good +{}.each { |x, y| puts x } +->(x, y) { puts x } +---- + +==== EnforcedStyleInsidePipes: space + +[source,ruby] +---- +# bad +{}.each { |x, y| puts x } +->(x, y) { puts x } + +# good +{}.each { | x, y | puts x } +->( x, y ) { puts x } +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyleInsidePipes +| `no_space` +| `space`, `no_space` +|=== + +== Layout/SpaceAroundEqualsInParameterDefault + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks that the equals signs in parameter default assignments +have or don't have surrounding space depending on configuration. + +=== Examples + +==== EnforcedStyle: space (default) + +[source,ruby] +---- +# bad +def some_method(arg1=:default, arg2=nil, arg3=[]) + # do something... +end + +# good +def some_method(arg1 = :default, arg2 = nil, arg3 = []) + # do something... +end +---- + +==== EnforcedStyle: no_space + +[source,ruby] +---- +# bad +def some_method(arg1 = :default, arg2 = nil, arg3 = []) + # do something... +end + +# good +def some_method(arg1=:default, arg2=nil, arg3=[]) + # do something... +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `space` +| `space`, `no_space` +|=== + +=== References + +* https://rubystyle.guide#spaces-around-equals + +== Layout/SpaceAroundKeyword + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks the spacing around the keywords. + +=== Examples + +[source,ruby] +---- +# bad +something 'test'do|x| +end + +while(something) +end + +something = 123if test + +# good +something 'test' do |x| +end + +while (something) +end + +something = 123 if test +---- + +== Layout/SpaceAroundMethodCallOperator + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.82 +| - +|=== + +Checks method call operators to not have spaces around them. + +=== Examples + +[source,ruby] +---- +# bad +foo. bar +foo .bar +foo . bar +foo. bar .buzz +foo + . bar + . buzz +foo&. bar +foo &.bar +foo &. bar +foo &. bar&. buzz +RuboCop:: Cop +RuboCop:: Cop:: Cop +:: RuboCop::Cop + +# good +foo.bar +foo.bar.buzz +foo + .bar + .buzz +foo&.bar +foo&.bar&.buzz +RuboCop::Cop +RuboCop::Cop::Cop +::RuboCop::Cop +---- + +== Layout/SpaceAroundOperators + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks that operators have space around them, except for ** which +should or shouldn't have surrounding space depending on configuration. + +This cop has `AllowForAlignment` option. When `true`, allows most +uses of extra spacing if the intent is to align with an operator on +the previous or next line, not counting empty lines or comment lines. + +=== Examples + +[source,ruby] +---- +# bad +total = 3*4 +"apple"+"juice" +my_number = 38/4 + +# good +total = 3 * 4 +"apple" + "juice" +my_number = 38 / 4 +---- + +==== AllowForAlignment: true (default) + +[source,ruby] +---- +# good +{ + 1 => 2, + 11 => 3 +} +---- + +==== AllowForAlignment: false + +[source,ruby] +---- +# bad +{ + 1 => 2, + 11 => 3 +} +---- + +==== EnforcedStyleForExponentOperator: no_space (default) + +[source,ruby] +---- +# bad +a ** b + +# good +a**b +---- + +==== EnforcedStyleForExponentOperator: space + +[source,ruby] +---- +# bad +a**b + +# good +a ** b +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowForAlignment +| `true` +| Boolean + +| EnforcedStyleForExponentOperator +| `no_space` +| `space`, `no_space` +|=== + +=== References + +* https://rubystyle.guide#spaces-operators + +== Layout/SpaceBeforeBlockBraces + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.52.1 +|=== + +Checks that block braces have or don't have a space before the opening +brace depending on configuration. + +=== Examples + +==== EnforcedStyle: space (default) + +[source,ruby] +---- +# bad +foo.map{ |a| + a.bar.to_s +} + +# good +foo.map { |a| + a.bar.to_s +} +---- + +==== EnforcedStyle: no_space + +[source,ruby] +---- +# bad +foo.map { |a| + a.bar.to_s +} + +# good +foo.map{ |a| + a.bar.to_s +} +---- + +==== EnforcedStyleForEmptyBraces: space (default) + +[source,ruby] +---- +# bad +7.times{} + +# good +7.times {} +---- + +==== EnforcedStyleForEmptyBraces: no_space + +[source,ruby] +---- +# bad +7.times {} + +# good +7.times{} +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `space` +| `space`, `no_space` + +| EnforcedStyleForEmptyBraces +| `space` +| `space`, `no_space` +|=== + +== Layout/SpaceBeforeComma + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for comma (,) preceded by space. + +=== Examples + +[source,ruby] +---- +# bad +[1 , 2 , 3] +a(1 , 2) +each { |a , b| } + +# good +[1, 2, 3] +a(1, 2) +each { |a, b| } +---- + +== Layout/SpaceBeforeComment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for missing space between a token and a comment on the +same line. + +=== Examples + +[source,ruby] +---- +# bad +1 + 1# this operation does ... + +# good +1 + 1 # this operation does ... +---- + +== Layout/SpaceBeforeFirstArg + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks that exactly one space is used between a method name and the +first argument for method calls without parentheses. + +Alternatively, extra spaces can be added to align the argument with +something on a preceding or following line, if the AllowForAlignment +config parameter is true. + +=== Examples + +[source,ruby] +---- +# bad +something x +something y, z +something'hello' + +# good +something x +something y, z +something 'hello' +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowForAlignment +| `true` +| Boolean +|=== + +== Layout/SpaceBeforeSemicolon + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for semicolon (;) preceded by space. + +=== Examples + +[source,ruby] +---- +# bad +x = 1 ; y = 2 + +# good +x = 1; y = 2 +---- + +== Layout/SpaceInLambdaLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for spaces between `->` and opening parameter +parenthesis (`(`) in lambda literals. + +=== Examples + +==== EnforcedStyle: require_no_space (default) + +[source,ruby] +---- +# bad +a = -> (x, y) { x + y } + +# good +a = ->(x, y) { x + y } +---- + +==== EnforcedStyle: require_space + +[source,ruby] +---- +# bad +a = ->(x, y) { x + y } + +# good +a = -> (x, y) { x + y } +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `require_no_space` +| `require_no_space`, `require_space` +|=== + +== Layout/SpaceInsideArrayLiteralBrackets + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| - +|=== + +Checks that brackets used for array literals have or don't have +surrounding space depending on configuration. + +=== Examples + +==== EnforcedStyle: space + +[source,ruby] +---- +# The `space` style enforces that array literals have +# surrounding space. + +# bad +array = [a, b, c, d] + +# good +array = [ a, b, c, d ] +---- + +==== EnforcedStyle: no_space (default) + +[source,ruby] +---- +# The `no_space` style enforces that array literals have +# no surrounding space. + +# bad +array = [ a, b, c, d ] + +# good +array = [a, b, c, d] +---- + +==== EnforcedStyle: compact + +[source,ruby] +---- +# The `compact` style normally requires a space inside +# array brackets, with the exception that successive left +# or right brackets are collapsed together in nested arrays. + +# bad +array = [ a, [ b, c ] ] +array = [ + [ a ], + [ b, c ] +] + +# good +array = [ a, [ b, c ]] +array = [[ a ], + [ b, c ]] +---- + +==== EnforcedStyleForEmptyBrackets: no_space (default) + +[source,ruby] +---- +# The `no_space` EnforcedStyleForEmptyBrackets style enforces that +# empty array brackets do not contain spaces. + +# bad +foo = [ ] +bar = [ ] + +# good +foo = [] +bar = [] +---- + +==== EnforcedStyleForEmptyBrackets: space + +[source,ruby] +---- +# The `space` EnforcedStyleForEmptyBrackets style enforces that +# empty array brackets contain exactly one space. + +# bad +foo = [] +bar = [ ] + +# good +foo = [ ] +bar = [ ] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `no_space` +| `space`, `no_space`, `compact` + +| EnforcedStyleForEmptyBrackets +| `no_space` +| `space`, `no_space` +|=== + +== Layout/SpaceInsideArrayPercentLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for unnecessary additional spaces inside array percent literals +(i.e. %i/%w). + +=== Examples + +[source,ruby] +---- +# bad +%w(foo bar baz) +# good +%i(foo bar baz) +---- + +== Layout/SpaceInsideBlockBraces + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks that block braces have or don't have surrounding space inside +them on configuration. For blocks taking parameters, it checks that the +left brace has or doesn't have trailing space depending on +configuration. + +=== Examples + +==== EnforcedStyle: space (default) + +[source,ruby] +---- +# The `space` style enforces that block braces have +# surrounding space. + +# bad +some_array.each {puts e} + +# good +some_array.each { puts e } +---- + +==== EnforcedStyle: no_space + +[source,ruby] +---- +# The `no_space` style enforces that block braces don't +# have surrounding space. + +# bad +some_array.each { puts e } + +# good +some_array.each {puts e} +---- + +==== EnforcedStyleForEmptyBraces: no_space (default) + +[source,ruby] +---- +# The `no_space` EnforcedStyleForEmptyBraces style enforces that +# block braces don't have a space in between when empty. + +# bad +some_array.each { } +some_array.each { } +some_array.each { } + +# good +some_array.each {} +---- + +==== EnforcedStyleForEmptyBraces: space + +[source,ruby] +---- +# The `space` EnforcedStyleForEmptyBraces style enforces that +# block braces have at least a space in between when empty. + +# bad +some_array.each {} + +# good +some_array.each { } +some_array.each { } +some_array.each { } +---- + +==== SpaceBeforeBlockParameters: true (default) + +[source,ruby] +---- +# The SpaceBeforeBlockParameters style set to `true` enforces that +# there is a space between `{` and `|`. Overrides `EnforcedStyle` +# if there is a conflict. + +# bad +[1, 2, 3].each {|n| n * 2 } + +# good +[1, 2, 3].each { |n| n * 2 } +---- + +==== SpaceBeforeBlockParameters: false + +[source,ruby] +---- +# The SpaceBeforeBlockParameters style set to `false` enforces that +# there is no space between `{` and `|`. Overrides `EnforcedStyle` +# if there is a conflict. + +# bad +[1, 2, 3].each { |n| n * 2 } + +# good +[1, 2, 3].each {|n| n * 2 } +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `space` +| `space`, `no_space` + +| EnforcedStyleForEmptyBraces +| `no_space` +| `space`, `no_space` + +| SpaceBeforeBlockParameters +| `true` +| Boolean +|=== + +== Layout/SpaceInsideHashLiteralBraces + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks that braces used for hash literals have or don't have +surrounding space depending on configuration. + +=== Examples + +==== EnforcedStyle: space (default) + +[source,ruby] +---- +# The `space` style enforces that hash literals have +# surrounding space. + +# bad +h = {a: 1, b: 2} + +# good +h = { a: 1, b: 2 } +---- + +==== EnforcedStyle: no_space + +[source,ruby] +---- +# The `no_space` style enforces that hash literals have +# no surrounding space. + +# bad +h = { a: 1, b: 2 } + +# good +h = {a: 1, b: 2} +---- + +==== EnforcedStyle: compact + +[source,ruby] +---- +# The `compact` style normally requires a space inside +# hash braces, with the exception that successive left +# braces or right braces are collapsed together in nested hashes. + +# bad +h = { a: { b: 2 } } +foo = { { a: 1 } => { b: { c: 2 } } } + +# good +h = { a: { b: 2 }} +foo = {{ a: 1 } => { b: { c: 2 }}} +---- + +==== EnforcedStyleForEmptyBraces: no_space (default) + +[source,ruby] +---- +# The `no_space` EnforcedStyleForEmptyBraces style enforces that +# empty hash braces do not contain spaces. + +# bad +foo = { } +bar = { } + +# good +foo = {} +bar = {} +---- + +==== EnforcedStyleForEmptyBraces: space + +[source,ruby] +---- +# The `space` EnforcedStyleForEmptyBraces style enforces that +# empty hash braces contain space. + +# bad +foo = {} + +# good +foo = { } +foo = { } +foo = { } +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `space` +| `space`, `no_space`, `compact` + +| EnforcedStyleForEmptyBraces +| `no_space` +| `space`, `no_space` +|=== + +=== References + +* https://rubystyle.guide#spaces-braces + +== Layout/SpaceInsideParens + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.55 +|=== + +Checks for spaces inside ordinary round parentheses. + +=== Examples + +==== EnforcedStyle: no_space (default) + +[source,ruby] +---- +# The `no_space` style enforces that parentheses do not have spaces. + +# bad +f( 3) +g = (a + 3 ) + +# good +f(3) +g = (a + 3) +---- + +==== EnforcedStyle: space + +[source,ruby] +---- +# The `space` style enforces that parentheses have a space at the +# beginning and end. +# Note: Empty parentheses should not have spaces. + +# bad +f(3) +g = (a + 3) +y( ) + +# good +f( 3 ) +g = ( a + 3 ) +y() +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `no_space` +| `space`, `no_space` +|=== + +=== References + +* https://rubystyle.guide#spaces-braces + +== Layout/SpaceInsidePercentLiteralDelimiters + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for unnecessary additional spaces inside the delimiters of +%i/%w/%x literals. + +=== Examples + +[source,ruby] +---- +# good +%i(foo bar baz) + +# bad +%w( foo bar baz ) + +# bad +%x( ls -l ) +---- + +== Layout/SpaceInsideRangeLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Checks for spaces inside range literals. + +=== Examples + +[source,ruby] +---- +# bad +1 .. 3 + +# good +1..3 + +# bad +'a' .. 'z' + +# good +'a'..'z' +---- + +=== References + +* https://rubystyle.guide#no-space-inside-range-literals + +== Layout/SpaceInsideReferenceBrackets + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| 0.53 +|=== + +Checks that reference brackets have or don't have +surrounding space depending on configuration. + +=== Examples + +==== EnforcedStyle: no_space (default) + +[source,ruby] +---- +# The `no_space` style enforces that reference brackets have +# no surrounding space. + +# bad +hash[ :key ] +array[ index ] + +# good +hash[:key] +array[index] +---- + +==== EnforcedStyle: space + +[source,ruby] +---- +# The `space` style enforces that reference brackets have +# surrounding space. + +# bad +hash[:key] +array[index] + +# good +hash[ :key ] +array[ index ] +---- + +==== EnforcedStyleForEmptyBrackets: no_space (default) + +[source,ruby] +---- +# The `no_space` EnforcedStyleForEmptyBrackets style enforces that +# empty reference brackets do not contain spaces. + +# bad +foo[ ] +foo[ ] + +# good +foo[] +---- + +==== EnforcedStyleForEmptyBrackets: space + +[source,ruby] +---- +# The `space` EnforcedStyleForEmptyBrackets style enforces that +# empty reference brackets contain exactly one space. + +# bad +foo[] +foo[ ] + +# good +foo[ ] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `no_space` +| `space`, `no_space` + +| EnforcedStyleForEmptyBrackets +| `no_space` +| `space`, `no_space` +|=== + +== Layout/SpaceInsideStringInterpolation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +This cop checks for whitespace within string interpolations. + +=== Examples + +==== EnforcedStyle: no_space (default) + +[source,ruby] +---- +# bad + var = "This is the #{ space } example" + +# good + var = "This is the #{no_space} example" +---- + +==== EnforcedStyle: space + +[source,ruby] +---- +# bad + var = "This is the #{no_space} example" + +# good + var = "This is the #{ space } example" +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `no_space` +| `space`, `no_space` +|=== + +=== References + +* https://rubystyle.guide#string-interpolation + +== Layout/TrailingEmptyLines + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.77 +|=== + +This cop looks for trailing blank lines and a final newline in the +source code. + +=== Examples + +==== EnforcedStyle: final_blank_line + +[source,ruby] +---- +# `final_blank_line` looks for one blank line followed by a new line +# at the end of files. + +# bad +class Foo; end +# EOF + +# bad +class Foo; end # EOF + +# good +class Foo; end + +# EOF +---- + +==== EnforcedStyle: final_newline (default) + +[source,ruby] +---- +# `final_newline` looks for one newline at the end of files. + +# bad +class Foo; end + +# EOF + +# bad +class Foo; end # EOF + +# good +class Foo; end +# EOF +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `final_newline` +| `final_newline`, `final_blank_line` +|=== + +=== References + +* https://rubystyle.guide#newline-eof + +== Layout/TrailingWhitespace + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.83 +|=== + +This cop looks for trailing whitespace in the source code. + +=== Examples + +[source,ruby] +---- +# The line in this example contains spaces after the 0. +# bad +x = 0 + +# The line in this example ends directly after the 0. +# good +x = 0 +---- + +==== AllowInHeredoc: false + +[source,ruby] +---- +# The line in this example contains spaces after the 0. +# bad +code = <<~RUBY + x = 0 +RUBY +---- + +==== AllowInHeredoc: true (default) + +[source,ruby] +---- +# The line in this example contains spaces after the 0. +# good +code = <<~RUBY + x = 0 +RUBY +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowInHeredoc +| `true` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#no-trailing-whitespace diff --git a/docs/modules/ROOT/pages/cops_lint.adoc b/docs/modules/ROOT/pages/cops_lint.adoc new file mode 100644 index 000000000000..2d32308518d3 --- /dev/null +++ b/docs/modules/ROOT/pages/cops_lint.adoc @@ -0,0 +1,5000 @@ += Lint + +== Lint/AmbiguousBlockAssociation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.48 +| - +|=== + +This cop checks for ambiguous block association with method +when param passed without parentheses. + +=== Examples + +[source,ruby] +---- +# bad +some_method a { |val| puts val } +---- + +[source,ruby] +---- +# good +# With parentheses, there's no ambiguity. +some_method(a { |val| puts val }) +# or (different meaning) +some_method(a) { |val| puts val } + +# good +# Operator methods require no disambiguation +foo == bar { |b| b.baz } + +# good +# Lambda arguments require no disambiguation +foo = ->(bar) { bar.baz } +---- + +=== References + +* https://rubystyle.guide#syntax + +== Lint/AmbiguousOperator + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.17 +| 0.83 +|=== + +This cop checks for ambiguous operators in the first argument of a +method invocation without parentheses. + +=== Examples + +[source,ruby] +---- +# bad + +# The `*` is interpreted as a splat operator but it could possibly be +# a `*` method invocation (i.e. `do_something.*(some_array)`). +do_something *some_array +---- + +[source,ruby] +---- +# good + +# With parentheses, there's no ambiguity. +do_something(*some_array) +---- + +=== References + +* https://rubystyle.guide#method-invocation-parens + +== Lint/AmbiguousRegexpLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.17 +| 0.83 +|=== + +This cop checks for ambiguous regexp literals in the first argument of +a method invocation without parentheses. + +=== Examples + +[source,ruby] +---- +# bad + +# This is interpreted as a method invocation with a regexp literal, +# but it could possibly be `/` method invocations. +# (i.e. `do_something./(pattern)./(i)`) +do_something /pattern/i +---- + +[source,ruby] +---- +# good + +# With parentheses, there's no ambiguity. +do_something(/pattern/i) +---- + +== Lint/AssignmentInCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| - +|=== + +This cop checks for assignments in the conditions of +if/while/until. + +`AllowSafeAssignment` option for safe assignment. +By safe assignment we mean putting parentheses around +an assignment to indicate "I know I'm using an assignment +as a condition. It's not a mistake." + +=== Examples + +[source,ruby] +---- +# bad +if some_var = true + do_something +end + +# good +if some_var == true + do_something +end +---- + +==== AllowSafeAssignment: true (default) + +[source,ruby] +---- +# good +if (some_var = true) + do_something +end +---- + +==== AllowSafeAssignment: false + +[source,ruby] +---- +# bad +if (some_var = true) + do_something +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowSafeAssignment +| `true` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#safe-assignment-in-condition + +== Lint/BigDecimalNew + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +`BigDecimal.new()` is deprecated since BigDecimal 1.3.3. +This cop identifies places where `BigDecimal.new()` +can be replaced by `BigDecimal()`. + +=== Examples + +[source,ruby] +---- +# bad +BigDecimal.new(123.456, 3) + +# good +BigDecimal(123.456, 3) +---- + +== Lint/BinaryOperatorWithIdenticalOperands + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| No +| 0.89 +| - +|=== + +This cop checks for places where binary operator has identical operands. + +It covers arithmetic operators: `+`, `-`, `*`, `/`, `%`, `**`; +comparison operators: `==`, `===`, `=~`, `>`, `>=`, `<`, `<=`; +bitwise operators: `|`, `^`, `&`, `<<`, `>>`; +boolean operators: `&&`, `||` +and "spaceship" operator - `<=>`. + +This cop is marked as unsafe as it does not consider side effects when calling methods +and thus can generate false positives: + if wr.take_char == '\0' && wr.take_char == '\0' + +=== Examples + +[source,ruby] +---- +# bad +x.top >= x.top + +if a.x != 0 && a.x != 0 + do_something +end + +def childs? + left_child || left_child +end +---- + +== Lint/BooleanSymbol + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.50 +| 0.83 +|=== + +This cop checks for `:true` and `:false` symbols. +In most cases it would be a typo. + +=== Examples + +[source,ruby] +---- +# bad +:true + +# good +true +---- + +[source,ruby] +---- +# bad +:false + +# good +false +---- + +== Lint/CircularArgumentReference + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.33 +| - +|=== + +This cop checks for circular argument references in optional keyword +arguments and optional ordinal arguments. + +This cop mirrors a warning produced by MRI since 2.2. + +=== Examples + +[source,ruby] +---- +# bad + +def bake(pie: pie) + pie.heat_up +end +---- + +[source,ruby] +---- +# good + +def bake(pie:) + pie.refrigerate +end +---- + +[source,ruby] +---- +# good + +def bake(pie: self.pie) + pie.feed_to(user) +end +---- + +[source,ruby] +---- +# bad + +def cook(dry_ingredients = dry_ingredients) + dry_ingredients.reduce(&:+) +end +---- + +[source,ruby] +---- +# good + +def cook(dry_ingredients = self.dry_ingredients) + dry_ingredients.combine +end +---- + +== Lint/ConstantDefinitionInBlock + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.91 +| - +|=== + +Do not define constants within a block, since the block's scope does not +isolate or namespace the constant in any way. + +If you are trying to define that constant once, define it outside of +the block instead, or use a variable or method if defining the constant +in the outer scope would be problematic. + +For meta-programming, use `const_set`. + +=== Examples + +[source,ruby] +---- +# bad +task :lint do + FILES_TO_LINT = Dir['lib/*.rb'] +end + +# bad +describe 'making a request' do + class TestRequest; end +end + +# bad +module M + extend ActiveSupport::Concern + included do + LIST = [] + end +end + +# good +task :lint do + files_to_lint = Dir['lib/*.rb'] +end + +# good +describe 'making a request' do + let(:test_request) { Class.new } + # see also `stub_const` for RSpec +end + +# good +module M + extend ActiveSupport::Concern + included do + const_set(:LIST, []) + end +end +---- + +=== References + +* https://rubystyle.guide#no-constant-definition-in-block + +== Lint/ConstantResolution + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.86 +| - +|=== + +Check that certain constants are fully qualified. + +This is not enabled by default because it would mark a lot of offenses +unnecessarily. + +Generally, gems should fully qualify all constants to avoid conflicts with +the code that uses the gem. Enable this cop without using `Only`/`Ignore` + +Large projects will over time end up with one or two constant names that +are problematic because of a conflict with a library or just internally +using the same name a namespace and a class. To avoid too many unnecessary +offenses, Enable this cop with `Only: [The, Constant, Names, Causing, Issues]` + +=== Examples + +[source,ruby] +---- +# By default checks every constant + +# bad +User + +# bad +User::Login + +# good +::User + +# good +::User::Login +---- + +==== Only: ['Login'] + +[source,ruby] +---- +# Restrict this cop to only being concerned about certain constants + +# bad +Login + +# good +::Login + +# good +User::Login +---- + +==== Ignore: ['Login'] + +[source,ruby] +---- +# Restrict this cop not being concerned about certain constants + +# bad +User + +# good +::User::Login + +# good +Login +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Only +| `[]` +| Array + +| Ignore +| `[]` +| Array +|=== + +== Lint/Debugger + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.14 +| 0.49 +|=== + +This cop checks for calls to debugger or pry. + +=== Examples + +[source,ruby] +---- +# bad (ok during development) + +# using pry +def some_method + binding.pry + do_something +end +---- + +[source,ruby] +---- +# bad (ok during development) + +# using byebug +def some_method + byebug + do_something +end +---- + +[source,ruby] +---- +# good + +def some_method + do_something +end +---- + +== Lint/DeprecatedClassMethods + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.19 +| - +|=== + +This cop checks for uses of the deprecated class method usages. + +=== Examples + +[source,ruby] +---- +# bad + +File.exists?(some_path) +Dir.exists?(some_path) +iterator? +---- + +[source,ruby] +---- +# good + +File.exist?(some_path) +Dir.exist?(some_path) +block_given? +---- + +== Lint/DeprecatedOpenSSLConstant + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.84 +| - +|=== + +Algorithmic constants for `OpenSSL::Cipher` and `OpenSSL::Digest` +deprecated since OpenSSL version 2.2.0. Prefer passing a string +instead. + +=== Examples + +[source,ruby] +---- +# Example for OpenSSL::Cipher instantiation. + +# bad +OpenSSL::Cipher::AES.new(128, :GCM) + +# good +OpenSSL::Cipher.new('aes-128-gcm') +---- + +[source,ruby] +---- +# Example for OpenSSL::Digest instantiation. + +# bad +OpenSSL::Digest::SHA256.new + +# good +OpenSSL::Digest.new('SHA256') +---- + +[source,ruby] +---- +# Example for ::Digest inherited class methods. + +# bad +OpenSSL::Digest::SHA256.digest('foo') + +# good +OpenSSL::Digest.digest('SHA256', 'foo') +---- + +== Lint/DisjunctiveAssignmentInConstructor + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.62 +| 0.88 +|=== + +This cop checks constructors for disjunctive assignments that should +be plain assignments. + +So far, this cop is only concerned with disjunctive assignment of +instance variables. + +In ruby, an instance variable is nil until a value is assigned, so the +disjunction is unnecessary. A plain assignment has the same effect. + +=== Examples + +[source,ruby] +---- +# bad +def initialize + @x ||= 1 +end + +# good +def initialize + @x = 1 +end +---- + +== Lint/DuplicateCaseCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.45 +| - +|=== + +This cop checks that there are no repeated conditions +used in case 'when' expressions. + +=== Examples + +[source,ruby] +---- +# bad + +case x +when 'first' + do_something +when 'first' + do_something_else +end +---- + +[source,ruby] +---- +# good + +case x +when 'first' + do_something +when 'second' + do_something_else +end +---- + +== Lint/DuplicateElsifCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.88 +| - +|=== + +This cop checks that there are no repeated conditions used in if 'elsif'. + +=== Examples + +[source,ruby] +---- +# bad +if x == 1 + do_something +elsif x == 1 + do_something_else +end + +# good +if x == 1 + do_something +elsif x == 2 + do_something_else +end +---- + +== Lint/DuplicateHashKey + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.34 +| 0.77 +|=== + +This cop checks for duplicated keys in hash literals. + +This cop mirrors a warning in Ruby 2.2. + +=== Examples + +[source,ruby] +---- +# bad + +hash = { food: 'apple', food: 'orange' } +---- + +[source,ruby] +---- +# good + +hash = { food: 'apple', other_food: 'orange' } +---- + +== Lint/DuplicateMethods + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.29 +| - +|=== + +This cop checks for duplicated instance (or singleton) method +definitions. + +=== Examples + +[source,ruby] +---- +# bad + +def foo + 1 +end + +def foo + 2 +end +---- + +[source,ruby] +---- +# bad + +def foo + 1 +end + +alias foo bar +---- + +[source,ruby] +---- +# good + +def foo + 1 +end + +def bar + 2 +end +---- + +[source,ruby] +---- +# good + +def foo + 1 +end + +alias bar foo +---- + +== Lint/DuplicateRequire + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.90 +| - +|=== + +This cop checks for duplicate `require`s and `require_relative`s. + +=== Examples + +[source,ruby] +---- +# bad +require 'foo' +require 'bar' +require 'foo' + +# good +require 'foo' +require 'bar' + +# good +require 'foo' +require_relative 'foo' +---- + +== Lint/DuplicateRescueException + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.89 +| - +|=== + +This cop checks that there are no repeated exceptions +used in 'rescue' expressions. + +=== Examples + +[source,ruby] +---- +# bad +begin + something +rescue FirstException + handle_exception +rescue FirstException + handle_other_exception +end + +# good +begin + something +rescue FirstException + handle_exception +rescue SecondException + handle_other_exception +end +---- + +== Lint/EachWithObjectArgument + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.31 +| - +|=== + +This cop checks if each_with_object is called with an immutable +argument. Since the argument is the object that the given block shall +make calls on to build something based on the enumerable that +each_with_object iterates over, an immutable argument makes no sense. +It's definitely a bug. + +=== Examples + +[source,ruby] +---- +# bad + +sum = numbers.each_with_object(0) { |e, a| a += e } +---- + +[source,ruby] +---- +# good + +num = 0 +sum = numbers.each_with_object(num) { |e, a| a += e } +---- + +== Lint/ElseLayout + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.17 +| - +|=== + +This cop checks for odd else block layout - like +having an expression on the same line as the else keyword, +which is usually a mistake. + +=== Examples + +[source,ruby] +---- +# bad + +if something + # ... +else do_this + do_that +end +---- + +[source,ruby] +---- +# good + +if something + # ... +else + do_this + do_that +end +---- + +== Lint/EmptyConditionalBody + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.89 +| - +|=== + +This cop checks for the presence of `if`, `elsif` and `unless` branches without a body. + +=== Examples + +[source,ruby] +---- +# bad +if condition +end + +# bad +unless condition +end + +# bad +if condition + do_something +elsif other_condition +end + +# good +if condition + do_something +end + +# good +unless condition + do_something +end + +# good +if condition + do_something +elsif other_condition + do_something_else +end +---- + +==== AllowComments: true (default) + +[source,ruby] +---- +# good +if condition + do_something +elsif other_condition + # noop +end +---- + +==== AllowComments: false + +[source,ruby] +---- +# bad +if condition + do_something +elsif other_condition + # noop +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowComments +| `true` +| Boolean +|=== + +== Lint/EmptyEnsure + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.10 +| 0.48 +|=== + +This cop checks for empty `ensure` blocks + +=== Examples + +[source,ruby] +---- +# bad + +def some_method + do_something +ensure +end +---- + +[source,ruby] +---- +# bad + +begin + do_something +ensure +end +---- + +[source,ruby] +---- +# good + +def some_method + do_something +ensure + do_something_else +end +---- + +[source,ruby] +---- +# good + +begin + do_something +ensure + do_something_else +end +---- + +== Lint/EmptyExpression + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.45 +| - +|=== + +This cop checks for the presence of empty expressions. + +=== Examples + +[source,ruby] +---- +# bad + +foo = () +if () + bar +end +---- + +[source,ruby] +---- +# good + +foo = (some_expression) +if (some_expression) + bar +end +---- + +== Lint/EmptyFile + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.90 +| - +|=== + +This cop enforces that Ruby source files are not empty. + +=== Examples + +[source,ruby] +---- +# bad +# Empty file + +# good +# File containing non commented source lines +---- + +==== AllowComments: true (default) + +[source,ruby] +---- +# good +# File consisting only of comments +---- + +==== AllowComments: false + +[source,ruby] +---- +# bad +# File consisting only of comments +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowComments +| `true` +| Boolean +|=== + +== Lint/EmptyInterpolation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.20 +| 0.45 +|=== + +This cop checks for empty interpolation. + +=== Examples + +[source,ruby] +---- +# bad + +"result is #{}" +---- + +[source,ruby] +---- +# good + +"result is #{some_result}" +---- + +== Lint/EmptyWhen + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.45 +| 0.83 +|=== + +This cop checks for the presence of `when` branches without a body. + +=== Examples + +[source,ruby] +---- +# bad +case foo +when bar + do_something +when baz +end +---- + +[source,ruby] +---- +# good +case condition +when foo + do_something +when bar + nil +end +---- + +==== AllowComments: true (default) + +[source,ruby] +---- +# good +case condition +when foo + do_something +when bar + # noop +end +---- + +==== AllowComments: false + +[source,ruby] +---- +# bad +case condition +when foo + do_something +when bar + # do nothing +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowComments +| `true` +| Boolean +|=== + +== Lint/EnsureReturn + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.83 +|=== + +This cop checks for `return` from an `ensure` block. +`return` from an ensure block is a dangerous code smell as it +will take precedence over any exception being raised, +and the exception will be silently thrown away as if it were rescued. + +If you want to rescue some (or all) exceptions, best to do it explicitly + +=== Examples + +[source,ruby] +---- +# bad + +def foo + do_something +ensure + cleanup + return self +end +---- + +[source,ruby] +---- +# good + +def foo + do_something + self +ensure + cleanup +end + +# also good + +def foo + begin + do_something + rescue SomeException + # Let's ignore this exception + end + self +ensure + cleanup +end +---- + +=== References + +* https://rubystyle.guide#no-return-ensure + +== Lint/ErbNewArguments + +NOTE: Required Ruby version: 2.6 + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.56 +| - +|=== + +This cop emulates the following Ruby warnings in Ruby 2.6. + +% cat example.rb +ERB.new('hi', nil, '-', '@output_buffer') +% ruby -rerb example.rb +example.rb:1: warning: Passing safe_level with the 2nd argument of +ERB.new is deprecated. Do not use it, and specify other arguments as +keyword arguments. +example.rb:1: warning: Passing trim_mode with the 3rd argument of +ERB.new is deprecated. Use keyword argument like +ERB.new(str, trim_mode:...) instead. +example.rb:1: warning: Passing eoutvar with the 4th argument of ERB.new +is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) +instead. + +Now non-keyword arguments other than first one are softly deprecated +and will be removed when Ruby 2.5 becomes EOL. +`ERB.new` with non-keyword arguments is deprecated since ERB 2.2.0. +Use `:trim_mode` and `:eoutvar` keyword arguments to `ERB.new`. +This cop identifies places where `ERB.new(str, trim_mode, eoutvar)` can +be replaced by `ERB.new(str, :trim_mode: trim_mode, eoutvar: eoutvar)`. + +=== Examples + +[source,ruby] +---- +# Target codes supports Ruby 2.6 and higher only +# bad +ERB.new(str, nil, '-', '@output_buffer') + +# good +ERB.new(str, trim_mode: '-', eoutvar: '@output_buffer') + +# Target codes supports Ruby 2.5 and lower only +# good +ERB.new(str, nil, '-', '@output_buffer') + +# Target codes supports Ruby 2.6, 2.5 and lower +# bad +ERB.new(str, nil, '-', '@output_buffer') + +# good +# Ruby standard library style +# https://github.com/ruby/ruby/commit/3406c5d +if ERB.instance_method(:initialize).parameters.assoc(:key) # Ruby 2.6+ + ERB.new(str, trim_mode: '-', eoutvar: '@output_buffer') +else + ERB.new(str, nil, '-', '@output_buffer') +end + +# good +# Use `RUBY_VERSION` style +if RUBY_VERSION >= '2.6' + ERB.new(str, trim_mode: '-', eoutvar: '@output_buffer') +else + ERB.new(str, nil, '-', '@output_buffer') +end +---- + +== Lint/FlipFlop + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.16 +| - +|=== + +This cop looks for uses of flip-flop operator. +flip-flop operator is deprecated since Ruby 2.6.0. + +=== Examples + +[source,ruby] +---- +# bad +(1..20).each do |x| + puts x if (x == 5) .. (x == 10) +end + +# good +(1..20).each do |x| + puts x if (x >= 5) && (x <= 10) +end +---- + +=== References + +* https://rubystyle.guide#no-flip-flops + +== Lint/FloatComparison + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.89 +| - +|=== + +This cop checks for the presence of precise comparison of floating point numbers. + +Floating point values are inherently inaccurate, and comparing them for exact equality +is almost never the desired semantics. Comparison via the `==/!=` operators checks +floating-point value representation to be exactly the same, which is very unlikely +if you perform any arithmetic operations involving precision loss. + +=== Examples + +[source,ruby] +---- +# bad +x == 0.1 +x != 0.1 + +# good - using BigDecimal +x.to_d == 0.1.to_d + +# good +(x - 0.1).abs < Float::EPSILON + +# good +tolerance = 0.0001 +(x - 0.1).abs < tolerance + +# Or some other epsilon based type of comparison: +# https://www.embeddeduse.com/2019/08/26/qt-compare-two-floats/ +---- + +=== References + +* https://rubystyle.guide#float-comparison + +== Lint/FloatOutOfRange + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.36 +| - +|=== + +This cop identifies Float literals which are, like, really really really +really really really really really big. Too big. No-one needs Floats +that big. If you need a float that big, something is wrong with you. + +=== Examples + +[source,ruby] +---- +# bad + +float = 3.0e400 +---- + +[source,ruby] +---- +# good + +float = 42.9 +---- + +== Lint/FormatParameterMismatch + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.33 +| - +|=== + +This lint sees if there is a mismatch between the number of +expected fields for format/sprintf/#% and what is actually +passed as arguments. + +In addition it checks whether different formats are used in the same +format string. Do not mix numbered, unnumbered, and named formats in +the same format string. + +=== Examples + +[source,ruby] +---- +# bad + +format('A value: %s and another: %i', a_value) +---- + +[source,ruby] +---- +# good + +format('A value: %s and another: %i', a_value, another) +---- + +[source,ruby] +---- +# bad + +format('Unnumbered format: %s and numbered: %2$s', a_value, another) +---- + +[source,ruby] +---- +# good + +format('Numbered format: %1$s and numbered %2$s', a_value, another) +---- + +== Lint/HashCompareByIdentity + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| No +| 0.93 +| - +|=== + +Prefer using `Hash#compare_by_identity` than using `object_id` for hash keys. + +This cop is marked as unsafe as a hash possibly can contain other keys +besides `object_id`s. + +=== Examples + +[source,ruby] +---- +# bad +hash = {} +hash[foo.object_id] = :bar +hash.key?(baz.object_id) + +# good +hash = {}.compare_by_identity +hash[foo] = :bar +hash.key?(baz) +---- + +=== References + +* https://rubystyle.guide#identity-comparison + +== Lint/HeredocMethodCallPosition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.68 +| - +|=== + +This cop checks for the ordering of a method call where +the receiver of the call is a HEREDOC. + +=== Examples + +[source,ruby] +---- +# bad + + <<-SQL + bar + SQL + .strip_indent + + <<-SQL + bar + SQL + .strip_indent + .trim + +# good + + <<~SQL + bar + SQL + + <<~SQL.trim + bar + SQL +---- + +=== References + +* https://rubystyle.guide#heredoc-method-calls + +== Lint/IdentityComparison + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.91 +| - +|=== + +Prefer `equal?` over `==` when comparing `object_id`. + +`Object#equal?` is provided to compare objects for identity, and in contrast +`Object#==` is provided for the purpose of doing value comparison. + +=== Examples + +[source,ruby] +---- +# bad +foo.object_id == bar.object_id + +# good +foo.equal?(bar) +---- + +=== References + +* https://rubystyle.guide#identity-comparison + +== Lint/ImplicitStringConcatenation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.36 +| - +|=== + +This cop checks for implicit string concatenation of string literals +which are on the same line. + +=== Examples + +[source,ruby] +---- +# bad + +array = ['Item 1' 'Item 2'] +---- + +[source,ruby] +---- +# good + +array = ['Item 1Item 2'] +array = ['Item 1' + 'Item 2'] +array = [ + 'Item 1' \ + 'Item 2' +] +---- + +== Lint/IneffectiveAccessModifier + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.36 +| - +|=== + +This cop checks for `private` or `protected` access modifiers which are +applied to a singleton method. These access modifiers do not make +singleton methods private/protected. `private_class_method` can be +used for that. + +=== Examples + +[source,ruby] +---- +# bad + +class C + private + + def self.method + puts 'hi' + end +end +---- + +[source,ruby] +---- +# good + +class C + def self.method + puts 'hi' + end + + private_class_method :method +end +---- + +[source,ruby] +---- +# good + +class C + class << self + private + + def method + puts 'hi' + end + end +end +---- + +== Lint/InheritException + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.41 +| - +|=== + +This cop looks for error classes inheriting from `Exception` +and its standard library subclasses, excluding subclasses of +`StandardError`. It is configurable to suggest using either +`RuntimeError` (default) or `StandardError` instead. + +=== Examples + +==== EnforcedStyle: runtime_error (default) + +[source,ruby] +---- +# bad + +class C < Exception; end + +C = Class.new(Exception) + +# good + +class C < RuntimeError; end + +C = Class.new(RuntimeError) +---- + +==== EnforcedStyle: standard_error + +[source,ruby] +---- +# bad + +class C < Exception; end + +C = Class.new(Exception) + +# good + +class C < StandardError; end + +C = Class.new(StandardError) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `runtime_error` +| `runtime_error`, `standard_error` +|=== + +== Lint/InterpolationCheck + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.50 +| 0.87 +|=== + +This cop checks for interpolation in a single quoted string. + +=== Examples + +[source,ruby] +---- +# bad + +foo = 'something with #{interpolation} inside' +---- + +[source,ruby] +---- +# good + +foo = "something with #{interpolation} inside" +---- + +== Lint/LiteralAsCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.51 +| - +|=== + +This cop checks for literals used as the conditions or as +operands in and/or expressions serving as the conditions of +if/while/until. + +=== Examples + +[source,ruby] +---- +# bad +if 20 + do_something +end + +# bad +if some_var && true + do_something +end + +# good +if some_var && some_condition + do_something +end + +# good +# When using a boolean value for an infinite loop. +while true + break if condition +end +---- + +== Lint/LiteralInInterpolation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.19 +| 0.32 +|=== + +This cop checks for interpolated literals. + +=== Examples + +[source,ruby] +---- +# bad + +"result is #{10}" +---- + +[source,ruby] +---- +# good + +"result is 10" +---- + +== Lint/Loop + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.89 +|=== + +This cop checks for uses of `begin...end while/until something`. + +=== Examples + +[source,ruby] +---- +# bad + +# using while +begin + do_something +end while some_condition +---- + +[source,ruby] +---- +# bad + +# using until +begin + do_something +end until some_condition +---- + +[source,ruby] +---- +# good + +# while replacement +loop do + do_something + break unless some_condition +end +---- + +[source,ruby] +---- +# good + +# until replacement +loop do + do_something + break if some_condition +end +---- + +=== References + +* https://rubystyle.guide#loop-with-break + +== Lint/MissingCopEnableDirective + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.52 +| - +|=== + +This cop checks that there is an `# rubocop:enable ...` statement +after a `# rubocop:disable ...` statement. This will prevent leaving +cop disables on wide ranges of code, that latter contributors to +a file wouldn't be aware of. + +=== Examples + +[source,ruby] +---- +# Lint/MissingCopEnableDirective: +# MaximumRangeSize: .inf + +# good +# rubocop:disable Layout/SpaceAroundOperators +x= 0 +# rubocop:enable Layout/SpaceAroundOperators +# y = 1 +# EOF + +# bad +# rubocop:disable Layout/SpaceAroundOperators +x= 0 +# EOF +---- + +[source,ruby] +---- +# Lint/MissingCopEnableDirective: +# MaximumRangeSize: 2 + +# good +# rubocop:disable Layout/SpaceAroundOperators +x= 0 +# With the previous, there are 2 lines on which cop is disabled. +# rubocop:enable Layout/SpaceAroundOperators + +# bad +# rubocop:disable Layout/SpaceAroundOperators +x= 0 +x += 1 +# Including this, that's 3 lines on which the cop is disabled. +# rubocop:enable Layout/SpaceAroundOperators +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| MaximumRangeSize +| `Infinity` +| Float +|=== + +== Lint/MissingSuper + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.89 +| - +|=== + +This cop checks for the presence of constructors and lifecycle callbacks +without calls to `super`. + +=== Examples + +[source,ruby] +---- +# bad +class Employee < Person + def initialize(name, salary) + @salary = salary + end +end + +# good +class Employee < Person + def initialize(name, salary) + super(name) + @salary = salary + end +end + +# bad +class Parent + def self.inherited(base) + do_something + end +end + +# good +class Parent + def self.inherited(base) + super + do_something + end +end +---- + +== Lint/MixedRegexpCaptureTypes + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.85 +| - +|=== + +Do not mix named captures and numbered captures in a Regexp literal +because numbered capture is ignored if they're mixed. +Replace numbered captures with non-capturing groupings or +named captures. + + # bad + /(?FOO)(BAR)/ + + # good + /(?FOO)(?BAR)/ + + # good + /(?FOO)(?:BAR)/ + + # good + /(FOO)(BAR)/ + +== Lint/MultipleComparison + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.47 +| 0.77 +|=== + +In math and Python, we can use `x < y < z` style comparison to compare +multiple value. However, we can't use the comparison in Ruby. However, +the comparison is not syntax error. This cop checks the bad usage of +comparison operators. + +=== Examples + +[source,ruby] +---- +# bad + +x < y < z +10 <= x <= 20 +---- + +[source,ruby] +---- +# good + +x < y && y < z +10 <= x && x <= 20 +---- + +== Lint/NestedMethodDefinition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.32 +| - +|=== + +This cop checks for nested method definitions. + +=== Examples + +[source,ruby] +---- +# bad + +# `bar` definition actually produces methods in the same scope +# as the outer `foo` method. Furthermore, the `bar` method +# will be redefined every time `foo` is invoked. +def foo + def bar + end +end +---- + +[source,ruby] +---- +# good + +def foo + bar = -> { puts 'hello' } + bar.call +end +---- + +[source,ruby] +---- +# good + +def foo + self.class.class_eval do + def bar + end + end +end + +def foo + self.class.module_exec do + def bar + end + end +end +---- + +[source,ruby] +---- +# good + +def foo + class << self + def bar + end + end +end +---- + +=== References + +* https://rubystyle.guide#no-nested-methods + +== Lint/NestedPercentLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.52 +| - +|=== + +This cop checks for nested percent literals. + +=== Examples + +[source,ruby] +---- +# bad + +# The percent literal for nested_attributes is parsed as four tokens, +# yielding the array [:name, :content, :"%i[incorrectly", :"nested]"]. +attributes = { + valid_attributes: %i[name content], + nested_attributes: %i[name content %i[incorrectly nested]] +} +---- + +== Lint/NextWithoutAccumulator + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.36 +| - +|=== + +Don't omit the accumulator when calling `next` in a `reduce` block. + +=== Examples + +[source,ruby] +---- +# bad + +result = (1..4).reduce(0) do |acc, i| + next if i.odd? + acc + i +end +---- + +[source,ruby] +---- +# good + +result = (1..4).reduce(0) do |acc, i| + next acc if i.odd? + acc + i +end +---- + +== Lint/NonDeterministicRequireOrder + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.78 +| - +|=== + +`Dir[...]` and `Dir.glob(...)` do not make any guarantees about +the order in which files are returned. The final order is +determined by the operating system and file system. +This means that using them in cases where the order matters, +such as requiring files, can lead to intermittent failures +that are hard to debug. To ensure this doesn't happen, +always sort the list. + +=== Examples + +[source,ruby] +---- +# bad +Dir["./lib/**/*.rb"].each do |file| + require file +end + +# good +Dir["./lib/**/*.rb"].sort.each do |file| + require file +end +---- + +[source,ruby] +---- +# bad +Dir.glob(Rails.root.join(__dir__, 'test', '*.rb')) do |file| + require file +end + +# good +Dir.glob(Rails.root.join(__dir__, 'test', '*.rb')).sort.each do |file| + require file +end +---- + +[source,ruby] +---- +# bad +Dir['./lib/**/*.rb'].each(&method(:require)) + +# good +Dir['./lib/**/*.rb'].sort.each(&method(:require)) +---- + +[source,ruby] +---- +# bad +Dir.glob(Rails.root.join('test', '*.rb'), &method(:require)) + +# good +Dir.glob(Rails.root.join('test', '*.rb')).sort.each(&method(:require)) +---- + +== Lint/NonLocalExitFromIterator + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.30 +| - +|=== + +This cop checks for non-local exits from iterators without a return +value. It registers an offense under these conditions: + +* No value is returned, +* the block is preceded by a method chain, +* the block has arguments, +* the method which receives the block is not `define_method` +or `define_singleton_method`, +* the return is not contained in an inner scope, e.g. a lambda or a +method definition. + +=== Examples + +[source,ruby] +---- +class ItemApi + rescue_from ValidationError do |e| # non-iteration block with arg + return { message: 'validation error' } unless e.errors # allowed + error_array = e.errors.map do |error| # block with method chain + return if error.suppress? # warned + return "#{error.param}: invalid" unless error.message # allowed + "#{error.param}: #{error.message}" + end + { message: 'validation error', errors: error_array } + end + + def update_items + transaction do # block without arguments + return unless update_necessary? # allowed + find_each do |item| # block without method chain + return if item.stock == 0 # false-negative... + item.update!(foobar: true) + end + end + end +end +---- + +== Lint/NumberConversion + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes (Unsafe) +| 0.53 +| 0.70 +|=== + +This cop warns the usage of unsafe number conversions. Unsafe +number conversion can cause unexpected error if auto type conversion +fails. Cop prefer parsing with number class instead. + +=== Examples + +[source,ruby] +---- +# bad + +'10'.to_i +'10.2'.to_f +'10'.to_c + +# good + +Integer('10', 10) +Float('10.2') +Complex('10') +---- + +== Lint/OrderedMagicComments + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +Checks the proper ordering of magic comments and whether +a magic comment is not placed before a shebang. + +=== Examples + +[source,ruby] +---- +# bad + +# frozen_string_literal: true +# encoding: ascii +p [''.frozen?, ''.encoding] #=> [true, #] + +# good + +# encoding: ascii +# frozen_string_literal: true +p [''.frozen?, ''.encoding] #=> [true, #] + +# good + +#!/usr/bin/env ruby +# encoding: ascii +# frozen_string_literal: true +p [''.frozen?, ''.encoding] #=> [true, #] +---- + +== Lint/OutOfRangeRegexpRef + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| No +| 0.89 +| - +|=== + +This cops looks for references of Regexp captures that are out of range +and thus always returns nil. + +=== Examples + +[source,ruby] +---- +/(foo)bar/ =~ 'foobar' + +# bad - always returns nil + +puts $2 # => nil + +# good + +puts $1 # => foo +---- + +== Lint/ParenthesesAsGroupedExpression + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.12 +| 0.83 +|=== + +Checks for space between the name of a called method and a left +parenthesis. + +=== Examples + +[source,ruby] +---- +# bad +do_something (foo) + +# good +do_something(foo) +do_something (2 + 3) * 4 +do_something (foo * bar).baz +---- + +=== References + +* https://rubystyle.guide#parens-no-spaces + +== Lint/PercentStringArray + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.41 +| - +|=== + +This cop checks for quotes and commas in %w, e.g. `%w('foo', "bar")` + +It is more likely that the additional characters are unintended (for +example, mistranslating an array of literals to percent string notation) +rather than meant to be part of the resulting strings. + +=== Examples + +[source,ruby] +---- +# bad + +%w('foo', "bar") +---- + +[source,ruby] +---- +# good + +%w(foo bar) +---- + +== Lint/PercentSymbolArray + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.41 +| - +|=== + +This cop checks for colons and commas in %i, e.g. `%i(:foo, :bar)` + +It is more likely that the additional characters are unintended (for +example, mistranslating an array of literals to percent string notation) +rather than meant to be part of the resulting symbols. + +=== Examples + +[source,ruby] +---- +# bad + +%i(:foo, :bar) +---- + +[source,ruby] +---- +# good + +%i(foo bar) +---- + +== Lint/RaiseException + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.81 +| 0.86 +|=== + +This cop checks for `raise` or `fail` statements which are +raising `Exception` class. + +You can specify a module name that will be an implicit namespace +using `AllowedImplicitNamespaces` option. The cop cause a false positive +for namespaced `Exception` when a namespace is omitted. This option can +prevent the false positive by specifying a namespace to be omitted for +`Exception`. Alternatively, make `Exception` a fully qualified class +name with an explicit namespace. + +=== Examples + +[source,ruby] +---- +# bad +raise Exception, 'Error message here' + +# good +raise StandardError, 'Error message here' +---- + +==== AllowedImplicitNamespaces: ['Gem'] + +[source,ruby] +---- +# good +module Gem + def self.foo + raise Exception # This exception means `Gem::Exception`. + end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedImplicitNamespaces +| `Gem` +| Array +|=== + +=== References + +* https://rubystyle.guide#raise-exception + +== Lint/RandOne + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.36 +| - +|=== + +This cop checks for `rand(1)` calls. +Such calls always return `0`. + +=== Examples + +[source,ruby] +---- +# bad + +rand 1 +Kernel.rand(-1) +rand 1.0 +rand(-1.0) +---- + +[source,ruby] +---- +# good + +0 # just use 0 instead +---- + +== Lint/RedundantCopDisableDirective + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.76 +| - +|=== + +This cop detects instances of rubocop:disable comments that can be +removed without causing any offenses to be reported. It's implemented +as a cop in that it inherits from the Cop base class and calls +add_offense. The unusual part of its implementation is that it doesn't +have any on_* methods or an investigate method. This means that it +doesn't take part in the investigation phase when the other cops do +their work. Instead, it waits until it's called in a later stage of the +execution. The reason it can't be implemented as a normal cop is that +it depends on the results of all other cops to do its work. + +=== Examples + +[source,ruby] +---- +# bad +# rubocop:disable Layout/LineLength +x += 1 +# rubocop:enable Layout/LineLength + +# good +x += 1 +---- + +== Lint/RedundantCopEnableDirective + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.76 +| - +|=== + +This cop detects instances of rubocop:enable comments that can be +removed. + +When comment enables all cops at once `rubocop:enable all` +that cop checks whether any cop was actually enabled. + +=== Examples + +[source,ruby] +---- +# bad +foo = 1 +# rubocop:enable Layout/LineLength + +# good +foo = 1 +---- + +[source,ruby] +---- +# bad +# rubocop:disable Style/StringLiterals +foo = "1" +# rubocop:enable Style/StringLiterals +baz +# rubocop:enable all + +# good +# rubocop:disable Style/StringLiterals +foo = "1" +# rubocop:enable all +baz +---- + +== Lint/RedundantRequireStatement + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.76 +| - +|=== + +Checks for unnecessary `require` statement. + +The following features are unnecessary `require` statement because +they are already loaded. + + ruby -ve 'p $LOADED_FEATURES.reject { |feature| %r|/| =~ feature }' + ruby 2.2.8p477 (2017-09-14 revision 59906) [x86_64-darwin13] + ["enumerator.so", "rational.so", "complex.so", "thread.rb"] + +This cop targets Ruby 2.2 or higher containing these 4 features. + +=== Examples + +[source,ruby] +---- +# bad +require 'unloaded_feature' +require 'thread' + +# good +require 'unloaded_feature' +---- + +== Lint/RedundantSafeNavigation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.93 +| - +|=== + +This cop checks for redundant safe navigation calls. +`instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods +are checked by default. These are customizable with `AllowedMethods` option. + +This cop is marked as unsafe, because auto-correction can change the +return type of the expression. An offending expression that previously +could return `nil` will be auto-corrected to never return `nil`. + +In the example below, the safe navigation operator (`&.`) is unnecessary +because `NilClass` has methods like `respond_to?` and `is_a?`. + +=== Examples + +[source,ruby] +---- +# bad +do_something if attrs&.respond_to?(:[]) + +# good +do_something if attrs.respond_to?(:[]) + +# bad +while node&.is_a?(BeginNode) + node = node.parent +end + +# good +while node.is_a?(BeginNode) + node = node.parent +end + +# good - without `&.` this will always return `true` +foo&.respond_to?(:to_a) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedMethods +| `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, `equal?` +| Array +|=== + +== Lint/RedundantSplatExpansion + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.76 +| - +|=== + +This cop checks for unneeded usages of splat expansion + +=== Examples + +[source,ruby] +---- +# bad + +a = *[1, 2, 3] +a = *'a' +a = *1 + +begin + foo +rescue *[StandardError, ApplicationError] + bar +end + +case foo +when *[1, 2, 3] + bar +else + baz +end +---- + +[source,ruby] +---- +# good + +c = [1, 2, 3] +a = *c +a, b = *c +a, *b = *c +a = *1..10 +a = ['a'] + +begin + foo +rescue StandardError, ApplicationError + bar +end + +case foo +when 1, 2, 3 + bar +else + baz +end +---- + +== Lint/RedundantStringCoercion + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.19 +| 0.77 +|=== + +This cop checks for string conversion in string interpolation, +which is redundant. + +=== Examples + +[source,ruby] +---- +# bad + +"result is #{something.to_s}" +---- + +[source,ruby] +---- +# good + +"result is #{something}" +---- + +=== References + +* https://rubystyle.guide#no-to-s + +== Lint/RedundantWithIndex + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.50 +| - +|=== + +This cop checks for redundant `with_index`. + +=== Examples + +[source,ruby] +---- +# bad +ary.each_with_index do |v| + v +end + +# good +ary.each do |v| + v +end + +# bad +ary.each.with_index do |v| + v +end + +# good +ary.each do |v| + v +end +---- + +== Lint/RedundantWithObject + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.51 +| - +|=== + +This cop checks for redundant `with_object`. + +=== Examples + +[source,ruby] +---- +# bad +ary.each_with_object([]) do |v| + v +end + +# good +ary.each do |v| + v +end + +# bad +ary.each.with_object([]) do |v| + v +end + +# good +ary.each do |v| + v +end +---- + +== Lint/RegexpAsCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.51 +| 0.86 +|=== + +This cop checks for regexp literals used as `match-current-line`. +If a regexp literal is in condition, the regexp matches `$_` implicitly. + +=== Examples + +[source,ruby] +---- +# bad +if /foo/ + do_something +end + +# good +if /foo/ =~ $_ + do_something +end +---- + +== Lint/RequireParentheses + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.18 +| - +|=== + +This cop checks for expressions where there is a call to a predicate +method with at least one argument, where no parentheses are used around +the parameter list, and a boolean operator, && or ||, is used in the +last argument. + +The idea behind warning for these constructs is that the user might +be under the impression that the return value from the method call is +an operand of &&/||. + +=== Examples + +[source,ruby] +---- +# bad + +if day.is? :tuesday && month == :jan + # ... +end +---- + +[source,ruby] +---- +# good + +if day.is?(:tuesday) && month == :jan + # ... +end +---- + +== Lint/RescueException + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| 0.27.1 +|=== + +This cop checks for `rescue` blocks targeting the Exception class. + +=== Examples + +[source,ruby] +---- +# bad + +begin + do_something +rescue Exception + handle_exception +end +---- + +[source,ruby] +---- +# good + +begin + do_something +rescue ArgumentError + handle_exception +end +---- + +=== References + +* https://rubystyle.guide#no-blind-rescues + +== Lint/RescueType + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| - +|=== + +Check for arguments to `rescue` that will result in a `TypeError` +if an exception is raised. + +=== Examples + +[source,ruby] +---- +# bad +begin + bar +rescue nil + baz +end + +# bad +def foo + bar +rescue 1, 'a', "#{b}", 0.0, [], {} + baz +end + +# good +begin + bar +rescue + baz +end + +# good +def foo + bar +rescue NameError + baz +end +---- + +== Lint/ReturnInVoidContext + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop checks for the use of a return with a value in a context +where the value will be ignored. (initialize and setter methods) + +=== Examples + +[source,ruby] +---- +# bad +def initialize + foo + return :qux if bar? + baz +end + +def foo=(bar) + return 42 +end +---- + +[source,ruby] +---- +# good +def initialize + foo + return if bar? + baz +end + +def foo=(bar) + return +end +---- + +== Lint/SafeNavigationChain + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.47 +| 0.77 +|=== + +The safe navigation operator returns nil if the receiver is +nil. If you chain an ordinary method call after a safe +navigation operator, it raises NoMethodError. We should use a +safe navigation operator after a safe navigation operator. +This cop checks for the problem outlined above. + +=== Examples + +[source,ruby] +---- +# bad + +x&.foo.bar +x&.foo + bar +x&.foo[bar] +---- + +[source,ruby] +---- +# good + +x&.foo&.bar +x&.foo || bar +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedMethods +| `present?`, `blank?`, `presence`, `try`, `try!`, `in?` +| Array +|=== + +== Lint/SafeNavigationConsistency + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.55 +| 0.77 +|=== + +This cop check to make sure that if safe navigation is used for a method +call in an `&&` or `||` condition that safe navigation is used for all +method calls on that same object. + +=== Examples + +[source,ruby] +---- +# bad +foo&.bar && foo.baz + +# bad +foo.bar || foo&.baz + +# bad +foo&.bar && (foobar.baz || foo.baz) + +# good +foo.bar && foo.baz + +# good +foo&.bar || foo&.baz + +# good +foo&.bar && (foobar.baz || foo&.baz) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedMethods +| `present?`, `blank?`, `presence`, `try`, `try!` +| Array +|=== + +== Lint/SafeNavigationWithEmpty + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.62 +| 0.87 +|=== + +This cop checks to make sure safe navigation isn't used with `empty?` in +a conditional. + +While the safe navigation operator is generally a good idea, when +checking `foo&.empty?` in a conditional, `foo` being `nil` will actually +do the opposite of what the author intends. + +=== Examples + +[source,ruby] +---- +# bad +return if foo&.empty? +return unless foo&.empty? + +# good +return if foo && foo.empty? +return unless foo && foo.empty? +---- + +== Lint/ScriptPermission + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.49 +| 0.50 +|=== + +This cop checks if a file which has a shebang line as +its first line is granted execute permission. + +=== Examples + +[source,ruby] +---- +# bad + +# A file which has a shebang line as its first line is not +# granted execute permission. + +#!/usr/bin/env ruby +puts 'hello, world' + +# good + +# A file which has a shebang line as its first line is +# granted execute permission. + +#!/usr/bin/env ruby +puts 'hello, world' + +# good + +# A file which has not a shebang line as its first line is not +# granted execute permission. + +puts 'hello, world' +---- + +== Lint/SelfAssignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.89 +| - +|=== + +This cop checks for self-assignments. + +=== Examples + +[source,ruby] +---- +# bad +foo = foo +foo, bar = foo, bar +Foo = Foo + +# good +foo = bar +foo, bar = bar, foo +Foo = Bar +---- + +== Lint/SendWithMixinArgument + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.75 +| - +|=== + +This cop checks for `send`, `public_send`, and `__send__` methods +when using mix-in. + +`include` and `prepend` methods were private methods until Ruby 2.0, +they were mixed-in via `send` method. This cop uses Ruby 2.1 or +higher style that can be called by public methods. +And `extend` method that was originally a public method is also targeted +for style unification. + +=== Examples + +[source,ruby] +---- +# bad +Foo.send(:include, Bar) +Foo.send(:prepend, Bar) +Foo.send(:extend, Bar) + +# bad +Foo.public_send(:include, Bar) +Foo.public_send(:prepend, Bar) +Foo.public_send(:extend, Bar) + +# bad +Foo.__send__(:include, Bar) +Foo.__send__(:prepend, Bar) +Foo.__send__(:extend, Bar) + +# good +Foo.include Bar +Foo.prepend Bar +Foo.extend Bar +---- + +== Lint/ShadowedArgument + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.52 +| - +|=== + +This cop checks for shadowed arguments. + +This cop has `IgnoreImplicitReferences` configuration option. +It means argument shadowing is used in order to pass parameters +to zero arity `super` when `IgnoreImplicitReferences` is `true`. + +=== Examples + +[source,ruby] +---- +# bad +do_something do |foo| + foo = 42 + puts foo +end + +def do_something(foo) + foo = 42 + puts foo +end + +# good +do_something do |foo| + foo = foo + 42 + puts foo +end + +def do_something(foo) + foo = foo + 42 + puts foo +end + +def do_something(foo) + puts foo +end +---- + +==== IgnoreImplicitReferences: false (default) + +[source,ruby] +---- +# bad +def do_something(foo) + foo = 42 + super +end + +def do_something(foo) + foo = super + bar +end +---- + +==== IgnoreImplicitReferences: true + +[source,ruby] +---- +# good +def do_something(foo) + foo = 42 + super +end + +def do_something(foo) + foo = super + bar +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IgnoreImplicitReferences +| `false` +| Boolean +|=== + +== Lint/ShadowedException + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.41 +| - +|=== + +This cop checks for a rescued exception that get shadowed by a +less specific exception being rescued before a more specific +exception is rescued. + +=== Examples + +[source,ruby] +---- +# bad + +begin + something +rescue Exception + handle_exception +rescue StandardError + handle_standard_error +end + +# good + +begin + something +rescue StandardError + handle_standard_error +rescue Exception + handle_exception +end + +# good, however depending on runtime environment. +# +# This is a special case for system call errors. +# System dependent error code depends on runtime environment. +# For example, whether `Errno::EAGAIN` and `Errno::EWOULDBLOCK` are +# the same error code or different error code depends on environment. +# This good case is for `Errno::EAGAIN` and `Errno::EWOULDBLOCK` with +# the same error code. +begin + something +rescue Errno::EAGAIN, Errno::EWOULDBLOCK + handle_standard_error +end +---- + +== Lint/ShadowingOuterLocalVariable + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| - +|=== + +This cop checks for the use of local variable names from an outer scope +in block arguments or block-local variables. This mirrors the warning +given by `ruby -cw` prior to Ruby 2.6: +"shadowing outer local variable - foo". + +=== Examples + +[source,ruby] +---- +# bad + +def some_method + foo = 1 + + 2.times do |foo| # shadowing outer `foo` + do_something(foo) + end +end +---- + +[source,ruby] +---- +# good + +def some_method + foo = 1 + + 2.times do |bar| + do_something(bar) + end +end +---- + +== Lint/StructNewOverride + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.81 +| - +|=== + +This cop checks unexpected overrides of the `Struct` built-in methods +via `Struct.new`. + +=== Examples + +[source,ruby] +---- +# bad +Bad = Struct.new(:members, :clone, :count) +b = Bad.new([], true, 1) +b.members #=> [] (overriding `Struct#members`) +b.clone #=> true (overriding `Object#clone`) +b.count #=> 1 (overriding `Enumerable#count`) + +# good +Good = Struct.new(:id, :name) +g = Good.new(1, "foo") +g.members #=> [:id, :name] +g.clone #=> # +g.count #=> 2 +---- + +== Lint/SuppressedException + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| 0.81 +|=== + +This cop checks for `rescue` blocks with no body. + +=== Examples + +[source,ruby] +---- +# bad +def some_method + do_something +rescue +end + +# bad +begin + do_something +rescue +end + +# good +def some_method + do_something +rescue + handle_exception +end + +# good +begin + do_something +rescue + handle_exception +end +---- + +==== AllowComments: true (default) + +[source,ruby] +---- +# good +def some_method + do_something +rescue + # do nothing +end + +# good +begin + do_something +rescue + # do nothing +end +---- + +==== AllowComments: false + +[source,ruby] +---- +# bad +def some_method + do_something +rescue + # do nothing +end + +# bad +begin + do_something +rescue + # do nothing +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowComments +| `true` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#dont-hide-exceptions + +== Lint/Syntax + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| - +|=== + +This cop repacks Parser's diagnostics/errors +into RuboCop's offenses. + +== Lint/ToJSON + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.66 +| - +|=== + +This cop checks to make sure `#to_json` includes an optional argument. +When overriding `#to_json`, callers may invoke JSON +generation via `JSON.generate(your_obj)`. Since `JSON#generate` allows +for an optional argument, your method should too. + +=== Examples + +[source,ruby] +---- +class Point + attr_reader :x, :y + + # bad, incorrect arity + def to_json + JSON.generate([x, y]) + end + + # good, preserving args + def to_json(*args) + JSON.generate([x, y], *args) + end + + # good, discarding args + def to_json(*_args) + JSON.generate([x, y]) + end +end +---- + +== Lint/TopLevelReturnWithArgument + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.89 +| - +|=== + +This cop checks for top level return with arguments. If there is a +top-level return statement with an argument, then the argument is +always ignored. This is detected automatically since Ruby 2.7. + +=== Examples + +[source,ruby] +---- +# Detected since Ruby 2.7 +return 1 # 1 is always ignored. +---- + +== Lint/TrailingCommaInAttributeDeclaration + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.90 +| - +|=== + +This cop checks for trailing commas in attribute declarations, such as +`#attr_reader`. Leaving a trailing comma will nullify the next method +definition by overriding it with a getter method. + +=== Examples + +[source,ruby] +---- +# bad +class Foo + attr_reader :foo, + + def bar + puts "Unreachable." + end +end + +# good +class Foo + attr_reader :foo + + def bar + puts "No problem!" + end +end +---- + +== Lint/UnderscorePrefixedVariableName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.21 +| - +|=== + +This cop checks for underscore-prefixed variables that are actually +used. + +Since block keyword arguments cannot be arbitrarily named at call +sites, the `AllowKeywordBlockArguments` will allow use of underscore- +prefixed block keyword arguments. + +=== Examples + +==== AllowKeywordBlockArguments: false (default) + +[source,ruby] +---- +# bad + +[1, 2, 3].each do |_num| + do_something(_num) +end + +query(:sales) do |_id:, revenue:, cost:| + {_id: _id, profit: revenue - cost} +end + +# good + +[1, 2, 3].each do |num| + do_something(num) +end + +[1, 2, 3].each do |_num| + do_something # not using `_num` +end +---- + +==== AllowKeywordBlockArguments: true + +[source,ruby] +---- +# good + +query(:sales) do |_id:, revenue:, cost:| + {_id: _id, profit: revenue - cost} +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowKeywordBlockArguments +| `false` +| Boolean +|=== + +== Lint/UnifiedInteger + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.43 +| - +|=== + +This cop checks for using Fixnum or Bignum constant. + +=== Examples + +[source,ruby] +---- +# bad + +1.is_a?(Fixnum) +1.is_a?(Bignum) +---- + +[source,ruby] +---- +# good + +1.is_a?(Integer) +---- + +== Lint/UnreachableCode + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| - +|=== + +This cop checks for unreachable code. +The check are based on the presence of flow of control +statement in non-final position in `begin` (implicit) blocks. + +=== Examples + +[source,ruby] +---- +# bad + +def some_method + return + do_something +end + +# bad + +def some_method + if cond + return + else + return + end + do_something +end +---- + +[source,ruby] +---- +# good + +def some_method + do_something +end +---- + +== Lint/UnreachableLoop + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.89 +| - +|=== + +This cop checks for loops that will have at most one iteration. + +A loop that can never reach the second iteration is a possible error in the code. +In rare cases where only one iteration (or at most one iteration) is intended behavior, +the code should be refactored to use `if` conditionals. + +=== Examples + +[source,ruby] +---- +# bad +while node + do_something(node) + node = node.parent + break +end + +# good +while node + do_something(node) + node = node.parent +end + +# bad +def verify_list(head) + item = head + begin + if verify(item) + return true + else + return false + end + end while(item) +end + +# good +def verify_list(head) + item = head + begin + if verify(item) + item = item.next + else + return false + end + end while(item) + + true +end + +# bad +def find_something(items) + items.each do |item| + if something?(item) + return item + else + raise NotFoundError + end + end +end + +# good +def find_something(items) + items.each do |item| + if something?(item) + return item + end + end + raise NotFoundError +end +---- + +== Lint/UnusedBlockArgument + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.21 +| 0.22 +|=== + +This cop checks for unused block arguments. + +=== Examples + +[source,ruby] +---- +# bad +do_something do |used, unused| + puts used +end + +do_something do |bar| + puts :foo +end + +define_method(:foo) do |bar| + puts :baz +end + +# good +do_something do |used, _unused| + puts used +end + +do_something do + puts :foo +end + +define_method(:foo) do |_bar| + puts :baz +end +---- + +==== IgnoreEmptyBlocks: true (default) + +[source,ruby] +---- +# good +do_something { |unused| } +---- + +==== IgnoreEmptyBlocks: false + +[source,ruby] +---- +# bad +do_something { |unused| } +---- + +==== AllowUnusedKeywordArguments: false (default) + +[source,ruby] +---- +# bad +do_something do |unused: 42| + foo +end +---- + +==== AllowUnusedKeywordArguments: true + +[source,ruby] +---- +# good +do_something do |unused: 42| + foo +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IgnoreEmptyBlocks +| `true` +| Boolean + +| AllowUnusedKeywordArguments +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#underscore-unused-vars + +== Lint/UnusedMethodArgument + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.21 +| 0.81 +|=== + +This cop checks for unused method arguments. + +=== Examples + +[source,ruby] +---- +# bad +def some_method(used, unused, _unused_but_allowed) + puts used +end + +# good +def some_method(used, _unused, _unused_but_allowed) + puts used +end +---- + +==== AllowUnusedKeywordArguments: false (default) + +[source,ruby] +---- +# bad +def do_something(used, unused: 42) + used +end +---- + +==== AllowUnusedKeywordArguments: true + +[source,ruby] +---- +# good +def do_something(used, unused: 42) + used +end +---- + +==== IgnoreEmptyMethods: true (default) + +[source,ruby] +---- +# good +def do_something(unused) +end +---- + +==== IgnoreEmptyMethods: false + +[source,ruby] +---- +# bad +def do_something(unused) +end +---- + +==== IgnoreNotImplementedMethods: true (default) + +[source,ruby] +---- +# good +def do_something(unused) + raise NotImplementedError +end + +def do_something_else(unused) + fail "TODO" +end +---- + +==== IgnoreNotImplementedMethods: false + +[source,ruby] +---- +# bad +def do_something(unused) + raise NotImplementedError +end + +def do_something_else(unused) + fail "TODO" +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowUnusedKeywordArguments +| `false` +| Boolean + +| IgnoreEmptyMethods +| `true` +| Boolean + +| IgnoreNotImplementedMethods +| `true` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#underscore-unused-vars + +== Lint/UriEscapeUnescape + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop identifies places where `URI.escape` can be replaced by +`CGI.escape`, `URI.encode_www_form`, or `URI.encode_www_form_component` +depending on your specific use case. +Also this cop identifies places where `URI.unescape` can be replaced by +`CGI.unescape`, `URI.decode_www_form`, +or `URI.decode_www_form_component` depending on your specific use case. + +=== Examples + +[source,ruby] +---- +# bad +URI.escape('http://example.com') +URI.encode('http://example.com') + +# good +CGI.escape('http://example.com') +URI.encode_www_form([['example', 'param'], ['lang', 'en']]) +URI.encode_www_form(page: 10, locale: 'en') +URI.encode_www_form_component('http://example.com') + +# bad +URI.unescape(enc_uri) +URI.decode(enc_uri) + +# good +CGI.unescape(enc_uri) +URI.decode_www_form(enc_uri) +URI.decode_www_form_component(enc_uri) +---- + +== Lint/UriRegexp + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.50 +| - +|=== + +This cop identifies places where `URI.regexp` is obsolete and should +not be used. Instead, use `URI::DEFAULT_PARSER.make_regexp`. + +=== Examples + +[source,ruby] +---- +# bad +URI.regexp('http://example.com') + +# good +URI::DEFAULT_PARSER.make_regexp('http://example.com') +---- + +== Lint/UselessAccessModifier + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.20 +| 0.83 +|=== + +This cop checks for redundant access modifiers, including those with no +code, those which are repeated, and leading `public` modifiers in a +class or module body. Conditionally-defined methods are considered as +always being defined, and thus access modifiers guarding such methods +are not redundant. + +This cop has `ContextCreatingMethods` option. The default setting value +is an empty array that means no method is specified. +This setting is an array of methods which, when called, are known to +create its own context in the module's current access context. + +It also has `MethodCreatingMethods` option. The default setting value +is an empty array that means no method is specified. +This setting is an array of methods which, when called, are known to +create other methods in the module's current access context. + +=== Examples + +[source,ruby] +---- +# bad +class Foo + public # this is redundant (default access is public) + + def method + end +end + +# bad +class Foo + # The following is redundant (methods defined on the class' + # singleton class are not affected by the public modifier) + public + + def self.method3 + end +end + +# bad +class Foo + protected + + define_method(:method2) do + end + + protected # this is redundant (repeated from previous modifier) + + [1,2,3].each do |i| + define_method("foo#{i}") do + end + end +end + +# bad +class Foo + private # this is redundant (no following methods are defined) +end + +# good +class Foo + private # this is not redundant (a method is defined) + + def method2 + end +end + +# good +class Foo + # The following is not redundant (conditionally defined methods are + # considered as always defining a method) + private + + if condition? + def method + end + end +end + +# good +class Foo + protected # this is not redundant (a method is defined) + + define_method(:method2) do + end +end +---- + +==== ContextCreatingMethods: concerning + +[source,ruby] +---- +# Lint/UselessAccessModifier: +# ContextCreatingMethods: +# - concerning + +# good +require 'active_support/concern' +class Foo + concerning :Bar do + def some_public_method + end + + private + + def some_private_method + end + end + + # this is not redundant because `concerning` created its own context + private + + def some_other_private_method + end +end +---- + +==== MethodCreatingMethods: delegate + +[source,ruby] +---- +# Lint/UselessAccessModifier: +# MethodCreatingMethods: +# - delegate + +# good +require 'active_support/core_ext/module/delegation' +class Foo + # this is not redundant because `delegate` creates methods + private + + delegate :method_a, to: :method_b +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| ContextCreatingMethods +| `[]` +| Array + +| MethodCreatingMethods +| `[]` +| Array +|=== + +== Lint/UselessAssignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.11 +| - +|=== + +This cop checks for every useless assignment to local variable in every +scope. +The basic idea for this cop was from the warning of `ruby -cw`: + + assigned but unused variable - foo + +Currently this cop has advanced logic that detects unreferenced +reassignments and properly handles varied cases such as branch, loop, +rescue, ensure, etc. + +=== Examples + +[source,ruby] +---- +# bad + +def some_method + some_var = 1 + do_something +end +---- + +[source,ruby] +---- +# good + +def some_method + some_var = 1 + do_something(some_var) +end +---- + +=== References + +* https://rubystyle.guide#underscore-unused-vars + +== Lint/UselessElseWithoutRescue + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.17 +| - +|=== + +This cop checks for useless `else` in `begin..end` without `rescue`. + +NOTE: This syntax is no longer valid on Ruby 2.6 or higher and +this cop is going to be removed at some point the future. + +=== Examples + +[source,ruby] +---- +# bad + +begin + do_something +else + do_something_else # This will never be run. +end +---- + +[source,ruby] +---- +# good + +begin + do_something +rescue + handle_errors +else + do_something_else +end +---- + +== Lint/UselessMethodDefinition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.90 +| - +|=== + +This cop checks for useless method definitions, specifically: empty constructors +and methods just delegating to `super`. + +This cop is marked as unsafe as it can trigger false positives for cases when +an empty constructor just overrides the parent constructor, which is bad anyway. + +=== Examples + +[source,ruby] +---- +# bad +def initialize + super +end + +def method + super +end + +# good - with default arguments +def initialize(x = Object.new) + super +end + +# good +def initialize + super + initialize_internals +end + +def method(*args) + super(:extra_arg, *args) +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowComments +| `true` +| Boolean +|=== + +== Lint/UselessSetterCall + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| No +| 0.13 +| 0.80 +|=== + +This cop checks for setter call to local variable as the final +expression of a function definition. + +NOTE: There are edge cases in which the local variable references a +value that is also accessible outside the local scope. This is not +detected by the cop, and it can yield a false positive. + +=== Examples + +[source,ruby] +---- +# bad + +def something + x = Something.new + x.attr = 5 +end +---- + +[source,ruby] +---- +# good + +def something + x = Something.new + x.attr = 5 + x +end +---- + +== Lint/UselessTimes + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.91 +| - +|=== + +This cop checks for uses of `Integer#times` that will never yield +(when the integer <= 0) or that will only ever yield once +(`1.times`). + +This cop is marked as unsafe as `times` returns its receiver, which +is *usually* OK, but might change behavior. + +=== Examples + +[source,ruby] +---- +# bad +-5.times { do_something } +0.times { do_something } +1.times { do_something } +1.times { |i| do_something(i) } + +# good +do_something +do_something(1) +---- + +== Lint/Void + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| - +|=== + +This cop checks for operators, variables, literals, and nonmutating +methods used in void context. + +=== Examples + +==== CheckForMethodsWithNoSideEffects: false (default) + +[source,ruby] +---- +# bad +def some_method + some_num * 10 + do_something +end + +def some_method(some_var) + some_var + do_something +end +---- + +==== CheckForMethodsWithNoSideEffects: true + +[source,ruby] +---- +# bad +def some_method(some_array) + some_array.sort + do_something(some_array) +end + +# good +def some_method + do_something + some_num * 10 +end + +def some_method(some_var) + do_something + some_var +end + +def some_method(some_array) + some_array.sort! + do_something(some_array) +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| CheckForMethodsWithNoSideEffects +| `false` +| Boolean +|=== diff --git a/docs/modules/ROOT/pages/cops_metrics.adoc b/docs/modules/ROOT/pages/cops_metrics.adoc new file mode 100644 index 000000000000..43e1cb2b3513 --- /dev/null +++ b/docs/modules/ROOT/pages/cops_metrics.adoc @@ -0,0 +1,481 @@ += Metrics + +== Metrics/AbcSize + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.27 +| 0.81 +|=== + +This cop checks that the ABC size of methods is not higher than the +configured maximum. The ABC size is based on assignments, branches +(method calls), and conditions. See http://c2.com/cgi/wiki?AbcMetric +and https://en.wikipedia.org/wiki/ABC_Software_Metric. + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IgnoredMethods +| `[]` +| Array + +| Max +| `17` +| Integer +|=== + +=== References + +* http://c2.com/cgi/wiki?AbcMetric +* https://en.wikipedia.org/wiki/ABC_Software_Metric + +== Metrics/BlockLength + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.44 +| 0.87 +|=== + +This cop checks if the length of a block exceeds some maximum value. +Comment lines can optionally be ignored. +The maximum allowed length is configurable. +The cop can be configured to ignore blocks passed to certain methods. + +You can set literals you want to fold with `CountAsOne`. +Available are: 'array', 'hash', and 'heredoc'. Each literal +will be counted as one line regardless of its actual size. + +NOTE: This cop does not apply for `Struct` definitions. + +=== Examples + +==== CountAsOne: ['array', 'heredoc'] + +[source,ruby] +---- +something do + array = [ # +1 + 1, + 2 + ] + + hash = { # +3 + key: 'value' + } + + msg = <<~HEREDOC # +1 + Heredoc + content. + HEREDOC +end # 5 points +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| CountComments +| `false` +| Boolean + +| Max +| `25` +| Integer + +| CountAsOne +| `[]` +| Array + +| ExcludedMethods +| `refine` +| Array + +| Exclude +| `**/*.gemspec` +| Array +|=== + +== Metrics/BlockNesting + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.25 +| 0.47 +|=== + +This cop checks for excessive nesting of conditional and looping +constructs. + +You can configure if blocks are considered using the `CountBlocks` +option. When set to `false` (the default) blocks are not counted +towards the nesting level. Set to `true` to count blocks as well. + +The maximum level of nesting allowed is configurable. + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| CountBlocks +| `false` +| Boolean + +| Max +| `3` +| Integer +|=== + +=== References + +* https://rubystyle.guide#three-is-the-number-thou-shalt-count + +== Metrics/ClassLength + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.25 +| 0.87 +|=== + +This cop checks if the length a class exceeds some maximum value. +Comment lines can optionally be ignored. +The maximum allowed length is configurable. + +You can set literals you want to fold with `CountAsOne`. +Available are: 'array', 'hash', and 'heredoc'. Each literal +will be counted as one line regardless of its actual size. + +NOTE: This cop also applies for `Struct` definitions. + +=== Examples + +==== CountAsOne: ['array', 'heredoc'] + +[source,ruby] +---- +class Foo + ARRAY = [ # +1 + 1, + 2 + ] + + HASH = { # +3 + key: 'value' + } + + MSG = <<~HEREDOC # +1 + Heredoc + content. + HEREDOC +end # 5 points +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| CountComments +| `false` +| Boolean + +| Max +| `100` +| Integer + +| CountAsOne +| `[]` +| Array +|=== + +== Metrics/CyclomaticComplexity + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.25 +| 0.81 +|=== + +This cop checks that the cyclomatic complexity of methods is not higher +than the configured maximum. The cyclomatic complexity is the number of +linearly independent paths through a method. The algorithm counts +decision points and adds one. + +An if statement (or unless or ?:) increases the complexity by one. An +else branch does not, since it doesn't add a decision point. The && +operator (or keyword and) can be converted to a nested if statement, +and ||/or is shorthand for a sequence of ifs, so they also add one. +Loops can be said to have an exit condition, so they add one. +Blocks that are calls to builtin iteration methods +(e.g. `ary.map{...}) also add one, others are ignored. + + def each_child_node(*types) # count begins: 1 + unless block_given? # unless: +1 + return to_enum(__method__, *types) + + children.each do |child| # each{}: +1 + next unless child.is_a?(Node) # unless: +1 + + yield child if types.empty? || # if: +1, ||: +1 + types.include?(child.type) + end + + self + end # total: 6 + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IgnoredMethods +| `[]` +| Array + +| Max +| `7` +| Integer +|=== + +== Metrics/MethodLength + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.25 +| 0.87 +|=== + +This cop checks if the length of a method exceeds some maximum value. +Comment lines can optionally be ignored. +The maximum allowed length is configurable. + +You can set literals you want to fold with `CountAsOne`. +Available are: 'array', 'hash', and 'heredoc'. Each literal +will be counted as one line regardless of its actual size. + +=== Examples + +==== CountAsOne: ['array', 'heredoc'] + +[source,ruby] +---- +def m + array = [ # +1 + 1, + 2 + ] + + hash = { # +3 + key: 'value' + } + + <<~HEREDOC # +1 + Heredoc + content. + HEREDOC +end # 5 points +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| CountComments +| `false` +| Boolean + +| Max +| `10` +| Integer + +| CountAsOne +| `[]` +| Array + +| ExcludedMethods +| `[]` +| Array +|=== + +=== References + +* https://rubystyle.guide#short-methods + +== Metrics/ModuleLength + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.31 +| 0.87 +|=== + +This cop checks if the length a module exceeds some maximum value. +Comment lines can optionally be ignored. +The maximum allowed length is configurable. + +You can set literals you want to fold with `CountAsOne`. +Available are: 'array', 'hash', and 'heredoc'. Each literal +will be counted as one line regardless of its actual size. + +=== Examples + +==== CountAsOne: ['array', 'heredoc'] + +[source,ruby] +---- +module M + ARRAY = [ # +1 + 1, + 2 + ] + + HASH = { # +3 + key: 'value' + } + + MSG = <<~HEREDOC # +1 + Heredoc + content. + HEREDOC +end # 5 points +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| CountComments +| `false` +| Boolean + +| Max +| `100` +| Integer + +| CountAsOne +| `[]` +| Array +|=== + +== Metrics/ParameterLists + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.25 +| - +|=== + +This cop checks for methods with too many parameters. +The maximum number of parameters is configurable. +Keyword arguments can optionally be excluded from the total count. + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Max +| `5` +| Integer + +| CountKeywordArgs +| `true` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#too-many-params + +== Metrics/PerceivedComplexity + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.25 +| 0.81 +|=== + +This cop tries to produce a complexity score that's a measure of the +complexity the reader experiences when looking at a method. For that +reason it considers `when` nodes as something that doesn't add as much +complexity as an `if` or a `&&`. Except if it's one of those special +`case`/`when` constructs where there's no expression after `case`. Then +the cop treats it as an `if`/`elsif`/`elsif`... and lets all the `when` +nodes count. In contrast to the CyclomaticComplexity cop, this cop +considers `else` nodes as adding complexity. + +=== Examples + +[source,ruby] +---- +def my_method # 1 + if cond # 1 + case var # 2 (0.8 + 4 * 0.2, rounded) + when 1 then func_one + when 2 then func_two + when 3 then func_three + when 4..10 then func_other + end + else # 1 + do_something until a && b # 2 + end # === +end # 7 complexity points +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IgnoredMethods +| `[]` +| Array + +| Max +| `8` +| Integer +|=== diff --git a/docs/modules/ROOT/pages/cops_migration.adoc b/docs/modules/ROOT/pages/cops_migration.adoc new file mode 100644 index 000000000000..b4b50b30d69c --- /dev/null +++ b/docs/modules/ROOT/pages/cops_migration.adoc @@ -0,0 +1,16 @@ += Migration + +== Migration/DepartmentName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.75 +| - +|=== + +Check that cop names in rubocop:disable comments are given with +department name. diff --git a/docs/modules/ROOT/pages/cops_naming.adoc b/docs/modules/ROOT/pages/cops_naming.adoc new file mode 100644 index 000000000000..57cfeeea848f --- /dev/null +++ b/docs/modules/ROOT/pages/cops_naming.adoc @@ -0,0 +1,1036 @@ += Naming + +== Naming/AccessorMethodName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop makes sure that accessor methods are named properly. + +=== Examples + +[source,ruby] +---- +# bad +def set_attribute(value) +end + +# good +def attribute=(value) +end + +# bad +def get_attribute +end + +# good +def attribute +end +---- + +=== References + +* https://rubystyle.guide#accessor_mutator_method_names + +== Naming/AsciiIdentifiers + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| 0.87 +|=== + +This cop checks for non-ascii characters in identifier and constant names. +Identifiers are always checked and whether constants are checked +can be controlled using AsciiConstants config. + +=== Examples + +[source,ruby] +---- +# bad +def καλημερα # Greek alphabet (non-ascii) +end + +# bad +def こんにちはと言う # Japanese character (non-ascii) +end + +# bad +def hello_🍣 # Emoji (non-ascii) +end + +# good +def say_hello +end + +# bad +신장 = 10 # Hangul character (non-ascii) + +# good +height = 10 + +# bad +params[:عرض_gteq] # Arabic character (non-ascii) + +# good +params[:width_gteq] +---- + +==== AsciiConstants: true (default) + +[source,ruby] +---- +# bad +class Foö +end + +FOÖ = "foo" +---- + +==== AsciiConstants: false + +[source,ruby] +---- +# good +class Foö +end + +FOÖ = "foo" +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AsciiConstants +| `true` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#english-identifiers + +== Naming/BinaryOperatorParameterName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop makes sure that certain binary operator methods have their +sole parameter named `other`. + +=== Examples + +[source,ruby] +---- +# bad +def +(amount); end + +# good +def +(other); end +---- + +=== References + +* https://rubystyle.guide#other-arg + +== Naming/BlockParameterName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.53 +| 0.77 +|=== + +This cop checks block parameter names for how descriptive they +are. It is highly configurable. + +The `MinNameLength` config option takes an integer. It represents +the minimum amount of characters the name must be. Its default is 1. +The `AllowNamesEndingInNumbers` config option takes a boolean. When +set to false, this cop will register offenses for names ending with +numbers. Its default is false. The `AllowedNames` config option +takes an array of permitted names that will never register an +offense. The `ForbiddenNames` config option takes an array of +restricted names that will always register an offense. + +=== Examples + +[source,ruby] +---- +# bad +bar do |varOne, varTwo| + varOne + varTwo +end + +# With `AllowNamesEndingInNumbers` set to false +foo { |num1, num2| num1 * num2 } + +# With `MinParamNameLength` set to number greater than 1 +baz { |a, b, c| do_stuff(a, b, c) } + +# good +bar do |thud, fred| + thud + fred +end + +foo { |speed, distance| speed * distance } + +baz { |age, height, gender| do_stuff(age, height, gender) } +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| MinNameLength +| `1` +| Integer + +| AllowNamesEndingInNumbers +| `true` +| Boolean + +| AllowedNames +| `[]` +| Array + +| ForbiddenNames +| `[]` +| Array +|=== + +== Naming/ClassAndModuleCamelCase + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| 0.85 +|=== + +This cop checks for class and module names with +an underscore in them. + +`AllowedNames` config takes an array of permitted names. +Its default value is `['module_parent']`. +These names can be full class/module names or part of the name. +eg. Adding `my_class` to the `AllowedNames` config will allow names like +`my_class`, `my_class::User`, `App::my_class`, `App::my_class::User`, etc. + +=== Examples + +[source,ruby] +---- +# bad +class My_Class +end +module My_Module +end + +# good +class MyClass +end +module MyModule +end +class module_parent::MyModule +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedNames +| `module_parent` +| Array +|=== + +=== References + +* https://rubystyle.guide#camelcase-classes + +== Naming/ConstantName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop checks whether constant names are written using +SCREAMING_SNAKE_CASE. + +To avoid false positives, it ignores cases in which we cannot know +for certain the type of value that would be assigned to a constant. + +=== Examples + +[source,ruby] +---- +# bad +InchInCm = 2.54 +INCHinCM = 2.54 +Inch_In_Cm = 2.54 + +# good +INCH_IN_CM = 2.54 +---- + +=== References + +* https://rubystyle.guide#screaming-snake-case + +== Naming/FileName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop makes sure that Ruby source files have snake_case +names. Ruby scripts (i.e. source files with a shebang in the +first line) are ignored. + +The cop also ignores `.gemspec` files, because Bundler +recommends using dashes to separate namespaces in nested gems +(i.e. `bundler-console` becomes `Bundler::Console`). As such, the +gemspec is supposed to be named `bundler-console.gemspec`. + +=== Examples + +[source,ruby] +---- +# bad +lib/layoutManager.rb + +anything/usingCamelCase + +# good +lib/layout_manager.rb + +anything/using_snake_case.rake +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Exclude +| `[]` +| Array + +| ExpectMatchingDefinition +| `false` +| Boolean + +| CheckDefinitionPathHierarchy +| `true` +| Boolean + +| Regex +| `` +| + +| IgnoreExecutableScripts +| `true` +| Boolean + +| AllowedAcronyms +| `CLI`, `DSL`, `ACL`, `API`, `ASCII`, `CPU`, `CSS`, `DNS`, `EOF`, `GUID`, `HTML`, `HTTP`, `HTTPS`, `ID`, `IP`, `JSON`, `LHS`, `QPS`, `RAM`, `RHS`, `RPC`, `SLA`, `SMTP`, `SQL`, `SSH`, `TCP`, `TLS`, `TTL`, `UDP`, `UI`, `UID`, `UUID`, `URI`, `URL`, `UTF8`, `VM`, `XML`, `XMPP`, `XSRF`, `XSS` +| Array +|=== + +=== References + +* https://rubystyle.guide#snake-case-files + +== Naming/HeredocDelimiterCase + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop checks that your heredocs are using the configured case. +By default it is configured to enforce uppercase heredocs. + +=== Examples + +==== EnforcedStyle: uppercase (default) + +[source,ruby] +---- +# bad +<<-sql + SELECT * FROM foo +sql + +# good +<<-SQL + SELECT * FROM foo +SQL +---- + +==== EnforcedStyle: lowercase + +[source,ruby] +---- +# bad +<<-SQL + SELECT * FROM foo +SQL + +# good +<<-sql + SELECT * FROM foo +sql +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `uppercase` +| `lowercase`, `uppercase` +|=== + +=== References + +* https://rubystyle.guide#heredoc-delimiters + +== Naming/HeredocDelimiterNaming + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop checks that your heredocs are using meaningful delimiters. +By default it disallows `END` and `EO*`, and can be configured through +forbidden listing additional delimiters. + +=== Examples + +[source,ruby] +---- +# good +<<-SQL + SELECT * FROM foo +SQL + +# bad +<<-END + SELECT * FROM foo +END + +# bad +<<-EOS + SELECT * FROM foo +EOS +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| ForbiddenDelimiters +| `(?-mix:(^|\s)(EO[A-Z]{1}|END)(\s|$))` +| Array +|=== + +=== References + +* https://rubystyle.guide#heredoc-delimiters + +== Naming/MemoizedInstanceVariableName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.53 +| 0.58 +|=== + +This cop checks for memoized methods whose instance variable name +does not match the method name. + +This cop can be configured with the EnforcedStyleForLeadingUnderscores +directive. It can be configured to allow for memoized instance variables +prefixed with an underscore. Prefixing ivars with an underscore is a +convention that is used to implicitly indicate that an ivar should not +be set or referenced outside of the memoization method. + +=== Examples + +==== EnforcedStyleForLeadingUnderscores: disallowed (default) + +[source,ruby] +---- +# bad +# Method foo is memoized using an instance variable that is +# not `@foo`. This can cause confusion and bugs. +def foo + @something ||= calculate_expensive_thing +end + +# good +def _foo + @foo ||= calculate_expensive_thing +end + +# good +def foo + @foo ||= calculate_expensive_thing +end + +# good +def foo + @foo ||= begin + calculate_expensive_thing + end +end + +# good +def foo + helper_variable = something_we_need_to_calculate_foo + @foo ||= calculate_expensive_thing(helper_variable) +end +---- + +==== EnforcedStyleForLeadingUnderscores: required + +[source,ruby] +---- +# bad +def foo + @something ||= calculate_expensive_thing +end + +# bad +def foo + @foo ||= calculate_expensive_thing +end + +# good +def foo + @_foo ||= calculate_expensive_thing +end + +# good +def _foo + @_foo ||= calculate_expensive_thing +end +---- + +==== EnforcedStyleForLeadingUnderscores :optional + +[source,ruby] +---- +# bad +def foo + @something ||= calculate_expensive_thing +end + +# good +def foo + @foo ||= calculate_expensive_thing +end + +# good +def foo + @_foo ||= calculate_expensive_thing +end + +# good +def _foo + @_foo ||= calculate_expensive_thing +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyleForLeadingUnderscores +| `disallowed` +| `disallowed`, `required`, `optional` +|=== + +== Naming/MethodName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop makes sure that all methods use the configured style, +snake_case or camelCase, for their names. + +This cop has `IgnoredPatterns` configuration option. + + Naming/MethodName: + IgnoredPatterns: + - '\A\s*onSelectionBulkChange\s*' + - '\A\s*onSelectionCleared\s*' + +Method names matching patterns are always allowed. + +=== Examples + +==== EnforcedStyle: snake_case (default) + +[source,ruby] +---- +# bad +def fooBar; end + +# good +def foo_bar; end +---- + +==== EnforcedStyle: camelCase + +[source,ruby] +---- +# bad +def foo_bar; end + +# good +def fooBar; end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `snake_case` +| `snake_case`, `camelCase` + +| IgnoredPatterns +| `[]` +| Array +|=== + +=== References + +* https://rubystyle.guide#snake-case-symbols-methods-vars + +== Naming/MethodParameterName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.53 +| 0.77 +|=== + +This cop checks method parameter names for how descriptive they +are. It is highly configurable. + +The `MinNameLength` config option takes an integer. It represents +the minimum amount of characters the name must be. Its default is 3. +The `AllowNamesEndingInNumbers` config option takes a boolean. When +set to false, this cop will register offenses for names ending with +numbers. Its default is false. The `AllowedNames` config option +takes an array of permitted names that will never register an +offense. The `ForbiddenNames` config option takes an array of +restricted names that will always register an offense. + +=== Examples + +[source,ruby] +---- +# bad +def bar(varOne, varTwo) + varOne + varTwo +end + +# With `AllowNamesEndingInNumbers` set to false +def foo(num1, num2) + num1 * num2 +end + +# With `MinArgNameLength` set to number greater than 1 +def baz(a, b, c) + do_stuff(a, b, c) +end + +# good +def bar(thud, fred) + thud + fred +end + +def foo(speed, distance) + speed * distance +end + +def baz(age_a, height_b, gender_c) + do_stuff(age_a, height_b, gender_c) +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| MinNameLength +| `3` +| Integer + +| AllowNamesEndingInNumbers +| `true` +| Boolean + +| AllowedNames +| `at`, `by`, `db`, `id`, `in`, `io`, `ip`, `of`, `on`, `os`, `pp`, `to` +| Array + +| ForbiddenNames +| `[]` +| Array +|=== + +== Naming/PredicateName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| 0.77 +|=== + +This cop makes sure that predicates are named properly. + +=== Examples + +[source,ruby] +---- +# bad +def is_even(value) +end + +def is_even?(value) +end + +# good +def even?(value) +end + +# bad +def has_value +end + +def has_value? +end + +# good +def value? +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| NamePrefix +| `is_`, `has_`, `have_` +| Array + +| ForbiddenPrefixes +| `is_`, `has_`, `have_` +| Array + +| AllowedMethods +| `is_a?` +| Array + +| MethodDefinitionMacros +| `define_method`, `define_singleton_method` +| Array + +| Exclude +| `spec/**/*` +| Array +|=== + +=== References + +* https://rubystyle.guide#bool-methods-qmark + +== Naming/RescuedExceptionsVariableName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.67 +| 0.68 +|=== + +This cop makes sure that rescued exceptions variables are named as +expected. + +The `PreferredName` config option takes a `String`. It represents +the required name of the variable. Its default is `e`. + +=== Examples + +==== PreferredName: e (default) + +[source,ruby] +---- +# bad +begin + # do something +rescue MyException => exception + # do something +end + +# good +begin + # do something +rescue MyException => e + # do something +end + +# good +begin + # do something +rescue MyException => _e + # do something +end +---- + +==== PreferredName: exception + +[source,ruby] +---- +# bad +begin + # do something +rescue MyException => e + # do something +end + +# good +begin + # do something +rescue MyException => exception + # do something +end + +# good +begin + # do something +rescue MyException => _exception + # do something +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| PreferredName +| `e` +| String +|=== + +== Naming/VariableName + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop makes sure that all variables use the configured style, +snake_case or camelCase, for their names. + +=== Examples + +==== EnforcedStyle: snake_case (default) + +[source,ruby] +---- +# bad +fooBar = 1 + +# good +foo_bar = 1 +---- + +==== EnforcedStyle: camelCase + +[source,ruby] +---- +# bad +foo_bar = 1 + +# good +fooBar = 1 +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `snake_case` +| `snake_case`, `camelCase` +|=== + +=== References + +* https://rubystyle.guide#snake-case-symbols-methods-vars + +== Naming/VariableNumber + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.50 +| - +|=== + +This cop makes sure that all numbered variables use the +configured style, snake_case, normalcase, or non_integer, +for their numbering. + +=== Examples + +==== EnforcedStyle: snake_case + +[source,ruby] +---- +# bad + +variable1 = 1 + +# good + +variable_1 = 1 +---- + +==== EnforcedStyle: normalcase (default) + +[source,ruby] +---- +# bad + +variable_1 = 1 + +# good + +variable1 = 1 +---- + +==== EnforcedStyle: non_integer + +[source,ruby] +---- +# bad + +variable1 = 1 + +variable_1 = 1 + +# good + +variableone = 1 + +variable_one = 1 +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `normalcase` +| `snake_case`, `normalcase`, `non_integer` +|=== diff --git a/manual/cops_security.md b/docs/modules/ROOT/pages/cops_security.adoc similarity index 50% rename from manual/cops_security.md rename to docs/modules/ROOT/pages/cops_security.adoc index 060636c06d5e..8f6c3bd51a33 100644 --- a/manual/cops_security.md +++ b/docs/modules/ROOT/pages/cops_security.adoc @@ -1,27 +1,40 @@ -# Security += Security -## Security/Eval +== Security/Eval -Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged ---- | --- | --- | --- | --- -Enabled | Yes | No | 0.47 | - +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.47 +| - +|=== This cop checks for the use of `Kernel#eval` and `Binding#eval`. -### Examples +=== Examples -```ruby +[source,ruby] +---- # bad eval(something) binding.eval(something) -``` +---- + +== Security/JSONLoad -## Security/JSONLoad +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged -Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged ---- | --- | --- | --- | --- -Enabled | Yes | Yes (Unsafe) | 0.43 | 0.44 +| Enabled +| Yes +| Yes (Unsafe) +| 0.43 +| 0.44 +|=== This cop checks for the use of JSON class methods which have potential security issues. @@ -34,40 +47,52 @@ If reading single values (rather than proper JSON objects), like option, like `JSON.parse('false', quirks_mode: true)`. Other similar issues may apply. -### Examples +=== Examples -```ruby +[source,ruby] +---- # bad JSON.load("{}") JSON.restore("{}") # good JSON.parse("{}") -``` +---- + +=== Configurable attributes -### Configurable attributes +|=== +| Name | Default value | Configurable values -Name | Default value | Configurable values ---- | --- | --- -AutoCorrect | `false` | Boolean +| AutoCorrect +| `false` +| Boolean +|=== -### References +=== References -* [https://ruby-doc.org/stdlib-2.3.0/libdoc/json/rdoc/JSON.html#method-i-load](https://ruby-doc.org/stdlib-2.3.0/libdoc/json/rdoc/JSON.html#method-i-load) +* https://ruby-doc.org/stdlib-2.7.0/libdoc/json/rdoc/JSON.html#method-i-load -## Security/MarshalLoad +== Security/MarshalLoad -Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged ---- | --- | --- | --- | --- -Enabled | Yes | No | 0.47 | - +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.47 +| - +|=== This cop checks for the use of Marshal class methods which have potential security issues leading to remote code execution when loading from an untrusted source. -### Examples +=== Examples -```ruby +[source,ruby] +---- # bad Marshal.load("{}") Marshal.restore("{}") @@ -77,17 +102,23 @@ Marshal.dump("{}") # okish - deep copy hack Marshal.load(Marshal.dump({})) -``` +---- + +=== References -### References +* https://ruby-doc.org/core-2.7.0/Marshal.html#module-Marshal-label-Security+considerations -* [https://ruby-doc.org/core-2.3.3/Marshal.html#module-Marshal-label-Security+considerations](https://ruby-doc.org/core-2.3.3/Marshal.html#module-Marshal-label-Security+considerations) +== Security/Open -## Security/Open +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged -Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged ---- | --- | --- | --- | --- -Enabled | No | No | 0.53 | - +| Enabled +| No +| No +| 0.53 +| - +|=== This cop checks for the use of `Kernel#open`. @@ -97,9 +128,10 @@ a serious security risk by using variable input to the argument of `Kernel#open`. It would be better to use `File.open`, `IO.popen` or `URI#open` explicitly. -### Examples +=== Examples -```ruby +[source,ruby] +---- # bad open(something) @@ -107,29 +139,36 @@ open(something) File.open(something) IO.popen(something) URI.parse(something).open -``` +---- + +== Security/YAMLLoad -## Security/YAMLLoad +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged -Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged ---- | --- | --- | --- | --- -Enabled | Yes | Yes (Unsafe) | 0.47 | - +| Enabled +| Yes +| Yes (Unsafe) +| 0.47 +| - +|=== This cop checks for the use of YAML class methods which have potential security issues leading to remote code execution when loading from an untrusted source. -### Examples +=== Examples -```ruby +[source,ruby] +---- # bad YAML.load("--- foo") # good YAML.safe_load("--- foo") YAML.dump("foo") -``` +---- -### References +=== References -* [https://ruby-doc.org/stdlib-2.3.3/libdoc/yaml/rdoc/YAML.html#module-YAML-label-Security](https://ruby-doc.org/stdlib-2.3.3/libdoc/yaml/rdoc/YAML.html#module-YAML-label-Security) +* https://ruby-doc.org/stdlib-2.7.0/libdoc/yaml/rdoc/YAML.html#module-YAML-label-Security diff --git a/docs/modules/ROOT/pages/cops_style.adoc b/docs/modules/ROOT/pages/cops_style.adoc new file mode 100644 index 000000000000..7b0b980ecb2d --- /dev/null +++ b/docs/modules/ROOT/pages/cops_style.adoc @@ -0,0 +1,11121 @@ += Style + +== Style/AccessModifierDeclarations + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.57 +| 0.81 +|=== + +Access modifiers should be declared to apply to a group of methods +or inline before each method, depending on configuration. +EnforcedStyle config covers only method definitions. +Applications of visibility methods to symbols can be controlled +using AllowModifiersOnSymbols config. + +=== Examples + +==== EnforcedStyle: group (default) + +[source,ruby] +---- +# bad +class Foo + + private def bar; end + private def baz; end + +end + +# good +class Foo + + private + + def bar; end + def baz; end + +end +---- + +==== EnforcedStyle: inline + +[source,ruby] +---- +# bad +class Foo + + private + + def bar; end + def baz; end + +end + +# good +class Foo + + private def bar; end + private def baz; end + +end +---- + +==== AllowModifiersOnSymbols: true + +[source,ruby] +---- +# good +class Foo + + private :bar, :baz + +end +---- + +==== AllowModifiersOnSymbols: false + +[source,ruby] +---- +# bad +class Foo + + private :bar, :baz + +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `group` +| `inline`, `group` + +| AllowModifiersOnSymbols +| `true` +| Boolean +|=== + +== Style/AccessorGrouping + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.87 +| - +|=== + +This cop checks for grouping of accessors in `class` and `module` bodies. +By default it enforces accessors to be placed in grouped declarations, +but it can be configured to enforce separating them in multiple declarations. + +Note: `Sorbet` is not compatible with "grouped" style. Consider "separated" style +or disabling this cop. + +=== Examples + +==== EnforcedStyle: grouped (default) + +[source,ruby] +---- +# bad +class Foo + attr_reader :bar + attr_reader :baz +end + +# good +class Foo + attr_reader :bar, :baz +end +---- + +==== EnforcedStyle: separated + +[source,ruby] +---- +# bad +class Foo + attr_reader :bar, :baz +end + +# good +class Foo + attr_reader :bar + attr_reader :baz +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `grouped` +| `separated`, `grouped` +|=== + +== Style/Alias + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.36 +|=== + +This cop enforces the use of either `#alias` or `#alias_method` +depending on configuration. +It also flags uses of `alias :symbol` rather than `alias bareword`. + +=== Examples + +==== EnforcedStyle: prefer_alias (default) + +[source,ruby] +---- +# bad +alias_method :bar, :foo +alias :bar :foo + +# good +alias bar foo +---- + +==== EnforcedStyle: prefer_alias_method + +[source,ruby] +---- +# bad +alias :bar :foo +alias bar foo + +# good +alias_method :bar, :foo +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `prefer_alias` +| `prefer_alias`, `prefer_alias_method` +|=== + +=== References + +* https://rubystyle.guide#alias-method-lexically + +== Style/AndOr + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.25 +|=== + +This cop checks for uses of `and` and `or`, and suggests using `&&` and +`||` instead. It can be configured to check only in conditions or in +all contexts. + +=== Examples + +==== EnforcedStyle: always + +[source,ruby] +---- +# bad +foo.save and return + +# bad +if foo and bar +end + +# good +foo.save && return + +# good +if foo && bar +end +---- + +==== EnforcedStyle: conditionals (default) + +[source,ruby] +---- +# bad +if foo and bar +end + +# good +foo.save && return + +# good +foo.save and return + +# good +if foo && bar +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `conditionals` +| `always`, `conditionals` +|=== + +=== References + +* https://rubystyle.guide#no-and-or-or + +== Style/ArrayCoercion + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| No +| Yes (Unsafe) +| 0.88 +| - +|=== + +This cop enforces the use of `Array()` instead of explicit `Array` check or `[*var]`. + +This cop is disabled by default because false positive will occur if +the argument of `Array()` is not an array (e.g. Hash, Set), +an array will be returned as an incompatibility result. + +=== Examples + +[source,ruby] +---- +# bad +paths = [paths] unless paths.is_a?(Array) +paths.each { |path| do_something(path) } + +# bad (always creates a new Array instance) +[*paths].each { |path| do_something(path) } + +# good (and a bit more readable) +Array(paths).each { |path| do_something(path) } +---- + +=== References + +* https://rubystyle.guide#array-coercion + +== Style/ArrayJoin + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.20 +| 0.31 +|=== + +This cop checks for uses of "*" as a substitute for _join_. + +Not all cases can reliably checked, due to Ruby's dynamic +types, so we consider only cases when the first argument is an +array literal or the second is a string literal. + +=== Examples + +[source,ruby] +---- +# bad +%w(foo bar baz) * "," + +# good +%w(foo bar baz).join(",") +---- + +=== References + +* https://rubystyle.guide#array-join + +== Style/AsciiComments + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| 0.52 +|=== + +This cop checks for non-ascii (non-English) characters +in comments. You could set an array of allowed non-ascii chars in +AllowedChars attribute (empty by default). + +=== Examples + +[source,ruby] +---- +# bad +# Translates from English to 日本語。 + +# good +# Translates from English to Japanese +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedChars +| `[]` +| Array +|=== + +=== References + +* https://rubystyle.guide#english-comments + +== Style/Attr + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.12 +|=== + +This cop checks for uses of Module#attr. + +=== Examples + +[source,ruby] +---- +# bad - creates a single attribute accessor (deprecated in Ruby 1.9) +attr :something, true +attr :one, :two, :three # behaves as attr_reader + +# good +attr_accessor :something +attr_reader :one, :two, :three +---- + +=== References + +* https://rubystyle.guide#attr + +== Style/AutoResourceCleanup + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.30 +| - +|=== + +This cop checks for cases when you could use a block +accepting version of a method that does automatic +resource cleanup. + +=== Examples + +[source,ruby] +---- +# bad +f = File.open('file') + +# good +File.open('file') do |f| + # ... +end +---- + +== Style/BarePercentLiterals + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.25 +| - +|=== + +This cop checks if usage of %() or %Q() matches configuration. + +=== Examples + +==== EnforcedStyle: bare_percent (default) + +[source,ruby] +---- +# bad +%Q(He said: "#{greeting}") +%q{She said: 'Hi'} + +# good +%(He said: "#{greeting}") +%{She said: 'Hi'} +---- + +==== EnforcedStyle: percent_q + +[source,ruby] +---- +# bad +%|He said: "#{greeting}"| +%/She said: 'Hi'/ + +# good +%Q|He said: "#{greeting}"| +%q/She said: 'Hi'/ +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `bare_percent` +| `percent_q`, `bare_percent` +|=== + +=== References + +* https://rubystyle.guide#percent-q-shorthand + +== Style/BeginBlock + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| - +|=== + +This cop checks for BEGIN blocks. + +=== Examples + +[source,ruby] +---- +# bad +BEGIN { test } +---- + +=== References + +* https://rubystyle.guide#no-BEGIN-blocks + +== Style/BisectedAttrAccessor + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.87 +| - +|=== + +This cop checks for places where `attr_reader` and `attr_writer` +for the same method can be combined into single `attr_accessor`. + +=== Examples + +[source,ruby] +---- +# bad +class Foo + attr_reader :bar + attr_writer :bar +end + +# good +class Foo + attr_accessor :bar +end +---- + +== Style/BlockComments + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.23 +|=== + +This cop looks for uses of block comments (=begin...=end). + +=== Examples + +[source,ruby] +---- +# bad +=begin +Multiple lines +of comments... +=end + +# good +# Multiple lines +# of comments... +---- + +=== References + +* https://rubystyle.guide#no-block-comments + +== Style/BlockDelimiters + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.30 +| 0.35 +|=== + +Check for uses of braces or do/end around single line or +multi-line blocks. + +=== Examples + +==== EnforcedStyle: line_count_based (default) + +[source,ruby] +---- +# bad - single line block +items.each do |item| item / 5 end + +# good - single line block +items.each { |item| item / 5 } + +# bad - multi-line block +things.map { |thing| + something = thing.some_method + process(something) +} + +# good - multi-line block +things.map do |thing| + something = thing.some_method + process(something) +end +---- + +==== EnforcedStyle: semantic + +[source,ruby] +---- +# Prefer `do...end` over `{...}` for procedural blocks. + +# return value is used/assigned +# bad +foo = map do |x| + x +end +puts (map do |x| + x +end) + +# return value is not used out of scope +# good +map do |x| + x +end + +# Prefer `{...}` over `do...end` for functional blocks. + +# return value is not used out of scope +# bad +each { |x| + x +} + +# return value is used/assigned +# good +foo = map { |x| + x +} +map { |x| + x +}.inspect + +# The AllowBracesOnProceduralOneLiners option is ignored unless the +# EnforcedStyle is set to `semantic`. If so: + +# If the AllowBracesOnProceduralOneLiners option is unspecified, or +# set to `false` or any other falsey value, then semantic purity is +# maintained, so one-line procedural blocks must use do-end, not +# braces. + +# bad +collection.each { |element| puts element } + +# good +collection.each do |element| puts element end + +# If the AllowBracesOnProceduralOneLiners option is set to `true`, or +# any other truthy value, then one-line procedural blocks may use +# either style. (There is no setting for requiring braces on them.) + +# good +collection.each { |element| puts element } + +# also good +collection.each do |element| puts element end +---- + +==== EnforcedStyle: braces_for_chaining + +[source,ruby] +---- +# bad +words.each do |word| + word.flip.flop +end.join("-") + +# good +words.each { |word| + word.flip.flop +}.join("-") +---- + +==== EnforcedStyle: always_braces + +[source,ruby] +---- +# bad +words.each do |word| + word.flip.flop +end + +# good +words.each { |word| + word.flip.flop +} +---- + +==== BracesRequiredMethods: ['sig'] + +[source,ruby] +---- +# Methods listed in the BracesRequiredMethods list, such as 'sig' +# in this example, will require `{...}` braces. This option takes +# precedence over all other configurations except IgnoredMethods. + +# bad +sig do + params( + foo: string, + ).void +end +def bar(foo) + puts foo +end + +# good +sig { + params( + foo: string, + ).void +} +def bar(foo) + puts foo +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `line_count_based` +| `line_count_based`, `semantic`, `braces_for_chaining`, `always_braces` + +| ProceduralMethods +| `benchmark`, `bm`, `bmbm`, `create`, `each_with_object`, `measure`, `new`, `realtime`, `tap`, `with_object` +| Array + +| FunctionalMethods +| `let`, `let!`, `subject`, `watch` +| Array + +| IgnoredMethods +| `lambda`, `proc`, `it` +| Array + +| AllowBracesOnProceduralOneLiners +| `false` +| Boolean + +| BracesRequiredMethods +| `[]` +| Array +|=== + +=== References + +* https://rubystyle.guide#single-line-blocks + +== Style/CaseEquality + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.89 +|=== + +This cop checks for uses of the case equality operator(===). + +=== Examples + +[source,ruby] +---- +# bad +Array === something +(1..100) === 7 +/something/ === some_string + +# good +something.is_a?(Array) +(1..100).include?(7) +/something/.match?(some_string) +---- + +==== AllowOnConstant + +[source,ruby] +---- +# Style/CaseEquality: +# AllowOnConstant: true + +# bad +(1..100) === 7 +/something/ === some_string + +# good +Array === something +(1..100).include?(7) +/something/.match?(some_string) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowOnConstant +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#no-case-equality + +== Style/CaseLikeIf + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.88 +| - +|=== + +This cop identifies places where `if-elsif` constructions +can be replaced with `case-when`. + +=== Examples + +[source,ruby] +---- +# bad +if status == :active + perform_action +elsif status == :inactive || status == :hibernating + check_timeout +else + final_action +end + +# good +case status +when :active + perform_action +when :inactive, :hibernating + check_timeout +else + final_action +end +---- + +=== References + +* https://rubystyle.guide#case-vs-if-else + +== Style/CharacterLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| - +|=== + +Checks for uses of the character literal ?x. + +=== Examples + +[source,ruby] +---- +# bad +?x + +# good +'x' + +# good +?\C-\M-d +---- + +=== References + +* https://rubystyle.guide#no-character-literals + +== Style/ClassAndModuleChildren + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes (Unsafe) +| 0.19 +| - +|=== + +This cop checks the style of children definitions at classes and +modules. Basically there are two different styles: + +The compact style is only forced for classes/modules with one child. + +=== Examples + +==== EnforcedStyle: nested (default) + +[source,ruby] +---- +# good +# have each child on its own line +class Foo + class Bar + end +end +---- + +==== EnforcedStyle: compact + +[source,ruby] +---- +# good +# combine definitions as much as possible +class Foo::Bar +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `nested` +| `nested`, `compact` +|=== + +=== References + +* https://rubystyle.guide#namespace-definition + +== Style/ClassCheck + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.24 +| - +|=== + +This cop enforces consistent use of `Object#is_a?` or `Object#kind_of?`. + +=== Examples + +==== EnforcedStyle: is_a? (default) + +[source,ruby] +---- +# bad +var.kind_of?(Date) +var.kind_of?(Integer) + +# good +var.is_a?(Date) +var.is_a?(Integer) +---- + +==== EnforcedStyle: kind_of? + +[source,ruby] +---- +# bad +var.is_a?(Time) +var.is_a?(String) + +# good +var.kind_of?(Time) +var.kind_of?(String) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `is_a?` +| `is_a?`, `kind_of?` +|=== + +=== References + +* https://rubystyle.guide#is-a-vs-kind-of + +== Style/ClassEqualityComparison + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.93 +| - +|=== + +This cop enforces the use of `Object#instance_of?` instead of class comparison +for equality. + +=== Examples + +[source,ruby] +---- +# bad +var.class == Date +var.class.equal?(Date) +var.class.eql?(Date) +var.class.name == 'Date' + +# good +var.instance_of?(Date) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IgnoredMethods +| `==`, `equal?`, `eql?` +| Array +|=== + +=== References + +* https://rubystyle.guide#instance-of-vs-class-comparison + +== Style/ClassMethods + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.20 +|=== + +This cop checks for uses of the class/module name instead of +self, when defining class/module methods. + +=== Examples + +[source,ruby] +---- +# bad +class SomeClass + def SomeClass.class_method + # ... + end +end + +# good +class SomeClass + def self.class_method + # ... + end +end +---- + +=== References + +* https://rubystyle.guide#def-self-class-methods + +== Style/ClassMethodsDefinitions + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.89 +| - +|=== + +This cop enforces using `def self.method_name` or `class << self` to define class methods. + +=== Examples + +==== EnforcedStyle: def_self (default) + +[source,ruby] +---- +# bad +class SomeClass + class << self + attr_accessor :class_accessor + + def class_method + # ... + end + end +end + +# good +class SomeClass + def self.class_method + # ... + end + + class << self + attr_accessor :class_accessor + end +end + +# good - contains private method +class SomeClass + class << self + attr_accessor :class_accessor + + private + + def private_class_method + # ... + end + end +end +---- + +==== EnforcedStyle: self_class + +[source,ruby] +---- +# bad +class SomeClass + def self.class_method + # ... + end +end + +# good +class SomeClass + class << self + def class_method + # ... + end + end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `def_self` +| `def_self`, `self_class` +|=== + +=== References + +* https://rubystyle.guide#def-self-class-methods + +== Style/ClassVars + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.13 +| - +|=== + +This cop checks for uses of class variables. Offenses +are signaled only on assignment to class variables to +reduce the number of offenses that would be reported. + +You have to be careful when setting a value for a class +variable; if a class has been inherited, changing the +value of a class variable also affects the inheriting +classes. This means that it's almost always better to +use a class instance variable instead. + +=== Examples + +[source,ruby] +---- +# bad +class A + @@test = 10 +end + +class A + def self.test(name, value) + class_variable_set("@@#{name}", value) + end +end + +class A; end +A.class_variable_set(:@@test, 10) + +# good +class A + @test = 10 +end + +class A + def test + @@test # you can access class variable without offense + end +end + +class A + def self.test(name) + class_variable_get("@@#{name}") # you can access without offense + end +end +---- + +=== References + +* https://rubystyle.guide#no-class-vars + +== Style/CollectionMethods + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| No +| Yes (Unsafe) +| 0.9 +| 0.27 +|=== + +This cop enforces the use of consistent method names +from the Enumerable module. + +Unfortunately we cannot actually know if a method is from +Enumerable or not (static analysis limitation), so this cop +can yield some false positives. + +You can customize the mapping from undesired method to desired method. + +e.g. to use `detect` over `find`: + + Style/CollectionMethods: + PreferredMethods: + find: detect + +The default mapping for `PreferredMethods` behaves as follows. + +=== Examples + +[source,ruby] +---- +# bad +items.collect +items.collect! +items.inject +items.detect +items.find_all +items.member? + +# good +items.map +items.map! +items.reduce +items.find +items.select +items.include? +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| PreferredMethods +| `{"collect"=>"map", "collect!"=>"map!", "inject"=>"reduce", "detect"=>"find", "find_all"=>"select", "member?"=>"include?"}` +| +|=== + +=== References + +* https://rubystyle.guide#map-find-select-reduce-include-size + +== Style/ColonMethodCall + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| - +|=== + +This cop checks for methods invoked via the :: operator instead +of the . operator (like FileUtils::rmdir instead of FileUtils.rmdir). + +=== Examples + +[source,ruby] +---- +# bad +Timeout::timeout(500) { do_something } +FileUtils::rmdir(dir) +Marshal::dump(obj) + +# good +Timeout.timeout(500) { do_something } +FileUtils.rmdir(dir) +Marshal.dump(obj) +---- + +=== References + +* https://rubystyle.guide#double-colons + +== Style/ColonMethodDefinition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| - +|=== + +This cop checks for class methods that are defined using the `::` +operator instead of the `.` operator. + +=== Examples + +[source,ruby] +---- +# bad +class Foo + def self::bar + end +end + +# good +class Foo + def self.bar + end +end +---- + +=== References + +* https://rubystyle.guide#colon-method-definition + +== Style/CombinableLoops + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| No +| 0.90 +| - +|=== + +This cop checks for places where multiple consecutive loops over the same data +can be combined into a single loop. It is very likely that combining them +will make the code more efficient and more concise. + +It is marked as unsafe, because the first loop might modify +a state that the second loop depends on; these two aren't combinable. + +=== Examples + +[source,ruby] +---- +# bad +def method + items.each do |item| + do_something(item) + end + + items.each do |item| + do_something_else(item) + end +end + +# good +def method + items.each do |item| + do_something(item) + do_something_else(item) + end +end + +# bad +def method + for item in items do + do_something(item) + end + + for item in items do + do_something_else(item) + end +end + +# good +def method + for item in items do + do_something(item) + do_something_else(item) + end +end + +# good +def method + each_slice(2) { |slice| do_something(slice) } + each_slice(3) { |slice| do_something(slice) } +end +---- + +== Style/CommandLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.30 +| - +|=== + +This cop enforces using `` or %x around command literals. + +=== Examples + +==== EnforcedStyle: backticks (default) + +[source,ruby] +---- +# bad +folders = %x(find . -type d).split + +# bad +%x( + ln -s foo.example.yml foo.example + ln -s bar.example.yml bar.example +) + +# good +folders = `find . -type d`.split + +# good +` + ln -s foo.example.yml foo.example + ln -s bar.example.yml bar.example +` +---- + +==== EnforcedStyle: mixed + +[source,ruby] +---- +# bad +folders = %x(find . -type d).split + +# bad +` + ln -s foo.example.yml foo.example + ln -s bar.example.yml bar.example +` + +# good +folders = `find . -type d`.split + +# good +%x( + ln -s foo.example.yml foo.example + ln -s bar.example.yml bar.example +) +---- + +==== EnforcedStyle: percent_x + +[source,ruby] +---- +# bad +folders = `find . -type d`.split + +# bad +` + ln -s foo.example.yml foo.example + ln -s bar.example.yml bar.example +` + +# good +folders = %x(find . -type d).split + +# good +%x( + ln -s foo.example.yml foo.example + ln -s bar.example.yml bar.example +) +---- + +==== AllowInnerBackticks: false (default) + +[source,ruby] +---- +# If `false`, the cop will always recommend using `%x` if one or more +# backticks are found in the command string. + +# bad +`echo \`ls\`` + +# good +%x(echo `ls`) +---- + +==== AllowInnerBackticks: true + +[source,ruby] +---- +# good +`echo \`ls\`` +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `backticks` +| `backticks`, `percent_x`, `mixed` + +| AllowInnerBackticks +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#percent-x + +== Style/CommentAnnotation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.10 +| 0.31 +|=== + +This cop checks that comment annotation keywords are written according +to guidelines. + +NOTE: With a multiline comment block (where each line is only a +comment), only the first line will be able to register an offense, even +if an annotation keyword starts another line. This is done to prevent +incorrect registering of keywords (eg. `review`) inside a paragraph as an +annotation. + +=== Examples + +[source,ruby] +---- +# bad +# TODO make better + +# good +# TODO: make better + +# bad +# TODO:make better + +# good +# TODO: make better + +# bad +# fixme: does not work + +# good +# FIXME: does not work + +# bad +# Optimize does not work + +# good +# OPTIMIZE: does not work +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Keywords +| `TODO`, `FIXME`, `OPTIMIZE`, `HACK`, `REVIEW` +| Array +|=== + +=== References + +* https://rubystyle.guide#annotate-keywords + +== Style/CommentedKeyword + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.51 +| - +|=== + +This cop checks for comments put on the same line as some keywords. +These keywords are: `begin`, `class`, `def`, `end`, `module`. + +Note that some comments +(`:nodoc:`, `:yields:`, `rubocop:disable` and `rubocop:todo`) +are allowed. + +=== Examples + +[source,ruby] +---- +# bad +if condition + statement +end # end if + +# bad +class X # comment + statement +end + +# bad +def x; end # comment + +# good +if condition + statement +end + +# good +class X # :nodoc: + y +end +---- + +== Style/ConditionalAssignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.36 +| 0.47 +|=== + +Check for `if` and `case` statements where each branch is used for +assignment to the same variable when using the return of the +condition can be used instead. + +=== Examples + +==== EnforcedStyle: assign_to_condition (default) + +[source,ruby] +---- +# bad +if foo + bar = 1 +else + bar = 2 +end + +case foo +when 'a' + bar += 1 +else + bar += 2 +end + +if foo + some_method + bar = 1 +else + some_other_method + bar = 2 +end + +# good +bar = if foo + 1 + else + 2 + end + +bar += case foo + when 'a' + 1 + else + 2 + end + +bar << if foo + some_method + 1 + else + some_other_method + 2 + end +---- + +==== EnforcedStyle: assign_inside_condition + +[source,ruby] +---- +# bad +bar = if foo + 1 + else + 2 + end + +bar += case foo + when 'a' + 1 + else + 2 + end + +bar << if foo + some_method + 1 + else + some_other_method + 2 + end + +# good +if foo + bar = 1 +else + bar = 2 +end + +case foo +when 'a' + bar += 1 +else + bar += 2 +end + +if foo + some_method + bar = 1 +else + some_other_method + bar = 2 +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `assign_to_condition` +| `assign_to_condition`, `assign_inside_condition` + +| SingleLineConditionsOnly +| `true` +| Boolean + +| IncludeTernaryExpressions +| `true` +| Boolean +|=== + +== Style/ConstantVisibility + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.66 +| - +|=== + +This cop checks that constants defined in classes and modules have +an explicit visibility declaration. By default, Ruby makes all class- +and module constants public, which litters the public API of the +class or module. Explicitly declaring a visibility makes intent more +clear, and prevents outside actors from touching private state. + +=== Examples + +[source,ruby] +---- +# bad +class Foo + BAR = 42 + BAZ = 43 +end + +# good +class Foo + BAR = 42 + private_constant :BAR + + BAZ = 43 + public_constant :BAZ +end +---- + +== Style/Copyright + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.30 +| - +|=== + +Check that a copyright notice was given in each source file. + +The default regexp for an acceptable copyright notice can be found in +config/default.yml. The default can be changed as follows: + + Style/Copyright: + Notice: '^Copyright (\(c\) )?2\d{3} Acme Inc' + +This regex string is treated as an unanchored regex. For each file +that RuboCop scans, a comment that matches this regex must be found or +an offense is reported. + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Notice +| `^Copyright (\(c\) )?2[0-9]{3} .+` +| String + +| AutocorrectNotice +| `` +| String +|=== + +== Style/DateTime + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes (Unsafe) +| 0.51 +| 0.92 +|=== + +This cop checks for consistent usage of the `DateTime` class over the +`Time` class. This cop is disabled by default since these classes, +although highly overlapping, have particularities that make them not +replaceable in certain situations when dealing with multiple timezones +and/or DST. + +=== Examples + +[source,ruby] +---- +# bad - uses `DateTime` for current time +DateTime.now + +# good - uses `Time` for current time +Time.now + +# bad - uses `DateTime` for modern date +DateTime.iso8601('2016-06-29') + +# good - uses `Time` for modern date +Time.iso8601('2016-06-29') + +# good - uses `DateTime` with start argument for historical date +DateTime.iso8601('1751-04-23', Date::ENGLAND) +---- + +==== AllowCoercion: false (default) + +[source,ruby] +---- +# bad - coerces to `DateTime` +something.to_datetime + +# good - coerces to `Time` +something.to_time +---- + +==== AllowCoercion: true + +[source,ruby] +---- +# good +something.to_datetime + +# good +something.to_time +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowCoercion +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#date--time + +== Style/DefWithParentheses + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.12 +|=== + +This cop checks for parentheses in the definition of a method, +that does not take any arguments. Both instance and +class/singleton methods are checked. + +=== Examples + +[source,ruby] +---- +# bad +def foo() + # does a thing +end + +# good +def foo + # does a thing +end + +# also good +def foo() does_a_thing end +---- + +[source,ruby] +---- +# bad +def Baz.foo() + # does a thing +end + +# good +def Baz.foo + # does a thing +end +---- + +=== References + +* https://rubystyle.guide#method-parens + +== Style/Dir + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.50 +| - +|=== + +This cop checks for places where the `#__dir__` method can replace more +complex constructs to retrieve a canonicalized absolute path to the +current file. + +=== Examples + +[source,ruby] +---- +# bad +path = File.expand_path(File.dirname(__FILE__)) + +# bad +path = File.dirname(File.realpath(__FILE__)) + +# good +path = __dir__ +---- + +== Style/DisableCopsWithinSourceCodeDirective + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.82 +| - +|=== + +Detects comments to enable/disable RuboCop. +This is useful if want to make sure that every RuboCop error gets fixed +and not quickly disabled with a comment. + +=== Examples + +[source,ruby] +---- +# bad +# rubocop:disable Metrics/AbcSize +def f +end +# rubocop:enable Metrics/AbcSize + +# good +def fixed_method_name_and_no_rubocop_comments +end +---- + +== Style/Documentation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.9 +| - +|=== + +This cop checks for missing top-level documentation of classes and +modules. Classes with no body are exempt from the check and so are +namespace modules - modules that have nothing in their bodies except +classes, other modules, constant definitions or constant visibility +declarations. + +The documentation requirement is annulled if the class or module has +a "#:nodoc:" comment next to it. Likewise, "#:nodoc: all" does the +same for all its children. + +=== Examples + +[source,ruby] +---- +# bad +class Person + # ... +end + +module Math +end + +# good +# Description/Explanation of Person class +class Person + # ... +end + +# allowed + # Class without body + class Person + end + + # Namespace - A namespace can be a class or a module + # Containing a class + module Namespace + # Description/Explanation of Person class + class Person + # ... + end + end + + # Containing constant visibility declaration + module Namespace + class Private + end + + private_constant :Private + end + + # Containing constant definition + module Namespace + Public = Class.new + end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Exclude +| `spec/**/*`, `test/**/*` +| Array +|=== + +== Style/DocumentationMethod + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.43 +| - +|=== + +This cop checks for missing documentation comment for public methods. +It can optionally be configured to also require documentation for +non-public methods. + +=== Examples + +[source,ruby] +---- +# bad + +class Foo + def bar + puts baz + end +end + +module Foo + def bar + puts baz + end +end + +def foo.bar + puts baz +end + +# good + +class Foo + # Documentation + def bar + puts baz + end +end + +module Foo + # Documentation + def bar + puts baz + end +end + +# Documentation +def foo.bar + puts baz +end +---- + +==== RequireForNonPublicMethods: false (default) + +[source,ruby] +---- +# good +class Foo + protected + def do_something + end +end + +class Foo + private + def do_something + end +end +---- + +==== RequireForNonPublicMethods: true + +[source,ruby] +---- +# bad +class Foo + protected + def do_something + end +end + +class Foo + private + def do_something + end +end + +# good +class Foo + protected + # Documentation + def do_something + end +end + +class Foo + private + # Documentation + def do_something + end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Exclude +| `spec/**/*`, `test/**/*` +| Array + +| RequireForNonPublicMethods +| `false` +| Boolean +|=== + +== Style/DoubleCopDisableDirective + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.73 +| - +|=== + +Detects double disable comments on one line. This is mostly to catch +automatically generated comments that need to be regenerated. + +=== Examples + +[source,ruby] +---- +# bad +def f # rubocop:disable Style/For # rubocop:disable Metrics/AbcSize +end + +# good +# rubocop:disable Metrics/AbcSize +def f # rubocop:disable Style/For +end +# rubocop:enable Metrics/AbcSize + +# if both fit on one line +def f # rubocop:disable Style/For, Metrics/AbcSize +end +---- + +== Style/DoubleNegation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.19 +| 0.84 +|=== + +This cop checks for uses of double negation (`!!`) to convert something to a boolean value. + +When using `EnforcedStyle: allowed_in_returns`, allow double nagation in contexts +that use boolean as a return value. When using `EnforcedStyle: forbidden`, double nagation +should be forbidden always. + +Please, note that when something is a boolean value +!!something and !something.nil? are not the same thing. +As you're unlikely to write code that can accept values of any type +this is rarely a problem in practice. + +=== Examples + +[source,ruby] +---- +# bad +!!something + +# good +!something.nil? +---- + +==== EnforcedStyle: allowed_in_returns (default) + +[source,ruby] +---- +# good +def foo? + !!return_value +end +---- + +==== EnforcedStyle: forbidden + +[source,ruby] +---- +# bad +def foo? + !!return_value +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `allowed_in_returns` +| `allowed_in_returns`, `forbidden` +|=== + +=== References + +* https://rubystyle.guide#no-bang-bang + +== Style/EachForSimpleLoop + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.41 +| - +|=== + +This cop checks for loops which iterate a constant number of times, +using a Range literal and `#each`. This can be done more readably using +`Integer#times`. + +This check only applies if the block takes no parameters. + +=== Examples + +[source,ruby] +---- +# bad +(1..5).each { } + +# good +5.times { } +---- + +[source,ruby] +---- +# bad +(0...10).each {} + +# good +10.times {} +---- + +== Style/EachWithObject + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.22 +| 0.42 +|=== + +This cop looks for inject / reduce calls where the passed in object is +returned at the end and so could be replaced by each_with_object without +the need to return the object at the end. + +However, we can't replace with each_with_object if the accumulator +parameter is assigned to within the block. + +=== Examples + +[source,ruby] +---- +# bad +[1, 2].inject({}) { |a, e| a[e] = e; a } + +# good +[1, 2].each_with_object({}) { |e, a| a[e] = e } +---- + +== Style/EmptyBlockParameter + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| - +|=== + +This cop checks for pipes for empty block parameters. Pipes for empty +block parameters do not cause syntax errors, but they are redundant. + +=== Examples + +[source,ruby] +---- +# bad +a do || + do_something +end + +# bad +a { || do_something } + +# good +a do +end + +# good +a { do_something } +---- + +== Style/EmptyCaseCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.40 +| - +|=== + +This cop checks for case statements with an empty condition. + +=== Examples + +[source,ruby] +---- +# bad: +case +when x == 0 + puts 'x is 0' +when y == 0 + puts 'y is 0' +else + puts 'neither is 0' +end + +# good: +if x == 0 + puts 'x is 0' +elsif y == 0 + puts 'y is 0' +else + puts 'neither is 0' +end + +# good: (the case condition node is not empty) +case n +when 0 + puts 'zero' +when 1 + puts 'one' +else + puts 'more' +end +---- + +== Style/EmptyElse + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.28 +| 0.32 +|=== + +Checks for empty else-clauses, possibly including comments and/or an +explicit `nil` depending on the EnforcedStyle. + +=== Examples + +==== EnforcedStyle: empty + +[source,ruby] +---- +# warn only on empty else + +# bad +if condition + statement +else +end + +# good +if condition + statement +else + nil +end + +# good +if condition + statement +else + statement +end + +# good +if condition + statement +end +---- + +==== EnforcedStyle: nil + +[source,ruby] +---- +# warn on else with nil in it + +# bad +if condition + statement +else + nil +end + +# good +if condition + statement +else +end + +# good +if condition + statement +else + statement +end + +# good +if condition + statement +end +---- + +==== EnforcedStyle: both (default) + +[source,ruby] +---- +# warn on empty else and else with nil in it + +# bad +if condition + statement +else + nil +end + +# bad +if condition + statement +else +end + +# good +if condition + statement +else + statement +end + +# good +if condition + statement +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `both` +| `empty`, `nil`, `both` +|=== + +== Style/EmptyLambdaParameter + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| - +|=== + +This cop checks for parentheses for empty lambda parameters. Parentheses +for empty lambda parameters do not cause syntax errors, but they are +redundant. + +=== Examples + +[source,ruby] +---- +# bad +-> () { do_something } + +# good +-> { do_something } + +# good +-> (arg) { do_something(arg) } +---- + +== Style/EmptyLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.12 +|=== + +This cop checks for the use of a method, the result of which +would be a literal, like an empty array, hash, or string. + +=== Examples + +[source,ruby] +---- +# bad +a = Array.new +h = Hash.new +s = String.new + +# good +a = [] +h = {} +s = '' +---- + +=== References + +* https://rubystyle.guide#literal-array-hash + +== Style/EmptyMethod + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.46 +| - +|=== + +This cop checks for the formatting of empty method definitions. +By default it enforces empty method definitions to go on a single +line (compact style), but it can be configured to enforce the `end` +to go on its own line (expanded style). + +NOTE: A method definition is not considered empty if it contains + comments. + +=== Examples + +==== EnforcedStyle: compact (default) + +[source,ruby] +---- +# bad +def foo(bar) +end + +def self.foo(bar) +end + +# good +def foo(bar); end + +def foo(bar) + # baz +end + +def self.foo(bar); end +---- + +==== EnforcedStyle: expanded + +[source,ruby] +---- +# bad +def foo(bar); end + +def self.foo(bar); end + +# good +def foo(bar) +end + +def self.foo(bar) +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `compact` +| `compact`, `expanded` +|=== + +=== References + +* https://rubystyle.guide#no-single-line-methods + +== Style/Encoding + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.50 +|=== + +This cop checks ensures source files have no utf-8 encoding comments. + +=== Examples + +[source,ruby] +---- +# bad +# encoding: UTF-8 +# coding: UTF-8 +# -*- coding: UTF-8 -*- +---- + +=== References + +* https://rubystyle.guide#utf-8 + +== Style/EndBlock + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.81 +|=== + +This cop checks for END blocks. + +=== Examples + +[source,ruby] +---- +# bad +END { puts 'Goodbye!' } + +# good +at_exit { puts 'Goodbye!' } +---- + +=== References + +* https://rubystyle.guide#no-END-blocks + +== Style/EvalWithLocation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.52 +| - +|=== + +This cop checks `eval` method usage. `eval` can receive source location +metadata, that are filename and line number. The metadata is used by +backtraces. This cop recommends to pass the metadata to `eval` method. + +=== Examples + +[source,ruby] +---- +# bad +eval <<-RUBY + def do_something + end +RUBY + +# bad +C.class_eval <<-RUBY + def do_something + end +RUBY + +# good +eval <<-RUBY, binding, __FILE__, __LINE__ + 1 + def do_something + end +RUBY + +# good +C.class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def do_something + end +RUBY +---- + +== Style/EvenOdd + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.12 +| 0.29 +|=== + +This cop checks for places where `Integer#even?` or `Integer#odd?` +can be used. + +=== Examples + +[source,ruby] +---- +# bad +if x % 2 == 0 +end + +# good +if x.even? +end +---- + +=== References + +* https://rubystyle.guide#predicate-methods + +== Style/ExpandPathArguments + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +This cop checks for use of the `File.expand_path` arguments. +Likewise, it also checks for the `Pathname.new` argument. + +Contrastive bad case and good case are alternately shown in +the following examples. + +=== Examples + +[source,ruby] +---- +# bad +File.expand_path('..', __FILE__) + +# good +File.expand_path(__dir__) + +# bad +File.expand_path('../..', __FILE__) + +# good +File.expand_path('..', __dir__) + +# bad +File.expand_path('.', __FILE__) + +# good +File.expand_path(__FILE__) + +# bad +Pathname(__FILE__).parent.expand_path + +# good +Pathname(__dir__).expand_path + +# bad +Pathname.new(__FILE__).parent.expand_path + +# good +Pathname.new(__dir__).expand_path +---- + +== Style/ExplicitBlockArgument + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.89 +| - +|=== + +This cop enforces the use of explicit block argument to avoid writing +block literal that just passes its arguments to another block. + +=== Examples + +[source,ruby] +---- +# bad +def with_tmp_dir + Dir.mktmpdir do |tmp_dir| + Dir.chdir(tmp_dir) { |dir| yield dir } # block just passes arguments + end +end + +# bad +def nine_times + 9.times { yield } +end + +# good +def with_tmp_dir(&block) + Dir.mktmpdir do |tmp_dir| + Dir.chdir(tmp_dir, &block) + end +end + +with_tmp_dir do |dir| + puts "dir is accessible as a parameter and pwd is set: #{dir}" +end + +# good +def nine_times(&block) + 9.times(&block) +end +---- + +=== References + +* https://rubystyle.guide#block-argument + +== Style/ExponentialNotation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.82 +| - +|=== + +This cop enforces consistency when using exponential notation +for numbers in the code (eg 1.2e4). Different styles are supported: +* `scientific` which enforces a mantissa between 1 (inclusive) + and 10 (exclusive). +* `engineering` which enforces the exponent to be a multiple of 3 + and the mantissa to be between 0.1 (inclusive) + and 10 (exclusive). +* `integral` which enforces the mantissa to always be a whole number + without trailing zeroes. + +=== Examples + +==== EnforcedStyle: scientific (default) + +[source,ruby] +---- +# Enforces a mantissa between 1 (inclusive) and 10 (exclusive). + +# bad +10e6 +0.3e4 +11.7e5 +3.14e0 + +# good +1e7 +3e3 +1.17e6 +3.14 +---- + +==== EnforcedStyle: engineering + +[source,ruby] +---- +# Enforces using multiple of 3 exponents, +# mantissa should be between 0.1 (inclusive) and 1000 (exclusive) + +# bad +3.2e7 +0.1e5 +12e5 +1232e6 + +# good +32e6 +10e3 +1.2e6 +1.232e9 +---- + +==== EnforcedStyle: integral + +[source,ruby] +---- +# Enforces the mantissa to have no decimal part and no +# trailing zeroes. + +# bad +3.2e7 +0.1e5 +120e4 + +# good +32e6 +1e4 +12e5 +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `scientific` +| `scientific`, `engineering`, `integral` +|=== + +=== References + +* https://rubystyle.guide#exponential-notation + +== Style/FloatDivision + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.72 +| - +|=== + +This cop checks for division with integers coerced to floats. +It is recommended to either always use `fdiv` or coerce one side only. +This cop also provides other options for code consistency. + +=== Examples + +==== EnforcedStyle: single_coerce (default) + +[source,ruby] +---- +# bad +a.to_f / b.to_f + +# good +a.to_f / b +a / b.to_f +---- + +==== EnforcedStyle: left_coerce + +[source,ruby] +---- +# bad +a / b.to_f +a.to_f / b.to_f + +# good +a.to_f / b +---- + +==== EnforcedStyle: right_coerce + +[source,ruby] +---- +# bad +a.to_f / b +a.to_f / b.to_f + +# good +a / b.to_f +---- + +==== EnforcedStyle: fdiv + +[source,ruby] +---- +# bad +a / b.to_f +a.to_f / b +a.to_f / b.to_f + +# good +a.fdiv(b) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `single_coerce` +| `left_coerce`, `right_coerce`, `single_coerce`, `fdiv` +|=== + +=== References + +* https://rubystyle.guide#float-division +* https://github.com/rubocop-hq/ruby-style-guide/issues/628 + +== Style/For + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.13 +| 0.59 +|=== + +This cop looks for uses of the `for` keyword or `each` method. The +preferred alternative is set in the EnforcedStyle configuration +parameter. An `each` call with a block on a single line is always +allowed. + +=== Examples + +==== EnforcedStyle: each (default) + +[source,ruby] +---- +# bad +def foo + for n in [1, 2, 3] do + puts n + end +end + +# good +def foo + [1, 2, 3].each do |n| + puts n + end +end +---- + +==== EnforcedStyle: for + +[source,ruby] +---- +# bad +def foo + [1, 2, 3].each do |n| + puts n + end +end + +# good +def foo + for n in [1, 2, 3] do + puts n + end +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `each` +| `each`, `for` +|=== + +=== References + +* https://rubystyle.guide#no-for-loops + +== Style/FormatString + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.19 +| 0.49 +|=== + +This cop enforces the use of a single string formatting utility. +Valid options include Kernel#format, Kernel#sprintf and String#%. + +The detection of String#% cannot be implemented in a reliable +manner for all cases, so only two scenarios are considered - +if the first argument is a string literal and if the second +argument is an array literal. + +=== Examples + +==== EnforcedStyle: format (default) + +[source,ruby] +---- +# bad +puts sprintf('%10s', 'hoge') +puts '%10s' % 'hoge' + +# good +puts format('%10s', 'hoge') +---- + +==== EnforcedStyle: sprintf + +[source,ruby] +---- +# bad +puts format('%10s', 'hoge') +puts '%10s' % 'hoge' + +# good +puts sprintf('%10s', 'hoge') +---- + +==== EnforcedStyle: percent + +[source,ruby] +---- +# bad +puts format('%10s', 'hoge') +puts sprintf('%10s', 'hoge') + +# good +puts '%10s' % 'hoge' +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `format` +| `format`, `sprintf`, `percent` +|=== + +=== References + +* https://rubystyle.guide#sprintf + +== Style/FormatStringToken + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.49 +| 0.75 +|=== + +Use a consistent style for named format string tokens. + +NOTE: `unannotated` style cop only works for strings +which are passed as arguments to those methods: +`printf`, `sprintf`, `format`, `%`. +The reason is that _unannotated_ format is very similar +to encoded URLs or Date/Time formatting strings. + +=== Examples + +==== EnforcedStyle: annotated (default) + +[source,ruby] +---- +# bad +format('%{greeting}', greeting: 'Hello') +format('%s', 'Hello') + +# good +format('%s', greeting: 'Hello') +---- + +==== EnforcedStyle: template + +[source,ruby] +---- +# bad +format('%s', greeting: 'Hello') +format('%s', 'Hello') + +# good +format('%{greeting}', greeting: 'Hello') +---- + +==== EnforcedStyle: unannotated + +[source,ruby] +---- +# bad +format('%s', greeting: 'Hello') +format('%{greeting}', greeting: 'Hello') + +# good +format('%s', 'Hello') +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `annotated` +| `annotated`, `template`, `unannotated` +|=== + +== Style/FrozenStringLiteralComment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes (Unsafe) +| 0.36 +| 0.79 +|=== + +This cop is designed to help you transition from mutable string literals +to frozen string literals. +It will add the comment `# frozen_string_literal: true` to the top of +files to enable frozen string literals. Frozen string literals may be +default in future Ruby. The comment will be added below a shebang and +encoding comment. + +Note that the cop will ignore files where the comment exists but is set +to `false` instead of `true`. + +=== Examples + +==== EnforcedStyle: always (default) + +[source,ruby] +---- +# The `always` style will always add the frozen string literal comment +# to a file, regardless of the Ruby version or if `freeze` or `<<` are +# called on a string literal. +# bad +module Bar + # ... +end + +# good +# frozen_string_literal: true + +module Bar + # ... +end + +# good +# frozen_string_literal: false + +module Bar + # ... +end +---- + +==== EnforcedStyle: never + +[source,ruby] +---- +# The `never` will enforce that the frozen string literal comment does +# not exist in a file. +# bad +# frozen_string_literal: true + +module Baz + # ... +end + +# good +module Baz + # ... +end +---- + +==== EnforcedStyle: always_true + +[source,ruby] +---- +# The `always_true` style enforces that the frozen string literal +# comment is set to `true`. This is a stricter option than `always` +# and forces projects to use frozen string literals. +# bad +# frozen_string_literal: false + +module Baz + # ... +end + +# bad +module Baz + # ... +end + +# good +# frozen_string_literal: true + +module Bar + # ... +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `always` +| `always`, `always_true`, `never` +|=== + +== Style/GlobalStdStream + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes (Unsafe) +| 0.89 +| - +|=== + +This cop enforces the use of `$stdout/$stderr/$stdin` instead of `STDOUT/STDERR/STDIN`. +`STDOUT/STDERR/STDIN` are constants, and while you can actually +reassign (possibly to redirect some stream) constants in Ruby, you'll get +an interpreter warning if you do so. + +=== Examples + +[source,ruby] +---- +# bad +STDOUT.puts('hello') + +hash = { out: STDOUT, key: value } + +def m(out = STDOUT) + out.puts('hello') +end + +# good +$stdout.puts('hello') + +hash = { out: $stdout, key: value } + +def m(out = $stdout) + out.puts('hello') +end +---- + +=== References + +* https://rubystyle.guide#global-stdout + +== Style/GlobalVars + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.13 +| - +|=== + +This cop looks for uses of global variables. +It does not report offenses for built-in global variables. +Built-in global variables are allowed by default. Additionally +users can allow additional variables via the AllowedVariables option. + +Note that backreferences like $1, $2, etc are not global variables. + +=== Examples + +[source,ruby] +---- +# bad +$foo = 2 +bar = $foo + 5 + +# good +FOO = 2 +foo = 2 +$stdin.read +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedVariables +| `[]` +| Array +|=== + +=== References + +* https://rubystyle.guide#instance-vars +* https://www.zenspider.com/ruby/quickref.html + +== Style/GuardClause + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.20 +| 0.22 +|=== + +Use a guard clause instead of wrapping the code inside a conditional +expression + +=== Examples + +[source,ruby] +---- +# bad +def test + if something + work + end +end + +# good +def test + return unless something + + work +end + +# also good +def test + work if something +end + +# bad +if something + raise 'exception' +else + ok +end + +# good +raise 'exception' if something +ok + +# bad +if something + foo || raise('exception') +else + ok +end + +# good +foo || raise('exception') if something +ok +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| MinBodyLength +| `1` +| Integer +|=== + +=== References + +* https://rubystyle.guide#no-nested-conditionals + +== Style/HashAsLastArrayItem + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.88 +| - +|=== + +Checks for presence or absence of braces around hash literal as a last +array item depending on configuration. + +NOTE: This cop will ignore arrays where all items are hashes, regardless of +EnforcedStyle. + +=== Examples + +==== EnforcedStyle: braces (default) + +[source,ruby] +---- +# bad +[1, 2, one: 1, two: 2] + +# good +[1, 2, { one: 1, two: 2 }] + +# good +[{ one: 1 }, { two: 2 }] +---- + +==== EnforcedStyle: no_braces + +[source,ruby] +---- +# bad +[1, 2, { one: 1, two: 2 }] + +# good +[1, 2, one: 1, two: 2] + +# good +[{ one: 1 }, { two: 2 }] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `braces` +| `braces`, `no_braces` +|=== + +=== References + +* https://rubystyle.guide#hash-literal-as-last-array-item + +== Style/HashEachMethods + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.80 +| - +|=== + +This cop checks for uses of `each_key` and `each_value` Hash methods. + +NOTE: If you have an array of two-element arrays, you can put + parentheses around the block arguments to indicate that you're not + working with a hash, and suppress RuboCop offenses. + +=== Examples + +[source,ruby] +---- +# bad +hash.keys.each { |k| p k } +hash.values.each { |v| p v } + +# good +hash.each_key { |k| p k } +hash.each_value { |v| p v } +---- + +=== References + +* https://rubystyle.guide#hash-each + +== Style/HashLikeCase + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.88 +| - +|=== + +This cop checks for places where `case-when` represents a simple 1:1 +mapping and can be replaced with a hash lookup. + +=== Examples + +==== MinBranchesCount: 3 (default) + +[source,ruby] +---- +# bad +case country +when 'europe' + 'http://eu.example.com' +when 'america' + 'http://us.example.com' +when 'australia' + 'http://au.example.com' +end + +# good +SITES = { + 'europe' => 'http://eu.example.com', + 'america' => 'http://us.example.com', + 'australia' => 'http://au.example.com' +} +SITES[country] +---- + +==== MinBranchesCount: 4 + +[source,ruby] +---- +# good +case country +when 'europe' + 'http://eu.example.com' +when 'america' + 'http://us.example.com' +when 'australia' + 'http://au.example.com' +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| MinBranchesCount +| `3` +| Integer +|=== + +== Style/HashSyntax + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.43 +|=== + +This cop checks hash literal syntax. + +It can enforce either the use of the class hash rocket syntax or +the use of the newer Ruby 1.9 syntax (when applicable). + +A separate offense is registered for each problematic pair. + +The supported styles are: + +* ruby19 - forces use of the 1.9 syntax (e.g. `{a: 1}`) when hashes have +all symbols for keys +* hash_rockets - forces use of hash rockets for all hashes +* no_mixed_keys - simply checks for hashes with mixed syntaxes +* ruby19_no_mixed_keys - forces use of ruby 1.9 syntax and forbids mixed +syntax hashes + +=== Examples + +==== EnforcedStyle: ruby19 (default) + +[source,ruby] +---- +# bad +{:a => 2} +{b: 1, :c => 2} + +# good +{a: 2, b: 1} +{:c => 2, 'd' => 2} # acceptable since 'd' isn't a symbol +{d: 1, 'e' => 2} # technically not forbidden +---- + +==== EnforcedStyle: hash_rockets + +[source,ruby] +---- +# bad +{a: 1, b: 2} +{c: 1, 'd' => 5} + +# good +{:a => 1, :b => 2} +---- + +==== EnforcedStyle: no_mixed_keys + +[source,ruby] +---- +# bad +{:a => 1, b: 2} +{c: 1, 'd' => 2} + +# good +{:a => 1, :b => 2} +{c: 1, d: 2} +---- + +==== EnforcedStyle: ruby19_no_mixed_keys + +[source,ruby] +---- +# bad +{:a => 1, :b => 2} +{c: 2, 'd' => 3} # should just use hash rockets + +# good +{a: 1, b: 2} +{:c => 3, 'd' => 4} +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `ruby19` +| `ruby19`, `hash_rockets`, `no_mixed_keys`, `ruby19_no_mixed_keys` + +| UseHashRocketsWithSymbolValues +| `false` +| Boolean + +| PreferHashRocketsForNonAlnumEndingSymbols +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#hash-literals + +== Style/HashTransformKeys + +NOTE: Required Ruby version: 2.5 + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.80 +| 0.90 +|=== + +This cop looks for uses of `_.each_with_object({}) {...}`, +`_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just +transforming the keys of a hash, and tries to use a simpler & faster +call to `transform_keys` instead. + +This can produce false positives if we are transforming an enumerable +of key-value-like pairs that isn't actually a hash, e.g.: +`[[k1, v1], [k2, v2], ...]` + +This cop should only be enabled on Ruby version 2.5 or newer +(`transform_keys` was added in Ruby 2.5.) + +=== Examples + +[source,ruby] +---- +# bad +{a: 1, b: 2}.each_with_object({}) { |(k, v), h| h[foo(k)] = v } +Hash[{a: 1, b: 2}.collect { |k, v| [foo(k), v] }] +{a: 1, b: 2}.map { |k, v| [k.to_s, v] }.to_h +{a: 1, b: 2}.to_h { |k, v| [k.to_s, v] } + +# good +{a: 1, b: 2}.transform_keys { |k| foo(k) } +{a: 1, b: 2}.transform_keys { |k| k.to_s } +---- + +== Style/HashTransformValues + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.80 +| 0.90 +|=== + +This cop looks for uses of `_.each_with_object({}) {...}`, +`_.map {...}.to_h`, and `Hash[_.map {...}]` that are actually just +transforming the values of a hash, and tries to use a simpler & faster +call to `transform_values` instead. + +This can produce false positives if we are transforming an enumerable +of key-value-like pairs that isn't actually a hash, e.g.: +`[[k1, v1], [k2, v2], ...]` + +This cop should only be enabled on Ruby version 2.4 or newer +(`transform_values` was added in Ruby 2.4.) + +=== Examples + +[source,ruby] +---- +# bad +{a: 1, b: 2}.each_with_object({}) { |(k, v), h| h[k] = foo(v) } +Hash[{a: 1, b: 2}.collect { |k, v| [k, foo(v)] }] +{a: 1, b: 2}.map { |k, v| [k, v * v] }.to_h +{a: 1, b: 2}.to_h { |k, v| [k, v * v] } + +# good +{a: 1, b: 2}.transform_values { |v| foo(v) } +{a: 1, b: 2}.transform_values { |v| v * v } +---- + +== Style/IdenticalConditionalBranches + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.36 +| - +|=== + +This cop checks for identical lines at the beginning or end of +each branch of a conditional statement. + +=== Examples + +[source,ruby] +---- +# bad +if condition + do_x + do_z +else + do_y + do_z +end + +# good +if condition + do_x +else + do_y +end +do_z + +# bad +if condition + do_z + do_x +else + do_z + do_y +end + +# good +do_z +if condition + do_x +else + do_y +end + +# bad +case foo +when 1 + do_x +when 2 + do_x +else + do_x +end + +# good +case foo +when 1 + do_x + do_y +when 2 + # nothing +else + do_x + do_z +end +---- + +== Style/IfInsideElse + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.36 +| - +|=== + +If the `else` branch of a conditional consists solely of an `if` node, +it can be combined with the `else` to become an `elsif`. +This helps to keep the nesting level from getting too deep. + +=== Examples + +[source,ruby] +---- +# bad +if condition_a + action_a +else + if condition_b + action_b + else + action_c + end +end + +# good +if condition_a + action_a +elsif condition_b + action_b +else + action_c +end +---- + +==== AllowIfModifier: false (default) + +[source,ruby] +---- +# bad +if condition_a + action_a +else + action_b if condition_b +end + +# good +if condition_a + action_a +elsif condition_b + action_b +end +---- + +==== AllowIfModifier: true + +[source,ruby] +---- +# good +if condition_a + action_a +else + action_b if condition_b +end + +# good +if condition_a + action_a +elsif condition_b + action_b +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowIfModifier +| `false` +| Boolean +|=== + +== Style/IfUnlessModifier + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.30 +|=== + +Checks for `if` and `unless` statements that would fit on one line if +written as modifier `if`/`unless`. The cop also checks for modifier +`if`/`unless` lines that exceed the maximum line length. + +The maximum line length is configured in the `Layout/LineLength` +cop. The tab size is configured in the `IndentationWidth` of the +`Layout/IndentationStyle` cop. + +=== Examples + +[source,ruby] +---- +# bad +if condition + do_stuff(bar) +end + +unless qux.empty? + Foo.do_something +end + +do_something_in_a_method_with_a_long_name(arg) if long_condition + +# good +do_stuff(bar) if condition +Foo.do_something unless qux.empty? + +if long_condition + do_something_in_a_method_with_a_long_name(arg) +end +---- + +=== References + +* https://rubystyle.guide#if-as-a-modifier + +== Style/IfUnlessModifierOfIfUnless + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.39 +| 0.87 +|=== + +Checks for if and unless statements used as modifiers of other if or +unless statements. + +=== Examples + +[source,ruby] +---- +# bad +tired? ? 'stop' : 'go faster' if running? + +# bad +if tired? + "please stop" +else + "keep going" +end if running? + +# good +if running? + tired? ? 'stop' : 'go faster' +end +---- + +== Style/IfWithSemicolon + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.83 +|=== + +Checks for uses of semicolon in if statements. + +=== Examples + +[source,ruby] +---- +# bad +result = if some_condition; something else another_thing end + +# good +result = some_condition ? something : another_thing +---- + +=== References + +* https://rubystyle.guide#no-semicolon-ifs + +== Style/ImplicitRuntimeError + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.41 +| - +|=== + +This cop checks for `raise` or `fail` statements which do not specify an +explicit exception class. (This raises a `RuntimeError`. Some projects +might prefer to use exception classes which more precisely identify the +nature of the error.) + +=== Examples + +[source,ruby] +---- +# bad +raise 'Error message here' + +# good +raise ArgumentError, 'Error message here' +---- + +== Style/InfiniteLoop + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.26 +| 0.61 +|=== + +Use `Kernel#loop` for infinite loops. + +=== Examples + +[source,ruby] +---- +# bad +while true + work +end + +# good +loop do + work +end +---- + +=== References + +* https://rubystyle.guide#infinite-loop + +== Style/InlineComment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.23 +| - +|=== + +This cop checks for trailing inline comments. + +=== Examples + +[source,ruby] +---- +# good +foo.each do |f| + # Standalone comment + f.bar +end + +# bad +foo.each do |f| + f.bar # Trailing inline comment +end +---- + +== Style/InverseMethods + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.48 +| - +|=== + +This cop check for usages of not (`not` or `!`) called on a method +when an inverse of that method can be used instead. +Methods that can be inverted by a not (`not` or `!`) should be defined +in `InverseMethods` +Methods that are inverted by inverting the return +of the block that is passed to the method should be defined in +`InverseBlocks` + +=== Examples + +[source,ruby] +---- +# bad +!foo.none? +!foo.any? { |f| f.even? } +!foo.blank? +!(foo == bar) +foo.select { |f| !f.even? } +foo.reject { |f| f != 7 } + +# good +foo.none? +foo.blank? +foo.any? { |f| f.even? } +foo != bar +foo == bar +!!('foo' =~ /^\w+$/) +!(foo.class < Numeric) # Checking class hierarchy is allowed +# Blocks with guard clauses are ignored: +foo.select do |f| + next if f.zero? + f != 1 +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| InverseMethods +| `{:any?=>:none?, :even?=>:odd?, :===>:!=, :=~=>:!~, :<=>:>=, :>=>:<=}` +| + +| InverseBlocks +| `{:select=>:reject, :select!=>:reject!}` +| +|=== + +== Style/IpAddresses + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.58 +| 0.91 +|=== + +This cop checks for hardcoded IP addresses, which can make code +brittle. IP addresses are likely to need to be changed when code +is deployed to a different server or environment, which may break +a deployment if forgotten. Prefer setting IP addresses in ENV or +other configuration. + +=== Examples + +[source,ruby] +---- +# bad +ip_address = '127.59.241.29' + +# good +ip_address = ENV['DEPLOYMENT_IP_ADDRESS'] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedAddresses +| `::` +| Array + +| Exclude +| `**/*.gemfile`, `**/Gemfile`, `**/gems.rb`, `**/*.gemspec` +| Array +|=== + +== Style/KeywordParametersOrder + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.90 +| - +|=== + +This cop enforces that optional keyword parameters are placed at the +end of the parameters list. + +This improves readability, because when looking through the source, +it is expected to find required parameters at the beginning of parameters list +and optional parameters at the end. + +=== Examples + +[source,ruby] +---- +# bad +def some_method(first: false, second:, third: 10) + # body omitted +end + +# good +def some_method(second:, first: false, third: 10) + # body omitted +end +---- + +=== References + +* https://rubystyle.guide#keyword-parameters-order + +== Style/Lambda + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.40 +|=== + +This cop (by default) checks for uses of the lambda literal syntax for +single line lambdas, and the method call syntax for multiline lambdas. +It is configurable to enforce one of the styles for both single line +and multiline lambdas as well. + +=== Examples + +==== EnforcedStyle: line_count_dependent (default) + +[source,ruby] +---- +# bad +f = lambda { |x| x } +f = ->(x) do + x + end + +# good +f = ->(x) { x } +f = lambda do |x| + x + end +---- + +==== EnforcedStyle: lambda + +[source,ruby] +---- +# bad +f = ->(x) { x } +f = ->(x) do + x + end + +# good +f = lambda { |x| x } +f = lambda do |x| + x + end +---- + +==== EnforcedStyle: literal + +[source,ruby] +---- +# bad +f = lambda { |x| x } +f = lambda do |x| + x + end + +# good +f = ->(x) { x } +f = ->(x) do + x + end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `line_count_dependent` +| `line_count_dependent`, `lambda`, `literal` +|=== + +=== References + +* https://rubystyle.guide#lambda-multi-line + +== Style/LambdaCall + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.13 +| 0.14 +|=== + +This cop checks for use of the lambda.(args) syntax. + +=== Examples + +==== EnforcedStyle: call (default) + +[source,ruby] +---- +# bad +lambda.(x, y) + +# good +lambda.call(x, y) +---- + +==== EnforcedStyle: braces + +[source,ruby] +---- +# bad +lambda.call(x, y) + +# good +lambda.(x, y) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `call` +| `call`, `braces` +|=== + +=== References + +* https://rubystyle.guide#proc-call + +== Style/LineEndConcatenation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes (Unsafe) +| 0.18 +| 0.64 +|=== + +This cop checks for string literal concatenation at +the end of a line. + +=== Examples + +[source,ruby] +---- +# bad +some_str = 'ala' + + 'bala' + +some_str = 'ala' << + 'bala' + +# good +some_str = 'ala' \ + 'bala' +---- + +== Style/MethodCallWithArgsParentheses + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.47 +| 0.61 +|=== + +This cop enforces the presence (default) or absence of parentheses in +method calls containing parameters. + +In the default style (require_parentheses), macro methods are ignored. +Additional methods can be added to the `IgnoredMethods` +or `IgnoredPatterns` list. These options are +valid only in the default style. Macros can be included by +either setting `IgnoreMacros` to false or adding specific macros to +the `IncludedMacros` list. + +Precedence of options is all follows: + +1. `IgnoredMethods` +2. `IgnoredPatterns` +3. `IncludedMacros` + +eg. If a method is listed in both +`IncludedMacros` and `IgnoredMethods`, then the latter takes +precedence (that is, the method is ignored). + +In the alternative style (omit_parentheses), there are three additional +options. + +1. `AllowParenthesesInChaining` is `false` by default. Setting it to + `true` allows the presence of parentheses in the last call during + method chaining. + +2. `AllowParenthesesInMultilineCall` is `false` by default. Setting it + to `true` allows the presence of parentheses in multi-line method + calls. + +3. `AllowParenthesesInCamelCaseMethod` is `false` by default. This + allows the presence of parentheses when calling a method whose name + begins with a capital letter and which has no arguments. Setting it + to `true` allows the presence of parentheses in such a method call + even with arguments. + +=== Examples + +==== EnforcedStyle: require_parentheses (default) + +[source,ruby] +---- +# bad +array.delete e + +# good +array.delete(e) + +# good +# Operators don't need parens +foo == bar + +# good +# Setter methods don't need parens +foo.bar = baz + +# okay with `puts` listed in `IgnoredMethods` +puts 'test' + +# okay with `^assert` listed in `IgnoredPatterns` +assert_equal 'test', x +---- + +==== EnforcedStyle: omit_parentheses + +[source,ruby] +---- +# bad +array.delete(e) + +# good +array.delete e + +# bad +foo.enforce(strict: true) + +# good +foo.enforce strict: true +---- + +==== IgnoreMacros: true (default) + +[source,ruby] +---- +# good +class Foo + bar :baz +end +---- + +==== IgnoreMacros: false + +[source,ruby] +---- +# bad +class Foo + bar :baz +end +---- + +==== AllowParenthesesInMultilineCall: false (default) + +[source,ruby] +---- +# bad +foo.enforce( + strict: true +) + +# good +foo.enforce \ + strict: true +---- + +==== AllowParenthesesInMultilineCall: true + +[source,ruby] +---- +# good +foo.enforce( + strict: true +) + +# good +foo.enforce \ + strict: true +---- + +==== AllowParenthesesInChaining: false (default) + +[source,ruby] +---- +# bad +foo().bar(1) + +# good +foo().bar 1 +---- + +==== AllowParenthesesInChaining: true + +[source,ruby] +---- +# good +foo().bar(1) + +# good +foo().bar 1 +---- + +==== AllowParenthesesInCamelCaseMethod: false (default) + +[source,ruby] +---- +# bad +Array(1) + +# good +Array 1 +---- + +==== AllowParenthesesInCamelCaseMethod: true + +[source,ruby] +---- +# good +Array(1) + +# good +Array 1 +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IgnoreMacros +| `true` +| Boolean + +| IgnoredMethods +| `[]` +| Array + +| IgnoredPatterns +| `[]` +| Array + +| IncludedMacros +| `[]` +| Array + +| AllowParenthesesInMultilineCall +| `false` +| Boolean + +| AllowParenthesesInChaining +| `false` +| Boolean + +| AllowParenthesesInCamelCaseMethod +| `false` +| Boolean + +| EnforcedStyle +| `require_parentheses` +| `require_parentheses`, `omit_parentheses` +|=== + +=== References + +* https://rubystyle.guide#method-invocation-parens + +== Style/MethodCallWithoutArgsParentheses + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.47 +| 0.55 +|=== + +This cop checks for unwanted parentheses in parameterless method calls. + +=== Examples + +[source,ruby] +---- +# bad +object.some_method() + +# good +object.some_method +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IgnoredMethods +| `[]` +| Array +|=== + +=== References + +* https://rubystyle.guide#method-invocation-parens + +== Style/MethodCalledOnDoEndBlock + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.14 +| - +|=== + +This cop checks for methods called on a do...end block. The point of +this check is that it's easy to miss the call tacked on to the block +when reading code. + +=== Examples + +[source,ruby] +---- +# bad +a do + b +end.c + +# good +a { b }.c + +# good +foo = a do + b +end +foo.c +---- + +=== References + +* https://rubystyle.guide#single-line-blocks + +== Style/MethodDefParentheses + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.16 +| 0.35 +|=== + +This cop checks for parentheses around the arguments in method +definitions. Both instance and class/singleton methods are checked. + +=== Examples + +==== EnforcedStyle: require_parentheses (default) + +[source,ruby] +---- +# The `require_parentheses` style requires method definitions +# to always use parentheses + +# bad +def bar num1, num2 + num1 + num2 +end + +def foo descriptive_var_name, + another_descriptive_var_name, + last_descriptive_var_name + do_something +end + +# good +def bar(num1, num2) + num1 + num2 +end + +def foo(descriptive_var_name, + another_descriptive_var_name, + last_descriptive_var_name) + do_something +end +---- + +==== EnforcedStyle: require_no_parentheses + +[source,ruby] +---- +# The `require_no_parentheses` style requires method definitions +# to never use parentheses + +# bad +def bar(num1, num2) + num1 + num2 +end + +def foo(descriptive_var_name, + another_descriptive_var_name, + last_descriptive_var_name) + do_something +end + +# good +def bar num1, num2 + num1 + num2 +end + +def foo descriptive_var_name, + another_descriptive_var_name, + last_descriptive_var_name + do_something +end +---- + +==== EnforcedStyle: require_no_parentheses_except_multiline + +[source,ruby] +---- +# The `require_no_parentheses_except_multiline` style prefers no +# parentheses when method definition arguments fit on single line, +# but prefers parentheses when arguments span multiple lines. + +# bad +def bar(num1, num2) + num1 + num2 +end + +def foo descriptive_var_name, + another_descriptive_var_name, + last_descriptive_var_name + do_something +end + +# good +def bar num1, num2 + num1 + num2 +end + +def foo(descriptive_var_name, + another_descriptive_var_name, + last_descriptive_var_name) + do_something +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `require_parentheses` +| `require_parentheses`, `require_no_parentheses`, `require_no_parentheses_except_multiline` +|=== + +=== References + +* https://rubystyle.guide#method-parens + +== Style/MinMax + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.50 +| - +|=== + +This cop checks for potential uses of `Enumerable#minmax`. + +=== Examples + +[source,ruby] +---- +# bad +bar = [foo.min, foo.max] +return foo.min, foo.max + +# good +bar = foo.minmax +return foo.minmax +---- + +== Style/MissingElse + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.30 +| 0.38 +|=== + +Checks for `if` expressions that do not have an `else` branch. + +Supported styles are: if, case, both. + +=== Examples + +==== EnforcedStyle: if + +[source,ruby] +---- +# warn when an `if` expression is missing an `else` branch. + +# bad +if condition + statement +end + +# good +if condition + statement +else + # the content of `else` branch will be determined by Style/EmptyElse +end + +# good +case var +when condition + statement +end + +# good +case var +when condition + statement +else + # the content of `else` branch will be determined by Style/EmptyElse +end +---- + +==== EnforcedStyle: case + +[source,ruby] +---- +# warn when a `case` expression is missing an `else` branch. + +# bad +case var +when condition + statement +end + +# good +case var +when condition + statement +else + # the content of `else` branch will be determined by Style/EmptyElse +end + +# good +if condition + statement +end + +# good +if condition + statement +else + # the content of `else` branch will be determined by Style/EmptyElse +end +---- + +==== EnforcedStyle: both (default) + +[source,ruby] +---- +# warn when an `if` or `case` expression is missing an `else` branch. + +# bad +if condition + statement +end + +# bad +case var +when condition + statement +end + +# good +if condition + statement +else + # the content of `else` branch will be determined by Style/EmptyElse +end + +# good +case var +when condition + statement +else + # the content of `else` branch will be determined by Style/EmptyElse +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `both` +| `if`, `case`, `both` +|=== + +== Style/MissingRespondToMissing + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.56 +| - +|=== + +This cop checks for the presence of `method_missing` without also +defining `respond_to_missing?`. + +=== Examples + +[source,ruby] +---- +#bad +def method_missing(name, *args) + # ... +end + +#good +def respond_to_missing?(name, include_private) + # ... +end + +def method_missing(name, *args) + # ... +end +---- + +=== References + +* https://rubystyle.guide#no-method-missing + +== Style/MixinGrouping + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.48 +| 0.49 +|=== + +This cop checks for grouping of mixins in `class` and `module` bodies. +By default it enforces mixins to be placed in separate declarations, +but it can be configured to enforce grouping them in one declaration. + +=== Examples + +==== EnforcedStyle: separated (default) + +[source,ruby] +---- +# bad +class Foo + include Bar, Qox +end + +# good +class Foo + include Qox + include Bar +end +---- + +==== EnforcedStyle: grouped + +[source,ruby] +---- +# bad +class Foo + extend Bar + extend Qox +end + +# good +class Foo + extend Qox, Bar +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `separated` +| `separated`, `grouped` +|=== + +=== References + +* https://rubystyle.guide#mixin-grouping + +== Style/MixinUsage + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.51 +| - +|=== + +This cop checks that `include`, `extend` and `prepend` statements appear +inside classes and modules, not at the top level, so as to not affect +the behavior of `Object`. + +=== Examples + +[source,ruby] +---- +# bad +include M + +class C +end + +# bad +extend M + +class C +end + +# bad +prepend M + +class C +end + +# good +class C + include M +end + +# good +class C + extend M +end + +# good +class C + prepend M +end +---- + +== Style/ModuleFunction + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes (Unsafe) +| 0.11 +| 0.65 +|=== + +This cop checks for use of `extend self` or `module_function` in a +module. + +Supported styles are: module_function, extend_self, forbidden. + +In case there are private methods, the cop won't be activated. +Otherwise, it forces to change the flow of the default code. + +The option `forbidden` prohibits the usage of both styles. + +These offenses are not safe to auto-correct since there are different +implications to each approach. + +=== Examples + +==== EnforcedStyle: module_function (default) + +[source,ruby] +---- +# bad +module Test + extend self + # ... +end + +# good +module Test + module_function + # ... +end +---- + +==== EnforcedStyle: module_function (default) + +[source,ruby] +---- +# good +module Test + extend self + # ... + private + # ... +end +---- + +==== EnforcedStyle: extend_self + +[source,ruby] +---- +# bad +module Test + module_function + # ... +end + +# good +module Test + extend self + # ... +end +---- + +==== EnforcedStyle: forbidden + +[source,ruby] +---- +# bad +module Test + module_function + # ... +end + +# bad +module Test + extend self + # ... +end + +# bad +module Test + extend self + # ... + private + # ... +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `module_function` +| `module_function`, `extend_self`, `forbidden` + +| Autocorrect +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#module-function + +== Style/MultilineBlockChain + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.13 +| - +|=== + +This cop checks for chaining of a block after another block that spans +multiple lines. + +=== Examples + +[source,ruby] +---- +# bad +Thread.list.select do |t| + t.alive? +end.map do |t| + t.object_id +end + +# good +alive_threads = Thread.list.select do |t| + t.alive? +end +alive_threads.map do |t| + t.object_id +end +---- + +=== References + +* https://rubystyle.guide#single-line-blocks + +== Style/MultilineIfModifier + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.45 +| - +|=== + +Checks for uses of if/unless modifiers with multiple-lines bodies. + +=== Examples + +[source,ruby] +---- +# bad +{ + result: 'this should not happen' +} unless cond + +# good +{ result: 'ok' } if cond +---- + +=== References + +* https://rubystyle.guide#no-multiline-if-modifiers + +== Style/MultilineIfThen + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.26 +|=== + +Checks for uses of the `then` keyword in multi-line if statements. + +=== Examples + +[source,ruby] +---- +# bad +# This is considered bad practice. +if cond then +end + +# good +# If statements can contain `then` on the same line. +if cond then a +elsif cond then b +end +---- + +=== References + +* https://rubystyle.guide#no-then + +== Style/MultilineMemoization + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.44 +| 0.48 +|=== + +This cop checks expressions wrapping styles for multiline memoization. + +=== Examples + +==== EnforcedStyle: keyword (default) + +[source,ruby] +---- +# bad +foo ||= ( + bar + baz +) + +# good +foo ||= begin + bar + baz +end +---- + +==== EnforcedStyle: braces + +[source,ruby] +---- +# bad +foo ||= begin + bar + baz +end + +# good +foo ||= ( + bar + baz +) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `keyword` +| `keyword`, `braces` +|=== + +== Style/MultilineMethodSignature + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.59 +| - +|=== + +This cop checks for method signatures that span multiple lines. + +=== Examples + +[source,ruby] +---- +# good + +def foo(bar, baz) +end + +# bad + +def foo(bar, + baz) +end +---- + +== Style/MultilineTernaryOperator + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.86 +|=== + +This cop checks for multi-line ternary op expressions. + +NOTE: `return if ... else ... end` is syntax error. If `return` is used before +multiline ternary operator expression, it cannot be auto-corrected. + +=== Examples + +[source,ruby] +---- +# bad +a = cond ? + b : c +a = cond ? b : + c +a = cond ? + b : + c + +# good +a = cond ? b : c +a = if cond + b +else + c +end +---- + +=== References + +* https://rubystyle.guide#no-multiline-ternary + +== Style/MultilineWhenThen + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.73 +| - +|=== + +This cop checks uses of the `then` keyword +in multi-line when statements. + +=== Examples + +[source,ruby] +---- +# bad +case foo +when bar then +end + +# good +case foo +when bar +end + +# good +case foo +when bar then do_something +end + +# good +case foo +when bar then do_something(arg1, + arg2) +end +---- + +=== References + +* https://rubystyle.guide#no-then + +== Style/MultipleComparison + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| No +| 0.49 +| - +|=== + +This cop checks against comparing a variable with multiple items, where +`Array#include?` could be used instead to avoid code repetition. + +=== Examples + +[source,ruby] +---- +# bad +a = 'a' +foo if a == 'a' || a == 'b' || a == 'c' + +# good +a = 'a' +foo if ['a', 'b', 'c'].include?(a) +---- + +== Style/MutableConstant + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.34 +| 0.65 +|=== + +This cop checks whether some constant value isn't a +mutable literal (e.g. array or hash). + +Strict mode can be used to freeze all constants, rather than +just literals. +Strict mode is considered an experimental feature. It has not been +updated with an exhaustive list of all methods that will produce +frozen objects so there is a decent chance of getting some false +positives. Luckily, there is no harm in freezing an already +frozen object. + +=== Examples + +==== EnforcedStyle: literals (default) + +[source,ruby] +---- +# bad +CONST = [1, 2, 3] + +# good +CONST = [1, 2, 3].freeze + +# good +CONST = <<~TESTING.freeze + This is a heredoc +TESTING + +# good +CONST = Something.new +---- + +==== EnforcedStyle: strict + +[source,ruby] +---- +# bad +CONST = Something.new + +# bad +CONST = Struct.new do + def foo + puts 1 + end +end + +# good +CONST = Something.new.freeze + +# good +CONST = Struct.new do + def foo + puts 1 + end +end.freeze +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `literals` +| `literals`, `strict` +|=== + +== Style/NegatedIf + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.20 +| 0.48 +|=== + +Checks for uses of if with a negated condition. Only ifs +without else are considered. There are three different styles: + +* both +* prefix +* postfix + +=== Examples + +==== EnforcedStyle: both (default) + +[source,ruby] +---- +# enforces `unless` for `prefix` and `postfix` conditionals + +# bad + +if !foo + bar +end + +# good + +unless foo + bar +end + +# bad + +bar if !foo + +# good + +bar unless foo +---- + +==== EnforcedStyle: prefix + +[source,ruby] +---- +# enforces `unless` for just `prefix` conditionals + +# bad + +if !foo + bar +end + +# good + +unless foo + bar +end + +# good + +bar if !foo +---- + +==== EnforcedStyle: postfix + +[source,ruby] +---- +# enforces `unless` for just `postfix` conditionals + +# bad + +bar if !foo + +# good + +bar unless foo + +# good + +if !foo + bar +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `both` +| `both`, `prefix`, `postfix` +|=== + +=== References + +* https://rubystyle.guide#unless-for-negatives + +== Style/NegatedUnless + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.69 +| - +|=== + +Checks for uses of unless with a negated condition. Only unless +without else are considered. There are three different styles: + +* both +* prefix +* postfix + +=== Examples + +==== EnforcedStyle: both (default) + +[source,ruby] +---- +# enforces `if` for `prefix` and `postfix` conditionals + +# bad +unless !foo + bar +end + +# good +if foo + bar +end + +# bad +bar unless !foo + +# good +bar if foo +---- + +==== EnforcedStyle: prefix + +[source,ruby] +---- +# enforces `if` for just `prefix` conditionals + +# bad +unless !foo + bar +end + +# good +if foo + bar +end + +# good +bar unless !foo +---- + +==== EnforcedStyle: postfix + +[source,ruby] +---- +# enforces `if` for just `postfix` conditionals + +# bad +bar unless !foo + +# good +bar if foo + +# good +unless !foo + bar +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `both` +| `both`, `prefix`, `postfix` +|=== + +=== References + +* https://rubystyle.guide#if-for-negatives + +== Style/NegatedWhile + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.20 +| - +|=== + +Checks for uses of while with a negated condition. + +=== Examples + +[source,ruby] +---- +# bad +while !foo + bar +end + +# good +until foo + bar +end + +# bad +bar until !foo + +# good +bar while foo +bar while !foo && baz +---- + +=== References + +* https://rubystyle.guide#until-for-negatives + +== Style/NestedModifier + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.35 +| - +|=== + +This cop checks for nested use of if, unless, while and until in their +modifier form. + +=== Examples + +[source,ruby] +---- +# bad +something if a if b + +# good +something if b && a +---- + +=== References + +* https://rubystyle.guide#no-nested-modifiers + +== Style/NestedParenthesizedCalls + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.36 +| 0.77 +|=== + +This cop checks for unparenthesized method calls in the argument list +of a parenthesized method call. + +=== Examples + +[source,ruby] +---- +# good +method1(method2(arg)) + +# bad +method1(method2 arg) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedMethods +| `be`, `be_a`, `be_an`, `be_between`, `be_falsey`, `be_kind_of`, `be_instance_of`, `be_truthy`, `be_within`, `eq`, `eql`, `end_with`, `include`, `match`, `raise_error`, `respond_to`, `start_with` +| Array +|=== + +== Style/NestedTernaryOperator + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.86 +|=== + +This cop checks for nested ternary op expressions. + +=== Examples + +[source,ruby] +---- +# bad +a ? (b ? b1 : b2) : a2 + +# good +if a + b ? b1 : b2 +else + a2 +end +---- + +=== References + +* https://rubystyle.guide#no-nested-ternary + +== Style/Next + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.22 +| 0.35 +|=== + +Use `next` to skip iteration instead of a condition at the end. + +=== Examples + +==== EnforcedStyle: skip_modifier_ifs (default) + +[source,ruby] +---- +# bad +[1, 2].each do |a| + if a == 1 + puts a + end +end + +# good +[1, 2].each do |a| + next unless a == 1 + puts a +end + +# good +[1, 2].each do |a| + puts a if a == 1 +end +---- + +==== EnforcedStyle: always + +[source,ruby] +---- +# With `always` all conditions at the end of an iteration needs to be +# replaced by next - with `skip_modifier_ifs` the modifier if like +# this one are ignored: `[1, 2].each { |a| puts a if a == 1 }` + +# bad +[1, 2].each do |a| + puts a if a == 1 +end + +# bad +[1, 2].each do |a| + if a == 1 + puts a + end +end + +# good +[1, 2].each do |a| + next unless a == 1 + puts a +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `skip_modifier_ifs` +| `skip_modifier_ifs`, `always` + +| MinBodyLength +| `3` +| Integer +|=== + +=== References + +* https://rubystyle.guide#no-nested-conditionals + +== Style/NilComparison + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.12 +| 0.59 +|=== + +This cop checks for comparison of something with nil using `==` and +`nil?`. + +Supported styles are: predicate, comparison. + +=== Examples + +==== EnforcedStyle: predicate (default) + +[source,ruby] +---- +# bad +if x == nil +end + +# good +if x.nil? +end +---- + +==== EnforcedStyle: comparison + +[source,ruby] +---- +# bad +if x.nil? +end + +# good +if x == nil +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `predicate` +| `predicate`, `comparison` +|=== + +=== References + +* https://rubystyle.guide#predicate-methods + +== Style/NonNilCheck + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.20 +| 0.22 +|=== + +This cop checks for non-nil checks, which are usually redundant. + +With `IncludeSemanticChanges` set to `false` by default, this cop +does not report offenses for `!x.nil?` and does no changes that might +change behavior. + +With `IncludeSemanticChanges` set to `true`, this cop reports offenses +for `!x.nil?` and autocorrects that and `x != nil` to solely `x`, which +is *usually* OK, but might change behavior. + +=== Examples + +[source,ruby] +---- +# bad +if x != nil +end + +# good +if x +end + +# Non-nil checks are allowed if they are the final nodes of predicate. +# good +def signed_in? + !current_user.nil? +end +---- + +==== IncludeSemanticChanges: false (default) + +[source,ruby] +---- +# good +if !x.nil? +end +---- + +==== IncludeSemanticChanges: true + +[source,ruby] +---- +# bad +if !x.nil? +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IncludeSemanticChanges +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#no-non-nil-checks + +== Style/Not + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.20 +|=== + +This cop checks for uses of the keyword `not` instead of `!`. + +=== Examples + +[source,ruby] +---- +# bad - parentheses are required because of op precedence +x = (not something) + +# good +x = !something +---- + +=== References + +* https://rubystyle.guide#bang-not-not + +== Style/NumericLiteralPrefix + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.41 +| - +|=== + +This cop checks for octal, hex, binary, and decimal literals using +uppercase prefixes and corrects them to lowercase prefix +or no prefix (in case of decimals). + +=== Examples + +==== EnforcedOctalStyle: zero_with_o (default) + +[source,ruby] +---- +# bad - missing octal prefix +num = 01234 + +# bad - uppercase prefix +num = 0O1234 +num = 0X12AB +num = 0B10101 + +# bad - redundant decimal prefix +num = 0D1234 +num = 0d1234 + +# good +num = 0o1234 +num = 0x12AB +num = 0b10101 +num = 1234 +---- + +==== EnforcedOctalStyle: zero_only + +[source,ruby] +---- +# bad +num = 0o1234 +num = 0O1234 + +# good +num = 01234 +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedOctalStyle +| `zero_with_o` +| `zero_with_o`, `zero_only` +|=== + +=== References + +* https://rubystyle.guide#numeric-literal-prefixes + +== Style/NumericLiterals + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.48 +|=== + +This cop checks for big numeric literals without _ between groups +of digits in them. + +=== Examples + +[source,ruby] +---- +# bad +1000000 +1_00_000 +1_0000 + +# good +1_000_000 +1000 +---- + +==== Strict: false (default) + +[source,ruby] +---- +# good +10_000_00 # typical representation of $10,000 in cents +---- + +==== Strict: true + +[source,ruby] +---- +# bad +10_000_00 # typical representation of $10,000 in cents +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| MinDigits +| `5` +| Integer + +| Strict +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#underscores-in-numerics + +== Style/NumericPredicate + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.42 +| 0.59 +|=== + +This cop checks for usage of comparison operators (`==`, +`>`, `<`) to test numbers as zero, positive, or negative. +These can be replaced by their respective predicate methods. +The cop can also be configured to do the reverse. + +The cop disregards `#nonzero?` as it its value is truthy or falsey, +but not `true` and `false`, and thus not always interchangeable with +`!= 0`. + +The cop ignores comparisons to global variables, since they are often +populated with objects which can be compared with integers, but are +not themselves `Integer` polymorphic. + +=== Examples + +==== EnforcedStyle: predicate (default) + +[source,ruby] +---- +# bad + +foo == 0 +0 > foo +bar.baz > 0 + +# good + +foo.zero? +foo.negative? +bar.baz.positive? +---- + +==== EnforcedStyle: comparison + +[source,ruby] +---- +# bad + +foo.zero? +foo.negative? +bar.baz.positive? + +# good + +foo == 0 +0 > foo +bar.baz > 0 +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `predicate` +| `predicate`, `comparison` + +| IgnoredMethods +| `[]` +| Array + +| Exclude +| `spec/**/*` +| Array +|=== + +=== References + +* https://rubystyle.guide#predicate-methods + +== Style/OneLineConditional + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.90 +|=== + +Checks for uses of if/then/else/end constructs on a single line. +AlwaysCorrectToMultiline config option can be set to true to auto-convert all offenses to +multi-line constructs. When AlwaysCorrectToMultiline is false (default case) the +auto-correct will first try converting them to ternary operators. + +=== Examples + +[source,ruby] +---- +# bad +if foo then bar else baz end + +# bad +unless foo then baz else bar end + +# good +foo ? bar : baz + +# good +bar if foo + +# good +if foo then bar end + +# good +if foo + bar +else + baz +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AlwaysCorrectToMultiline +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#ternary-operator + +== Style/OptionHash + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.33 +| 0.34 +|=== + +This cop checks for options hashes and discourages them if the +current Ruby version supports keyword arguments. + +=== Examples + +[source,ruby] +---- +# bad +def fry(options = {}) + temperature = options.fetch(:temperature, 300) + # ... +end + +# good +def fry(temperature: 300) + # ... +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| SuspiciousParamNames +| `options`, `opts`, `args`, `params`, `parameters` +| Array +|=== + +== Style/OptionalArguments + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| No +| 0.33 +| 0.83 +|=== + +This cop checks for optional arguments to methods +that do not come at the end of the argument list. + +=== Examples + +[source,ruby] +---- +# bad +def foo(a = 1, b, c) +end + +# good +def baz(a, b, c = 1) +end + +def foobar(a = 1, b = 2, c = 3) +end +---- + +=== References + +* https://rubystyle.guide#optional-arguments + +== Style/OptionalBooleanParameter + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| No +| 0.89 +| - +|=== + +This cop checks for places where keyword arguments can be used instead of +boolean arguments when defining methods. `respond_to_missing?` method is allowed by default. +These are customizable with `AllowedMethods` option. + +=== Examples + +[source,ruby] +---- +# bad +def some_method(bar = false) + puts bar +end + +# bad - common hack before keyword args were introduced +def some_method(options = {}) + bar = options.fetch(:bar, false) + puts bar +end + +# good +def some_method(bar: false) + puts bar +end +---- + +==== AllowedMethods: ['some_method'] + +[source,ruby] +---- +# good +def some_method(bar = false) + puts bar +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowedMethods +| `respond_to_missing?` +| Array +|=== + +=== References + +* https://rubystyle.guide#boolean-keyword-arguments + +== Style/OrAssignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.50 +| - +|=== + +This cop checks for potential usage of the `||=` operator. + +=== Examples + +[source,ruby] +---- +# bad +name = name ? name : 'Bozhidar' + +# bad +name = if name + name + else + 'Bozhidar' + end + +# bad +unless name + name = 'Bozhidar' +end + +# bad +name = 'Bozhidar' unless name + +# good - set name to 'Bozhidar', only if it's nil or false +name ||= 'Bozhidar' +---- + +=== References + +* https://rubystyle.guide#double-pipe-for-uninit + +== Style/ParallelAssignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.32 +| - +|=== + +Checks for simple usages of parallel assignment. +This will only complain when the number of variables +being assigned matched the number of assigning variables. + +=== Examples + +[source,ruby] +---- +# bad +a, b, c = 1, 2, 3 +a, b, c = [1, 2, 3] + +# good +one, two = *foo +a, b = foo() +a, b = b, a + +a = 1 +b = 2 +c = 3 +---- + +=== References + +* https://rubystyle.guide#parallel-assignment + +== Style/ParenthesesAroundCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.56 +|=== + +This cop checks for the presence of superfluous parentheses around the +condition of if/unless/while/until. + +`AllowSafeAssignment` option for safe assignment. +By safe assignment we mean putting parentheses around +an assignment to indicate "I know I'm using an assignment +as a condition. It's not a mistake." + +=== Examples + +[source,ruby] +---- +# bad +x += 1 while (x < 10) +foo unless (bar || baz) + +if (x > 10) +elsif (x < 3) +end + +# good +x += 1 while x < 10 +foo unless bar || baz + +if x > 10 +elsif x < 3 +end +---- + +==== AllowSafeAssignment: true (default) + +[source,ruby] +---- +# good +foo unless (bar = baz) +---- + +==== AllowSafeAssignment: false + +[source,ruby] +---- +# bad +foo unless (bar = baz) +---- + +==== AllowInMultilineConditions: false (default) + +[source,ruby] +---- +# bad +if (x > 10 && + y > 10) +end + +# good + if x > 10 && + y > 10 + end +---- + +==== AllowInMultilineConditions: true + +[source,ruby] +---- +# good +if (x > 10 && + y > 10) +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowSafeAssignment +| `true` +| Boolean + +| AllowInMultilineConditions +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#no-parens-around-condition + +== Style/PercentLiteralDelimiters + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.19 +| 0.48.1 +|=== + +This cop enforces the consistent usage of `%`-literal delimiters. + +Specify the 'default' key to set all preferred delimiters at once. You +can continue to specify individual preferred delimiters to override the +default. + +=== Examples + +[source,ruby] +---- +# Style/PercentLiteralDelimiters: +# PreferredDelimiters: +# default: '[]' +# '%i': '()' + +# good +%w[alpha beta] + %i(gamma delta) + +# bad +%W(alpha #{beta}) + +# bad +%I(alpha beta) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| PreferredDelimiters +| `{"default"=>"()", "%i"=>"[]", "%I"=>"[]", "%r"=>"{}", "%w"=>"[]", "%W"=>"[]"}` +| +|=== + +=== References + +* https://rubystyle.guide#percent-literal-braces + +== Style/PercentQLiterals + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.25 +| - +|=== + +This cop checks for usage of the %Q() syntax when %q() would do. + +=== Examples + +==== EnforcedStyle: lower_case_q (default) + +[source,ruby] +---- +# The `lower_case_q` style prefers `%q` unless +# interpolation is needed. +# bad +%Q[Mix the foo into the baz.] +%Q(They all said: 'Hooray!') + +# good +%q[Mix the foo into the baz] +%q(They all said: 'Hooray!') +---- + +==== EnforcedStyle: upper_case_q + +[source,ruby] +---- +# The `upper_case_q` style requires the sole use of `%Q`. +# bad +%q/Mix the foo into the baz./ +%q{They all said: 'Hooray!'} + +# good +%Q/Mix the foo into the baz./ +%Q{They all said: 'Hooray!'} +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `lower_case_q` +| `lower_case_q`, `upper_case_q` +|=== + +== Style/PerlBackrefs + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.13 +| - +|=== + +This cop looks for uses of Perl-style regexp match +backreferences like $1, $2, etc. + +=== Examples + +[source,ruby] +---- +# bad +puts $1 + +# good +puts Regexp.last_match(1) +---- + +=== References + +* https://rubystyle.guide#no-perl-regexp-last-matchers + +== Style/PreferredHashMethods + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.41 +| 0.70 +|=== + +This cop (by default) checks for uses of methods Hash#has_key? and +Hash#has_value? where it enforces Hash#key? and Hash#value? +It is configurable to enforce the inverse, using `verbose` method +names also. + +=== Examples + +==== EnforcedStyle: short (default) + +[source,ruby] +---- +# bad +Hash#has_key? +Hash#has_value? + +# good +Hash#key? +Hash#value? +---- + +==== EnforcedStyle: verbose + +[source,ruby] +---- +# bad +Hash#key? +Hash#value? + +# good +Hash#has_key? +Hash#has_value? +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `short` +| `short`, `verbose` +|=== + +=== References + +* https://rubystyle.guide#hash-key + +== Style/Proc + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.18 +|=== + +This cop checks for uses of Proc.new where Kernel#proc +would be more appropriate. + +=== Examples + +[source,ruby] +---- +# bad +p = Proc.new { |n| puts n } + +# good +p = proc { |n| puts n } +---- + +=== References + +* https://rubystyle.guide#proc + +== Style/RaiseArgs + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.14 +| 0.40 +|=== + +This cop checks the args passed to `fail` and `raise`. For exploded +style (default), it recommends passing the exception class and message +to `raise`, rather than construct an instance of the error. It will +still allow passing just a message, or the construction of an error +with more than one argument. + +The exploded style works identically, but with the addition that it +will also suggest constructing error objects when the exception is +passed multiple arguments. + +=== Examples + +==== EnforcedStyle: exploded (default) + +[source,ruby] +---- +# bad +raise StandardError.new("message") + +# good +raise StandardError, "message" +fail "message" +raise MyCustomError.new(arg1, arg2, arg3) +raise MyKwArgError.new(key1: val1, key2: val2) +---- + +==== EnforcedStyle: compact + +[source,ruby] +---- +# bad +raise StandardError, "message" +raise RuntimeError, arg1, arg2, arg3 + +# good +raise StandardError.new("message") +raise MyCustomError.new(arg1, arg2, arg3) +fail "message" +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `exploded` +| `compact`, `exploded` +|=== + +=== References + +* https://rubystyle.guide#exception-class-messages + +== Style/RandomWithOffset + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| - +|=== + +This cop checks for the use of randomly generated numbers, +added/subtracted with integer literals, as well as those with +Integer#succ and Integer#pred methods. Prefer using ranges instead, +as it clearly states the intentions. + +=== Examples + +[source,ruby] +---- +# bad +rand(6) + 1 +1 + rand(6) +rand(6) - 1 +1 - rand(6) +rand(6).succ +rand(6).pred +Random.rand(6) + 1 +Kernel.rand(6) + 1 +rand(0..5) + 1 + +# good +rand(1..6) +rand(1...7) +---- + +=== References + +* https://rubystyle.guide#random-numbers + +== Style/RedundantAssignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.87 +| - +|=== + +This cop checks for redundant assignment before returning. + +=== Examples + +[source,ruby] +---- +# bad +def test + x = foo + x +end + +# bad +def test + if x + z = foo + z + elsif y + z = bar + z + end +end + +# good +def test + foo +end + +# good +def test + if x + foo + elsif y + bar + end +end +---- + +== Style/RedundantBegin + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.10 +| 0.21 +|=== + +This cop checks for redundant `begin` blocks. + +Currently it checks for code like this: + +=== Examples + +[source,ruby] +---- +# bad +def redundant + begin + ala + bala + rescue StandardError => e + something + end +end + +# good +def preferred + ala + bala +rescue StandardError => e + something +end + +# bad +begin + do_something +end + +# good +do_something + +# bad +# When using Ruby 2.5 or later. +do_something do + begin + something + rescue => ex + anything + end +end + +# good +# In Ruby 2.5 or later, you can omit `begin` in `do-end` block. +do_something do + something +rescue => ex + anything +end + +# good +# Stabby lambdas don't support implicit `begin` in `do-end` blocks. +-> do + begin + foo + rescue Bar + baz + end +end +---- + +=== References + +* https://rubystyle.guide#begin-implicit + +== Style/RedundantCapitalW + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.76 +| - +|=== + +This cop checks for usage of the %W() syntax when %w() would do. + +=== Examples + +[source,ruby] +---- +# bad +%W(cat dog pig) +%W[door wall floor] + +# good +%w/swim run bike/ +%w[shirt pants shoes] +%W(apple #{fruit} grape) +---- + +== Style/RedundantCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.76 +| - +|=== + +This cop checks for unnecessary conditional expressions. + +=== Examples + +[source,ruby] +---- +# bad +a = b ? b : c + +# good +a = b || c +---- + +[source,ruby] +---- +# bad +if b + b +else + c +end + +# good +b || c + +# good +if b + b +elsif cond + c +end +---- + +== Style/RedundantConditional + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.50 +| - +|=== + +This cop checks for redundant returning of true/false in conditionals. + +=== Examples + +[source,ruby] +---- +# bad +x == y ? true : false + +# bad +if x == y + true +else + false +end + +# good +x == y + +# bad +x == y ? false : true + +# good +x != y +---- + +== Style/RedundantException + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.14 +| 0.29 +|=== + +This cop checks for RuntimeError as the argument of raise/fail. + +It checks for code like this: + +=== Examples + +[source,ruby] +---- +# Bad +raise RuntimeError, 'message' + +# Bad +raise RuntimeError.new('message') + +# Good +raise 'message' +---- + +=== References + +* https://rubystyle.guide#no-explicit-runtimeerror + +== Style/RedundantFetchBlock + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.86 +| - +|=== + +This cop identifies places where `fetch(key) { value }` +can be replaced by `fetch(key, value)`. + +In such cases `fetch(key, value)` method is faster +than `fetch(key) { value }`. + +=== Examples + +==== SafeForConstants: false (default) + +[source,ruby] +---- +# bad +hash.fetch(:key) { 5 } +hash.fetch(:key) { true } +hash.fetch(:key) { nil } +array.fetch(5) { :value } +ENV.fetch(:key) { 'value' } + +# good +hash.fetch(:key, 5) +hash.fetch(:key, true) +hash.fetch(:key, nil) +array.fetch(5, :value) +ENV.fetch(:key, 'value') +---- + +==== SafeForConstants: true + +[source,ruby] +---- +# bad +ENV.fetch(:key) { VALUE } + +# good +ENV.fetch(:key, VALUE) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| SafeForConstants +| `false` +| Boolean +|=== + +=== References + +* https://github.com/JuanitoFatas/fast-ruby#hashfetch-with-argument-vs-hashfetch--block-code + +== Style/RedundantFileExtensionInRequire + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.88 +| - +|=== + +This cop checks for the presence of superfluous `.rb` extension in +the filename provided to `require` and `require_relative`. + +Note: If the extension is omitted, Ruby tries adding '.rb', '.so', + and so on to the name until found. If the file named cannot be found, + a `LoadError` will be raised. + There is an edge case where `foo.so` file is loaded instead of a `LoadError` + if `foo.so` file exists when `require 'foo.rb'` will be changed to `require 'foo'`, + but that seems harmless. + +=== Examples + +[source,ruby] +---- +# bad +require 'foo.rb' +require_relative '../foo.rb' + +# good +require 'foo' +require 'foo.so' +require_relative '../foo' +require_relative '../foo.so' +---- + +=== References + +* https://rubystyle.guide#no-explicit-rb-to-require + +== Style/RedundantFreeze + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.34 +| 0.66 +|=== + +This cop check for uses of Object#freeze on immutable objects. + +=== Examples + +[source,ruby] +---- +# bad +CONST = 1.freeze + +# good +CONST = 1 +---- + +== Style/RedundantInterpolation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.76 +| - +|=== + +This cop checks for strings that are just an interpolated expression. + +=== Examples + +[source,ruby] +---- +# bad +"#{@var}" + +# good +@var.to_s + +# good if @var is already a String +@var +---- + +== Style/RedundantParentheses + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.36 +| - +|=== + +This cop checks for redundant parentheses. + +=== Examples + +[source,ruby] +---- +# bad +(x) if ((y.z).nil?) + +# good +x if y.z.nil? +---- + +== Style/RedundantPercentQ + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.76 +| - +|=== + +This cop checks for usage of the %q/%Q syntax when '' or "" would do. + +=== Examples + +[source,ruby] +---- +# bad +name = %q(Bruce Wayne) +time = %q(8 o'clock) +question = %q("What did you say?") + +# good +name = 'Bruce Wayne' +time = "8 o'clock" +question = '"What did you say?"' +---- + +=== References + +* https://rubystyle.guide#percent-q + +== Style/RedundantRegexpCharacterClass + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.85 +| - +|=== + +This cop checks for unnecessary single-element Regexp character classes. + +=== Examples + +[source,ruby] +---- +# bad +r = /[x]/ + +# good +r = /x/ + +# bad +r = /[\s]/ + +# good +r = /\s/ + +# good +r = /[ab]/ +---- + +== Style/RedundantRegexpEscape + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| Yes +| 0.85 +| - +|=== + +This cop checks for redundant escapes inside Regexp literals. + +=== Examples + +[source,ruby] +---- +# bad +%r{foo\/bar} + +# good +%r{foo/bar} + +# good +/foo\/bar/ + +# good +%r/foo\/bar/ + +# good +%r!foo\!bar! + +# bad +/a\-b/ + +# good +/a-b/ + +# bad +/[\+\-]\d/ + +# good +/[+\-]\d/ +---- + +== Style/RedundantReturn + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.10 +| 0.14 +|=== + +This cop checks for redundant `return` expressions. + +=== Examples + +[source,ruby] +---- +# These bad cases should be extended to handle methods whose body is +# if/else or a case expression with a default branch. + +# bad +def test + return something +end + +# bad +def test + one + two + three + return something +end + +# good +def test + return something if something_else +end + +# good +def test + if x + elsif y + else + end +end +---- + +==== AllowMultipleReturnValues: false (default) + +[source,ruby] +---- +# bad +def test + return x, y +end +---- + +==== AllowMultipleReturnValues: true + +[source,ruby] +---- +# good +def test + return x, y +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowMultipleReturnValues +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#no-explicit-return + +== Style/RedundantSelf + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.10 +| 0.13 +|=== + +This cop checks for redundant uses of `self`. + +The usage of `self` is only needed when: + +* Sending a message to same object with zero arguments in + presence of a method name clash with an argument or a local + variable. + +* Calling an attribute writer to prevent an local variable assignment. + +Note, with using explicit self you can only send messages with public or +protected scope, you cannot send private messages this way. + +Note we allow uses of `self` with operators because it would be awkward +otherwise. + +=== Examples + +[source,ruby] +---- +# bad +def foo(bar) + self.baz +end + +# good +def foo(bar) + self.bar # Resolves name clash with the argument. +end + +def foo + bar = 1 + self.bar # Resolves name clash with the local variable. +end + +def foo + %w[x y z].select do |bar| + self.bar == bar # Resolves name clash with argument of the block. + end +end +---- + +=== References + +* https://rubystyle.guide#no-self-unless-required + +== Style/RedundantSelfAssignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.90 +| - +|=== + +This cop checks for places where redundant assignments are made for in place +modification methods. + +This cop is marked as unsafe, because it can produce false positives for +user defined methods having one of the expected names, but not modifying +its receiver in place. + +=== Examples + +[source,ruby] +---- +# bad +args = args.concat(ary) +hash = hash.merge!(other) + +# good +args.concat(foo) +args += foo +hash.merge!(other) + +# bad +self.foo = foo.concat(ary) + +# good +foo.concat(ary) +self.foo += ary +---- + +== Style/RedundantSort + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.76 +| - +|=== + +This cop is used to identify instances of sorting and then +taking only the first or last element. The same behavior can +be accomplished without a relatively expensive sort by using +`Enumerable#min` instead of sorting and taking the first +element and `Enumerable#max` instead of sorting and taking the +last element. Similarly, `Enumerable#min_by` and +`Enumerable#max_by` can replace `Enumerable#sort_by` calls +after which only the first or last element is used. + +=== Examples + +[source,ruby] +---- +# bad +[2, 1, 3].sort.first +[2, 1, 3].sort[0] +[2, 1, 3].sort.at(0) +[2, 1, 3].sort.slice(0) + +# good +[2, 1, 3].min + +# bad +[2, 1, 3].sort.last +[2, 1, 3].sort[-1] +[2, 1, 3].sort.at(-1) +[2, 1, 3].sort.slice(-1) + +# good +[2, 1, 3].max + +# bad +arr.sort_by(&:foo).first +arr.sort_by(&:foo)[0] +arr.sort_by(&:foo).at(0) +arr.sort_by(&:foo).slice(0) + +# good +arr.min_by(&:foo) + +# bad +arr.sort_by(&:foo).last +arr.sort_by(&:foo)[-1] +arr.sort_by(&:foo).at(-1) +arr.sort_by(&:foo).slice(-1) + +# good +arr.max_by(&:foo) +---- + +== Style/RedundantSortBy + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.36 +| - +|=== + +This cop identifies places where `sort_by { ... }` can be replaced by +`sort`. + +=== Examples + +[source,ruby] +---- +# bad +array.sort_by { |x| x } +array.sort_by do |var| + var +end + +# good +array.sort +---- + +== Style/RegexpLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.30 +|=== + +This cop enforces using // or %r around regular expressions. + +=== Examples + +==== EnforcedStyle: slashes (default) + +[source,ruby] +---- +# bad +snake_case = %r{^[\dA-Z_]+$} + +# bad +regex = %r{ + foo + (bar) + (baz) +}x + +# good +snake_case = /^[\dA-Z_]+$/ + +# good +regex = / + foo + (bar) + (baz) +/x +---- + +==== EnforcedStyle: percent_r + +[source,ruby] +---- +# bad +snake_case = /^[\dA-Z_]+$/ + +# bad +regex = / + foo + (bar) + (baz) +/x + +# good +snake_case = %r{^[\dA-Z_]+$} + +# good +regex = %r{ + foo + (bar) + (baz) +}x +---- + +==== EnforcedStyle: mixed + +[source,ruby] +---- +# bad +snake_case = %r{^[\dA-Z_]+$} + +# bad +regex = / + foo + (bar) + (baz) +/x + +# good +snake_case = /^[\dA-Z_]+$/ + +# good +regex = %r{ + foo + (bar) + (baz) +}x +---- + +==== AllowInnerSlashes: false (default) + +[source,ruby] +---- +# If `false`, the cop will always recommend using `%r` if one or more +# slashes are found in the regexp string. + +# bad +x =~ /home\// + +# good +x =~ %r{home/} +---- + +==== AllowInnerSlashes: true + +[source,ruby] +---- +# good +x =~ /home\// +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `slashes` +| `slashes`, `percent_r`, `mixed` + +| AllowInnerSlashes +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#percent-r + +== Style/RescueModifier + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.34 +|=== + +This cop checks for uses of rescue in its modifier form. + +The cop to check `rescue` in its modifier form is added for following +reasons: + +* The syntax of modifier form `rescue` can be misleading because it + might led us to believe that `rescue` handles the given exception + but it actually rescue all exceptions to return the given rescue + block. In this case, value returned by handle_error or + SomeException. + +* Modifier form `rescue` would rescue all the exceptions. It would + silently skip all exception or errors and handle the error. + Example: If `NoMethodError` is raised, modifier form rescue would + handle the exception. + +=== Examples + +[source,ruby] +---- +# bad +some_method rescue handle_error + +# bad +some_method rescue SomeException + +# good +begin + some_method +rescue + handle_error +end + +# good +begin + some_method +rescue SomeException + handle_error +end +---- + +=== References + +* https://rubystyle.guide#no-rescue-modifiers + +== Style/RescueStandardError + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| - +|=== + +This cop checks for rescuing `StandardError`. There are two supported +styles `implicit` and `explicit`. This cop will not register an offense +if any error other than `StandardError` is specified. + +=== Examples + +==== EnforcedStyle: implicit + +[source,ruby] +---- +# `implicit` will enforce using `rescue` instead of +# `rescue StandardError`. + +# bad +begin + foo +rescue StandardError + bar +end + +# good +begin + foo +rescue + bar +end + +# good +begin + foo +rescue OtherError + bar +end + +# good +begin + foo +rescue StandardError, SecurityError + bar +end +---- + +==== EnforcedStyle: explicit (default) + +[source,ruby] +---- +# `explicit` will enforce using `rescue StandardError` +# instead of `rescue`. + +# bad +begin + foo +rescue + bar +end + +# good +begin + foo +rescue StandardError + bar +end + +# good +begin + foo +rescue OtherError + bar +end + +# good +begin + foo +rescue StandardError, SecurityError + bar +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `explicit` +| `implicit`, `explicit` +|=== + +== Style/ReturnNil + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.50 +| - +|=== + +This cop enforces consistency between 'return nil' and 'return'. + +Supported styles are: return, return_nil. + +=== Examples + +==== EnforcedStyle: return (default) + +[source,ruby] +---- +# bad +def foo(arg) + return nil if arg +end + +# good +def foo(arg) + return if arg +end +---- + +==== EnforcedStyle: return_nil + +[source,ruby] +---- +# bad +def foo(arg) + return if arg +end + +# good +def foo(arg) + return nil if arg +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `return` +| `return`, `return_nil` +|=== + +== Style/SafeNavigation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes (Unsafe) +| 0.43 +| 0.77 +|=== + +This cop transforms usages of a method call safeguarded by a non `nil` +check for the variable whose method is being called to +safe navigation (`&.`). If there is a method chain, all of the methods +in the chain need to be checked for safety, and all of the methods will +need to be changed to use safe navigation. We have limited the cop to +not register an offense for method chains that exceed 2 methods. + +Configuration option: ConvertCodeThatCanStartToReturnNil +The default for this is `false`. When configured to `true`, this will +check for code in the format `!foo.nil? && foo.bar`. As it is written, +the return of this code is limited to `false` and whatever the return +of the method is. If this is converted to safe navigation, +`foo&.bar` can start returning `nil` as well as what the method +returns. + +=== Examples + +[source,ruby] +---- +# bad +foo.bar if foo +foo.bar.baz if foo +foo.bar(param1, param2) if foo +foo.bar { |e| e.something } if foo +foo.bar(param) { |e| e.something } if foo + +foo.bar if !foo.nil? +foo.bar unless !foo +foo.bar unless foo.nil? + +foo && foo.bar +foo && foo.bar.baz +foo && foo.bar(param1, param2) +foo && foo.bar { |e| e.something } +foo && foo.bar(param) { |e| e.something } + +# good +foo&.bar +foo&.bar&.baz +foo&.bar(param1, param2) +foo&.bar { |e| e.something } +foo&.bar(param) { |e| e.something } +foo && foo.bar.baz.qux # method chain with more than 2 methods +foo && foo.nil? # method that `nil` responds to + +# Method calls that do not use `.` +foo && foo < bar +foo < bar if foo + +# When checking `foo&.empty?` in a conditional, `foo` being `nil` will actually +# do the opposite of what the author intends. +foo && foo.empty? + +# This could start returning `nil` as well as the return of the method +foo.nil? || foo.bar +!foo || foo.bar + +# Methods that are used on assignment, arithmetic operation or +# comparison should not be converted to use safe navigation +foo.baz = bar if foo +foo.baz + bar if foo +foo.bar > 2 if foo +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| ConvertCodeThatCanStartToReturnNil +| `false` +| Boolean + +| AllowedMethods +| `present?`, `blank?`, `presence`, `try`, `try!` +| Array +|=== + +== Style/Sample + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.30 +| - +|=== + +This cop is used to identify usages of `shuffle.first`, +`shuffle.last`, and `shuffle[]` and change them to use +`sample` instead. + +=== Examples + +[source,ruby] +---- +# bad +[1, 2, 3].shuffle.first +[1, 2, 3].shuffle.first(2) +[1, 2, 3].shuffle.last +[2, 1, 3].shuffle.at(0) +[2, 1, 3].shuffle.slice(0) +[1, 2, 3].shuffle[2] +[1, 2, 3].shuffle[0, 2] # sample(2) will do the same +[1, 2, 3].shuffle[0..2] # sample(3) will do the same +[1, 2, 3].shuffle(random: Random.new).first + +# good +[1, 2, 3].shuffle +[1, 2, 3].sample +[1, 2, 3].sample(3) +[1, 2, 3].shuffle[1, 3] # sample(3) might return a longer Array +[1, 2, 3].shuffle[1..3] # sample(3) might return a longer Array +[1, 2, 3].shuffle[foo, bar] +[1, 2, 3].shuffle(random: Random.new) +---- + +=== References + +* https://github.com/JuanitoFatas/fast-ruby#arrayshufflefirst-vs-arraysample-code + +== Style/SelfAssignment + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.19 +| 0.29 +|=== + +This cop enforces the use the shorthand for self-assignment. + +=== Examples + +[source,ruby] +---- +# bad +x = x + 1 + +# good +x += 1 +---- + +=== References + +* https://rubystyle.guide#self-assignment + +== Style/Semicolon + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.19 +|=== + +This cop checks for multiple expressions placed on the same line. +It also checks for lines terminated with a semicolon. + +This cop has `AllowAsExpressionSeparator` configuration option. +It allows `;` to separate several expressions on the same line. + +=== Examples + +[source,ruby] +---- +# bad +foo = 1; bar = 2; +baz = 3; + +# good +foo = 1 +bar = 2 +baz = 3 +---- + +==== AllowAsExpressionSeparator: false (default) + +[source,ruby] +---- +# bad +foo = 1; bar = 2 +---- + +==== AllowAsExpressionSeparator: true + +[source,ruby] +---- +# good +foo = 1; bar = 2 +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowAsExpressionSeparator +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#no-semicolon + +== Style/Send + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.33 +| - +|=== + +This cop checks for the use of the send method. + +=== Examples + +[source,ruby] +---- +# bad +Foo.send(:bar) +quuz.send(:fred) + +# good +Foo.__send__(:bar) +quuz.public_send(:fred) +---- + +=== References + +* https://rubystyle.guide#prefer-public-send + +== Style/SignalException + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.11 +| 0.37 +|=== + +This cop checks for uses of `fail` and `raise`. + +=== Examples + +==== EnforcedStyle: only_raise (default) + +[source,ruby] +---- +# The `only_raise` style enforces the sole use of `raise`. +# bad +begin + fail +rescue Exception + # handle it +end + +def watch_out + fail +rescue Exception + # handle it +end + +Kernel.fail + +# good +begin + raise +rescue Exception + # handle it +end + +def watch_out + raise +rescue Exception + # handle it +end + +Kernel.raise +---- + +==== EnforcedStyle: only_fail + +[source,ruby] +---- +# The `only_fail` style enforces the sole use of `fail`. +# bad +begin + raise +rescue Exception + # handle it +end + +def watch_out + raise +rescue Exception + # handle it +end + +Kernel.raise + +# good +begin + fail +rescue Exception + # handle it +end + +def watch_out + fail +rescue Exception + # handle it +end + +Kernel.fail +---- + +==== EnforcedStyle: semantic + +[source,ruby] +---- +# The `semantic` style enforces the use of `fail` to signal an +# exception, then will use `raise` to trigger an offense after +# it has been rescued. +# bad +begin + raise +rescue Exception + # handle it +end + +def watch_out + # Error thrown +rescue Exception + fail +end + +Kernel.fail +Kernel.raise + +# good +begin + fail +rescue Exception + # handle it +end + +def watch_out + fail +rescue Exception + raise 'Preferably with descriptive message' +end + +explicit_receiver.fail +explicit_receiver.raise +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `only_raise` +| `only_raise`, `only_fail`, `semantic` +|=== + +=== References + +* https://rubystyle.guide#prefer-raise-over-fail + +== Style/SingleArgumentDig + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.89 +| - +|=== + +Sometimes using dig method ends up with just a single +argument. In such cases, dig should be replaced with []. + +=== Examples + +[source,ruby] +---- +# bad +{ key: 'value' }.dig(:key) +[1, 2, 3].dig(0) + +# good +{ key: 'value' }[:key] +[1, 2, 3][0] + +# good +{ key1: { key2: 'value' } }.dig(:key1, :key2) +[1, [2, [3]]].dig(1, 1) + +# good +keys = %i[key1 key2] +{ key1: { key2: 'value' } }.dig(*keys) +---- + +== Style/SingleLineBlockParams + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| No +| 0.16 +| 0.47 +|=== + +This cop checks whether the block parameters of a single-line +method accepting a block match the names specified via configuration. + +For instance one can configure `reduce`(`inject`) to use |a, e| as +parameters. + +Configuration option: Methods +Should be set to use this cop. Array of hashes, where each key is the +method name and value - array of argument names. + +=== Examples + +==== Methods: [{reduce: %w[a b]}] + +[source,ruby] +---- +# bad +foo.reduce { |c, d| c + d } +foo.reduce { |_, _d| 1 } + +# good +foo.reduce { |a, b| a + b } +foo.reduce { |a, _b| a } +foo.reduce { |a, (id, _)| a + id } +foo.reduce { true } + +# good +foo.reduce do |c, d| + c + d +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Methods +| `{"reduce"=>["acc", "elem"]}`, `{"inject"=>["acc", "elem"]}` +| Array +|=== + +== Style/SingleLineMethods + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.19 +|=== + +This cop checks for single-line method definitions that contain a body. +It will accept single-line methods with no body. + +=== Examples + +[source,ruby] +---- +# bad +def some_method; body end +def link_to(url); {:name => url}; end +def @table.columns; super; end + +# good +def self.resource_class=(klass); end +def @table.columns; end +---- + +==== AllowIfMethodIsEmpty: true (default) + +[source,ruby] +---- +# good +def no_op; end +---- + +==== AllowIfMethodIsEmpty: false + +[source,ruby] +---- +# bad +def no_op; end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowIfMethodIsEmpty +| `true` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#no-single-line-methods + +== Style/SlicingWithRange + +NOTE: Required Ruby version: 2.6 + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.83 +| - +|=== + +This cop checks that arrays are sliced with endless ranges instead of +`ary[start..-1]` on Ruby 2.6+. + +=== Examples + +[source,ruby] +---- +# bad +items[1..-1] + +# good +items[1..] +---- + +== Style/SoleNestedConditional + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| Yes +| No +| 0.89 +| - +|=== + +If the branch of a conditional consists solely of a conditional node, +its conditions can be combined with the conditions of the outer branch. +This helps to keep the nesting level from getting too deep. + +=== Examples + +[source,ruby] +---- +# bad +if condition_a + if condition_b + do_something + end +end + +# good +if condition_a && condition_b + do_something +end +---- + +==== AllowModifier: false (default) + +[source,ruby] +---- +# bad +if condition_a + do_something if condition_b +end +---- + +==== AllowModifier: true + +[source,ruby] +---- +# good +if condition_a + do_something if condition_b +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowModifier +| `false` +| Boolean +|=== + +== Style/SpecialGlobalVars + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes (Unsafe) +| 0.13 +| 0.36 +|=== + +This cop looks for uses of Perl-style global variables. + +=== Examples + +==== EnforcedStyle: use_english_names (default) + +[source,ruby] +---- +# good +puts $LOAD_PATH +puts $LOADED_FEATURES +puts $PROGRAM_NAME +puts $ERROR_INFO +puts $ERROR_POSITION +puts $FIELD_SEPARATOR # or $FS +puts $OUTPUT_FIELD_SEPARATOR # or $OFS +puts $INPUT_RECORD_SEPARATOR # or $RS +puts $OUTPUT_RECORD_SEPARATOR # or $ORS +puts $INPUT_LINE_NUMBER # or $NR +puts $LAST_READ_LINE +puts $DEFAULT_OUTPUT +puts $DEFAULT_INPUT +puts $PROCESS_ID # or $PID +puts $CHILD_STATUS +puts $LAST_MATCH_INFO +puts $IGNORECASE +puts $ARGV # or ARGV +puts $MATCH +puts $PREMATCH +puts $POSTMATCH +puts $LAST_PAREN_MATCH +---- + +==== EnforcedStyle: use_perl_names + +[source,ruby] +---- +# good +puts $: +puts $" +puts $0 +puts $! +puts $@ +puts $; +puts $, +puts $/ +puts $\ +puts $. +puts $_ +puts $> +puts $< +puts $$ +puts $? +puts $~ +puts $= +puts $* +puts $& +puts $` +puts $' +puts $+ +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `use_english_names` +| `use_perl_names`, `use_english_names` +|=== + +=== References + +* https://rubystyle.guide#no-cryptic-perlisms + +== Style/StabbyLambdaParentheses + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.35 +| - +|=== + +Check for parentheses around stabby lambda arguments. +There are two different styles. Defaults to `require_parentheses`. + +=== Examples + +==== EnforcedStyle: require_parentheses (default) + +[source,ruby] +---- +# bad +->a,b,c { a + b + c } + +# good +->(a,b,c) { a + b + c} +---- + +==== EnforcedStyle: require_no_parentheses + +[source,ruby] +---- +# bad +->(a,b,c) { a + b + c } + +# good +->a,b,c { a + b + c} +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `require_parentheses` +| `require_parentheses`, `require_no_parentheses` +|=== + +=== References + +* https://rubystyle.guide#stabby-lambda-with-args + +== Style/StderrPuts + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.51 +| - +|=== + +This cop identifies places where `$stderr.puts` can be replaced by +`warn`. The latter has the advantage of easily being disabled by, +the `-W0` interpreter flag or setting `$VERBOSE` to `nil`. + +=== Examples + +[source,ruby] +---- +# bad +$stderr.puts('hello') + +# good +warn('hello') +---- + +=== References + +* https://rubystyle.guide#warn + +== Style/StringConcatenation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Pending +| No +| Yes (Unsafe) +| 0.89 +| - +|=== + +This cop checks for places where string concatenation +can be replaced with string interpolation. + +The cop can autocorrect simple cases but will skip autocorrecting +more complex cases where the resulting code would be harder to read. +In those cases, it might be useful to extract statements to local +variables or methods which you can then interpolate in a string. + +=== Examples + +[source,ruby] +---- +# bad +email_with_name = user.name + ' <' + user.email + '>' + +# good +email_with_name = "#{user.name} <#{user.email}>" +email_with_name = format('%s <%s>', user.name, user.email) +---- + +=== References + +* https://rubystyle.guide#string-interpolation + +== Style/StringHashKeys + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| No +| Yes (Unsafe) +| 0.52 +| 0.75 +|=== + +This cop checks for the use of strings as keys in hashes. The use of +symbols is preferred instead. + +=== Examples + +[source,ruby] +---- +# bad +{ 'one' => 1, 'two' => 2, 'three' => 3 } + +# good +{ one: 1, two: 2, three: 3 } +---- + +=== References + +* https://rubystyle.guide#symbols-as-keys + +== Style/StringLiterals + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.36 +|=== + +Checks if uses of quotes match the configured preference. + +=== Examples + +==== EnforcedStyle: single_quotes (default) + +[source,ruby] +---- +# bad +"No special symbols" +"No string interpolation" +"Just text" + +# good +'No special symbols' +'No string interpolation' +'Just text' +"Wait! What's #{this}!" +---- + +==== EnforcedStyle: double_quotes + +[source,ruby] +---- +# bad +'Just some text' +'No special chars or interpolation' + +# good +"Just some text" +"No special chars or interpolation" +"Every string in #{project} uses double_quotes" +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `single_quotes` +| `single_quotes`, `double_quotes` + +| ConsistentQuotesInMultiline +| `false` +| Boolean +|=== + +=== References + +* https://rubystyle.guide#consistent-string-literals + +== Style/StringLiteralsInInterpolation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.27 +| - +|=== + +This cop checks that quotes inside the string interpolation +match the configured preference. + +=== Examples + +==== EnforcedStyle: single_quotes (default) + +[source,ruby] +---- +# bad +result = "Tests #{success ? "PASS" : "FAIL"}" + +# good +result = "Tests #{success ? 'PASS' : 'FAIL'}" +---- + +==== EnforcedStyle: double_quotes + +[source,ruby] +---- +# bad +result = "Tests #{success ? 'PASS' : 'FAIL'}" + +# good +result = "Tests #{success ? "PASS" : "FAIL"}" +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `single_quotes` +| `single_quotes`, `double_quotes` +|=== + +== Style/StringMethods + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| Yes +| Yes +| 0.34 +| 0.34.2 +|=== + +This cop enforces the use of consistent method names +from the String class. + +=== Examples + +[source,ruby] +---- +# bad +'name'.intern +'var'.unfavored_method + +# good +'name'.to_sym +'var'.preferred_method +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| PreferredMethods +| `{"intern"=>"to_sym"}` +| +|=== + +== Style/Strip + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.36 +| - +|=== + +This cop identifies places where `lstrip.rstrip` can be replaced by +`strip`. + +=== Examples + +[source,ruby] +---- +# bad +'abc'.lstrip.rstrip +'abc'.rstrip.lstrip + +# good +'abc'.strip +---- + +== Style/StructInheritance + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.29 +| 0.86 +|=== + +This cop checks for inheritance from Struct.new. + +=== Examples + +[source,ruby] +---- +# bad +class Person < Struct.new(:first_name, :last_name) + def age + 42 + end +end + +# good +Person = Struct.new(:first_name, :last_name) do + def age + 42 + end +end +---- + +=== References + +* https://rubystyle.guide#no-extend-struct-new + +== Style/SymbolArray + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.49 +|=== + +This cop can check for array literals made up of symbols that are not +using the %i() syntax. + +Alternatively, it checks for symbol arrays using the %i() syntax on +projects which do not want to use that syntax. + +Configuration option: MinSize +If set, arrays with fewer elements than this value will not trigger the +cop. For example, a `MinSize` of `3` will not enforce a style on an +array of 2 or fewer elements. + +=== Examples + +==== EnforcedStyle: percent (default) + +[source,ruby] +---- +# good +%i[foo bar baz] + +# bad +[:foo, :bar, :baz] +---- + +==== EnforcedStyle: brackets + +[source,ruby] +---- +# good +[:foo, :bar, :baz] + +# bad +%i[foo bar baz] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `percent` +| `percent`, `brackets` + +| MinSize +| `2` +| Integer +|=== + +=== References + +* https://rubystyle.guide#percent-i + +== Style/SymbolLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.30 +| - +|=== + +This cop checks symbol literal syntax. + +=== Examples + +[source,ruby] +---- +# bad +:"symbol" + +# good +:symbol +---- + +== Style/SymbolProc + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.26 +| 0.64 +|=== + +Use symbols as procs when possible. + +=== Examples + +[source,ruby] +---- +# bad +something.map { |s| s.upcase } + +# good +something.map(&:upcase) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| IgnoredMethods +| `respond_to`, `define_method` +| Array +|=== + +== Style/TernaryParentheses + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.42 +| 0.46 +|=== + +This cop checks for the presence of parentheses around ternary +conditions. It is configurable to enforce inclusion or omission of +parentheses using `EnforcedStyle`. Omission is only enforced when +removing the parentheses won't cause a different behavior. + +`AllowSafeAssignment` option for safe assignment. +By safe assignment we mean putting parentheses around +an assignment to indicate "I know I'm using an assignment +as a condition. It's not a mistake." + +=== Examples + +==== EnforcedStyle: require_no_parentheses (default) + +[source,ruby] +---- +# bad +foo = (bar?) ? a : b +foo = (bar.baz?) ? a : b +foo = (bar && baz) ? a : b + +# good +foo = bar? ? a : b +foo = bar.baz? ? a : b +foo = bar && baz ? a : b +---- + +==== EnforcedStyle: require_parentheses + +[source,ruby] +---- +# bad +foo = bar? ? a : b +foo = bar.baz? ? a : b +foo = bar && baz ? a : b + +# good +foo = (bar?) ? a : b +foo = (bar.baz?) ? a : b +foo = (bar && baz) ? a : b +---- + +==== EnforcedStyle: require_parentheses_when_complex + +[source,ruby] +---- +# bad +foo = (bar?) ? a : b +foo = (bar.baz?) ? a : b +foo = bar && baz ? a : b + +# good +foo = bar? ? a : b +foo = bar.baz? ? a : b +foo = (bar && baz) ? a : b +---- + +==== AllowSafeAssignment: true (default) + +[source,ruby] +---- +# good +foo = (bar = baz) ? a : b +---- + +==== AllowSafeAssignment: false + +[source,ruby] +---- +# bad +foo = (bar = baz) ? a : b +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `require_no_parentheses` +| `require_parentheses`, `require_no_parentheses`, `require_parentheses_when_complex` + +| AllowSafeAssignment +| `true` +| Boolean +|=== + +== Style/TrailingBodyOnClass + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +This cop checks for trailing code after the class definition. + +=== Examples + +[source,ruby] +---- +# bad +class Foo; def foo; end +end + +# good +class Foo + def foo; end +end +---- + +== Style/TrailingBodyOnMethodDefinition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| - +|=== + +This cop checks for trailing code after the method definition. + +=== Examples + +[source,ruby] +---- +# bad +def some_method; do_stuff +end + +def f(x); b = foo + b[c: x] +end + +# good +def some_method + do_stuff +end + +def f(x) + b = foo + b[c: x] +end +---- + +== Style/TrailingBodyOnModule + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +This cop checks for trailing code after the module definition. + +=== Examples + +[source,ruby] +---- +# bad +module Foo extend self +end + +# good +module Foo + extend self +end +---- + +== Style/TrailingCommaInArguments + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.36 +| - +|=== + +This cop checks for trailing comma in argument lists. +The supported styles are: + +* `consistent_comma`: Requires a comma after the last argument, +for all parenthesized method calls with arguments. +* `comma`: Requires a comma after the last argument, but only for +parenthesized method calls where each argument is on its own line. +* `no_comma`: Requires that there is no comma after the last +argument. + +=== Examples + +==== EnforcedStyleForMultiline: consistent_comma + +[source,ruby] +---- +# bad +method(1, 2,) + +# good +method(1, 2) + +# good +method( + 1, 2, + 3, +) + +# good +method( + 1, 2, 3, +) + +# good +method( + 1, + 2, +) +---- + +==== EnforcedStyleForMultiline: comma + +[source,ruby] +---- +# bad +method(1, 2,) + +# good +method(1, 2) + +# bad +method( + 1, 2, + 3, +) + +# good +method( + 1, 2, + 3 +) + +# bad +method( + 1, 2, 3, +) + +# good +method( + 1, 2, 3 +) + +# good +method( + 1, + 2, +) +---- + +==== EnforcedStyleForMultiline: no_comma (default) + +[source,ruby] +---- +# bad +method(1, 2,) + +# good +method(1, 2) + +# good +method( + 1, + 2 +) +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyleForMultiline +| `no_comma` +| `comma`, `consistent_comma`, `no_comma` +|=== + +=== References + +* https://rubystyle.guide#no-trailing-params-comma + +== Style/TrailingCommaInArrayLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +This cop checks for trailing comma in array literals. +The configuration options are: + +* `consistent_comma`: Requires a comma after the +last item of all non-empty, multiline array literals. +* `comma`: Requires a comma after last item in an array, +but only when each item is on its own line. +* `no_comma`: Does not requires a comma after the +last item in an array + +=== Examples + +==== EnforcedStyleForMultiline: consistent_comma + +[source,ruby] +---- +# bad +a = [1, 2,] + +# good +a = [1, 2] + +# good +a = [ + 1, 2, + 3, +] + +# good +a = [ + 1, 2, 3, +] + +# good +a = [ + 1, + 2, +] +---- + +==== EnforcedStyleForMultiline: comma + +[source,ruby] +---- +# bad +a = [1, 2,] + +# good +a = [1, 2] + +# bad +a = [ + 1, 2, + 3, +] + +# good +a = [ + 1, 2, + 3 +] + +# bad +a = [ + 1, 2, 3, +] + +# good +a = [ + 1, 2, 3 +] + +# good +a = [ + 1, + 2, +] +---- + +==== EnforcedStyleForMultiline: no_comma (default) + +[source,ruby] +---- +# bad +a = [1, 2,] + +# good +a = [ + 1, + 2 +] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyleForMultiline +| `no_comma` +| `comma`, `consistent_comma`, `no_comma` +|=== + +=== References + +* https://rubystyle.guide#no-trailing-array-commas + +== Style/TrailingCommaInBlockArgs + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Disabled +| No +| Yes (Unsafe) +| 0.81 +| - +|=== + +This cop checks whether trailing commas in block arguments are +required. Blocks with only one argument and a trailing comma require +that comma to be present. Blocks with more than one argument never +require a trailing comma. + +=== Examples + +[source,ruby] +---- +# bad +add { |foo, bar,| foo + bar } + +# good +add { |foo, bar| foo + bar } + +# good +add { |foo,| foo } + +# good +add { foo } + +# bad +add do |foo, bar,| + foo + bar +end + +# good +add do |foo, bar| + foo + bar +end + +# good +add do |foo,| + foo +end + +# good +add do + foo + bar +end +---- + +== Style/TrailingCommaInHashLiteral + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.53 +| - +|=== + +This cop checks for trailing comma in hash literals. +The configuration options are: + +* `consistent_comma`: Requires a comma after the +last item of all non-empty, multiline hash literals. +* `comma`: Requires a comma after the last item in a hash, +but only when each item is on its own line. +* `no_comma`: Does not requires a comma after the +last item in a hash + +=== Examples + +==== EnforcedStyleForMultiline: consistent_comma + +[source,ruby] +---- +# bad +a = { foo: 1, bar: 2, } + +# good +a = { foo: 1, bar: 2 } + +# good +a = { + foo: 1, bar: 2, + qux: 3, +} + +# good +a = { + foo: 1, bar: 2, qux: 3, +} + +# good +a = { + foo: 1, + bar: 2, +} +---- + +==== EnforcedStyleForMultiline: comma + +[source,ruby] +---- +# bad +a = { foo: 1, bar: 2, } + +# good +a = { foo: 1, bar: 2 } + +# bad +a = { + foo: 1, bar: 2, + qux: 3, +} + +# good +a = { + foo: 1, bar: 2, + qux: 3 +} + +# bad +a = { + foo: 1, bar: 2, qux: 3, +} + +# good +a = { + foo: 1, bar: 2, qux: 3 +} + +# good +a = { + foo: 1, + bar: 2, +} +---- + +==== EnforcedStyleForMultiline: no_comma (default) + +[source,ruby] +---- +# bad +a = { foo: 1, bar: 2, } + +# good +a = { + foo: 1, + bar: 2 +} +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyleForMultiline +| `no_comma` +| `comma`, `consistent_comma`, `no_comma` +|=== + +== Style/TrailingMethodEndStatement + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.52 +| - +|=== + +This cop checks for trailing code after the method definition. + +=== Examples + +[source,ruby] +---- +# bad +def some_method +do_stuff; end + +def do_this(x) + baz.map { |b| b.this(x) } end + +def foo + block do + bar + end end + +# good +def some_method + do_stuff +end + +def do_this(x) + baz.map { |b| b.this(x) } +end + +def foo + block do + bar + end +end +---- + +== Style/TrailingUnderscoreVariable + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.31 +| 0.35 +|=== + +This cop checks for extra underscores in variable assignment. + +=== Examples + +[source,ruby] +---- +# bad +a, b, _ = foo() +a, b, _, = foo() +a, _, _ = foo() +a, _, _, = foo() + +# good +a, b, = foo() +a, = foo() +*a, b, _ = foo() +# => We need to know to not include 2 variables in a +a, *b, _ = foo() +# => The correction `a, *b, = foo()` is a syntax error +---- + +==== AllowNamedUnderscoreVariables: true (default) + +[source,ruby] +---- +# good +a, b, _something = foo() +---- + +==== AllowNamedUnderscoreVariables: false + +[source,ruby] +---- +# bad +a, b, _something = foo() +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| AllowNamedUnderscoreVariables +| `true` +| Boolean +|=== + +== Style/TrivialAccessors + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.77 +|=== + +This cop looks for trivial reader/writer methods, that could +have been created with the attr_* family of functions automatically. + +=== Examples + +[source,ruby] +---- +# bad +def foo + @foo +end + +def bar=(val) + @bar = val +end + +def self.baz + @baz +end + +# good +attr_reader :foo +attr_writer :bar + +class << self + attr_reader :baz +end +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| ExactNameMatch +| `true` +| Boolean + +| AllowPredicates +| `true` +| Boolean + +| AllowDSLWriters +| `false` +| Boolean + +| IgnoreClassMethods +| `false` +| Boolean + +| AllowedMethods +| `to_ary`, `to_a`, `to_c`, `to_enum`, `to_h`, `to_hash`, `to_i`, `to_int`, `to_io`, `to_open`, `to_path`, `to_proc`, `to_r`, `to_regexp`, `to_str`, `to_s`, `to_sym` +| Array +|=== + +=== References + +* https://rubystyle.guide#attr_family + +== Style/UnlessElse + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| - +|=== + +This cop looks for `unless` expressions with `else` clauses. + +=== Examples + +[source,ruby] +---- +# bad +unless foo_bar.nil? + # do something... +else + # do a different thing... +end + +# good +if foo_bar.present? + # do something... +else + # do a different thing... +end +---- + +=== References + +* https://rubystyle.guide#no-else-with-unless + +== Style/UnpackFirst + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.54 +| - +|=== + +This cop checks for accessing the first element of `String#unpack` +which can be replaced with the shorter method `unpack1`. + +=== Examples + +[source,ruby] +---- +# bad +'foo'.unpack('h*').first +'foo'.unpack('h*')[0] +'foo'.unpack('h*').slice(0) +'foo'.unpack('h*').at(0) + +# good +'foo'.unpack1('h*') +---- + +== Style/VariableInterpolation + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.20 +|=== + +This cop checks for variable interpolation (like "#@ivar"). + +=== Examples + +[source,ruby] +---- +# bad +"His name is #$name" +/check #$pattern/ +"Let's go to the #@store" + +# good +"His name is #{$name}" +/check #{$pattern}/ +"Let's go to the #{@store}" +---- + +=== References + +* https://rubystyle.guide#curlies-interpolate + +== Style/WhenThen + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| - +|=== + +This cop checks for `when;` uses in `case` expressions. + +=== Examples + +[source,ruby] +---- +# bad +case foo +when 1; 'baz' +when 2; 'bar' +end + +# good +case foo +when 1 then 'baz' +when 2 then 'bar' +end +---- + +=== References + +* https://rubystyle.guide#one-line-cases + +== Style/WhileUntilDo + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| - +|=== + +Checks for uses of `do` in multi-line `while/until` statements. + +=== Examples + +[source,ruby] +---- +# bad +while x.any? do + do_something(x.pop) +end + +# good +while x.any? + do_something(x.pop) +end +---- + +[source,ruby] +---- +# bad +until x.empty? do + do_something(x.pop) +end + +# good +until x.empty? + do_something(x.pop) +end +---- + +=== References + +* https://rubystyle.guide#no-multiline-while-do + +== Style/WhileUntilModifier + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.30 +|=== + +Checks for while and until statements that would fit on one line +if written as a modifier while/until. The maximum line length is +configured in the `Layout/LineLength` cop. + +=== Examples + +[source,ruby] +---- +# bad +while x < 10 + x += 1 +end + +# good +x += 1 while x < 10 +---- + +[source,ruby] +---- +# bad +until x > 10 + x += 1 +end + +# good +x += 1 until x > 10 +---- + +=== References + +* https://rubystyle.guide#while-as-a-modifier + +== Style/WordArray + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| Yes +| Yes +| 0.9 +| 0.36 +|=== + +This cop can check for array literals made up of word-like +strings, that are not using the %w() syntax. + +Alternatively, it can check for uses of the %w() syntax, in projects +which do not want to include that syntax. + +Configuration option: MinSize +If set, arrays with fewer elements than this value will not trigger the +cop. For example, a `MinSize` of `3` will not enforce a style on an +array of 2 or fewer elements. + +=== Examples + +==== EnforcedStyle: percent (default) + +[source,ruby] +---- +# good +%w[foo bar baz] + +# bad +['foo', 'bar', 'baz'] +---- + +==== EnforcedStyle: brackets + +[source,ruby] +---- +# good +['foo', 'bar', 'baz'] + +# bad +%w[foo bar baz] +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `percent` +| `percent`, `brackets` + +| MinSize +| `2` +| Integer + +| WordRegex +| `(?-mix:\A(?:\p{Word}|\p{Word}-\p{Word}|\n|\t)+\z)` +| +|=== + +=== References + +* https://rubystyle.guide#percent-w + +== Style/YodaCondition + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.49 +| 0.75 +|=== + +This cop can either enforce or forbid Yoda conditions, +i.e. comparison operations where the order of expression is reversed. +eg. `5 == x` + +=== Examples + +==== EnforcedStyle: forbid_for_all_comparison_operators (default) + +[source,ruby] +---- +# bad +99 == foo +"bar" != foo +42 >= foo +10 < bar + +# good +foo == 99 +foo == "bar" +foo <= 42 +bar > 10 +"#{interpolation}" == foo +/#{interpolation}/ == foo +---- + +==== EnforcedStyle: forbid_for_equality_operators_only + +[source,ruby] +---- +# bad +99 == foo +"bar" != foo + +# good +99 >= foo +3 < a && a < 5 +---- + +==== EnforcedStyle: require_for_all_comparison_operators + +[source,ruby] +---- +# bad +foo == 99 +foo == "bar" +foo <= 42 +bar > 10 + +# good +99 == foo +"bar" != foo +42 >= foo +10 < bar +---- + +==== EnforcedStyle: require_for_equality_operators_only + +[source,ruby] +---- +# bad +99 >= foo +3 < a && a < 5 + +# good +99 == foo +"bar" != foo +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| EnforcedStyle +| `forbid_for_all_comparison_operators` +| `forbid_for_all_comparison_operators`, `forbid_for_equality_operators_only`, `require_for_all_comparison_operators`, `require_for_equality_operators_only` +|=== + +=== References + +* https://en.wikipedia.org/wiki/Yoda_conditions + +== Style/ZeroLengthPredicate + +|=== +| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged + +| Enabled +| No +| Yes (Unsafe) +| 0.37 +| 0.39 +|=== + +This cop checks for numeric comparisons that can be replaced +by a predicate method, such as receiver.length == 0, +receiver.length > 0, receiver.length != 0, +receiver.length < 1 and receiver.size == 0 that can be +replaced by receiver.empty? and !receiver.empty?. + +=== Examples + +[source,ruby] +---- +# bad +[1, 2, 3].length == 0 +0 == "foobar".length +array.length < 1 +{a: 1, b: 2}.length != 0 +string.length > 0 +hash.size > 0 + +# good +[1, 2, 3].empty? +"foobar".empty? +array.empty? +!{a: 1, b: 2}.empty? +!string.empty? +!hash.empty? +---- diff --git a/manual/development.md b/docs/modules/ROOT/pages/development.adoc similarity index 55% rename from manual/development.md rename to docs/modules/ROOT/pages/development.adoc index 3a9555eaaab8..fc103207bc7a 100644 --- a/manual/development.md +++ b/docs/modules/ROOT/pages/development.adoc @@ -1,57 +1,67 @@ -## Add a new cop += Development -Use a rake task to generate a cop template. +This section of the documentation will teach you how to develop new cops. We'll +start with generating a cop template and then we'll address the various aspects +of its implementation (interacting with the AST, auto-correct, configuration) +and testing. -```sh -$ bundle exec rake new_cop[Department/Name] +== Create a new cop + +Use the bundled rake task `new_cop` to generate a cop template: + +[source,sh] +---- +$ bundle exec rake 'new_cop[Department/Name]' Files created: - lib/rubocop/cop/department/name.rb - spec/rubocop/cop/department/name_spec.rb File modified: - `require_relative 'rubocop/cop/department/name'` added into lib/rubocop.rb - A configuration for the cop is added into config/default.yml - - If you want to disable the cop by default, set `Enabled` option to false. Do 3 steps: 1. Add an entry to the "New features" section in CHANGELOG.md, e.g. "Add new `Department/Name` cop. ([@your_id][])" 2. Modify the description of Department/Name in config/default.yml 3. Implement your new cop in the generated file! -``` +---- -## Implementing the cop +== Basics -RuboCop uses [parser](https://github.com/whitequark/parser) to create the -Abstract Syntax Tree representation of the code. +RuboCop uses the https://github.com/whitequark/parser[parser] library to create the +Abstract Syntax Tree (AST) representation of the code. You can install `parser` gem and use `ruby-parse` command line utility to check what the AST looks like in the output. -```sh +[source,sh] +---- $ gem install parser -``` +---- And then try to parse a simple integer representation with `ruby-parse`: -```sh +[source,sh] +---- $ ruby-parse -e '1' (int 1) -``` +---- -Each expression surrounded by parens represents a node. The first +Each expression surrounded by parentheses represents a node in the AST. The first element is the node type and the tail contains the children with all information needed to represent the code. -Another example of a local variable `name` being assigned with the "John" -string value: +Here's another example - a local variable `name` being assigned the +string value "John": -```sh +[source,sh] +---- $ ruby-parse -e 'name = "John"' (lvasgn :name (str "John")) -``` +---- -### Inspecting the AST representation +=== Inspecting the AST representation Let's imagine we want to simplify statements from `!array.empty?` to `array.any?`: @@ -59,123 +69,154 @@ Let's imagine we want to simplify statements from `!array.empty?` to First, check what the bad code returns in the Abstract Syntax Tree representation. -```sh +[source,sh] +---- $ ruby-parse -e '!array.empty?' (send (send (send nil :array) :empty?) :!) -``` +---- Now, it's time to debug our expression using the REPL from RuboCop: -```sh +[source,sh] +---- $ bin/console -``` +---- First we need to declare the code that we want to match, and use the -[ProcessedSource](https://www.rubydoc.info/gems/rubocop/RuboCop/ProcessedSource) +https://www.rubydoc.info/gems/rubocop-ast/RuboCop/AST/ProcessedSource[ProcessedSource] that is a simple wrap to make the parser interpret the code and build the AST: -```ruby +[source,ruby] +---- code = '!something.empty?' source = RuboCop::ProcessedSource.new(code, RUBY_VERSION.to_f) node = source.ast # => s(:send, s(:send, s(:send, nil, :something), :empty?), :!) -``` +---- The node has a few attributes that can be useful in the journey: -```ruby +[source,ruby] +---- node.type # => :send node.children # => [s(:send, s(:send, nil, :something), :empty?), :!] node.source # => "!something.empty?" -``` +---- + +== Implementation -### Writing rules to make node pattern matches: +=== Writing Node Pattern Rules + +NOTE: You can write cops without using `NodePattern` (and many older cops don't use it), but it +generally simplifies a lot the code, as manual node matching and destructuring can be +quite verbose. Now that you're familiar with AST, you can learn a bit about the -[node pattern](https://www.rubydoc.info/gems/rubocop/RuboCop/NodePattern) +https://www.rubydoc.info/gems/rubocop-ast/RuboCop/AST/NodePattern[node pattern] and use patterns to match with specific nodes that you want to match. -You can learn more about Node Pattern [here](https://docs.rubocop.org/en/latest/node_pattern/). +You can learn more about Node Pattern https://github.com/rubocop-hq/rubocop-ast/blob/master/docs/modules/ROOT/pages/node_pattern.adoc[here]. Node pattern matches something very similar to the current output from AST representation, then let's start with something very generic: -```ruby +[source,ruby] +---- NodePattern.new('send').match(node) # => true -``` +---- It matches because the root is a `send` type. Now lets match it deeply using -parens to define details for sub-nodes. If you don't care about what an internal -node is, you can use `...` to skip it and just consider " a node". +parentheses to define details for sub-nodes. If you don't care about what an internal +node is, you can use `+...+` to skip it and just consider " a node". -```ruby +[source,ruby] +---- NodePattern.new('(send ...)').match(node) # => true NodePattern.new('(send (send ...) :!)').match(node) # => true NodePattern.new('(send (send (send ...) :empty?) :!)').match(node) # => true -``` +---- Sometimes it's hard to comprehend complex expressions you're building with the pattern, then, if you got lost with the node pattern parens surrounding deeply, try to use the `$` to capture the internal expression and check exactly each piece of the expression: -```ruby +[source,ruby] +---- NodePattern.new('(send (send (send $...) :empty?) :!)').match(node) # => [nil, :something] -``` +---- It's not needed to strictly receive a send in the internal node because maybe it can also be a literal array like: -```ruby +[source,ruby] +---- ![].empty? -``` +---- The code above has the following representation: -```ruby +[source,ruby] +---- => s(:send, s(:send, s(:array), :empty?), :!) -``` +---- -It's possible to skip the internal node with `...` to make sure that it's just +It's possible to skip the internal node with `+...+` to make sure that it's just another internal node: -```ruby +[source,ruby] +---- NodePattern.new('(send (send (...) :empty?) :!)').match(node) # => true -``` +---- -In other words, it says: "Match code calling `!.empty?`". +In other words, it says: "Match code calling ``!.empty?``". -Great! Now, lets implement our cop to simplifly such statements: +Great! Now, lets implement our cop to simplify such statements: -```sh -$ rake new_cop[Style/SimplifyNotEmptyWithAny] -``` +[source,sh] +---- +$ rake 'new_cop[Style/SimplifyNotEmptyWithAny]' +---- After the cop scaffold is generated, change the node matcher to match with the expression achieved previously: -```ruby -def_node_matcher :not_empty_call?, <<-PATTERN - (send (send (...) :empty?) :!) +[source,ruby] +---- +def_node_matcher :not_empty_call?, <<~PATTERN + (send (send $(...) :empty?) :!) PATTERN -``` +---- + +Note that we added a `$` sign to capture the "expression" in `!.empty?`, +it will become useful later. + +Get yourself familiar with the AST node hooks that +https://www.rubydoc.info/gems/parser/Parser/AST/Processor[`parser`] +and https://www.rubydoc.info/gems/rubocop-ast/RuboCop/AST/Traversal[`rubocop-ast`] +provide. As it starts with a `send` type, it's needed to implement the `on_send` method, as the cop scaffold already suggested: -```ruby +[source,ruby] +---- def on_send(node) return unless not_empty_call?(node) add_offense(node) end -``` +---- + +The `on_send` callback is the most used and can be optimized by restricting the acceptable +method names with a constant `RESTRICT_ON_SEND`. And the final cop code will look like something like this: -```ruby +[source,ruby] +---- module RuboCop module Cop module Style @@ -187,13 +228,15 @@ module RuboCop # # # good # array.any? - class SimplifyNotEmptyWithAny < Cop + class SimplifyNotEmptyWithAny < Base MSG = 'Use `.any?` and remove the negation part.'.freeze - def_node_matcher :not_empty_call?, <<-PATTERN - (send (send (...) :empty?) :!) + def_node_matcher :not_empty_call?, <<~PATTERN + (send (send $(...) :empty?) :!) PATTERN + RESTRICT_ON_SEND = [:!].freeze # optimization: don't call `on_send` unless + # the method name is in this list def on_send(node) return unless not_empty_call?(node) @@ -203,65 +246,99 @@ module RuboCop end end end -``` +---- Update the spec to cover the expected syntax: -```ruby -describe RuboCop::Cop::Style::SimplifyNotEmptyWithAny do - let(:config) { RuboCop::Config.new } - subject(:cop) { described_class.new(config) } - +[source,ruby] +---- +describe RuboCop::Cop::Style::SimplifyNotEmptyWithAny, :config do it 'registers an offense when using `!a.empty?`' do - expect_offense(<<-RUBY.strip_indent) + expect_offense(<<~RUBY) !array.empty? ^^^^^^^^^^^^^ Use `.any?` and remove the negation part. RUBY end it 'does not register an offense when using `.any?` or `.empty?`' do - expect_no_offenses(<<-RUBY.strip_indent) + expect_no_offenses(<<~RUBY) array.any? array.empty? RUBY end end -``` +---- + +If your code has variables of different lengths, you can use `%{foo}`, +`^{foo}`, and `_{foo}` to format your template; you can also abbreviate +offense messages with `[...]`: + +[source,ruby] +---- +%w[raise fail].each do |keyword| + expect_offense(<<~RUBY, keyword: keyword) + %{keyword}(RuntimeError, msg) + ^{keyword}^^^^^^^^^^^^^^^^^^^ Redundant `RuntimeError` argument [...] + RUBY + +%w[has_one has_many].each do |type| + expect_offense(<<~RUBY, type: type) + class Book + %{type} :chapter, foreign_key: 'book_id' + _{type} ^^^^^^^^^^^^^^^^^^^^^^ Specifying the default [...] + end + RUBY +end +---- -### Autocorrect feature +=== Auto-correct -The autocorrect can help humans automatically fixing offenses earlier detected. -It's necessary to define the `autocorrect` method that returns a lambda -[rewriter](https://github.com/whitequark/parser/blob/master/lib/parser/rewriter.rb) -with the corrector where you can give instructions about what to do with the +The auto-correct can help humans automatically fix offenses that have been detected. +It's necessary to `extend AutoCorrector`. +The method `add_offense` yields a corrector object that is a thin wrapper on +https://www.rubydoc.info/gems/parser/Parser/Source/TreeRewriter[parser's TreeRewriter] +to which you can give instructions about what to do with the offensive node. Let's start with a simple spec to cover it: -```ruby -it 'autocorrect `!a.empty?` to `a.any?` ' do - expect(autocorrect_source('!a.empty?')).to eq('a.any?') +[source,ruby] +---- +it 'corrects `!a.empty?`' do + expect_offense(<<~RUBY) + !array.empty? + ^^^^^^^^^^^^^ Use `.any?` and remove the negation part. + RUBY + + expect_correction(<<~RUBY) + array.any? + RUBY end -``` +---- + +And then add the autocorrecting block on the cop side: -And then define the `autocorrect` method on the cop side: +[source,ruby] +---- +extend AutoCorrector -```ruby -def autocorrect(node) - lambda do |corrector| - internal_expression = node.children[0].children[0].source - corrector.replace(node.loc.expression, "#{internal_expression}.any?") +def on_send(node) + expression = not_empty_call?(node) + return unless expression + + add_offense(node) do |corrector| + corrector.replace(node, "#{expression.source}.any?") end end -``` +---- -The corrector allows you to `insert_after` and `insert_before` or -`replace` in a specific range of the code. +The corrector allows you to `insert_after`, `insert_before`, `wrap` or +`replace` a specific node or in any specific range of the code. -The range can be determined on `node.location` where it brings specific +Range can be determined on `node.location` where it brings specific ranges for expression or other internal information that the node holds. -### Configuration +=== Configuration Each cop can hold a configuration and you can refer to `cop_config` in the instance and it will bring a hash with options declared in the `.rubocop.yml` @@ -270,26 +347,29 @@ file. For example, lets imagine we want to make configurable to make the replacement works with other method than `.any?`: -```yml +[source,yml] +---- Style/SimplifyNotEmptyWithAny: Enabled: true ReplaceAnyWith: "size > 0" -``` +---- And then on the autocorrect method, you just need to use the `cop_config` it: -```ruby -def autocorrect(node) - lambda do |corrector| - internal_expression = node.children[0].children[0].source - replacement = cop_config['ReplaceAnyWith'] || "any?" - new_expression = "#{internal_expression}.#{replacement}" - corrector.replace(node.loc.expression, new_expression) +[source,ruby] +---- +def on_send(node) + expression = not_empty_call?(node) + return unless expression + + add_offense(node) do |corrector| + replacement = cop_config['ReplaceAnyWith'] || 'any?' + corrector.replace(node, "#{expression.source}.#{replacement}") end end -``` +---- -### Documentation +== Documentation Every new cop requires explanation and examples to make it easy for the community to understand its purpose. This documentation is generated by `yard` and is added @@ -297,7 +377,8 @@ directly into the `cop.rb` file. For every `SupportedStyle` and unique configuration you have included in the cop, there needs to be examples. Examples must have valid Ruby syntax. Do not use upticks. -```ruby +[source,ruby] +---- module Department # Description of your cop. Include description of ALL config options. Particularly # ones that take booleans and arrays, because we generally do not show examples for @@ -349,7 +430,7 @@ module Department # class YourCop # ... -``` +---- Take note of the placement and spacing of all the documentation pieces. Such as config keys being in alphabetical order, the `(default)` being specified, and one empty line @@ -359,17 +440,26 @@ we strive to make this consistent. PRs improving RuboCop documentation are very Run `rake generate_cops_documentation` to apply your `yard` documentation into the manual. CI will fail if the manual and `yard` comments do not match exactly. `rake default` will also generate the new documentation. -### Testing your cop in a real codebase +== Testing your cop in a real codebase Generally, is a good practice to check if your cop is working properly over a -huge codebase to guarantee it's working in a range of different syntaxes. +significant codebase (e.g. Rails or some big project you're working on) to +guarantee it's working in a range of different syntaxes. + +There are several ways to do this. Two common approaches: + +. From within your local `rubocop` repo, run `exe/rubocop ~/your/other/codebase`. +. From within the other codebase's `Gemfile`, set a path to your local repo like this: `gem 'rubocop', path: '/full/path/to/rubocop'`. Then run `rubocop` within your codebase. + +With approach #2, you can use local versions of RuboCop extension repos such as `rubocop-rspec` as well. To make it fast and do not get confused with other cops in action, you can use `--only` parameter in the command line to filter by your cop name: -```sh +[source,sh] +---- $ rubocop --only Style/SimplifyNotEmptyWithAny -``` +---- In the end, do not forget to run `rake generate_cops_documentation` to update the docs. diff --git a/docs/modules/ROOT/pages/extensions.adoc b/docs/modules/ROOT/pages/extensions.adoc new file mode 100644 index 000000000000..81081a41d02d --- /dev/null +++ b/docs/modules/ROOT/pages/extensions.adoc @@ -0,0 +1,87 @@ += Extensions + +It's possible to extend RuboCop with custom cops and formatters. + +== Loading Extensions + +Besides the `--require` command line option you can also specify ruby +files that should be loaded with the optional `require` directive in the +`.rubocop.yml` file: + +[source,yaml] +---- +require: + - ../my/custom/file.rb + - rubocop-extension +---- + +NOTE: The paths are directly passed to `Kernel.require`. If your +extension file is not in `$LOAD_PATH`, you need to specify the path as +relative path prefixed with `./` explicitly or absolute path. Paths +starting with a `.` are resolved relative to `.rubocop.yml`. + +== Custom Cops + +You can configure the custom cops in your `.rubocop.yml` just like any +other cop. + +=== Writing your own Cops + +If you'd like to create an extension gem, you can use https://github.com/rubocop-hq/rubocop-extension-generator[rubocop-extension-generator]. + +See xref:development.adoc[development] to learn how to implement a cop. + +=== Known Custom Cops + +* https://github.com/rubocop-hq/rubocop-performance[rubocop-performance] - +Performance optimization analysis +* https://github.com/rubocop-hq/rubocop-rails[rubocop-rails] - +Rails-specific analysis +* https://github.com/rubocop-hq/rubocop-rspec[rubocop-rspec] - +RSpec-specific analysis +* https://github.com/rubocop-hq/rubocop-minitest[rubocop-minitest] - +Minitest-specific analysis +* https://github.com/covermymeds/rubocop-thread_safety[rubocop-thread_safety] - +Thread-safety analysis +* https://github.com/milch/rubocop-require_tools[rubocop-require_tools] - +Dynamic analysis for missing require statements +* https://github.com/puppetlabs/rubocop-i18n[rubocop-i18n] - +i18n wrapper function analysis (gettext and rails-i18n) +* https://github.com/rubocop-hq/rubocop-sequel[rubocop-sequel] - +Code style checking for Sequel gem +* https://github.com/chef/cookstyle[cookstyle] - +Custom cops and config defaults for Chef Infra Cookbooks +* https://github.com/rubocop-hq/rubocop-rake[rubocop-rake] - +Rake-specific analysis +* https://github.com/utkarsh2102/rubocop-packaging[rubocop-packaging] - +Upstream best practices and coding conventions for downstream compatibility. + +Any extensions missing? Send us a Pull Request! + +== Custom Formatters + +You can customize RuboCop's output format with custom formatters. + +=== Creating a Custom Formatter + +To implement a custom formatter, you need to subclass +`RuboCop::Formatter::BaseFormatter` and override some methods, +or implement all formatter API methods by duck typing. + +Please see the documents below for more formatter API details. + +* https://www.rubydoc.info/gems/rubocop/RuboCop/Formatter/BaseFormatter[RuboCop::Formatter::BaseFormatter] +* https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Offense[RuboCop::Cop::Offense] +* https://www.rubydoc.info/gems/parser/Parser/Source/Range[Parser::Source::Range] + +=== Using a Custom Formatter from the Command Line + +You can tell RuboCop to use your custom formatter with a combination of +`--format` and `--require` option. +For example, when you have defined `MyCustomFormatter` in +`./path/to/my_custom_formatter.rb`, you would type this command: + +[source,sh] +---- +$ rubocop --require ./path/to/my_custom_formatter --format MyCustomFormatter +---- diff --git a/manual/formatters.md b/docs/modules/ROOT/pages/formatters.adoc similarity index 66% rename from manual/formatters.md rename to docs/modules/ROOT/pages/formatters.adoc index 158e8f779b2b..6c64c1c34ea1 100644 --- a/manual/formatters.md +++ b/docs/modules/ROOT/pages/formatters.adoc @@ -1,11 +1,11 @@ -## Formatters += Formatters You can change the output format of RuboCop by specifying formatters with the `-f/--format` option. RuboCop ships with several built-in formatters, and also you can create your custom formatter. Additionally the output can be redirected to a file instead of `$stdout` with the `-o/--out` option. -Some of the built-in formatters produce **machine-parsable** output +Some of the built-in formatters produce *machine-parsable* output and they are considered public APIs. The rest of the formatters are for humans, so parsing their outputs is discouraged. @@ -13,7 +13,8 @@ You can enable multiple formatters at the same time by specifying `-f/--format` The `-o/--out` option applies to the previously specified `-f/--format`, or the default `progress` format if no `-f/--format` is specified before the `-o/--out` option. -```sh +[source,sh] +---- # Simple format to $stdout. $ rubocop --format simple @@ -37,18 +38,19 @@ $ rubocop --out result.txt --format simple # ~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~ # | | # default format $stdout -``` +---- -You can also load [custom formatters](extensions.md#custom-formatters). +You can also load xref:extensions.adoc#custom-formatters[custom formatters]. -### Progress Formatter (default) +== Progress Formatter (default) The default `progress` formatter outputs a character for each inspected file, and at the end it displays all detected offenses in the `clang` format. A `.` represents a clean file, and each of the capital letters means the severest offense (convention, warning, error, or fatal) found in a file. -```sh +[source,sh] +---- $ rubocop Inspecting 26 files ..W.C....C..CWCW.C...WC.CC @@ -62,26 +64,28 @@ lib/foo.rb:6:5: C: Style/Documentation: Missing top-level class documentation co ... 26 files inspected, 46 offenses detected -``` +---- -### Auto Gen Formatter +== Auto Gen Formatter Behaves like Progress Formatter except that it will not show any offenses. -```sh -$ rubocop +[source,sh] +---- +$ rubocop --format autogenconf Inspecting 26 files ..W.C....C..CWCW.C...WC.CC 26 files inspected, 46 offenses detected -``` +---- -### Clang Style Formatter +== Clang Style Formatter The `clang` formatter displays the offenses in a manner similar to `clang`: -```sh -$ rubocop test.rb +[source,sh] +---- +$ rubocop --format clang test.rb Inspecting 1 file W @@ -101,15 +105,16 @@ test.rb:4:5: W: Layout/DefEndAlignment: end at 4, 4 is not aligned with if at 2, ^^^ 1 file inspected, 4 offenses detected -``` +---- -### Fuubar Style Formatter +== Fuubar Style Formatter The `fuubar` style formatter displays a progress bar and shows details of offenses in the `clang` format as soon as they are detected. -This is inspired by the [Fuubar](https://github.com/thekompanee/fuubar) formatter for RSpec. +This is inspired by the https://github.com/thekompanee/fuubar[Fuubar] formatter for RSpec. -```sh +[source,sh] +---- $ rubocop --format fuubar lib/foo.rb.rb:1:1: C: Naming/MethodName: Use snake_case for method names. def badName @@ -118,26 +123,45 @@ lib/bar.rb:13:14: W: Lint/DeprecatedClassMethods: File.exists? is deprecated in File.exists?(path) ^^^^^^^ 22/53 files |======== 43 ========> | ETA: 00:00:02 -``` +---- + +== Pacman Style Formatter + +The `pacman` style formatter prints a PACDOT per every file to be analyzed. Pacman will "eat" one PACDOT per file when no offense is detected. Otherwise it will print a Ghost. +This is inspired by the https://github.com/go-labs/rspec_pacman_formatter[Pacman] formatter for RSpec. + +[source,sh] +---- +$ rubocop --format pacman +Eating 31 files +src/foo.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true. +src/bar.rb:14:15: C: Style/MutableConstant: Freeze mutable objects assigned to constants. + GHOST = 'ᗣ' + ^^^ +....ᗣ...ᗣ...ᗧ•••••••••••••••••• +31 examples, 2 failures +---- -### Emacs Style Formatter +== Emacs Style Formatter -**Machine-parsable** +*Machine-parsable* The `emacs` formatter displays the offenses in a format suitable for consumption by `Emacs` (and possibly other tools). -```sh +[source,sh] +---- $ rubocop --format emacs test.rb /Users/bozhidar/projects/test.rb:1:1: C: Naming/MethodName: Use snake_case for method names. /Users/bozhidar/projects/test.rb:2:3: C: Style/IfUnlessModifier: Favor modifier if/unless usage when you have a single-line body. Another good alternative is the usage of control flow &&/||. /Users/bozhidar/projects/test.rb:4:5: W: Layout/DefEndAlignment: end at 4, 4 is not aligned with if at 2, 2 -``` +---- -### Simple Formatter +== Simple Formatter The name of the formatter says it all :-) -```sh +[source,sh] +---- $ rubocop --format simple test.rb == test.rb == C: 1: 5: Naming/MethodName: Use snake_case for method names. @@ -146,32 +170,39 @@ C: 2: 3: Style/IfUnlessModifier: Favor modifier if usage when having a single- W: 4: 5: Layout/DefEndAlignment: end at 4, 4 is not aligned with if at 2, 2 1 file inspected, 4 offenses detected -``` +---- -### Quiet Formatter +== Quiet Formatter -Behaves like Simple Formatter if there are offenses. Completely quiet otherwise. +Behaves like Simple Formatter if there are offenses. Completely quiet otherwise: -### File List Formatter +[source,sh] +---- +$ rubocop --format quiet +---- - **Machine-parsable** +== File List Formatter + +*Machine-parsable* Sometimes you might want to just open all files with offenses in your favorite editor. This formatter outputs just the names of the files with offenses in them and makes it possible to do something like: -```sh +[source,sh] +---- $ rubocop --format files | xargs vim -``` +---- -### JSON Formatter +== JSON Formatter -**Machine-parsable** +*Machine-parsable* You can get RuboCop's inspection result in JSON format by passing `--format json` option in command line. The JSON structure is like the following example: -```javascript +[source,javascript] +---- { "metadata": { "rubocop_version": "0.50.0", @@ -215,9 +246,54 @@ The JSON structure is like the following example: "inspected_file_count": 2 } } -``` - -### Offense Count Formatter +---- + +== JUnit Style Formatter + +*Machine-parsable* + +The `junit` style formatter provides the JUnit formatting. +This formatter is based on the https://github.com/mikian/rubocop-junit-formatter[rubocop-junit-formatter gem]. + +[source,sh] +---- +$ rubocop --format junit + + + + + + /tmp/src/example.rb:1:1 + + + + + /tmp/src/example.rb:1:5 + + + + + /tmp/src/example.rb:2:8 + + + + +---- + +The `junit` style formatter is very useful for continuous integration systems +such as Jenkins, most of which support junit formatting when parsing test +results. A typical invocation in this type of scenario might look like: + +[source,sh] +---- +$ rubocop --format junit --out test-reports/junit.xml +---- + +Since there is one XML node for each cop for each file, the size of the resulting +XML can get quite large. If it is too large for you, you can restrict the output +to just failures by adding the `--display-only-failed` option. + +== Offense Count Formatter Sometimes when first applying RuboCop to a codebase, it's nice to be able to see where most of your style cleanup is going to be spent. @@ -225,53 +301,56 @@ see where most of your style cleanup is going to be spent. With this in mind, you can use the offense count formatter to outline the offended cops and the number of offenses found for each by running: -```sh +[source,sh] +---- $ rubocop --format offenses -36 Metrics/LineLength +36 Layout/LineLength 18 Style/StringLiterals 13 Style/Documentation 10 Style/ExpandPathArguments 8 Style/EmptyMethod 6 Layout/IndentationConsistency -4 Lint/HandleExceptions +4 Lint/SuppressedException 3 Layout/EmptyLinesAroundAccessModifier 2 Layout/ExtraSpacing 1 Layout/AccessModifierIndentation 1 Style/ClassAndModuleChildren -- 102 Total +---- -``` - -### Worst Offenders Formatter +== Worst Offenders Formatter Similar to the Offense Count formatter, but lists the files which need the most attention: -```sh +[source,sh] +---- $ rubocop --format worst 89 this/file/is/really/bad.rb 2 much/better.rb -- 91 Total -``` +---- -### HTML Formatter +== HTML Formatter -Useful for CI environments. It will create an HTML report like [this](http://f.cl.ly/items/0M3029412x3O091a1X1R/expected.html). +Useful for CI environments. It will create an HTML report like http://f.cl.ly/items/0M3029412x3O091a1X1R/expected.html[this]. -```sh +[source,sh] +---- $ rubocop --format html -o rubocop.html -``` +---- -### TAP Formatter +== TAP Formatter - **Machine-parsable** +*Machine-parsable* -Useful for CI environments, it will format report following the [Test Anything Protocol](https://testanything.org). +Useful for CI environments, it will format report following the https://testanything.org[Test Anything Protocol]. -```sh +[source,sh] +---- $ rubocop --format tap 1..3 not ok 1 - lib/rubocop.rb @@ -288,4 +367,4 @@ not ok 3 - exe/rubocop # ^ 3 files inspected, 3 offenses detected -``` +---- diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc new file mode 100644 index 000000000000..ee3876a76d11 --- /dev/null +++ b/docs/modules/ROOT/pages/index.adoc @@ -0,0 +1,64 @@ += RuboCop + +[,Officer Alex J. Murphy / RoboCop] +____ +Role models are important. +____ + +== Overview + +*RuboCop* is a Ruby static code analyzer (a.k.a. linter) and code +formatter. Out of the box it will enforce many of the guidelines +outlined in the community https://rubystyle.guide[Ruby Style Guide]. + +RuboCop packs a lot of features on top of what you'd normally expect from a +linter: + +* Works with every major Ruby implementation +* Auto-correction of many of the code offenses it detects +* Robust code formatting capabilities +* Multiple result formatters for both interactive use and for feeding data into other tools +* Ability to have different configuration for different parts of your codebase +* Ability to disable certain cops only for specific files or parts of files +* Extremely flexible configuration that allows you to adapt RuboCop to pretty much every style and preference +* It's easy to extend RuboCop with custom cops and formatters +* A vast number of ready-made extensions (e.g. `rubocop-rails`, `rubocop-rspec`, `rubocop-performance` and `rubocop-minitest`) +* Wide editor/IDE support +* Many online services use RuboCop internally (e.g. HoundCI, Sider and CodeClimate) +* Best logo/stickers ever + +The project is closely tied to several efforts to document and promote the best practices of the Ruby community: + +* https://rubystyle.guide/[Ruby Style Guide] +* https://rails.rubystyle.guide/[Rails Style Guide] +* https://rspec.rubystyle.guide/[RSpec Style Guide] +* https://minitest.rubystyle.guide/[Minitest Style Guide] + +A long-term goal of RuboCop (and its core extensions) is to cover with cops all the guidelines from the community style guides. + +== Philosophy + +Early on RuboCop aimed to be an opinionated linter/formater that adhered very closely to the Ruby Style Guide (think `gofmt` and the like). +In those days cops supported just a single style and you couldn't even turn individual cops off. Eventually, we realized +that in the Ruby community there were some many competing styles and preferences that it was going to be really +challenging to find one set of defaults that makes everyone happy. Part of this was Ruby's own culture and philosophy, +part was the lack of common standards for almost 20 years. It's hard to undo any of those, but it's also not really necessary. + +The early feedback we got lead us to adopt of philosophy of (extreme) configurability and flexibility, and trying to account for every _common_ style +of programming in Ruby. While we still believe that there's a lot of merit to just sticking to the community +style guides, we acknowledge that Ruby is all about diversity and doing things the way that makes you happy. Whatever +style preferences you have RuboCop is there for you. That's our promises and our guarantee. Within the subjective limits of sanity that is. + +== Next Steps + +So, what to do next? While you can peruse the documentation in whatever way you'd like, here are +a few recommendations: + +* See xref:usage/basic_usage.adoc["Basic Usage"] to get yourself familiar with RuboCop's +capabilities. +* Adjust RuboCop to your style/preferences. RuboCop is an extremely flexible tool and most aspects of its behavior +can be tweaked via various https://github.com/rubocop-hq/rubocop/blob/master/config/default.yml[configuration +options]. See xref:configuration.adoc["Configuration"] for more details. +* See xref:versioning.adoc["Versioning"] for information about RuboCop versioning, +updates, and the process of introducing new cops. +* Explore the xref:extensions.adoc[existing extensions]. diff --git a/docs/modules/ROOT/pages/installation.adoc b/docs/modules/ROOT/pages/installation.adoc new file mode 100644 index 000000000000..c8a04ae50fae --- /dev/null +++ b/docs/modules/ROOT/pages/installation.adoc @@ -0,0 +1,44 @@ += Installation + +RuboCop's installation is pretty standard: + +[source,sh] +---- +$ gem install rubocop +---- + +If you'd rather install RuboCop using `bundler`, don't require it in your `Gemfile`: + +[source,rb] +---- +gem 'rubocop', require: false +---- + +RuboCop's development is moving at a very rapid pace and there are +often backward-incompatible changes between minor releases (since we +haven't reached version 1.0 yet). To prevent an unwanted RuboCop update you +might want to use a conservative version locking in your `Gemfile`: + +[source,rb] +---- +gem 'rubocop', '~> 0.93.1', require: false +---- + +NOTE: You can check out our progress on the road to version 1.0 https://github.com/rubocop-hq/rubocop/milestone/4[here]. +You can also help us get there faster! :-) + +.A Modular RuboCop +**** +Originally RuboCop bundled cops focused on performance and Ruby on Rails, but those were +extracted into their own gems eventually: + +* the performance cops were extracted in `rubocop-performance` and were removed from the main gem in 0.68 +* the Ruby on Rails cops were extracted in `rubocop-rails` and were removed from the main gem in 0.72 + +You'll need to install those gems separately if you'd like to use them. +See https://metaredux.com/posts/2019/05/22/a-modular-rubocop.html[this article] for more details. + +Additionally, RuboCop's AST logic was extracted to `rubocop-ast` in RuboCop 0.84. While this change is +transparent to RuboCop's users (`rubocop-ast` is a runtime dependency of `rubocop`), it's good to be +aware that you can leverage RuboCop's AST node extensions and AST node pattern matching outside of RuboCop. +**** diff --git a/docs/modules/ROOT/pages/integration_with_other_tools.adoc b/docs/modules/ROOT/pages/integration_with_other_tools.adoc new file mode 100644 index 000000000000..0fb71dd5e9e1 --- /dev/null +++ b/docs/modules/ROOT/pages/integration_with_other_tools.adoc @@ -0,0 +1,120 @@ += Integration with Other Tools + +== Editor integration + +=== Emacs + +https://github.com/rubocop-hq/rubocop-emacs[rubocop.el] is a simple +Emacs interface for RuboCop. It allows you to run RuboCop inside Emacs +and quickly jump between problems in your code. + +https://github.com/flycheck/flycheck[flycheck] > 0.9 also supports +RuboCop and uses it by default when available. + +=== Vim + +RuboCop is supported by +https://github.com/scrooloose/syntastic[syntastic], +https://github.com/neomake/neomake[neomake], +and https://github.com/w0rp/ale[ale]. + +There is also the https://github.com/ngmy/vim-rubocop[vim-rubocop] plugin. + +=== Sublime Text + +If you're a ST user you might find the +https://github.com/pderichs/sublime_rubocop[Sublime RuboCop plugin] +useful. + +=== Brackets + +The https://github.com/smockle-archive/brackets-rubocop[brackets-rubocop] +extension displays RuboCop results in Brackets. +It can be installed via the extension manager in Brackets. + +=== TextMate2 + +The https://github.com/mrdougal/textmate2-rubocop[textmate2-rubocop] +bundle displays formatted RuboCop results in a new window. +Installation instructions can be found https://github.com/mrdougal/textmate2-rubocop#installation[here]. + +=== Atom + +The https://github.com/AtomLinter/linter-rubocop[linter-rubocop] plugin for Atom's +https://github.com/AtomLinter/Linter[linter] runs RuboCop and highlights the offenses in Atom. + +=== LightTable + +The https://github.com/seancaffery/lt-rubocop[lt-rubocop] plugin +provides LightTable integration. + +=== RubyMine / Intellij IDEA + +RuboCop support is https://www.jetbrains.com/help/idea/2017.1/rubocop.html[available] as of the 2017.1 releases. + +=== Visual Studio Code + +The https://marketplace.visualstudio.com/items?itemName=rebornix.Ruby[ruby] extension +provides RuboCop integration for Visual Studio Code. RuboCop is also used for the formatting +capabilities of this extension. + +=== Other Editors + +Here's one great opportunity to contribute to RuboCop - implement +RuboCop integration for your favorite editor. + +== Git pre-commit hook integration + +https://github.com/brigade/overcommit[overcommit] is a fully configurable and +extendable Git commit hook manager. To use RuboCop with overcommit, add the +following to your `.overcommit.yml` file: + +[source,yaml] +---- +PreCommit: + RuboCop: + enabled: true +---- + +== Guard integration + +If you're fond of https://github.com/guard/guard[Guard] you might +like +https://github.com/yujinakayama/guard-rubocop[guard-rubocop]. It +allows you to automatically check Ruby code style with RuboCop when +files are modified. + +== Rake integration + +To use RuboCop in your `Rakefile` add the following: + +[source,ruby] +---- +require 'rubocop/rake_task' + +RuboCop::RakeTask.new +---- + +If you run `rake -T`, the following two RuboCop tasks should show up: + +[source,sh] +---- +$ rake rubocop # Run RuboCop +$ rake rubocop:auto_correct # Auto-correct RuboCop offenses +---- + +The above will use default values + +[source,ruby] +---- +require 'rubocop/rake_task' + +desc 'Run RuboCop on the lib directory' +RuboCop::RakeTask.new(:rubocop) do |task| + task.patterns = ['lib/**/*.rb'] + # only show the files with failures + task.formatters = ['files'] + # don't abort rake on failure + task.fail_on_error = false +end +---- diff --git a/manual/support.md b/docs/modules/ROOT/pages/support.adoc similarity index 50% rename from manual/support.md rename to docs/modules/ROOT/pages/support.adoc index 9792e176f725..48bb1515b15c 100644 --- a/manual/support.md +++ b/docs/modules/ROOT/pages/support.adoc @@ -1,37 +1,34 @@ += Support + RuboCop currently has several official & unofficial support channels. +For questions, suggestions, and support refer to one of them. -For questions, suggestions, and support refer to one of them. Please, don't -use the support channels to report issues, as this makes them harder to track. +NOTE: Please, don't use the support channels to report issues, as this makes them +harder to track. -## Gitter +== Gitter Most internal discussions about the development of RuboCop happen on its -[gitter channel](https://gitter.im/bbatsov/rubocop). You can often find +https://gitter.im/bbatsov/rubocop[gitter channel]. You can often find RuboCop's maintainers there and get some interesting news from the project's kitchen. -## Mailing List +== Mailing List -The [official mailing list](https://groups.google.com/forum/#!forum/rubocop) is +The https://groups.google.com/forum/#!forum/rubocop[official mailing list] is hosted at Google Groups. It's a low-traffic list, so don't be too hesitant to subscribe. -## Freenode +== Freenode If you're into IRC you can visit the `#rubocop` channel on Freenode. It's not actively monitored by the RuboCop maintainers themselves, but still you can get support from other RuboCop users there. -## Stackoverflow +== StackOverflow We're also encouraging users to ask RuboCop-related questions on StackOverflow. When doing so you should use the -[RuboCop](https://stackoverflow.com/questions/tagged/rubocop) tag (ideally combined +https://stackoverflow.com/questions/tagged/rubocop[RuboCop] tag (ideally combined with the tag `ruby`). - -## Bountysource - -If you're willing to pay for some feature to be implemented you can use -[Bountysource](https://www.bountysource.com/teams/rubocop/issues) to place a -bounty for the work you want to be done. diff --git a/docs/modules/ROOT/pages/usage/auto_correct.adoc b/docs/modules/ROOT/pages/usage/auto_correct.adoc new file mode 100644 index 000000000000..92be24a5e12d --- /dev/null +++ b/docs/modules/ROOT/pages/usage/auto_correct.adoc @@ -0,0 +1,116 @@ += Auto-correct + +In auto-correct mode, RuboCop will try to automatically fix offenses: + +[source,sh] +---- +$ rubocop -A +# or +$ rubocop --auto-correct-all +---- + +There are a couple of things to keep in mind about auto-correct: + +- For some offenses, it is not possible to implement automatic correction. +- Some automatic corrections that _are_ possible have not been implemented yet. +- Some automatic corrections might change (slightly) the semantics of the code, +meaning they'd produce code that's mostly equivalent to the original code, but +not 100% equivalent. We call such auto-correct behaviour "unsafe". + +TIP: You should always run your test suite after using the auto-correct functionality. + +== Safe auto-correct + +[source,sh] +---- +$ rubocop -a +# or +$ rubocop --auto-correct +---- + +In RuboCop 0.60, we began to annotate cops as `Safe` or not safe. The definition of +safety is that the cop doesn't generate false positives. On top of that there's `SafeAutoCorrect` +that might be set to `false` in cases where only the auto-correct performed by a cop +is unsafe, but that the offense detection logic is safe. To sum it up: + +* Safe (`true/false`) - indicates whether the cop can yield false positives (by +design) or not. +* SafeAutoCorrect (`true/false`) - indicates whether the auto-correct a cop +does is safe (equivalent) by design. If a cop is unsafe its auto-correct automatically +becomes unsafe as well. + +If a cop or its auto-correct is annotated as "not safe", it will be omitted when using `--auto-correct`. + +NOTE: Currently there might still be cops that aren't marked as unsafe or +with unsafe auto-correct. Eventually, the safety of each cop will be specified +in the default configuration. + +=== Example of Unsafe Cop + +[source,ruby] +---- +class Miner + def dig(how_deep) + # ... + end +end + + +Miner.new.dig(42) # => Style/SingleArgumentDig + # => Use Miner.new[] instead of dig +---- + +This is the wrong diagnostic; this (contrived) use of `dig` is not an issue, +and there might not be an alternative. This cop is marked as `Safe: false`. + +[source,ruby] +---- +# example.rb: +str = 'hello' # => Missing magic comment `# frozen_string_literal: true` +str << 'world' + +# auto-corrects to: +# frozen_string_literal: true + +str = 'hello' +str << 'world' # => now fails because `str` is frozen + +# must be manually corrected to: +# frozen_string_literal: true + +str = +'hello' # => We want an unfrozen string literal here... +str << 'world' # => ok +---- + +This diagnostic is valid since the magic comment is indeed missing (thus `Safe: true`), +but the auto-correction is not; some string literals need to be prefixed with `+` to avoid +having them frozen. + +To run all auto-corrections (safe and unsafe): + +[source,sh] +---- +$ rubocop -A +# or +$ rubocop --auto-correct-all +---- + +It is recommended to be even more vigilant when using this option and review carefully the changes. + +== Generating comments + +[source,sh] +---- +$ rubocop --auto-correct --disable-uncorrectable +---- + +or + +[source,sh] +---- +$ rubocop --auto-correct-all --disable-uncorrectable +---- + +You can add the flag `--disable-uncorrectable`, which will generate +`# rubocop:todo` comments in the code to stop the reporting of offenses that +could not be corrected automatically. diff --git a/docs/modules/ROOT/pages/usage/basic_usage.adoc b/docs/modules/ROOT/pages/usage/basic_usage.adoc new file mode 100644 index 000000000000..bfbcd391516e --- /dev/null +++ b/docs/modules/ROOT/pages/usage/basic_usage.adoc @@ -0,0 +1,273 @@ += Basic Usage + +RuboCop has three primary uses: + +. Code style checker (a.k.a. linter) +. A replacement for `ruby -w` (a subset of its linting capabilities) +. Code formatter + +In the next sections we'll briefly cover all of them. + +== Code style checker + +Running `rubocop` with no arguments will check all Ruby source files +in the current directory: + +[source,sh] +---- +$ rubocop +---- + +Alternatively you can pass `rubocop` a list of files and directories to check: + +[source,sh] +---- +$ rubocop app spec lib/something.rb +---- + +Here's RuboCop in action. Consider the following Ruby source code: + +[source,ruby] +---- +def badName + if something + test + end +end +---- + +Running RuboCop on it (assuming it's in a file named `test.rb`) would produce the following report: + +---- +Inspecting 1 file +W + +Offenses: + +test.rb:1:1: C: Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true. +def badName +^ +test.rb:1:5: C: Naming/MethodName: Use snake_case for method names. +def badName + ^^^^^^^ +test.rb:2:3: C: Style/GuardClause: Use a guard clause instead of wrapping the code inside a conditional expression. + if something + ^^ +test.rb:2:3: C: Style/IfUnlessModifier: Favor modifier if usage when having a single-line body. Another good alternative is the usage of control flow &&/||. + if something + ^^ +test.rb:4:5: W: Layout/EndAlignment: end at 4, 4 is not aligned with if at 2, 2. + end + ^^^ + +1 file inspected, 5 offenses detected +---- + +=== Auto-correcting offenses + +You can also run RuboCop in an auto-correct mode, where it will try to +automatically fix the problems it found in your code: + +[source,sh] +---- +$ rubocop -a +# or +$ rubocop --auto-correct +---- + +TIP: See xref:usage/auto_correct.adoc[Auto-correct] for more details. + +=== Changing what RuboCop considers to be offenses + +RuboCop comes with a preconfigured set of rules for each of its cops, based on the https://rubystyle.guide[Ruby Style Guide]. +Depending on your project, you may wish to reconfigure a cop, tell to ignore certain files, or disable it altogether. + +The most common way to change RuboCop's behaviour is to create a configuration file named `.rubocop.yml` in the +project's root directory. + +For more information, see xref:configuration.adoc[Configuration]. + +== RuboCop as a replacement for `ruby -w` + +RuboCop natively implements almost all `ruby -w` lint warning checks, and then some. If you want you can use RuboCop +simply as a replacement for `ruby -w`: + +[source,sh] +---- +$ rubocop -l +# or +$ rubocop --lint +---- + +== RuboCop as a formatter + +There's a handy shortcut to run auto-correction only on code layout (a.k.a. formatting) offenses: + +[source,sh] +---- +$ rubocop -x +# or +$ rubocop --fix-layout +---- + +NOTE: This option was introduced in RuboCop 0.57.0. + +== Command-line flags + +For more details check the available command-line options: + +[source,sh] +---- +$ rubocop -h +---- + +To specify multiple cops for one flag, separate cops with commas and no spaces: + +[source,sh] +---- +$ rubocop --only Rails/Blank,Layout/HeredocIndentation,Naming/FileName +---- + + +|=== +| Command flag | Description + +| `-a/--auto-correct` +| Auto-correct offenses (only when it's safe). See xref:usage/auto_correct.adoc[Auto-correct]. + +| `-A/--auto-correct-all` +| Auto-correct offenses (safe and unsafe). See xref:usage/auto_correct.adoc[Auto-correct]. + +| `--auto-gen-config` +| Generate a configuration file acting as a TODO list. + +| `--[no-]color` +| Force color output on or off. + +| `-c/--config` +| Run with specified config file. + +| `-C/--cache` +| Store and reuse results for faster operation. + +| `-d/--debug` +| Displays some extra debug output. + +| `--disable-pending-cops` +| Run without pending cops. + +| `--disable-uncorrectable` +| Used with --auto-correct to annotate any offenses that do not support autocorrect with `rubocop:todo` comments. + +| `-D/--[no-]display-cop-names` +| Displays cop names in offense messages. Default is true. + +| `--display-only-fail-level-offenses` +| Only output offense messages at the specified `--fail-level` or above + +| `--enable-pending-cops` +| Run with pending cops. + +| `--except` +| Run all cops enabled by configuration except the specified cop(s) and/or departments. + +| `--exclude-limit` +| Limit how many individual files `--auto-gen-config` can list in `Exclude` parameters, default is 15. + +| `-E/--extra-details` +| Displays extra details in offense messages. + +| `-f/--format` +| Choose a formatter, see xref:formatters.adoc[Formatters]. + +| `-F/--fail-fast` +| Inspect files in order of modification time and stops after first file with offenses. + +| `--fail-level` +| Minimum xref:configuration.adoc#severity[severity] for exit with error code. Full severity name or upper case initial can be given. Normally, auto-corrected offenses are ignored. Use `A` or `autocorrect` if you'd like them to trigger failure. + +| `--force-exclusion` +| Force excluding files specified in the configuration `Exclude` even if they are explicitly passed as arguments. + +| `--only-recognized-file-types` +| Inspect files given on the command line only if they are listed in `AllCops`/`Include` parameters of user configuration or default configuration. + +| `-h/--help` +| Print usage information. + +| `--ignore-parent-exclusion` +| Ignores all Exclude: settings from all .rubocop.yml files present in parent folders. This is useful when you are importing submodules when you want to test them without being affected by the parent module's rubocop settings. + +| `--init` +| Generate a .rubocop.yml file in the current directory. + +| `-l/--lint` +| Run only lint cops. + +| `-L/--list-target-files` +| List all files RuboCop will inspect. + +| `--[no-]auto-gen-only-exclude` +| Generate only `Exclude` parameters and not `Max` when running `--auto-gen-config`, except if the number of files with offenses is bigger than `exclude-limit`. Default is false + +| `--[no-]auto-gen-timestamp` +| Include the date and time when `--auto-gen-config` was run in the config file it generates. Default is true. + +| `--[no-]offense-counts` +| Show offense counts in config file generated by `--auto-gen-config`. Default is true. + +| `--only` +| Run only the specified cop(s) and/or cops in the specified departments. + +| `-o/--out` +| Write output to a file instead of STDOUT. + +| `--parallel` +| Use available CPUs to execute inspection in parallel. + +| `-r/--require` +| Require Ruby file (see xref:extensions.adoc#loading-extensions[Loading Extensions]). + +| `--regenerate-todo` +| Regenerate the TODO list using the same options as the last time it was generated with `--auto-gen-config` (generation options can be overridden). + +| `--safe` +| Run only safe cops. + +| `--safe-auto-correct` +| Omit cops annotated as "not safe". See xref:auto_correct.adoc[Auto-correct]. + +| `--show-cops` +| Shows available cops and their configuration. + +| `-s/--stdin` +| Pipe source from STDIN. This is useful for editor integration. Takes one argument, a path, relative to the root of the project. RuboCop will use this path to determine which cops are enabled (via eg. Include/Exclude), and so that certain cops like Naming/FileName can be checked. + +| `-x/--fix-layout` +| Auto-correct only code layout (formatting) offenses. + +| `-v/--version` +| Displays the current version and exits. + +| `-V/--verbose-version` +| Displays the current version plus the version of Parser and Ruby. +|=== + +Default command-line options are loaded from `.rubocop` and `RUBOCOP_OPTS` and are combined with command-line options that are explicitly passed to `rubocop`. +Thus, the options have the following order of precedence (from highest to lowest): + +. Explicit command-line options +. Options from `RUBOCOP_OPTS` environment variable +. Options from `.rubocop` file. + +== Exit codes + +RuboCop exits with the following status codes: + +* `0` if no offenses are found or if the severity of all offenses are less than +`--fail-level`. (By default, if you use `--auto-correct`, offenses which are +auto-corrected do not cause RuboCop to fail.) +* `1` if one or more offenses equal or greater to `--fail-level` are found. (By +default, this is any offense which is not auto-corrected.) +* `2` if RuboCop terminates abnormally due to invalid configuration, invalid CLI +options, or an internal error. diff --git a/manual/caching.md b/docs/modules/ROOT/pages/usage/caching.adoc similarity index 66% rename from manual/caching.md rename to docs/modules/ROOT/pages/usage/caching.adoc index abc2167301b6..6269ca8de442 100644 --- a/manual/caching.md +++ b/docs/modules/ROOT/pages/usage/caching.adoc @@ -1,25 +1,26 @@ -## Caching += Caching Large projects containing hundreds or even thousands of files can take a really long time to inspect, but RuboCop has functionality to mitigate this problem. There's a caching mechanism that stores information about offenses found in inspected files. -### Cache Validity +== Cache Validity Later runs will be able to retrieve this information and present the stored information instead of inspecting the file again. This will be done if the cache for the file is still valid, which it is if there are no changes in: + * the contents of the inspected file * RuboCop configuration for the file * the options given to `rubocop`, with some exceptions that have no - bearing on which offenses are reported +bearing on which offenses are reported * the Ruby version used to invoke `rubocop` * version of the `rubocop` program (or to be precise, anything in the - source code of the invoked `rubocop` program) +source code of the invoked `rubocop` program) -### Enabling and Disabling the Cache +== Enabling and Disabling the Cache The caching functionality is enabled if the configuration parameter `AllCops: UseCache` is `true`, which it is by default. The command @@ -28,19 +29,26 @@ overriding the configuration parameter. If `AllCops: UseCache` is set to `false` in the local `.rubocop.yml`, then it's `--cache true` that overrides the setting. -### Cache Path +== Cache Path By default, the cache is stored in either `$XDG_CACHE_HOME/$UID/rubocop_cache` if `$XDG_CACHE_HOME` is set or in -`$HOME/.cache/rubocop_cache/` if it's not. The configuration parameter -`AllCops: CacheRootDirectory` can be used to set the root to a -different path. One reason to use this option could be that there's a -network disk where users on different machines want to have a common -RuboCop cache. Another could be that a Continuous Integration system -allows directories, but not a temporary directory, to be saved between -runs. - -### Cache Pruning +`$HOME/.cache/rubocop_cache/` if it's not. + +The root can be set to a different path in a number of ways (from +**highest** precedence to **lowest**): + +* the `--cache-root` command line option +* the `$RUBOCOP_CACHE_ROOT` environment variable +* the `AllCops: CacheRootDirectory` configuration parameter + +One reason to set the cache root could be that there's a network disk +where users on different machines want to have a common RuboCop cache. +Another could be that a Continuous Integration system allows +directories, but not a temporary directory, to be saved between runs, +or that the system caches certain folders by default. + +== Cache Pruning Each time a file has changed, its offenses will be stored under a new key in the cache. This means that the cache will continue to grow diff --git a/docs/modules/ROOT/pages/v1_upgrade_notes.adoc b/docs/modules/ROOT/pages/v1_upgrade_notes.adoc new file mode 100644 index 000000000000..bd18cbd6ae76 --- /dev/null +++ b/docs/modules/ROOT/pages/v1_upgrade_notes.adoc @@ -0,0 +1,256 @@ += v1 Upgrade Notes +:doctype: book + +== Cop Upgrade guide + +Your custom cops should continue to work in v1. + +Nevertheless it is suggested that you tweak them to use the v1 API by following the following steps: + +1) Your class should inherit from `RuboCop::Cop::Base` instead of `RuboCop::Cop::Cop`. + +2) Locate your calls to `add_offense` and make sure that you pass as the first argument either an `AST::Node`, a `::Parser::Source::Comment` or a `::Parser::Source::Range`, and no `location:` named parameter. + +[discrete] +==== Example: + +[source,ruby] +---- +# Before +class MySillyCop < Cop + def on_send(node) + if node.method_name == :- + add_offense(node, location: :selector, message: "Be positive") + end + end +end + +# After +class MySillyCop < Base + def on_send(node) + if node.method_name == :- + add_offense(node.loc.selector, message: "Be positive") + end + end +end +---- + +=== If your class supports autocorrection + +Your class must `extend AutoCorrector`. + +The `corrector` is now yielded from `add_offense`. Move the code of your method `autocorrect` in that block and do not wrap your correction in a lambda. `Corrector` are more powerful and can now be `merge`d. + +==== Example: + +[source,ruby] +---- +# Before +class MySillyCorrectingCop < Cop + def on_send(node) + if node.method_name == :- + add_offense(node, location: :selector, message: 'Be positive') + end + end + + def autocorrect(node) + lambda do |corrector| + corrector.replace(node.loc.selector, '+') + end + end +end + +# After +class MySillyCorrectingCop < Base + extend AutoCorrector + + def on_send(node) + if node.method_name == :- + add_offense(node.loc.selector, message: 'Be positive') do |corrector| + corrector.replace(node.loc.selector, '+') + end + end + end +end +---- + +=== Instance variables + +Do not use RuboCop's internal instance variables. If you used `@processed_source`, use `processed_source`. If you have a need to access an instance variable, open an issue with your use case. + +By default, a Cop instance will be called only once for a given `processed_source`, so instance variables will be uninitialized when the investigation starts. Using `@cache ||= ...` is fine. If you want to initialize some instance variable, the callback `on_new_investigation` is the best place to do so. + +[source,ruby] +---- +class MyCachingCop < Base + def on_send(node) + if my_cached_data[node] + @counts(node.method_name) += 1 + #... + end + end + + # One way: + def my_cached_data + @data ||= processed_source.comments.map { # ... } + end + + # Another way: + def on_new_investigation + @counts = Hash.new(0) + super # Be nice and call super for callback + end +end +---- + +=== Other API changes + +If your cop uses `investigate`, `investigate_post_walk`, `join_force?`, or internal classes like `Corrector`, `Commissioner`, `Team`, these have changed. See the <>. + +=== Upgrading specs + +It is highly recommended you use `expect_offense` / `expect_correction` / `expect_no_offense` in your specs, e.g.: + +[source,ruby] +---- +require 'rubocop/rspec/support' + +RSpec.describe RuboCop::Cop::Custom::MySillyCorrectingCop, :config do + # No need for `let(:cop)` + it 'is positive' do + expect_offense(<<~RUBY) + 42 + 2 - 2 + ^ Be positive + RUBY + + expect_correction(<<~RUBY) + 42 + 2 + 2 + RUBY + end + + it 'does not register an offense for calls to `despair`' do + expect_no_offenses(<<~RUBY) + "don't".despair + RUBY + end +end +---- + +In the unlikely case where you use the class `RuboCop::Cop::Corrector` directly, it has changed a bit but you can ease your transition with `RuboCop::Cop::Legacy::Corrector` that is meant to be somewhat backwards compatible. You will need to `require 'rubocop/cop/legacy/corrector'`. + +== Detailed API Changes + +This section lists all changes (big or small) to the API. It is meant for maintainers of the nuts & bolts of RuboCop; most cop writers will not be impacted by these and are thus not the target audience. + +=== Base class + +_Legacy_: Cops inherit from `Cop::Cop`. + +_Current_: Cops inherit from `Cop::Base`. Having a different base class makes the implementation much cleaner and makes it easy to signal which API is being used. `Cop::Cop` inherits from `Cop::Base` and refines some methods for backward compatibility. + +=== `add_offense` API + +==== arguments + +_Legacy:_ interface allowed for a `node`, with an optional `location` (symbol or range) or a range with a mandatory range as the location. Some cops were abusing the `node` argument and passing very different things. + +_Current:_ pass a range (or node as a shortcut for `node.loc.expression`), no `location:`. No abuse tolerated. + +==== de-dupping changes + +Both de-dup on `range` and won't process the duplicated offenses at all. + +_Legacy:_ if offenses on same `node` but different `range`: considered as multiple offenses but a single auto-correct call. + +_Current:_ not applicable and not needed with autocorrection's API. + +==== yield + +Both yield under the same conditions (unless cop is disabled for that line), but: + +_Legacy:_ yields after offense added to `#offenses` + +_Current:_ yields before offense is added to `#offenses`. + +Even the legacy mode yields a corrector, but if a developer uses it an error will be raised asking her to inherit from `Cop::Base` instead. + +=== Auto Correction + +==== `#autocorrect` + +_Legacy:_ calls `autocorrect` unless it is disabled / autocorrect is off. + +_Current:_ yields a corrector unless it is disabled. The corrector will be ignored if autocorrecting is off, etc. No support for `autocorrect` method, but a warning is issued if that method is still defined. + +==== Empty corrections + +_Legacy:_ `autocorrect` could return `nil` / `false` in cases where it couldn't actually make a correction. + +_Current:_ No special API. Cases where no corrections are made are automatically detected. + +==== Correction timing + +_Legacy:_ the lambda was called only later in the process, and only under specific conditions (if the auto-correct setting is turned on, etc.) + +_Current:_ correction is built immediately (assuming the cop isn't disabled for the line) and applied later in the process. + +==== Exception handling + +Both: `Commissioner` will rescue all ``StandardError``s during analysis (unless `option[:raise_error]`) and store a corresponding `ErrorWithAnalyzedFileLocation` in its error list. This is done when calling the cop's `on_send` & al., or when calling `investigate` / `investigate_post_walk` callback. + +_Legacy:_ autocorrecting cops were treating errors differently depending on when they occurred. Some errors were silently ignored. Others were rescued as above. Others crashed. Some code in `Team` would rescue errors and add them to the list of errors but I don't think the code worked. + +_Current:_ `Team` no longer has any special error handling to do as potential exceptions happen when `Commissioner` is running. + +==== Other error handling + +_Legacy:_ Clobbering errors are silently ignored. Calling `insert_before` with ranges that extend beyond the source code was silently fixed. + +_Current:_ Such errors are not ignored. It is still ok that a given Cop's corrections clobber another Cop's, but any given Cop should not issue corrections that clobber each other, or with invalid ranges, otherwise these will be listed in the processing errors. + +==== `#corrections` + +_Legacy:_ Corrections were held in `#corrections` as an array of lambdas. A proxy was written to maintain compatibility with `+cop.corrections << ...+`, `+cop.corrections.concat ...+`, etc. + +_Current:_ Corrections are held in `current_corrector`, a `Corrector` which inherits from `Source::TreeRewriter`. + +==== `#support_autocorrect?` + +_Legacy:_ was an instance method. + +_Current:_ now a class method. + +==== Joining forces + +_Legacy:_ `join_force?(force_class)` was called with every force class + +_Current:_ `self.joining_forces` is now used to return the force (or an array of forces) to join. + +=== Cop persistence + +Cops can now be persisted between files. By default new cop instances are created for each source. See `support_multiple_source?` documentation. + +=== Internal classes + +==== `Corrector` + +_Legacy:_ `initialize` accepted a second argument (an array of lambdas). Available through `Legacy::Corrector` if needed. + +_Current:_ derives from `parser`'s `TreeRewriter`. No second argument to `initialize`; not needed as correctors can be merged. + +==== `Commissioner` & `Team` + +Refactored for better separation of concern, being reusable, better result reporting and better error handling. + +=== Misc API changes + +* internal API clarified for Commissioner. It calls `begin_investigation` and receives the results in `complete_investigation`. +* New method `add_global_offense` for offenses that are not attached to a location in particular; it's used for Syntax errors only right now. +* `#offenses`: No longer accessible. +* Callbacks `investigate(processed_source)` and `investigate_post_walk(processed_source)` are renamed `on_new_investigation` and `on_investigation_end` and don't accept an argument; all `on_` callbacks should rely on `processed_source`. +* `#find_location` is deprecated. +* `Correction` is deprecated. +* A few registry access methods were moved from `Cop` to `Registry` both for correctness (e.g. `MyCop.qualified_cop_name` did not work nor made sense) and so that `Cop::Cop` no longer holds any necessary code anymore. Backwards compatibility is maintained. + ** `Cop.registry` \=> `Registry.global` + ** `Cop.all` \=> `Registry.all` + ** `Cop.qualified_cop_name` \=> `Registry.qualified_cop_name` diff --git a/docs/modules/ROOT/pages/versioning.adoc b/docs/modules/ROOT/pages/versioning.adoc new file mode 100644 index 000000000000..a4446c537909 --- /dev/null +++ b/docs/modules/ROOT/pages/versioning.adoc @@ -0,0 +1,94 @@ += Versioning + +NOTE: Some of the information here is forward looking, as RuboCop 1.0 is still not released. + +RuboCop is stable between major versions, both in terms of API and cop +configuration. + +== Release Policy + +We're following https://semver.org/[Semantic Versioning] (as much as +one can be following it when the major version is 0). At this point +bumps of the minor (second) version number are considered major releases +and always include new features or significant changes to existing +features. API compatibility between major releases is a big concern, as +there are many RuboCop extensions that can be affected by breaking API +changes. + +The development cycle for the next major +release starts immediately after the previous one has been +shipped. Bugfix/point releases (if any) address only serious bugs and +never contain new features. + +Here are a few examples: + +* 0.50.0 - Feature release +* 0.50.1 - Bug-fix release +* 0.50.2 - Bug-fix release +* 0.51.0 - Feature release + +== Pending Cops + +In the early versions of RuboCop a common source of frustration was that +new cops were added to pretty much every release, and as they were enabled +by default, every upgrade resulted in broken CI builds and trying to figure +out what exactly was changed. After considering many options to address +this eventually we opted for an approach that limits these type of changes +to major RuboCop releases. + +Now new cops introduced between major versions are set to a special pending +status and are not enabled by default. A warning is emitted if such cops +are not explicitly enabled or disabled in the user configuration. Here's +one such message: + +---- +The following cops were added to RuboCop, but are not configured. Please +set Enabled to either `true` or `false` in your `.rubocop.yml` file: + - Style/HashEachMethods (0.80) + - Style/HashTransformKeys (0.80) + - Style/HashTransformValues (0.80) +For more information: https://docs.rubocop.org/rubocop/versioning.html +---- + +You can see that 3 new cops were added in RuboCop 0.80 and it's up to you +to decide if you want to enable or disable them. + +To suppress this message set `NewCops` to either `enable` or `disable` in your `.rubocop.yml` file. + +The following setting or using `rubocop --enable-pending-cops` command-line option, pending cops are enabled in bulk. + +[source,yaml] +---- +AllCops: + NewCops: enable +---- + +The following setting or using `rubocop --disable-pending-cops` command-line option, pending cops are disabled in bulk. + +[source,yaml] +---- +AllCops: + NewCops: disable +---- + +The command-line options takes precedence over `.rubocop.yml` file. + +Or set `Enabled` to either `true` or `false` in your `.rubocop.yml` file. + +`Style/ANewCop` is an example of a newly added pending cop: + +[source,yaml] +---- +Style/ANewCop: + Enabled: true +---- + +or + +[source,yaml] +---- +Style/ANewCop: + Enabled: false +---- + +On major version updates, pending cops are enabled in bulk. diff --git a/lib/rubocop.rb b/lib/rubocop.rb index 930236aa3fb3..a3e1b9b630ba 100644 --- a/lib/rubocop.rb +++ b/lib/rubocop.rb @@ -1,64 +1,29 @@ # frozen_string_literal: true -require 'parser' +require 'English' +before_us = $LOADED_FEATURES.dup require 'rainbow' -require 'English' require 'set' require 'forwardable' +require 'regexp_parser' require 'unicode/display_width/no_string_ext' +# we have to require RuboCop's version, before rubocop-ast's require_relative 'rubocop/version' +require 'rubocop-ast' + +require_relative 'rubocop/ast_aliases' +require_relative 'rubocop/ext/regexp_node' require_relative 'rubocop/core_ext/string' +require_relative 'rubocop/ext/processed_source' + require_relative 'rubocop/path_util' require_relative 'rubocop/file_finder' require_relative 'rubocop/platform' -require_relative 'rubocop/string_util' require_relative 'rubocop/name_similarity' -require_relative 'rubocop/node_pattern' require_relative 'rubocop/string_interpreter' -require_relative 'rubocop/ast/sexp' -require_relative 'rubocop/ast/node' -require_relative 'rubocop/ast/node/mixin/method_identifier_predicates' -require_relative 'rubocop/ast/node/mixin/binary_operator_node' -require_relative 'rubocop/ast/node/mixin/collection_node' -require_relative 'rubocop/ast/node/mixin/conditional_node' -require_relative 'rubocop/ast/node/mixin/hash_element_node' -require_relative 'rubocop/ast/node/mixin/method_dispatch_node' -require_relative 'rubocop/ast/node/mixin/modifier_node' -require_relative 'rubocop/ast/node/mixin/parameterized_node' -require_relative 'rubocop/ast/node/mixin/predicate_operator_node' -require_relative 'rubocop/ast/node/mixin/basic_literal_node' -require_relative 'rubocop/ast/node/and_node' -require_relative 'rubocop/ast/node/args_node' -require_relative 'rubocop/ast/node/array_node' -require_relative 'rubocop/ast/node/block_node' -require_relative 'rubocop/ast/node/break_node' -require_relative 'rubocop/ast/node/case_node' -require_relative 'rubocop/ast/node/def_node' -require_relative 'rubocop/ast/node/defined_node' -require_relative 'rubocop/ast/node/ensure_node' -require_relative 'rubocop/ast/node/for_node' -require_relative 'rubocop/ast/node/hash_node' -require_relative 'rubocop/ast/node/if_node' -require_relative 'rubocop/ast/node/keyword_splat_node' -require_relative 'rubocop/ast/node/or_node' -require_relative 'rubocop/ast/node/pair_node' -require_relative 'rubocop/ast/node/range_node' -require_relative 'rubocop/ast/node/regexp_node' -require_relative 'rubocop/ast/node/resbody_node' -require_relative 'rubocop/ast/node/retry_node' -require_relative 'rubocop/ast/node/send_node' -require_relative 'rubocop/ast/node/str_node' -require_relative 'rubocop/ast/node/super_node' -require_relative 'rubocop/ast/node/symbol_node' -require_relative 'rubocop/ast/node/until_node' -require_relative 'rubocop/ast/node/when_node' -require_relative 'rubocop/ast/node/while_node' -require_relative 'rubocop/ast/node/yield_node' -require_relative 'rubocop/ast/builder' -require_relative 'rubocop/ast/traversal' require_relative 'rubocop/error' require_relative 'rubocop/warning' @@ -69,8 +34,10 @@ require_relative 'rubocop/cop/autocorrect_logic' require_relative 'rubocop/cop/badge' require_relative 'rubocop/cop/registry' +require_relative 'rubocop/cop/base' require_relative 'rubocop/cop/cop' require_relative 'rubocop/cop/commissioner' +require_relative 'rubocop/cop/documentation' require_relative 'rubocop/cop/corrector' require_relative 'rubocop/cop/force' require_relative 'rubocop/cop/severity' @@ -88,14 +55,15 @@ require_relative 'rubocop/cop/variable_force/variable_table' require_relative 'rubocop/cop/mixin/annotation_comment' -require_relative 'rubocop/cop/mixin/array_hash_indentation' require_relative 'rubocop/cop/mixin/array_min_size' require_relative 'rubocop/cop/mixin/array_syntax' require_relative 'rubocop/cop/mixin/alignment' +require_relative 'rubocop/cop/mixin/allowed_methods' +require_relative 'rubocop/cop/mixin/auto_corrector' require_relative 'rubocop/cop/mixin/check_assignment' +require_relative 'rubocop/cop/mixin/check_line_breakable' require_relative 'rubocop/cop/mixin/configurable_max' require_relative 'rubocop/cop/mixin/code_length' # relies on configurable_max -require_relative 'rubocop/cop/mixin/classish_length' # relies on code_length require_relative 'rubocop/cop/mixin/configurable_enforced_style' require_relative 'rubocop/cop/mixin/configurable_formatting' require_relative 'rubocop/cop/mixin/configurable_naming' @@ -110,14 +78,20 @@ require_relative 'rubocop/cop/mixin/enforce_superclass' require_relative 'rubocop/cop/mixin/first_element_line_break' require_relative 'rubocop/cop/mixin/frozen_string_literal' -require_relative 'rubocop/cop/mixin/hash_alignment' +require_relative 'rubocop/cop/mixin/hash_alignment_styles' +require_relative 'rubocop/cop/mixin/hash_transform_method' require_relative 'rubocop/cop/mixin/ignored_pattern' require_relative 'rubocop/cop/mixin/ignored_methods' require_relative 'rubocop/cop/mixin/integer_node' +require_relative 'rubocop/cop/mixin/interpolation' +require_relative 'rubocop/cop/mixin/line_length_help' require_relative 'rubocop/cop/mixin/match_range' +require_relative 'rubocop/cop/metrics/utils/repeated_csend_discount' require_relative 'rubocop/cop/mixin/method_complexity' require_relative 'rubocop/cop/mixin/method_preference' require_relative 'rubocop/cop/mixin/min_body_length' +require_relative 'rubocop/cop/mixin/multiline_element_indentation' +require_relative 'rubocop/cop/mixin/multiline_element_line_breaks' require_relative 'rubocop/cop/mixin/multiline_expression_indentation' require_relative 'rubocop/cop/mixin/multiline_literal_brace_layout' require_relative 'rubocop/cop/mixin/negative_conditional' @@ -126,14 +100,13 @@ require_relative 'rubocop/cop/mixin/on_normal_if_unless' require_relative 'rubocop/cop/mixin/ordered_gem_node' require_relative 'rubocop/cop/mixin/parentheses' -require_relative 'rubocop/cop/mixin/parser_diagnostic' require_relative 'rubocop/cop/mixin/percent_array' require_relative 'rubocop/cop/mixin/percent_literal' require_relative 'rubocop/cop/mixin/preceding_following_alignment' require_relative 'rubocop/cop/mixin/preferred_delimiters' +require_relative 'rubocop/cop/mixin/rational_literal' require_relative 'rubocop/cop/mixin/rescue_node' require_relative 'rubocop/cop/mixin/safe_assignment' -require_relative 'rubocop/cop/mixin/safe_mode' require_relative 'rubocop/cop/mixin/space_after_punctuation' require_relative 'rubocop/cop/mixin/space_before_punctuation' require_relative 'rubocop/cop/mixin/surrounding_space' @@ -141,12 +114,16 @@ require_relative 'rubocop/cop/mixin/string_help' require_relative 'rubocop/cop/mixin/string_literals_help' require_relative 'rubocop/cop/mixin/target_ruby_version' -require_relative 'rubocop/cop/mixin/target_rails_version' -require_relative 'rubocop/cop/mixin/too_many_lines' require_relative 'rubocop/cop/mixin/trailing_body' require_relative 'rubocop/cop/mixin/trailing_comma' require_relative 'rubocop/cop/mixin/uncommunicative_name' require_relative 'rubocop/cop/mixin/unused_argument' +require_relative 'rubocop/cop/mixin/visibility_help' +require_relative 'rubocop/cop/mixin/comments_help' # relies on visibility_help + +require_relative 'rubocop/cop/utils/format_string' + +require_relative 'rubocop/cop/migration/department_name' require_relative 'rubocop/cop/correctors/alignment_corrector' require_relative 'rubocop/cop/correctors/condition_corrector' @@ -172,11 +149,13 @@ require_relative 'rubocop/cop/gemspec/duplicated_assignment' require_relative 'rubocop/cop/gemspec/ordered_dependencies' require_relative 'rubocop/cop/gemspec/required_ruby_version' +require_relative 'rubocop/cop/gemspec/ruby_version_globals_usage' require_relative 'rubocop/cop/layout/access_modifier_indentation' -require_relative 'rubocop/cop/layout/align_array' -require_relative 'rubocop/cop/layout/align_hash' -require_relative 'rubocop/cop/layout/align_parameters' +require_relative 'rubocop/cop/layout/argument_alignment' +require_relative 'rubocop/cop/layout/array_alignment' +require_relative 'rubocop/cop/layout/assignment_indentation' +require_relative 'rubocop/cop/layout/begin_end_alignment' require_relative 'rubocop/cop/layout/block_alignment' require_relative 'rubocop/cop/layout/block_end_newline' require_relative 'rubocop/cop/layout/case_indentation' @@ -191,41 +170,51 @@ require_relative 'rubocop/cop/layout/empty_comment' require_relative 'rubocop/cop/layout/empty_line_after_guard_clause' require_relative 'rubocop/cop/layout/empty_line_after_magic_comment' +require_relative 'rubocop/cop/layout/empty_line_after_multiline_condition' require_relative 'rubocop/cop/layout/empty_line_between_defs' require_relative 'rubocop/cop/layout/empty_lines_around_access_modifier' require_relative 'rubocop/cop/layout/empty_lines_around_arguments' +require_relative 'rubocop/cop/layout/empty_lines_around_attribute_accessor' require_relative 'rubocop/cop/layout/empty_lines_around_begin_body' require_relative 'rubocop/cop/layout/empty_lines_around_block_body' require_relative 'rubocop/cop/layout/empty_lines_around_class_body' -require_relative 'rubocop/cop/layout/empty_lines_around_exception_handling_keywords' # rubocop:disable Metrics/LineLength +require_relative 'rubocop/cop/layout/empty_lines_around_exception_handling_keywords' require_relative 'rubocop/cop/layout/empty_lines_around_method_body' require_relative 'rubocop/cop/layout/empty_lines_around_module_body' require_relative 'rubocop/cop/layout/empty_lines' require_relative 'rubocop/cop/layout/end_alignment' require_relative 'rubocop/cop/layout/end_of_line' require_relative 'rubocop/cop/layout/extra_spacing' +require_relative 'rubocop/cop/layout/first_argument_indentation' +require_relative 'rubocop/cop/layout/first_array_element_indentation' require_relative 'rubocop/cop/layout/first_array_element_line_break' +require_relative 'rubocop/cop/layout/first_hash_element_indentation' require_relative 'rubocop/cop/layout/first_hash_element_line_break' require_relative 'rubocop/cop/layout/first_method_argument_line_break' require_relative 'rubocop/cop/layout/first_method_parameter_line_break' require_relative 'rubocop/cop/layout/first_parameter_indentation' -require_relative 'rubocop/cop/layout/indent_array' -require_relative 'rubocop/cop/layout/indent_assignment' +require_relative 'rubocop/cop/layout/hash_alignment' +require_relative 'rubocop/cop/layout/heredoc_argument_closing_parenthesis' +require_relative 'rubocop/cop/layout/heredoc_indentation' require_relative 'rubocop/cop/layout/indentation_consistency' +require_relative 'rubocop/cop/layout/indentation_style' require_relative 'rubocop/cop/layout/indentation_width' -require_relative 'rubocop/cop/layout/indent_hash' -require_relative 'rubocop/cop/layout/indent_heredoc' require_relative 'rubocop/cop/layout/initial_indentation' -require_relative 'rubocop/cop/layout/leading_blank_lines' require_relative 'rubocop/cop/layout/leading_comment_space' +require_relative 'rubocop/cop/layout/leading_empty_lines' +require_relative 'rubocop/cop/layout/line_length' require_relative 'rubocop/cop/layout/multiline_array_brace_layout' +require_relative 'rubocop/cop/layout/multiline_array_line_breaks' require_relative 'rubocop/cop/layout/multiline_assignment_layout' require_relative 'rubocop/cop/layout/multiline_block_layout' require_relative 'rubocop/cop/layout/multiline_hash_brace_layout' +require_relative 'rubocop/cop/layout/multiline_hash_key_line_breaks' +require_relative 'rubocop/cop/layout/multiline_method_argument_line_breaks' require_relative 'rubocop/cop/layout/multiline_method_call_brace_layout' require_relative 'rubocop/cop/layout/multiline_method_call_indentation' require_relative 'rubocop/cop/layout/multiline_method_definition_brace_layout' require_relative 'rubocop/cop/layout/multiline_operation_indentation' +require_relative 'rubocop/cop/layout/parameter_alignment' require_relative 'rubocop/cop/layout/rescue_ensure_alignment' require_relative 'rubocop/cop/layout/space_after_colon' require_relative 'rubocop/cop/layout/space_after_comma' @@ -235,6 +224,7 @@ require_relative 'rubocop/cop/layout/space_around_block_parameters' require_relative 'rubocop/cop/layout/space_around_equals_in_parameter_default' require_relative 'rubocop/cop/layout/space_around_keyword' +require_relative 'rubocop/cop/layout/space_around_method_call_operator' require_relative 'rubocop/cop/layout/space_around_operators' require_relative 'rubocop/cop/layout/space_before_block_braces' require_relative 'rubocop/cop/layout/space_before_comma' @@ -251,8 +241,7 @@ require_relative 'rubocop/cop/layout/space_inside_range_literal' require_relative 'rubocop/cop/layout/space_inside_reference_brackets' require_relative 'rubocop/cop/layout/space_inside_string_interpolation' -require_relative 'rubocop/cop/layout/tab' -require_relative 'rubocop/cop/layout/trailing_blank_lines' +require_relative 'rubocop/cop/layout/trailing_empty_lines' require_relative 'rubocop/cop/layout/trailing_whitespace' require_relative 'rubocop/cop/lint/ambiguous_block_association' @@ -260,27 +249,38 @@ require_relative 'rubocop/cop/lint/ambiguous_regexp_literal' require_relative 'rubocop/cop/lint/assignment_in_condition' require_relative 'rubocop/cop/lint/big_decimal_new' +require_relative 'rubocop/cop/lint/binary_operator_with_identical_operands' require_relative 'rubocop/cop/lint/boolean_symbol' require_relative 'rubocop/cop/lint/circular_argument_reference' +require_relative 'rubocop/cop/lint/constant_definition_in_block' +require_relative 'rubocop/cop/lint/constant_resolution' require_relative 'rubocop/cop/lint/debugger' require_relative 'rubocop/cop/lint/deprecated_class_methods' +require_relative 'rubocop/cop/lint/deprecated_open_ssl_constant' require_relative 'rubocop/cop/lint/disjunctive_assignment_in_constructor' require_relative 'rubocop/cop/lint/duplicate_case_condition' +require_relative 'rubocop/cop/lint/duplicate_elsif_condition' +require_relative 'rubocop/cop/lint/duplicate_hash_key' require_relative 'rubocop/cop/lint/duplicate_methods' -require_relative 'rubocop/cop/lint/duplicated_key' +require_relative 'rubocop/cop/lint/duplicate_require' +require_relative 'rubocop/cop/lint/duplicate_rescue_exception' require_relative 'rubocop/cop/lint/each_with_object_argument' require_relative 'rubocop/cop/lint/else_layout' +require_relative 'rubocop/cop/lint/empty_conditional_body' require_relative 'rubocop/cop/lint/empty_ensure' require_relative 'rubocop/cop/lint/empty_expression' +require_relative 'rubocop/cop/lint/empty_file' require_relative 'rubocop/cop/lint/empty_interpolation' require_relative 'rubocop/cop/lint/empty_when' -require_relative 'rubocop/cop/lint/end_in_method' require_relative 'rubocop/cop/lint/ensure_return' require_relative 'rubocop/cop/lint/erb_new_arguments' require_relative 'rubocop/cop/lint/flip_flop' +require_relative 'rubocop/cop/lint/float_comparison' require_relative 'rubocop/cop/lint/float_out_of_range' require_relative 'rubocop/cop/lint/format_parameter_mismatch' -require_relative 'rubocop/cop/lint/handle_exceptions' +require_relative 'rubocop/cop/lint/hash_compare_by_identity' +require_relative 'rubocop/cop/lint/heredoc_method_call_position' +require_relative 'rubocop/cop/lint/identity_comparison' require_relative 'rubocop/cop/lint/implicit_string_concatenation' require_relative 'rubocop/cop/lint/inherit_exception' require_relative 'rubocop/cop/lint/ineffective_access_modifier' @@ -289,17 +289,28 @@ require_relative 'rubocop/cop/lint/literal_in_interpolation' require_relative 'rubocop/cop/lint/loop' require_relative 'rubocop/cop/lint/missing_cop_enable_directive' -require_relative 'rubocop/cop/lint/multiple_compare' +require_relative 'rubocop/cop/lint/missing_super' +require_relative 'rubocop/cop/lint/mixed_regexp_capture_types' +require_relative 'rubocop/cop/lint/multiple_comparison' require_relative 'rubocop/cop/lint/nested_method_definition' require_relative 'rubocop/cop/lint/nested_percent_literal' require_relative 'rubocop/cop/lint/next_without_accumulator' +require_relative 'rubocop/cop/lint/non_deterministic_require_order' require_relative 'rubocop/cop/lint/non_local_exit_from_iterator' require_relative 'rubocop/cop/lint/number_conversion' require_relative 'rubocop/cop/lint/ordered_magic_comments' +require_relative 'rubocop/cop/lint/out_of_range_regexp_ref' require_relative 'rubocop/cop/lint/parentheses_as_grouped_expression' require_relative 'rubocop/cop/lint/percent_string_array' require_relative 'rubocop/cop/lint/percent_symbol_array' +require_relative 'rubocop/cop/lint/raise_exception' require_relative 'rubocop/cop/lint/rand_one' +require_relative 'rubocop/cop/lint/redundant_cop_disable_directive' +require_relative 'rubocop/cop/lint/redundant_cop_enable_directive' +require_relative 'rubocop/cop/lint/redundant_require_statement' +require_relative 'rubocop/cop/lint/redundant_safe_navigation' +require_relative 'rubocop/cop/lint/redundant_splat_expansion' +require_relative 'rubocop/cop/lint/redundant_string_coercion' require_relative 'rubocop/cop/lint/redundant_with_index' require_relative 'rubocop/cop/lint/redundant_with_object' require_relative 'rubocop/cop/lint/regexp_as_condition' @@ -311,38 +322,42 @@ require_relative 'rubocop/cop/lint/safe_navigation_chain' require_relative 'rubocop/cop/lint/safe_navigation_with_empty' require_relative 'rubocop/cop/lint/script_permission' +require_relative 'rubocop/cop/lint/self_assignment' +require_relative 'rubocop/cop/lint/send_with_mixin_argument' require_relative 'rubocop/cop/lint/shadowed_argument' require_relative 'rubocop/cop/lint/shadowed_exception' require_relative 'rubocop/cop/lint/shadowing_outer_local_variable' -require_relative 'rubocop/cop/lint/string_conversion_in_interpolation' +require_relative 'rubocop/cop/lint/struct_new_override' +require_relative 'rubocop/cop/lint/suppressed_exception' require_relative 'rubocop/cop/lint/syntax' require_relative 'rubocop/cop/lint/to_json' +require_relative 'rubocop/cop/lint/top_level_return_with_argument' +require_relative 'rubocop/cop/lint/trailing_comma_in_attribute_declaration' require_relative 'rubocop/cop/lint/underscore_prefixed_variable_name' require_relative 'rubocop/cop/lint/unified_integer' -require_relative 'rubocop/cop/lint/unneeded_cop_disable_directive' -require_relative 'rubocop/cop/lint/unneeded_cop_enable_directive' -require_relative 'rubocop/cop/lint/unneeded_require_statement' -require_relative 'rubocop/cop/lint/unneeded_splat_expansion' require_relative 'rubocop/cop/lint/unreachable_code' +require_relative 'rubocop/cop/lint/unreachable_loop' require_relative 'rubocop/cop/lint/unused_block_argument' require_relative 'rubocop/cop/lint/unused_method_argument' require_relative 'rubocop/cop/lint/uri_escape_unescape' require_relative 'rubocop/cop/lint/uri_regexp' require_relative 'rubocop/cop/lint/useless_access_modifier' require_relative 'rubocop/cop/lint/useless_assignment' -require_relative 'rubocop/cop/lint/useless_comparison' require_relative 'rubocop/cop/lint/useless_else_without_rescue' +require_relative 'rubocop/cop/lint/useless_method_definition' require_relative 'rubocop/cop/lint/useless_setter_call' +require_relative 'rubocop/cop/lint/useless_times' require_relative 'rubocop/cop/lint/void' +require_relative 'rubocop/cop/metrics/utils/iterating_block' require_relative 'rubocop/cop/metrics/cyclomatic_complexity' # relies on cyclomatic_complexity require_relative 'rubocop/cop/metrics/utils/abc_size_calculator' +require_relative 'rubocop/cop/metrics/utils/code_length_calculator' require_relative 'rubocop/cop/metrics/abc_size' require_relative 'rubocop/cop/metrics/block_length' require_relative 'rubocop/cop/metrics/block_nesting' require_relative 'rubocop/cop/metrics/class_length' -require_relative 'rubocop/cop/metrics/line_length' require_relative 'rubocop/cop/metrics/method_length' require_relative 'rubocop/cop/metrics/module_length' require_relative 'rubocop/cop/metrics/parameter_lists' @@ -350,6 +365,7 @@ require_relative 'rubocop/cop/naming/accessor_method_name' require_relative 'rubocop/cop/naming/ascii_identifiers' +require_relative 'rubocop/cop/naming/block_parameter_name' require_relative 'rubocop/cop/naming/class_and_module_camel_case' require_relative 'rubocop/cop/naming/constant_name' require_relative 'rubocop/cop/naming/file_name' @@ -357,64 +373,40 @@ require_relative 'rubocop/cop/naming/heredoc_delimiter_naming' require_relative 'rubocop/cop/naming/memoized_instance_variable_name' require_relative 'rubocop/cop/naming/method_name' +require_relative 'rubocop/cop/naming/method_parameter_name' require_relative 'rubocop/cop/naming/binary_operator_parameter_name' require_relative 'rubocop/cop/naming/predicate_name' -require_relative 'rubocop/cop/naming/uncommunicative_block_param_name' -require_relative 'rubocop/cop/naming/uncommunicative_method_param_name' +require_relative 'rubocop/cop/naming/rescued_exceptions_variable_name' require_relative 'rubocop/cop/naming/variable_name' require_relative 'rubocop/cop/naming/variable_number' -require_relative 'rubocop/cop/performance/caller' -require_relative 'rubocop/cop/performance/case_when_splat' -require_relative 'rubocop/cop/performance/casecmp' -require_relative 'rubocop/cop/performance/count' -require_relative 'rubocop/cop/performance/detect' -require_relative 'rubocop/cop/performance/double_start_end_with' -require_relative 'rubocop/cop/performance/end_with' -require_relative 'rubocop/cop/performance/fixed_size' -require_relative 'rubocop/cop/performance/flat_map' -require_relative 'rubocop/cop/performance/inefficient_hash_search' -require_relative 'rubocop/cop/performance/lstrip_rstrip' -require_relative 'rubocop/cop/performance/open_struct' -require_relative 'rubocop/cop/performance/range_include' -require_relative 'rubocop/cop/performance/redundant_block_call' -require_relative 'rubocop/cop/performance/redundant_match' -require_relative 'rubocop/cop/performance/redundant_merge' -require_relative 'rubocop/cop/performance/redundant_sort_by' -require_relative 'rubocop/cop/performance/regexp_match' -require_relative 'rubocop/cop/performance/reverse_each' -require_relative 'rubocop/cop/performance/sample' -require_relative 'rubocop/cop/performance/size' -require_relative 'rubocop/cop/performance/compare_with_block' -require_relative 'rubocop/cop/performance/start_with' -require_relative 'rubocop/cop/performance/string_replacement' -require_relative 'rubocop/cop/performance/times_map' -require_relative 'rubocop/cop/performance/unfreeze_string' -require_relative 'rubocop/cop/performance/unneeded_sort' -require_relative 'rubocop/cop/performance/uri_default_parser' -require_relative 'rubocop/cop/performance/chain_array_allocation' - require_relative 'rubocop/cop/style/access_modifier_declarations' +require_relative 'rubocop/cop/style/accessor_grouping' require_relative 'rubocop/cop/style/alias' require_relative 'rubocop/cop/style/and_or' +require_relative 'rubocop/cop/style/array_coercion' require_relative 'rubocop/cop/style/array_join' require_relative 'rubocop/cop/style/ascii_comments' require_relative 'rubocop/cop/style/attr' require_relative 'rubocop/cop/style/auto_resource_cleanup' require_relative 'rubocop/cop/style/bare_percent_literals' require_relative 'rubocop/cop/style/begin_block' +require_relative 'rubocop/cop/style/bisected_attr_accessor' require_relative 'rubocop/cop/style/block_comments' require_relative 'rubocop/cop/style/block_delimiters' -require_relative 'rubocop/cop/style/braces_around_hash_parameters' require_relative 'rubocop/cop/style/case_equality' +require_relative 'rubocop/cop/style/case_like_if' require_relative 'rubocop/cop/style/character_literal' require_relative 'rubocop/cop/style/class_and_module_children' require_relative 'rubocop/cop/style/class_check' +require_relative 'rubocop/cop/style/class_equality_comparison' require_relative 'rubocop/cop/style/class_methods' +require_relative 'rubocop/cop/style/class_methods_definitions' require_relative 'rubocop/cop/style/class_vars' require_relative 'rubocop/cop/style/collection_methods' require_relative 'rubocop/cop/style/colon_method_call' require_relative 'rubocop/cop/style/colon_method_definition' +require_relative 'rubocop/cop/style/combinable_loops' require_relative 'rubocop/cop/style/command_literal' require_relative 'rubocop/cop/style/comment_annotation' require_relative 'rubocop/cop/style/commented_keyword' @@ -424,8 +416,10 @@ require_relative 'rubocop/cop/style/date_time' require_relative 'rubocop/cop/style/def_with_parentheses' require_relative 'rubocop/cop/style/dir' +require_relative 'rubocop/cop/style/disable_cops_within_source_code_directive' require_relative 'rubocop/cop/style/documentation_method' require_relative 'rubocop/cop/style/documentation' +require_relative 'rubocop/cop/style/double_cop_disable_directive' require_relative 'rubocop/cop/style/double_negation' require_relative 'rubocop/cop/style/each_for_simple_loop' require_relative 'rubocop/cop/style/each_with_object' @@ -440,13 +434,22 @@ require_relative 'rubocop/cop/style/eval_with_location' require_relative 'rubocop/cop/style/even_odd' require_relative 'rubocop/cop/style/expand_path_arguments' +require_relative 'rubocop/cop/style/explicit_block_argument' +require_relative 'rubocop/cop/style/exponential_notation' +require_relative 'rubocop/cop/style/float_division' require_relative 'rubocop/cop/style/for' require_relative 'rubocop/cop/style/format_string' require_relative 'rubocop/cop/style/format_string_token' require_relative 'rubocop/cop/style/frozen_string_literal_comment' +require_relative 'rubocop/cop/style/global_std_stream' require_relative 'rubocop/cop/style/global_vars' require_relative 'rubocop/cop/style/guard_clause' +require_relative 'rubocop/cop/style/hash_as_last_array_item' +require_relative 'rubocop/cop/style/hash_each_methods' +require_relative 'rubocop/cop/style/hash_like_case' require_relative 'rubocop/cop/style/hash_syntax' +require_relative 'rubocop/cop/style/hash_transform_keys' +require_relative 'rubocop/cop/style/hash_transform_values' require_relative 'rubocop/cop/style/identical_conditional_branches' require_relative 'rubocop/cop/style/if_inside_else' require_relative 'rubocop/cop/style/if_unless_modifier' @@ -457,14 +460,21 @@ require_relative 'rubocop/cop/style/inverse_methods' require_relative 'rubocop/cop/style/inline_comment' require_relative 'rubocop/cop/style/ip_addresses' +require_relative 'rubocop/cop/style/keyword_parameters_order' require_relative 'rubocop/cop/style/lambda' require_relative 'rubocop/cop/style/lambda_call' require_relative 'rubocop/cop/style/line_end_concatenation' require_relative 'rubocop/cop/style/method_call_without_args_parentheses' require_relative 'rubocop/cop/style/method_call_with_args_parentheses' +require_relative 'rubocop/cop/style/redundant_assignment' +require_relative 'rubocop/cop/style/redundant_fetch_block' +require_relative 'rubocop/cop/style/redundant_file_extension_in_require' +require_relative 'rubocop/cop/style/redundant_self_assignment' +require_relative 'rubocop/cop/style/sole_nested_conditional' +require_relative 'rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses' +require_relative 'rubocop/cop/style/method_call_with_args_parentheses/require_parentheses' require_relative 'rubocop/cop/style/method_called_on_do_end_block' require_relative 'rubocop/cop/style/method_def_parentheses' -require_relative 'rubocop/cop/style/method_missing_super' require_relative 'rubocop/cop/style/min_max' require_relative 'rubocop/cop/style/missing_else' require_relative 'rubocop/cop/style/missing_respond_to_missing' @@ -477,9 +487,11 @@ require_relative 'rubocop/cop/style/multiline_method_signature' require_relative 'rubocop/cop/style/multiline_memoization' require_relative 'rubocop/cop/style/multiline_ternary_operator' +require_relative 'rubocop/cop/style/multiline_when_then' require_relative 'rubocop/cop/style/multiple_comparison' require_relative 'rubocop/cop/style/mutable_constant' require_relative 'rubocop/cop/style/negated_if' +require_relative 'rubocop/cop/style/negated_unless' require_relative 'rubocop/cop/style/negated_while' require_relative 'rubocop/cop/style/nested_modifier' require_relative 'rubocop/cop/style/nested_parenthesized_calls' @@ -495,6 +507,7 @@ require_relative 'rubocop/cop/style/or_assignment' require_relative 'rubocop/cop/style/option_hash' require_relative 'rubocop/cop/style/optional_arguments' +require_relative 'rubocop/cop/style/optional_boolean_parameter' require_relative 'rubocop/cop/style/parallel_assignment' require_relative 'rubocop/cop/style/parentheses_around_condition' require_relative 'rubocop/cop/style/percent_literal_delimiters' @@ -505,30 +518,43 @@ require_relative 'rubocop/cop/style/raise_args' require_relative 'rubocop/cop/style/random_with_offset' require_relative 'rubocop/cop/style/redundant_begin' +require_relative 'rubocop/cop/style/redundant_capital_w' +require_relative 'rubocop/cop/style/redundant_condition' +require_relative 'rubocop/cop/style/redundant_conditional' require_relative 'rubocop/cop/style/redundant_exception' require_relative 'rubocop/cop/style/redundant_freeze' +require_relative 'rubocop/cop/style/redundant_interpolation' require_relative 'rubocop/cop/style/redundant_parentheses' +require_relative 'rubocop/cop/style/redundant_percent_q' +require_relative 'rubocop/cop/style/redundant_regexp_character_class' +require_relative 'rubocop/cop/style/redundant_regexp_escape' require_relative 'rubocop/cop/style/redundant_return' require_relative 'rubocop/cop/style/redundant_self' -require_relative 'rubocop/cop/style/redundant_conditional' +require_relative 'rubocop/cop/style/redundant_sort' +require_relative 'rubocop/cop/style/redundant_sort_by' require_relative 'rubocop/cop/style/regexp_literal' require_relative 'rubocop/cop/style/rescue_modifier' require_relative 'rubocop/cop/style/rescue_standard_error' require_relative 'rubocop/cop/style/return_nil' require_relative 'rubocop/cop/style/safe_navigation' +require_relative 'rubocop/cop/style/sample' require_relative 'rubocop/cop/style/self_assignment' require_relative 'rubocop/cop/style/semicolon' require_relative 'rubocop/cop/style/send' require_relative 'rubocop/cop/style/signal_exception' +require_relative 'rubocop/cop/style/single_argument_dig' require_relative 'rubocop/cop/style/single_line_block_params' require_relative 'rubocop/cop/style/single_line_methods' +require_relative 'rubocop/cop/style/slicing_with_range' require_relative 'rubocop/cop/style/special_global_vars' require_relative 'rubocop/cop/style/stabby_lambda_parentheses' require_relative 'rubocop/cop/style/stderr_puts' +require_relative 'rubocop/cop/style/string_concatenation' require_relative 'rubocop/cop/style/string_hash_keys' require_relative 'rubocop/cop/style/string_literals' require_relative 'rubocop/cop/style/string_literals_in_interpolation' require_relative 'rubocop/cop/style/string_methods' +require_relative 'rubocop/cop/style/strip' require_relative 'rubocop/cop/style/struct_inheritance' require_relative 'rubocop/cop/style/symbol_array' require_relative 'rubocop/cop/style/symbol_literal' @@ -539,15 +565,12 @@ require_relative 'rubocop/cop/style/trailing_body_on_module' require_relative 'rubocop/cop/style/trailing_comma_in_arguments' require_relative 'rubocop/cop/style/trailing_comma_in_array_literal' +require_relative 'rubocop/cop/style/trailing_comma_in_block_args' require_relative 'rubocop/cop/style/trailing_comma_in_hash_literal' require_relative 'rubocop/cop/style/trailing_method_end_statement' require_relative 'rubocop/cop/style/trailing_underscore_variable' require_relative 'rubocop/cop/style/trivial_accessors' require_relative 'rubocop/cop/style/unless_else' -require_relative 'rubocop/cop/style/unneeded_capital_w' -require_relative 'rubocop/cop/style/unneeded_condition' -require_relative 'rubocop/cop/style/unneeded_interpolation' -require_relative 'rubocop/cop/style/unneeded_percent_q' require_relative 'rubocop/cop/style/unpack_first' require_relative 'rubocop/cop/style/variable_interpolation' require_relative 'rubocop/cop/style/when_then' @@ -557,56 +580,6 @@ require_relative 'rubocop/cop/style/yoda_condition' require_relative 'rubocop/cop/style/zero_length_predicate' -require_relative 'rubocop/cop/rails/action_filter' -require_relative 'rubocop/cop/rails/active_record_aliases' -require_relative 'rubocop/cop/rails/active_support_aliases' -require_relative 'rubocop/cop/rails/application_job' -require_relative 'rubocop/cop/rails/application_record' -require_relative 'rubocop/cop/rails/assert_not' -require_relative 'rubocop/cop/rails/belongs_to' -require_relative 'rubocop/cop/rails/blank' -require_relative 'rubocop/cop/rails/bulk_change_table' -require_relative 'rubocop/cop/rails/create_table_with_timestamps' -require_relative 'rubocop/cop/rails/date' -require_relative 'rubocop/cop/rails/delegate' -require_relative 'rubocop/cop/rails/delegate_allow_blank' -require_relative 'rubocop/cop/rails/dynamic_find_by' -require_relative 'rubocop/cop/rails/enum_uniqueness' -require_relative 'rubocop/cop/rails/environment_comparison' -require_relative 'rubocop/cop/rails/exit' -require_relative 'rubocop/cop/rails/file_path' -require_relative 'rubocop/cop/rails/find_by' -require_relative 'rubocop/cop/rails/find_each' -require_relative 'rubocop/cop/rails/has_and_belongs_to_many' -require_relative 'rubocop/cop/rails/has_many_or_has_one_dependent' -require_relative 'rubocop/cop/rails/http_positional_arguments' -require_relative 'rubocop/cop/rails/http_status' -require_relative 'rubocop/cop/rails/ignored_skip_action_filter_option' -require_relative 'rubocop/cop/rails/inverse_of' -require_relative 'rubocop/cop/rails/lexically_scoped_action_filter' -require_relative 'rubocop/cop/rails/link_to_blank' -require_relative 'rubocop/cop/rails/not_null_column' -require_relative 'rubocop/cop/rails/output' -require_relative 'rubocop/cop/rails/output_safety' -require_relative 'rubocop/cop/rails/pluralization_grammar' -require_relative 'rubocop/cop/rails/presence' -require_relative 'rubocop/cop/rails/present' -require_relative 'rubocop/cop/rails/read_write_attribute' -require_relative 'rubocop/cop/rails/redundant_receiver_in_with_options' -require_relative 'rubocop/cop/rails/reflection_class_name' -require_relative 'rubocop/cop/rails/refute_methods' -require_relative 'rubocop/cop/rails/relative_date_constant' -require_relative 'rubocop/cop/rails/request_referer' -require_relative 'rubocop/cop/rails/reversible_migration' -require_relative 'rubocop/cop/rails/safe_navigation' -require_relative 'rubocop/cop/rails/save_bang' -require_relative 'rubocop/cop/rails/scope_args' -require_relative 'rubocop/cop/rails/skips_model_validations' -require_relative 'rubocop/cop/rails/time_zone' -require_relative 'rubocop/cop/rails/uniq_before_pluck' -require_relative 'rubocop/cop/rails/unknown_env' -require_relative 'rubocop/cop/rails/validation' - require_relative 'rubocop/cop/security/eval' require_relative 'rubocop/cop/security/json_load' require_relative 'rubocop/cop/security/marshal_load' @@ -620,17 +593,18 @@ # relies on simple text require_relative 'rubocop/formatter/clang_style_formatter' require_relative 'rubocop/formatter/disabled_config_formatter' -require_relative 'rubocop/formatter/disabled_lines_formatter' require_relative 'rubocop/formatter/emacs_style_formatter' require_relative 'rubocop/formatter/file_list_formatter' require_relative 'rubocop/formatter/fuubar_style_formatter' require_relative 'rubocop/formatter/html_formatter' require_relative 'rubocop/formatter/json_formatter' +require_relative 'rubocop/formatter/junit_formatter' require_relative 'rubocop/formatter/offense_count_formatter' require_relative 'rubocop/formatter/progress_formatter' require_relative 'rubocop/formatter/quiet_formatter' require_relative 'rubocop/formatter/tap_formatter' require_relative 'rubocop/formatter/worst_offenders_formatter' +require_relative 'rubocop/formatter/pacman_formatter' # relies on progress formatter require_relative 'rubocop/formatter/auto_gen_config_formatter' @@ -640,15 +614,31 @@ require_relative 'rubocop/config' require_relative 'rubocop/config_loader_resolver' require_relative 'rubocop/config_loader' +require_relative 'rubocop/config_obsoletion' require_relative 'rubocop/config_store' +require_relative 'rubocop/config_validator' require_relative 'rubocop/target_finder' -require_relative 'rubocop/token' +require_relative 'rubocop/directive_comment' require_relative 'rubocop/comment_config' require_relative 'rubocop/magic_comment' -require_relative 'rubocop/processed_source' require_relative 'rubocop/result_cache' require_relative 'rubocop/runner' require_relative 'rubocop/cli' +require_relative 'rubocop/cli/command' +require_relative 'rubocop/cli/environment' +require_relative 'rubocop/cli/command/base' +require_relative 'rubocop/cli/command/auto_genenerate_config' +require_relative 'rubocop/cli/command/execute_runner' +require_relative 'rubocop/cli/command/init_dotfile' +require_relative 'rubocop/cli/command/show_cops' +require_relative 'rubocop/cli/command/version' +require_relative 'rubocop/config_regeneration' require_relative 'rubocop/options' require_relative 'rubocop/remote_config' +require_relative 'rubocop/target_ruby' require_relative 'rubocop/yaml_duplication_checker' + +unless File.exist?("#{__dir__}/../rubocop.gemspec") # Check if we are a gem + RuboCop::ResultCache.rubocop_required_features = $LOADED_FEATURES - before_us +end +RuboCop::AST.rubocop_loaded if RuboCop::AST.respond_to?(:rubocop_loaded) diff --git a/lib/rubocop/ast/builder.rb b/lib/rubocop/ast/builder.rb deleted file mode 100644 index bc124e07c202..000000000000 --- a/lib/rubocop/ast/builder.rb +++ /dev/null @@ -1,75 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # `RuboCop::AST::Builder` is an AST builder that is utilized to let `Parser` - # generate ASTs with {RuboCop::AST::Node}. - # - # @example - # buffer = Parser::Source::Buffer.new('(string)') - # buffer.source = 'puts :foo' - # - # builder = RuboCop::AST::Builder.new - # require 'parser/ruby25' - # parser = Parser::Ruby25.new(builder) - # root_node = parser.parse(buffer) - class Builder < Parser::Builders::Default - NODE_MAP = { - and: AndNode, - args: ArgsNode, - array: ArrayNode, - block: BlockNode, - break: BreakNode, - case: CaseNode, - def: DefNode, - defined?: DefinedNode, - defs: DefNode, - ensure: EnsureNode, - for: ForNode, - hash: HashNode, - if: IfNode, - irange: RangeNode, - erange: RangeNode, - kwsplat: KeywordSplatNode, - or: OrNode, - pair: PairNode, - regexp: RegexpNode, - resbody: ResbodyNode, - retry: RetryNode, - csend: SendNode, - send: SendNode, - str: StrNode, - dstr: StrNode, - xstr: StrNode, - super: SuperNode, - zsuper: SuperNode, - sym: SymbolNode, - until: UntilNode, - until_post: UntilNode, - when: WhenNode, - while: WhileNode, - while_post: WhileNode, - yield: YieldNode - }.freeze - - # Generates {Node} from the given information. - # - # @return [Node] the generated node - def n(type, children, source_map) - node_klass(type).new(type, children, location: source_map) - end - - # TODO: Figure out what to do about literal encoding handling... - # More details here https://github.com/whitequark/parser/issues/283 - def string_value(token) - value(token) - end - - private - - def node_klass(type) - NODE_MAP[type] || Node - end - end - end -end diff --git a/lib/rubocop/ast/node.rb b/lib/rubocop/ast/node.rb deleted file mode 100644 index 5941484e6186..000000000000 --- a/lib/rubocop/ast/node.rb +++ /dev/null @@ -1,642 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # `RuboCop::AST::Node` is a subclass of `Parser::AST::Node`. It provides - # access to parent nodes and an object-oriented way to traverse an AST with - # the power of `Enumerable`. - # - # It has predicate methods for every node type, like this: - # - # @example - # node.send_type? # Equivalent to: `node.type == :send` - # node.op_asgn_type? # Equivalent to: `node.type == :op_asgn` - # - # # Non-word characters (other than a-zA-Z0-9_) in type names are omitted. - # node.defined_type? # Equivalent to: `node.type == :defined?` - # - # # Find the first lvar node under the receiver node. - # lvar_node = node.each_descendant.find(&:lvar_type?) - # - class Node < Parser::AST::Node # rubocop:disable Metrics/ClassLength - include RuboCop::AST::Sexp - extend NodePattern::Macros - - # <=> isn't included here, because it doesn't return a boolean. - COMPARISON_OPERATORS = %i[== === != <= >= > <].freeze - - TRUTHY_LITERALS = %i[str dstr xstr int float sym dsym array - hash regexp true irange erange complex - rational regopt].freeze - FALSEY_LITERALS = %i[false nil].freeze - LITERALS = (TRUTHY_LITERALS + FALSEY_LITERALS).freeze - COMPOSITE_LITERALS = %i[dstr xstr dsym array hash irange - erange regexp].freeze - BASIC_LITERALS = (LITERALS - COMPOSITE_LITERALS).freeze - MUTABLE_LITERALS = %i[str dstr xstr array hash - regexp irange erange].freeze - IMMUTABLE_LITERALS = (LITERALS - MUTABLE_LITERALS).freeze - - EQUALS_ASSIGNMENTS = %i[lvasgn ivasgn cvasgn gvasgn - casgn masgn].freeze - SHORTHAND_ASSIGNMENTS = %i[op_asgn or_asgn and_asgn].freeze - ASSIGNMENTS = (EQUALS_ASSIGNMENTS + SHORTHAND_ASSIGNMENTS).freeze - - BASIC_CONDITIONALS = %i[if while until].freeze - CONDITIONALS = [*BASIC_CONDITIONALS, :case].freeze - VARIABLES = %i[ivar gvar cvar lvar].freeze - REFERENCES = %i[nth_ref back_ref].freeze - KEYWORDS = %i[alias and break case class def defs defined? - kwbegin do else ensure for if module next - not or postexe redo rescue retry return self - super zsuper then undef until when while - yield].freeze - OPERATOR_KEYWORDS = %i[and or].freeze - SPECIAL_KEYWORDS = %w[__FILE__ __LINE__ __ENCODING__].freeze - - # @see https://www.rubydoc.info/gems/ast/AST/Node:initialize - def initialize(type, children = [], properties = {}) - @mutable_attributes = {} - - # ::AST::Node#initialize freezes itself. - super - - # #parent= may be invoked multiple times for a node because there are - # pending nodes while constructing AST and they are replaced later. - # For example, `lvar` and `send` type nodes are initially created as an - # `ident` type node and fixed to the appropriate type later. - # So, the #parent attribute needs to be mutable. - each_child_node do |child_node| - child_node.parent = self unless child_node.complete? - end - end - - Parser::Meta::NODE_TYPES.each do |node_type| - method_name = "#{node_type.to_s.gsub(/\W/, '')}_type?" - define_method(method_name) do - type == node_type - end - end - - # Returns the parent node, or `nil` if the receiver is a root node. - # - # @return [Node, nil] the parent node or `nil` - def parent - @mutable_attributes[:parent] - end - - def parent=(node) - @mutable_attributes[:parent] = node - end - - def complete! - @mutable_attributes.freeze - each_child_node(&:complete!) - end - - def complete? - @mutable_attributes.frozen? - end - - protected :parent= # rubocop:disable Style/AccessModifierDeclarations - - # Override `AST::Node#updated` so that `AST::Processor` does not try to - # mutate our ASTs. Since we keep references from children to parents and - # not just the other way around, we cannot update an AST and share - # identical subtrees. Rather, the entire AST must be copied any time any - # part of it is changed. - def updated(type = nil, children = nil, properties = {}) - properties[:location] ||= @location - klass = RuboCop::AST::Builder::NODE_MAP[type || @type] || Node - klass.new(type || @type, children || @children, properties) - end - - # Returns the index of the receiver node in its siblings. (Sibling index - # uses zero based numbering.) - # - # @return [Integer] the index of the receiver node in its siblings - def sibling_index - parent.children.index { |sibling| sibling.equal?(self) } - end - - # Common destructuring method. This can be used to normalize - # destructuring for different variations of the node. - # Some node types override this with their own custom - # destructuring method. - # - # @return [Array] the different parts of the ndde - def node_parts - to_a - end - - # Calls the given block for each ancestor node from parent to root. - # If no block is given, an `Enumerator` is returned. - # - # @overload each_ancestor - # Yield all nodes. - # @overload each_ancestor(type) - # Yield only nodes matching the type. - # @param [Symbol] type a node type - # @overload each_ancestor(type_a, type_b, ...) - # Yield only nodes matching any of the types. - # @param [Symbol] type_a a node type - # @param [Symbol] type_b a node type - # @overload each_ancestor(types) - # Yield only nodes matching any of types in the array. - # @param [Array] types an array containing node types - # @yieldparam [Node] node each ancestor node - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_ancestor(*types, &block) - return to_enum(__method__, *types) unless block_given? - - visit_ancestors(types, &block) - - self - end - - # Returns an array of ancestor nodes. - # This is a shorthand for `node.each_ancestor.to_a`. - # - # @return [Array] an array of ancestor nodes - def ancestors - each_ancestor.to_a - end - - # Calls the given block for each child node. - # If no block is given, an `Enumerator` is returned. - # - # Note that this is different from `node.children.each { |child| ... }` - # which yields all children including non-node elements. - # - # @overload each_child_node - # Yield all nodes. - # @overload each_child_node(type) - # Yield only nodes matching the type. - # @param [Symbol] type a node type - # @overload each_child_node(type_a, type_b, ...) - # Yield only nodes matching any of the types. - # @param [Symbol] type_a a node type - # @param [Symbol] type_b a node type - # @overload each_child_node(types) - # Yield only nodes matching any of types in the array. - # @param [Array] types an array containing node types - # @yieldparam [Node] node each child node - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_child_node(*types) - return to_enum(__method__, *types) unless block_given? - - children.each do |child| - next unless child.is_a?(Node) - - yield child if types.empty? || types.include?(child.type) - end - - self - end - - # Returns an array of child nodes. - # This is a shorthand for `node.each_child_node.to_a`. - # - # @return [Array] an array of child nodes - def child_nodes - each_child_node.to_a - end - - # Calls the given block for each descendant node with depth first order. - # If no block is given, an `Enumerator` is returned. - # - # @overload each_descendant - # Yield all nodes. - # @overload each_descendant(type) - # Yield only nodes matching the type. - # @param [Symbol] type a node type - # @overload each_descendant(type_a, type_b, ...) - # Yield only nodes matching any of the types. - # @param [Symbol] type_a a node type - # @param [Symbol] type_b a node type - # @overload each_descendant(types) - # Yield only nodes matching any of types in the array. - # @param [Array] types an array containing node types - # @yieldparam [Node] node each descendant node - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_descendant(*types, &block) - return to_enum(__method__, *types) unless block_given? - - visit_descendants(types, &block) - - self - end - - # Returns an array of descendant nodes. - # This is a shorthand for `node.each_descendant.to_a`. - # - # @return [Array] an array of descendant nodes - def descendants - each_descendant.to_a - end - - # Calls the given block for the receiver and each descendant node in - # depth-first order. - # If no block is given, an `Enumerator` is returned. - # - # This method would be useful when you treat the receiver node as the root - # of a tree and want to iterate over all nodes in the tree. - # - # @overload each_node - # Yield all nodes. - # @overload each_node(type) - # Yield only nodes matching the type. - # @param [Symbol] type a node type - # @overload each_node(type_a, type_b, ...) - # Yield only nodes matching any of the types. - # @param [Symbol] type_a a node type - # @param [Symbol] type_b a node type - # @overload each_node(types) - # Yield only nodes matching any of types in the array. - # @param [Array] types an array containing node types - # @yieldparam [Node] node each node - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_node(*types, &block) - return to_enum(__method__, *types) unless block_given? - - yield self if types.empty? || types.include?(type) - - visit_descendants(types, &block) - - self - end - - def source - loc.expression.source - end - - def source_range - loc.expression - end - - def first_line - loc.line - end - - def last_line - loc.last_line - end - - def line_count - return 0 unless source_range - - source_range.last_line - source_range.first_line + 1 - end - - def nonempty_line_count - source.lines.grep(/\S/).size - end - - def source_length - source_range ? source_range.size : 0 - end - - ## Destructuring - - def_node_matcher :receiver, <<-PATTERN - {(send $_ ...) (block (send $_ ...) ...)} - PATTERN - - # Note: for masgn, #asgn_rhs will be an array node - def_node_matcher :asgn_rhs, '[assignment? (... $_)]' - def_node_matcher :str_content, '(str $_)' - - def const_name - return unless const_type? - - namespace, name = *self - if namespace && !namespace.cbase_type? - "#{namespace.const_name}::#{name}" - else - name.to_s - end - end - - def_node_matcher :defined_module0, <<-PATTERN - {(class (const $_ $_) ...) - (module (const $_ $_) ...) - (casgn $_ $_ (send (const nil? {:Class :Module}) :new ...)) - (casgn $_ $_ (block (send (const nil? {:Class :Module}) :new ...) ...))} - PATTERN - # rubocop:disable Style/AccessModifierDeclarations - private :defined_module0 - # rubocop:enable Style/AccessModifierDeclarations - - def defined_module - namespace, name = *defined_module0 - s(:const, namespace, name) if name - end - - def defined_module_name - (const = defined_module) && const.const_name - end - - ## Searching the AST - - def parent_module_name - # what class or module is this method/constant/etc definition in? - # returns nil if answer cannot be determined - ancestors = each_ancestor(:class, :module, :sclass, :casgn, :block) - result = ancestors.map do |ancestor| - parent_module_name_part(ancestor) { |full_name| return full_name } - end.compact.reverse.join('::') - result.empty? ? 'Object' : result - end - - ## Predicates - - def multiline? - line_count > 1 - end - - def single_line? - line_count == 1 - end - - def empty_source? - source_length.zero? - end - - # Some cops treat the shovel operator as a kind of assignment. - def_node_matcher :assignment_or_similar?, <<-PATTERN - {assignment? (send _recv :<< ...)} - PATTERN - - def literal? - LITERALS.include?(type) - end - - def basic_literal? - BASIC_LITERALS.include?(type) - end - - def truthy_literal? - TRUTHY_LITERALS.include?(type) - end - - def falsey_literal? - FALSEY_LITERALS.include?(type) - end - - def mutable_literal? - MUTABLE_LITERALS.include?(type) - end - - def immutable_literal? - IMMUTABLE_LITERALS.include?(type) - end - - %i[literal basic_literal].each do |kind| - recursive_kind = :"recursive_#{kind}?" - kind_filter = :"#{kind}?" - define_method(recursive_kind) do - case type - when :send - [*COMPARISON_OPERATORS, :!, :<=>].include?(method_name) && - receiver.send(recursive_kind) && - arguments.all?(&recursive_kind) - when :begin, :pair, *OPERATOR_KEYWORDS, *COMPOSITE_LITERALS - children.all?(&recursive_kind) - else - send(kind_filter) - end - end - end - - def variable? - VARIABLES.include?(type) - end - - def reference? - REFERENCES.include?(type) - end - - def equals_asgn? - EQUALS_ASSIGNMENTS.include?(type) - end - - def shorthand_asgn? - SHORTHAND_ASSIGNMENTS.include?(type) - end - - def assignment? - ASSIGNMENTS.include?(type) - end - - def basic_conditional? - BASIC_CONDITIONALS.include?(type) - end - - def conditional? - CONDITIONALS.include?(type) - end - - def keyword? - return true if special_keyword? || send_type? && prefix_not? - return false unless KEYWORDS.include?(type) - - !OPERATOR_KEYWORDS.include?(type) || loc.operator.is?(type.to_s) - end - - def special_keyword? - SPECIAL_KEYWORDS.include?(source) - end - - def operator_keyword? - OPERATOR_KEYWORDS.include?(type) - end - - def parenthesized_call? - loc.respond_to?(:begin) && loc.begin && loc.begin.is?('(') - end - - def chained? - parent && parent.send_type? && eql?(parent.receiver) - end - - def argument? - parent && parent.send_type? && parent.arguments.include?(self) - end - - def numeric_type? - int_type? || float_type? - end - - def range_type? - irange_type? || erange_type? - end - - def_node_matcher :guard_clause?, <<-PATTERN - [{(send nil? {:raise :fail} ...) return break next} single_line?] - PATTERN - - def_node_matcher :proc?, <<-PATTERN - {(block (send nil? :proc) ...) - (block (send (const nil? :Proc) :new) ...) - (send (const nil? :Proc) :new)} - PATTERN - - def_node_matcher :lambda?, '(block (send nil? :lambda) ...)' - def_node_matcher :lambda_or_proc?, '{lambda? proc?}' - - def_node_matcher :class_constructor?, <<-PATTERN - { (send (const nil? {:Class :Module}) :new ...) - (block (send (const nil? {:Class :Module}) :new ...) ...)} - PATTERN - - def_node_matcher :module_definition?, <<-PATTERN - {class module (casgn _ _ class_constructor?)} - PATTERN - - # Some expressions are evaluated for their value, some for their side - # effects, and some for both - # If we know that an expression is useful only for its side effects, that - # means we can transform it in ways which preserve the side effects, but - # change the return value - # So, does the return value of this node matter? If we changed it to - # `(...; nil)`, might that affect anything? - # - # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity - def value_used? - # Be conservative and return true if we're not sure. - return false if parent.nil? - - case parent.type - when :array, :defined?, :dstr, :dsym, :eflipflop, :erange, :float, - :hash, :iflipflop, :irange, :not, :pair, :regexp, :str, :sym, - :when, :xstr - parent.value_used? - when :begin, :kwbegin - begin_value_used? - when :for - for_value_used? - when :case, :if - case_if_value_used? - when :while, :until, :while_post, :until_post - while_until_value_used? - else - true - end - end - # rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity - - # Some expressions are evaluated for their value, some for their side - # effects, and some for both. - # If we know that expressions are useful only for their return values, - # and have no side effects, that means we can reorder them, change the - # number of times they are evaluated, or replace them with other - # expressions which are equivalent in value. - # So, is evaluation of this node free of side effects? - # - def pure? - # Be conservative and return false if we're not sure - case type - when :__FILE__, :__LINE__, :const, :cvar, :defined?, :false, :float, - :gvar, :int, :ivar, :lvar, :nil, :str, :sym, :true, :regopt - true - when :and, :array, :begin, :case, :dstr, :dsym, :eflipflop, :ensure, - :erange, :for, :hash, :if, :iflipflop, :irange, :kwbegin, :not, - :or, :pair, :regexp, :until, :until_post, :when, :while, - :while_post - child_nodes.all?(&:pure?) - else - false - end - end - - protected - - def visit_descendants(types, &block) - each_child_node do |child| - yield child if types.empty? || types.include?(child.type) - child.visit_descendants(types, &block) - end - end - - private - - def visit_ancestors(types) - last_node = self - - while (current_node = last_node.parent) - yield current_node if types.empty? || - types.include?(current_node.type) - last_node = current_node - end - end - - def begin_value_used? - # the last child node determines the value of the parent - sibling_index == parent.children.size - 1 ? parent.value_used? : false - end - - def for_value_used? - # `for var in enum; body; end` - # (for ) - sibling_index == 2 ? parent.value_used? : true - end - - def case_if_value_used? - # (case ) - # (if ) - sibling_index.zero? ? true : parent.value_used? - end - - def while_until_value_used? - # (while ) -> always evaluates to `nil` - sibling_index.zero? - end - - def parent_module_name_part(node) - case node.type - when :class, :module, :casgn - # TODO: if constant name has cbase (leading ::), then we don't need - # to keep traversing up through nested classes/modules - node.defined_module_name - when :sclass - yield parent_module_name_for_sclass(node) - else # block - parent_module_name_for_block(node) { yield nil } - end - end - - def parent_module_name_for_sclass(sclass_node) - # TODO: look for constant definition and see if it is nested - # inside a class or module - subject = sclass_node.children[0] - - if subject.const_type? - "#" - elsif subject.self_type? - "#" - end - end - - def parent_module_name_for_block(ancestor) - if ancestor.method_name == :class_eval - # `class_eval` with no receiver applies to whatever module or class - # we are currently in - return unless (receiver = ancestor.receiver) - - yield unless receiver.const_type? - receiver.const_name - elsif !new_class_or_module_block?(ancestor) - yield - end - end - - def_node_matcher :new_class_or_module_block?, <<-PATTERN - ^(casgn _ _ (block (send (const _ {:Class :Module}) :new) ...)) - PATTERN - end - end -end diff --git a/lib/rubocop/ast/node/and_node.rb b/lib/rubocop/ast/node/and_node.rb deleted file mode 100644 index c7fe9a97d23e..000000000000 --- a/lib/rubocop/ast/node/and_node.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `until` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `until` nodes within RuboCop. - class AndNode < Node - include BinaryOperatorNode - include PredicateOperatorNode - - # Returns the alternate operator of the `and` as a string. - # Returns `and` for `&&` and vice versa. - # - # @return [String] the alternate of the `and` operator - def alternate_operator - logical_operator? ? SEMANTIC_AND : LOGICAL_AND - end - - # Returns the inverse keyword of the `and` node as a string. - # Returns `||` for `&&` and `or` for `and`. - # - # @return [String] the inverse of the `and` operator - def inverse_operator - logical_operator? ? LOGICAL_OR : SEMANTIC_OR - end - end - end -end diff --git a/lib/rubocop/ast/node/args_node.rb b/lib/rubocop/ast/node/args_node.rb deleted file mode 100644 index 4e3d7689f817..000000000000 --- a/lib/rubocop/ast/node/args_node.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `args` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `args` nodes within RuboCop. - class ArgsNode < Node - include CollectionNode - - # It returns true if arguments are empty and delimiters do not exist. - # @example: - # # true - # def x; end - # x { } - # -> {} - # - # # false - # def x(); end - # def x a; end - # x { || } - # -> () {} - # -> a {} - def empty_and_without_delimiters? - loc.expression.nil? - end - end - end -end diff --git a/lib/rubocop/ast/node/array_node.rb b/lib/rubocop/ast/node/array_node.rb deleted file mode 100644 index d4f8835e0b42..000000000000 --- a/lib/rubocop/ast/node/array_node.rb +++ /dev/null @@ -1,57 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `array` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `array` nodes within RuboCop. - class ArrayNode < Node - PERCENT_LITERAL_TYPES = { - string: /^%[wW]/, - symbol: /^%[iI]/ - }.freeze - - # Returns an array of all value nodes in the `array` literal. - # - # @return [Array] an array of value nodes - def values - each_child_node.to_a - end - - # Checks whether the `array` literal is delimited by square brackets. - # - # @return [Boolean] whether the array is enclosed in square brackets - def square_brackets? - loc.begin && loc.begin.is?('[') - end - - # Checks whether the `array` literal is delimited by percent brackets. - # - # @overload percent_literal? - # Check for any percent literal. - # - # @overload percent_literal?(type) - # Check for percent literal of type `type`. - # - # @param type [Symbol] an optional percent literal type - # - # @return [Boolean] whether the array is enclosed in percent brackets - def percent_literal?(type = nil) - if type - loc.begin && loc.begin.source =~ PERCENT_LITERAL_TYPES[type] - else - loc.begin && loc.begin.source.start_with?('%') - end - end - - # Checks whether the `array` literal is delimited by either percent or - # square brackets - # - # @return [Boolean] whether the array is enclosed in percent or square - # brackets - def bracketed? - square_brackets? || percent_literal? - end - end - end -end diff --git a/lib/rubocop/ast/node/block_node.rb b/lib/rubocop/ast/node/block_node.rb deleted file mode 100644 index f37d67650804..000000000000 --- a/lib/rubocop/ast/node/block_node.rb +++ /dev/null @@ -1,115 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `block` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `send` nodes within RuboCop. - # - # A `block` node is essentially a method send with a block. Parser nests - # the `send` node inside the `block` node. - class BlockNode < Node - VOID_CONTEXT_METHODS = %i[each tap].freeze - - # The `send` node associated with this block. - # - # @return [SendNode] the `send` node associated with the `block` node - def send_node - node_parts[0] - end - - # The arguments of this block. - # - # @return [Array] - def arguments - node_parts[1] - end - - # The body of this block. - # - # @return [Node, nil] the body of the `block` node or `nil` - def body - node_parts[2] - end - - # The name of the dispatched method as a symbol. - # - # @return [Symbol] the name of the dispatched method - def method_name - send_node.method_name - end - - # Checks whether this block takes any arguments. - # - # @return [Boolean] whether this `block` node takes any arguments - def arguments? - !arguments.empty? - end - - # Checks whether the `block` literal is delimited by curly braces. - # - # @return [Boolean] whether the `block` literal is enclosed in braces - def braces? - loc.end && loc.end.is?('}') - end - - # Checks whether the `block` literal is delimited by `do`-`end` keywords. - # - # @return [Boolean] whether the `block` literal is enclosed in `do`-`end` - def keywords? - loc.end && loc.end.is?('end') - end - - # The delimiters for this `block` literal. - # - # @return [Array] the delimiters for the `block` literal - def delimiters - [loc.begin.source, loc.end.source].freeze - end - - # The opening delimiter for this `block` literal. - # - # @return [String] the opening delimiter for the `block` literal - def opening_delimiter - delimiters.first - end - - # The closing delimiter for this `block` literal. - # - # @return [String] the closing delimiter for the `block` literal - def closing_delimiter - delimiters.last - end - - # Checks whether this is a single line block. This is overridden here - # because the general version in `Node` does not work for `block` nodes. - # - # @return [Boolean] whether the `block` literal is on a single line - def single_line? - loc.begin.line == loc.end.line - end - - # Checks whether this is a multiline block. This is overridden here - # because the general version in `Node` does not work for `block` nodes. - # - # @return [Boolean] whether the `block` literal is on a several lines - def multiline? - !single_line? - end - - # Checks whether this `block` literal belongs to a lambda. - # - # @return [Boolean] whether the `block` literal belongs to a lambda - def lambda? - send_node.method?(:lambda) - end - - # Checks whether this node body is a void context. - # - # @return [Boolean] whether the `block` node body is a void context - def void_context? - VOID_CONTEXT_METHODS.include?(method_name) - end - end - end -end diff --git a/lib/rubocop/ast/node/break_node.rb b/lib/rubocop/ast/node/break_node.rb deleted file mode 100644 index 032aded7ea8d..000000000000 --- a/lib/rubocop/ast/node/break_node.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `break` nodes. This will be used in place of a - # plain node when the builder constructs the AST, making its methods - # available to all `break` nodes within RuboCop. - class BreakNode < Node - include MethodDispatchNode - include ParameterizedNode - - def arguments - [] - end - end - end -end diff --git a/lib/rubocop/ast/node/case_node.rb b/lib/rubocop/ast/node/case_node.rb deleted file mode 100644 index 42b75185a4a8..000000000000 --- a/lib/rubocop/ast/node/case_node.rb +++ /dev/null @@ -1,56 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `case` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `case` nodes within RuboCop. - class CaseNode < Node - include ConditionalNode - - # Returns the keyword of the `case` statement as a string. - # - # @return [String] the keyword of the `case` statement - def keyword - 'case' - end - - # Calls the given block for each `when` node in the `case` statement. - # If no block is given, an `Enumerator` is returned. - # - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_when - return when_branches.to_enum(__method__) unless block_given? - - when_branches.each do |condition| - yield condition - end - - self - end - - # Returns an array of all the when branches in the `case` statement. - # - # @return [Array] an array of `when` nodes - def when_branches - node_parts[1...-1] - end - - # Returns the else branch of the `case` statement, if any. - # - # @return [Node] the else branch node of the `case` statement - # @return [nil] if the case statement does not have an else branch. - def else_branch - node_parts[-1] - end - - # Checks whether this case statement has an `else` branch. - # - # @return [Boolean] whether the `case` statement has an `else` branch - def else? - loc.else - end - end - end -end diff --git a/lib/rubocop/ast/node/def_node.rb b/lib/rubocop/ast/node/def_node.rb deleted file mode 100644 index de697d0ef47e..000000000000 --- a/lib/rubocop/ast/node/def_node.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `def` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `def` nodes within RuboCop. - class DefNode < Node - include ParameterizedNode - include MethodIdentifierPredicates - - # Checks whether this node body is a void context. - # - # @return [Boolean] whether the `def` node body is a void context - def void_context? - method?(:initialize) || assignment_method? - end - - # The name of the defined method as a symbol. - # - # @return [Symbol] the name of the defined method - def method_name - node_parts[2] - end - - # An array containing the arguments of the method definition. - # - # @return [Array] the arguments of the method definition - def arguments - node_parts[1] - end - - # The body of the method definition. - # - # @note this can be either a `begin` node, if the method body contains - # multiple expressions, or any other node, if it contains a single - # expression. - # - # @return [Node] the body of the method definition - def body - node_parts[0] - end - - # The receiver of the method definition, if any. - # - # @return [Node, nil] the receiver of the method definition, or `nil`. - def receiver - node_parts[3] - end - - # Custom destructuring method. This can be used to normalize - # destructuring for different variations of the node. - # - # In this case, the `def` node destructures into: - # - # `method_name, arguments, body` - # - # while the `defs` node destructures into: - # - # `receiver, method_name, arguments, body` - # - # so we reverse the destructured array to get the optional receiver - # at the end, where it can be discarded. - # - # @return [Array] the different parts of the `def` or `defs` node - def node_parts - to_a.reverse - end - end - end -end diff --git a/lib/rubocop/ast/node/defined_node.rb b/lib/rubocop/ast/node/defined_node.rb deleted file mode 100644 index cf5229474d70..000000000000 --- a/lib/rubocop/ast/node/defined_node.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `defined?` nodes. This will be used in place of a - # plain node when the builder constructs the AST, making its methods - # available to all `send` nodes within RuboCop. - class DefinedNode < Node - include ParameterizedNode - include MethodDispatchNode - - def node_parts - [nil, :defined?, *to_a] - end - end - end -end diff --git a/lib/rubocop/ast/node/ensure_node.rb b/lib/rubocop/ast/node/ensure_node.rb deleted file mode 100644 index a9be864496bb..000000000000 --- a/lib/rubocop/ast/node/ensure_node.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `ensure` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `ensure` nodes within RuboCop. - class EnsureNode < Node - # Returns the body of the `ensure` clause. - # - # @return [Node, nil] The body of the `ensure`. - def body - node_parts[1] - end - end - end -end diff --git a/lib/rubocop/ast/node/for_node.rb b/lib/rubocop/ast/node/for_node.rb deleted file mode 100644 index b6c10aef66fa..000000000000 --- a/lib/rubocop/ast/node/for_node.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `for` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `for` nodes within RuboCop. - class ForNode < Node - # Returns the keyword of the `for` statement as a string. - # - # @return [String] the keyword of the `until` statement - def keyword - 'for' - end - - # Checks whether the `for` node has a `do` keyword. - # - # @return [Boolean] whether the `for` node has a `do` keyword - def do? - loc.begin && loc.begin.is?('do') - end - - # Checks whether this node body is a void context. - # Always `true` for `for`. - # - # @return [true] whether the `for` node body is a void context - def void_context? - true - end - - # Returns the iteration variable of the `for` loop. - # - # @return [Node] The iteration variable of the `for` loop - def variable - node_parts[0] - end - - # Returns the collection the `for` loop is iterating over. - # - # @return [Node] The collection the `for` loop is iterating over - def collection - node_parts[1] - end - - # Returns the body of the `for` loop. - # - # @return [Node, nil] The body of the `for` loop. - def body - node_parts[2] - end - end - end -end diff --git a/lib/rubocop/ast/node/hash_node.rb b/lib/rubocop/ast/node/hash_node.rb deleted file mode 100644 index 40afbcc03d20..000000000000 --- a/lib/rubocop/ast/node/hash_node.rb +++ /dev/null @@ -1,109 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `hash` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `hash` nodes within RuboCop. - class HashNode < Node - # Returns an array of all the key value pairs in the `hash` literal. - # - # @return [Array] an array of `pair` nodes - def pairs - each_pair.to_a - end - - # Checks whether the `hash` node contains any `pair`- or `kwsplat` nodes. - # - # @return[Boolean] whether the `hash` is empty - def empty? - children.empty? - end - - # Calls the given block for each `pair` node in the `hash` literal. - # If no block is given, an `Enumerator` is returned. - # - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_pair - return each_child_node(:pair).to_enum unless block_given? - - each_child_node(:pair) do |pair| - yield(*pair) - end - - self - end - - # Returns an array of all the keys in the `hash` literal. - # - # @return [Array] an array of keys in the `hash` literal - def keys - each_key.to_a - end - - # Calls the given block for each `key` node in the `hash` literal. - # If no block is given, an `Enumerator` is returned. - # - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_key - return pairs.map(&:key).to_enum unless block_given? - - pairs.map(&:key).each do |key| - yield key - end - - self - end - - # Returns an array of all the values in the `hash` literal. - # - # @return [Array] an array of values in the `hash` literal - def values - each_pair.map(&:value) - end - - # Calls the given block for each `value` node in the `hash` literal. - # If no block is given, an `Enumerator` is returned. - # - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_value - return pairs.map(&:value).to_enum unless block_given? - - pairs.map(&:value).each do |value| - yield value - end - - self - end - - # Checks whether any of the key value pairs in the `hash` literal are on - # the same line. - # - # @note A multiline `pair` is considered to be on the same line if it - # shares any of its lines with another `pair` - # - # @return [Boolean] whether any `pair` nodes are on the same line - def pairs_on_same_line? - pairs.each_cons(2).any? { |first, second| first.same_line?(second) } - end - - # Checks whether this `hash` uses a mix of hash rocket and colon - # delimiters for its pairs. - # - # @return [Boolean] whether the `hash` uses mixed delimiters - def mixed_delimiters? - pairs.map(&:delimiter).uniq.size > 1 - end - - # Checks whether the `hash` literal is delimited by curly braces. - # - # @return [Boolean] whether the `hash` literal is enclosed in braces - def braces? - loc.end && loc.end.is?('}') - end - end - end -end diff --git a/lib/rubocop/ast/node/if_node.rb b/lib/rubocop/ast/node/if_node.rb deleted file mode 100644 index c8bb187edfbf..000000000000 --- a/lib/rubocop/ast/node/if_node.rb +++ /dev/null @@ -1,175 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `if` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `if` nodes within RuboCop. - class IfNode < Node - include ConditionalNode - include ModifierNode - - # Checks whether this node is an `if` statement. (This is not true of - # ternary operators and `unless` statements.) - # - # @return [Boolean] whether the node is an `if` statement - def if? - keyword == 'if' - end - - # Checks whether this node is an `unless` statement. (This is not true - # of ternary operators and `if` statements.) - # - # @return [Boolean] whether the node is an `unless` statement - def unless? - keyword == 'unless' - end - - # Checks whether the `if` is an `elsif`. Parser handles these by nesting - # `if` nodes in the `else` branch. - # - # @return [Boolean] whether the node is an `elsif` - def elsif? - keyword == 'elsif' - end - - # Checks whether the `if` node has an `else` clause. - # - # @note This returns `true` for nodes containing an `elsif` clause. - # This is legacy behavior, and many cops rely on it. - # - # @return [Boolean] whether the node has an `else` clause - def else? - loc.respond_to?(:else) && loc.else - end - - # Checks whether the `if` node is a ternary operator. - # - # @return [Boolean] whether the `if` node is a ternary operator - def ternary? - loc.respond_to?(:question) - end - - # Returns the keyword of the `if` statement as a string. Returns an empty - # string for ternary operators. - # - # @return [String] the keyword of the `if` statement - def keyword - ternary? ? '' : loc.keyword.source - end - - # Returns the inverse keyword of the `if` node as a string. Returns `if` - # for `unless` nodes and vice versa. Returns an empty string for ternary - # operators. - # - # @return [String] the inverse keyword of the `if` statement - def inverse_keyword - if keyword == 'if' - 'unless' - elsif keyword == 'unless' - 'if' - else - '' - end - end - - # Checks whether the `if` node is in a modifier form, i.e. a condition - # trailing behind an expression. Only `if` and `unless` nodes without - # other branches can be modifiers. - # - # @return [Boolean] whether the `if` node is a modifier - def modifier_form? - (if? || unless?) && super - end - - # Chacks whether the `if` node has nested `if` nodes in any of its - # branches. - # - # @note This performs a shallow search. - # - # @return [Boolean] whether the `if` node contains nested conditionals - def nested_conditional? - node_parts[1..2].compact.each do |branch| - branch.each_node(:if) do |nested| - return true unless nested.elsif? - end - end - - false - end - - # Checks whether the `if` node has at least one `elsif` branch. Returns - # true if this `if` node itself is an `elsif`. - # - # @return [Boolean] whether the `if` node has at least one `elsif` branch - def elsif_conditional? - else_branch && else_branch.if_type? && else_branch.elsif? - end - - # Returns the branch of the `if` node that gets evaluated when its - # condition is truthy. - # - # @note This is normalized for `unless` nodes. - # - # @return [Node] the truthy branch node of the `if` node - # @return [nil] if the truthy branch is empty - def if_branch - node_parts[1] - end - - # Returns the branch of the `if` node that gets evaluated when its - # condition is falsey. - # - # @note This is normalized for `unless` nodes. - # - # @return [Node] the falsey branch node of the `if` node - # @return [nil] when there is no else branch - def else_branch - node_parts[2] - end - - # Custom destructuring method. This is used to normalize the branches - # for `if` and `unless` nodes, to aid comparisons and conversions. - # - # @return [Array] the different parts of the `if` statement - def node_parts - if unless? - condition, false_branch, true_branch = *self - else - condition, true_branch, false_branch = *self - end - - [condition, true_branch, false_branch] - end - - # Returns an array of all the branches in the conditional statement. - # - # @return [Array] an array of branch nodes - def branches - branches = [if_branch] - - return branches unless else_branch - - other_branches = if elsif_conditional? - else_branch.branches - else - [else_branch] - end - branches.concat(other_branches) - end - - # Calls the given block for each branch node in the conditional statement. - # If no block is given, an `Enumerator` is returned. - # - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_branch - return branches.to_enum(__method__) unless block_given? - - branches.each do |branch| - yield branch - end - end - end - end -end diff --git a/lib/rubocop/ast/node/keyword_splat_node.rb b/lib/rubocop/ast/node/keyword_splat_node.rb deleted file mode 100644 index 263a4791c9d0..000000000000 --- a/lib/rubocop/ast/node/keyword_splat_node.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `kwsplat` nodes. This will be used in place of a - # plain node when the builder constructs the AST, making its methods - # available to all `kwsplat` nodes within RuboCop. - class KeywordSplatNode < Node - include HashElementNode - - DOUBLE_SPLAT = '**'.freeze - - # This is used for duck typing with `pair` nodes which also appear as - # `hash` elements. - # - # @return [false] - def hash_rocket? - false - end - - # This is used for duck typing with `pair` nodes which also appear as - # `hash` elements. - # - # @return [false] - def colon? - false - end - - # Returns the operator for the `kwsplat` as a string. - # - # @return [String] the double splat operator - def operator - DOUBLE_SPLAT - end - - # Custom destructuring method. This is used to normalize the branches - # for `pair` and `kwsplat` nodes, to add duck typing to `hash` elements. - # - # @return [Array] the different parts of the `kwsplat` - def node_parts - [self, self] - end - end - end -end diff --git a/lib/rubocop/ast/node/mixin/basic_literal_node.rb b/lib/rubocop/ast/node/mixin/basic_literal_node.rb deleted file mode 100644 index 8354e6100a80..000000000000 --- a/lib/rubocop/ast/node/mixin/basic_literal_node.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Common functionality for primitive literal nodes: `sym`, `str`, - # `int`, `float`, ... - module BasicLiteralNode - # Returns the value of the literal. - # - # @return [mixed] the value of the literal - def value - node_parts[0] - end - end - end -end diff --git a/lib/rubocop/ast/node/mixin/binary_operator_node.rb b/lib/rubocop/ast/node/mixin/binary_operator_node.rb deleted file mode 100644 index b5cc6800c40e..000000000000 --- a/lib/rubocop/ast/node/mixin/binary_operator_node.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Common functionality for nodes that are binary operations: - # `or`, `and` ... - module BinaryOperatorNode - # Returns the left hand side node of the binary operation. - # - # @return [Node] the left hand side of the binary operation - def lhs - node_parts[0] - end - - # Returns the right hand side node of the binary operation. - # - # @return [Node] the right hand side of the binary operation - def rhs - node_parts[1] - end - - # Returns all of the conditions, including nested conditions, - # of the binary operation. - # - # @return [Array] the left and right hand side of the binary - # operation and the let and right hand side of any nested binary - # operators - def conditions - lhs, rhs = *self - lhs = lhs.children.first if lhs.begin_type? - rhs = rhs.children.first if rhs.begin_type? - - [lhs, rhs].each_with_object([]) do |side, collection| - if side.operator_keyword? - collection.concat(side.conditions) - else - collection << side - end - end - end - end - end -end diff --git a/lib/rubocop/ast/node/mixin/collection_node.rb b/lib/rubocop/ast/node/mixin/collection_node.rb deleted file mode 100644 index acb12de7a4df..000000000000 --- a/lib/rubocop/ast/node/mixin/collection_node.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A mixin that helps give collection nodes array polymorphism. - module CollectionNode - extend Forwardable - - ARRAY_METHODS = - (Array.instance_methods - Object.instance_methods - [:to_a]).freeze - - def_delegators :to_a, *ARRAY_METHODS - end - end -end diff --git a/lib/rubocop/ast/node/mixin/conditional_node.rb b/lib/rubocop/ast/node/mixin/conditional_node.rb deleted file mode 100644 index 656004a9654b..000000000000 --- a/lib/rubocop/ast/node/mixin/conditional_node.rb +++ /dev/null @@ -1,45 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Common functionality for nodes that have conditions: - # `if`, `while`, `until`, `case`. - # This currently doesn't include `when` nodes, because they have multiple - # conditions, and need to be checked for that. - module ConditionalNode - # Checks whether the condition of the node is written on a single line. - # - # @return [Boolean] whether the condition is on a single line - def single_line_condition? - loc.keyword.line == condition.source_range.line - end - - # Checks whether the condition of the node is written on more than - # one line. - # - # @return [Boolean] whether the condition is on more than one line - def multiline_condition? - !single_line_condition? - end - - # Returns the condition of the node. This works together with each node's - # custom destructuring method to select the correct part of the node. - # - # @return [Node, nil] the condition of the node - def condition - node_parts[0] - end - - # Returns the body associated with the condition. This works together with - # each node's custom destructuring method to select the correct part of - # the node. - # - # @note For `if` nodes, this is the truthy branch. - # - # @return [Node, nil] the body of the node - def body - node_parts[1] - end - end - end -end diff --git a/lib/rubocop/ast/node/mixin/hash_element_node.rb b/lib/rubocop/ast/node/mixin/hash_element_node.rb deleted file mode 100644 index 930a3c9dbb34..000000000000 --- a/lib/rubocop/ast/node/mixin/hash_element_node.rb +++ /dev/null @@ -1,125 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Common functionality for nodes that can be used as hash elements: - # `pair`, `kwsplat` - module HashElementNode - # Returns the key of this `hash` element. - # - # @note For keyword splats, this returns the whole node - # - # @return [Node] the key of the hash element - def key - node_parts[0] - end - - # Returns the value of this `hash` element. - # - # @note For keyword splats, this returns the whole node - # - # @return [Node] the value of the hash element - def value - node_parts[1] - end - - # Checks whether this `hash` element is on the same line as `other`. - # - # @note A multiline element is considered to be on the same line if it - # shares any of its lines with `other` - # - # @return [Boolean] whether this element is on the same line as `other` - def same_line?(other) - loc.last_line == other.loc.line || loc.line == other.loc.last_line - end - - # Returns the delta between this pair's key and the argument pair's. - # - # @note Keys on the same line always return a delta of 0 - # @note Keyword splats always return a delta of 0 for right alignment - # - # @param [Symbol] alignment whether to check the left or right side - # @return [Integer] the delta between the two keys - def key_delta(other, alignment = :left) - HashElementDelta.new(self, other).key_delta(alignment) - end - - # Returns the delta between this element's value and the argument's. - # - # @note Keyword splats always return a delta of 0 - # - # @return [Integer] the delta between the two values - def value_delta(other) - HashElementDelta.new(self, other).value_delta - end - - # Returns the delta between this element's delimiter and the argument's. - # - # @note Pairs with different delimiter styles return a delta of 0 - # - # @return [Integer] the delta between the two delimiters - def delimiter_delta(other) - HashElementDelta.new(self, other).delimiter_delta - end - - # A helper class for comparing the positions of different parts of a - # `pair` node. - class HashElementDelta - def initialize(first, second) - @first = first - @second = second - - raise ArgumentError unless valid_argument_types? - end - - def key_delta(alignment = :left) - return 0 if first.same_line?(second) - return 0 if keyword_splat? && alignment == :right - - delta(first.key.loc, second.key.loc, alignment) - end - - def value_delta - return 0 if first.same_line?(second) - return 0 if keyword_splat? - - delta(first.value.loc, second.value.loc) - end - - def delimiter_delta - return 0 if first.same_line?(second) - return 0 if first.delimiter != second.delimiter - - delta(first.loc.operator, second.loc.operator) - end - - private - - attr_reader :first, :second - - def valid_argument_types? - [first, second].all? do |argument| - argument.pair_type? || argument.kwsplat_type? - end - end - - def delta(first, second, alignment = :left) - case alignment - when :left - first.column - second.column - when :right - first.last_column - second.last_column - else - 0 - end - end - - def keyword_splat? - [first, second].any?(&:kwsplat_type?) - end - end - - private_constant :HashElementDelta - end - end -end diff --git a/lib/rubocop/ast/node/mixin/method_dispatch_node.rb b/lib/rubocop/ast/node/mixin/method_dispatch_node.rb deleted file mode 100644 index bb6e6297922e..000000000000 --- a/lib/rubocop/ast/node/mixin/method_dispatch_node.rb +++ /dev/null @@ -1,251 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Common functionality for nodes that are a kind of method dispatch: - # `send`, `csend`, `super`, `zsuper`, `yield`, `defined?` - module MethodDispatchNode - extend NodePattern::Macros - include MethodIdentifierPredicates - - ARITHMETIC_OPERATORS = %i[+ - * / % **].freeze - - # The receiving node of the method dispatch. - # - # @return [Node, nil] the receiver of the dispatched method or `nil` - def receiver - node_parts[0] - end - - # The name of the dispatched method as a symbol. - # - # @return [Symbol] the name of the dispatched method - def method_name - node_parts[1] - end - - # An array containing the arguments of the dispatched method. - # - # @return [Array] the arguments of the dispatched method - def arguments - node_parts[2..-1] - end - - # The `block` node associated with this method dispatch, if any. - # - # @return [BlockNode, nil] the `block` node associated with this method - # call or `nil` - def block_node - parent if block_literal? - end - - # Checks whether the dispatched method is a macro method. A macro method - # is defined as a method that sits in a class, module, or block body and - # has an implicit receiver. - # - # @note This does not include DSLs that use nested blocks, like RSpec - # - # @return [Boolean] whether the dispatched method is a macro method - def macro? - !receiver && macro_scope? - end - - # Checks whether the dispatched method is an access modifier. - # - # @return [Boolean] whether the dispatched method is an access modifier - def access_modifier? - bare_access_modifier? || non_bare_access_modifier? - end - - # Checks whether the dispatched method is a bare access modifier that - # affects all methods defined after the macro. - # - # @return [Boolean] whether the dispatched method is a bare - # access modifier - def bare_access_modifier? - macro? && bare_access_modifier_declaration? - end - - # Checks whether the dispatched method is a non-bare access modifier that - # affects only the method it receives. - # - # @return [Boolean] whether the dispatched method is a non-bare - # access modifier - def non_bare_access_modifier? - macro? && non_bare_access_modifier_declaration? - end - - # Checks whether the name of the dispatched method matches the argument - # and has an implicit receiver. - # - # @param [Symbol, String] name the method name to check for - # @return [Boolean] whether the method name matches the argument - def command?(name) - !receiver && method?(name) - end - - # Checks whether the dispatched method is a setter method. - # - # @return [Boolean] whether the dispatched method is a setter - def setter_method? - loc.respond_to?(:operator) && loc.operator - end - alias assignment? setter_method? - - # Checks whether the dispatched method uses a dot to connect the - # receiver and the method name. - # - # This is useful for comparison operators, which can be called either - # with or without a dot, i.e. `foo == bar` or `foo.== bar`. - # - # @return [Boolean] whether the method was called with a connecting dot - def dot? - loc.respond_to?(:dot) && loc.dot && loc.dot.is?('.') - end - - # Checks whether the dispatched method uses a double colon to connect the - # receiver and the method name. - # - # @return [Boolean] whether the method was called with a connecting dot - def double_colon? - loc.respond_to?(:dot) && loc.dot && loc.dot.is?('::') - end - - # Checks whether the *explicit* receiver of this method dispatch is - # `self`. - # - # @return [Boolean] whether the receiver of this method dispatch is `self` - def self_receiver? - receiver && receiver.self_type? - end - - # Checks whether the *explicit* receiver of this method dispatch is a - # `const` node. - # - # @return [Boolean] whether the receiver of this method dispatch - # is a `const` node - def const_receiver? - receiver && receiver.const_type? - end - - # Checks whether the method dispatch is the implicit form of `#call`, - # e.g. `foo.(bar)`. - # - # @return [Boolean] whether the method is the implicit form of `#call` - def implicit_call? - method?(:call) && !loc.selector - end - - # Whether this method dispatch has an explicit block. - # - # @return [Boolean] whether the dispatched method has a block - def block_literal? - parent && parent.block_type? && eql?(parent.send_node) - end - - # Checks whether this node is an arithmetic operation - # - # @return [Boolean] whether the dispatched method is an arithmetic - # operation - def arithmetic_operation? - ARITHMETIC_OPERATORS.include?(method_name) - end - - # Checks if this node is part of a chain of `def` modifiers. - # - # @example - # - # private def foo; end - # - # @return [Boolean] whether the dispatched method is a `def` modifier - def def_modifier? - send_type? && - [self, *each_descendant(:send)].any?(&:adjacent_def_modifier?) - end - - # Checks whether this is a lambda. Some versions of parser parses - # non-literal lambdas as a method send. - # - # @return [Boolean] whether this method is a lambda - def lambda? - block_literal? && command?(:lambda) - end - - # Checks whether this is a lambda literal (stabby lambda.) - # - # @example - # - # -> (foo) { bar } - # - # @return [Boolean] whether this method is a lambda literal - def lambda_literal? - block_literal? && loc.expression && loc.expression.source == '->' - end - - # Checks whether this is a unary operation. - # - # @example - # - # -foo - # - # @return [Boolean] whether this method is a unary operation - def unary_operation? - return false unless loc.selector - - operator_method? && loc.expression.begin_pos == loc.selector.begin_pos - end - - # Checks whether this is a binary operation. - # - # @example - # - # foo + bar - # - # @return [Bookean] whether this method is a binary operation - def binary_operation? - return false unless loc.selector - - operator_method? && loc.expression.begin_pos != loc.selector.begin_pos - end - - private - - def_node_matcher :macro_scope?, <<-PATTERN - {^{({sclass class module block} ...) class_constructor?} - ^^{({sclass class module block} ... (begin ...)) class_constructor?} - ^#macro_kwbegin_wrapper? - #root_node?} - PATTERN - - # Check if a node's parent is a kwbegin wrapper within a macro scope - # - # @param parent [Node] parent of the node being checked - # - # @return [Boolean] true if the parent is a kwbegin in a macro scope - def macro_kwbegin_wrapper?(parent) - parent.kwbegin_type? && macro_scope?(parent) - end - - # Check if a node does not have a parent - # - # @param node [Node] - # - # @return [Boolean] if the parent is nil - def root_node?(node) - node.parent.nil? - end - - def_node_matcher :adjacent_def_modifier?, <<-PATTERN - (send nil? _ ({def defs} ...)) - PATTERN - - def_node_matcher :bare_access_modifier_declaration?, <<-PATTERN - (send nil? {:public :protected :private :module_function}) - PATTERN - - def_node_matcher :non_bare_access_modifier_declaration?, <<-PATTERN - (send nil? {:public :protected :private :module_function} _) - PATTERN - end - end -end diff --git a/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb b/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb deleted file mode 100644 index a0c25fe7b02b..000000000000 --- a/lib/rubocop/ast/node/mixin/method_identifier_predicates.rb +++ /dev/null @@ -1,114 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Common predicates for nodes that reference method identifiers: - # `send`, `csend`, `def`, `defs`, `super`, `zsuper` - # - # @note this mixin expects `#method_name` and `#receiver` to be implemented - module MethodIdentifierPredicates - ENUMERATOR_METHODS = %i[collect collect_concat detect downto each - find find_all find_index inject loop map! - map reduce reject reject! reverse_each select - select! times upto].freeze - - # http://phrogz.net/programmingruby/language.html#table_18.4 - OPERATOR_METHODS = %i[| ^ & <=> == === =~ > >= < <= << >> + - * / - % ** ~ +@ -@ !@ ~@ [] []= ! != !~ `].freeze - - # Checks whether the method name matches the argument. - # - # @param [Symbol, String] name the method name to check for - # @return [Boolean] whether the method name matches the argument - def method?(name) - method_name == name.to_sym - end - - # Checks whether the method is an operator method. - # - # @return [Boolean] whether the method is an operator - def operator_method? - OPERATOR_METHODS.include?(method_name) - end - - # Checks whether the method is a comparison method. - # - # @return [Boolean] whether the method is a comparison - def comparison_method? - Node::COMPARISON_OPERATORS.include?(method_name) - end - - # Checks whether the method is an assignment method. - # - # @return [Boolean] whether the method is an assignment - def assignment_method? - !comparison_method? && method_name.to_s.end_with?('=') - end - - # Checks whether the method is an enumerator method. - # - # @return [Boolean] whether the method is an enumerator - def enumerator_method? - ENUMERATOR_METHODS.include?(method_name) || - method_name.to_s.start_with?('each_') - end - - # Checks whether the method is a predicate method. - # - # @return [Boolean] whether the method is a predicate method - def predicate_method? - method_name.to_s.end_with?('?') - end - - # Checks whether the method is a bang method. - # - # @return [Boolean] whether the method is a bang method - def bang_method? - method_name.to_s.end_with?('!') - end - - # Checks whether the method is a camel case method, - # e.g. `Integer()`. - # - # @return [Boolean] whether the method is a camel case method - def camel_case_method? - method_name.to_s =~ /\A[A-Z]/ - end - - # Checks whether the *explicit* receiver of this node is `self`. - # - # @return [Boolean] whether the receiver of this node is `self` - def self_receiver? - receiver && receiver.self_type? - end - - # Checks whether the *explicit* receiver of node is a `const` node. - # - # @return [Boolean] whether the receiver of this node is a `const` node - def const_receiver? - receiver && receiver.const_type? - end - - # Checks whether this is a negation method, i.e. `!` or keyword `not`. - # - # @return [Boolean] whether this method is a negation method - def negation_method? - receiver && method_name == :! - end - - # Checks whether this is a prefix not method, e.g. `not foo`. - # - # @return [Boolean] whether this method is a prefix not - def prefix_not? - negation_method? && loc.selector.is?('not') - end - - # Checks whether this is a prefix bang method, e.g. `!foo`. - # - # @return [Boolean] whether this method is a prefix bang - def prefix_bang? - negation_method? && loc.selector.is?('!') - end - end - end -end diff --git a/lib/rubocop/ast/node/mixin/modifier_node.rb b/lib/rubocop/ast/node/mixin/modifier_node.rb deleted file mode 100644 index 55ffa80787ab..000000000000 --- a/lib/rubocop/ast/node/mixin/modifier_node.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Common functionality for nodes that can be used as modifiers: - # `if`, `while`, `until` - module ModifierNode - # Checks whether the node is in a modifier form, i.e. a condition - # trailing behind an expression. - # - # @return [Boolean] whether the node is a modifier - def modifier_form? - loc.end.nil? - end - end - end -end diff --git a/lib/rubocop/ast/node/mixin/parameterized_node.rb b/lib/rubocop/ast/node/mixin/parameterized_node.rb deleted file mode 100644 index 0ecb3afbcb66..000000000000 --- a/lib/rubocop/ast/node/mixin/parameterized_node.rb +++ /dev/null @@ -1,61 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Common functionality for nodes that are parameterized: - # `send`, `super`, `zsuper`, `def`, `defs` - module ParameterizedNode - # Checks whether this node's arguments are wrapped in parentheses. - # - # @return [Boolean] whether this node's arguments are - # wrapped in parentheses - def parenthesized? - loc.end && loc.end.is?(')') - end - - # A shorthand for getting the first argument of the node. - # Equivalent to `arguments.first`. - # - # @return [Node, nil] the first argument of the node, - # or `nil` if there are no arguments - def first_argument - arguments[0] - end - - # A shorthand for getting the last argument of the node. - # Equivalent to `arguments.last`. - # - # @return [Node, nil] the last argument of the node, - # or `nil` if there are no arguments - def last_argument - arguments[-1] - end - - # Checks whether this node has any arguments. - # - # @return [Boolean] whether this node has any arguments - def arguments? - !arguments.empty? - end - - # Checks whether any argument of the node is a splat - # argument, i.e. `*splat`. - # - # @return [Boolean] whether the node is a splat argument - def splat_argument? - arguments? && - (arguments.any?(&:splat_type?) || arguments.any?(&:restarg_type?)) - end - alias rest_argument? splat_argument? - - # Whether the last argument of the node is a block pass, - # i.e. `&block`. - # - # @return [Boolean] whether the last argument of the node is a block pass - def block_argument? - arguments? && - (last_argument.block_pass_type? || last_argument.blockarg_type?) - end - end - end -end diff --git a/lib/rubocop/ast/node/mixin/predicate_operator_node.rb b/lib/rubocop/ast/node/mixin/predicate_operator_node.rb deleted file mode 100644 index 1813976cd68c..000000000000 --- a/lib/rubocop/ast/node/mixin/predicate_operator_node.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Common functionality for nodes that are predicates: - # `or`, `and` ... - module PredicateOperatorNode - LOGICAL_AND = '&&'.freeze - SEMANTIC_AND = 'and'.freeze - LOGICAL_OR = '||'.freeze - SEMANTIC_OR = 'or'.freeze - - # Returns the operator as a string. - # - # @return [String] the operator - def operator - loc.operator.source - end - - # Checks whether this is a logical operator. - # - # @return [Boolean] whether this is a logical operator - def logical_operator? - operator == LOGICAL_AND || operator == LOGICAL_OR - end - - # Checks whether this is a semantic operator. - # - # @return [Boolean] whether this is a semantic operator - def semantic_operator? - operator == SEMANTIC_AND || operator == SEMANTIC_OR - end - end - end -end diff --git a/lib/rubocop/ast/node/or_node.rb b/lib/rubocop/ast/node/or_node.rb deleted file mode 100644 index 31c65ac481c1..000000000000 --- a/lib/rubocop/ast/node/or_node.rb +++ /dev/null @@ -1,29 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `or` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `or` nodes within RuboCop. - class OrNode < Node - include BinaryOperatorNode - include PredicateOperatorNode - - # Returns the alternate operator of the `or` as a string. - # Returns `or` for `||` and vice versa. - # - # @return [String] the alternate of the `or` operator - def alternate_operator - logical_operator? ? SEMANTIC_OR : LOGICAL_OR - end - - # Returns the inverse keyword of the `or` node as a string. - # Returns `and` for `or` and `&&` for `||`. - # - # @return [String] the inverse of the `or` operator - def inverse_operator - logical_operator? ? LOGICAL_AND : SEMANTIC_AND - end - end - end -end diff --git a/lib/rubocop/ast/node/pair_node.rb b/lib/rubocop/ast/node/pair_node.rb deleted file mode 100644 index 47e6fa4ed7d9..000000000000 --- a/lib/rubocop/ast/node/pair_node.rb +++ /dev/null @@ -1,63 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `pair` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `pair` nodes within RuboCop. - class PairNode < Node - include HashElementNode - - HASH_ROCKET = '=>'.freeze - SPACED_HASH_ROCKET = ' => '.freeze - COLON = ':'.freeze - SPACED_COLON = ': '.freeze - - # Checks whether the `pair` uses a hash rocket delimiter. - # - # @return [Boolean] whether this `pair` uses a hash rocket delimiter - def hash_rocket? - loc.operator.is?(HASH_ROCKET) - end - - # Checks whether the `pair` uses a colon delimiter. - # - # @return [Boolean] whether this `pair` uses a colon delimiter - def colon? - loc.operator.is?(COLON) - end - - # Returns the delimiter of the `pair` as a string. Returns `=>` for a - # colon delimited `pair` and `:` for a hash rocket delimited `pair`. - # - # @param [Boolean] with_spacing whether to include spacing - # @return [String] the delimiter of the `pair` - def delimiter(with_spacing = false) - if with_spacing - hash_rocket? ? SPACED_HASH_ROCKET : SPACED_COLON - else - hash_rocket? ? HASH_ROCKET : COLON - end - end - - # Returns the inverse delimiter of the `pair` as a string. - # - # @param [Boolean] with_spacing whether to include spacing - # @return [String] the inverse delimiter of the `pair` - def inverse_delimiter(with_spacing = false) - if with_spacing - hash_rocket? ? SPACED_COLON : SPACED_HASH_ROCKET - else - hash_rocket? ? COLON : HASH_ROCKET - end - end - - # Checks whether the value starts on its own line. - # - # @return [Boolean] whether the value in the `pair` starts its own line - def value_on_new_line? - key.loc.line != value.loc.line - end - end - end -end diff --git a/lib/rubocop/ast/node/range_node.rb b/lib/rubocop/ast/node/range_node.rb deleted file mode 100644 index b7c5e74840ac..000000000000 --- a/lib/rubocop/ast/node/range_node.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `irange` and `erange` nodes. This will be used in - # place of a plain node when the builder constructs the AST, making its - # methods available to all `irange` and `erange` nodes within RuboCop. - class RangeNode < Node - end - end -end diff --git a/lib/rubocop/ast/node/regexp_node.rb b/lib/rubocop/ast/node/regexp_node.rb deleted file mode 100644 index 4024e7f58240..000000000000 --- a/lib/rubocop/ast/node/regexp_node.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `regexp` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `regexp` nodes within RuboCop. - class RegexpNode < Node - OPTIONS = { - x: Regexp::EXTENDED, - i: Regexp::IGNORECASE, - m: Regexp::MULTILINE, - n: Regexp::NOENCODING - }.freeze - - # @return [Regexp] a regexp of this node - def to_regexp - option = regopt.children.map { |opt| OPTIONS[opt] }.inject(:|) - Regexp.new(content, option) - end - - # @return [RuboCop::AST::Node] a regopt node - def regopt - first, second = *self - first.regopt_type? ? first : second - end - - # @return [String] a string of regexp content - def content - str = children.first - str.str_content || '' - end - end - end -end diff --git a/lib/rubocop/ast/node/resbody_node.rb b/lib/rubocop/ast/node/resbody_node.rb deleted file mode 100644 index f51e83e59cfd..000000000000 --- a/lib/rubocop/ast/node/resbody_node.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `resbody` nodes. This will be used in place of a - # plain node when the builder constructs the AST, making its methods - # available to all `resbody` nodes within RuboCop. - class ResbodyNode < Node - # Returns the body of the `rescue` clause. - # - # @return [Node, nil] The body of the `resbody`. - def body - node_parts[2] - end - end - end -end diff --git a/lib/rubocop/ast/node/retry_node.rb b/lib/rubocop/ast/node/retry_node.rb deleted file mode 100644 index e1aa96046dc3..000000000000 --- a/lib/rubocop/ast/node/retry_node.rb +++ /dev/null @@ -1,17 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `retry` nodes. This will be used in place of a - # plain node when the builder constructs the AST, making its methods - # available to all `retry` nodes within RuboCop. - class RetryNode < Node - include MethodDispatchNode - include ParameterizedNode - - def arguments - [] - end - end - end -end diff --git a/lib/rubocop/ast/node/send_node.rb b/lib/rubocop/ast/node/send_node.rb deleted file mode 100644 index 363e5a6a3b09..000000000000 --- a/lib/rubocop/ast/node/send_node.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `send` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `send` nodes within RuboCop. - class SendNode < Node - include ParameterizedNode - include MethodDispatchNode - end - end -end diff --git a/lib/rubocop/ast/node/str_node.rb b/lib/rubocop/ast/node/str_node.rb deleted file mode 100644 index 37b95bd73993..000000000000 --- a/lib/rubocop/ast/node/str_node.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `str`, `dstr`, and `xstr` nodes. This will be used - # in place of a plain node when the builder constructs the AST, making - # its methods available to all `str` nodes within RuboCop. - class StrNode < Node - include BasicLiteralNode - - def heredoc? - loc.is_a?(Parser::Source::Map::Heredoc) - end - end - end -end diff --git a/lib/rubocop/ast/node/super_node.rb b/lib/rubocop/ast/node/super_node.rb deleted file mode 100644 index db7a01c40831..000000000000 --- a/lib/rubocop/ast/node/super_node.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `super`- and `zsuper` nodes. This will be used in - # place of a plain node when the builder constructs the AST, making its - # methods available to all `super`- and `zsuper` nodes within RuboCop. - class SuperNode < Node - include ParameterizedNode - include MethodDispatchNode - - # Custom destructuring method. This can be used to normalize - # destructuring for different variations of the node. - # - # @return [Array] the different parts of the `super` node - def node_parts - [nil, :super, *to_a] - end - end - end -end diff --git a/lib/rubocop/ast/node/symbol_node.rb b/lib/rubocop/ast/node/symbol_node.rb deleted file mode 100644 index 9f3c4d064197..000000000000 --- a/lib/rubocop/ast/node/symbol_node.rb +++ /dev/null @@ -1,12 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `sym` nodes. This will be used in place of a - # plain node when the builder constructs the AST, making its methods - # available to all `sym` nodes within RuboCop. - class SymbolNode < Node - include BasicLiteralNode - end - end -end diff --git a/lib/rubocop/ast/node/until_node.rb b/lib/rubocop/ast/node/until_node.rb deleted file mode 100644 index 18f8af898d88..000000000000 --- a/lib/rubocop/ast/node/until_node.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `until` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `until` nodes within RuboCop. - class UntilNode < Node - include ConditionalNode - include ModifierNode - - # Returns the keyword of the `until` statement as a string. - # - # @return [String] the keyword of the `until` statement - def keyword - 'until' - end - - # Returns the inverse keyword of the `until` node as a string. - # Returns `while` for `until` nodes and vice versa. - # - # @return [String] the inverse keyword of the `until` statement - def inverse_keyword - 'while' - end - - # Checks whether the `until` node has a `do` keyword. - # - # @return [Boolean] whether the `until` node has a `do` keyword - def do? - loc.begin && loc.begin.is?('do') - end - end - end -end diff --git a/lib/rubocop/ast/node/when_node.rb b/lib/rubocop/ast/node/when_node.rb deleted file mode 100644 index 1fd1c15e2b45..000000000000 --- a/lib/rubocop/ast/node/when_node.rb +++ /dev/null @@ -1,53 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `when` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `when` nodes within RuboCop. - class WhenNode < Node - # Returns an array of all the conditions in the `when` branch. - # - # @return [Array] an array of condition nodes - def conditions - node_parts[0...-1] - end - - # Calls the given block for each condition node in the `when` branch. - # If no block is given, an `Enumerator` is returned. - # - # @return [self] if a block is given - # @return [Enumerator] if no block is given - def each_condition - return conditions.to_enum(__method__) unless block_given? - - conditions.each do |condition| - yield condition - end - - self - end - - # Returns the index of the `when` branch within the `case` statement. - # - # @return [Integer] the index of the `when` branch - def branch_index - parent.when_branches.index(self) - end - - # Checks whether the `when` node has a `then` keyword. - # - # @return [Boolean] whether the `when` node has a `then` keyword - def then? - loc.begin && loc.begin.is?('then') - end - - # Returns the body of the `when` node. - # - # @return [Node, nil] the body of the `when` node - def body - node_parts[-1] - end - end - end -end diff --git a/lib/rubocop/ast/node/while_node.rb b/lib/rubocop/ast/node/while_node.rb deleted file mode 100644 index 154862042444..000000000000 --- a/lib/rubocop/ast/node/while_node.rb +++ /dev/null @@ -1,35 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `while` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `while` nodes within RuboCop. - class WhileNode < Node - include ConditionalNode - include ModifierNode - - # Returns the keyword of the `while` statement as a string. - # - # @return [String] the keyword of the `while` statement - def keyword - 'while' - end - - # Returns the inverse keyword of the `while` node as a string. - # Returns `until` for `while` nodes and vice versa. - # - # @return [String] the inverse keyword of the `while` statement - def inverse_keyword - 'until' - end - - # Checks whether the `until` node has a `do` keyword. - # - # @return [Boolean] whether the `until` node has a `do` keyword - def do? - loc.begin && loc.begin.is?('do') - end - end - end -end diff --git a/lib/rubocop/ast/node/yield_node.rb b/lib/rubocop/ast/node/yield_node.rb deleted file mode 100644 index 1ae1fd68a89b..000000000000 --- a/lib/rubocop/ast/node/yield_node.rb +++ /dev/null @@ -1,21 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # A node extension for `yield` nodes. This will be used in place of a plain - # node when the builder constructs the AST, making its methods available - # to all `yield` nodes within RuboCop. - class YieldNode < Node - include ParameterizedNode - include MethodDispatchNode - - # Custom destructuring method. This can be used to normalize - # destructuring for different variations of the node. - # - # @return [Array] the different parts of the `send` node - def node_parts - [nil, :yield, *to_a] - end - end - end -end diff --git a/lib/rubocop/ast/sexp.rb b/lib/rubocop/ast/sexp.rb deleted file mode 100644 index 36c878cf43a0..000000000000 --- a/lib/rubocop/ast/sexp.rb +++ /dev/null @@ -1,16 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # This module provides a shorthand method to create a {Node} like - # `Parser::AST::Sexp`. - # - # @see https://www.rubydoc.info/gems/ast/AST/Sexp - module Sexp - # Creates a {Node} with type `type` and children `children`. - def s(type, *children) - Node.new(type, children) - end - end - end -end diff --git a/lib/rubocop/ast/traversal.rb b/lib/rubocop/ast/traversal.rb deleted file mode 100644 index fb553589bb57..000000000000 --- a/lib/rubocop/ast/traversal.rb +++ /dev/null @@ -1,183 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module AST - # Provides methods for traversing an AST. - # Does not transform an AST; for that, use Parser::AST::Processor. - # Override methods to perform custom processing. Remember to call `super` - # if you want to recursively process descendant nodes. - module Traversal - def walk(node) - return if node.nil? - - send(:"on_#{node.type}", node) - nil - end - - NO_CHILD_NODES = %i[true false nil int float complex - rational str sym regopt self lvar - ivar cvar gvar nth_ref back_ref cbase - arg restarg blockarg shadowarg - kwrestarg zsuper lambda redo retry].freeze - ONE_CHILD_NODE = %i[splat kwsplat block_pass not break next - preexe postexe match_current_line defined? - arg_expr].freeze - MANY_CHILD_NODES = %i[dstr dsym xstr regexp array hash pair - mlhs masgn or_asgn and_asgn - undef alias args super yield or and - while_post until_post iflipflop eflipflop - match_with_lvasgn begin kwbegin return].freeze - SECOND_CHILD_ONLY = %i[lvasgn ivasgn cvasgn gvasgn optarg kwarg - kwoptarg].freeze - - NO_CHILD_NODES.each do |type| - module_eval("def on_#{type}(node); end", __FILE__, __LINE__) - end - - ONE_CHILD_NODE.each do |type| - module_eval(<<-RUBY, __FILE__, __LINE__ + 1) - def on_#{type}(node) - if (child = node.children[0]) - send(:"on_\#{child.type}", child) - end - end - RUBY - end - - MANY_CHILD_NODES.each do |type| - module_eval(<<-RUBY, __FILE__, __LINE__ + 1) - def on_#{type}(node) - node.children.each { |child| send(:"on_\#{child.type}", child) } - nil - end - RUBY - end - - SECOND_CHILD_ONLY.each do |type| - # Guard clause is for nodes nested within mlhs - module_eval(<<-RUBY, __FILE__, __LINE__ + 1) - def on_#{type}(node) - if (child = node.children[1]) - send(:"on_\#{child.type}", child) - end - end - RUBY - end - - def on_const(node) - return unless (child = node.children[0]) - - send(:"on_#{child.type}", child) - end - - def on_casgn(node) - children = node.children - if (child = children[0]) # always const??? - send(:"on_#{child.type}", child) - end - return unless (child = children[2]) - - send(:"on_#{child.type}", child) - end - - def on_class(node) - children = node.children - child = children[0] # always const??? - send(:"on_#{child.type}", child) - if (child = children[1]) - send(:"on_#{child.type}", child) - end - return unless (child = children[2]) - - send(:"on_#{child.type}", child) - end - - def on_def(node) - children = node.children - on_args(children[1]) - return unless (child = children[2]) - - send(:"on_#{child.type}", child) - end - - def on_send(node) - node.children.each_with_index do |child, i| - next if i == 1 - - send(:"on_#{child.type}", child) if child - end - nil - end - - alias on_csend on_send - - def on_op_asgn(node) - children = node.children - child = children[0] - send(:"on_#{child.type}", child) - child = children[2] - send(:"on_#{child.type}", child) - end - - def on_defs(node) - children = node.children - child = children[0] - send(:"on_#{child.type}", child) - on_args(children[2]) - return unless (child = children[3]) - - send(:"on_#{child.type}", child) - end - - def on_if(node) - children = node.children - child = children[0] - send(:"on_#{child.type}", child) - if (child = children[1]) - send(:"on_#{child.type}", child) - end - return unless (child = children[2]) - - send(:"on_#{child.type}", child) - end - - def on_while(node) - children = node.children - child = children[0] - send(:"on_#{child.type}", child) - return unless (child = children[1]) - - send(:"on_#{child.type}", child) - end - - alias on_until on_while - alias on_module on_while - alias on_sclass on_while - - def on_block(node) - children = node.children - child = children[0] - send(:"on_#{child.type}", child) # can be send, zsuper... - on_args(children[1]) - return unless (child = children[2]) - - send(:"on_#{child.type}", child) - end - - def on_case(node) - node.children.each do |child| - send(:"on_#{child.type}", child) if child - end - nil - end - - alias on_rescue on_case - alias on_resbody on_case - alias on_ensure on_case - alias on_for on_case - alias on_when on_case - alias on_irange on_case - alias on_erange on_case - end - end -end diff --git a/lib/rubocop/ast_aliases.rb b/lib/rubocop/ast_aliases.rb new file mode 100644 index 000000000000..e0f0cd3dc98a --- /dev/null +++ b/lib/rubocop/ast_aliases.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +# These aliases are for compatibility. +module RuboCop + NodePattern = AST::NodePattern + ProcessedSource = AST::ProcessedSource + Token = AST::Token +end diff --git a/lib/rubocop/cached_data.rb b/lib/rubocop/cached_data.rb index 935a7b12b206..ece9052aefbf 100644 --- a/lib/rubocop/cached_data.rb +++ b/lib/rubocop/cached_data.rb @@ -4,6 +4,7 @@ module RuboCop # Converts RuboCop objects to and from the serialization format JSON. + # @api private class CachedData def initialize(filename) @filename = filename @@ -20,6 +21,7 @@ def to_json(offenses) private def serialize_offense(offense) + status = :uncorrected if %i[corrected corrected_with_todo].include?(offense.status) { # Calling #to_s here ensures that the serialization works when using # other json serializers such as Oj. Some of these gems do not call @@ -29,16 +31,16 @@ def serialize_offense(offense) begin_pos: offense.location.begin_pos, end_pos: offense.location.end_pos }, - message: message(offense), + message: message(offense), cop_name: offense.cop_name, - status: :uncorrected + status: status || offense.status } end def message(offense) # JSON.dump will fail if the offense message contains text which is not # valid UTF-8 - offense.message.scrub + offense.message.dup.force_encoding(::Encoding::UTF_8).scrub end # Restore an offense object loaded from a JSON file. diff --git a/lib/rubocop/cli.rb b/lib/rubocop/cli.rb index ddf70dde53c5..646c586a401f 100644 --- a/lib/rubocop/cli.rb +++ b/lib/rubocop/cli.rb @@ -1,20 +1,9 @@ # frozen_string_literal: true -# rubocop:disable Metrics/ClassLength module RuboCop # The CLI is a class responsible of handling all the command line interface # logic. class CLI - include Formatter::TextUtil - - PHASE_1 = 'Phase 1 of 2: run Metrics/LineLength cop'.freeze - PHASE_2 = 'Phase 2 of 2: run all cops'.freeze - - PHASE_1_OVERRIDDEN = '(skipped because the default Metrics/LineLength:Max' \ - ' is overridden)'.freeze - PHASE_1_DISABLED = '(skipped because Metrics/LineLength is ' \ - 'disabled)'.freeze - STATUS_SUCCESS = 0 STATUS_OFFENSES = 1 STATUS_ERROR = 2 @@ -41,10 +30,16 @@ def initialize # rubocop:disable Metrics/MethodLength, Metrics/AbcSize def run(args = ARGV) @options, paths = Options.new.parse(args) - validate_options_vs_config - act_on_options - apply_default_formatter - execute_runners(paths) + @env = Environment.new(@options, @config_store, paths) + + if @options[:init] + run_command(:init) + else + act_on_options + validate_options_vs_config + apply_default_formatter + execute_runners + end rescue ConfigNotFoundError, IncorrectCopNameError, OptionArgumentError => e warn e.message STATUS_ERROR @@ -66,82 +61,21 @@ def run(args = ARGV) private - def execute_runners(paths) - if @options[:auto_gen_config] - reset_config_and_auto_gen_file - line_length_contents = maybe_run_line_length_cop(paths) - run_all_cops_auto_gen_config(line_length_contents, paths) - else - execute_runner(paths) - end + def run_command(name) + @env.run(name) end - def maybe_run_line_length_cop(paths) - if !line_length_enabled?(@config_store.for(Dir.pwd)) - puts Rainbow("#{PHASE_1} #{PHASE_1_DISABLED}").yellow - '' - elsif !same_max_line_length?( - @config_store.for(Dir.pwd), ConfigLoader.default_configuration - ) - puts Rainbow("#{PHASE_1} #{PHASE_1_OVERRIDDEN}").yellow - '' + def execute_runners + if @options[:auto_gen_config] + run_command(:auto_gen_config) else - run_line_length_cop_auto_gen_config(paths) - end - end - - def line_length_enabled?(config) - line_length_cop(config)['Enabled'] - end - - def same_max_line_length?(config1, config2) - max_line_length(config1) == max_line_length(config2) - end - - def max_line_length(config) - line_length_cop(config)['Max'] - end - - def line_length_cop(config) - config.for_cop('Metrics/LineLength') - end - - # Do an initial run with only Metrics/LineLength so that cops that depend - # on Metrics/LineLength:Max get the correct value for that parameter. - def run_line_length_cop_auto_gen_config(paths) - puts Rainbow(PHASE_1).yellow - @options[:only] = ['Metrics/LineLength'] - execute_runner(paths) - @options.delete(:only) - @config_store = ConfigStore.new - # Save the todo configuration of the LineLength cop. - IO.read(ConfigLoader::AUTO_GENERATED_FILE) - .lines - .drop_while { |line| line.start_with?('#') } - .join - end - - def run_all_cops_auto_gen_config(line_length_contents, paths) - puts Rainbow(PHASE_2).yellow - result = execute_runner(paths) - # This run was made with the current maximum length allowed, so append - # the saved setting for LineLength. - File.open(ConfigLoader::AUTO_GENERATED_FILE, 'a') do |f| - f.write(line_length_contents) + run_command(:execute_runner) end - result - end - - def reset_config_and_auto_gen_file - @config_store = ConfigStore.new - @config_store.options_config = @options[:config] if @options[:config] - File.open(ConfigLoader::AUTO_GENERATED_FILE, 'w') {} - ConfigLoader.add_inheritance_from_auto_generated_file end def validate_options_vs_config if @options[:parallel] && - !@config_store.for(Dir.pwd).for_all_cops['UseCache'] + !@config_store.for_pwd.for_all_cops['UseCache'] raise OptionArgumentError, '-P/--parallel uses caching to speed up ' \ 'execution, so combining with AllCops: ' \ 'UseCache: false is not allowed.' @@ -149,10 +83,7 @@ def validate_options_vs_config end def act_on_options - ConfigLoader.debug = @options[:debug] - ConfigLoader.auto_gen_config = @options[:auto_gen_config] - ConfigLoader.ignore_parent_exclusion = @options[:ignore_parent_exclusion] - ConfigLoader.options_config = @options[:config] + set_options_to_config_loader @config_store.options_config = @options[:config] if @options[:config] @config_store.force_default_config! if @options[:force_default_config] @@ -168,31 +99,18 @@ def act_on_options end end - def execute_runner(paths) - runner = Runner.new(@options, @config_store) - - all_passed = runner.run(paths) - display_warning_summary(runner.warnings) - display_error_summary(runner.errors) - maybe_print_corrected_source - - all_pass_or_excluded = all_passed || @options[:auto_gen_config] - - if runner.aborting? - STATUS_INTERRUPTED - elsif all_pass_or_excluded && runner.errors.empty? - STATUS_SUCCESS - else - STATUS_OFFENSES - end + def set_options_to_config_loader + ConfigLoader.debug = @options[:debug] + ConfigLoader.disable_pending_cops = @options[:disable_pending_cops] + ConfigLoader.enable_pending_cops = @options[:enable_pending_cops] + ConfigLoader.ignore_parent_exclusion = @options[:ignore_parent_exclusion] end def handle_exiting_options return unless Options::EXITING_OPTIONS.any? { |o| @options.key? o } - puts RuboCop::Version.version(false) if @options[:version] - puts RuboCop::Version.version(true) if @options[:verbose_version] - print_available_cops if @options[:show_cops] + run_command(:version) if @options[:version] || @options[:verbose_version] + run_command(:show_cops) if @options[:show_cops] raise Finished end @@ -203,105 +121,11 @@ def apply_default_formatter if @options[:auto_gen_config] formatter = 'autogenconf' else - cfg = @config_store.for(Dir.pwd).for_all_cops + cfg = @config_store.for_pwd.for_all_cops formatter = cfg['DefaultFormatter'] || 'progress' end [[formatter, @options[:output_path]]] end - - return unless @options[:auto_gen_config] - - @options[:formatters] << [Formatter::DisabledConfigFormatter, - ConfigLoader::AUTO_GENERATED_FILE] - end - - def print_available_cops - # Load the configs so the require()s are done for custom cops - @config_store.for(Dir.pwd) - registry = Cop::Cop.registry - show_all = @options[:show_cops].empty? - - if show_all - puts "# Available cops (#{registry.length}) + config for #{Dir.pwd}: " - end - - registry.departments.sort!.each do |department| - print_cops_of_department(registry, department, show_all) - end - end - - def print_cops_of_department(registry, department, show_all) - selected_cops = if show_all - cops_of_department(registry, department) - else - selected_cops_of_department(registry, department) - end - - puts "# Department '#{department}' (#{selected_cops.length}):" if show_all - - print_cop_details(selected_cops) - end - - def print_cop_details(cops) - cops.each do |cop| - puts '# Supports --auto-correct' if cop.new.support_autocorrect? - puts "#{cop.cop_name}:" - puts config_lines(cop) - puts - end - end - - def selected_cops_of_department(cops, department) - cops_of_department(cops, department).select do |cop| - @options[:show_cops].include?(cop.cop_name) - end - end - - def cops_of_department(cops, department) - cops.with_department(department).sort! - end - - def config_lines(cop) - cnf = @config_store.for(Dir.pwd).for_cop(cop) - cnf.to_yaml.lines.to_a.drop(1).map { |line| ' ' + line } - end - - def display_warning_summary(warnings) - return if warnings.empty? - - warn Rainbow("\n#{pluralize(warnings.size, 'warning')}:").yellow - - warnings.each { |warning| warn warning } - end - - def display_error_summary(errors) - return if errors.empty? - - warn Rainbow("\n#{pluralize(errors.size, 'error')} occurred:").red - - errors.each { |error| warn error } - - warn <<-WARNING.strip_indent - Errors are usually caused by RuboCop bugs. - Please, report your problems to RuboCop's issue tracker. - #{Gem.loaded_specs['rubocop'].metadata['bug_tracker_uri']} - - Mention the following information in the issue report: - #{RuboCop::Version.version(true)} - WARNING - end - - def maybe_print_corrected_source - # If we are asked to autocorrect source code read from stdin, the only - # reasonable place to write it is to stdout - # Unfortunately, we also write other information to stdout - # So a delimiter is needed for tools to easily identify where the - # autocorrected source begins - return unless @options[:stdin] && @options[:auto_correct] - - puts '=' * 20 - print @options[:stdin] end end end -# rubocop:enable Metrics/ClassLength diff --git a/lib/rubocop/cli/command.rb b/lib/rubocop/cli/command.rb new file mode 100644 index 000000000000..775e929a2de0 --- /dev/null +++ b/lib/rubocop/cli/command.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module RuboCop + class CLI + # Home of subcommands in the CLI. + # @api private + module Command + class << self + # Find the command with a given name and run it in an environment. + def run(env, name) + class_for(name).new(env).run + end + + private + + def class_for(name) + Base.by_command_name(name) + end + end + end + end +end diff --git a/lib/rubocop/cli/command/auto_genenerate_config.rb b/lib/rubocop/cli/command/auto_genenerate_config.rb new file mode 100644 index 000000000000..5dd87a554f08 --- /dev/null +++ b/lib/rubocop/cli/command/auto_genenerate_config.rb @@ -0,0 +1,141 @@ +# frozen_string_literal: true + +module RuboCop + class CLI + module Command + # Generate a configuration file acting as a TODO list. + # @api private + class AutoGenerateConfig < Base + self.command_name = :auto_gen_config + + AUTO_GENERATED_FILE = '.rubocop_todo.yml' + + PHASE_1 = 'Phase 1 of 2: run Layout/LineLength cop' + PHASE_2 = 'Phase 2 of 2: run all cops' + + PHASE_1_OVERRIDDEN = + '(skipped because the default Layout/LineLength:Max is overridden)' + PHASE_1_DISABLED = + '(skipped because Layout/LineLength is disabled)' + + def run + add_formatter + reset_config_and_auto_gen_file + line_length_contents = maybe_run_line_length_cop + run_all_cops(line_length_contents) + end + + private + + def maybe_run_line_length_cop + if !line_length_enabled?(@config_store.for_pwd) + skip_line_length_cop(PHASE_1_DISABLED) + elsif !same_max_line_length?( + @config_store.for_pwd, ConfigLoader.default_configuration + ) + skip_line_length_cop(PHASE_1_OVERRIDDEN) + else + run_line_length_cop + end + end + + def skip_line_length_cop(reason) + puts Rainbow("#{PHASE_1} #{reason}").yellow + '' + end + + def line_length_enabled?(config) + line_length_cop(config)['Enabled'] + end + + def same_max_line_length?(config1, config2) + max_line_length(config1) == max_line_length(config2) + end + + def max_line_length(config) + line_length_cop(config)['Max'] + end + + def line_length_cop(config) + config.for_cop('Layout/LineLength') + end + + # Do an initial run with only Layout/LineLength so that cops that + # depend on Layout/LineLength:Max get the correct value for that + # parameter. + def run_line_length_cop + puts Rainbow(PHASE_1).yellow + @options[:only] = ['Layout/LineLength'] + execute_runner + @options.delete(:only) + @config_store = ConfigStore.new + # Save the todo configuration of the LineLength cop. + IO.read(AUTO_GENERATED_FILE) + .lines + .drop_while { |line| line.start_with?('#') } + .join + end + + def run_all_cops(line_length_contents) + puts Rainbow(PHASE_2).yellow + result = execute_runner + # This run was made with the current maximum length allowed, so append + # the saved setting for LineLength. + File.open(AUTO_GENERATED_FILE, 'a') do |f| + f.write(line_length_contents) + end + result + end + + def reset_config_and_auto_gen_file + @config_store = ConfigStore.new + @config_store.options_config = @options[:config] if @options[:config] + File.open(AUTO_GENERATED_FILE, 'w') {} + add_inheritance_from_auto_generated_file(@options[:config]) + end + + def add_formatter + @options[:formatters] << [Formatter::DisabledConfigFormatter, + AUTO_GENERATED_FILE] + end + + def execute_runner + Environment.new(@options, @config_store, @paths).run(:execute_runner) + end + + def add_inheritance_from_auto_generated_file(config_file) + file_string = " #{AUTO_GENERATED_FILE}" + + config_file ||= ConfigLoader::DOTFILE + + if File.exist?(config_file) + files = Array(ConfigLoader.load_yaml_configuration(config_file)['inherit_from']) + + return if files.include?(AUTO_GENERATED_FILE) + + files.unshift(AUTO_GENERATED_FILE) + file_string = "\n - #{files.join("\n - ")}" if files.size > 1 + rubocop_yml_contents = existing_configuration(config_file) + end + + write_config_file(config_file, file_string, rubocop_yml_contents) + + puts "Added inheritance from `#{AUTO_GENERATED_FILE}` in `#{ConfigLoader::DOTFILE}`." + end + + def existing_configuration(config_file) + IO.read(config_file, encoding: Encoding::UTF_8) + .sub(/^inherit_from: *[^\n]+/, '') + .sub(/^inherit_from: *(\n *- *[^\n]+)+/, '') + end + + def write_config_file(file_name, file_string, rubocop_yml_contents) + File.open(file_name, 'w') do |f| + f.write "inherit_from:#{file_string}\n" + f.write "\n#{rubocop_yml_contents}" if /\S/.match?(rubocop_yml_contents) + end + end + end + end + end +end diff --git a/lib/rubocop/cli/command/base.rb b/lib/rubocop/cli/command/base.rb new file mode 100644 index 000000000000..f35798a4889a --- /dev/null +++ b/lib/rubocop/cli/command/base.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module RuboCop + class CLI + module Command + # A subcommand in the CLI. + # @api private + class Base + attr_reader :env + + @subclasses = [] + + class << self + attr_accessor :command_name + + def inherited(subclass) + super + @subclasses << subclass + end + + def by_command_name(name) + @subclasses.detect { |s| s.command_name == name } + end + end + + def initialize(env) + @env = env + @options = env.options + @config_store = env.config_store + @paths = env.paths + end + end + end + end +end diff --git a/lib/rubocop/cli/command/execute_runner.rb b/lib/rubocop/cli/command/execute_runner.rb new file mode 100644 index 000000000000..f336981ef077 --- /dev/null +++ b/lib/rubocop/cli/command/execute_runner.rb @@ -0,0 +1,85 @@ +# frozen_string_literal: true + +module RuboCop + class CLI + module Command + # Run all the selected cops and report the result. + # @api private + class ExecuteRunner < Base + include Formatter::TextUtil + + # Combination of short and long formatter names. + INTEGRATION_FORMATTERS = %w[h html j json ju junit].freeze + + self.command_name = :execute_runner + + def run + execute_runner(@paths) + end + + private + + def execute_runner(paths) + runner = Runner.new(@options, @config_store) + + all_passed = runner.run(paths) + display_warning_summary(runner.warnings) + display_error_summary(runner.errors) + maybe_print_corrected_source + + all_pass_or_excluded = all_passed || @options[:auto_gen_config] + + if runner.aborting? + STATUS_INTERRUPTED + elsif all_pass_or_excluded && runner.errors.empty? + STATUS_SUCCESS + else + STATUS_OFFENSES + end + end + + def display_warning_summary(warnings) + return if warnings.empty? + + warn Rainbow("\n#{pluralize(warnings.size, 'warning')}:").yellow + + warnings.each { |warning| warn warning } + end + + def display_error_summary(errors) + return if errors.empty? + + warn Rainbow("\n#{pluralize(errors.size, 'error')} occurred:").red + + errors.each { |error| warn error } + + warn <<~WARNING + Errors are usually caused by RuboCop bugs. + Please, report your problems to RuboCop's issue tracker. + #{Gem.loaded_specs['rubocop'].metadata['bug_tracker_uri']} + + Mention the following information in the issue report: + #{RuboCop::Version.version(debug: true)} + WARNING + end + + def maybe_print_corrected_source + # Integration tools (like RubyMine) expect to have only the JSON result + # when specifying JSON format. Similar HTML and JUnit are targeted as well. + # See: https://github.com/rubocop-hq/rubocop/issues/8673 + return if INTEGRATION_FORMATTERS.include?(@options[:format]) + + # If we are asked to autocorrect source code read from stdin, the only + # reasonable place to write it is to stdout + # Unfortunately, we also write other information to stdout + # So a delimiter is needed for tools to easily identify where the + # autocorrected source begins + return unless @options[:stdin] && @options[:auto_correct] + + puts '=' * 20 + print @options[:stdin] + end + end + end + end +end diff --git a/lib/rubocop/cli/command/init_dotfile.rb b/lib/rubocop/cli/command/init_dotfile.rb new file mode 100644 index 000000000000..36c34f5a6545 --- /dev/null +++ b/lib/rubocop/cli/command/init_dotfile.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module RuboCop + class CLI + module Command + # Generate a .rubocop.yml file in the current directory. + # @api private + class InitDotfile < Base + DOTFILE = ConfigLoader::DOTFILE + + self.command_name = :init + + def run + path = File.expand_path(DOTFILE) + + if File.exist?(DOTFILE) + warn Rainbow("#{DOTFILE} already exists at #{path}").red + + STATUS_ERROR + else + description = <<~DESC + # The behavior of RuboCop can be controlled via the .rubocop.yml + # configuration file. It makes it possible to enable/disable + # certain cops (checks) and to alter their behavior if they accept + # any parameters. The file can be placed either in your home + # directory or in some project directory. + # + # RuboCop will start looking for the configuration file in the directory + # where the inspected file is and continue its way up to the root directory. + # + # See https://docs.rubocop.org/rubocop/configuration + DESC + + File.open(DOTFILE, 'w') do |f| + f.write(description) + end + + puts "Writing new #{DOTFILE} to #{path}" + + STATUS_SUCCESS + end + end + end + end + end +end diff --git a/lib/rubocop/cli/command/show_cops.rb b/lib/rubocop/cli/command/show_cops.rb new file mode 100644 index 000000000000..e99069b3ea8a --- /dev/null +++ b/lib/rubocop/cli/command/show_cops.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +module RuboCop + class CLI + module Command + # Shows the given cops, or all cops by default, and their configurations + # for the current directory. + # @api private + class ShowCops < Base + self.command_name = :show_cops + + def initialize(env) + super + + # Load the configs so the require()s are done for custom cops + @config = @config_store.for(Dir.pwd) + end + + def run + print_available_cops + end + + private + + def print_available_cops + registry = Cop::Registry.global + show_all = @options[:show_cops].empty? + + if show_all + puts "# Available cops (#{registry.length}) " \ + "+ config for #{Dir.pwd}: " + end + + registry.departments.sort!.each do |department| + print_cops_of_department(registry, department, show_all) + end + end + + def print_cops_of_department(registry, department, show_all) + selected_cops = if show_all + cops_of_department(registry, department) + else + selected_cops_of_department(registry, department) + end + + puts "# Department '#{department}' (#{selected_cops.length}):" if show_all + + print_cop_details(selected_cops) + end + + def print_cop_details(cops) + cops.each do |cop| + puts '# Supports --auto-correct' if cop.support_autocorrect? + puts "#{cop.cop_name}:" + puts config_lines(cop) + puts + end + end + + def selected_cops_of_department(cops, department) + cops_of_department(cops, department).select do |cop| + @options[:show_cops].include?(cop.cop_name) + end + end + + def cops_of_department(cops, department) + cops.with_department(department).sort! + end + + def config_lines(cop) + cnf = @config.for_cop(cop) + cnf.to_yaml.lines.to_a.drop(1).map { |line| " #{line}" } + end + end + end + end +end diff --git a/lib/rubocop/cli/command/version.rb b/lib/rubocop/cli/command/version.rb new file mode 100644 index 000000000000..84435d3f2564 --- /dev/null +++ b/lib/rubocop/cli/command/version.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module RuboCop + class CLI + module Command + # Display version. + # @api private + class Version < Base + self.command_name = :version + + def run + puts RuboCop::Version.version(debug: false) if @options[:version] + puts RuboCop::Version.version(debug: true) if @options[:verbose_version] + end + end + end + end +end diff --git a/lib/rubocop/cli/environment.rb b/lib/rubocop/cli/environment.rb new file mode 100644 index 000000000000..70276eb9587a --- /dev/null +++ b/lib/rubocop/cli/environment.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module RuboCop + class CLI + # Execution environment for a CLI command. + # @api private + class Environment + attr_reader :options, :config_store, :paths + + def initialize(options, config_store, paths) + @options = options + @config_store = config_store + @paths = paths + end + + # Run a command in this environment. + def run(name) + Command.run(self, name) + end + end + end +end diff --git a/lib/rubocop/comment_config.rb b/lib/rubocop/comment_config.rb index fee95b9bc249..7c285f7a746d 100644 --- a/lib/rubocop/comment_config.rb +++ b/lib/rubocop/comment_config.rb @@ -4,14 +4,20 @@ module RuboCop # This class parses the special `rubocop:disable` comments in a source # and provides a way to check if each cop is enabled at arbitrary line. class CommentConfig - UNNEEDED_DISABLE = 'Lint/UnneededCopDisableDirective'.freeze + # @api private + REDUNDANT_DISABLE = 'Lint/RedundantCopDisableDirective' - COP_NAME_PATTERN = '([A-Z]\w+/)?(?:[A-Z]\w+)'.freeze - COP_NAMES_PATTERN = "(?:#{COP_NAME_PATTERN} , )*#{COP_NAME_PATTERN}".freeze - COPS_PATTERN = "(all|#{COP_NAMES_PATTERN})".freeze + # @api private + COP_NAME_PATTERN = '([A-Z]\w+/)?(?:[A-Z]\w+)' + # @api private + COP_NAMES_PATTERN = "(?:#{COP_NAME_PATTERN} , )*#{COP_NAME_PATTERN}" + # @api private + COPS_PATTERN = "(all|#{COP_NAMES_PATTERN})" + # @api private COMMENT_DIRECTIVE_REGEXP = Regexp.new( - ('# rubocop : ((?:dis|en)able)\b ' + COPS_PATTERN).gsub(' ', '\s*') + "# rubocop : ((?:disable|enable|todo))\\b #{COPS_PATTERN}" + .gsub(' ', '\s*') ) CopAnalysis = Struct.new(:line_ranges, :start_line_number) @@ -35,12 +41,15 @@ def cop_disabled_line_ranges end def extra_enabled_comments - extra_enabled_comments_with_names([], {}) + extra_enabled_comments_with_names( + extras: Hash.new { |h, k| h[k] = [] }, + names: Hash.new(0) + ) end private - def extra_enabled_comments_with_names(extras, names) + def extra_enabled_comments_with_names(extras:, names:) each_directive do |comment, cop_names, disabled| next unless comment_only_line?(comment.loc.expression.line) @@ -54,7 +63,7 @@ def extra_enabled_comments_with_names(extras, names) extras end - def analyze + def analyze # rubocop:todo Metrics/AbcSize analyses = Hash.new { |hash, key| hash[key] = CopAnalysis.new([], nil) } each_mentioned_cop do |cop_name, disabled, line, single_line| @@ -112,7 +121,8 @@ def cop_line_ranges(analysis) def each_mentioned_cop each_directive do |comment, cop_names, disabled| comment_line_number = comment.loc.expression.line - single_line = !comment_only_line?(comment_line_number) + single_line = !comment_only_line?(comment_line_number) || + directive_on_comment_line?(comment) cop_names.each do |cop_name| yield qualified_cop_name(cop_name), disabled, comment_line_number, @@ -121,10 +131,12 @@ def each_mentioned_cop end end - def each_directive - return if processed_source.comments.nil? + def directive_on_comment_line?(comment) + comment.text[1..-1].match?(COMMENT_DIRECTIVE_REGEXP) + end - processed_source.each_comment do |comment| + def each_directive + processed_source.comments.each do |comment| directive = directive_parts(comment) next unless directive @@ -141,17 +153,17 @@ def directive_parts(comment) cop_names = cops_string == 'all' ? all_cop_names : cops_string.split(/,\s*/) - disabled = (switch == 'disable') + disabled = %w[disable todo].include?(switch) [cop_names, disabled] end def qualified_cop_name(cop_name) - Cop::Cop.qualified_cop_name(cop_name.strip, processed_source.file_path) + Cop::Registry.qualified_cop_name(cop_name.strip, processed_source.file_path) end def all_cop_names - @all_cop_names ||= Cop::Cop.registry.names - [UNNEEDED_DISABLE] + @all_cop_names ||= Cop::Registry.global.names - [REDUNDANT_DISABLE] end def comment_only_line?(line_number) @@ -175,24 +187,25 @@ def enable_all?(comment) def handle_enable_all(names, extras, comment) enabled_cops = 0 names.each do |name, counter| - next unless counter > 0 + next unless counter.positive? names[name] -= 1 enabled_cops += 1 end - extras << [comment, 'all'] if enabled_cops.zero? + extras[comment] << 'all' if enabled_cops.zero? end + # Collect cops that have been disabled or enabled by name in a directive comment + # so that `Lint/RedundantCopEnableDirective` can register offenses correctly. def handle_switch(cop_names, names, disabled, extras, comment) cop_names.each do |name| - names[name] ||= 0 if disabled names[name] += 1 - elsif names[name] > 0 + elsif (names[name]).positive? names[name] -= 1 else - extras << [comment, name] + extras[comment] << name end end end diff --git a/lib/rubocop/config.rb b/lib/rubocop/config.rb index c77778140cad..6e1db9cc24e1 100644 --- a/lib/rubocop/config.rb +++ b/lib/rubocop/config.rb @@ -2,237 +2,35 @@ require 'pathname' +# FIXME: Moving Rails department code to RuboCop Rails will remove +# the following rubocop:disable comment. +# rubocop:disable Metrics/ClassLength module RuboCop # This class represents the configuration of the RuboCop application # and all its cops. A Config is associated with a YAML configuration # file from which it was read. Several different Configs can be used # during a run of the rubocop program, if files in several # directories are inspected. - - # rubocop:disable Metrics/ClassLength class Config include PathUtil include FileFinder + extend Forwardable - COMMON_PARAMS = %w[Exclude Include Severity inherit_mode - AutoCorrect StyleGuide Details].freeze - INTERNAL_PARAMS = %w[Description StyleGuide VersionAdded - VersionChanged Reference Safe SafeAutoCorrect].freeze + CopConfig = Struct.new(:name, :metadata) - # 2.2 is the oldest officially supported Ruby version. - DEFAULT_RUBY_VERSION = 2.2 - KNOWN_RUBIES = [2.2, 2.3, 2.4, 2.5, 2.6].freeze - OBSOLETE_RUBIES = { 1.9 => '0.50', 2.0 => '0.50', 2.1 => '0.58' }.freeze - RUBY_VERSION_FILENAME = '.ruby-version'.freeze DEFAULT_RAILS_VERSION = 5.0 - OBSOLETE_COPS = { - 'Style/FlipFlop' => - 'The `Style/FlipFlop` cop has been moved to `Lint/FlipFlop`.', - 'Style/TrailingComma' => - 'The `Style/TrailingComma` cop no longer exists. Please use ' \ - '`Style/TrailingCommaInArguments`, ' \ - '`Style/TrailingCommaInArrayLiteral`, and/or ' \ - '`Style/TrailingCommaInHashLiteral` instead.', - 'Style/TrailingCommaInLiteral' => - 'The `Style/TrailingCommaInLiteral` cop no longer exists. Please use ' \ - '`Style/TrailingCommaInArrayLiteral` and/or ' \ - '`Style/TrailingCommaInHashLiteral` instead.', - 'Rails/DefaultScope' => - 'The `Rails/DefaultScope` cop no longer exists.', - 'Lint/InvalidCharacterLiteral' => - 'The `Lint/InvalidCharacterLiteral` cop has been removed since it ' \ - 'was never being actually triggered.', - 'Style/SingleSpaceBeforeFirstArg' => - 'The `Style/SingleSpaceBeforeFirstArg` cop has been renamed to ' \ - '`Layout/SpaceBeforeFirstArg`.', - 'Lint/RescueWithoutErrorClass' => - 'The `Lint/RescueWithoutErrorClass` cop has been replaced by ' \ - '`Style/RescueStandardError`.', - 'Lint/SpaceBeforeFirstArg' => - 'The `Lint/SpaceBeforeFirstArg` cop has been removed, since it was a ' \ - 'duplicate of `Layout/SpaceBeforeFirstArg`. Please use ' \ - '`Layout/SpaceBeforeFirstArg` instead.', - 'Layout/SpaceAfterControlKeyword' => - 'The `Layout/SpaceAfterControlKeyword` cop has been removed. Please ' \ - 'use `Layout/SpaceAroundKeyword` instead.', - 'Layout/SpaceBeforeModifierKeyword' => - 'The `Layout/SpaceBeforeModifierKeyword` cop has been removed. ' \ - 'Please use `Layout/SpaceAroundKeyword` instead.', - 'Style/SpaceAfterControlKeyword' => - 'The `Style/SpaceAfterControlKeyword` cop has been removed. Please ' \ - 'use `Layout/SpaceAroundKeyword` instead.', - 'Style/SpaceBeforeModifierKeyword' => - 'The `Style/SpaceBeforeModifierKeyword` cop has been removed. Please ' \ - 'use `Layout/SpaceAroundKeyword` instead.', - 'Style/MethodCallParentheses' => - 'The `Style/MethodCallParentheses` cop has been renamed to ' \ - '`Style/MethodCallWithoutArgsParentheses`.', - 'Lint/Eval' => - 'The `Lint/Eval` cop has been renamed to `Security/Eval`.', - 'Style/DeprecatedHashMethods' => - 'The `Style/DeprecatedHashMethods` cop has been renamed to ' \ - '`Style/PreferredHashMethods`.', - 'Style/AccessorMethodName' => - 'The `Style/AccessorMethodName` cop has been moved to ' \ - '`Naming/AccessorMethodName`.', - 'Style/AsciiIdentifiers' => - 'The `Style/AsciiIdentifiers` cop has been moved to ' \ - '`Naming/AccessorMethodName`.', - 'Style/OpMethod' => - 'The `Style/OpMethod` cop has been renamed and moved to ' \ - '`Naming/BinaryOperatorParameterName`.', - 'Style/ClassAndModuleCamelCase' => - 'The `Style/ClassAndModuleCamelCase` cop has been renamed to ' \ - '`Naming/ClassAndModuleCamelCase`.', - 'Style/ConstantName' => - 'The `Style/ConstantName` cop has been renamed to ' \ - '`Naming/ConstantName`.', - 'Style/FileName' => - 'The `Style/FileName` cop has been renamed to `Naming/FileName`.', - 'Style/MethodName' => - 'The `Style/MethodName` cop has been renamed to ' \ - '`Naming/MethodName`.', - 'Style/PredicateName' => - 'The `Style/PredicateName` cop has been renamed to ' \ - '`Naming/PredicateName`.', - 'Style/VariableName' => - 'The `Style/VariableName` cop has been renamed to ' \ - '`Naming/VariableName`.', - 'Style/VariableNumber' => - 'The `Style/VariableNumber` cop has been renamed to ' \ - '`Naming/VariableNumber`.', - 'Lint/BlockAlignment' => - 'The `Lint/BlockAlignment` cop has been renamed to ' \ - '`Layout/BlockAlignment`.', - 'Lint/EndAlignment' => - 'The `Lint/EndAlignment` cop has been renamed to ' \ - '`Layout/EndAlignment`.', - 'Lint/DefEndAlignment' => - 'The `Lint/DefEndAlignment` cop has been renamed to ' \ - '`Layout/DefEndAlignment`.', - 'Performance/HashEachMethods' => - 'The `Performance/HashEachMethods` cop has been removed ' \ - 'since it no longer provides performance benefits in ' \ - 'modern rubies.', - 'Style/MethodMissing' => - 'The `Style/MethodMissing` cop has been split into ' \ - '`Style/MethodMissingSuper` and `Style/MissingRespondToMissing`.' - }.freeze - - OBSOLETE_PARAMETERS = [ - { - cop: 'Layout/SpaceAroundOperators', - parameter: 'MultiSpaceAllowedForOperators', - alternative: 'If your intention was to allow extra spaces ' \ - 'for alignment, please use AllowForAlignment: ' \ - 'true instead.' - }, - { - cop: 'Style/Encoding', - parameter: 'EnforcedStyle', - alternative: 'Style/Encoding no longer supports styles. ' \ - 'The "never" behavior is always assumed.' - }, - { - cop: 'Style/Encoding', - parameter: 'SupportedStyles', - alternative: 'Style/Encoding no longer supports styles. ' \ - 'The "never" behavior is always assumed.' - }, - { - cop: 'Style/Encoding', - parameter: 'AutoCorrectEncodingComment', - alternative: 'Style/Encoding no longer supports styles. ' \ - 'The "never" behavior is always assumed.' - }, - { - cop: 'Style/IfUnlessModifier', - parameter: 'MaxLineLength', - alternative: - '`Style/IfUnlessModifier: MaxLineLength` has been removed. Use ' \ - '`Metrics/LineLength: Max` instead' - }, - { - cop: 'Style/SpaceAroundOperators', - parameter: 'MultiSpaceAllowedForOperators', - alternative: 'If your intention was to allow extra spaces ' \ - 'for alignment, please use AllowForAlignment: ' \ - 'true instead.' - }, - { - cop: 'Style/WhileUntilModifier', - parameter: 'MaxLineLength', - alternative: - '`Style/WhileUntilModifier: MaxLineLength` has been removed. Use ' \ - '`Metrics/LineLength: Max` instead' - }, - { - cop: 'AllCops', - parameter: 'RunRailsCops', - alternative: "Use the following configuration instead:\n" \ - "Rails:\n Enabled: true" - }, - { - cop: 'Layout/CaseIndentation', - parameter: 'IndentWhenRelativeTo', - alternative: '`IndentWhenRelativeTo` has been renamed to ' \ - '`EnforcedStyle`' - }, - { - cop: 'Lint/BlockAlignment', - parameter: 'AlignWith', - alternative: '`AlignWith` has been renamed to ' \ - '`EnforcedStyleAlignWith`' - }, - { - cop: 'Layout/BlockAlignment', - parameter: 'AlignWith', - alternative: '`AlignWith` has been renamed to ' \ - '`EnforcedStyleAlignWith`' - }, - { - cop: 'Lint/EndAlignment', - parameter: 'AlignWith', - alternative: '`AlignWith` has been renamed to ' \ - '`EnforcedStyleAlignWith`' - }, - { - cop: 'Layout/EndAlignment', - parameter: 'AlignWith', - alternative: '`AlignWith` has been renamed to ' \ - '`EnforcedStyleAlignWith`' - }, - { - cop: 'Lint/DefEndAlignment', - parameter: 'AlignWith', - alternative: '`AlignWith` has been renamed to ' \ - '`EnforcedStyleAlignWith`' - }, - { - cop: 'Layout/DefEndAlignment', - parameter: 'AlignWith', - alternative: '`AlignWith` has been renamed to ' \ - '`EnforcedStyleAlignWith`' - }, - { - cop: 'Rails/UniqBeforePluck', - parameter: 'EnforcedMode', - alternative: '`EnforcedMode` has been renamed to ' \ - '`EnforcedStyle`' - } - ].freeze - attr_reader :loaded_path def initialize(hash = {}, loaded_path = nil) @loaded_path = loaded_path @for_cop = Hash.new do |h, cop| - qualified_cop_name = Cop::Cop.qualified_cop_name(cop, loaded_path) + qualified_cop_name = Cop::Registry.qualified_cop_name(cop, loaded_path) cop_options = self[qualified_cop_name] || {} cop_options['Enabled'] = enable_cop?(qualified_cop_name, cop_options) h[cop] = cop_options end @hash = hash + @validator = ConfigValidator.new(self) end def self.create(hash, path) @@ -243,54 +41,14 @@ def check deprecation_check do |deprecation_message| warn("#{loaded_path} - #{deprecation_message}") end - validate + @validator.validate make_excludes_absolute self end - def [](key) - @hash[key] - end - - def []=(key, value) - @hash[key] = value - end - - def delete(key) - @hash.delete(key) - end - - def each(&block) - @hash.each(&block) - end - - def key?(key) - @hash.key?(key) - end - - def keys - @hash.keys - end - - def each_key(&block) - @hash.each_key(&block) - end - - def map(&block) - @hash.map(&block) - end - - def merge(other_hash) - @hash.merge(other_hash) - end - - def to_h - @hash - end - - def to_hash - @hash - end + def_delegators :@hash, :[], :[]=, :delete, :each, :key?, :keys, :each_key, + :fetch, :map, :merge, :to_h, :to_hash, :transform_values + def_delegators :@validator, :validate, :target_ruby_version def to_s @to_s ||= @hash.to_s @@ -300,9 +58,16 @@ def signature @signature ||= Digest::SHA1.hexdigest(to_s) end + # True if this is a config file that is shipped with RuboCop + def internal? + base_config_path = File.expand_path(File.join(ConfigLoader::RUBOCOP_HOME, + 'config')) + File.expand_path(loaded_path).start_with?(base_config_path) + end + def make_excludes_absolute each_key do |key| - validate_section_presence(key) + @validator.validate_section_presence(key) next unless self[key]['Exclude'] self[key]['Exclude'].map! do |exclude_elem| @@ -339,38 +104,48 @@ def deprecation_check end end + # @return [Config] for the given cop / cop name. + # Note: the 'Enabled' attribute is calculated according to the department's + # and 'AllCops' configuration; other attributes are not inherited. def for_cop(cop) @for_cop[cop.respond_to?(:cop_name) ? cop.cop_name : cop] end + # @return [Config] for the given cop merged with that of its department (if any) + # Note: the 'Enabled' attribute is same as that returned by `for_cop` + def for_badge(badge) + cop_config = for_cop(badge.to_s) + fetch(badge.department.to_s) { return cop_config } + .merge(cop_config) + end + + # @return [Config] for the given department name. + # Note: the 'Enabled' attribute will be present only if specified + # at the department's level + def for_department(department_name) + @for_department ||= Hash.new do |h, dept| + h[dept] = self[dept] || {} + end + @for_department[department_name.to_s] + end + def for_all_cops @for_all_cops ||= self['AllCops'] || {} end - def validate - # Don't validate RuboCop's own files. Avoids infinite recursion. - base_config_path = File.expand_path(File.join(ConfigLoader::RUBOCOP_HOME, - 'config')) - return if File.expand_path(loaded_path).start_with?(base_config_path) - - valid_cop_names, invalid_cop_names = keys.partition do |key| - ConfigLoader.default_configuration.key?(key) - end + def disabled_new_cops? + for_all_cops['NewCops'] == 'disable' + end - reject_obsolete_cops_and_parameters - warn_about_unrecognized_cops(invalid_cop_names) - check_target_ruby - validate_parameter_names(valid_cop_names) - validate_enforced_styles(valid_cop_names) - validate_syntax_cop - reject_mutually_exclusive_defaults + def enabled_new_cops? + for_all_cops['NewCops'] == 'enable' end def file_to_include?(file) relative_file_path = path_relative_to_config(file) # Optimization to quickly decide if the given file is hidden (on the top - # level) and can not be matched by any pattern. + # level) and cannot be matched by any pattern. is_hidden = relative_file_path.start_with?('.') && !relative_file_path.start_with?('..') return false if is_hidden && !possibly_include_hidden? @@ -394,7 +169,7 @@ def allowed_camel_case_file?(file) return true if File.extname(file) == '.gemspec' file_to_include?(file) do |pattern, relative_path, absolute_path| - pattern.to_s =~ /[A-Z]/ && + /[A-Z]/.match?(pattern.to_s) && (match_path?(pattern, relative_path) || match_path?(pattern, absolute_path)) end @@ -444,26 +219,6 @@ def base_dir_for_path_parameters end end - def target_ruby_version - @target_ruby_version ||= begin - if for_all_cops['TargetRubyVersion'] - @target_ruby_version_source = :rubocop_yml - - for_all_cops['TargetRubyVersion'].to_f - elsif target_ruby_version_from_version_file - @target_ruby_version_source = :ruby_version_file - - target_ruby_version_from_version_file - elsif target_ruby_version_from_bundler_lock_file - @target_ruby_version_source = :bundler_lock_file - - target_ruby_version_from_bundler_lock_file - else - DEFAULT_RUBY_VERSION - end - end - end - def target_rails_version @target_rails_version ||= if for_all_cops['TargetRailsVersion'] @@ -475,187 +230,34 @@ def target_rails_version end end - private - - def warn_about_unrecognized_cops(invalid_cop_names) - invalid_cop_names.each do |name| - # There could be a custom cop with this name. If so, don't warn - next if Cop::Cop.registry.contains_cop_matching?([name]) - - # Special case for inherit_mode, which is a directive that we keep in - # the configuration (even though it's not a cop), because it's easier - # to do so than to pass the value around to various methods. - next if name == 'inherit_mode' - - warn Rainbow("Warning: unrecognized cop #{name} found in " \ - "#{smart_loaded_path}").yellow - end - end - - def validate_syntax_cop - syntax_config = self['Lint/Syntax'] - default_config = ConfigLoader.default_configuration['Lint/Syntax'] - - return unless syntax_config && - default_config.merge(syntax_config) != default_config - - raise ValidationError, - "configuration for Syntax cop found in #{smart_loaded_path}\n" \ - 'It\'s not possible to disable this cop.' - end - - def validate_section_presence(name) - return unless key?(name) && self[name].nil? - - raise ValidationError, - "empty section #{name} found in #{smart_loaded_path}" - end - - def validate_parameter_names(valid_cop_names) - valid_cop_names.each do |name| - validate_section_presence(name) - default_config = ConfigLoader.default_configuration[name] - - self[name].each_key do |param| - next if COMMON_PARAMS.include?(param) || default_config.key?(param) - - message = - "Warning: #{name} does not support #{param} parameter.\n\n" \ - "Supported parameters are:\n\n" \ - " - #{(default_config.keys - INTERNAL_PARAMS).join("\n - ")}\n" - - warn Rainbow(message).yellow.to_s - end - end - end - - def validate_enforced_styles(valid_cop_names) - valid_cop_names.each do |name| - styles = self[name].select { |key, _| key.start_with?('Enforced') } - - styles.each do |style_name, style| - supported_key = RuboCop::Cop::Util.to_supported_styles(style_name) - valid = ConfigLoader.default_configuration[name][supported_key] - next unless valid - next if valid.include?(style) - - msg = "invalid #{style_name} '#{style}' for #{name} found in " \ - "#{smart_loaded_path}\n" \ - "Valid choices are: #{valid.join(', ')}" - raise ValidationError, msg - end - end - end - - def reject_obsolete_cops_and_parameters - messages = [ - obsolete_cops, - obsolete_parameters - ].flatten.compact - return if messages.empty? - - raise ValidationError, messages.join("\n") - end - - def obsolete_parameters - OBSOLETE_PARAMETERS.map do |params| - obsolete_parameter_message(params[:cop], params[:parameter], - params[:alternative]) - end - end - - def obsolete_parameter_message(cop, parameter, alternative) - return unless self[cop] && self[cop].key?(parameter) - - "obsolete parameter #{parameter} (for #{cop}) " \ - "found in #{smart_loaded_path}" \ - "\n#{alternative}" + def smart_loaded_path + PathUtil.smart_path(@loaded_path) end - def obsolete_cops - OBSOLETE_COPS.map do |cop_name, message| - next unless key?(cop_name) || key?(Cop::Badge.parse(cop_name).cop_name) + def bundler_lock_file_path + return nil unless loaded_path - message + "\n(obsolete configuration found in #{smart_loaded_path}," \ - ' please update it)' + base_path = base_dir_for_path_parameters + ['gems.locked', 'Gemfile.lock'].each do |file_name| + path = find_file_upwards(file_name, base_path) + return path if path end + nil end - def check_target_ruby - return if KNOWN_RUBIES.include?(target_ruby_version) - - msg = if OBSOLETE_RUBIES.include?(target_ruby_version) - "Unsupported Ruby version #{target_ruby_version} found in " \ - "#{target_ruby_source}. #{target_ruby_version}-compatible " \ - 'analysis was dropped after version ' \ - "#{OBSOLETE_RUBIES[target_ruby_version]}." - else - "Unknown Ruby version #{target_ruby_version.inspect} found in " \ - "#{target_ruby_source}." - end + def pending_cops + keys.each_with_object([]) do |qualified_cop_name, pending_cops| + department = department_of(qualified_cop_name) + next if department && department['Enabled'] == false - msg += "\nSupported versions: #{KNOWN_RUBIES.join(', ')}" - - raise ValidationError, msg - end + cop_metadata = self[qualified_cop_name] + next unless cop_metadata['Enabled'] == 'pending' - def target_ruby_source - case @target_ruby_version_source - when :ruby_version_file - "`#{RUBY_VERSION_FILENAME}`" - when :bundler_lock_file - "`#{bundler_lock_file_path}`" - when :rubocop_yml - "`TargetRubyVersion` parameter (in #{smart_loaded_path})" + pending_cops << CopConfig.new(qualified_cop_name, cop_metadata) end end - def ruby_version_file - @ruby_version_file ||= - find_file_upwards(RUBY_VERSION_FILENAME, base_dir_for_path_parameters) - end - - def target_ruby_version_from_version_file - file = ruby_version_file - return unless file && File.file?(file) - - @target_ruby_version_from_version_file ||= - File.read(file).match(/\A(ruby-)?(?\d+\.\d+)/) do |md| - md[:version].to_f - end - end - - def target_ruby_version_from_bundler_lock_file - @target_ruby_version_from_bundler_lock_file ||= - read_ruby_version_from_bundler_lock_file - end - - def read_ruby_version_from_bundler_lock_file - lock_file_path = bundler_lock_file_path - return nil unless lock_file_path - - in_ruby_section = false - File.foreach(lock_file_path) do |line| - # If ruby is in Gemfile.lock or gems.lock, there should be two lines - # towards the bottom of the file that look like: - # RUBY VERSION - # ruby W.X.YpZ - # We ultimately want to match the "ruby W.X.Y.pZ" line, but there's - # extra logic to make sure we only start looking once we've seen the - # "RUBY VERSION" line. - in_ruby_section ||= line.match(/^\s*RUBY\s*VERSION\s*$/) - next unless in_ruby_section - - # We currently only allow this feature to work with MRI ruby. If jruby - # (or something else) is used by the project, it's lock file will have a - # line that looks like: - # RUBY VERSION - # ruby W.X.YpZ (jruby x.x.x.x) - # The regex won't match in this situation. - result = line.match(/^\s*ruby\s+(\d+\.\d+)[p.\d]*\s*$/) - return result.captures.first.to_f if result - end - end + private def target_rails_version_from_bundler_lock_file @target_rails_version_from_bundler_lock_file ||= @@ -674,43 +276,23 @@ def read_rails_version_from_bundler_lock_file end end - def bundler_lock_file_path - return nil unless loaded_path - - base_path = base_dir_for_path_parameters - ['gems.locked', 'Gemfile.lock'].each do |file_name| - path = find_file_upwards(file_name, base_path) - return path if path + def enable_cop?(qualified_cop_name, cop_options) + department = department_of(qualified_cop_name) + cop_enabled = cop_options.fetch('Enabled') do + !for_all_cops['DisabledByDefault'] end - nil - end + return true if cop_enabled == 'override_department' + return false if department && department['Enabled'] == false - def reject_mutually_exclusive_defaults - disabled_by_default = for_all_cops['DisabledByDefault'] - enabled_by_default = for_all_cops['EnabledByDefault'] - return unless disabled_by_default && enabled_by_default - - msg = 'Cops cannot be both enabled by default and disabled by default' - raise ValidationError, msg + cop_enabled end - def enable_cop?(qualified_cop_name, cop_options) + def department_of(qualified_cop_name) cop_department, cop_name = qualified_cop_name.split('/') - department = cop_name.nil? + return nil if cop_name.nil? - unless department - department_options = self[cop_department] - if department_options && department_options['Enabled'] == false - return false - end - end - - cop_options.fetch('Enabled', true) - end - - def smart_loaded_path - PathUtil.smart_path(@loaded_path) + self[cop_department] end end - # rubocop:enable Metrics/ClassLength end +# rubocop:enable Metrics/ClassLength diff --git a/lib/rubocop/config_loader.rb b/lib/rubocop/config_loader.rb index 69a3abc4357f..77d15ee32119 100644 --- a/lib/rubocop/config_loader.rb +++ b/lib/rubocop/config_loader.rb @@ -14,24 +14,23 @@ class ConfigNotFoundError < Error # during a run of the rubocop program, if files in several # directories are inspected. class ConfigLoader - DOTFILE = '.rubocop.yml'.freeze + DOTFILE = '.rubocop.yml' + XDG_CONFIG = 'config.yml' RUBOCOP_HOME = File.realpath(File.join(File.dirname(__FILE__), '..', '..')) DEFAULT_FILE = File.join(RUBOCOP_HOME, 'config', 'default.yml') - AUTO_GENERATED_FILE = '.rubocop_todo.yml'.freeze class << self include FileFinder - attr_accessor :debug, :auto_gen_config, :ignore_parent_exclusion, - :options_config - attr_writer :default_configuration + attr_accessor :debug, :ignore_parent_exclusion, + :disable_pending_cops, :enable_pending_cops + attr_writer :default_configuration, :project_root alias debug? debug - alias auto_gen_config? auto_gen_config alias ignore_parent_exclusion? ignore_parent_exclusion def clear_options - @debug = @auto_gen_config = @options_config = nil + @debug = nil FileFinder.root_level = nil end @@ -45,7 +44,8 @@ def load_file(file) add_missing_namespaces(path, hash) - resolver.resolve_inheritance_from_gems(hash, hash.delete('inherit_gem')) + resolver.override_department_setting_for_cops({}, hash) + resolver.resolve_inheritance_from_gems(hash) resolver.resolve_inheritance(path, hash, file, debug?) hash.delete('inherit_from') @@ -53,9 +53,27 @@ def load_file(file) Config.create(hash, path) end + def load_yaml_configuration(absolute_path) + file_contents = read_file(absolute_path) + yaml_code = Dir.chdir(File.dirname(absolute_path)) do + ERB.new(file_contents).result + end + check_duplication(yaml_code, absolute_path) + hash = yaml_safe_load(yaml_code, absolute_path) || {} + + puts "configuration from #{absolute_path}" if debug? + + raise(TypeError, "Malformed configuration in #{absolute_path}") unless hash.is_a?(Hash) + + hash + end + def add_missing_namespaces(path, hash) - hash.keys.each do |key| - q = Cop::Cop.qualified_cop_name(key, path) + # Using `hash.each_key` will cause the + # `can't add a new key into hash during iteration` error + hash_keys = hash.keys + hash_keys.each do |key| + q = Cop::Registry.qualified_cop_name(key, path) next if q == key hash[q] = hash.delete(key) @@ -75,109 +93,137 @@ def merge(base_hash, derived_hash) # user's home directory is checked. If there's no .rubocop.yml # there either, the path to the default file is returned. def configuration_file_for(target_dir) - find_file_upwards(DOTFILE, target_dir, use_home: true) || DEFAULT_FILE + find_project_dotfile(target_dir) || find_user_dotfile || + find_user_xdg_config || DEFAULT_FILE end def configuration_from_file(config_file) - config = load_file(config_file) - return config if config_file == DEFAULT_FILE + return default_configuration if config_file == DEFAULT_FILE + config = load_file(config_file) if ignore_parent_exclusion? print 'Ignoring AllCops/Exclude from parent folders' if debug? else add_excludes_from_files(config, config_file) end - merge_with_default(config, config_file) + + merge_with_default(config, config_file).tap do |merged_config| + warn_on_pending_cops(merged_config.pending_cops) unless possible_new_cops?(config) + end + end + + def possible_new_cops?(config) + disable_pending_cops || enable_pending_cops || + config.disabled_new_cops? || config.enabled_new_cops? end def add_excludes_from_files(config, config_file) - found_files = find_files_upwards(DOTFILE, config_file, use_home: true) - return if found_files.empty? - return if PathUtil.relative_path(found_files.last) == - PathUtil.relative_path(config_file) + exclusion_file = find_last_file_upwards(DOTFILE, config_file, project_root) + + return unless exclusion_file + return if PathUtil.relative_path(exclusion_file) == PathUtil.relative_path(config_file) print 'AllCops/Exclude ' if debug? - config.add_excludes_from_higher_level(load_file(found_files.last)) + config.add_excludes_from_higher_level(load_file(exclusion_file)) end def default_configuration @default_configuration ||= begin - print 'Default ' if debug? - load_file(DEFAULT_FILE) - end + print 'Default ' if debug? + load_file(DEFAULT_FILE) + end end - # Merges the given configuration with the default one. If - # AllCops:DisabledByDefault is true, it changes the Enabled params so - # that only cops from user configuration are enabled. - # If AllCops::EnabledByDefault is true, it changes the Enabled params - # so that only cops explicitly disabled in user configuration are - # disabled. - def merge_with_default(config, config_file) - resolver.merge_with_default(config, config_file) + # Returns the path rubocop inferred as the root of the project. No file + # searches will go past this directory. + def project_root + @project_root ||= find_project_root end - def add_inheritance_from_auto_generated_file - file_string = " #{AUTO_GENERATED_FILE}" + PENDING_BANNER = <<~BANNER + The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file. - config_file = options_config || DOTFILE + Please also note that can also opt-in to new cops by default by adding this to your config: + AllCops: + NewCops: enable + BANNER - if File.exist?(config_file) - files = Array(load_yaml_configuration(config_file)['inherit_from']) + def warn_on_pending_cops(pending_cops) + return if pending_cops.empty? - return if files.include?(AUTO_GENERATED_FILE) + warn Rainbow(PENDING_BANNER).yellow - files.unshift(AUTO_GENERATED_FILE) - file_string = "\n - " + files.join("\n - ") if files.size > 1 - rubocop_yml_contents = existing_configuration(config_file) + pending_cops.each do |cop| + warn_pending_cop cop end - write_config_file(config_file, file_string, rubocop_yml_contents) + warn Rainbow('For more information: https://docs.rubocop.org/rubocop/versioning.html').yellow + end - puts "Added inheritance from `#{AUTO_GENERATED_FILE}` in `#{DOTFILE}`." + def warn_pending_cop(cop) + version = cop.metadata['VersionAdded'] || 'N/A' + + warn Rainbow("#{cop.name}: # (new in #{version})").yellow + warn Rainbow(' Enabled: true').yellow + end + + # Merges the given configuration with the default one. + def merge_with_default(config, config_file, unset_nil: true) + resolver.merge_with_default(config, config_file, unset_nil: unset_nil) end private - def existing_configuration(config_file) - IO.read(config_file, encoding: Encoding::UTF_8) - .sub(%r{^inherit_from: *[.\/\w]+}, '') - .sub(%r{^inherit_from: *(\n *- *[.\/\w]+)+}, '') + def find_project_dotfile(target_dir) + find_file_upwards(DOTFILE, target_dir, project_root) end - def write_config_file(file_name, file_string, rubocop_yml_contents) - File.open(file_name, 'w') do |f| - f.write "inherit_from:#{file_string}\n" - f.write "\n#{rubocop_yml_contents}" if rubocop_yml_contents =~ /\S/ - end - end + def find_project_root + pwd = Dir.pwd + gems_file = find_last_file_upwards('Gemfile', pwd) || find_last_file_upwards('gems.rb', pwd) + return unless gems_file - def resolver - @resolver ||= ConfigLoaderResolver.new + File.dirname(gems_file) end - def load_yaml_configuration(absolute_path) - yaml_code = read_file(absolute_path) - check_duplication(yaml_code, absolute_path) - hash = yaml_safe_load(yaml_code, absolute_path) || {} + def find_user_dotfile + return unless ENV.key?('HOME') - puts "configuration from #{absolute_path}" if debug? + file = File.join(Dir.home, DOTFILE) + return file if File.exist?(file) + end - unless hash.is_a?(Hash) - raise(TypeError, "Malformed configuration in #{absolute_path}") - end + def find_user_xdg_config + xdg_config_home = expand_path(ENV.fetch('XDG_CONFIG_HOME', '~/.config')) + xdg_config = File.join(xdg_config_home, 'rubocop', XDG_CONFIG) + return xdg_config if File.exist?(xdg_config) + end - hash + def expand_path(path) + File.expand_path(path) + rescue ArgumentError + # Could happen because HOME or ID could not be determined. Fall back on + # using the path literally in that case. + path + end + + def resolver + @resolver ||= ConfigLoaderResolver.new end def check_duplication(yaml_code, absolute_path) smart_path = PathUtil.smart_path(absolute_path) YAMLDuplicationChecker.check(yaml_code, absolute_path) do |key1, key2| value = key1.value - line1 = key1.start_line + 1 - line2 = key2.start_line + 1 - message = "#{smart_path}:#{line1}: " \ - "`#{value}` is concealed by line #{line2}" + # .start_line is only available since ruby 2.5 / psych 3.0 + message = if key1.respond_to? :start_line + line1 = key1.start_line + 1 + line2 = key2.start_line + 1 + "#{smart_path}:#{line1}: " \ + "`#{value}` is concealed by line #{line2}" + else + "#{smart_path}: `#{value}` is concealed by duplicate" + end warn Rainbow(message).yellow end end @@ -194,16 +240,16 @@ def read_file(absolute_path) def yaml_safe_load(yaml_code, filename) if defined?(SafeYAML) && SafeYAML.respond_to?(:load) - SafeYAML.load(yaml_code, filename, - whitelisted_tags: %w[!ruby/regexp]) + SafeYAML.load(yaml_code, filename, whitelisted_tags: %w[!ruby/regexp]) + # Ruby 2.6+ + elsif Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0') + YAML.safe_load(yaml_code, + permitted_classes: [Regexp, Symbol], + permitted_symbols: [], + aliases: true, + filename: filename) else - YAML.safe_load( - yaml_code, - permitted_classes: [Regexp, Symbol], - permitted_symbols: [], - aliases: false, - filename: filename - ) + YAML.safe_load(yaml_code, [Regexp, Symbol], [], true, filename) end end end diff --git a/lib/rubocop/config_loader_resolver.rb b/lib/rubocop/config_loader_resolver.rb index fbf8fefc4489..4a3bf7fef2da 100644 --- a/lib/rubocop/config_loader_resolver.rb +++ b/lib/rubocop/config_loader_resolver.rb @@ -5,6 +5,7 @@ module RuboCop # A help class for ConfigLoader that handles configuration resolution. + # @api private class ConfigLoaderResolver def resolve_requires(path, hash) config_dir = File.dirname(path) @@ -17,10 +18,12 @@ def resolve_requires(path, hash) end end + # rubocop:disable Metrics/MethodLength def resolve_inheritance(path, hash, file, debug) inherited_files = Array(hash['inherit_from']) base_configs(path, inherited_files, file) .reverse.each_with_index do |base_config, index| + override_department_setting_for_cops(base_config, hash) base_config.each do |k, v| next unless v.is_a?(Hash) @@ -34,8 +37,10 @@ def resolve_inheritance(path, hash, file, debug) end end end + # rubocop:enable Metrics/MethodLength - def resolve_inheritance_from_gems(hash, gems) + def resolve_inheritance_from_gems(hash) + gems = hash.delete('inherit_gem') (gems || {}).each_pair do |gem_name, config_path| if gem_name == 'rubocop' raise ArgumentError, @@ -55,7 +60,7 @@ def resolve_inheritance_from_gems(hash, gems) # only cops from user configuration are enabled. If # AllCops::EnabledByDefault is true, it changes the Enabled params so that # only cops explicitly disabled in user configuration are disabled. - def merge_with_default(config, config_file) + def merge_with_default(config, config_file, unset_nil:) default_configuration = ConfigLoader.default_configuration disabled_by_default = config.for_all_cops['DisabledByDefault'] @@ -67,13 +72,11 @@ def merge_with_default(config, config_file) end end - if disabled_by_default - config = handle_disabled_by_default(config, default_configuration) - end + config = handle_disabled_by_default(config, default_configuration) if disabled_by_default - Config.new(merge(default_configuration, config, - inherit_mode: config['inherit_mode'] || {}), - config_file) + opts = { inherit_mode: config['inherit_mode'] || {}, + unset_nil: unset_nil } + Config.new(merge(default_configuration, config, **opts), config_file) end # Return a recursive merge of two hashes. That is, a normal hash merge, @@ -85,20 +88,44 @@ def merge(base_hash, derived_hash, **opts) result = base_hash.merge(derived_hash) keys_appearing_in_both = base_hash.keys & derived_hash.keys keys_appearing_in_both.each do |key| - if base_hash[key].is_a?(Hash) + if opts[:unset_nil] && derived_hash[key].nil? + result.delete(key) + elsif base_hash[key].is_a?(Hash) result[key] = merge(base_hash[key], derived_hash[key], **opts) elsif should_union?(base_hash, key, opts[:inherit_mode]) result[key] = base_hash[key] | derived_hash[key] elsif opts[:debug] - warn_on_duplicate_setting(base_hash, derived_hash, key, opts) + warn_on_duplicate_setting(base_hash, derived_hash, key, **opts) end end result end # rubocop:enable Metrics/AbcSize + # An `Enabled: true` setting in user configuration for a cop overrides an + # `Enabled: false` setting for its department. + def override_department_setting_for_cops(base_hash, derived_hash) + derived_hash.each_key do |key| + next unless key =~ %r{(.*)/.*} + + department = Regexp.last_match(1) + next unless disabled?(derived_hash, department) || + disabled?(base_hash, department) + + # The `override_department` setting for the `Enabled` parameter is an + # internal setting that's not documented in the manual. It will cause a + # cop to be enabled later, when logic surrounding enabled/disabled it + # run, even though its department is disabled. + derived_hash[key]['Enabled'] = 'override_department' if derived_hash[key]['Enabled'] + end + end + private + def disabled?(hash, department) + hash[department] && hash[department]['Enabled'] == false + end + def duplicate_setting?(base_hash, derived_hash, key, inherited_file) return false if inherited_file.nil? # Not inheritance resolving merge return false if inherited_file.start_with?('..') # Legitimate override @@ -145,10 +172,20 @@ def base_configs(path, inherit_from, file) def inherited_file(path, inherit_from, file) if remote_file?(inherit_from) + # A remote configuration, e.g. `inherit_from: http://example.com/rubocop.yml`. RemoteConfig.new(inherit_from, File.dirname(path)) + elsif Pathname.new(inherit_from).absolute? + # An absolute path to a config, e.g. `inherit_from: /Users/me/rubocop.yml`. + # The path may come from `inherit_gem` option, where a gem name is expanded + # to an absolute path to that gem. + print 'Inheriting ' if ConfigLoader.debug? + inherit_from elsif file.is_a?(RemoteConfig) + # A path relative to a URL, e.g. `inherit_from: configs/default.yml` + # in a config included with `inherit_from: http://example.com/rubocop.yml` file.inherit_from_remote(inherit_from, path) else + # A local relative path, e.g. `inherit_from: default.yml` print 'Inheriting ' if ConfigLoader.debug? File.expand_path(inherit_from, File.dirname(path)) end @@ -156,22 +193,16 @@ def inherited_file(path, inherit_from, file) def remote_file?(uri) regex = URI::DEFAULT_PARSER.make_regexp(%w[http https]) - uri =~ /\A#{regex}\z/ + /\A#{regex}\z/.match?(uri) end def handle_disabled_by_default(config, new_default_configuration) department_config = config.to_hash.reject { |cop| cop.include?('/') } department_config.each do |dept, dept_params| - # Rails is always disabled by default and the department's Enabled flag - # works like the --rails command line option, which is that when - # AllCops:DisabledByDefault is true, each Rails cop must still be - # explicitly mentioned in user configuration in order to be enabled. - next if dept == 'Rails' - next unless dept_params['Enabled'] new_default_configuration.each do |cop, params| - next unless cop.start_with?(dept + '/') + next unless cop.start_with?("#{dept}/") # Retain original default configuration for cops in the department. params['Enabled'] = ConfigLoader.default_configuration[cop]['Enabled'] @@ -183,13 +214,19 @@ def handle_disabled_by_default(config, new_default_configuration) end end - def transform(config) - Hash[config.map { |cop, params| [cop, yield(params)] }] + def transform(config, &block) + config.transform_values(&block) end def gem_config_path(gem_name, relative_config_path) - spec = Gem::Specification.find_by_name(gem_name) - File.join(spec.gem_dir, relative_config_path) + if defined?(Bundler) + gem = Bundler.load.specs[gem_name].first + gem_path = gem.full_gem_path if gem + end + + gem_path ||= Gem::Specification.find_by_name(gem_name).gem_dir + + File.join(gem_path, relative_config_path) rescue Gem::LoadError => e raise Gem::LoadError, "Unable to find gem #{gem_name}; is the gem installed? #{e}" diff --git a/lib/rubocop/config_obsoletion.rb b/lib/rubocop/config_obsoletion.rb new file mode 100644 index 000000000000..aa372f868cd0 --- /dev/null +++ b/lib/rubocop/config_obsoletion.rb @@ -0,0 +1,283 @@ +# frozen_string_literal: true + +module RuboCop + # This class handles obsolete configuration. + # @api private + class ConfigObsoletion + RENAMED_COPS = { + 'Layout/AlignArguments' => 'Layout/ArgumentAlignment', + 'Layout/AlignArray' => 'Layout/ArrayAlignment', + 'Layout/AlignHash' => 'Layout/HashAlignment', + 'Layout/AlignParameters' => 'Layout/ParameterAlignment', + 'Layout/IndentArray' => 'Layout/FirstArrayElementIndentation', + 'Layout/IndentAssignment' => 'Layout/AssignmentIndentation', + 'Layout/IndentFirstArgument' => 'Layout/FirstArgumentIndentation', + 'Layout/IndentFirstArrayElement' => 'Layout/FirstArrayElementIndentation', + 'Layout/IndentFirstHashElement' => 'Layout/FirstHashElementIndentation', + 'Layout/IndentFirstParameter' => 'Layout/FirstParameterIndentation', + 'Layout/IndentHash' => 'Layout/FirstHashElementIndentation', + 'Layout/IndentHeredoc' => 'Layout/HeredocIndentation', + 'Layout/LeadingBlankLines' => 'Layout/LeadingEmptyLines', + 'Layout/Tab' => 'Layout/IndentationStyle', + 'Layout/TrailingBlankLines' => 'Layout/TrailingEmptyLines', + 'Lint/DuplicatedKey' => 'Lint/DuplicateHashKey', + 'Lint/EndInMethod' => 'Style/EndBlock', + 'Lint/HandleExceptions' => 'Lint/SuppressedException', + 'Lint/MultipleCompare' => 'Lint/MultipleComparison', + 'Lint/StringConversionInInterpolation' => 'Lint/RedundantStringCoercion', + 'Lint/UnneededCopDisableDirective' => 'Lint/RedundantCopDisableDirective', + 'Lint/UnneededCopEnableDirective' => 'Lint/RedundantCopEnableDirective', + 'Lint/UnneededRequireStatement' => 'Lint/RedundantRequireStatement', + 'Lint/UnneededSplatExpansion' => 'Lint/RedundantSplatExpansion', + 'Naming/UncommunicativeBlockParamName' => 'Naming/BlockParameterName', + 'Naming/UncommunicativeMethodParamName' => 'Naming/MethodParameterName', + 'Style/DeprecatedHashMethods' => 'Style/PreferredHashMethods', + 'Style/MethodCallParentheses' => 'Style/MethodCallWithoutArgsParentheses', + 'Style/OpMethod' => 'Naming/BinaryOperatorParameterName', + 'Style/SingleSpaceBeforeFirstArg' => 'Layout/SpaceBeforeFirstArg', + 'Style/UnneededCapitalW' => 'Style/RedundantCapitalW', + 'Style/UnneededCondition' => 'Style/RedundantCondition', + 'Style/UnneededInterpolation' => 'Style/RedundantInterpolation', + 'Style/UnneededPercentQ' => 'Style/RedundantPercentQ', + 'Style/UnneededSort' => 'Style/RedundantSort' + }.map do |old_name, new_name| + [old_name, "The `#{old_name}` cop has been renamed to `#{new_name}`."] + end + + MOVED_COPS = { + 'Security' => 'Lint/Eval', + 'Naming' => %w[Style/ClassAndModuleCamelCase Style/ConstantName + Style/FileName Style/MethodName Style/PredicateName + Style/VariableName Style/VariableNumber + Style/AccessorMethodName Style/AsciiIdentifiers], + 'Layout' => %w[Lint/BlockAlignment Lint/EndAlignment + Lint/DefEndAlignment Metrics/LineLength], + 'Lint' => 'Style/FlipFlop' + }.map do |new_department, old_names| + Array(old_names).map do |old_name| + [old_name, "The `#{old_name}` cop has been moved to " \ + "`#{new_department}/#{old_name.split('/').last}`."] + end + end + + REMOVED_COPS = { + 'Layout/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword', + 'Layout/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword', + 'Lint/RescueWithoutErrorClass' => 'Style/RescueStandardError', + 'Style/SpaceAfterControlKeyword' => 'Layout/SpaceAroundKeyword', + 'Style/SpaceBeforeModifierKeyword' => 'Layout/SpaceAroundKeyword', + 'Style/TrailingComma' => 'Style/TrailingCommaInArguments, ' \ + 'Style/TrailingCommaInArrayLiteral, and/or ' \ + 'Style/TrailingCommaInHashLiteral', + 'Style/TrailingCommaInLiteral' => 'Style/TrailingCommaInArrayLiteral ' \ + 'and/or ' \ + 'Style/TrailingCommaInHashLiteral', + 'Style/BracesAroundHashParameters' => nil + }.map do |old_name, other_cops| + if other_cops + more = ". Please use #{other_cops} instead".gsub(%r{[A-Z]\w+/\w+}, + '`\&`') + end + [old_name, "The `#{old_name}` cop has been removed#{more}."] + end + + REMOVED_COPS_WITH_REASON = { + 'Lint/InvalidCharacterLiteral' => 'it was never being actually triggered', + 'Lint/SpaceBeforeFirstArg' => + 'it was a duplicate of `Layout/SpaceBeforeFirstArg`. Please use ' \ + '`Layout/SpaceBeforeFirstArg` instead', + 'Style/MethodMissingSuper' => 'it has been superseded by `Lint/MissingSuper`. Please use ' \ + '`Lint/MissingSuper` instead', + 'Lint/UselessComparison' => 'it has been superseded by '\ + '`Lint/BinaryOperatorWithIdenticalOperands`. Please use '\ + '`Lint/BinaryOperatorWithIdenticalOperands` instead' + }.map do |cop_name, reason| + [cop_name, "The `#{cop_name}` cop has been removed since #{reason}."] + end + + SPLIT_COPS = { + 'Style/MethodMissing' => + 'The `Style/MethodMissing` cop has been split into ' \ + '`Style/MethodMissingSuper` and `Style/MissingRespondToMissing`.' + }.to_a + + OBSOLETE_COPS = Hash[*(RENAMED_COPS + MOVED_COPS + REMOVED_COPS + + REMOVED_COPS_WITH_REASON + SPLIT_COPS).flatten] + + OBSOLETE_PARAMETERS = [ + { + cops: %w[Layout/SpaceAroundOperators Style/SpaceAroundOperators], + parameters: 'MultiSpaceAllowedForOperators', + alternative: 'If your intention was to allow extra spaces for ' \ + 'alignment, please use AllowForAlignment: true instead.' + }, + { + cops: 'Style/Encoding', + parameters: %w[EnforcedStyle SupportedStyles + AutoCorrectEncodingComment], + alternative: 'Style/Encoding no longer supports styles. ' \ + 'The "never" behavior is always assumed.' + }, + { + cops: 'Style/IfUnlessModifier', + parameters: 'MaxLineLength', + alternative: '`Style/IfUnlessModifier: MaxLineLength` has been ' \ + 'removed. Use `Layout/LineLength: Max` instead' + }, + { + cops: 'Style/WhileUntilModifier', + parameters: 'MaxLineLength', + alternative: '`Style/WhileUntilModifier: MaxLineLength` has been ' \ + 'removed. Use `Layout/LineLength: Max` instead' + }, + { + cops: 'AllCops', + parameters: 'RunRailsCops', + alternative: "Use the following configuration instead:\n" \ + "Rails:\n Enabled: true" + }, + { + cops: 'Layout/CaseIndentation', + parameters: 'IndentWhenRelativeTo', + alternative: '`IndentWhenRelativeTo` has been renamed to ' \ + '`EnforcedStyle`' + }, + { + cops: %w[Lint/BlockAlignment Layout/BlockAlignment Lint/EndAlignment + Layout/EndAlignment Lint/DefEndAlignment + Layout/DefEndAlignment], + parameters: 'AlignWith', + alternative: '`AlignWith` has been renamed to `EnforcedStyleAlignWith`' + }, + { + cops: 'Rails/UniqBeforePluck', + parameters: 'EnforcedMode', + alternative: '`EnforcedMode` has been renamed to `EnforcedStyle`' + }, + { + cops: 'Style/MethodCallWithArgsParentheses', + parameters: 'IgnoredMethodPatterns', + alternative: '`IgnoredMethodPatterns` has been renamed to ' \ + '`IgnoredPatterns`' + }, + { + cops: %w[Performance/Count Performance/Detect], + parameters: 'SafeMode', + alternative: '`SafeMode` has been removed. ' \ + 'Use `SafeAutoCorrect` instead.' + }, + { + cops: 'Bundler/GemComment', + parameters: 'Whitelist', + alternative: '`Whitelist` has been renamed to `IgnoredGems`.' + }, + { + cops: %w[ + Lint/SafeNavigationChain Lint/SafeNavigationConsistency + Style/NestedParenthesizedCalls Style/SafeNavigation + Style/TrivialAccessors + ], + parameters: 'Whitelist', + alternative: '`Whitelist` has been renamed to `AllowedMethods`.' + }, + { + cops: 'Style/IpAddresses', + parameters: 'Whitelist', + alternative: '`Whitelist` has been renamed to `AllowedAddresses`.' + }, + { + cops: 'Naming/HeredocDelimiterNaming', + parameters: 'Blacklist', + alternative: '`Blacklist` has been renamed to `ForbiddenDelimiters`.' + }, + { + cops: 'Naming/PredicateName', + parameters: 'NamePrefixBlacklist', + alternative: '`NamePrefixBlacklist` has been renamed to ' \ + '`ForbiddenPrefixes`.' + }, + { + cops: 'Naming/PredicateName', + parameters: 'NameWhitelist', + alternative: '`NameWhitelist` has been renamed to ' \ + '`AllowedMethods`.' + } + ].freeze + + OBSOLETE_ENFORCED_STYLES = [ + { + cop: 'Layout/IndentationConsistency', + parameter: 'EnforcedStyle', + enforced_style: 'rails', + alternative: '`EnforcedStyle: rails` has been renamed to ' \ + '`EnforcedStyle: indented_internal_methods`' + } + ].freeze + + def initialize(config) + @config = config + end + + def reject_obsolete_cops_and_parameters + messages = [obsolete_cops, obsolete_parameters, + obsolete_enforced_style].flatten.compact + return if messages.empty? + + raise ValidationError, messages.join("\n") + end + + private + + def obsolete_cops + OBSOLETE_COPS.map do |cop_name, message| + next unless @config.key?(cop_name) || + @config.key?(Cop::Badge.parse(cop_name).cop_name) + + message + "\n(obsolete configuration found in " \ + "#{smart_loaded_path}, please update it)" + end + end + + def obsolete_enforced_style + OBSOLETE_ENFORCED_STYLES.map do |params| + obsolete_enforced_style_message(params[:cop], params[:parameter], + params[:enforced_style], + params[:alternative]) + end + end + + def obsolete_enforced_style_message(cop, param, enforced_style, alternative) + style = @config[cop]&.detect { |key, _| key.start_with?(param) } + + return unless style && style[1] == enforced_style + + "obsolete `#{param}: #{enforced_style}` (for #{cop}) found in " \ + "#{smart_loaded_path}\n#{alternative}" + end + + def obsolete_parameters + OBSOLETE_PARAMETERS.map do |params| + obsolete_parameter_message(params[:cops], params[:parameters], + params[:alternative]) + end + end + + def obsolete_parameter_message(cops, parameters, alternative) + Array(cops).map do |cop| + obsolete_parameters = Array(parameters).select do |param| + @config[cop]&.key?(param) + end + next if obsolete_parameters.empty? + + obsolete_parameters.map do |parameter| + "obsolete parameter #{parameter} (for #{cop}) found in " \ + "#{smart_loaded_path}\n#{alternative}" + end + end + end + + def smart_loaded_path + PathUtil.smart_path(@config.loaded_path) + end + end +end diff --git a/lib/rubocop/config_regeneration.rb b/lib/rubocop/config_regeneration.rb new file mode 100644 index 000000000000..bae43fea9be5 --- /dev/null +++ b/lib/rubocop/config_regeneration.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module RuboCop + # This class handles collecting the options for regenerating a TODO file. + # @api private + class ConfigRegeneration + AUTO_GENERATED_FILE = RuboCop::CLI::Command::AutoGenerateConfig::AUTO_GENERATED_FILE + COMMAND_REGEX = /(?<=`rubocop )(.*?)(?=`)/.freeze + DEFAULT_OPTIONS = { auto_gen_config: true }.freeze + + # Get options from the comment in the TODO file, and parse them as options + def options + # If there's no existing TODO file, generate one + return DEFAULT_OPTIONS unless todo_exists? + + match = generation_command.match(COMMAND_REGEX) + return DEFAULT_OPTIONS unless match + + options = match[1].split(' ') + Options.new.parse(options).first + end + + private + + def todo_exists? + File.exist?(AUTO_GENERATED_FILE) && !File.empty?(AUTO_GENERATED_FILE) + end + + def generation_command + File.foreach(AUTO_GENERATED_FILE).take(2).last + end + end +end diff --git a/lib/rubocop/config_store.rb b/lib/rubocop/config_store.rb index 3edcec71c40e..7c01f7b58eef 100644 --- a/lib/rubocop/config_store.rb +++ b/lib/rubocop/config_store.rb @@ -29,20 +29,34 @@ def force_default_config! @options_config = ConfigLoader.default_configuration end - def for(file_or_dir) - return @options_config if @options_config + def for_file(file) + for_dir(File.dirname(file)) + end + + def for_pwd + for_dir(Dir.pwd) + end + # If type (file/dir) is known beforehand, + # prefer using #for_file or #for_dir for improved performance + def for(file_or_dir) dir = if File.directory?(file_or_dir) file_or_dir else File.dirname(file_or_dir) end + for_dir(dir) + end + + def for_dir(dir) + return @options_config if @options_config + @path_cache[dir] ||= ConfigLoader.configuration_file_for(dir) path = @path_cache[dir] @object_cache[path] ||= begin - print "For #{dir}: " if ConfigLoader.debug? - ConfigLoader.configuration_from_file(path) - end + print "For #{dir}: " if ConfigLoader.debug? + ConfigLoader.configuration_from_file(path) + end end end end diff --git a/lib/rubocop/config_validator.rb b/lib/rubocop/config_validator.rb new file mode 100644 index 000000000000..81fb923e69e9 --- /dev/null +++ b/lib/rubocop/config_validator.rb @@ -0,0 +1,224 @@ +# frozen_string_literal: true + +require 'pathname' + +module RuboCop + # Handles validation of configuration, for example cop names, parameter + # names, and Ruby versions. + class ConfigValidator + extend Forwardable + + # @api private + COMMON_PARAMS = %w[Exclude Include Severity inherit_mode + AutoCorrect StyleGuide Details].freeze + # @api private + INTERNAL_PARAMS = %w[Description StyleGuide + VersionAdded VersionChanged VersionRemoved + Reference Safe SafeAutoCorrect].freeze + # @api private + NEW_COPS_VALUES = %w[pending disable enable].freeze + + def_delegators :@config, :smart_loaded_path, :for_all_cops + + def initialize(config) + @config = config + @config_obsoletion = ConfigObsoletion.new(config) + @target_ruby = TargetRuby.new(config) + end + + def validate + check_cop_config_value(@config) + reject_conflicting_safe_settings + + # Don't validate RuboCop's own files further. Avoids infinite recursion. + return if @config.internal? + + valid_cop_names, invalid_cop_names = @config.keys.partition do |key| + ConfigLoader.default_configuration.key?(key) + end + + @config_obsoletion.reject_obsolete_cops_and_parameters + + alert_about_unrecognized_cops(invalid_cop_names) + check_target_ruby + validate_new_cops_parameter + validate_parameter_names(valid_cop_names) + validate_enforced_styles(valid_cop_names) + validate_syntax_cop + reject_mutually_exclusive_defaults + end + + def target_ruby_version + target_ruby.version + end + + def validate_section_presence(name) + return unless @config.key?(name) && @config[name].nil? + + raise ValidationError, + "empty section #{name} found in #{smart_loaded_path}" + end + + private + + attr_reader :target_ruby + + def check_target_ruby + return if target_ruby.supported? + + source = target_ruby.source + last_version = target_ruby.rubocop_version_with_support + + msg = if last_version + "RuboCop found unsupported Ruby version #{target_ruby_version} " \ + "in #{source}. #{target_ruby_version}-compatible " \ + "analysis was dropped after version #{last_version}." + else + 'RuboCop found unknown Ruby version ' \ + "#{target_ruby_version.inspect} in #{source}." + end + + msg += "\nSupported versions: #{TargetRuby.supported_versions.join(', ')}" + + raise ValidationError, msg + end + + def alert_about_unrecognized_cops(invalid_cop_names) + unknown_cops = [] + invalid_cop_names.each do |name| + # There could be a custom cop with this name. If so, don't warn + next if Cop::Registry.global.contains_cop_matching?([name]) + + # Special case for inherit_mode, which is a directive that we keep in + # the configuration (even though it's not a cop), because it's easier + # to do so than to pass the value around to various methods. + next if name == 'inherit_mode' + + unknown_cops << "unrecognized cop #{name} found in " \ + "#{smart_loaded_path}" + end + raise ValidationError, unknown_cops.join(', ') if unknown_cops.any? + end + + def validate_syntax_cop + syntax_config = @config['Lint/Syntax'] + default_config = ConfigLoader.default_configuration['Lint/Syntax'] + + return unless syntax_config && + default_config.merge(syntax_config) != default_config + + raise ValidationError, + "configuration for Syntax cop found in #{smart_loaded_path}\n" \ + 'It\'s not possible to disable this cop.' + end + + def validate_new_cops_parameter + new_cop_parameter = @config.for_all_cops['NewCops'] + return if new_cop_parameter.nil? || + NEW_COPS_VALUES.include?(new_cop_parameter) + + message = "invalid #{new_cop_parameter} for `NewCops` found in" \ + "#{smart_loaded_path}\n" \ + "Valid choices are: #{NEW_COPS_VALUES.join(', ')}" + + raise ValidationError, message + end + + def validate_parameter_names(valid_cop_names) + valid_cop_names.each do |name| + validate_section_presence(name) + each_invalid_parameter(name) do |param, supported_params| + warn Rainbow(<<~MESSAGE).yellow + Warning: #{name} does not support #{param} parameter. + + Supported parameters are: + + - #{supported_params.join("\n - ")} + MESSAGE + end + end + end + + def each_invalid_parameter(cop_name) + default_config = ConfigLoader.default_configuration[cop_name] + + @config[cop_name].each_key do |param| + next if COMMON_PARAMS.include?(param) || default_config.key?(param) + + supported_params = default_config.keys - INTERNAL_PARAMS + + yield param, supported_params + end + end + + def validate_enforced_styles(valid_cop_names) # rubocop:todo Metrics/AbcSize + valid_cop_names.each do |name| + styles = @config[name].select { |key, _| key.start_with?('Enforced') } + + styles.each do |style_name, style| + supported_key = RuboCop::Cop::Util.to_supported_styles(style_name) + valid = ConfigLoader.default_configuration[name][supported_key] + + next unless valid + next if valid.include?(style) + next if validate_support_and_has_list(name, style, valid) + + msg = "invalid #{style_name} '#{style}' for #{name} found in " \ + "#{smart_loaded_path}\n" \ + "Valid choices are: #{valid.join(', ')}" + raise ValidationError, msg + end + end + end + + def validate_support_and_has_list(name, formats, valid) + ConfigLoader.default_configuration[name]['AllowMultipleStyles'] && + formats.is_a?(Array) && + formats.all? { |format| valid.include?(format) } + end + + def reject_mutually_exclusive_defaults + disabled_by_default = for_all_cops['DisabledByDefault'] + enabled_by_default = for_all_cops['EnabledByDefault'] + return unless disabled_by_default && enabled_by_default + + msg = 'Cops cannot be both enabled by default and disabled by default' + raise ValidationError, msg + end + + def reject_conflicting_safe_settings + @config.each do |name, cop_config| + next unless cop_config.is_a?(Hash) + next unless cop_config['Safe'] == false && + cop_config['SafeAutoCorrect'] == true + + msg = 'Unsafe cops cannot have a safe auto-correction ' \ + "(section #{name} in #{smart_loaded_path})" + raise ValidationError, msg + end + end + + def check_cop_config_value(hash, parent = nil) + hash.each do |key, value| + check_cop_config_value(value, key) if value.is_a?(Hash) + + next unless %w[Enabled + Safe + SafeAutoCorrect + AutoCorrect].include?(key) && value.is_a?(String) + + next if key == 'Enabled' && + %w[pending override_department].include?(value) + + raise ValidationError, msg_not_boolean(parent, key, value) + end + end + + # FIXME: Handling colors in exception messages like this is ugly. + def msg_not_boolean(parent, key, value) + "#{Rainbow('').reset}" \ + "Property #{Rainbow(key).yellow} of cop #{Rainbow(parent).yellow}" \ + " is supposed to be a boolean and #{Rainbow(value).yellow} is not." + end + end +end diff --git a/lib/rubocop/cop/autocorrect_logic.rb b/lib/rubocop/cop/autocorrect_logic.rb index c5b75acf3ae6..5339246eea99 100644 --- a/lib/rubocop/cop/autocorrect_logic.rb +++ b/lib/rubocop/cop/autocorrect_logic.rb @@ -5,15 +5,24 @@ module Cop # This module encapsulates the logic for autocorrect behavior for a cop. module AutocorrectLogic def autocorrect? - autocorrect_requested? && support_autocorrect? && autocorrect_enabled? + autocorrect_requested? && correctable? && autocorrect_enabled? end def autocorrect_requested? @options.fetch(:auto_correct, false) end - def support_autocorrect? - respond_to?(:autocorrect) + def correctable? + self.class.support_autocorrect? || disable_uncorrectable? + end + + def disable_uncorrectable? + @options[:disable_uncorrectable] == true + end + + def safe_autocorrect? + cop_config.fetch('Safe', true) && + cop_config.fetch('SafeAutoCorrect', true) end def autocorrect_enabled? @@ -22,12 +31,65 @@ def autocorrect_enabled? return false if cop_config['AutoCorrect'] == false - if @options.fetch(:safe_auto_correct, false) - return cop_config.fetch('SafeAutoCorrect', true) - end + return safe_autocorrect? if @options.fetch(:safe_auto_correct, false) true end + + private + + def disable_offense(range) + eol_comment = " # rubocop:todo #{cop_name}" + needed_line_length = (range.source_line + eol_comment).length + if needed_line_length <= max_line_length + disable_offense_at_end_of_line(range_of_first_line(range), + eol_comment) + else + disable_offense_before_and_after(range_by_lines(range)) + end + end + + def range_of_first_line(range) + begin_of_first_line = range.begin_pos - range.column + end_of_first_line = begin_of_first_line + range.source_line.length + + Parser::Source::Range.new(range.source_buffer, + begin_of_first_line, + end_of_first_line) + end + + # Expand the given range to include all of any lines it covers. Does not + # include newline at end of the last line. + def range_by_lines(range) + begin_of_first_line = range.begin_pos - range.column + + last_line = range.source_buffer.source_line(range.last_line) + last_line_offset = last_line.length - range.last_column + end_of_last_line = range.end_pos + last_line_offset + + Parser::Source::Range.new(range.source_buffer, + begin_of_first_line, + end_of_last_line) + end + + def max_line_length + config.for_cop('Layout/LineLength')['Max'] || 120 + end + + def disable_offense_at_end_of_line(range, eol_comment) + Corrector.new(range).insert_after(range, eol_comment) + end + + def disable_offense_before_and_after(range_by_lines) + range_with_newline = range_by_lines.resize(range_by_lines.size + 1) + leading_whitespace = range_by_lines.source_line[/^\s*/] + + Corrector.new(range_by_lines).wrap( + range_with_newline, + "#{leading_whitespace}# rubocop:todo #{cop_name}\n", + "#{leading_whitespace}# rubocop:enable #{cop_name}\n" + ) + end end end end diff --git a/lib/rubocop/cop/badge.rb b/lib/rubocop/cop/badge.rb index 54c46009f199..be1710879c45 100644 --- a/lib/rubocop/cop/badge.rb +++ b/lib/rubocop/cop/badge.rb @@ -4,16 +4,16 @@ module RuboCop module Cop # Identifier of all cops containing a department and cop name. # - # All cops are identified by their badge. For example, the badge - # for `RuboCop::Cop::Layout::Tab` is `Layout/Tab`. Badges can be - # parsed as either `Department/CopName` or just `CopName` to allow - # for badge references in source files that omit the department - # for RuboCop to infer. + # All cops are identified by their badge. For example, the badge for + # `RuboCop::Cop::Layout::IndentationStyle` is `Layout/IndentationStyle`. + # Badges can be parsed as either `Department/CopName` or just `CopName` to + # allow for badge references in source files that omit the department for + # RuboCop to infer. class Badge # Error raised when a badge parse fails. class InvalidBadge < Error MSG = 'Invalid badge %p. ' \ - 'Expected `Department/CopName` or `CopName`.'.freeze + 'Expected `Department/CopName` or `CopName`.' def initialize(token) super(format(MSG, badge: token)) @@ -58,7 +58,7 @@ def match?(other) end def to_s - qualified? ? "#{department}/#{cop_name}" : cop_name + @to_s ||= qualified? ? "#{department}/#{cop_name}" : cop_name end def qualified? diff --git a/lib/rubocop/cop/base.rb b/lib/rubocop/cop/base.rb new file mode 100644 index 000000000000..888e328421fa --- /dev/null +++ b/lib/rubocop/cop/base.rb @@ -0,0 +1,430 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + # A scaffold for concrete cops. + # + # The Cop::Base class is meant to be extended. + # + # Cops track offenses and can autocorrect them on the fly. + # + # A commissioner object is responsible for traversing the AST and invoking + # the specific callbacks on each cop. + # + # First the callback `on_new_investigation` is called; + # if a cop needs to do its own processing of the AST or depends on + # something else. + # + # Then callbacks like `on_def`, `on_send` (see AST::Traversal) are called + # with their respective nodes. + # + # Finally the callback `on_investigation_end` is called. + # + # Within these callbacks, cops are meant to call `add_offense` or + # `add_global_offense`. Use the `processed_source` method to + # get the currently processed source being investigated. + # + # In case of invalid syntax / unparseable content, + # the callback `on_other_file` is called instead of all the other + # `on_...` callbacks. + # + # Private methods are not meant for custom cops consumption, + # nor are any instance variables. + # + class Base # rubocop:disable Metrics/ClassLength + extend RuboCop::AST::Sexp + extend NodePattern::Macros + include RuboCop::AST::Sexp + include Util + include IgnoredNode + include AutocorrectLogic + + attr_reader :config, :processed_source + + # Reports of an investigation. + # Immutable + # Consider creation API private + InvestigationReport = Struct.new(:cop, :processed_source, :offenses, :corrector) + + # List of methods names to restrict calls for `on_send` / `on_csend` + RESTRICT_ON_SEND = Set[].freeze + + # List of cops that should not try to autocorrect at the same + # time as this cop + # + # @return [Array] + # + # @api public + def self.autocorrect_incompatible_with + [] + end + + # Cops (other than builtin) are encouraged to implement this + # @return [String, nil] + # + # @api public + def self.documentation_url + Documentation.url_for(self) if builtin? + end + + def initialize(config = nil, options = nil) + @config = config || Config.new + @options = options || { debug: false } + reset_investigation + end + + # Called before all on_... have been called + # When refining this method, always call `super` + def on_new_investigation + # Typically do nothing here + end + + # Called after all on_... have been called + # When refining this method, always call `super` + def on_investigation_end + # Typically do nothing here + end + + # Called instead of all on_... callbacks for unrecognized files / syntax errors + # When refining this method, always call `super` + def on_other_file + # Typically do nothing here + end + + # Override and return the Force class(es) you need to join + def self.joining_forces; end + + # Gets called if no message is specified when calling `add_offense` or + # `add_global_offense` + # Cops are discouraged to override this; instead pass your message directly + def message(_range = nil) + self.class::MSG + end + + # Adds an offense that has no particular location. + # No correction can be applied to global offenses + def add_global_offense(message = nil, severity: nil) + severity = find_severity(nil, severity) + message = find_message(nil, message) + @current_offenses << + Offense.new(severity, Offense::NO_LOCATION, message, name, :unsupported) + end + + # Adds an offense on the specified range (or node with an expression) + # Unless that offense is disabled for this range, a corrector will be yielded + # to provide the cop the opportunity to autocorrect the offense. + # If message is not specified, the method `message` will be called. + def add_offense(node_or_range, message: nil, severity: nil, &block) + range = range_from_node_or_range(node_or_range) + return unless current_offense_locations.add?(range) + + range_to_pass = callback_argument(range) + + severity = find_severity(range_to_pass, severity) + message = find_message(range_to_pass, message) + + status, corrector = enabled_line?(range.line) ? correct(range, &block) : :disabled + + @current_offenses << Offense.new(severity, range, message, name, status, corrector) + end + + # This method should be overridden when a cop's behavior depends + # on state that lives outside of these locations: + # + # (1) the file under inspection + # (2) the cop's source code + # (3) the config (eg a .rubocop.yml file) + # + # For example, some cops may want to look at other parts of + # the codebase being inspected to find violations. A cop may + # use the presence or absence of file `foo.rb` to determine + # whether a certain violation exists in `bar.rb`. + # + # Overriding this method allows the cop to indicate to RuboCop's + # ResultCache system when those external dependencies change, + # ie when the ResultCache should be invalidated. + def external_dependency_checksum + nil + end + + def self.inherited(subclass) + super + Registry.global.enlist(subclass) + end + + # Call for abstract Cop classes + def self.exclude_from_registry + Registry.global.dismiss(self) + end + + # Returns if class supports auto_correct. + # It is recommended to extend AutoCorrector instead of overriding + def self.support_autocorrect? + false + end + + ### Naming + + def self.badge + @badge ||= Badge.for(name) + end + + def self.cop_name + badge.to_s + end + + def self.department + badge.department + end + + def self.lint? + department == :Lint + end + + # Returns true if the cop name or the cop namespace matches any of the + # given names. + def self.match?(given_names) + return false unless given_names + + given_names.include?(cop_name) || + given_names.include?(department.to_s) + end + + def cop_name + @cop_name ||= self.class.cop_name + end + + alias name cop_name + + ### Configuration Helpers + + def cop_config + # Use department configuration as basis, but let individual cop + # configuration override. + @cop_config ||= @config.for_badge(self.class.badge) + end + + def config_to_allow_offenses + Formatter::DisabledConfigFormatter + .config_to_allow_offenses[cop_name] ||= {} + end + + def config_to_allow_offenses=(hash) + Formatter::DisabledConfigFormatter.config_to_allow_offenses[cop_name] = + hash + end + + def target_ruby_version + @config.target_ruby_version + end + + def target_rails_version + @config.target_rails_version + end + + def relevant_file?(file) + file == RuboCop::AST::ProcessedSource::STRING_SOURCE_NAME || + file_name_matches_any?(file, 'Include', true) && + !file_name_matches_any?(file, 'Exclude', false) + end + + def excluded_file?(file) + !relevant_file?(file) + end + + ### Persistence + + # Override if your cop should be called repeatedly for multiple investigations + # Between calls to `on_new_investigation` and `on_investigation_end`, + # the result of `processed_source` will remain constant. + # You should invalidate any caches that depend on the current `processed_source` + # in the `on_new_investigation` callback. + # If your cop does autocorrections, be aware that your instance may be called + # multiple times with the same `processed_source.path` but different content. + def self.support_multiple_source? + false + end + + # @api private + # Called between investigations + def ready + return self if self.class.support_multiple_source? + + self.class.new(@config, @options) + end + + ### Reserved for Cop::Cop + + # @deprecated Make potential errors with previous API more obvious + def offenses + raise 'The offenses are not directly available; ' \ + 'they are returned as the result of the investigation' + end + + private + + ### Reserved for Cop::Cop + + def callback_argument(range) + range + end + + def apply_correction(corrector) + @current_corrector&.merge!(corrector) if corrector + end + + def correction_strategy + return :unsupported unless correctable? + return :uncorrected unless autocorrect? + + :attempt_correction + end + + ### Reserved for Commissioner: + + def current_offense_locations + @current_offense_locations ||= Set.new + end + + def currently_disabled_lines + @currently_disabled_lines ||= Set.new + end + + private_class_method def self.restrict_on_send + @restrict_on_send ||= self::RESTRICT_ON_SEND.to_set.freeze + end + + # Called before any investigation + def begin_investigation(processed_source) + @current_offenses = [] + @current_offense_locations = nil + @currently_disabled_lines = nil + @processed_source = processed_source + @current_corrector = Corrector.new(@processed_source) if @processed_source.valid_syntax? + end + + # Called to complete an investigation + def complete_investigation + InvestigationReport.new(self, processed_source, @current_offenses, @current_corrector) + ensure + reset_investigation + end + + ### Actually private methods + + def self.builtin? + return false unless (m = instance_methods(false).first) # any custom method will do + + path, _line = instance_method(m).source_location + path.start_with?(__dir__) + end + private_class_method :builtin? + + def reset_investigation + @currently_disabled_lines = @current_offenses = @processed_source = @current_corrector = nil + end + + # @return [Symbol, Corrector] offense status + def correct(range) + status = correction_strategy + + if block_given? + corrector = Corrector.new(self) + yield corrector + if !corrector.empty? && !self.class.support_autocorrect? + raise "The Cop #{name} must `extend AutoCorrector` to be able to autocorrect" + end + end + + status = attempt_correction(range, corrector) if status == :attempt_correction + + [status, corrector] + end + + # @return [Symbol] offense status + def attempt_correction(range, corrector) + if corrector && !corrector.empty? + status = :corrected + elsif disable_uncorrectable? + corrector = disable_uncorrectable(range) + status = :corrected_with_todo + else + return :uncorrected + end + + apply_correction(corrector) if corrector + status + end + + def disable_uncorrectable(range) + line = range.line + return unless currently_disabled_lines.add?(line) + + disable_offense(range) + end + + def range_from_node_or_range(node_or_range) + if node_or_range.respond_to?(:loc) + node_or_range.loc.expression + elsif node_or_range.is_a?(::Parser::Source::Range) + node_or_range + else + extra = ' (call `add_global_offense`)' if node_or_range.nil? + raise "Expected a Source::Range, got #{node_or_range.inspect}#{extra}" + end + end + + def find_message(range, message) + annotate(message || message(range)) + end + + def annotate(message) + RuboCop::Cop::MessageAnnotator.new( + config, cop_name, cop_config, @options + ).annotate(message) + end + + def file_name_matches_any?(file, parameter, default_result) + patterns = cop_config[parameter] + return default_result unless patterns + + path = nil + patterns.any? do |pattern| + # Try to match the absolute path, as Exclude properties are absolute. + next true if match_path?(pattern, file) + + # Try with relative path. + path ||= config.path_relative_to_config(file) + match_path?(pattern, path) + end + end + + def enabled_line?(line_number) + return true if @options[:ignore_disable_comments] || !@processed_source + + @processed_source.comment_config.cop_enabled_at_line?(self, line_number) + end + + def find_severity(_range, severity) + custom_severity || severity || default_severity + end + + def default_severity + self.class.lint? ? :warning : :convention + end + + def custom_severity + severity = cop_config['Severity'] + return unless severity + + if Severity::NAMES.include?(severity.to_sym) + severity.to_sym + else + message = "Warning: Invalid severity '#{severity}'. " \ + "Valid severities are #{Severity::NAMES.join(', ')}." + warn(Rainbow(message).red) + end + end + end + end +end diff --git a/lib/rubocop/cop/bundler/duplicated_gem.rb b/lib/rubocop/cop/bundler/duplicated_gem.rb index f300fcab25df..cb5c753eaf24 100644 --- a/lib/rubocop/cop/bundler/duplicated_gem.rb +++ b/lib/rubocop/cop/bundler/duplicated_gem.rb @@ -29,7 +29,7 @@ class DuplicatedGem < Cop include RangeHelp MSG = 'Gem `%s` requirements already given on line '\ - '%d of the Gemfile.'.freeze + '%d of the Gemfile.' def investigate(processed_source) return if processed_source.blank? @@ -53,7 +53,11 @@ def duplicated_gem_nodes gem_declarations(processed_source.ast) .group_by(&:first_argument) .values - .select { |nodes| nodes.size > 1 } + .select { |nodes| nodes.size > 1 && !condition?(nodes) } + end + + def condition?(nodes) + nodes[0].parent&.if_type? && nodes[0].parent == nodes[1].parent end def register_offense(node, gem_name, line_of_first_occurrence) diff --git a/lib/rubocop/cop/bundler/gem_comment.rb b/lib/rubocop/cop/bundler/gem_comment.rb index aa7d74686711..5c8074deffb5 100644 --- a/lib/rubocop/cop/bundler/gem_comment.rb +++ b/lib/rubocop/cop/bundler/gem_comment.rb @@ -5,7 +5,25 @@ module Cop module Bundler # Add a comment describing each gem in your Gemfile. # - # @example + # Optionally, the "OnlyFor" configuration + # can be used to only register offenses when the gems + # use certain options or have version specifiers. + # Add "version_specifiers" and/or the gem option names + # you want to check. + # + # A useful use-case is to enforce a comment when using + # options that change the source of a gem: + # + # - `bitbucket` + # - `gist` + # - `git` + # - `github` + # - `source` + # + # For a full list of options supported by bundler, + # you can check the https://bundler.io/man/gemfile.5.html[official documentation]. + # + # @example OnlyFor: [] (default) # # bad # # gem 'foo' @@ -15,23 +33,56 @@ module Bundler # # Helpers for the foo things. # gem 'foo' # + # @example OnlyFor: ['version_specifiers'] + # # bad + # + # gem 'foo', '< 2.1' + # + # # good + # + # # Version 2.1 introduces breaking change baz + # gem 'foo', '< 2.1' + # + # @example OnlyFor: ['version_specifiers', 'github'] + # # bad + # + # gem 'foo', github: 'some_account/some_fork_of_foo' + # + # gem 'bar', '< 2.1' + # + # # good + # + # # Using this fork because baz + # gem 'foo', github: 'some_account/some_fork_of_foo' + # + # # Version 2.1 introduces breaking change baz + # gem 'bar', '< 2.1' + # class GemComment < Cop include DefNode - MSG = 'Missing gem description comment.'.freeze + MSG = 'Missing gem description comment.' + CHECKED_OPTIONS_CONFIG = 'OnlyFor' + VERSION_SPECIFIERS_OPTION = 'version_specifiers' + RESTRICT_ON_SEND = %i[gem].freeze def_node_matcher :gem_declaration?, '(send nil? :gem str ...)' def on_send(node) return unless gem_declaration?(node) - return if whitelisted_gem?(node) - return if commented?(node) + return if ignored_gem?(node) + return if commented_any_descendant?(node) + return if cop_config[CHECKED_OPTIONS_CONFIG].any? && !checked_options_present?(node) add_offense(node) end private + def commented_any_descendant?(node) + commented?(node) || node.each_descendant.any? { |n| commented?(n) } + end + def commented?(node) preceding_lines = preceding_lines(node) preceding_comment?(node, preceding_lines.last) @@ -40,12 +91,12 @@ def commented?(node) # The args node1 & node2 may represent a RuboCop::AST::Node # or a Parser::Source::Comment. Both respond to #loc. def precede?(node1, node2) - node2.loc.line - node1.loc.line == 1 + node2.loc.line - node1.loc.line <= 1 end def preceding_lines(node) processed_source.ast_with_comments[node].select do |line| - line.loc.line < node.loc.line + line.loc.line <= node.loc.line end end @@ -54,9 +105,32 @@ def preceding_comment?(node1, node2) comment_line?(node2.loc.expression.source) end - def whitelisted_gem?(node) - whitelist = Array(cop_config['Whitelist']) - whitelist.include?(node.first_argument.value) + def ignored_gem?(node) + ignored_gems = Array(cop_config['IgnoredGems']) + ignored_gems.include?(node.first_argument.value) + end + + def checked_options_present?(node) + (cop_config[CHECKED_OPTIONS_CONFIG].include?(VERSION_SPECIFIERS_OPTION) && + version_specified_gem?(node)) || + contains_checked_options?(node) + end + + # Besides the gem name, all other *positional* arguments to `gem` are version specifiers, + # as long as it has one we know there's at least one version specifier. + def version_specified_gem?(node) + # arguments[0] is the gem name + node.arguments[1]&.str_type? + end + + def contains_checked_options?(node) + (Array(cop_config[CHECKED_OPTIONS_CONFIG]) & gem_options(node).map(&:to_s)).any? + end + + def gem_options(node) + return [] unless node.arguments.last&.type == :hash + + node.arguments.last.keys.map(&:value) end end end diff --git a/lib/rubocop/cop/bundler/insecure_protocol_source.rb b/lib/rubocop/cop/bundler/insecure_protocol_source.rb index 237cd09f0207..3a8f7712eda9 100644 --- a/lib/rubocop/cop/bundler/insecure_protocol_source.rb +++ b/lib/rubocop/cop/bundler/insecure_protocol_source.rb @@ -13,8 +13,8 @@ module Bundler # # However, it don't replace all `sources` of `http://` with `https://`. # For example, when specifying an internal gem server using HTTP on the - # intranet, a use case where HTTPS can not be specified was considered. - # Consider using HTTP only if you can not use HTTPS. + # intranet, a use case where HTTPS cannot be specified was considered. + # Consider using HTTP only if you cannot use HTTPS. # # @example # # bad @@ -25,44 +25,36 @@ module Bundler # # good # source 'https://rubygems.org' # strongly recommended # source 'http://rubygems.org' - class InsecureProtocolSource < Cop + class InsecureProtocolSource < Base include RangeHelp + extend AutoCorrector MSG = 'The source `:%s` is deprecated because HTTP requests ' \ 'are insecure. ' \ "Please change your source to 'https://rubygems.org' " \ - "if possible, or 'http://rubygems.org' if not.".freeze + "if possible, or 'http://rubygems.org' if not." - def_node_matcher :insecure_protocol_source?, <<-PATTERN + RESTRICT_ON_SEND = %i[source].freeze + + def_node_matcher :insecure_protocol_source?, <<~PATTERN (send nil? :source - (sym ${:gemcutter :rubygems :rubyforge})) + $(sym ${:gemcutter :rubygems :rubyforge})) PATTERN def on_send(node) - insecure_protocol_source?(node) do |source| + insecure_protocol_source?(node) do |source_node, source| message = format(MSG, source: source) add_offense( - node, - location: range(node.first_argument.loc.expression), + source_node, message: message - ) - end - end - - def autocorrect(node) - lambda do |corrector| - corrector.replace( - node.first_argument.loc.expression, "'https://rubygems.org'" - ) + ) do |corrector| + corrector.replace( + source_node, "'https://rubygems.org'" + ) + end end end - - private - - def range(node) - range_between(node.begin_pos, node.end_pos) - end end end end diff --git a/lib/rubocop/cop/bundler/ordered_gems.rb b/lib/rubocop/cop/bundler/ordered_gems.rb index 93d903a57013..c6d40a60e7f9 100644 --- a/lib/rubocop/cop/bundler/ordered_gems.rb +++ b/lib/rubocop/cop/bundler/ordered_gems.rb @@ -30,7 +30,7 @@ class OrderedGems < Cop MSG = 'Gems should be sorted in an alphabetical order within their '\ 'section of the Gemfile. '\ - 'Gem `%s` should appear before `%s`.'.freeze + 'Gem `%s` should appear before `%s`.' def investigate(processed_source) return if processed_source.blank? @@ -64,7 +64,7 @@ def previous_declaration(node) declarations.to_a[node_index - 1] end - def_node_search :gem_declarations, <<-PATTERN + def_node_search :gem_declarations, <<~PATTERN (:send nil? :gem str ...) PATTERN end diff --git a/lib/rubocop/cop/commissioner.rb b/lib/rubocop/cop/commissioner.rb index 014aea6bac79..d6c6a3dfc650 100644 --- a/lib/rubocop/cop/commissioner.rb +++ b/lib/rubocop/cop/commissioner.rb @@ -7,7 +7,37 @@ module Cop class Commissioner include RuboCop::AST::Traversal - CopError = Struct.new(:error, :line, :column) + RESTRICTED_CALLBACKS = %i[on_send on_csend].freeze + private_constant :RESTRICTED_CALLBACKS + + # How a Commissioner returns the results of the investigation + # as a list of Cop::InvestigationReport and any errors caught + # during the investigation. + # Immutable + # Consider creation API private + InvestigationReport = Struct.new(:processed_source, :cop_reports, :errors) do + def cops + @cops ||= cop_reports.map(&:cop) + end + + def offenses_per_cop + @offenses_per_cop ||= cop_reports.map(&:offenses) + end + + def correctors + @correctors ||= cop_reports.map(&:corrector) + end + + def offenses + @offenses ||= offenses_per_cop.flatten(1) + end + + def merge(investigation) + InvestigationReport.new(processed_source, + cop_reports + investigation.cop_reports, + errors + investigation.errors) + end + end attr_reader :errors @@ -15,9 +45,10 @@ def initialize(cops, forces = [], options = {}) @cops = cops @forces = forces @options = options - @callbacks = {} + @callbacks = Hash.new { |h, k| h[k] = cops_callbacks_for(k) } + @restricted_map = {} - reset_errors + reset end # Create methods like :on_send, :on_super, etc. They will be called @@ -30,29 +61,39 @@ def initialize(cops, forces = [], options = {}) method_name = :"on_#{node_type}" next unless method_defined?(method_name) - define_method(method_name) do |node| - trigger_responding_cops(method_name, node) - super(node) unless NO_CHILD_NODES.include?(node_type) + if RESTRICTED_CALLBACKS.include?(method_name) + trigger_restricted = "trigger_restricted_cops(:on_#{node_type}, node)" end + + class_eval(<<~RUBY, __FILE__, __LINE__ + 1) + def on_#{node_type}(node) + trigger_responding_cops(:on_#{node_type}, node) + #{trigger_restricted} + #{'super(node)' unless NO_CHILD_NODES.include?(node_type)} + end + RUBY end + # @return [InvestigationReport] def investigate(processed_source) - reset_errors - remove_irrelevant_cops(processed_source.file_path) - reset_callbacks - prepare(processed_source) - invoke_custom_processing(@cops, processed_source) - invoke_custom_processing(@forces, processed_source) - walk(processed_source.ast) unless processed_source.blank? - @cops.flat_map(&:offenses) + reset + + @cops.each { |cop| cop.send :begin_investigation, processed_source } + if processed_source.valid_syntax? + invoke(:on_new_investigation, @cops) + invoke(:investigate, @forces, processed_source) + walk(processed_source.ast) unless @cops.empty? + invoke(:on_investigation_end, @cops) + else + invoke(:on_other_file, @cops) + end + reports = @cops.map { |cop| cop.send(:complete_investigation) } + InvestigationReport.new(processed_source, reports, @errors) end private def trigger_responding_cops(callback, node) - @callbacks[callback] ||= @cops.select do |cop| - cop.respond_to?(callback) - end @callbacks[callback].each do |cop| with_cop_error_handling(cop, node) do cop.send(callback, node) @@ -60,41 +101,46 @@ def trigger_responding_cops(callback, node) end end - def reset_errors - @errors = Hash.new { |hash, k| hash[k] = [] } + def reset + @errors = [] end - def remove_irrelevant_cops(filename) - @cops.reject! { |cop| cop.excluded_file?(filename) } - @cops.reject! do |cop| - cop.class.respond_to?(:support_target_ruby_version?) && - !cop.class.support_target_ruby_version?(cop.target_ruby_version) + def cops_callbacks_for(callback) + callbacks = @cops.select do |cop| + cop.respond_to?(callback) end - @cops.reject! do |cop| - cop.class.respond_to?(:support_target_rails_version?) && - !cop.class.support_target_rails_version?(cop.target_rails_version) + if RESTRICTED_CALLBACKS.include?(callback) + @restricted_map[callback] = restricted_map(callbacks) end + callbacks end - def reset_callbacks - @callbacks.clear + def trigger_restricted_cops(event, node) + name = node.method_name + @restricted_map.fetch(event)[name]&.each do |cop| + with_cop_error_handling(cop, node) do + cop.send(event, node) + end + end end - # TODO: Bad design. - def prepare(processed_source) - @cops.each { |cop| cop.processed_source = processed_source } + # Note: mutates `callbacks` in place + def restricted_map(callbacks) + map = {} + callbacks.select! do |cop| + restrictions = cop.class.send :restrict_on_send + restrictions.each do |name| + (map[name] ||= []) << cop + end + restrictions.empty? + end + map end - # There are cops/forces that require their own custom processing. - # If they define the #investigate method, all input parameters passed - # to the commissioner will be passed to the cop too in order to do - # its own processing. - def invoke_custom_processing(cops_or_forces, processed_source) - cops_or_forces.each do |cop| - next unless cop.respond_to?(:investigate) - + def invoke(callback, cops, *args) + cops.each do |cop| with_cop_error_handling(cop) do - cop.investigate(processed_source) + cop.send(callback, *args) end end end @@ -107,12 +153,8 @@ def with_cop_error_handling(cop, node = nil) rescue StandardError => e raise e if @options[:raise_error] - if node - line = node.first_line - column = node.loc.column - end - error = CopError.new(e, line, column) - @errors[cop] << error + err = ErrorWithAnalyzedFileLocation.new(cause: e, node: node, cop: cop) + @errors << err end end end diff --git a/lib/rubocop/cop/cop.rb b/lib/rubocop/cop/cop.rb index 1c412424e467..ac1ee8c0aec4 100644 --- a/lib/rubocop/cop/cop.rb +++ b/lib/rubocop/cop/cop.rb @@ -1,243 +1,159 @@ # frozen_string_literal: true require 'uri' +require_relative 'legacy/corrections_proxy' module RuboCop module Cop - # A scaffold for concrete cops. - # - # The Cop class is meant to be extended. - # - # Cops track offenses and can autocorrect them on the fly. - # - # A commissioner object is responsible for traversing the AST and invoking - # the specific callbacks on each cop. - # If a cop needs to do its own processing of the AST or depends on - # something else, it should define the `#investigate` method and do - # the processing there. - # - # @example - # - # class CustomCop < Cop - # def investigate(processed_source) - # # Do custom processing - # end - # end - class Cop - extend RuboCop::AST::Sexp - extend NodePattern::Macros - include RuboCop::AST::Sexp - include Util - include IgnoredNode - include AutocorrectLogic - - attr_reader :config, :offenses, :corrections - attr_accessor :processed_source # TODO: Bad design. - - @registry = Registry.new - - class << self - attr_reader :registry - end - - def self.all - registry.without_department(:Test).cops - end - - def self.qualified_cop_name(name, origin) - registry.qualified_cop_name(name, origin) - end - - def self.non_rails - registry.without_department(:Rails) - end - - def self.inherited(subclass) - registry.enlist(subclass) - end - - def self.badge - @badge ||= Badge.for(name) - end - - def self.cop_name - badge.to_s - end - - def self.department - badge.department - end - - def self.lint? - department == :Lint + # @deprecated Use Cop::Base instead + # Legacy scaffold for Cops. + # See https://docs.rubocop.org/rubocop/cop_api_v1_changelog.html + class Cop < Base + attr_reader :offenses + + exclude_from_registry + + # @deprecated + Correction = Struct.new(:lambda, :node, :cop) do + def call(corrector) + lambda.call(corrector) + rescue StandardError => e + raise ErrorWithAnalyzedFileLocation.new( + cause: e, node: node, cop: cop + ) + end end - # Returns true if the cop name or the cop namespace matches any of the - # given names. - def self.match?(given_names) - return false unless given_names - - given_names.include?(cop_name) || - given_names.include?(department.to_s) + def add_offense(node_or_range, location: :expression, message: nil, severity: nil, &block) + @v0_argument = node_or_range + range = find_location(node_or_range, location) + if block.nil? && !autocorrect? + super(range, message: message, severity: severity) + else + super(range, message: message, severity: severity) do |corrector| + emulate_v0_callsequence(corrector, &block) + end + end end - # List of cops that should not try to autocorrect at the same - # time as this cop - # - # @return [Array] - # - # @api public - def self.autocorrect_incompatible_with - [] + def find_location(node, loc) + # Location can be provided as a symbol, e.g.: `:keyword` + loc.is_a?(Symbol) ? node.loc.public_send(loc) : loc end - def initialize(config = nil, options = nil) - @config = config || Config.new - @options = options || { debug: false } - - @offenses = [] - @corrections = [] - @corrected_nodes = {} - @corrected_nodes.compare_by_identity - @processed_source = nil + # @deprecated Use class method + def support_autocorrect? + # warn 'deprecated, use cop.class.support_autocorrect?' TODO + self.class.support_autocorrect? end - def join_force?(_force_class) - false + def self.support_autocorrect? + method_defined?(:autocorrect) end - def cop_config - # Use department configuration as basis, but let individual cop - # configuration override. - @cop_config ||= @config.for_cop(self.class.department.to_s) - .merge(@config.for_cop(self)) - end + def self.joining_forces + return unless method_defined?(:join_force?) - def message(_node = nil) - self.class::MSG + cop = new + Force.all.select do |force_class| + cop.join_force?(force_class) + end end - # rubocop:disable Metrics/CyclomaticComplexity - def add_offense(node, location: :expression, message: nil, severity: nil) - loc = find_location(node, location) - - return if duplicate_location?(loc) - - severity = custom_severity || severity || default_severity - - message ||= message(node) - message = annotate(message) - - status = enabled_line?(loc.line) ? correct(node) : :disabled - - @offenses << Offense.new(severity, loc, message, name, status) - yield if block_given? && status != :disabled - end - # rubocop:enable Metrics/CyclomaticComplexity + # @deprecated + def corrections + # warn 'Cop#corrections is deprecated' TODO + return [] unless @last_corrector - def find_location(node, loc) - # Location can be provided as a symbol, e.g.: `:keyword` - loc.is_a?(Symbol) ? node.loc.public_send(loc) : loc + Legacy::CorrectionsProxy.new(@last_corrector) end - def duplicate_location?(location) - @offenses.any? { |o| o.location == location } + # Called before all on_... have been called + def on_new_investigation + investigate(processed_source) if respond_to?(:investigate) + super end - def correct(node) - return :unsupported unless support_autocorrect? - return :uncorrected unless autocorrect? - return :already_corrected if @corrected_nodes.key?(node) - - @corrected_nodes[node] = true - correction = autocorrect(node) - return :uncorrected unless correction - - @corrections << correction - :corrected + # Called after all on_... have been called + def on_investigation_end + investigate_post_walk(processed_source) if respond_to?(:investigate_post_walk) + super end - def config_to_allow_offenses - Formatter::DisabledConfigFormatter - .config_to_allow_offenses[cop_name] ||= {} - end + ### Deprecated registry access - def config_to_allow_offenses=(hash) - Formatter::DisabledConfigFormatter.config_to_allow_offenses[cop_name] = - hash + # @deprecated Use Registry.global + def self.registry + Registry.global end - def target_ruby_version - @config.target_ruby_version + # @deprecated Use Registry.all + def self.all + Registry.all end - def target_rails_version - @config.target_rails_version + # @deprecated Use Registry.qualified_cop_name + def self.qualified_cop_name(name, origin) + Registry.qualified_cop_name(name, origin) end + # @deprecated + # Open issue if there's a valid use case to include this in Base def parse(source, path = nil) ProcessedSource.new(source, target_ruby_version, path) end - def cop_name - @cop_name ||= self.class.cop_name - end - - alias name cop_name + private - def relevant_file?(file) - file_name_matches_any?(file, 'Include', true) && - !file_name_matches_any?(file, 'Exclude', false) + def begin_investigation(processed_source) + super + @offenses = @current_offenses + @last_corrector = @current_corrector end - def excluded_file?(file) - !relevant_file?(file) + # Override Base + def callback_argument(_range) + @v0_argument end - private - - def annotate(message) - RuboCop::Cop::MessageAnnotator.new( - config, cop_config, @options - ).annotate(message, name) + def apply_correction(corrector) + suppress_clobbering { super } end - def file_name_matches_any?(file, parameter, default_result) - patterns = cop_config[parameter] - return default_result unless patterns + # Just for legacy + def emulate_v0_callsequence(corrector) + lambda = correction_lambda + yield corrector if block_given? + unless corrector.empty? + raise 'Your cop must inherit from Cop::Base and extend AutoCorrector' + end - path = nil - patterns.any? do |pattern| - # Try to match the absolute path, as Exclude properties are absolute. - next true if match_path?(pattern, file) + return unless lambda - # Try with relative path. - path ||= config.path_relative_to_config(file) - match_path?(pattern, path) + suppress_clobbering do + lambda.call(corrector) end end - def enabled_line?(line_number) - return true if @options[:ignore_disable_comments] || !@processed_source + def correction_lambda + return unless correction_strategy == :attempt_correction && support_autocorrect? - @processed_source.comment_config.cop_enabled_at_line?(self, line_number) + dedup_on_node(@v0_argument) do + autocorrect(@v0_argument) + end end - def default_severity - self.class.lint? ? :warning : :convention + def dedup_on_node(node) + @corrected_nodes ||= {}.compare_by_identity + yield unless @corrected_nodes.key?(node) + ensure + @corrected_nodes[node] = true end - def custom_severity - severity = cop_config['Severity'] - return unless severity - - if Severity::NAMES.include?(severity.to_sym) - severity.to_sym - else - message = "Warning: Invalid severity '#{severity}'. " \ - "Valid severities are #{Severity::NAMES.join(', ')}." - warn(Rainbow(message).red) - end + def suppress_clobbering + yield + rescue ::Parser::ClobberingError + # ignore Clobbering errors end end end diff --git a/lib/rubocop/cop/corrector.rb b/lib/rubocop/cop/corrector.rb index d0cae9284261..a8ca6a9b2e0c 100644 --- a/lib/rubocop/cop/corrector.rb +++ b/lib/rubocop/cop/corrector.rb @@ -8,163 +8,110 @@ module Cop # Important! # The nodes modified by the corrections should be part of the # AST of the source_buffer. - class Corrector + class Corrector < ::Parser::Source::TreeRewriter + # @param source [Parser::Source::Buffer, or anything + # leading to one via `(processed_source.)buffer`] # - # @param source_buffer [Parser::Source::Buffer] - # @param corrections [Array(#call)] - # Array of Objects that respond to #call. They will receive the - # corrector itself and should use its method to modify the source. - # - # @example - # - # class AndOrCorrector - # def initialize(node) - # @node = node - # end - # - # def call(corrector) - # replacement = (@node.type == :and ? '&&' : '||') - # corrector.replace(@node.loc.operator, replacement) - # end - # end - # - # corrections = [AndOrCorrector.new(node)] - # corrector = Corrector.new(source_buffer, corrections) - def initialize(source_buffer, corrections = []) - @source_buffer = source_buffer - raise 'source_buffer should be a Parser::Source::Buffer' unless \ - source_buffer.is_a? Parser::Source::Buffer - - @corrections = corrections - @source_rewriter = Parser::Source::TreeRewriter.new( - source_buffer, + # corrector = Corrector.new(cop) + def initialize(source) + source = self.class.source_buffer(source) + super( + source, different_replacements: :raise, swallowed_insertions: :raise, crossing_deletions: :accept ) - @diagnostics = [] # Don't print warnings to stderr if corrections conflict with each other - @source_rewriter.diagnostics.consumer = lambda do |diagnostic| - @diagnostics << diagnostic - end - end - - attr_reader :corrections, :diagnostics - - # Does the actual rewrite and returns string corresponding to - # the rewritten source. - # - # @return [String] - def rewrite - # rubocop:disable Lint/HandleExceptions - @corrections.each do |correction| - begin - @source_rewriter.transaction do - correction.call(self) - end - rescue ::Parser::ClobberingError - end - end - # rubocop:enable Lint/HandleExceptions - - @source_rewriter.process + diagnostics.consumer = ->(diagnostic) {} end - # Removes the source range. - # - # @param [Parser::Source::Range] range - def remove(range) - validate_range range - @source_rewriter.remove(range) - end - - # Inserts new code before the given source range. - # - # @param [Parser::Source::Range] range - # @param [String] content - def insert_before(range, content) - validate_range range - # TODO: Fix Cops using bad ranges instead - if range.end_pos > @source_buffer.source.size - range = range.with(end_pos: @source_buffer.source.size) - end - - @source_rewriter.insert_before(range, content) - end - - # Inserts new code after the given source range. - # - # @param [Parser::Source::Range] range - # @param [String] content - def insert_after(range, content) - validate_range range - @source_rewriter.insert_after(range, content) - end - - # Replaces the code of the source range `range` with `content`. - # - # @param [Parser::Source::Range] range - # @param [String] content - def replace(range, content) - validate_range range - @source_rewriter.replace(range, content) - end + alias rewrite process # Legacy # Removes `size` characters prior to the source range. # - # @param [Parser::Source::Range] range + # @param [Parser::Source::Range, Rubocop::AST::Node] range or node # @param [Integer] size - def remove_preceding(range, size) - validate_range range - to_remove = Parser::Source::Range.new(range.source_buffer, - range.begin_pos - size, - range.begin_pos) - @source_rewriter.remove(to_remove) + def remove_preceding(node_or_range, size) + range = to_range(node_or_range) + to_remove = range.with( + begin_pos: range.begin_pos - size, + end_pos: range.begin_pos + ) + remove(to_remove) end # Removes `size` characters from the beginning of the given range. # If `size` is greater than the size of `range`, the removed region can # overrun the end of `range`. # - # @param [Parser::Source::Range] range + # @param [Parser::Source::Range, Rubocop::AST::Node] range or node # @param [Integer] size - def remove_leading(range, size) - validate_range range - to_remove = Parser::Source::Range.new(range.source_buffer, - range.begin_pos, - range.begin_pos + size) - @source_rewriter.remove(to_remove) + def remove_leading(node_or_range, size) + range = to_range(node_or_range) + to_remove = range.with(end_pos: range.begin_pos + size) + remove(to_remove) end # Removes `size` characters from the end of the given range. # If `size` is greater than the size of `range`, the removed region can # overrun the beginning of `range`. # - # @param [Parser::Source::Range] range + # @param [Parser::Source::Range, Rubocop::AST::Node] range or node # @param [Integer] size - def remove_trailing(range, size) - validate_range range - to_remove = Parser::Source::Range.new(range.source_buffer, - range.end_pos - size, - range.end_pos) - @source_rewriter.remove(to_remove) + def remove_trailing(node_or_range, size) + range = to_range(node_or_range) + to_remove = range.with(begin_pos: range.end_pos - size) + remove(to_remove) + end + + # Duck typing for get to a ::Parser::Source::Buffer + def self.source_buffer(source) + source = source.processed_source if source.respond_to?(:processed_source) + source = source.buffer if source.respond_to?(:buffer) + source = source.source_buffer if source.respond_to?(:source_buffer) + + unless source.is_a? ::Parser::Source::Buffer + raise TypeError, 'Expected argument to lead to a Parser::Source::Buffer ' \ + "but got #{source.inspect}" + end + + source end private # :nodoc: - def validate_range(range) - return if range.source_buffer == @source_buffer + def to_range(node_or_range) + range = case node_or_range + when ::RuboCop::AST::Node, ::Parser::Source::Comment + node_or_range.loc.expression + when ::Parser::Source::Range + node_or_range + else + raise TypeError, + 'Expected a Parser::Source::Range, Comment or ' \ + "Rubocop::AST::Node, got #{node_or_range.class}" + end + validate_buffer(range.source_buffer) + range + end + + def check_range_validity(node_or_range) + super(to_range(node_or_range)) + end + + def validate_buffer(buffer) + return if buffer == source_buffer - unless range.source_buffer.is_a?(Parser::Source::Buffer) + unless buffer.is_a?(::Parser::Source::Buffer) # actually this should be enforced by parser gem - raise 'Corrector expected range source buffer to be a '\ - "Parser::Source::Buffer, but got #{range.source_buffer.class}" + raise 'Corrector expected range source buffer to be a ' \ + "Parser::Source::Buffer, but got #{buffer.class}" end - raise "Correction target buffer #{range.source_buffer.object_id} "\ - "name:#{range.source_buffer.name.inspect}"\ - " is not current #{@source_buffer.object_id} "\ + raise "Correction target buffer #{buffer.object_id} " \ + "name:#{buffer.name.inspect}" \ + " is not current #{@source_buffer.object_id} " \ "name:#{@source_buffer.name.inspect} under investigation" end end diff --git a/lib/rubocop/cop/correctors/alignment_corrector.rb b/lib/rubocop/cop/correctors/alignment_corrector.rb index 6c90b6074410..397338e3c1b6 100644 --- a/lib/rubocop/cop/correctors/alignment_corrector.rb +++ b/lib/rubocop/cop/correctors/alignment_corrector.rb @@ -19,47 +19,68 @@ def correct(processed_source, node, column_delta) expr = node.respond_to?(:loc) ? node.loc.expression : node return if block_comment_within?(expr) + taboo_ranges = inside_string_ranges(node) + lambda do |corrector| each_line(expr) do |line_begin_pos| autocorrect_line(corrector, line_begin_pos, expr, column_delta, - heredoc_ranges(node)) + taboo_ranges) end end end - def align_end(processed_source, node, align_to) + def align_end(corrector, processed_source, node, align_to) @processed_source = processed_source whitespace = whitespace_range(node) return false unless whitespace.source.strip.empty? column = alignment_column(align_to) - ->(corrector) { corrector.replace(whitespace, ' ' * column) } + corrector.replace(whitespace, ' ' * column) end private def autocorrect_line(corrector, line_begin_pos, expr, column_delta, - heredoc_ranges) + taboo_ranges) range = calculate_range(expr, line_begin_pos, column_delta) - # We must not change indentation of heredoc strings. - return if heredoc_ranges.any? { |h| within?(range, h) } + # We must not change indentation of heredoc strings or inside other + # string literals + return if taboo_ranges.any? { |t| within?(range, t) } - if column_delta > 0 - unless range.source == "\n" - # TODO: Fix ranges instead of using `begin` - corrector.insert_before(range.begin, ' ' * column_delta) - end - elsif range.source =~ /\A[ \t]+\z/ + if column_delta.positive? && range.resize(1).source != "\n" + corrector.insert_before(range, ' ' * column_delta) + elsif /\A[ \t]+\z/.match?(range.source) remove(range, corrector) end end - def heredoc_ranges(node) + def inside_string_ranges(node) return [] unless node.is_a?(Parser::AST::Node) - node.each_node(:dstr) - .select(&:heredoc?) - .map { |n| n.loc.heredoc_body.join(n.loc.heredoc_end) } + node.each_node(:str, :dstr, :xstr).map { |n| inside_string_range(n) } + .compact + end + + def inside_string_range(node) + loc = node.location + + if node.heredoc? + loc.heredoc_body.join(loc.heredoc_end) + elsif delimited_string_literal?(node) + loc.begin.end.join(loc.end.begin) + end + end + + # Some special kinds of string literals are not composed of literal + # characters between two delimiters: + # - The source map of `?a` responds to :begin and :end but its end is + # nil. + # - The source map of `__FILE__` responds to neither :begin nor :end. + def delimited_string_literal?(node) + loc = node.location + + loc.respond_to?(:begin) && loc.begin && + loc.respond_to?(:end) && loc.end end def block_comment_within?(expr) @@ -69,15 +90,16 @@ def block_comment_within?(expr) end def calculate_range(expr, line_begin_pos, column_delta) + return range_between(line_begin_pos, line_begin_pos) if column_delta.positive? + starts_with_space = expr.source_buffer.source[line_begin_pos].start_with?(' ') - pos_to_remove = if column_delta > 0 || starts_with_space - line_begin_pos - else - line_begin_pos - column_delta.abs - end - range_between(pos_to_remove, pos_to_remove + column_delta.abs) + if starts_with_space + range_between(line_begin_pos, line_begin_pos + column_delta.abs) + else + range_between(line_begin_pos - column_delta.abs, line_begin_pos) + end end def remove(range, corrector) @@ -86,7 +108,7 @@ def remove(range, corrector) corrector.remove(range) rescue RuntimeError range = range_between(range.begin_pos + 1, range.end_pos + 1) - retry if range.source =~ /^ +$/ + retry if /^ +$/.match?(range.source) ensure $stderr = original_stderr end diff --git a/lib/rubocop/cop/correctors/condition_corrector.rb b/lib/rubocop/cop/correctors/condition_corrector.rb index 7b35969e3d45..7de6c60f4d17 100644 --- a/lib/rubocop/cop/correctors/condition_corrector.rb +++ b/lib/rubocop/cop/correctors/condition_corrector.rb @@ -5,14 +5,11 @@ module Cop # This class does condition auto-correction class ConditionCorrector class << self - def correct_negative_condition(node) + def correct_negative_condition(corrector, node) condition = negated_condition(node) - lambda do |corrector| - corrector.replace(node.loc.keyword, node.inverse_keyword) - corrector.replace(condition.source_range, - condition.children.first.source) - end + corrector.replace(node.loc.keyword, node.inverse_keyword) + corrector.replace(condition, condition.children.first.source) end private diff --git a/lib/rubocop/cop/correctors/each_to_for_corrector.rb b/lib/rubocop/cop/correctors/each_to_for_corrector.rb index b9780acbc4b5..ce83c4d4cde5 100644 --- a/lib/rubocop/cop/correctors/each_to_for_corrector.rb +++ b/lib/rubocop/cop/correctors/each_to_for_corrector.rb @@ -7,8 +7,8 @@ class EachToForCorrector extend NodePattern::Macros CORRECTION_WITH_ARGUMENTS = - 'for %s in %s do'.freeze - CORRECTION_WITHOUT_ARGUMENTS = 'for _ in %s do'.freeze + 'for %s in %s do' + CORRECTION_WITHOUT_ARGUMENTS = 'for _ in %s do' def initialize(block_node) @block_node = block_node diff --git a/lib/rubocop/cop/correctors/empty_line_corrector.rb b/lib/rubocop/cop/correctors/empty_line_corrector.rb index 2ef842f30c39..ab68bdea247f 100644 --- a/lib/rubocop/cop/correctors/empty_line_corrector.rb +++ b/lib/rubocop/cop/correctors/empty_line_corrector.rb @@ -5,20 +5,19 @@ module Cop # This class does empty line auto-correction class EmptyLineCorrector class << self - def correct(node) + def correct(corrector, node) offense_style, range = node - lambda do |corrector| - case offense_style - when :no_empty_lines then - corrector.remove(range) - when :empty_lines then - corrector.insert_before(range, "\n") - end + + case offense_style + when :no_empty_lines + corrector.remove(range) + when :empty_lines + corrector.insert_before(range, "\n") end end - def insert_before(node) - ->(corrector) { corrector.insert_before(node.source_range, "\n") } + def insert_before(corrector, node) + corrector.insert_before(node, "\n") end end end diff --git a/lib/rubocop/cop/correctors/for_to_each_corrector.rb b/lib/rubocop/cop/correctors/for_to_each_corrector.rb index 64709daca5b7..5e54fc25685e 100644 --- a/lib/rubocop/cop/correctors/for_to_each_corrector.rb +++ b/lib/rubocop/cop/correctors/for_to_each_corrector.rb @@ -6,7 +6,7 @@ module Cop class ForToEachCorrector extend NodePattern::Macros - CORRECTION = '%s.each do |%s|'.freeze + CORRECTION = '%s.each do |%s|' def initialize(for_node) @for_node = for_node diff --git a/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb b/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb index ba9fa51b47b6..70c8432376b7 100644 --- a/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +++ b/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb @@ -44,13 +44,13 @@ def insert_separating_space(corrector) end def replace_selector(corrector) - corrector.replace(method.source_range, 'lambda') + corrector.replace(method, 'lambda') end def remove_arguments(corrector) return if arguments.empty_and_without_delimiters? - corrector.remove(arguments.source_range) + corrector.remove(arguments) end def insert_arguments(corrector) @@ -62,7 +62,7 @@ def insert_arguments(corrector) def remove_leading_whitespace(corrector) corrector.remove_preceding( - arguments.source_range, + arguments, arguments.source_range.begin_pos - block_node.send_node.source_range.end_pos ) @@ -70,7 +70,7 @@ def remove_leading_whitespace(corrector) def remove_trailing_whitespace(corrector) size = block_begin.begin_pos - arguments.source_range.end_pos - 1 - corrector.remove_preceding(block_begin, size) if size > 0 + corrector.remove_preceding(block_begin, size) if size.positive? end def replace_delimiters(corrector) @@ -93,11 +93,11 @@ def needs_separating_space? end def arguments_end_pos - arguments.loc.end && arguments.loc.end.end_pos + arguments.loc.end&.end_pos end def arguments_begin_pos - arguments.loc.begin && arguments.loc.begin.begin_pos + arguments.loc.begin&.begin_pos end def block_end @@ -117,19 +117,19 @@ def arg_to_unparenthesized_call? parent = current_node.parent - if parent && parent.pair_type? + if parent&.pair_type? current_node = parent.parent parent = current_node.parent end - return false unless parent && parent.send_type? + return false unless parent&.send_type? return false if parent.parenthesized_call? current_node.sibling_index > 1 end def separating_space? - block_begin.source_buffer.source[block_begin.begin_pos + 2].match(/\s/) + block_begin.source_buffer.source[block_begin.begin_pos + 2].match?(/\s/) end end end diff --git a/lib/rubocop/cop/correctors/line_break_corrector.rb b/lib/rubocop/cop/correctors/line_break_corrector.rb index d0dfb1179f6b..8911cf7f0d63 100644 --- a/lib/rubocop/cop/correctors/line_break_corrector.rb +++ b/lib/rubocop/cop/correctors/line_break_corrector.rb @@ -16,7 +16,7 @@ def correct_trailing_body(configured_width:, corrector:, node:, processed_source:) @processed_source = processed_source range = first_part_of(node.to_a.last) - eol_comment = end_of_line_comment(node.source_range.line) + eol_comment = processed_source.comment_at_line(node.source_range.line) break_line_before(range: range, node: node, corrector: corrector, configured_width: configured_width) @@ -25,12 +25,12 @@ def correct_trailing_body(configured_width:, corrector:, node:, remove_semicolon(node, corrector) end - def break_line_before(range:, node:, corrector:, indent_steps: 1, - configured_width:) + def break_line_before(range:, node:, corrector:, configured_width:, + indent_steps: 1) corrector.insert_before( range, - "\n" + ' ' * (node.loc.keyword.column + - indent_steps * configured_width) + "\n#{' ' * (node.loc.keyword.column + + indent_steps * configured_width)}" ) end @@ -38,9 +38,9 @@ def move_comment(eol_comment:, node:, corrector:) return unless eol_comment text = eol_comment.loc.expression.source - corrector.insert_before(node.source_range, - text + "\n" + (' ' * node.loc.keyword.column)) - corrector.remove(eol_comment.loc.expression) + corrector.insert_before(node, + "#{text}\n#{' ' * node.loc.keyword.column}") + corrector.remove(eol_comment) end private @@ -52,8 +52,8 @@ def remove_semicolon(node, corrector) end def semicolon(node) - @semicolon ||= {} - @semicolon[node.object_id] ||= tokens(node).find(&:semicolon?) + @semicolon ||= {}.compare_by_identity + @semicolon[node] ||= processed_source.tokens_within(node).find(&:semicolon?) end end end diff --git a/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb b/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb index e0dc789a253b..50830f1839e1 100644 --- a/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +++ b/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb @@ -8,12 +8,17 @@ class MultilineLiteralBraceCorrector include MultilineLiteralBraceLayout include RangeHelp - def initialize(node, processed_source) + def self.correct(corrector, node, processed_source) + new(corrector, node, processed_source).call + end + + def initialize(corrector, node, processed_source) + @corrector = corrector @node = node @processed_source = processed_source end - def call(corrector) + def call if closing_brace_on_same_line?(node) correct_same_line_brace(corrector) else @@ -29,10 +34,10 @@ def call(corrector) private - attr_reader :node, :processed_source + attr_reader :corrector, :node, :processed_source def correct_same_line_brace(corrector) - corrector.insert_before(node.loc.end, "\n".freeze) + corrector.insert_before(node.loc.end, "\n") end def correct_next_line_brace(corrector) @@ -40,10 +45,36 @@ def correct_next_line_brace(corrector) range_with_surrounding_space(range: node.loc.end, side: :left) ) - corrector.insert_after( - last_element_range_with_trailing_comma(node), + corrector.insert_before( + last_element_range_with_trailing_comma(node).end, + content_if_comment_present(corrector, node) + ) + end + + def content_if_comment_present(corrector, node) + range = range_with_surrounding_space( + range: children(node).last.source_range, + side: :right + ).end.resize(1) + if range.source == '#' + select_content_to_be_inserted_after_last_element(corrector, node) + else node.loc.end.source + end + end + + def select_content_to_be_inserted_after_last_element(corrector, node) + range = range_between( + node.loc.end.begin_pos, + range_by_whole_lines(node.loc.expression).end.end_pos ) + + remove_trailing_content_of_comment(corrector, range) + range.source + end + + def remove_trailing_content_of_comment(corrector, range) + corrector.remove(range) end def last_element_range_with_trailing_comma(node) diff --git a/lib/rubocop/cop/correctors/parentheses_corrector.rb b/lib/rubocop/cop/correctors/parentheses_corrector.rb index 8f613829ca17..e49e7fc6496c 100644 --- a/lib/rubocop/cop/correctors/parentheses_corrector.rb +++ b/lib/rubocop/cop/correctors/parentheses_corrector.rb @@ -5,21 +5,18 @@ module Cop # This auto-corrects parentheses class ParenthesesCorrector class << self - def correct(node) - lambda do |corrector| - corrector.remove(node.loc.begin) - corrector.remove(node.loc.end) + def correct(corrector, node) + corrector.remove(node.loc.begin) + corrector.remove(node.loc.end) + return unless ternary_condition?(node) && next_char_is_question_mark?(node) - if ternary_condition?(node) && next_char_is_question_mark?(node) - corrector.insert_after(node.loc.end, ' ') - end - end + corrector.insert_after(node.loc.end, ' ') end private def ternary_condition?(node) - node.parent && node.parent.if_type? && node.parent.ternary? + node.parent&.if_type? && node.parent&.ternary? end def next_char_is_question_mark?(node) diff --git a/lib/rubocop/cop/correctors/percent_literal_corrector.rb b/lib/rubocop/cop/correctors/percent_literal_corrector.rb index eb62ea894ae7..433977454fb0 100644 --- a/lib/rubocop/cop/correctors/percent_literal_corrector.rb +++ b/lib/rubocop/cop/correctors/percent_literal_corrector.rb @@ -13,23 +13,18 @@ def initialize(config, preferred_delimiters) @preferred_delimiters = preferred_delimiters end - def correct(node, char) + def correct(corrector, node, char) escape = escape_words?(node) char = char.upcase if escape delimiters = delimiters_for("%#{char}") contents = new_contents(node, escape, delimiters) - wrap_contents(node, contents, char, delimiters) + wrap_contents(corrector, node, contents, char, delimiters) end private - def wrap_contents(node, contents, char, delimiters) - lambda do |corrector| - corrector.replace( - node.source_range, - "%#{char}#{delimiters[0]}#{contents}#{delimiters[1]}" - ) - end + def wrap_contents(corrector, node, contents, char, delimiters) + corrector.replace(node, "%#{char}#{delimiters[0]}#{contents}#{delimiters[1]}") end def escape_words?(node) @@ -71,7 +66,7 @@ def process_multiline_words(node, escape, delimiters) prev_line_num, base_line_num, index) - prev_line_num = word_node.first_line + prev_line_num = word_node.last_line content = fix_escaped_content(word_node, escape, delimiters) line_breaks + content end @@ -98,7 +93,7 @@ def process_lines(node, previous_line_num, base_line_num, source_in_lines) end def fix_escaped_content(word_node, escape, delimiters) - content = word_node.children.first.to_s + content = +word_node.children.first.to_s content = escape_string(content) if escape substitute_escaped_delimiters(content, delimiters) content @@ -110,7 +105,7 @@ def substitute_escaped_delimiters(content, delimiters) def end_content(source) result = /\A(\s*)\]/.match(source.split("\n").last) - ("\n" + result[1]) if result + "\n#{result[1]}" if result end end end diff --git a/lib/rubocop/cop/correctors/punctuation_corrector.rb b/lib/rubocop/cop/correctors/punctuation_corrector.rb index e57c0676d64c..2a4df3f610cc 100644 --- a/lib/rubocop/cop/correctors/punctuation_corrector.rb +++ b/lib/rubocop/cop/correctors/punctuation_corrector.rb @@ -5,22 +5,20 @@ module Cop # This auto-corrects punctuation class PunctuationCorrector class << self - def remove_space(space_before) - ->(corrector) { corrector.remove(space_before) } + def remove_space(corrector, space_before) + corrector.remove(space_before) end - def add_space(token) - ->(corrector) { corrector.replace(token.pos, token.pos.source + ' ') } + def add_space(corrector, token) + corrector.replace(token.pos, "#{token.pos.source} ") end - def swap_comma(range) + def swap_comma(corrector, range) return unless range - lambda do |corrector| - case range.source - when ',' then corrector.remove(range) - else corrector.insert_after(range, ',') - end + case range.source + when ',' then corrector.remove(range) + else corrector.insert_after(range, ',') end end end diff --git a/lib/rubocop/cop/correctors/space_corrector.rb b/lib/rubocop/cop/correctors/space_corrector.rb index c3542669537a..d0ceb55fcb7b 100644 --- a/lib/rubocop/cop/correctors/space_corrector.rb +++ b/lib/rubocop/cop/correctors/space_corrector.rb @@ -12,12 +12,11 @@ class << self def empty_corrections(processed_source, corrector, empty_config, left_token, right_token) @processed_source = processed_source + range = range_between(left_token.end_pos, right_token.begin_pos) if offending_empty_space?(empty_config, left_token, right_token) - range = side_space_range(range: left_token.pos, side: :right) corrector.remove(range) corrector.insert_after(left_token.pos, ' ') elsif offending_empty_no_space?(empty_config, left_token, right_token) - range = side_space_range(range: left_token.pos, side: :right) corrector.remove(range) end end @@ -36,9 +35,7 @@ def remove_space(processed_source, corrector, left_token, right_token) def add_space(processed_source, corrector, left_token, right_token) @processed_source = processed_source - unless left_token.space_after? - corrector.insert_after(left_token.pos, ' ') - end + corrector.insert_after(left_token.pos, ' ') unless left_token.space_after? return if right_token.space_before? corrector.insert_before(right_token.pos, ' ') diff --git a/lib/rubocop/cop/correctors/string_literal_corrector.rb b/lib/rubocop/cop/correctors/string_literal_corrector.rb index 9b54ac1d0b74..018fff80f829 100644 --- a/lib/rubocop/cop/correctors/string_literal_corrector.rb +++ b/lib/rubocop/cop/correctors/string_literal_corrector.rb @@ -13,9 +13,9 @@ def correct(node, style) lambda do |corrector| str = node.str_content if style == :single_quotes - corrector.replace(node.source_range, to_string_literal(str)) + corrector.replace(node, to_string_literal(str)) else - corrector.replace(node.source_range, str.inspect) + corrector.replace(node, str.inspect) end end end diff --git a/lib/rubocop/cop/correctors/unused_arg_corrector.rb b/lib/rubocop/cop/correctors/unused_arg_corrector.rb index 04b6e210b8d6..82a144f5b92f 100644 --- a/lib/rubocop/cop/correctors/unused_arg_corrector.rb +++ b/lib/rubocop/cop/correctors/unused_arg_corrector.rb @@ -9,22 +9,31 @@ class UnusedArgCorrector class << self attr_reader :processed_source - def correct(processed_source, node) + def correct(corrector, processed_source, node) return if %i[kwarg kwoptarg].include?(node.type) @processed_source = processed_source if node.blockarg_type? - lambda do |corrector| - range = range_with_surrounding_space(range: node.source_range, - side: :left) - range = range_with_surrounding_comma(range, :left) - corrector.remove(range) - end + correct_for_blockarg_type(corrector, node) else - ->(corrector) { corrector.insert_before(node.loc.name, '_') } + variable_name = if node.optarg_type? + node.node_parts[0] + else + # Extract only a var name without splat (`*`) + node.source.gsub(/\A\*+/, '') + end + + corrector.replace(node.loc.name, "_#{variable_name}") end end + + def correct_for_blockarg_type(corrector, node) + range = range_with_surrounding_space(range: node.source_range, side: :left) + range = range_with_surrounding_comma(range, :left) + + corrector.remove(range) + end end end end diff --git a/lib/rubocop/cop/documentation.rb b/lib/rubocop/cop/documentation.rb new file mode 100644 index 000000000000..651bcde37c9b --- /dev/null +++ b/lib/rubocop/cop/documentation.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + # Helpers for builtin documentation + module Documentation + module_function + + # @api private + def department_to_basename(department) + "cops_#{department.downcase}" + end + + # @api private + def url_for(cop_class) + base = department_to_basename(cop_class.department) + fragment = cop_class.cop_name.downcase.gsub(/[^a-z]/, '') + "https://docs.rubocop.org/rubocop/#{base}.html##{fragment}" + end + end + end +end diff --git a/lib/rubocop/cop/force.rb b/lib/rubocop/cop/force.rb index aafcbe99d863..bfb7566af4ce 100644 --- a/lib/rubocop/cop/force.rb +++ b/lib/rubocop/cop/force.rb @@ -11,6 +11,7 @@ def self.all end def self.inherited(subclass) + super all << subclass end diff --git a/lib/rubocop/cop/gemspec/duplicated_assignment.rb b/lib/rubocop/cop/gemspec/duplicated_assignment.rb index 03ee01d8f806..117e171930c2 100644 --- a/lib/rubocop/cop/gemspec/duplicated_assignment.rb +++ b/lib/rubocop/cop/gemspec/duplicated_assignment.rb @@ -38,9 +38,9 @@ class DuplicatedAssignment < Cop include RangeHelp MSG = '`%s` method calls already given on line '\ - '%d of the gemspec.'.freeze + '%d of the gemspec.' - def_node_search :gem_specification, <<-PATTERN + def_node_search :gem_specification, <<~PATTERN (block (send (const @@ -49,7 +49,7 @@ class DuplicatedAssignment < Cop (arg $_)) ...) PATTERN - def_node_search :assignment_method_declarations, <<-PATTERN + def_node_search :assignment_method_declarations, <<~PATTERN (send (lvar #match_block_variable_name?) #assignment_method? ...) PATTERN diff --git a/lib/rubocop/cop/gemspec/ordered_dependencies.rb b/lib/rubocop/cop/gemspec/ordered_dependencies.rb index 461d1035aae6..071e3cc50683 100644 --- a/lib/rubocop/cop/gemspec/ordered_dependencies.rb +++ b/lib/rubocop/cop/gemspec/ordered_dependencies.rb @@ -57,7 +57,6 @@ class OrderedDependencies < Cop MSG = 'Dependencies should be sorted in an alphabetical order within ' \ 'their section of the gemspec. '\ 'Dependency `%s` should appear before `%s`.' - .freeze def investigate(processed_source) return if processed_source.blank? @@ -69,9 +68,7 @@ def investigate(processed_source) gem_name(current), gem_name(previous) ) - unless get_dependency_name(previous) == get_dependency_name(current) - next - end + next unless get_dependency_name(previous) == get_dependency_name(current) register_offense(previous, current) end @@ -98,8 +95,8 @@ def get_dependency_name(node) node.method_name end - def_node_search :dependency_declarations, <<-PATTERN - (send (lvar _) {:add_dependency :add_runtime_dependency :add_development_dependency} ...) + def_node_search :dependency_declarations, <<~PATTERN + (send (lvar _) {:add_dependency :add_runtime_dependency :add_development_dependency} (str _) ...) PATTERN end end diff --git a/lib/rubocop/cop/gemspec/required_ruby_version.rb b/lib/rubocop/cop/gemspec/required_ruby_version.rb index 54352b2c7750..7b912b48257d 100644 --- a/lib/rubocop/cop/gemspec/required_ruby_version.rb +++ b/lib/rubocop/cop/gemspec/required_ruby_version.rb @@ -3,17 +3,17 @@ module RuboCop module Cop module Gemspec - # Checks that `required_ruby_version` of gemspec and `TargetRubyVersion` - # of .rubocop.yml are equal. + # Checks that `required_ruby_version` of gemspec is specified and + # equal to `TargetRubyVersion` of .rubocop.yml. # Thereby, RuboCop to perform static analysis working on the version # required by gemspec. # # @example - # # When `TargetRubyVersion` of .rubocop.yml is `2.3`. + # # When `TargetRubyVersion` of .rubocop.yml is `2.5`. # # # bad # Gem::Specification.new do |spec| - # spec.required_ruby_version = '>= 2.2.0' + # # no `required_ruby_version` specified # end # # # bad @@ -21,59 +21,85 @@ module Gemspec # spec.required_ruby_version = '>= 2.4.0' # end # + # # bad + # Gem::Specification.new do |spec| + # spec.required_ruby_version = '>= 2.6.0' + # end + # + # # good + # Gem::Specification.new do |spec| + # spec.required_ruby_version = '>= 2.5.0' + # end + # # # good # Gem::Specification.new do |spec| - # spec.required_ruby_version = '>= 2.3.0' + # spec.required_ruby_version = '>= 2.5' # end # # # good # Gem::Specification.new do |spec| - # spec.required_ruby_version = '>= 2.3' + # spec.required_ruby_version = ['>= 2.5.0', '< 2.7.0'] # end # # # good # Gem::Specification.new do |spec| - # spec.required_ruby_version = ['>= 2.3.0', '< 2.5.0'] + # spec.required_ruby_version = '~> 2.5' # end class RequiredRubyVersion < Cop - MSG = '`required_ruby_version` (%s, ' \ - 'declared in %s) and `TargetRubyVersion` ' \ - '(%s, which may be specified in ' \ - '.rubocop.yml) should be equal.'.freeze + include RangeHelp + + NOT_EQUAL_MSG = '`required_ruby_version` (%s, ' \ + 'declared in %s) and `TargetRubyVersion` ' \ + '(%s, which may be specified in ' \ + '.rubocop.yml) should be equal.' + MISSING_MSG = '`required_ruby_version` should be specified.' - def_node_search :required_ruby_version, <<-PATTERN - (send _ :required_ruby_version= ${(str _) (array (str _))}) + def_node_search :required_ruby_version, <<~PATTERN + (send _ :required_ruby_version= $_) PATTERN + def_node_matcher :defined_ruby_version, <<~PATTERN + {$(str _) $(array (str _) (str _)) + (send (const (const nil? :Gem) :Requirement) :new $(str _))} + PATTERN + + # rubocop:disable Metrics/AbcSize def investigate(processed_source) - required_ruby_version(processed_source.ast) do |version| - ruby_version = extract_ruby_version(version) + version_def = required_ruby_version(processed_source.ast).first - return if ruby_version == target_ruby_version.to_s + if version_def + ruby_version = extract_ruby_version(defined_ruby_version(version_def)) + return if !ruby_version || ruby_version == target_ruby_version.to_s add_offense( processed_source.ast, - location: version.loc.expression, - message: message(ruby_version, target_ruby_version) + location: version_def.loc.expression, + message: not_equal_message(ruby_version, target_ruby_version) ) + else + range = source_range(processed_source.buffer, 1, 0) + add_offense(nil, location: range, message: MISSING_MSG) end end + # rubocop:enable Metrics/AbcSize private def extract_ruby_version(required_ruby_version) + return unless required_ruby_version + if required_ruby_version.array_type? required_ruby_version = required_ruby_version.children.detect do |v| - v.str_content =~ /[>=]/ + /[>=]/.match?(v.str_content) end end - required_ruby_version.str_content.match(/(\d\.\d)/)[1] + required_ruby_version.str_content.scan(/\d/).first(2).join('.') end - def message(required_ruby_version, target_ruby_version) + def not_equal_message(required_ruby_version, target_ruby_version) format( - MSG, + NOT_EQUAL_MSG, required_ruby_version: required_ruby_version, gemspec_filename: File.basename(processed_source.file_path), target_ruby_version: target_ruby_version diff --git a/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb b/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb new file mode 100644 index 000000000000..ad46145c2ebb --- /dev/null +++ b/lib/rubocop/cop/gemspec/ruby_version_globals_usage.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Gemspec + # Checks that `RUBY_VERSION` constant is not used in gemspec. + # Using `RUBY_VERSION` is dangerous because value of the + # constant is determined by `rake release`. + # It's possible to have dependency based on ruby version used + # to execute `rake release` and not user's ruby version. + # + # @example + # + # # bad + # Gem::Specification.new do |spec| + # if RUBY_VERSION >= '2.5' + # spec.add_runtime_dependency 'gem_a' + # else + # spec.add_runtime_dependency 'gem_b' + # end + # end + # + # # good + # Gem::Specification.new do |spec| + # spec.add_runtime_dependency 'gem_a' + # end + # + class RubyVersionGlobalsUsage < Cop + MSG = 'Do not use `RUBY_VERSION` in gemspec file.' + + def_node_matcher :ruby_version?, '(const {cbase nil?} :RUBY_VERSION)' + + def_node_search :gem_specification?, <<~PATTERN + (block + (send + (const + (const {cbase nil?} :Gem) :Specification) :new) + ...) + PATTERN + + def on_const(node) + return unless gem_spec_with_ruby_version?(node) + + add_offense(node) + end + + private + + def gem_spec_with_ruby_version?(node) + gem_specification?(processed_source.ast) && ruby_version?(node) + end + end + end + end +end diff --git a/lib/rubocop/cop/generator.rb b/lib/rubocop/cop/generator.rb index 49f654456de8..18d1bf8ecce3 100644 --- a/lib/rubocop/cop/generator.rb +++ b/lib/rubocop/cop/generator.rb @@ -6,8 +6,15 @@ module Cop # # This generator will take a cop name and generate a source file # and spec file when given a valid qualified cop name. + # @api private class Generator - SOURCE_TEMPLATE = <<-RUBY.strip_indent + # Note: RDoc 5.1.0 or lower has the following issue. + # https://github.com/rubocop-hq/rubocop/issues/7043 + # + # The following `String#gsub` can be replaced with + # squiggly heredoc when RuboCop supports Ruby 2.5 or higher + # (RDoc 6.0 or higher). + SOURCE_TEMPLATE = <<-RUBY.gsub(/^ {8}/, '') # frozen_string_literal: true # TODO: when finished, run `rake generate_cops_documentation` to update the docs @@ -48,16 +55,16 @@ module %s # # good # good_foo_method(args) # - class %s < Cop + class %s < Base # TODO: Implement the cop in here. # # In many cases, you can use a node matcher for matching node pattern. - # See https://github.com/rubocop-hq/rubocop/blob/master/lib/rubocop/node_pattern.rb + # See https://github.com/rubocop-hq/rubocop-ast/blob/master/lib/rubocop/ast/node_pattern.rb # # For example - MSG = 'Use `#good_method` instead of `#bad_method`.'.freeze + MSG = 'Use `#good_method` instead of `#bad_method`.' - def_node_matcher :bad_method?, <<-PATTERN + def_node_matcher :bad_method?, <<~PATTERN (send nil? :bad_method ...) PATTERN @@ -72,7 +79,7 @@ def on_send(node) end RUBY - SPEC_TEMPLATE = <<-SPEC.strip_indent + SPEC_TEMPLATE = <<~SPEC # frozen_string_literal: true RSpec.describe RuboCop::Cop::%s::%s do @@ -84,24 +91,23 @@ def on_send(node) # # For example it 'registers an offense when using `#bad_method`' do - expect_offense(<<-RUBY.strip_indent) + expect_offense(<<~RUBY) bad_method ^^^^^^^^^^ Use `#good_method` instead of `#bad_method`. RUBY end it 'does not register an offense when using `#good_method`' do - expect_no_offenses(<<-RUBY.strip_indent) + expect_no_offenses(<<~RUBY) good_method RUBY end end SPEC - CONFIGURATION_ADDED_MESSAGE = <<-MESSAGE.strip_indent - [modify] A configuration for the cop is added into %s. - If you want to disable the cop by default, set `Enabled` option to false. - MESSAGE + CONFIGURATION_ADDED_MESSAGE = + '[modify] A configuration for the cop is added into ' \ + '%s.' def initialize(name, github_user, output: $stdout) @badge = Badge.parse(name) @@ -127,11 +133,12 @@ def inject_require(root_file_path: 'lib/rubocop.rb') ).inject end - def inject_config(config_file_path: 'config/default.yml') + def inject_config(config_file_path: 'config/default.yml', + version_added: bump_minor_version) injector = ConfigurationInjector.new(configuration_file_path: config_file_path, badge: badge, - version_added: bump_minor_version) + version_added: version_added) injector.inject do output.puts(format(CONFIGURATION_ADDED_MESSAGE, @@ -140,7 +147,7 @@ def inject_config(config_file_path: 'config/default.yml') end def todo - <<-TODO.strip_indent + <<~TODO Do 3 steps: 1. Add an entry to the "New features" section in CHANGELOG.md, e.g. "Add new `#{badge}` cop. ([@#{github_user}][])" diff --git a/lib/rubocop/cop/generator/configuration_injector.rb b/lib/rubocop/cop/generator/configuration_injector.rb index acb58665a563..53cb65e209e3 100644 --- a/lib/rubocop/cop/generator/configuration_injector.rb +++ b/lib/rubocop/cop/generator/configuration_injector.rb @@ -7,12 +7,11 @@ class Generator # It looks for other directives that require files in the same (cop) # namespace and injects the provided one in alpha class ConfigurationInjector - TEMPLATE = <<-YAML.strip_indent - %s: - Description: 'TODO: Write a description of the cop.' - Enabled: true - VersionAdded: '%s' - + TEMPLATE = <<~YAML + %s: + Description: 'TODO: Write a description of the cop.' + Enabled: pending + VersionAdded: '%s' YAML def initialize(configuration_file_path:, badge:, version_added:) @@ -23,8 +22,13 @@ def initialize(configuration_file_path:, badge:, version_added:) end def inject - configuration_entries.insert(find_target_line, - new_configuration_entry) + target_line = find_target_line + if target_line + configuration_entries.insert(target_line, + "#{new_configuration_entry}\n") + else + configuration_entries.push("\n#{new_configuration_entry}") + end File.write(configuration_file_path, configuration_entries.join) @@ -49,11 +53,12 @@ def find_target_line return index if badge.to_s < line end - configuration_entries.size - 1 + + nil end def cop_name_line?(yaml) - yaml !~ /^[\s#]/ + !/^[\s#]/.match?(yaml) end end end diff --git a/lib/rubocop/cop/generator/require_file_injector.rb b/lib/rubocop/cop/generator/require_file_injector.rb index 3a8af5a30a3d..a871659c1595 100644 --- a/lib/rubocop/cop/generator/require_file_injector.rb +++ b/lib/rubocop/cop/generator/require_file_injector.rb @@ -54,7 +54,7 @@ def target_line elsif in_the_same_department break index end - end + end || require_entries.size end end diff --git a/lib/rubocop/cop/ignored_node.rb b/lib/rubocop/cop/ignored_node.rb index 7648c576e38c..6be9265df805 100644 --- a/lib/rubocop/cop/ignored_node.rb +++ b/lib/rubocop/cop/ignored_node.rb @@ -10,9 +10,7 @@ def ignore_node(node) def part_of_ignored_node?(node) ignored_nodes.map(&:loc).any? do |ignored_loc| - if ignored_loc.expression.begin_pos > node.source_range.begin_pos - next false - end + next false if ignored_loc.expression.begin_pos > node.source_range.begin_pos ignored_end_pos = if ignored_loc.respond_to?(:heredoc_body) ignored_loc.heredoc_end.end_pos diff --git a/lib/rubocop/cop/internal_affairs.rb b/lib/rubocop/cop/internal_affairs.rb index 73c64e1ce580..cf88c4695434 100644 --- a/lib/rubocop/cop/internal_affairs.rb +++ b/lib/rubocop/cop/internal_affairs.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require_relative 'internal_affairs/method_name_equal' require_relative 'internal_affairs/node_destructuring' require_relative 'internal_affairs/node_type_predicate' require_relative 'internal_affairs/offense_location_keyword' diff --git a/lib/rubocop/cop/internal_affairs/method_name_equal.rb b/lib/rubocop/cop/internal_affairs/method_name_equal.rb new file mode 100644 index 000000000000..31fa59294de5 --- /dev/null +++ b/lib/rubocop/cop/internal_affairs/method_name_equal.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module InternalAffairs + # Checks that method names are checked using `method?` method. + # + # @example + # # bad + # node.method_name == :do_something + # + # # good + # node.method?(:do_something) + # + class MethodNameEqual < Base + include RangeHelp + extend AutoCorrector + + MSG = 'Use `method?(%s)` instead of ' \ + '`method_name == %s`.' + RESTRICT_ON_SEND = %i[==].freeze + + def_node_matcher :method_name?, <<~PATTERN + (send + $(send + (...) :method_name) :== + $...) + PATTERN + + def on_send(node) + method_name?(node) do |method_name_node, method_name_arg| + message = format(MSG, method_name: method_name_arg.first.source) + + range = range(method_name_node, node) + + add_offense(range, message: message) do |corrector| + corrector.replace(range, "method?(#{method_name_arg.first.source})") + end + end + end + + private + + def range(method_name_node, node) + range_between( + method_name_node.loc.selector.begin_pos, node.source_range.end_pos + ) + end + end + end + end +end diff --git a/lib/rubocop/cop/internal_affairs/node_destructuring.rb b/lib/rubocop/cop/internal_affairs/node_destructuring.rb index 40832d1bada5..38156260f7cd 100644 --- a/lib/rubocop/cop/internal_affairs/node_destructuring.rb +++ b/lib/rubocop/cop/internal_affairs/node_destructuring.rb @@ -3,34 +3,32 @@ module RuboCop module Cop module InternalAffairs - # Checks that node destructuring is done either using the node - # extensions or using a splat. + # Checks that node destructuring is using the node extensions. # # @example Using splat expansion # # # bad - # receiver, method_name, arguments = send_node.children - # - # # good - # receiver, method_name, arguments = *send_node - # - # @example Using node extensions + # _receiver, method_name, _arguments = send_node.children # # # bad - # _receiver, method_name, _arguments = send_node.children + # _receiver, method_name, _arguments = *send_node # # # good # method_name = send_node.method_name - class NodeDestructuring < Cop - MSG = 'Use the methods provided with the node extensions or ' \ - 'destructure the node using `*`.'.freeze + class NodeDestructuring < Base + MSG = 'Use the methods provided with the node extensions instead ' \ + 'of manually destructuring nodes.' + + def_node_matcher :node_variable?, <<~PATTERN + {(lvar [#node_suffix? _]) (send nil? [#node_suffix? _])} + PATTERN - def_node_matcher :node_children_destructuring?, <<-PATTERN - (masgn (mlhs ...) (send (send nil? [#node_suffix? _]) :children)) + def_node_matcher :node_destructuring?, <<~PATTERN + {(masgn (mlhs ...) {(send #node_variable? :children) (array (splat #node_variable?))})} PATTERN def on_masgn(node) - node_children_destructuring?(node) do + node_destructuring?(node) do add_offense(node) end end diff --git a/lib/rubocop/cop/internal_affairs/node_type_predicate.rb b/lib/rubocop/cop/internal_affairs/node_type_predicate.rb index 0a445dd71556..89da1ec3da80 100644 --- a/lib/rubocop/cop/internal_affairs/node_type_predicate.rb +++ b/lib/rubocop/cop/internal_affairs/node_type_predicate.rb @@ -13,29 +13,27 @@ module InternalAffairs # # good # node.send_type? # - class NodeTypePredicate < Cop - MSG = 'Use `#%s_type?` to check node type.'.freeze + class NodeTypePredicate < Base + extend AutoCorrector - def_node_matcher :node_type_check, <<-PATTERN + MSG = 'Use `#%s_type?` to check node type.' + RESTRICT_ON_SEND = %i[==].freeze + + def_node_matcher :node_type_check, <<~PATTERN (send (send $_ :type) :== (sym $_)) PATTERN def on_send(node) - node_type_check(node) do |_receiver, node_type| + node_type_check(node) do |receiver, node_type| return unless Parser::Meta::NODE_TYPES.include?(node_type) - add_offense(node, message: format(MSG, type: node_type)) - end - end - - def autocorrect(node) - receiver, node_type = node_type_check(node) - range = Parser::Source::Range.new(node.source_range.source_buffer, - receiver.loc.expression.end_pos + 1, - node.loc.expression.end_pos) - - lambda do |corrector| - corrector.replace(range, "#{node_type}_type?") + message = format(MSG, type: node_type) + add_offense(node, message: message) do |corrector| + range = node.loc.expression.with( + begin_pos: receiver.loc.expression.end_pos + 1 + ) + corrector.replace(range, "#{node_type}_type?") + end end end end diff --git a/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb b/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb index 7393293907f8..9e4cb2da12f0 100644 --- a/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb +++ b/lib/rubocop/cop/internal_affairs/offense_location_keyword.rb @@ -13,31 +13,32 @@ module InternalAffairs # # # good # add_offense(node, location: :selector) - class OffenseLocationKeyword < Cop + class OffenseLocationKeyword < Base + extend AutoCorrector + MSG = 'Use `:%s` as the location argument to ' \ - '`#add_offense`.'.freeze + '`#add_offense`.' + RESTRICT_ON_SEND = %i[add_offense].freeze def on_send(node) node_type_check(node) do |node_arg, kwargs| find_offending_argument(node_arg, kwargs) do |location, keyword| - add_offense(location, message: format(MSG, keyword: keyword)) + add_offense(location, message: format(MSG, keyword: keyword)) do |corrector| + (*, keyword) = offending_location_argument(location.parent) + + corrector.replace(location, ":#{keyword}") + end end end end - def autocorrect(node) - (*, keyword) = offending_location_argument(node.parent) - - ->(corrector) { corrector.replace(node.source_range, ":#{keyword}") } - end - private - def_node_matcher :node_type_check, <<-PATTERN + def_node_matcher :node_type_check, <<~PATTERN (send nil? :add_offense $_node $hash) PATTERN - def_node_matcher :offending_location_argument, <<-PATTERN + def_node_matcher :offending_location_argument, <<~PATTERN (pair (sym :location) $(send (send $_node :loc) $_keyword)) PATTERN diff --git a/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb b/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb index 5b8b6376f038..a76309fe6a0f 100644 --- a/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb +++ b/lib/rubocop/cop/internal_affairs/redundant_location_argument.rb @@ -16,40 +16,31 @@ module InternalAffairs # add_offense(node) # add_offense(node, location: :selector) # - class RedundantLocationArgument < Cop + class RedundantLocationArgument < Base include RangeHelp + extend AutoCorrector - MSG = 'Redundant location argument to `#add_offense`.'.freeze + MSG = 'Redundant location argument to `#add_offense`.' + RESTRICT_ON_SEND = %i[add_offense].freeze - def_node_matcher :add_offense_kwargs, <<-PATTERN - (send nil? :add_offense _ $hash) - PATTERN - - def_node_matcher :redundant_location_argument?, <<-PATTERN - (pair (sym :location) (sym :expression)) + def_node_matcher :redundant_location_argument, <<~PATTERN + (send nil? :add_offense _ + (hash <$(pair (sym :location) (sym :expression)) ...>) + ) PATTERN def on_send(node) - redundant_location_argument(node) { |argument| add_offense(argument) } - end + redundant_location_argument(node) do |argument| + add_offense(argument) do |corrector| + range = offending_range(argument) - def autocorrect(node) - range = offending_range(node) - - ->(corrector) { corrector.remove(range) } + corrector.remove(range) + end + end end private - def redundant_location_argument(node) - add_offense_kwargs(node) do |kwargs| - result = - kwargs.pairs.find { |arg| redundant_location_argument?(arg) } - - yield result if result - end - end - def offending_range(node) with_space = range_with_surrounding_space(range: node.loc.expression) diff --git a/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb b/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb index 23b27e2c9d9b..e6b4a67c7d34 100644 --- a/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb +++ b/lib/rubocop/cop/internal_affairs/redundant_message_argument.rb @@ -19,16 +19,18 @@ module InternalAffairs # add_offense(node, message: CUSTOM_MSG) # add_offense(node, message: message(other_node)) # - class RedundantMessageArgument < Cop + class RedundantMessageArgument < Base include RangeHelp + extend AutoCorrector - MSG = 'Redundant message argument to `#add_offense`.'.freeze + MSG = 'Redundant message argument to `#add_offense`.' + RESTRICT_ON_SEND = %i[add_offense].freeze - def_node_matcher :node_type_check, <<-PATTERN + def_node_matcher :node_type_check, <<~PATTERN (send nil? :add_offense $_node $hash) PATTERN - def_node_matcher :redundant_message_argument, <<-PATTERN + def_node_matcher :redundant_message_argument, <<~PATTERN (pair (sym :message) ${(const nil? :MSG) (send nil? :message) (send nil? :message _)}) @@ -39,17 +41,15 @@ class RedundantMessageArgument < Cop def on_send(node) node_type_check(node) do |node_arg, kwargs| find_offending_argument(node_arg, kwargs) do |pair| - add_offense(pair) + add_offense(pair) do |corrector| + range = offending_range(pair) + + corrector.remove(range) + end end end end - def autocorrect(node) - range = offending_range(node) - - ->(corrector) { corrector.remove(range) } - end - private def offending_range(node) diff --git a/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb b/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb index c2a5b7797424..ceb07dbcfbbb 100644 --- a/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb +++ b/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb @@ -13,18 +13,18 @@ module InternalAffairs # # good # expect(cop.messages).to eq(['Do not write bad code like that.']) # - class UselessMessageAssertion < Cop - MSG = 'Do not specify cop behavior using `described_class::MSG`.'.freeze + class UselessMessageAssertion < Base + MSG = 'Do not specify cop behavior using `described_class::MSG`.' - def_node_search :described_class_msg, <<-PATTERN + def_node_search :described_class_msg, <<~PATTERN (const (send nil? :described_class) :MSG) PATTERN - def_node_matcher :rspec_expectation_on_msg?, <<-PATTERN + def_node_matcher :rspec_expectation_on_msg?, <<~PATTERN (send (send nil? :expect #contains_described_class_msg?) :to ...) PATTERN - def investigate(_processed_source) + def on_new_investigation assertions_using_described_class_msg.each do |node| add_offense(node) end diff --git a/lib/rubocop/cop/layout/access_modifier_indentation.rb b/lib/rubocop/cop/layout/access_modifier_indentation.rb index 61807bd6a928..74e638252cc3 100644 --- a/lib/rubocop/cop/layout/access_modifier_indentation.rb +++ b/lib/rubocop/cop/layout/access_modifier_indentation.rb @@ -3,8 +3,9 @@ module RuboCop module Cop module Layout - # Modifiers should be indented as deep as method definitions, or as deep - # as the class/module keyword, depending on configuration. + # Bare access modifiers (those not applying to specific methods) should be + # indented as deep as method definitions, or as deep as the class/module + # keyword, depending on configuration. # # @example EnforcedStyle: indent (default) # # bad @@ -36,26 +37,16 @@ class AccessModifierIndentation < Cop include ConfigurableEnforcedStyle include RangeHelp - MSG = '%