class RuboCop::Cop::Style::MixinGrouping

This cop checks for grouping of mixins in `class` and `module` bodies. By default it enforces mixins to be placed in separate declarations, but it can be configured to enforce grouping them in one declaration.

@example EnforcedStyle: separated (default)

# bad
class Foo
  include Bar, Qox
end

# good
class Foo
  include Qox
  include Bar
end

@example EnforcedStyle: grouped

# bad
class Foo
  extend Bar
  extend Qox
end

# good
class Foo
  extend Qox, Bar
end

Constants

MIXIN_METHODS
MSG

Public Instance Methods

autocorrect(node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 50
def autocorrect(node)
  range = node.loc.expression
  if separated_style?
    correction = separate_mixins(node)
  else
    mixins = sibling_mixins(node)
    if node == mixins.first
      correction = group_mixins(node, mixins)
    else
      range = range_to_remove_for_subsequent_mixin(mixins, node)
      correction = ''
    end
  end

  ->(corrector) { corrector.replace(range, correction) }
end
on_class(node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 39
def on_class(node)
  begin_node = node.child_nodes.find(&:begin_type?) || node
  begin_node.each_child_node(:send).select(&:macro?).each do |macro|
    next unless MIXIN_METHODS.include?(macro.method_name)

    check(macro)
  end
end
Also aliased as: on_module
on_module(node)
Alias for: on_class

Private Instance Methods

check(send_node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 81
def check(send_node)
  if separated_style?
    check_separated_style(send_node)
  else
    check_grouped_style(send_node)
  end
end
check_grouped_style(send_node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 89
def check_grouped_style(send_node)
  return if sibling_mixins(send_node).size == 1

  add_offense(send_node)
end
check_separated_style(send_node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 95
def check_separated_style(send_node)
  return if send_node.arguments.one?

  add_offense(send_node)
end
group_mixins(node, mixins) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 134
def group_mixins(node, mixins)
  mixin_names = mixins.reverse.flat_map do |mixin|
    mixin.arguments.map(&:source)
  end

  "#{node.method_name} #{mixin_names.join(', ')}"
end
grouped_style?() click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 117
def grouped_style?
  style == :grouped
end
indent(node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 142
def indent(node)
  ' ' * node.loc.column
end
message(send_node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 110
def message(send_node)
  suffix =
    separated_style? ? 'separate statements' : 'a single statement'

  format(MSG, mixin: send_node.method_name, suffix: suffix)
end
range_to_remove_for_subsequent_mixin(mixins, node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 69
def range_to_remove_for_subsequent_mixin(mixins, node)
  range = node.loc.expression
  prev_mixin = mixins.each_cons(2) { |m, n| break m if n == node }
  between = prev_mixin.loc.expression.end
                      .join(range.begin)
  # if separated from previous mixin with only whitespace?
  if between.source !~ /\S/
    range = range.join(between) # then remove that too
  end
  range
end
separate_mixins(node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 125
def separate_mixins(node)
  arguments = node.arguments.reverse
  mixins = ["#{node.method_name} #{arguments.first.source}"]

  arguments[1..-1].inject(mixins) do |replacement, arg|
    replacement << "#{indent(node)}#{node.method_name} #{arg.source}"
  end.join("\n")
end
separated_style?() click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 121
def separated_style?
  style == :separated
end
sibling_mixins(send_node) click to toggle source
# File lib/rubocop/cop/style/mixin_grouping.rb, line 101
def sibling_mixins(send_node)
  siblings = send_node.parent.each_child_node(:send)
                      .select(&:macro?)

  siblings.select do |sibling_node|
    sibling_node.method_name == send_node.method_name
  end
end