require 'digest' module UniverseCompiler module Entity class Reference class << self def references @references ||= {} end def new_instance(entity = nil) k = entity_to_cache_key entity return references[k] if references[k] e = new entity references[k] = e e end def entity_to_cache_key(entity_or_reference) universe_name = entity_or_reference.universe.nil? ? '' : entity_or_reference.universe.name universe_name ||= '' [entity_or_reference.type, entity_or_reference.name, universe_name] end private :new end yaml_tag '!psref' yaml_tag '!entity' include UniverseCompiler::Utils::ErrorPropagation include UniverseCompiler::Entity::Conversion attr_reader :type, :name, :universe def initialize(entity = nil) self.entity = entity unless entity.nil? end def entity=(entity) @type = entity.type @name = entity.name self.universe = entity.universe end def universe=(another_universe) k = self.class.entity_to_cache_key self self.class.references.delete k @universe = another_universe self.class.entity_to_cache_key self end def to_entity(raise_error: true) false_or_raise "Cannot get entity '#{to_composite_key.inspect}' if its universe is not defined!", raise_error: raise_error if universe.nil? entity = universe.get_entity *to_composite_key false_or_raise "Cannot find entity '#{to_composite_key.inspect}' in the universe '#{universe}'", raise_error: raise_error if entity.nil? entity end def encode_with(coder) coder.scalar = '%s/%s' % [type, name] end def init_with(coder) initialize case coder.tag when '!psref' @type = coder['type'] @name = coder['name'] when '!entity' if md = coder.scalar.match(/^(?[^\/]+)\/(?.+)$/) @type = md['type'].to_sym @name = md['name'] else raise UniverseCompiler::Error 'Invalid deserialization !' end else raise UniverseCompiler::Error 'Invalid deserialization !' end end end end end