-
-
Notifications
You must be signed in to change notification settings - Fork 267
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #242 from tabuchi0919/tag-instead-of-content-tag
Add new Rails/ContentTag cop
- Loading branch information
Showing
7 changed files
with
229 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# frozen_string_literal: true | ||
|
||
module RuboCop | ||
module Cop | ||
module Rails | ||
# This cop checks that `tag` is used instead of `content_tag` | ||
# because `content_tag` is legacy syntax. | ||
# | ||
# @example | ||
# # bad | ||
# content_tag(:p, 'Hello world!') | ||
# content_tag(:br) | ||
# | ||
# # good | ||
# tag.p('Hello world!') | ||
# tag.br | ||
class ContentTag < Cop | ||
include RangeHelp | ||
extend TargetRailsVersion | ||
|
||
minimum_target_rails_version 5.1 | ||
|
||
MSG = 'Use `tag` instead of `content_tag`.' | ||
|
||
def on_send(node) | ||
return unless node.method?(:content_tag) | ||
|
||
add_offense(node) | ||
end | ||
|
||
def autocorrect(node) | ||
lambda do |corrector| | ||
if method_name?(node.first_argument) | ||
replace_method_with_tag_method(corrector, node) | ||
remove_first_argument(corrector, node) | ||
else | ||
corrector.replace(node.loc.selector, 'tag') | ||
end | ||
end | ||
end | ||
|
||
private | ||
|
||
def method_name?(node) | ||
return false unless node.str_type? || node.sym_type? | ||
|
||
/^[a-zA-Z_][a-zA-Z_0-9]*$/.match?(node.value) | ||
end | ||
|
||
def replace_method_with_tag_method(corrector, node) | ||
corrector.replace( | ||
node.loc.selector, | ||
"tag.#{node.first_argument.value}" | ||
) | ||
end | ||
|
||
def remove_first_argument(corrector, node) | ||
if node.arguments.length > 1 | ||
corrector.remove( | ||
range_between(child_node_beg(node, 0), child_node_beg(node, 1)) | ||
) | ||
elsif node.arguments.length == 1 | ||
corrector.remove(node.arguments[0].loc.expression) | ||
end | ||
end | ||
|
||
def child_node_beg(node, index) | ||
node.arguments[index].loc.expression.begin_pos | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
# frozen_string_literal: true | ||
|
||
RSpec.describe RuboCop::Cop::Rails::ContentTag, :config do | ||
subject(:cop) { described_class.new(config) } | ||
|
||
context 'Rails 5.0', :rails50 do | ||
it 'does not register an offense' do | ||
expect_no_offenses(<<~RUBY) | ||
content_tag(:p, 'Hello world!') | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense with empty tag' do | ||
expect_no_offenses(<<~RUBY) | ||
content_tag(:br) | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense with array of classnames' do | ||
expect_no_offenses(<<~RUBY) | ||
content_tag(:div, "Hello world!", class: ["strong", "highlight"]) | ||
RUBY | ||
end | ||
|
||
it 'does not register an offense with nested content_tag' do | ||
expect_no_offenses(<<~RUBY) | ||
content_tag(:div) { content_tag(:strong, 'Hi') } | ||
RUBY | ||
end | ||
end | ||
|
||
context 'Rails 5.1', :rails51 do | ||
it 'corrects an offence' do | ||
expect_offense(<<~RUBY) | ||
content_tag(:p, 'Hello world!') | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `tag` instead of `content_tag`. | ||
RUBY | ||
expect_correction(<<~RUBY) | ||
tag.p('Hello world!') | ||
RUBY | ||
end | ||
|
||
it 'corrects an offence with empty tag' do | ||
expect_offense(<<~RUBY) | ||
content_tag(:br) | ||
^^^^^^^^^^^^^^^^ Use `tag` instead of `content_tag`. | ||
RUBY | ||
expect_correction(<<~RUBY) | ||
tag.br() | ||
RUBY | ||
end | ||
|
||
it 'corrects an offence with array of classnames' do | ||
expect_offense(<<~RUBY) | ||
content_tag(:div, "Hello world!", class: ["strong", "highlight"]) | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `tag` instead of `content_tag`. | ||
RUBY | ||
expect_correction(<<~RUBY) | ||
tag.div("Hello world!", class: ["strong", "highlight"]) | ||
RUBY | ||
end | ||
|
||
it 'corrects an offence with nested content_tag' do | ||
expect_offense(<<~RUBY) | ||
content_tag(:div) { content_tag(:strong, 'Hi') } | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `tag` instead of `content_tag`. | ||
^^^^^^^^^^^^^^^^^ Use `tag` instead of `content_tag`. | ||
RUBY | ||
expect_correction(<<~RUBY) | ||
tag.div() { tag.strong('Hi') } | ||
RUBY | ||
end | ||
|
||
it 'corrects an offence when first argument is hash' do | ||
expect_offense(<<~RUBY) | ||
content_tag({foo: 1}) | ||
^^^^^^^^^^^^^^^^^^^^^ Use `tag` instead of `content_tag`. | ||
RUBY | ||
expect_correction(<<~RUBY) | ||
tag({foo: 1}) | ||
RUBY | ||
end | ||
|
||
it 'corrects an offence when first argument is non-identifier string' do | ||
expect_offense(<<~RUBY) | ||
content_tag('foo-bar') | ||
^^^^^^^^^^^^^^^^^^^^^^ Use `tag` instead of `content_tag`. | ||
RUBY | ||
expect_correction(<<~RUBY) | ||
tag('foo-bar') | ||
RUBY | ||
end | ||
|
||
it 'does not register an offence when `tag` is used with an argument' do | ||
expect_no_offenses(<<~RUBY) | ||
tag.p('Hello world!') | ||
RUBY | ||
end | ||
|
||
it 'does not register an offence when `tag` is used without arguments' do | ||
expect_no_offenses(<<~RUBY) | ||
tag.br | ||
RUBY | ||
end | ||
|
||
it 'does not register an offence when `tag` is used with arguments' do | ||
expect_no_offenses(<<~RUBY) | ||
tag.div("Hello world!", class: ["strong", "highlight"]) | ||
RUBY | ||
end | ||
|
||
it 'does not register an offence when `tag` is nested' do | ||
expect_no_offenses(<<~RUBY) | ||
tag.div() { tag.strong('Hi') } | ||
RUBY | ||
end | ||
end | ||
end |