Class: RuboCop::Cop::Style::AccessorGrouping
| Relationships & Source Files | |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
::RuboCop::Cop::AutoCorrector,
::RuboCop::Cop::Base,
::RuboCop::ExcludeLimit,
NodePattern::Macros,
RuboCop::AST::Sexp
|
|
|
Instance Chain:
|
|
| Inherits: |
RuboCop::Cop::Base
|
| Defined in: | lib/rubocop/cop/style/accessor_grouping.rb |
Overview
Checks for grouping of accessors in class and module bodies.
By default it enforces accessors to be placed in grouped
declarations, reducing boilerplate. It can also be configured
to enforce separating them into individual declarations for
easier diffing and per-attribute documentation.
|
Note
|
If there is a method call before the accessor method it is always allowed as it might be intended like Sorbet. |
|
Note
|
If there is a RBS::Inline annotation comment just after the accessor method it is always allowed. |
Constant Summary
-
GROUPED_MSG =
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 61'Group together all `%<accessor>s` attributes.' -
SEPARATED_MSG =
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 62'Use one attribute per `%<accessor>s`.'
::RuboCop::Cop::Base - Inherited
EMPTY_OFFENSES, RESTRICT_ON_SEND
::RuboCop::Cop::ConfigurableEnforcedStyle - Included
::RuboCop::Cop::RangeHelp - Included
::RuboCop::Cop::VisibilityHelp - Included
Class Attribute Summary
::RuboCop::Cop::AutoCorrector - Extended
::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
- #grouped_style? ⇒ Boolean readonly private
- #separated_style? ⇒ Boolean readonly private
::RuboCop::Cop::ConfigurableEnforcedStyle - Included
::RuboCop::Cop::Base - Inherited
::RuboCop::Cop::AutocorrectLogic - Included
Instance Method Summary
- #on_class(node) (also: #on_sclass, #on_module)
-
#on_module(node)
Alias for #on_class.
-
#on_sclass(node)
Alias for #on_class.
- #autocorrect(corrector, node) private
- #check(send_node) private
-
#class_send_elements(class_node)
private
Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity.
- #group_accessors(node, accessors) private
-
#groupable_accessor?(node) ⇒ Boolean
private
Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity.
- #groupable_sibling_accessor?(node, sibling) ⇒ Boolean private
- #groupable_sibling_accessors(send_node) private
- #message(send_node) private
- #preferred_accessors(node) private
- #previous_line_comment?(node) ⇒ Boolean private
- #range_with_trailing_argument_comment(node) private
- #separate_accessors(node) private
-
#skip_for_grouping?(node) ⇒ Boolean
private
Group after constants.
::RuboCop::Cop::VisibilityHelp - Included
::RuboCop::Cop::RangeHelp - Included
| #add_range, | |
| #arguments_range | A range containing the first to the last argument of a method call or method definition. |
| #column_offset_between, | |
| #contents_range | A range containing only the contents of a literal with delimiters (e.g. |
| #directions, | |
| #effective_column | Returns the column attribute of the range, except if the range is on the first line and there’s a byte order mark at the beginning of that line, in which case 1 is subtracted from the column value. |
| #final_pos, #move_pos, #move_pos_str, #range_between, #range_by_whole_lines, #range_with_comments, #range_with_comments_and_lines, #range_with_surrounding_comma, #range_with_surrounding_space, #source_range | |
::RuboCop::Cop::ConfigurableEnforcedStyle - 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
#grouped_style? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 139
def grouped_style? style == :grouped end
#separated_style? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 143
def separated_style? style == :separated end
Instance Method Details
#autocorrect(corrector, node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 87
def autocorrect(corrector, node) if (preferred_accessors = preferred_accessors(node)) corrector.replace( grouped_style? ? node : range_with_trailing_argument_comment(node), preferred_accessors ) else range = range_with_surrounding_space(node.source_range, side: :left) corrector.remove(range) end end
#check(send_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 76
def check(send_node) return if previous_line_comment?(send_node) || !groupable_accessor?(send_node) return unless (grouped_style? && groupable_sibling_accessors(send_node).size > 1) || (separated_style? && send_node.arguments.size > 1) = (send_node) add_offense(send_node, message: ) do |corrector| autocorrect(corrector, send_node) end end
#class_send_elements(class_node) (private)
Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 127
def class_send_elements(class_node) class_def = class_node.body if !class_def || class_def.def_type? [] elsif class_def.send_type? [class_def] else class_def.each_child_node(:send).to_a end end
#group_accessors(node, accessors) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 184
def group_accessors(node, accessors) accessor_names = accessors.flat_map { |accessor| accessor.arguments.map(&:source) }.uniq "#{node.method_name} #{accessor_names.join(', ')}" end
#groupable_accessor?(node) ⇒ Boolean (private)
Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 104
def groupable_accessor?(node) return true unless (previous_expression = node.left_siblings.last) # Accessors with Sorbet `sig { ... }` blocks shouldn't be groupable. if previous_expression.block_type? previous_expression.child_nodes.each do |child_node| break previous_expression = child_node if child_node.send_type? end end return true unless previous_expression.send_type? # Accessors with RBS::Inline annotations shouldn't be groupable. return false if processed_source.comments.any? do |c| same_line?(c, previous_expression) && c.text.start_with?('#:') end previous_expression.attribute_accessor? || previous_expression.access_modifier? || node.first_line - previous_expression.last_line > 1 # there is a space between nodes end
#groupable_sibling_accessor?(node, sibling) ⇒ Boolean (private)
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 147
def groupable_sibling_accessor?(node, sibling) sibling.attribute_accessor? && sibling.method?(node.method_name) && node_visibility(sibling) == node_visibility(node) && groupable_accessor?(sibling) && !previous_line_comment?(sibling) end
#groupable_sibling_accessors(send_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 154
def groupable_sibling_accessors(send_node) send_node.parent.each_child_node(:send).select do |sibling| groupable_sibling_accessor?(send_node, sibling) end end
#message(send_node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 160
def (send_node) msg = grouped_style? ? GROUPED_MSG : SEPARATED_MSG format(msg, accessor: send_node.method_name) end
#on_class(node) Also known as: #on_sclass, #on_module
[ GitHub ]# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 64
def on_class(node) class_send_elements(node).each do |macro| next unless macro.attribute_accessor? check(macro) end end
#on_module(node)
Alias for #on_class.
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 72
alias on_module on_class
#on_sclass(node)
Alias for #on_class.
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 71
alias on_sclass on_class
#preferred_accessors(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 165
def preferred_accessors(node) if grouped_style? return if skip_for_grouping?(node) accessors = groupable_sibling_accessors(node) if node.loc == accessors.first.loc || skip_for_grouping?(accessors.first) group_accessors(node, accessors) end else separate_accessors(node) end end
#previous_line_comment?(node) ⇒ Boolean (private)
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 99
def previous_line_comment?(node) comment_line?(processed_source[node.first_line - 2]) end
#range_with_trailing_argument_comment(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 205
def range_with_trailing_argument_comment(node) comment = processed_source.ast_with_comments[node.last_argument].last if comment add_range(node.source_range, comment.source_range) else node end end
#separate_accessors(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 190
def separate_accessors(node) node.arguments.flat_map do |arg| lines = [ *processed_source.ast_with_comments[arg].map(&:text), "#{node.method_name} #{arg.source}" ] if arg == node.first_argument lines else indent = ' ' * node.loc.column lines.map { |line| "#{indent}#{line}" } end end.join("\n") end
#skip_for_grouping?(node) ⇒ Boolean (private)
Group after constants
# File 'lib/rubocop/cop/style/accessor_grouping.rb', line 179
def skip_for_grouping?(node) node.right_siblings.any?(&:casgn_type?) && node.right_siblings.any? { |n| n.send_type? && groupable_sibling_accessor?(node, n) } end