class RuboCop::Cop::Lint::SafeNavigationChain
The safe navigation operator returns nil if the receiver is nil. If you chain an ordinary method call after a safe navigation operator, it raises NoMethodError. We should use a safe navigation operator after a safe navigation operator. This cop checks for the problem outlined above.
@example
# bad x&.foo.bar x&.foo + bar x&.foo[bar] # good x&.foo&.bar x&.foo || bar
Constants
- MSG
- PLUS_MINUS_METHODS
Public Instance Methods
Source
# File lib/rubocop/cop/lint/safe_navigation_chain.rb, line 40 def on_send(node) return unless require_safe_navigation?(node) bad_method?(node) do |safe_nav, method| return if nil_methods.include?(method) || PLUS_MINUS_METHODS.include?(node.method_name) begin_range = node.loc.dot || safe_nav.source_range.end location = begin_range.join(node.source_range.end) add_offense(location) do |corrector| autocorrect(corrector, offense_range: location, send_node: node) end end end
Private Instance Methods
Source
# File lib/rubocop/cop/lint/safe_navigation_chain.rb, line 86 def autocorrect(corrector, offense_range:, send_node:) corrector.replace( offense_range, add_safe_navigation_operator(offense_range: offense_range, send_node: send_node) ) corrector.wrap(send_node, '(', ')') if require_parentheses?(send_node) end
@param [RuboCop::Cop::Corrector] corrector @param [Parser::Source::Range] offense_range @param [RuboCop::AST::SendNode] send_node
Source
# File lib/rubocop/cop/lint/safe_navigation_chain.rb, line 95 def brackets?(send_node) send_node.method?(:[]) || send_node.method?(:[]=) end
Source
# File lib/rubocop/cop/lint/safe_navigation_chain.rb, line 108 def operator_inside_collection_literal?(send_node) # If an operator call (without a dot) is inside an array or a hash, it needs # to be parenthesized when converted to safe navigation. send_node.parent&.type?(:array, :pair) && !send_node.loc.dot end
Source
# File lib/rubocop/cop/lint/safe_navigation_chain.rb, line 99 def require_parentheses?(send_node) return true if operator_inside_collection_literal?(send_node) return false unless send_node.comparison_method? return false unless (node = send_node.parent) (node.respond_to?(:logical_operator?) && node.logical_operator?) || (node.respond_to?(:comparison_method?) && node.comparison_method?) end