Skip to content

Commit

Permalink
Merge pull request #281 from fatkodima/mailer-name-cop
Browse files Browse the repository at this point in the history
Add new `Rails/MailerName` cop
  • Loading branch information
koic authored Jun 29, 2020
2 parents 763ca75 + f0e9127 commit db1bf58
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### New features

* [#281](https://github.com/rubocop-hq/rubocop-rails/pull/281): Add new `Rails/MailerName` cop. ([@fatkodima][])
* [#246](https://github.com/rubocop-hq/rubocop-rails/issues/246): Add new `Rails/PluckInWhere` cop. ([@fatkodima][])
* [#17](https://github.com/rubocop-hq/rubocop-rails/issues/17): Add new `Rails/NegateInclude` cop. ([@fatkodima][])
* [#278](https://github.com/rubocop-hq/rubocop-rails/pull/278): Add new `Rails/Pluck` cop. ([@eugeneius][])
Expand Down
8 changes: 8 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,14 @@ Rails/LinkToBlank:
Enabled: true
VersionAdded: '0.62'

Rails/MailerName:
Description: 'Mailer should end with `Mailer` suffix.'
StyleGuide: 'https://rails.rubystyle.guide/#mailer-name'
Enabled: 'pending'
VersionAdded: '2.7'
Include:
- app/mailers/**/*.rb

Rails/NegateInclude:
Description: 'Prefer `collection.exclude?(obj)` over `!collection.include?(obj)`.'
Enabled: 'pending'
Expand Down
1 change: 1 addition & 0 deletions docs/modules/ROOT/pages/cops.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
* xref:cops_rails.adoc#railsinverseof[Rails/InverseOf]
* xref:cops_rails.adoc#railslexicallyscopedactionfilter[Rails/LexicallyScopedActionFilter]
* xref:cops_rails.adoc#railslinktoblank[Rails/LinkToBlank]
* xref:cops_rails.adoc#railsmailername[Rails/MailerName]
* xref:cops_rails.adoc#railsnegateinclude[Rails/NegateInclude]
* xref:cops_rails.adoc#railsnotnullcolumn[Rails/NotNullColumn]
* xref:cops_rails.adoc#railsoutput[Rails/Output]
Expand Down
50 changes: 50 additions & 0 deletions docs/modules/ROOT/pages/cops_rails.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1894,6 +1894,56 @@ link_to 'Click here', url, target: '_blank', rel: 'noreferrer'
* https://html.spec.whatwg.org/multipage/links.html#link-type-noopener
* https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer

== Rails/MailerName

|===
| Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged

| Pending
| Yes
| Yes
| 2.7
| -
|===

This cop enforces that mailer names end with `Mailer` suffix.

Without the `Mailer` suffix it isn't immediately apparent what's a mailer
and which views are related to the mailer.

=== Examples

[source,ruby]
----
# bad
class User < ActionMailer::Base
end
class User < ApplicationMailer
end
# good
class UserMailer < ActionMailer::Base
end
class UserMailer < ApplicationMailer
end
----

=== Configurable attributes

|===
| Name | Default value | Configurable values

| Include
| `app/mailers/**/*.rb`
| Array
|===

=== References

* https://rails.rubystyle.guide/#mailer-name

== Rails/NegateInclude

|===
Expand Down
80 changes: 80 additions & 0 deletions lib/rubocop/cop/rails/mailer_name.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Rails
# This cop enforces that mailer names end with `Mailer` suffix.
#
# Without the `Mailer` suffix it isn't immediately apparent what's a mailer
# and which views are related to the mailer.
#
# @example
# # bad
# class User < ActionMailer::Base
# end
#
# class User < ApplicationMailer
# end
#
# # good
# class UserMailer < ActionMailer::Base
# end
#
# class UserMailer < ApplicationMailer
# end
#
class MailerName < Cop
MSG = 'Mailer should end with `Mailer` suffix.'

def_node_matcher :mailer_base_class?, <<~PATTERN
{
(const (const nil? :ActionMailer) :Base)
(const nil? :ApplicationMailer)
}
PATTERN

def_node_matcher :class_definition?, <<~PATTERN
(class $(const _ !#mailer_suffix?) #mailer_base_class? ...)
PATTERN

def_node_matcher :class_new_definition?, <<~PATTERN
(send (const nil? :Class) :new #mailer_base_class?)
PATTERN

def on_class(node)
class_definition?(node) do |name_node|
add_offense(name_node)
end
end

def on_send(node)
return unless class_new_definition?(node)

casgn_parent = node.each_ancestor(:casgn).first
return unless casgn_parent

name = casgn_parent.children[1]
add_offense(casgn_parent, location: :name) unless mailer_suffix?(name)
end

def autocorrect(node)
lambda do |corrector|
if node.casgn_type?
name = node.children[1]
corrector.replace(node.loc.name, "#{name}Mailer")
else
name = node.children.last
corrector.replace(node.source_range, "#{name}Mailer")
end
end
end

private

def mailer_suffix?(mailer_name)
mailer_name.to_s.end_with?('Mailer')
end
end
end
end
end
1 change: 1 addition & 0 deletions lib/rubocop/cop/rails_cops.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
require_relative 'rails/inverse_of'
require_relative 'rails/lexically_scoped_action_filter'
require_relative 'rails/link_to_blank'
require_relative 'rails/mailer_name'
require_relative 'rails/negate_include'
require_relative 'rails/not_null_column'
require_relative 'rails/output'
Expand Down
48 changes: 48 additions & 0 deletions spec/rubocop/cop/rails/mailer_name_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Rails::MailerName do
subject(:cop) { described_class.new }

['ActionMailer::Base', 'ApplicationMailer'].each do |base|
context 'when regular class definition' do
it 'registers an offense and corrects when name without suffix' do
expect_offense(<<~RUBY)
class User < #{base}
^^^^ Mailer should end with `Mailer` suffix.
end
RUBY

expect_correction(<<~RUBY)
class UserMailer < #{base}
end
RUBY
end

it 'does not register an offense when name with suffix' do
expect_no_offenses(<<~RUBY)
class UserMailer < #{base}
end
RUBY
end
end

context 'when `Class.new` definition' do
it 'registers an offense and corrects when name without suffix' do
expect_offense(<<~RUBY)
User = Class.new(#{base})
^^^^ Mailer should end with `Mailer` suffix.
RUBY

expect_correction(<<~RUBY)
UserMailer = Class.new(#{base})
RUBY
end

it 'does not register an offense when name with suffix' do
expect_no_offenses(<<~RUBY)
UserMailer = Class.new(#{base})
RUBY
end
end
end
end

0 comments on commit db1bf58

Please sign in to comment.