callme 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 22eae5e35215e5eed4a7876f1bdac5b8f8f9bcdb
4
+ data.tar.gz: 734e00afe63b56af60134a224acc0489ae09d481
5
+ SHA512:
6
+ metadata.gz: ab1b440d21c6f30ee6ff3d95b89d5462485bf5505a468994ee1712117dc3e5c2e6b019b6e17660313f6ecbb7937f1c539e286a98a3464e0cb5d8f091f6def3cd
7
+ data.tar.gz: be2243ddbedb38520e29e85e652db9f2a09a168d99ae89dec6c30e2e8e57925f2e95be4e35094eb342d87f0adc93137bfdcdd008d6782c7fae096667c852d55b
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ vendor/
2
+ tags
3
+ .bundle
4
+ .DS_Store
5
+ pkg
data/.travis.yml ADDED
@@ -0,0 +1,3 @@
1
+ rvm:
2
+ - 2.0.0
3
+ script: "bundle exec rspec spec/"
data/.yardops ADDED
@@ -0,0 +1 @@
1
+ lib/**/*.rb
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in aggregate_builder.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'rspec'
8
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,32 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ callme (0.5.0)
5
+ request_store
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.2.5)
11
+ rake (10.1.1)
12
+ request_store (1.0.5)
13
+ rspec (2.14.1)
14
+ rspec-core (~> 2.14.0)
15
+ rspec-expectations (~> 2.14.0)
16
+ rspec-mocks (~> 2.14.0)
17
+ rspec-core (2.14.7)
18
+ rspec-expectations (2.14.4)
19
+ diff-lcs (>= 1.1.3, < 2.0)
20
+ rspec-mocks (2.14.4)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ bundler (~> 1.3)
27
+ callme!
28
+ rake
29
+ rspec
30
+
31
+ BUNDLED WITH
32
+ 1.14.6
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Albert Gazizov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # Callme [![Build Status](https://travis-ci.org/mindreframer/callme.png)](https://travis-ci.org/mindreframer/callme) [![Code Climate](https://codeclimate.com/github/mindreframer/callme.png)](https://codeclimate.com/github/mindreframer/callme)
2
+
3
+
4
+
5
+ Callme is an Inversion of Control container for Ruby.
6
+ It takes advantage of the dynamic nature of Ruby to provide a rich and flexible approach to injecting dependencies.
7
+ It's inspired by SpringIoc and tries to give you the same features.
8
+
9
+ ## Usage
10
+ Lets say you have a Logger which has the Appender dependency
11
+
12
+ ```ruby
13
+ class Logger
14
+ attr_accessor :appender
15
+
16
+ def info(message)
17
+ # do some work with appender
18
+ end
19
+ end
20
+
21
+ class Appender
22
+ end
23
+ ```
24
+ To use Logger you need to inject the instance of Appender class, for example
25
+ using setter injection:
26
+ ```ruby
27
+ logger = Logger.new
28
+ logger.appender = Appender.new
29
+ logger.info('some message')
30
+ ```
31
+
32
+ Callme eliminates the manual injection step and injects dependencies by itself.
33
+ To use it you need to instantiate Callme::Container and pass dependency definitions(we call them beans) to it:
34
+ ```ruby
35
+ container = Callme::Container.new do |c|
36
+ c.bean(:appender, class: Appender)
37
+ c.bean(:logger, class: Logger) do
38
+ attr :appender, ref: :appender
39
+ end
40
+ end
41
+ ```
42
+ Now you can get the Logger instance from container with already set dependencies and use it:
43
+ ```ruby
44
+ logger = container[:logger]
45
+ logger.info('some message')
46
+ ```
47
+
48
+ To simplify injection Callme allows you specify dependencies inside of your class:
49
+ ```ruby
50
+ class Logger
51
+ inject :appender
52
+
53
+ def info(message)
54
+ # do some work with appender
55
+ end
56
+ end
57
+
58
+ class Appender
59
+ end
60
+ ```
61
+ With `inject` keyword you won't need to specify class dependencies in bean definition:
62
+ ```ruby
63
+ container = Callme::Container.new do |c|
64
+ c.bean(:appender, class: Appender)
65
+ c.bean(:logger, class: Logger)
66
+ end
67
+ ```
68
+
69
+
70
+
71
+ ## Inheriting from other containers
72
+ Quite often you will want to selectively override some parts of the system, use `Callme::Container.with_parent` to
73
+ create a new container with all the beans copied from the parent container.
74
+
75
+ ```ruby
76
+ class ContactBook
77
+ inject :contacts_repository
78
+ inject :validator, ref: :contact_validator
79
+ end
80
+ class ContactBookService
81
+ inject :contacts_repository
82
+ inject :validator, ref: :contact_validator
83
+ end
84
+ class ContactsRepository
85
+ end
86
+ class ContactValidator
87
+ end
88
+ class TestContactValidator
89
+ end
90
+
91
+ class AnotherTestContactValidator
92
+ end
93
+
94
+ parent = Callme::Container.new do |c|
95
+ c.bean(:contacts_repository, class: ContactsRepository)
96
+ c.bean(:contact_validator, class: ContactValidator)
97
+ c.bean(:contact_book, class: ContactBook)
98
+ c.bean(:contact_book_service, class: "ContactBookService")
99
+ end
100
+ puts parent[:contact_book_service].validator.class
101
+ #=> ContactValidator
102
+
103
+ testcontainer = Callme::Container.with_parent(parent) do |c|
104
+ c.bean(:contact_validator, class: TestContactValidator)
105
+ end
106
+ puts testcontainer[:contact_book_service].validator.class
107
+ #=> TestContactValidator
108
+
109
+ third = Callme::Container.with_parent(parent) do |c|
110
+ c.bean(:contact_validator, class: AnotherTestContactValidator)
111
+ end
112
+
113
+ puts third[:contact_book_service].validator.class
114
+ #=> AnotherTestContactValidator
115
+ ```
116
+
117
+
118
+ ## Installation
119
+
120
+ Add this line to your application's Gemfile:
121
+
122
+ gem 'callme'
123
+
124
+ And then execute:
125
+
126
+ $ bundle
127
+
128
+ Or install it yourself as:
129
+
130
+ $ gem install callme
131
+
132
+ ## Contributing
133
+
134
+ 1. Fork it
135
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
136
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
137
+ 4. Push to the branch (`git push origin my-new-feature`)
138
+ 5. Create new Pull Request
139
+
140
+ # TODO
141
+ 1. Constructor based injection
142
+ 2. Scope registration, refactor BeanFactory. Callme:Container.register_scope(SomeScope)
143
+ 3. Write documentation with more examples
144
+
145
+ ## Author
146
+ Roman Heinrich, [@mindreframer](https://twitter.com/mindreframer)
147
+ Albert Gazizov, [@deeper4k](https://twitter.com/deeper4k)
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "callme"
5
+
6
+ require "irb"
7
+ IRB.start(__FILE__)
data/callme.gemspec ADDED
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'callme/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "callme"
8
+ spec.version = Callme::VERSION
9
+ spec.authors = ["Roman Heinrich", "Albert Gazizov"]
10
+ spec.email = ["roman.heinrich@gmail.com"]
11
+ spec.description = %q{Callme: Simple depencency injection lib}
12
+ spec.summary = %q{Callme: Simple depencency injection lib}
13
+ spec.homepage = "http://github.com/mindreframer/callme"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(spec)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "request_store"
22
+ spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "rake"
24
+ end
@@ -0,0 +1,49 @@
1
+ # Helper class for arguments validation
2
+ module Callme::ArgsValidator
3
+ class << self
4
+
5
+ # Checks that specifid +obj+ is a symbol
6
+ # @param obj some object
7
+ # @param obj_name object's name, used to clarify error causer in exception
8
+ def is_symbol!(obj, obj_name)
9
+ unless obj.is_a?(Symbol)
10
+ raise ArgumentError, "#{obj_name} should be a Symbol"
11
+ end
12
+ end
13
+
14
+ # Checks that specifid +obj+ is an Array
15
+ # @param obj some object
16
+ # @param obj_name object's name, used to clarify error causer in exception
17
+ def is_array!(obj, obj_name)
18
+ unless obj.is_a?(Array)
19
+ raise ArgumentError, "#{obj_name} should be an Array"
20
+ end
21
+ end
22
+
23
+ # Checks that specifid +obj+ is a Hash
24
+ # @param obj some object
25
+ # @param obj_name object's name, used to clarify error causer in exception
26
+ def is_hash!(obj, obj_name)
27
+ unless obj.is_a?(Hash)
28
+ raise ArgumentError, "#{obj_name} should be a Hash"
29
+ end
30
+ end
31
+
32
+ # Checks that specifid +hash+ has a specified +key+
33
+ # @param hash some hash
34
+ # @param key hash's key
35
+ def has_key!(hash, key)
36
+ unless hash.has_key?(key)
37
+ raise ArgumentError, "#{hash} should has #{key} key"
38
+ end
39
+ end
40
+
41
+ # Checks that specified +block+ is given
42
+ # @param block some block
43
+ def block_given!(block)
44
+ unless block
45
+ raise ArgumentError, "Block should be given"
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,115 @@
1
+ require 'callme/scopes'
2
+ require 'callme/scopes/singleton_scope'
3
+ require 'callme/scopes/prototype_scope'
4
+ require 'callme/scopes/request_scope'
5
+
6
+ # Instantiates beans according to their scopes
7
+ class Callme::BeanFactory
8
+ attr_reader :const_loader
9
+
10
+ # Constructor
11
+ # @param beans_metadata_storage [BeansMetadataStorage] storage of bean metadatas
12
+ def initialize(const_loader, beans_metadata_storage)
13
+ @const_loader = const_loader
14
+ @beans_metadata_storage = beans_metadata_storage
15
+ @singleton_scope = Callme::Scopes::SingletonScope.new(self)
16
+ @prototype_scope = Callme::Scopes::PrototypeScope.new(self)
17
+ @request_scope = Callme::Scopes::RequestScope.new(self)
18
+ end
19
+
20
+ # Get bean from the container by it's +name+.
21
+ # According to the bean scope it will be newly created or returned already
22
+ # instantiated bean
23
+ # @param [Symbol] bean name
24
+ # @return bean instance
25
+ # @raise MissingBeanError if bean with the specified name is not found
26
+ def get_bean(name)
27
+ bean_metadata = @beans_metadata_storage.by_name(name)
28
+ unless bean_metadata
29
+ raise Callme::Errors::MissingBeanError, "Bean with name :#{name} is not defined"
30
+ end
31
+ get_bean_with_metadata(bean_metadata)
32
+ end
33
+
34
+ # Get bean by the specified +bean metadata+
35
+ # @param [BeanMetadata] bean metadata
36
+ # @return bean instance
37
+ def get_bean_with_metadata(bean_metadata)
38
+ get_scope_by_metadata(bean_metadata).get_bean(bean_metadata)
39
+ end
40
+
41
+ # Create new bean instance according
42
+ # to the specified +bean_metadata+
43
+ # @param [BeanMetadata] bean metadata
44
+ # @return bean instance
45
+ # @raise MissingBeanError if some of bean dependencies are not found
46
+ def create_bean_and_save(bean_metadata, beans_storage)
47
+ if bean_metadata.bean_class.is_a?(Class)
48
+ bean_class = bean_metadata.bean_class
49
+ else
50
+ bean_class = const_loader.load_const(bean_metadata.bean_class)
51
+ bean_metadata.fetch_attrs!(bean_class)
52
+ end
53
+ bean = bean_metadata.instance ? bean_class.new : bean_class
54
+ if bean_metadata.has_factory_method?
55
+ set_bean_dependencies(bean, bean_metadata)
56
+ bean = bean.send(bean_metadata.factory_method)
57
+ beans_storage[bean_metadata.name] = bean
58
+ else
59
+ # put to container first to prevent circular dependencies
60
+ beans_storage[bean_metadata.name] = bean
61
+ set_bean_dependencies(bean, bean_metadata)
62
+ end
63
+
64
+ bean
65
+ end
66
+
67
+ # Delete bean from the container by it's +name+.
68
+ # @param [Symbol] bean name
69
+ # @raise MissingBeanError if bean with the specified name is not found
70
+ def delete_bean(name)
71
+ bean_metadata = @beans_metadata_storage.by_name(name)
72
+ unless bean_metadata
73
+ raise Callme::Errors::MissingBeanError, "Bean with name :#{name} is not defined"
74
+ end
75
+ get_scope_by_metadata(bean_metadata).delete_bean(bean_metadata)
76
+ end
77
+
78
+ private
79
+
80
+ def set_bean_dependencies(bean, bean_metadata)
81
+ bean_metadata.attrs.each do |attr|
82
+ bean_metadata = @beans_metadata_storage.by_name(attr.ref)
83
+ unless bean_metadata
84
+ raise Callme::Errors::MissingBeanError, "Bean with name :#{attr.ref} is not defined, check #{bean.class}"
85
+ end
86
+ case bean_metadata.scope
87
+ when :singleton
88
+ bean.send("#{attr.name}=", get_bean(attr.ref))
89
+ when :prototype
90
+ bean.instance_variable_set(:@_callme_bean_factory, self)
91
+ bean.define_singleton_method(attr.name) do
92
+ @_callme_bean_factory.get_bean(attr.ref)
93
+ end
94
+ when :request
95
+ bean.instance_variable_set(:@_callme_bean_factory, self)
96
+ bean.define_singleton_method(attr.name) do
97
+ @_callme_bean_factory.get_bean(attr.ref)
98
+ end
99
+ end
100
+ end
101
+ end
102
+
103
+ def get_scope_by_metadata(bean_metadata)
104
+ case bean_metadata.scope
105
+ when :singleton
106
+ @singleton_scope
107
+ when :prototype
108
+ @prototype_scope
109
+ when :request
110
+ @request_scope
111
+ else
112
+ raise Callme::Errors::UnsupportedScopeError, "Bean with name :#{bean_metadata.name} has unsupported scope :#{bean_metadata.scope}"
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,70 @@
1
+ # Stores bean specific data: bean class, name,
2
+ # scope and bean dependencies
3
+ class Callme::BeanMetadata
4
+ attr_reader :name, :bean_class, :scope, :instance, :factory_method, :attrs
5
+
6
+ # Constructor
7
+ # @param name [Symbol] bean name
8
+ # @params options [Hash] includes bean class and scope
9
+ # @params &block [Proc] bean dependencies, has the following structure:
10
+ # do |c|
11
+ # attr :some_dependency, ref: :dependency_name
12
+ # arg :another_dependency, ref: :another_dependency_name
13
+ # end
14
+ # here attr means setter injection, arg means constructon injects
15
+ # +some_dependency+ is an attr_accessor defined in the bean class,
16
+ # +ref+ specifies what dependency from container to use to set the attribute
17
+ def initialize(name, options, &block)
18
+ Callme::ArgsValidator.has_key!(options, :class)
19
+
20
+ @name = name
21
+ @bean_class = options[:class]
22
+ @scope = options[:scope] || :singleton
23
+ @instance = options[:instance].nil? ? true : options[:instance]
24
+ @factory_method = options[:factory_method]
25
+ @attrs = []
26
+
27
+ fetch_attrs!(@bean_class)
28
+
29
+ if block
30
+ Dsl.new(@attrs).instance_exec(&block)
31
+ end
32
+ end
33
+
34
+ def fetch_attrs!(klass)
35
+ if klass.respond_to?(:_callme_injectable_attrs)
36
+ klass._callme_injectable_attrs.each do |attr, options|
37
+ options[:ref] ||= attr
38
+ @attrs << Callme::BeanMetadata::Attribute.new(attr, options)
39
+ end
40
+ end
41
+ end
42
+
43
+ def has_factory_method?
44
+ !!@factory_method
45
+ end
46
+
47
+ class Attribute
48
+ attr_reader :name, :ref
49
+
50
+ def initialize(name, options)
51
+ Callme::ArgsValidator.has_key!(options, :ref)
52
+ @name = name
53
+ @ref = options[:ref]
54
+ end
55
+ end
56
+
57
+ class Dsl
58
+ def initialize(attrs)
59
+ @attrs = attrs
60
+ end
61
+
62
+ def attr(name, options)
63
+ @attrs << Callme::BeanMetadata::Attribute.new(name, options)
64
+ end
65
+
66
+ def arg(name, options)
67
+ @args << Callme::BeanMetadata::Attribute.new(name, options)
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,32 @@
1
+ # Storage of bean metadatas
2
+ class Callme::BeansMetadataStorage
3
+ def initialize(bean_metadatas = {})
4
+ @bean_metadatas = bean_metadatas
5
+ end
6
+
7
+ # Finds bean metadata in storage by it's name
8
+ # @param name [Symbol] bean metadata name
9
+ # @return bean metadata
10
+ def by_name(name)
11
+ @bean_metadatas[name]
12
+ end
13
+
14
+ # Saves a given +bean_metadata+ to the storage
15
+ # @param bean_metadata [BeanMetadata] bean metadata for saving
16
+ def put(bean_metadata)
17
+ @bean_metadatas[bean_metadata.name] = bean_metadata
18
+ end
19
+
20
+ def bean_classes
21
+ @bean_metadatas.values.map(&:bean_class)
22
+ end
23
+
24
+ def keys
25
+ @bean_metadatas.keys
26
+ end
27
+
28
+ # Creates an independent copy of this instance
29
+ def copy
30
+ self.class.new(@bean_metadatas.dup)
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ module Callme::ConstLoaders
2
+ module ActiveSupport
3
+ def self.load_const(const_name)
4
+ ::ActiveSupport::Inflector.constantize(const_name)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,9 @@
1
+ module Callme::ConstLoaders
2
+ module Native
3
+ def self.load_const(const_name)
4
+ const_name.split('::').inject(Object) do |mod, const_part|
5
+ mod.const_get(const_part)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,107 @@
1
+ require 'callme/errors'
2
+ require 'callme/args_validator'
3
+ require 'callme/bean_metadata'
4
+ require 'callme/beans_metadata_storage'
5
+ require 'callme/bean_factory'
6
+ require 'callme/const_loaders/native'
7
+
8
+ module Callme
9
+
10
+ # Callme::Container is the central data store for registering objects
11
+ # used for dependency injection. Users register classes by
12
+ # providing a name and a class to create the object(we call them beans). Beans
13
+ # may be retrieved by asking for them by name (via the [] operator)
14
+ class Container
15
+ DEFAULT_CONST_LOADER = Callme::ConstLoaders::Native
16
+
17
+ # Constructor
18
+ # @param resources [Array] array of procs with container's beans definitions
19
+ # @param &block [Proc] optional proc with container's beans definitions
20
+ def initialize(const_loader = DEFAULT_CONST_LOADER, &block)
21
+ @const_loader = const_loader
22
+ @beans_metadata_storage = Callme::BeansMetadataStorage.new
23
+ @bean_factory = Callme::BeanFactory.new(const_loader, @beans_metadata_storage)
24
+
25
+ block.call(self) if block_given?
26
+ end
27
+
28
+ # Evaluates the given array of blocks on the container instance
29
+ # what adds new bean definitions to the container
30
+ # @param resources [Array] array of procs with container's beans definitions
31
+ def self.new_with_beans(resources, const_loader = DEFAULT_CONST_LOADER)
32
+ Callme::ArgsValidator.is_array!(resources, :resources)
33
+
34
+ self.new(const_loader).tap do |container|
35
+ resources.each do |resource|
36
+ resource.call(container)
37
+ end
38
+ end
39
+ end
40
+
41
+ def self.with_parent(parent_container, &block)
42
+ const_loader = parent_container.instance_variable_get("@const_loader")
43
+ beans_metadata_storage = parent_container.instance_variable_get("@beans_metadata_storage").copy
44
+ container = self.new(const_loader)
45
+ container.instance_eval do
46
+ @beans_metadata_storage = beans_metadata_storage
47
+ @bean_factory = Callme::BeanFactory.new(const_loader, beans_metadata_storage)
48
+ end
49
+ block.call(container) if block_given?
50
+ container
51
+ end
52
+
53
+ # Registers new bean in container
54
+ # @param bean_name [Symbol] bean name
55
+ # @param options [Hash] includes bean class and bean scope
56
+ # @param &block [Proc] the block which describes bean dependencies,
57
+ # see more in the BeanMetadata
58
+ def bean(bean_name, options, &block)
59
+ Callme::ArgsValidator.is_symbol!(bean_name, :bean_name)
60
+ Callme::ArgsValidator.is_hash!(options, :options)
61
+
62
+ bean = Callme::BeanMetadata.new(bean_name, options, &block)
63
+ @beans_metadata_storage.put(bean)
64
+ end
65
+
66
+ # Registers new bean in container and replace existing instance if it's instantiated
67
+ # @param bean_name [Symbol] bean name
68
+ # @param options [Hash] includes bean class and bean scope
69
+ # @param &block [Proc] the block which describes bean dependencies,
70
+ # see more in the BeanMetadata
71
+ def replace_bean(bean_name, options, &block)
72
+ if @bean_factory.get_bean(bean_name)
73
+ @bean_factory.delete_bean(bean_name)
74
+ end
75
+ bean(bean_name, options, &block)
76
+ end
77
+
78
+ def reset!
79
+ @bean_factory = Callme::BeanFactory.new(@const_loader, @beans_metadata_storage)
80
+ end
81
+
82
+ # Returns bean instance from the container
83
+ # by the specified bean name
84
+ # @param name [Symbol] bean name
85
+ # @return bean instance
86
+ def [](name)
87
+ Callme::ArgsValidator.is_symbol!(name, :bean_name)
88
+ return @bean_factory.get_bean(name)
89
+ end
90
+
91
+ def keys
92
+ @beans_metadata_storage.keys
93
+ end
94
+
95
+ # Load defined in bean classes
96
+ # this is needed for production usage
97
+ # for eager loading
98
+ def eager_load_bean_classes
99
+ @beans_metadata_storage.bean_classes.each do |bean_class|
100
+ if !bean_class.is_a?(Class)
101
+ @const_loader.load_const(bean_class)
102
+ end
103
+ end
104
+ end
105
+
106
+ end
107
+ end
@@ -0,0 +1,10 @@
1
+ module Callme::Errors
2
+ # Thrown when a service cannot be located by name.
3
+ class MissingBeanError < StandardError; end
4
+
5
+ # Thrown when a duplicate service is registered.
6
+ class DuplicateBeanError < StandardError; end
7
+
8
+ # Thrown when an unsupported bean scope is specified.
9
+ class UnsupportedScopeError < StandardError; end
10
+ end