class RuboCop::Cop::Style::MixinGrouping
end
extend Qox, Bar
class Foo
@good
end
extend Qox
extend Bar
class Foo
@bad
EnforcedStyle: grouped
end
include Bar
include Qox
class Foo
@good
end
include Bar, Qox
class Foo
@bad
EnforcedStyle: separated (default)
@example
but it can be configured to enforce grouping them in one declaration.
By default it enforces mixins to be placed in separate declarations,
This cop checks for grouping of mixins in ‘class` and `module` bodies.
def autocorrect(node)
def autocorrect(node) if separated_style? range = node.loc.expression correction = separate_mixins(node) else mixins = sibling_mixins(node) mixins.unshift(node) range = node.loc.expression.join(mixins.last.loc.expression) correction = group_mixins(node, mixins) end ->(corrector) { corrector.replace(range, correction) } end
def check(send_node)
def check(send_node) if separated_style? check_separated_style(send_node) else check_grouped_style(send_node) end end
def check_grouped_style(send_node)
def check_grouped_style(send_node) return if sibling_mixins(send_node).empty? add_offense(send_node, :expression) end
def check_separated_style(send_node)
def check_separated_style(send_node) return if send_node.arguments.one? add_offense(send_node, :expression) end
def group_mixins(node, mixins)
def group_mixins(node, mixins) _receiver, mixin, *_args = *node all_mixin_arguments = mixins.reverse.flat_map do |m| m.arguments.map(&:source) end "#{mixin} #{all_mixin_arguments.join(', ')}" end
def grouped_style?
def grouped_style? style == :grouped end
def indent(node)
def indent(node) ' ' * node.loc.column end
def message(send_node)
def message(send_node) suffix = separated_style? ? 'separate statements' : 'a single statement' format(MSG, send_node.method_name, suffix) end
def on_send(node)
def on_send(node) return unless node.macro? && MIXIN_METHODS.include?(node.method_name) check(node) end
def separate_mixins(node)
def separate_mixins(node) _receiver, mixin, *args = *node args.reverse! first_mixin = String.new("#{mixin} #{args.first.source}") args[1..-1].inject(first_mixin) do |replacement, arg| replacement << "\n#{indent(node)}#{mixin} #{arg.source}" end end
def separated_style?
def separated_style? style == :separated end
def sibling_mixins(send_node)
def sibling_mixins(send_node) siblings = send_node.parent.each_child_node(:send) .reject { |sibling| sibling == send_node } siblings.select do |sibling_node| sibling_node.method_name == send_node.method_name end end