Skip to content

Commit

Permalink
Add new Rails/RenderText cop
Browse files Browse the repository at this point in the history
  • Loading branch information
fatkodima committed Jun 30, 2020
1 parent 80b0f77 commit 3a41b0b
Show file tree
Hide file tree
Showing 7 changed files with 136 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

* [#276](https://github.com/rubocop-hq/rubocop-rails/pull/276): Add new `Rails/RenderText` cop. ([@fatkodima][])
* [#271](https://github.com/rubocop-hq/rubocop-rails/pull/271): Add new `Rails/RenderInline` cop. ([@fatkodima][])
* [#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][])
Expand Down
6 changes: 6 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,12 @@ Rails/RenderInline:
Enabled: 'pending'
VersionAdded: '2.7'

Rails/RenderText:
Description: 'Prefer `render plain:` over `render text:`.'
StyleGuide: 'https://rails.rubystyle.guide/#plain-text-rendering'
Enabled: 'pending'
VersionAdded: '2.7'

Rails/RequestReferer:
Description: 'Use consistent syntax for request.referer.'
Enabled: true
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 @@ -58,6 +58,7 @@
* xref:cops_rails.adoc#railsrefutemethods[Rails/RefuteMethods]
* xref:cops_rails.adoc#railsrelativedateconstant[Rails/RelativeDateConstant]
* xref:cops_rails.adoc#railsrenderinline[Rails/RenderInline]
* xref:cops_rails.adoc#railsrendertext[Rails/RenderText]
* xref:cops_rails.adoc#railsrequestreferer[Rails/RequestReferer]
* xref:cops_rails.adoc#railsreversiblemigration[Rails/ReversibleMigration]
* xref:cops_rails.adoc#railssafenavigation[Rails/SafeNavigation]
Expand Down
33 changes: 33 additions & 0 deletions docs/modules/ROOT/pages/cops_rails.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2820,6 +2820,39 @@ end

* https://rails.rubystyle.guide/#inline-rendering

== Rails/RenderText

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

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

This cop identifies places where `render text:` can be
replaced with `render plain:`.

=== Examples

[source,ruby]
----
# bad - sets MIME type to `text/html`
render text: 'Ruby!'
# bad - requires explicit MIME type declaration
render text: 'Ruby!', content_type: 'text/plain'
# good - short and precise
render plain: 'Ruby!'
----

=== References

* https://rails.rubystyle.guide/#plain-text-rendering

== Rails/RequestReferer

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

module RuboCop
module Cop
module Rails
# This cop identifies places where `render text:` can be
# replaced with `render plain:`.
#
# @example
# # bad - sets MIME type to `text/html`
# render text: 'Ruby!'
#
# # bad - requires explicit MIME type declaration
# render text: 'Ruby!', content_type: 'text/plain'
#
# # good - short and precise
# render plain: 'Ruby!'
#
class RenderText < Cop
MSG = 'Prefer `render plain:` over `render text:`.'

def_node_matcher :render_text_call?, <<~PATTERN
(send nil? :render $(hash <$(pair (sym :text) $_) ...>))
PATTERN

def on_send(node)
add_offense(node) if render_text_call?(node)
end

def autocorrect(node)
render_text_call?(node) do |options_node, option_node, option_value|
content_type_node = find_content_type(options_node)

if content_type_node && content_type_node.value.value == 'text/plain'
rest_options = options_node.pairs - [option_node, content_type_node]

lambda do |corrector|
corrector.replace(
node,
replacement(rest_options, option_value)
)
end
end
end
end

private

def find_content_type(node)
node.pairs.find { |p| p.key.value.to_sym == :content_type }
end

def replacement(rest_options, option_value)
if rest_options.any?
"render plain: #{option_value.source}, #{rest_options.map(&:source).join(', ')}"
else
"render plain: #{option_value.source}"
end
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 @@ -60,6 +60,7 @@
require_relative 'rails/refute_methods'
require_relative 'rails/relative_date_constant'
require_relative 'rails/render_inline'
require_relative 'rails/render_text'
require_relative 'rails/request_referer'
require_relative 'rails/reversible_migration'
require_relative 'rails/safe_navigation'
Expand Down
31 changes: 31 additions & 0 deletions spec/rubocop/cop/rails/render_text_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# frozen_string_literal: true

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

it 'registers an offense when using `render text:`' do
expect_offense(<<~RUBY)
render text: 'Ruby!'
^^^^^^^^^^^^^^^^^^^^ Prefer `render plain:` over `render text:`.
RUBY

expect_no_corrections
end

it 'registers an offense and corrects when using `render text:` with `content_type: "text/plain"`' do
expect_offense(<<~RUBY)
render text: 'Ruby!', content_type: 'text/plain'
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `render plain:` over `render text:`.
RUBY

expect_correction(<<~RUBY)
render plain: 'Ruby!'
RUBY
end

it 'does not register an offense when using `render plain:`' do
expect_no_offenses(<<~RUBY)
render plain: 'Ruby!'
RUBY
end
end

0 comments on commit 3a41b0b

Please sign in to comment.