Skip to content

Commit

Permalink
Pluginfy RuboCop Rails
Browse files Browse the repository at this point in the history
This PR adds support for RuboCop's Plugin feature.

Since RuboCop Rails still supports some older versions of RuboCop,
a conditional check using `RuboCop.const_defined?(:Plugin)` has been added for compatibility.

Once only versions of RuboCop that support the Plugin feature are supported,
the compatibility code and the `RuboCop::Rails::Inject` module will be removed.

This means that the legacy style will gradually become deprecated in the near future.
  • Loading branch information
koic committed Feb 8, 2025
1 parent aceb874 commit a057738
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 13 deletions.
6 changes: 4 additions & 2 deletions .rubocop.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
# This is the configuration used to check the rubocop source code.

inherit_from: .rubocop_todo.yml
plugins:
- rubocop-internal_affairs
- rubocop-rails

require:
- rubocop/cop/internal_affairs
- rubocop-performance
- rubocop-rails
- rubocop-rspec

AllCops:
Expand Down
46 changes: 42 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,48 @@ gem 'rubocop-rails', require: false

## Usage

You need to tell RuboCop to load the Rails extension. There are three
You need to tell RuboCop to load the Rails extension. There are some
ways to do this:

### RuboCop configuration file
### RuboCop configuration file (Recommended Style)

Put this into your `.rubocop.yml`.

```yaml
plugins: rubocop-rails
```
Alternatively, use the following array notation when specifying multiple extensions.
```yaml
plugins:
- rubocop-other-extension
- rubocop-rails
```
Now you can run `rubocop` and it will automatically load the RuboCop Rails
cops together with the standard cops.

> [!NOTE]
> The plugin system is supported in RuboCop 1.72+.

### Command line

```sh
$ rubocop --plugin rubocop-rails
```

### Rake task

```ruby
require 'rubocop/rake_task'
RuboCop::RakeTask.new do |task|
task.plugins << 'rubocop-rails'
end
```

### RuboCop configuration file (Legacy Style)

Put this into your `.rubocop.yml`.

Expand All @@ -45,15 +83,15 @@ require:
Now you can run `rubocop` and it will automatically load the RuboCop Rails
cops together with the standard cops.

### Command line
### Command line (Legacy Style)

```sh
$ rubocop --require rubocop-rails
```

Note: `--rails` option is required while `rubocop` command supports `--rails` option.

### Rake task
### Rake task (Legacy Style)

```ruby
require 'rubocop/rake_task'
Expand Down
1 change: 1 addition & 0 deletions changelog/new_pluginfy_with_lint_roller.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#1434](https://github.com/rubocop/rubocop-rails/pull/1434): Pluginfy RuboCop Rails. ([@koic][])
38 changes: 34 additions & 4 deletions docs/modules/ROOT/pages/usage.adoc
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
= Usage

You need to tell RuboCop to load the Rails extension. There are three
You need to tell RuboCop to load the Rails extension. There are some
ways to do this:

== RuboCop configuration file
== RuboCop configuration file (Recommended Style)

Put this into your `.rubocop.yml`.

[source,yaml]
----
require: rubocop-rails
plugins: rubocop-rails
----

Now you can run `rubocop` and it will automatically load the RuboCop Rails
Expand All @@ -19,11 +19,41 @@ cops together with the standard cops.

[source,sh]
----
$ rubocop --require rubocop-rails
$ rubocop --plugin rubocop-rails
----

== Rake task

[source,ruby]
----
RuboCop::RakeTask.new do |task|
task.plugins << 'rubocop-rails'
end
----

NOTE: The plugin system is supported in RuboCop 1.72+.

== RuboCop configuration file (Legacy Style)

Put this into your `.rubocop.yml`.

[source,yaml]
----
require: rubocop-rails
----

Now you can run `rubocop` and it will automatically load the RuboCop Rails
cops together with the standard cops.

== Command line (Legacy Style)

[source,sh]
----
$ rubocop --require rubocop-rails
----

== Rake task (Legacy Style)

[source,ruby]
----
RuboCop::RakeTask.new do |task|
Expand Down
11 changes: 10 additions & 1 deletion lib/rubocop-rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,16 @@
require_relative 'rubocop/rails/schema_loader'
require_relative 'rubocop/rails/schema_loader/schema'

RuboCop::Rails::Inject.defaults!
# FIXME: When RuboCop Rails requires RuboCop 1.72.0+ only, the following compatibility code can be removed.
if RuboCop.const_defined?(:Plugin)
require_relative 'rubocop/rails/plugin'
else
# NOTE: Until the plugin stabilizes, an option to use the older version of RuboCop is provided.
# The plugin will be unified in the future.
require_relative 'rubocop/rails/inject'

RuboCop::Rails::Inject.defaults!
end

require_relative 'rubocop/cop/rails_cops'

Expand Down
2 changes: 1 addition & 1 deletion lib/rubocop/rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@ module Rails

private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)

::RuboCop::ConfigObsoletion.files << PROJECT_ROOT.join('config', 'obsoletion.yml')
ConfigObsoletion.files << Pathname("#{__dir__}/../../config/obsoletion.yml")
end
end
31 changes: 31 additions & 0 deletions lib/rubocop/rails/plugin.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

require 'lint_roller'

module RuboCop
module Rails
# A plugin that integrates RuboCop Rails with RuboCop's plugin system.
class Plugin < LintRoller::Plugin
def about
LintRoller::About.new(
name: 'rubocop-rails',
version: Version::STRING,
homepage: 'https://github.com/rubocop/rubocop-rails',
description: 'A RuboCop extension focused on enforcing Rails best practices and coding conventions.'
)
end

def supported?(context)
context.engine == :rubocop
end

def rules(_context)
LintRoller::Rules.new(
type: :path,
config_format: :rubocop,
value: Pathname.new(__dir__).join('../../../config/default.yml')
)
end
end
end
end
3 changes: 3 additions & 0 deletions rubocop-rails.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,12 @@ Gem::Specification.new do |s|
'rubygems_mfa_required' => 'true'
}

s.metadata['default_lint_roller_plugin'] = 'RuboCop::Rails::Plugin'

s.add_dependency 'activesupport', '>= 4.2.0'
# Rack::Utils::SYMBOL_TO_STATUS_CODE, which is used by HttpStatus cop, was
# introduced in rack 1.1
s.add_dependency 'lint_roller', '~> 1.1'
s.add_dependency 'rack', '>= 1.1'
s.add_dependency 'rubocop', '>= 1.52.0', '< 2.0'
s.add_dependency 'rubocop-ast', '>= 1.38.0', '< 2.0'
Expand Down
3 changes: 3 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@
require_relative 'support/file_helper'
require_relative 'support/shared_contexts'

# FIXME: Once only RuboCop versions that support plugins remain, please remove the `if` condition.
RuboCop::ConfigLoader.inject_defaults!("#{__dir__}/../config/default.yml") if RuboCop.const_defined?(:Plugin)

# Requires supporting files with custom matchers and macros, etc,
# in ./support/ and its subdirectories.
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each { |f| require f }
Expand Down
2 changes: 1 addition & 1 deletion tasks/cops_documentation.rake
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ task update_cops_documentation: :yard_for_generate_documentation do

# NOTE: Update `<<next>>` version for docs/modules/ROOT/pages/cops_rails.adoc
# when running release tasks.
RuboCop::Rails::Inject.defaults!
RuboCop::ConfigLoader.inject_defaults!("#{__dir__}/../config/default.yml")

CopsDocumentationGenerator.new(departments: deps, extra_info: extra_info).call
end
Expand Down

0 comments on commit a057738

Please sign in to comment.