class RuboCop::Cop::Style::AccessModifierDeclarations
Access modifiers should be declared to apply to a group of methods or inline before each method, depending on configuration. EnforcedStyle config covers only method definitions. Applications of visibility methods to symbols can be controlled using AllowModifiersOnSymbols config. Also, the visibility of ‘attr*` methods can be controlled using AllowModifiersOnAttrs config.
In Ruby 3.0, ‘attr*` methods now return an array of defined method names as symbols. So we can write the modifier and `attr*` in inline style. AllowModifiersOnAttrs config allows `attr*` methods to be written in inline style without modifying applications that have been maintained for a long time in group style. Furthermore, developers who are not very familiar with Ruby may know that the modifier applies to `def`, but they may not know that it also applies to `attr*` methods. It would be easier to understand if we could write `attr*` methods in inline style.
@safety
Autocorrection is not safe, because the visibility of dynamically defined methods can vary depending on the state determined by the group access modifier.
@example EnforcedStyle: group (default)
# bad class Foo private def bar; end private def baz; end end # good class Foo private def bar; end def baz; end end
@example EnforcedStyle: inline
# bad class Foo private def bar; end def baz; end end # good class Foo private def bar; end private def baz; end end
@example AllowModifiersOnSymbols: true (default)
# good class Foo private :bar, :baz private *%i[qux quux] private *METHOD_NAMES private *private_methods end
@example AllowModifiersOnSymbols: false
# bad class Foo private :bar, :baz private *%i[qux quux] private *METHOD_NAMES private *private_methods end
@example AllowModifiersOnAttrs: true (default)
# good class Foo public attr_reader :bar protected attr_writer :baz private attr_accessor :qux private attr :quux def public_method; end private def private_method; end end
@example AllowModifiersOnAttrs: false
# bad class Foo public attr_reader :bar protected attr_writer :baz private attr_accessor :qux private attr :quux end
@example AllowModifiersOnAliasMethod: true (default)
# good class Foo public alias_method :bar, :foo protected alias_method :baz, :foo private alias_method :qux, :foo end
@example AllowModifiersOnAliasMethod: false
# bad class Foo public alias_method :bar, :foo protected alias_method :baz, :foo private alias_method :qux, :foo end
Constants
- GROUP_STYLE_MESSAGE
- INLINE_STYLE_MESSAGE
- RESTRICT_ON_SEND
Public Instance Methods
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 172 def on_send(node) return if allowed?(node) if offense?(node) add_offense(node.loc.selector) do |corrector| autocorrect(corrector, node) end opposite_style_detected else correct_style_detected end end
Private Instance Methods
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 263 def access_modifier_is_inlined?(node) node.arguments.any? end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 267 def access_modifier_is_not_inlined?(node) !access_modifier_is_inlined?(node) end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 234 def allow_modifiers_on_alias_method?(node) cop_config['AllowModifiersOnAliasMethod'] && access_modifier_with_alias_method?(node) end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 230 def allow_modifiers_on_attrs?(node) cop_config['AllowModifiersOnAttrs'] && access_modifier_with_attr?(node) end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 226 def allow_modifiers_on_symbols?(node) cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node) end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 187 def allowed?(node) !node.access_modifier? || node.parent&.type?(:pair, :any_block) || allow_modifiers_on_symbols?(node) || allow_modifiers_on_attrs?(node) || allow_modifiers_on_alias_method?(node) end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 195 def autocorrect(corrector, node) case style when :group autocorrect_group_style(corrector, node) when :inline autocorrect_inline_style(corrector, node) end end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 204 def autocorrect_group_style(corrector, node) def_nodes = find_corresponding_def_nodes(node) return unless def_nodes.any? replace_defs(corrector, node, def_nodes) end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 211 def autocorrect_inline_style(corrector, node) if node.parent&.begin_type? remove_modifier_node_within_begin(corrector, node, node.parent) else remove_nodes(corrector, node) end select_grouped_def_nodes(node).each do |grouped_def_node| insert_inline_modifier(corrector, grouped_def_node, node.method_name) end end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 248 def correctable_group_offense?(node) return false unless group_style? return false if allowed?(node) access_modifier_is_inlined?(node) && find_corresponding_def_nodes(node).any? end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 356 def def_source(node, def_nodes) [ *processed_source.ast_with_comments[node].map(&:text), *def_nodes.map(&:source) ].join("\n") end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 310 def find_argument_less_modifier_node(node) return unless (parent = node.parent) parent.each_child_node(:send).find do |child| child.method?(node.method_name) && child.arguments.empty? end end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 291 def find_corresponding_def_nodes(node) if access_modifier_with_symbol?(node) method_names = node.arguments.filter_map do |argument| next unless argument.sym_type? argument.respond_to?(:value) && argument.value end def_nodes = node.parent.each_child_node(:def).select do |child| method_names.include?(child.method_name) end # If there isn't a `def` node for each symbol, we will skip autocorrection. def_nodes.size == method_names.size ? def_nodes : [] else [node.first_argument] end end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 255 def group_style? style == :group end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 259 def inline_style? style == :inline end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 340 def insert_inline_modifier(corrector, node, modifier_name) corrector.insert_before(node, "#{modifier_name} ") end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 281 def message(range) access_modifier = range.source if group_style? format(GROUP_STYLE_MESSAGE, access_modifier: access_modifier) elsif inline_style? format(INLINE_STYLE_MESSAGE, access_modifier: access_modifier) end end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 238 def offense?(node) if group_style? return false if node.parent ? node.parent.if_type? : access_modifier_with_symbol?(node) access_modifier_is_inlined?(node) && !right_siblings_same_inline_method?(node) else access_modifier_is_not_inlined?(node) && select_grouped_def_nodes(node).any? end end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 222 def percent_symbol_array?(node) node.array_type? && node.percent_literal?(:symbol) end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 350 def remove_modifier_node_within_begin(corrector, modifier_node, begin_node) def_node = begin_node.children[1] range = modifier_node.source_range.begin.join(def_node.source_range.begin) corrector.remove(range) end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 344 def remove_nodes(corrector, *nodes) nodes.each do |node| corrector.remove(range_with_comments_and_lines(node)) end end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 324 def replace_defs(corrector, node, def_nodes) source = def_source(node, def_nodes) argument_less_modifier_node = find_argument_less_modifier_node(node) if argument_less_modifier_node corrector.insert_after(argument_less_modifier_node, "\n\n#{source}") elsif (ancestor = node.each_ancestor(:class, :module).first) corrector.insert_before(ancestor.loc.end, "#{node.method_name}\n\n#{source}\n") else corrector.replace(node, "#{node.method_name}\n\n#{source}") return end remove_nodes(corrector, *def_nodes, node) end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 271 def right_siblings_same_inline_method?(node) node.right_siblings.any? do |sibling| sibling.send_type? && correctable_group_offense?(sibling) && sibling.method?(node.method_name) && !sibling.arguments.empty? && find_corresponding_def_nodes(sibling).any? end end
Source
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 318 def select_grouped_def_nodes(node) node.right_siblings.take_while do |sibling| !(sibling.send_type? && sibling.bare_access_modifier_declaration?) end.select(&:def_type?) end