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 end
@example AllowModifiersOnSymbols: false
# bad class Foo private :bar, :baz private *%i[qux quux] private *METHOD_NAMES 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
Constants
- ALLOWED_NODE_TYPES
- GROUP_STYLE_MESSAGE
- INLINE_STYLE_MESSAGE
- RESTRICT_ON_SEND
Public Instance Methods
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 146 def on_send(node) return unless node.access_modifier? return if ALLOWED_NODE_TYPES.include?(node.parent&.type) return if allow_modifiers_on_symbols?(node) return if allow_modifiers_on_attrs?(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
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 205 def access_modifier_is_inlined?(node) node.arguments.any? end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 209 def access_modifier_is_not_inlined?(node) !access_modifier_is_inlined?(node) end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 187 def allow_modifiers_on_attrs?(node) cop_config['AllowModifiersOnAttrs'] && access_modifier_with_attr?(node) end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 183 def allow_modifiers_on_symbols?(node) cop_config['AllowModifiersOnSymbols'] && access_modifier_with_symbol?(node) end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 164 def autocorrect(corrector, node) case style when :group def_node = find_corresponding_def_node(node) return unless def_node replace_def(corrector, node, def_node) when :inline remove_node(corrector, node) select_grouped_def_nodes(node).each do |grouped_def_node| insert_inline_modifier(corrector, grouped_def_node, node.method_name) end end end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 279 def def_source(node, def_node) [*processed_source.ast_with_comments[node].map(&:text), def_node.source].join("\n") end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 240 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
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 229 def find_corresponding_def_node(node) if access_modifier_with_symbol?(node) method_name = node.first_argument.respond_to?(:value) && node.first_argument.value node.parent.each_child_node(:def).find do |child| child.method?(method_name) end else node.first_argument end end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 197 def group_style? style == :group end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 201 def inline_style? style == :inline end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 271 def insert_inline_modifier(corrector, node, modifier_name) corrector.insert_before(node, "#{modifier_name} ") end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 219 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
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 191 def offense?(node) (group_style? && access_modifier_is_inlined?(node) && !right_siblings_same_inline_method?(node)) || (inline_style? && access_modifier_is_not_inlined?(node)) end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 179 def percent_symbol_array?(node) node.array_type? && node.percent_literal?(:symbol) end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 275 def remove_node(corrector, node) corrector.remove(range_with_comments_and_lines(node)) end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 254 def replace_def(corrector, node, def_node) source = def_source(node, def_node) 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(:block, :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_node(corrector, def_node) remove_node(corrector, node) end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 213 def right_siblings_same_inline_method?(node) node.right_siblings.any? do |sibling| sibling.send_type? && sibling.method?(node.method_name) && !sibling.arguments.empty? end end
# File lib/rubocop/cop/style/access_modifier_declarations.rb, line 248 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