# frozen_string_literal: true module RuboCop module Cop module Rake # If namespaces are defined with the same name, Rake executes the both namespaces # in definition order. # It is redundant. You should squash them into one definition. # This cop detects it. # # @example # # bad # namespace :foo do # task :bar do # end # end # namespace :foo do # task :hoge do # end # end # # # good # namespace :foo do # task :bar do # end # task :hoge do # end # end # class DuplicateNamespace < Base include Helper::OnNamespace MSG = 'Namespace `%s` is defined at both %s and %s.' def initialize(*) super @namespaces = {} end def on_namespace(node) namespaces = namespaces(node) return if namespaces.include?(nil) full_name = namespaces.reverse.join(':') if (previous = @namespaces[full_name]) message = message_for_dup(previous: previous, current: node, namespace: full_name) add_offense(node, message: message) else @namespaces[full_name] = node end end def namespaces(node) ns = [] node.each_ancestor(:block) do |block_node| send_node = block_node.send_node next unless send_node.method?(:namespace) name = Helper::TaskName.task_name(send_node) ns << name end ns end def message_for_dup(previous:, current:, namespace:) format( MSG, namespace: namespace, previous: source_location(previous), current: source_location(current), ) end def source_location(node) range = node.location.expression path = smart_path(range.source_buffer.name) "#{path}:#{range.line}" end end end end end