Module: RuboCop::Cop::IndexedMethodArity
| Relationships & Source Files | |
| Extension / Inclusion / Inheritance Descendants | |
|
Included In:
| |
| Defined in: | lib/rubocop/cop/mixin/indexed_method_arity.rb |
Overview
Shared machinery for cops that compare a call site’s arguments against
a method signature from the project index (Rubydex::Signature).
A signature is reduced to a shape - [min, max, has_keywords] where
max is nil for a rest parameter - and the number of positional
arguments a call passes is counted with Ruby’s semantics for trailing
keyword hashes: keywords passed to a method with no keyword parameters
collapse into a single positional hash.
Instance Method Summary
- #arity_satisfied?(given, min, max) ⇒ Boolean private
- #double_splat?(hash_node) ⇒ Boolean private
- #expected_range(min, max) private
- #forwards_arguments?(arguments) ⇒ Boolean private
-
#indexed_member_shape(member)
private
The agreed
[min, max, has_keywords]shape of an indexed member’s method definitions, or nil when the member is not backed by plain method definitions (attr, alias), has no signature, forwards arguments, or its definitions disagree on arity (e.g. - #keyword_hash(node) private
- #keyword_parameters?(signature) ⇒ Boolean private
- #maximum_positional(signature, min) private
-
#positional_argument_count(node, callee_has_keywords)
private
The number of positional arguments the call passes, or nil when it cannot be determined statically (argument forwarding).
- #shape_for(signature) private
- #signature_shape(signatures) private
Instance Method Details
#arity_satisfied?(given, min, max) ⇒ Boolean (private)
# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 16
def arity_satisfied?(given, min, max) given >= min && (max.nil? || given <= max) end
#double_splat?(hash_node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 89
def double_splat?(hash_node) hash_node.each_child_node.any?(&:kwsplat_type?) end
#expected_range(min, max) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 20
def expected_range(min, max) return "#{min}+" if max.nil? return min.to_s if min == max "#{min}..#{max}" end
#forwards_arguments?(arguments) ⇒ Boolean (private)
# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 79
def forwards_arguments?(arguments) arguments.any? do |argument| argument.type?(:splat, :forwarded_args, :forwarded_restarg, :forwarded_kwrestarg) end end
#indexed_member_shape(member) (private)
The agreed [min, max, has_keywords] shape of an indexed member’s
method definitions, or nil when the member is not backed by plain
method definitions (attr, alias), has no signature, forwards
arguments, or its definitions disagree on arity (e.g. reopened with
a different one).
# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 32
def indexed_member_shape(member) definitions = member.definitions.grep(Rubydex::MethodDefinition) return nil if definitions.empty? signature_shape(definitions.flat_map(&:signatures)) end
#keyword_hash(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 85
def keyword_hash(node) node if node&.hash_type? && !node.braces? end
#keyword_parameters?(signature) ⇒ Boolean (private)
# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 58
def keyword_parameters?(signature) !signature.keyword_parameters.empty? || !signature.optional_keyword_parameters.empty? || !signature.rest_keyword_parameter.nil? end
#maximum_positional(signature, min) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 52
def maximum_positional(signature, min) return nil if signature.rest_positional_parameter min + signature.optional_positional_parameters.size end
#positional_argument_count(node, callee_has_keywords) (private)
The number of positional arguments the call passes, or nil when it cannot be determined statically (argument forwarding).
# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 66
def positional_argument_count(node, callee_has_keywords) arguments = node.arguments return nil if forwards_arguments?(arguments) arguments = arguments[0...-1] if arguments.last&.block_pass_type? return arguments.size unless (keyword_hash = keyword_hash(arguments.last)) return nil if double_splat?(keyword_hash) # A keyword-style hash passed to a method with no keyword parameters is # received as a single positional hash argument. callee_has_keywords ? arguments.size - 1 : arguments.size end
#shape_for(signature) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 44
def shape_for(signature) return nil if signature.forward_parameter min = signature.positional_parameters.size + signature.post_parameters.size [min, maximum_positional(signature, min), keyword_parameters?(signature)] end
#signature_shape(signatures) (private)
[ GitHub ]# File 'lib/rubocop/cop/mixin/indexed_method_arity.rb', line 39
def signature_shape(signatures) shapes = signatures.filter_map { |signature| shape_for(signature) }.uniq shapes.one? ? shapes.first : nil end