Class: RuboCop::Cop::DevDoc::Style::StringSymbolComparison
- Inherits:
-
Base
- Object
- Base
- RuboCop::Cop::DevDoc::Style::StringSymbolComparison
- Defined in:
- lib/rubocop/cop/dev_doc/style/string_symbol_comparison.rb
Overview
Flag direct == / != comparisons between a known-string source
and a symbol literal. Such comparisons are silently always false
('draft' == :draft is false in Ruby), so they signal that the
caller forgot to convert at the boundary.
Rationale
Strings and symbols are not equal in Ruby, and string-typed values
arrive from boundaries the developer doesn't control: HTTP params,
request headers, ENV. Comparing one of these directly against a
symbol literal is a guaranteed bug. Allow-list into a symbol at the
boundary instead — see
best_practices/backend/en/01a_defensive_programming.md item 7.
❌
if params[:status] == :draft # always false
✔ Allow-list into a symbol at the boundary, then compare
@filter_status = glib_allowlist_symbol_param(params[:status], STATUSES, default: :draft)
if @filter_status == :draft
A bare &.to_sym conversion would also fix the always-false bug,
but it lets ANY client value into the symbol domain — the sibling
DevDoc/Style/AvoidSymbolizingBoundaryInput flags exactly that.
The two cops are a complementary pair: this one polices comparing
without converting; that one polices converting without validating.
Sources detected
params[…]request.headers[…]ENV[…]
Limitations
The cop only catches the direct comparison form. Once the value flows into a local or instance variable, type information is lost and Rubocop cannot trace it back to the original string source. Those cases are caught by review.
Constant Summary collapse
- MSG =
'Comparing string-typed `%<source>s` to a symbol literal is always false. ' \ 'Allow-list it into a symbol at the boundary ' \ '(`glib_allowlist_symbol_param(value, ALLOWED, default:)`) or compare against ' \ 'a string instead (see backend/01a_defensive_programming.md item 7).'.freeze
- RESTRICT_ON_SEND =
%i[== !=].freeze
Instance Method Summary collapse
Instance Method Details
#on_send(node) ⇒ Object
71 72 73 74 75 76 77 78 79 80 |
# File 'lib/rubocop/cop/dev_doc/style/string_symbol_comparison.rb', line 71 def on_send(node) lhs = node.receiver rhs = node.first_argument return unless lhs && rhs source_node = pick_string_source(lhs, rhs) return unless source_node add_offense(node, message: format(MSG, source: source_node.source)) end |