Skip to content

Commit

Permalink
Support Nokogiri::HTML.parse and Nokogiri::HTML5.parse on `Rails/…
Browse files Browse the repository at this point in the history
…ResponseParsedBody`
  • Loading branch information
r7kamura committed Dec 7, 2023
1 parent dc6cebc commit 8773d37
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 11 deletions.
1 change: 1 addition & 0 deletions changelog/change_support_nokogiri_html_parse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#1181](https://github.com/rubocop/rubocop-rails/pull/1181): Support `Nokogiri::HTML.parse` and `Nokogiri::HTML5.parse` on `Rails/ResponseParsedBody`. ([@r7kamura][])
2 changes: 1 addition & 1 deletion config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -902,7 +902,7 @@ Rails/RequireDependency:
VersionAdded: '2.10'

Rails/ResponseParsedBody:
Description: Prefer `response.parsed_body` to `JSON.parse(response.body)`.
Description: Prefer `response.parsed_body` to custom parsing logic for `response.body`.
Enabled: pending
Safe: false
VersionAdded: '2.18'
Expand Down
62 changes: 52 additions & 10 deletions lib/rubocop/cop/rails/response_parsed_body.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,30 @@
module RuboCop
module Cop
module Rails
# Prefer `response.parsed_body` to `JSON.parse(response.body)`.
# Prefer `response.parsed_body` to custom parsing logic for `response.body`.
#
# @safety
# This cop is unsafe because Content-Type may not be `application/json`. For example, the proprietary
# Content-Type provided by corporate entities such as `application/vnd.github+json` is not supported at
# `response.parsed_body` by default, so you still have to use `JSON.parse(response.body)` there.
# This cop is unsafe because Content-Type may not be `application/json` or `text/html`.
# For example, the proprietary Content-Type provided by corporate entities such as
# `application/vnd.github+json` is not supported at `response.parsed_body` by default,
# so you still have to use `JSON.parse(response.body)` there.
#
# @example
# # bad
# JSON.parse(response.body)
#
# # bad
# Nokogiri::HTML.parse(response.body)
#
# # bad
# Nokogiri::HTML5.parse(response.body)
#
# # good
# response.parsed_body
class ResponseParsedBody < Base
extend AutoCorrector
extend TargetRailsVersion

MSG = 'Prefer `response.parsed_body` to `JSON.parse(response.body)`.'

RESTRICT_ON_SEND = %i[parse].freeze

minimum_target_rails_version 5.0
Expand All @@ -38,19 +43,56 @@ class ResponseParsedBody < Base
)
PATTERN

# @!method nokogiri_html_parse_response_body(node)
def_node_matcher :nokogiri_html_parse_response_body, <<~PATTERN
(send
(const
(const {nil? cbase} :Nokogiri)
${:HTML :HTML5}
)
:parse
(send
(send nil? :response)
:body
)
)
PATTERN

def on_send(node)
return unless json_parse_response_body?(node)
check_json_parse_response_body(node)

add_offense(node) do |corrector|
autocorrect(corrector, node)
end
return unless target_rails_version >= 7.1

check_nokogiri_html_parse_response_body(node)
end

private

def autocorrect(corrector, node)
corrector.replace(node, 'response.parsed_body')
end

def check_json_parse_response_body(node)
return unless json_parse_response_body?(node)

add_offense(
node,
message: 'Prefer `response.parsed_body` to `JSON.parse(response.body)`.'
) do |corrector|
autocorrect(corrector, node)
end
end

def check_nokogiri_html_parse_response_body(node)
return unless (const = nokogiri_html_parse_response_body(node))

add_offense(
node,
message: "Prefer `response.parsed_body` to `Nokogiri::#{const}.parse(response.body)`."
) do |corrector|
autocorrect(corrector, node)
end
end
end
end
end
Expand Down
34 changes: 34 additions & 0 deletions spec/rubocop/cop/rails/response_parsed_body_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,38 @@
RUBY
end
end

context 'when `Nokogiri::HTML.parse(response.body)` is used on Rails 7.0', :rails70 do
it 'registers no offense' do
expect_no_offenses(<<~RUBY)
Nokogiri::HTML.parse(response.body)
RUBY
end
end

context 'when `Nokogiri::HTML.parse(response.body)` is used on Rails 7.1', :rails71 do
it 'registers offense' do
expect_offense(<<~RUBY)
Nokogiri::HTML.parse(response.body)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `response.parsed_body` to `Nokogiri::HTML.parse(response.body)`.
RUBY

expect_correction(<<~RUBY)
response.parsed_body
RUBY
end
end

context 'when `Nokogiri::HTML5.parse(response.body)` is used on Rails 7.1', :rails71 do
it 'registers offense' do
expect_offense(<<~RUBY)
Nokogiri::HTML5.parse(response.body)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `response.parsed_body` to `Nokogiri::HTML5.parse(response.body)`.
RUBY

expect_correction(<<~RUBY)
response.parsed_body
RUBY
end
end
end

0 comments on commit 8773d37

Please sign in to comment.