module Gitlab class CrossProjectAccess class << self delegate :add_check, :find_check, :checks, to: :instance end def self.instance @instance ||= new end attr_reader :checks def initialize @checks = {} end def add_check( klass, actions: {}, positive_condition: nil, negative_condition: nil, skip: false) new_check = CheckInfo.new(actions, positive_condition, negative_condition, skip ) @checks[klass] ||= Gitlab::CrossProjectAccess::CheckCollection.new @checks[klass].add_check(new_check) recalculate_checks_for_class(klass) @checks[klass] end def find_check(object) @cached_checks ||= Hash.new do |cache, new_class| parent_classes = @checks.keys.select { |existing_class| new_class <= existing_class } closest_class = closest_parent(parent_classes, new_class) cache[new_class] = @checks[closest_class] end @cached_checks[object.class] end private def recalculate_checks_for_class(klass) new_collection = @checks[klass] @checks.each do |existing_class, existing_check_collection| if existing_class < klass existing_check_collection.add_collection(new_collection) elsif klass < existing_class new_collection.add_collection(existing_check_collection) end end end def closest_parent(classes, subject) relevant_ancestors = subject.ancestors & classes relevant_ancestors.first end end end