class RuboCop::Cop::Lint::FormatParameterMismatch
This lint sees if there is a mismatch between the number of expected fields for format/sprintf/#% and what is actually passed as arguments.
@example
format('A value: %s and another: %i', a_value)
Constants
- FIELD_REGEX
- KERNEL
- MSG
- NAMED_FIELD_REGEX
- NAMED_INTERPOLATION
- PERCENT
- PERCENT_PERCENT
- SHOVEL
- STRING_TYPES
Public Instance Methods
on_send(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 28 def on_send(node) add_offense(node, :selector) if offending_node?(node) end
Private Instance Methods
called_on_string?(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 46 def called_on_string?(node) receiver_node, _method, format_string, = *node if receiver_node.nil? || receiver_node.const_type? format_string && format_string.str_type? else receiver_node.str_type? end end
count_matches(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 81 def count_matches(node) receiver_node, _method_name, *args = *node if (sprintf?(node) || format?(node)) && !heredoc?(node) number_of_args_for_format = (args.size - 1) number_of_expected_fields = expected_fields_count(args.first) elsif percent?(node) && args.first.array_type? number_of_expected_fields = expected_fields_count(receiver_node) number_of_args_for_format = args.first.child_nodes.size else number_of_args_for_format = number_of_expected_fields = :unknown end [number_of_args_for_format, number_of_expected_fields] end
expected_fields_count(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 109 def expected_fields_count(node) return :unknown unless node.str_type? return 1 if node.source =~ NAMED_INTERPOLATION node .source .scan(FIELD_REGEX) .select { |x| x.first != PERCENT_PERCENT } .reduce(0) { |a, e| a + (e[2] =~ /\*/ ? 2 : 1) } end
format?(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 120 def format?(node) format_method?(:format, node) end
format_method?(name, node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 97 def format_method?(name, node) receiver, method_name, *args = *node if receiver && receiver.const_type? return false unless receiver.loc.name.is?(KERNEL) end return false unless method_name == name args.size > 1 && args.first.str_type? end
heredoc?(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 75 def heredoc?(node) _receiver, _name, args = *node args.source[0, 2] == SHOVEL end
message(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 142 def message(node) _receiver, method_name, *_args = *node num_args_for_format, num_expected_fields = count_matches(node) method_name = 'String#%' if PERCENT == method_name.to_s format(MSG, num_args_for_format, method_name, num_expected_fields) end
named_mode?(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 55 def named_mode?(node) receiver_node, _method_name, *args = *node relevant_node = if sprintf?(node) || format?(node) args.first elsif percent?(node) receiver_node end !relevant_node.source.scan(NAMED_FIELD_REGEX).empty? end
node_with_splat_args?(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 67 def node_with_splat_args?(node) return false if percent?(node) _receiver_node, _method_name, *args = *node args.butfirst.any? { |arg| arg.type == :splat } end
offending_node?(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 34 def offending_node?(node) return false unless called_on_string?(node) return false unless sprintf?(node) || format?(node) || percent?(node) return false if named_mode?(node) || node_with_splat_args?(node) num_of_format_args, num_of_expected_fields = count_matches(node) num_of_format_args != :unknown && num_of_expected_fields != :unknown && num_of_expected_fields != num_of_format_args end
percent?(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 128 def percent?(node) receiver_node, method_name, *arg_nodes = *node percent = method_name == :% && (STRING_TYPES.include?(receiver_node.type) || arg_nodes[0].array_type?) if percent && STRING_TYPES.include?(receiver_node.type) return false if heredoc?(node) end percent end
sprintf?(node)
click to toggle source
# File lib/rubocop/cop/lint/format_parameter_mismatch.rb, line 124 def sprintf?(node) format_method?(:sprintf, node) end