# frozen_string_literal: true module Shirinji class Resolver ARG_TYPES = %i[key keyreq].freeze attr_reader :map, :singletons def initialize(map) @map = map @singletons = {} end def resolve(name) bean = map.get(name) if bean.access == :singleton single = singletons[name] return single if single end resolve_bean(bean).tap do |instance| singletons[name] = instance if bean.access == :singleton end end def reload(map) @map = map reset_cache end def reset_cache @singletons = {} end private def resolve_bean(bean) send(:"resolve_#{bean.value ? :value : :class}_bean", bean) end def resolve_value_bean(bean) bean.value.is_a?(Proc) ? bean.value.call : bean.value end def resolve_class_bean(bean) klass, params = resolve_class(bean) return klass unless bean.construct return klass.new if params.empty? check_params!(params) args = params.each_with_object({}) do |(_type, arg), memo| memo[arg] = resolve_attribute(bean, arg) end klass.new(**args) end def resolve_class(bean) klass = bean.class_name.constantize construct = klass.instance_method(:initialize) [klass, construct.parameters] end def resolve_attribute(bean, arg) return arg unless (attr = bean.attributes[arg]) return attr.value if attr.value resolve(attr.reference) end def check_params!(params) params.each do |pair| next if ARG_TYPES.include?(pair.first) raise ArgumentError, 'Only key arguments are allowed' end end end end