Skip to content

Commit 94ccd43

Browse files
authored
Merge pull request rubocop#863 from r7kamura/feature/response-parsed-body
Add `Rails/ResponseParsedBody` cop
2 parents eabfa71 + 0c5ccee commit 94ccd43

File tree

5 files changed

+115
-0
lines changed

5 files changed

+115
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#863](https://github.com/rubocop/rubocop-rails/pull/863): Add `Rails/ResponseParsedBody` cop. ([@r7kamura][])

config/default.yml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,6 +841,17 @@ Rails/RequireDependency:
841841
Enabled: false
842842
VersionAdded: '2.10'
843843

844+
Rails/ResponseParsedBody:
845+
Description: Prefer `response.parsed_body` to `JSON.parse(response.body)`.
846+
Enabled: pending
847+
SafeAutoCorrect: false
848+
VersionAdded: "<<next>>"
849+
Include:
850+
- spec/controllers/**/*.rb
851+
- spec/requests/**/*.rb
852+
- test/controllers/**/*.rb
853+
- test/integration/**/*.rb
854+
844855
Rails/ReversibleMigration:
845856
Description: 'Checks whether the change method of the migration file is reversible.'
846857
StyleGuide: 'https://rails.rubystyle.guide#reversible-migration'
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module Rails
6+
# Prefer `response.parsed_body` to `JSON.parse(response.body)`.
7+
#
8+
# @safety
9+
# This cop's autocorrection is unsafe because Content-Type may not be `application/json`. For example, the
10+
# proprietary Content-Type provided by corporate entities such as `application/vnd.github+json` is not
11+
# supported at `response.parsed_body` by default, so you still have to use `JSON.parse(response.body)` there.
12+
#
13+
# @example
14+
# # bad
15+
# JSON.parse(response.body)
16+
#
17+
# # good
18+
# response.parsed_body
19+
class ResponseParsedBody < Base
20+
extend AutoCorrector
21+
extend TargetRailsVersion
22+
23+
MSG = 'Prefer `response.parsed_body` to `JSON.parse(response.body)`.'
24+
25+
RESTRICT_ON_SEND = %i[parse].freeze
26+
27+
minimum_target_rails_version 5.0
28+
29+
# @!method json_parse_response_body?(node)
30+
def_node_matcher :json_parse_response_body?, <<~PATTERN
31+
(send
32+
(const {nil? cbase} :JSON)
33+
:parse
34+
(send
35+
(send nil? :response)
36+
:body
37+
)
38+
)
39+
PATTERN
40+
41+
def on_send(node)
42+
return unless json_parse_response_body?(node)
43+
44+
add_offense(node) do |corrector|
45+
autocorrect(corrector, node)
46+
end
47+
end
48+
49+
private
50+
51+
def autocorrect(corrector, node)
52+
corrector.replace(node, 'response.parsed_body')
53+
end
54+
end
55+
end
56+
end
57+
end

lib/rubocop/cop/rails_cops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@
9999
require_relative 'rails/render_plain_text'
100100
require_relative 'rails/request_referer'
101101
require_relative 'rails/require_dependency'
102+
require_relative 'rails/response_parsed_body'
102103
require_relative 'rails/reversible_migration'
103104
require_relative 'rails/reversible_migration_method_definition'
104105
require_relative 'rails/root_join_chain'
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::Rails::ResponseParsedBody, :config do
4+
context 'when `response.parsed_body` is used' do
5+
it 'registers no offense' do
6+
expect_no_offenses(<<~RUBY)
7+
expect(response.parsed_body).to eq('foo' => 'bar')
8+
RUBY
9+
end
10+
end
11+
12+
context 'when Rails version is 4.2 or older', :rails42 do
13+
it 'registers no offense' do
14+
expect_no_offenses(<<~RUBY)
15+
expect(JSON.parse(response.body)).to eq('foo' => 'bar')
16+
RUBY
17+
end
18+
end
19+
20+
context 'when `JSON.parse(response.body)` is used' do
21+
it 'registers offense' do
22+
expect_offense(<<~RUBY)
23+
expect(JSON.parse(response.body)).to eq('foo' => 'bar')
24+
^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `response.parsed_body` to `JSON.parse(response.body)`.
25+
RUBY
26+
27+
expect_correction(<<~RUBY)
28+
expect(response.parsed_body).to eq('foo' => 'bar')
29+
RUBY
30+
end
31+
end
32+
33+
context 'when `::JSON.parse(response.body)` is used' do
34+
it 'registers offense' do
35+
expect_offense(<<~RUBY)
36+
expect(::JSON.parse(response.body)).to eq('foo' => 'bar')
37+
^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `response.parsed_body` to `JSON.parse(response.body)`.
38+
RUBY
39+
40+
expect_correction(<<~RUBY)
41+
expect(response.parsed_body).to eq('foo' => 'bar')
42+
RUBY
43+
end
44+
end
45+
end

0 commit comments

Comments
 (0)