class SmartIoC::BeanFactory

Instantiates beans according to their scopes

Attributes

bean_file_loader[R]

Public Class Methods

new(bean_definitions_storage, extra_package_contexts) click to toggle source
# File lib/smart_ioc/bean_factory.rb, line 8
def initialize(bean_definitions_storage, extra_package_contexts)
  @bean_definitions_storage = bean_definitions_storage
  @extra_package_contexts   = extra_package_contexts
  @bean_file_loader         = SmartIoC::BeanFileLoader.new
  @singleton_scope          = SmartIoC::Scopes::Singleton.new
  @prototype_scope          = SmartIoC::Scopes::Prototype.new
  @thread_scope             = SmartIoC::Scopes::Request.new
  @semaphore                = Mutex.new
end

Public Instance Methods

clear_scopes() click to toggle source
# File lib/smart_ioc/bean_factory.rb, line 18
def clear_scopes
  all_scopes.each(&:clear)
end
force_clear_scopes() click to toggle source
# File lib/smart_ioc/bean_factory.rb, line 22
def force_clear_scopes
  all_scopes.each(&:force_clear)
end
get_bean(bean_name, package: nil, parent_bean_definition: nil, context: nil, parent_bean_name: nil) click to toggle source

Get bean from the container by it's name, package, context @param bean_name [Symbol] bean name @param package [Symbol] package name @param parent_bean_definition [SmartIoC::BeanDefinition] parent bean definition @param context [Symbol] context @return bean instance @raise [ArgumentError] if bean is not found @raise [ArgumentError] if ambiguous bean definition was found

# File lib/smart_ioc/bean_factory.rb, line 34
def get_bean(bean_name, package: nil, parent_bean_definition: nil, context: nil, parent_bean_name: nil)
  check_arg(bean_name, :bean_name, Symbol)
  check_arg(package, :package, Symbol) if package
  check_arg(parent_bean_definition, :parent_bean_definition, SmartIoC::BeanDefinition) if parent_bean_definition
  check_arg(context, :context, Symbol) if context

  @bean_file_loader.require_bean(bean_name)

  parent_package_name = parent_bean_definition ? parent_bean_definition.package : nil
  context = autodetect_context(bean_name, package, parent_package_name, context, parent_bean_name)
  bean_definition = @bean_definitions_storage.find(bean_name, package, context, parent_package_name)
  scope = get_scope(bean_definition)
  bean = scope.get_bean(bean_definition.klass)

  if !bean
    bean = init_bean(bean_definition)
  end

  scope.save_bean(bean_definition.klass, bean)
  bean
rescue SmartIoC::Errors::AmbiguousBeanDefinition => e
  e.parent_bean_definition = parent_bean_definition
  raise e
end

Private Instance Methods

all_scopes() click to toggle source
# File lib/smart_ioc/bean_factory.rb, line 139
def all_scopes
  [@singleton_scope, @prototype_scope, @thread_scope]
end
autodetect_bean_definition(bean, package, parent_bean_package, parent_bean_name) click to toggle source
# File lib/smart_ioc/bean_factory.rb, line 90
  def autodetect_bean_definition(bean, package, parent_bean_package, parent_bean_name)
    if package
      bean_context = @extra_package_contexts.get_context(package)
      bds = @bean_definitions_storage.filter_by_with_drop_to_default_context(bean, package, bean_context)

      return bds.first if bds.size == 1
      raise ArgumentError, "bean :#{bean} is not found in package :#{package}"
    end

    if parent_bean_package
      bean_context = @extra_package_contexts.get_context(parent_bean_package)
      bds = @bean_definitions_storage.filter_by_with_drop_to_default_context(bean, parent_bean_package, bean_context)

      return bds.first if bds.size == 1
    end

    bds = @bean_definitions_storage.filter_by(bean)
    bds_by_package = bds.group_by(&:package)
    smart_bds = []

    bds_by_package.each do |package, bd_list|
      # try to find bean definition with package context
      bd = bd_list.detect {|bd| bd.context == @extra_package_contexts.get_context(bd.package)}
      smart_bds << bd if bd

      # last try: find for :default context
      if !bd
        bd = bd_list.detect {|bd| bd.context == SmartIoC::Container::DEFAULT_CONTEXT}
        smart_bds << bd if bd
      end
    end

    if smart_bds.size > 1
      raise ArgumentError.new(
%Q(Unable to autodetect bean :#{bean}#{parent_bean_name ? " for bean :#{parent_bean_name}" : ''}.
Several definitions were found:\n
#{smart_bds.map(&:inspect).join("\n\n")}.
Set package directly for injected dependency
)
      )
    end

    if smart_bds.size == 0
      raise ArgumentError, "Unable to find bean :#{bean} in any package."
    end

    return smart_bds.first
  end
autodetect_context(bean_name, package, parent_bean_package, context, parent_bean_name) click to toggle source
# File lib/smart_ioc/bean_factory.rb, line 79
def autodetect_context(bean_name, package, parent_bean_package, context, parent_bean_name)
  return context if context

  if package
    @extra_package_contexts.get_context(package)
  else
    bean_definition = autodetect_bean_definition(bean_name, package, parent_bean_package, parent_bean_name)
    @extra_package_contexts.get_context(bean_definition.package)
  end
end
get_scope(bean_definition) click to toggle source
# File lib/smart_ioc/bean_factory.rb, line 143
def get_scope(bean_definition)
  case bean_definition.scope
  when SmartIoC::Scopes::Singleton::VALUE
    @singleton_scope
  when SmartIoC::Scopes::Prototype::VALUE
    @prototype_scope
  when SmartIoC::Scopes::Request::VALUE
    @thread_scope
  else
    raise ArgumentError, "bean definition for :#{bean_definition.name} has unsupported scope :#{bean_definition.scope}"
  end
end
init_bean(bean_definition) click to toggle source
# File lib/smart_ioc/bean_factory.rb, line 61
def init_bean(bean_definition)
  bean = if bean_definition.is_instance?
    bean_definition.klass.allocate
  else
    bean_definition.klass
  end

  if bean_definition.has_factory_method?
    bean = bean.send(bean_definition.factory_method)
  end

  if bean_definition.after_init
    bean.send(bean_definition.after_init)
  end

  bean
end