Class: RuboCop::Cop::Naming::PredicateMethod
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
::RuboCop::Cop::Base ,
::RuboCop::ExcludeLimit ,
NodePattern::Macros,
RuboCop::AST::Sexp
|
|
Instance Chain:
|
|
Inherits: |
RuboCop::Cop::Base
|
Defined in: | lib/rubocop/cop/naming/predicate_method.rb |
Overview
Checks that predicate methods end with ?
and non-predicate methods do not.
The names of predicate methods (methods that return a boolean value) should end in a question mark. Methods that don’t return a boolean, shouldn’t end in a question mark.
The cop assesses a predicate method as one that returns boolean values. Likewise, a method that only returns literal values is assessed as non-predicate. Other predicate method calls are assumed to return boolean values. The cop does not make an assessment if the return type is unknown (non-predicate method calls, variables, etc.).
Note
|
Operator methods (def == , etc.) are ignored.
|
By default, the cop runs in conservative
mode, which allows a method to be named
with a question mark as long as at least one return value is boolean. In aggressive
mode, methods with a question mark will register an offense if any known non-boolean
return values are detected.
The cop also has ::RuboCop::Cop::AllowedMethods
configuration in order to prevent the cop from
registering an offense from a method name that does not confirm to the naming
guidelines. By default, call
is allowed. The cop also has AllowedPatterns
configuration to allow method names by regular expression.
The cop can furthermore be configured to allow all bang methods (method names
ending with !
), with AllowBangMethods: true
(default false).
Constant Summary
-
MSG_NON_PREDICATE =
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 128'Non-predicate method names should not end with `?`.'
-
MSG_PREDICATE =
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 127'Predicate method names should end with `?`.'
::RuboCop::Cop::Base
- Inherited
Class Attribute Summary
::RuboCop::Cop::Base
- Inherited
.gem_requirements, .lint?, | |
.support_autocorrect? | Returns if class supports autocorrect. |
.support_multiple_source? | Override if your cop should be called repeatedly for multiple investigations Between calls to |
Class Method Summary
::RuboCop::Cop::Base
- Inherited
.autocorrect_incompatible_with | List of cops that should not try to autocorrect at the same time as this cop. |
.badge | Naming. |
.callbacks_needed, .cop_name, .department, | |
.documentation_url | Returns a url to view this cops documentation online. |
.exclude_from_registry | Call for abstract Cop classes. |
.inherited, | |
.joining_forces | Override and return the Force class(es) you need to join. |
.match? | Returns true if the cop name or the cop namespace matches any of the given names. |
.new, | |
.requires_gem | Register a version requirement for the given gem name. |
.restrict_on_send |
::RuboCop::ExcludeLimit
- Extended
exclude_limit | Sets up a configuration option to have an exclude limit tracked. |
transform |
Instance Attribute Summary
- #allow_bang_methods? ⇒ Boolean readonly private
- #conservative? ⇒ Boolean readonly private
::RuboCop::Cop::AllowedMethods
- Included
::RuboCop::Cop::Base
- Inherited
::RuboCop::Cop::AutocorrectLogic
- Included
Instance Method Summary
- #on_def(node) (also: #on_defs)
-
#on_defs(node)
Alias for #on_def.
- #acceptable?(return_values) ⇒ Boolean private
- #all_return_values_boolean?(return_values) ⇒ Boolean private
- #allowed?(node) ⇒ Boolean private
- #allowed_bang_method?(node) ⇒ Boolean private
- #and_or?(node) ⇒ Boolean private
- #boolean_return?(value) ⇒ Boolean private
- #extract_and_or_clauses(node) private
- #extract_conditional_branches(node) private
- #extract_return_value(node) private
- #last_value(node) private
- #potential_non_predicate?(return_values) ⇒ Boolean private
- #process_return_values(return_values) private
- #return_values(node) private
- #unknown_method_call?(value) ⇒ Boolean private
::RuboCop::Cop::AllowedPattern
- Included
#allowed_line?, #allowed_patterns, #cop_config_deprecated_methods_values, #cop_config_patterns_values, #ignored_line?, #matches_allowed_pattern?, #matches_ignored_pattern? |
::RuboCop::Cop::AllowedMethods
- Included
::RuboCop::Cop::Base
- Inherited
#add_global_offense | Adds an offense that has no particular location. |
#add_offense | Adds an offense on the specified range (or node with an expression) Unless that offense is disabled for this range, a corrector will be yielded to provide the cop the opportunity to autocorrect the offense. |
#begin_investigation | Called before any investigation. |
#callbacks_needed, | |
#cop_config | Configuration Helpers. |
#cop_name, #excluded_file?, | |
#external_dependency_checksum | This method should be overridden when a cop’s behavior depends on state that lives outside of these locations: |
#inspect, | |
#message | Gets called if no message is specified when calling |
#name | Alias for Base#cop_name. |
#offenses, | |
#on_investigation_end | Called after all on_… |
#on_new_investigation | Called before all on_… |
#on_other_file | Called instead of all on_… |
#parse | There should be very limited reasons for a Cop to do it’s own parsing. |
#parser_engine, | |
#ready | Called between investigations. |
#relevant_file?, | |
#target_gem_version | Returns a gems locked versions (i.e. |
#target_rails_version, #target_ruby_version, #annotate, #apply_correction, #attempt_correction, | |
#callback_argument | Reserved for Cop::Cop. |
#complete_investigation | Called to complete an investigation. |
#correct, #current_corrector, | |
#current_offense_locations | Reserved for Commissioner: |
#current_offenses, #currently_disabled_lines, #custom_severity, #default_severity, #disable_uncorrectable, #enabled_line?, #file_name_matches_any?, #find_message, #find_severity, #range_for_original, #range_from_node_or_range, | |
#reset_investigation | Actually private methods. |
#use_corrector |
::RuboCop::Cop::AutocorrectLogic
- Included
::RuboCop::Cop::IgnoredNode
- Included
Constructor Details
This class inherits a constructor from RuboCop::Cop::Base
Instance Attribute Details
#allow_bang_methods? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 275
def allow_bang_methods? cop_config.fetch('AllowBangMethods', false) end
#conservative? ⇒ Boolean
(readonly, private)
[ GitHub ]
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 265
def conservative? cop_config.fetch('Mode', :conservative).to_sym == :conservative end
Instance Method Details
#acceptable?(return_values) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 154
def acceptable?(return_values) # In `conservative` mode, if the method returns `super`, `zsuper`, or a # non-comparison method call, the method name is acceptable. return false unless conservative? return_values.any? do |value| value.type?(:super, :zsuper) || unknown_method_call?(value) end end
#all_return_values_boolean?(return_values) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 184
def all_return_values_boolean?(return_values) values = return_values.reject { |value| value.type?(:super, :zsuper) } return false if values.empty? values.all? { |value| boolean_return?(value) } end
#allowed?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 146
def allowed?(node) allowed_method?(node.method_name) || matches_allowed_pattern?(node.method_name) || allowed_bang_method?(node) || node.operator_method? || node.body.nil? end
#allowed_bang_method?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 269
def allowed_bang_method?(node) return false unless allow_bang_methods? node.bang_method? end
#and_or?(node) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 242
def and_or?(node) node.type?(:and, :or) end
#boolean_return?(value) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 191
def boolean_return?(value) return true if value.boolean_type? return false unless value.call_type? value.comparison_method? || value.predicate_method? || value.negation_method? end
#extract_and_or_clauses(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/predicate_method.rb', line 246
def extract_and_or_clauses(node) # Recursively traverse an `and` or `or` node to collect all clauses within return node unless and_or?(node) [extract_and_or_clauses(node.lhs), extract_and_or_clauses(node.rhs)].flatten end
#extract_conditional_branches(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/predicate_method.rb', line 253
def extract_conditional_branches(node) return node unless node.conditional? if node.type?(:while, :until) # If there is no body, act as implicit `nil`. node.body ? [last_value(node.body)] : [s(:nil)] else # Branches with no value act as an implicit `nil`. node.branches.filter_map { |branch| branch ? last_value(branch) : s(:nil) } end end
#extract_return_value(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/predicate_method.rb', line 212
def extract_return_value(node) return node unless node.return_type? # `return` without a value is a `nil` return. return s(:nil) if node.arguments.empty? # When there's a multiple return, it cannot be a predicate # so just return an `array` sexp for simplicity. return s(:array) unless node.arguments.one? node.first_argument end
#last_value(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/predicate_method.rb', line 225
def last_value(node) value = node.begin_type? ? node.children.last : node value&.return_type? ? extract_return_value(value) : value end
#on_def(node) Also known as: #on_defs
[ GitHub ]# File 'lib/rubocop/cop/naming/predicate_method.rb', line 130
def on_def(node) return if allowed?(node) return_values = return_values(node.body) return if acceptable?(return_values) if node.predicate_method? && potential_non_predicate?(return_values) add_offense(node.loc.name, message: MSG_NON_PREDICATE) elsif !node.predicate_method? && all_return_values_boolean?(return_values) add_offense(node.loc.name, message: MSG_PREDICATE) end end
#on_defs(node)
Alias for #on_def.
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 142
alias on_defs on_def
#potential_non_predicate?(return_values) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 198
def potential_non_predicate?(return_values) # Assumes a method to be non-predicate if all return values are non-boolean literals. # # In `Mode: conservative`, if any of the return values is a boolean, # the method name is acceptable. # In `Mode: aggressive`, all return values must be booleans for a predicate # method, or else an offense will be registered. return false if conservative? && return_values.any? { |value| boolean_return?(value) } return_values.any? do |value| value.literal? && !value.boolean_type? end end
#process_return_values(return_values) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/predicate_method.rb', line 230
def process_return_values(return_values) return_values.flat_map do |value| if value.conditional? process_return_values(extract_conditional_branches(value)) elsif and_or?(value) process_return_values(extract_and_or_clauses(value)) else value end end end
#return_values(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/naming/predicate_method.rb', line 170
def return_values(node) # Collect all the (implicit and explicit) return values of a node return_values = Set.new(node.begin_type? ? [] : [extract_return_value(node)]) node.each_descendant(:return) do |return_node| return_values << extract_return_value(return_node) end last_value = last_value(node) return_values << last_value if last_value process_return_values(return_values) end
#unknown_method_call?(value) ⇒ Boolean
(private)
# File 'lib/rubocop/cop/naming/predicate_method.rb', line 164
def unknown_method_call?(value) return false unless value.call_type? !value.comparison_method? && !value.predicate_method? && !value.negation_method? end