class RubbyCop::Cop::Style::SafeNavigation
This cop transforms usages of a method call safeguarded by a non `nil` check for the variable whose method is being called to safe navigation (`&.`).
Configuration option: ConvertCodeThatCanStartToReturnNil The default for this is `false`. When configured to `true`, this will check for code in the format `!foo.nil? && foo.bar`. As it is written, the return of this code is limited to `false` and whatever the return of the method is. If this is converted to safe navigation, `foo&.bar` can start returning `nil` as well as what the method returns.
@example
# bad foo.bar if foo foo.bar(param1, param2) if foo foo.bar { |e| e.something } if foo foo.bar(param) { |e| e.something } if foo foo.bar if !foo.nil? foo.bar unless !foo foo.bar unless foo.nil? foo && foo.bar foo && foo.bar(param1, param2) foo && foo.bar { |e| e.something } foo && foo.bar(param) { |e| e.something } # good foo&.bar foo&.bar(param1, param2) foo&.bar { |e| e.something } foo&.bar(param) { |e| e.something } foo.nil? || foo.bar !foo || foo.bar # Methods that `nil` will `respond_to?` should not be converted to # use safe navigation foo.to_i if foo
Constants
- MSG
- NIL_METHODS
Public Instance Methods
allowed_if_condition?(node)
click to toggle source
# File lib/rubbycop/cop/style/safe_navigation.rb, line 100 def allowed_if_condition?(node) node.if_type? && (node.else? || node.elsif?) end
autocorrect(node)
click to toggle source
# File lib/rubbycop/cop/style/safe_navigation.rb, line 113 def autocorrect(node) if node.if_type? _check, body, = *node.node_parts else _check, body = *node end method_call, = *body if body.block_type? lambda do |corrector| corrector.remove(begin_range(node, body)) corrector.remove(end_range(node, body)) corrector.insert_before((method_call || body).loc.dot, '&') end end
check_node(node)
click to toggle source
# File lib/rubbycop/cop/style/safe_navigation.rb, line 89 def check_node(node) return if target_ruby_version < 2.3 return if allowed_if_condition?(node) checked_variable, receiver, method = extract_parts(node) return unless receiver == checked_variable return if NIL_METHODS.include?(method) return unless method =~ /\w+[=!?]?/ add_offense(node, :expression) end
extract_parts(node)
click to toggle source
# File lib/rubbycop/cop/style/safe_navigation.rb, line 104 def extract_parts(node) if cop_config['ConvertCodeThatCanStartToReturnNil'] safe_navigation_candidate(node) || candidate_that_may_introduce_nil(node) else safe_navigation_candidate(node) end end
on_and(node)
click to toggle source
# File lib/rubbycop/cop/style/safe_navigation.rb, line 81 def on_and(node) check_node(node) end
on_if(node)
click to toggle source
# File lib/rubbycop/cop/style/safe_navigation.rb, line 75 def on_if(node) return if node.ternary? check_node(node) end
on_or(node)
click to toggle source
# File lib/rubbycop/cop/style/safe_navigation.rb, line 85 def on_or(node) check_node(node) end
Private Instance Methods
begin_range(node, method_call)
click to toggle source
# File lib/rubbycop/cop/style/safe_navigation.rb, line 131 def begin_range(node, method_call) Parser::Source::Range.new(node.loc.expression.source_buffer, node.loc.expression.begin_pos, method_call.loc.expression.begin_pos) end
end_range(node, method_call)
click to toggle source
# File lib/rubbycop/cop/style/safe_navigation.rb, line 137 def end_range(node, method_call) Parser::Source::Range.new(node.loc.expression, method_call.loc.expression.end_pos, node.loc.expression.end_pos) end