class RuboCop::Cop::Style::DigChain
Check for chained ‘dig` calls that can be collapsed into a single `dig`.
@safety
This cop is unsafe because it cannot be guaranteed that the receiver is an `Enumerable` or does not have a nonstandard implementation of `dig`.
@example
# bad x.dig(:foo).dig(:bar).dig(:baz) x.dig(:foo, :bar).dig(:baz) x.dig(:foo, :bar)&.dig(:baz) # good x.dig(:foo, :bar, :baz) # good - `dig`s cannot be combined x.dig(:foo).bar.dig(:baz)
Constants
- MSG
- RESTRICT_ON_SEND
Public Instance Methods
Source
# File lib/rubocop/cop/style/dig_chain.rb, line 33 def on_send(node) return if ignored_node?(node) return unless node.loc.dot return unless dig?(node) range, arguments = inspect_chain(node) return if invalid_arguments?(arguments) return unless range register_offense(node, range, arguments) end
Also aliased as: on_csend
Private Instance Methods
Source
# File lib/rubocop/cop/style/dig_chain.rb, line 49 def inspect_chain(node) arguments = node.arguments.dup end_range = node.source_range.end while dig?(node = node.receiver) begin_range = node.loc.selector arguments.unshift(*node.arguments) ignore_node(node) end return unless begin_range [begin_range.join(end_range), arguments] end
Walk up the method chain while the receiver is ‘dig` with arguments.
Source
# File lib/rubocop/cop/style/dig_chain.rb, line 64 def invalid_arguments?(arguments) # If any of the arguments are arguments forwarding (`...`), it can only be the # first argument, or else the resulting code will have a syntax error. return false unless arguments&.any? forwarded_args_index = arguments.index(&:forwarded_args_type?) forwarded_args_index && forwarded_args_index < (arguments.size - 1) end
Source
# File lib/rubocop/cop/style/dig_chain.rb, line 74 def register_offense(node, range, arguments) arguments = arguments.map(&:source).join(', ') replacement = "dig(#{arguments})" add_offense(range, message: format(MSG, replacement: replacement)) do |corrector| corrector.replace(range, replacement) comments_in_range(node).reverse_each do |comment| corrector.insert_before(node, "#{comment.source}\n") end end end