smart_container 0.1.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 +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +15 -0
- data/.travis.yml +28 -0
- data/CHANGELOG.md +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +83 -0
- data/LICENSE.txt +21 -0
- data/README.md +39 -0
- data/Rakefile +21 -0
- data/bin/console +8 -0
- data/bin/setup +8 -0
- data/lib/smart_core/container.rb +135 -0
- data/lib/smart_core/container/arbitary_lock.rb +22 -0
- data/lib/smart_core/container/definition_dsl.rb +109 -0
- data/lib/smart_core/container/definition_dsl/command_set.rb +87 -0
- data/lib/smart_core/container/definition_dsl/commands.rb +9 -0
- data/lib/smart_core/container/definition_dsl/commands/base.rb +48 -0
- data/lib/smart_core/container/definition_dsl/commands/definition.rb +9 -0
- data/lib/smart_core/container/definition_dsl/commands/definition/compose.rb +49 -0
- data/lib/smart_core/container/definition_dsl/commands/definition/namespace.rb +54 -0
- data/lib/smart_core/container/definition_dsl/commands/definition/register.rb +54 -0
- data/lib/smart_core/container/definition_dsl/commands/instantiation.rb +8 -0
- data/lib/smart_core/container/definition_dsl/commands/instantiation/compose.rb +53 -0
- data/lib/smart_core/container/definition_dsl/commands/instantiation/freeze_state.rb +27 -0
- data/lib/smart_core/container/definition_dsl/inheritance.rb +23 -0
- data/lib/smart_core/container/dependency_compatability.rb +9 -0
- data/lib/smart_core/container/dependency_compatability/definition.rb +38 -0
- data/lib/smart_core/container/dependency_compatability/general.rb +61 -0
- data/lib/smart_core/container/dependency_compatability/registry.rb +36 -0
- data/lib/smart_core/container/dependency_resolver.rb +93 -0
- data/lib/smart_core/container/dependency_resolver/route.rb +83 -0
- data/lib/smart_core/container/dependency_resolver/route/cursor.rb +47 -0
- data/lib/smart_core/container/entities.rb +11 -0
- data/lib/smart_core/container/entities/base.rb +26 -0
- data/lib/smart_core/container/entities/dependency.rb +38 -0
- data/lib/smart_core/container/entities/dependency_builder.rb +50 -0
- data/lib/smart_core/container/entities/namespace.rb +73 -0
- data/lib/smart_core/container/entities/namespace_builder.rb +41 -0
- data/lib/smart_core/container/errors.rb +65 -0
- data/lib/smart_core/container/key_guard.rb +31 -0
- data/lib/smart_core/container/mixin.rb +83 -0
- data/lib/smart_core/container/registry.rb +250 -0
- data/lib/smart_core/container/registry_builder.rb +51 -0
- data/lib/smart_core/container/version.rb +9 -0
- data/smart_container.gemspec +38 -0
- metadata +191 -0
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
module SmartCore::Container::Entities
|
6
|
+
require_relative 'entities/base'
|
7
|
+
require_relative 'entities/dependency'
|
8
|
+
require_relative 'entities/dependency_builder'
|
9
|
+
require_relative 'entities/namespace'
|
10
|
+
require_relative 'entities/namespace_builder'
|
11
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Container::Entities::Base
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.1.0
|
10
|
+
attr_reader :external_name
|
11
|
+
|
12
|
+
# @param external_name [String]
|
13
|
+
# @return [void]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
# @since 0.1.0
|
17
|
+
def initialize(external_name)
|
18
|
+
@external_name = external_name
|
19
|
+
end
|
20
|
+
|
21
|
+
# @return [Any]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
# @since 0.1.0
|
25
|
+
def reveal; end
|
26
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Container::Entities::Dependency < SmartCore::Container::Entities::Base
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.1.0
|
10
|
+
alias_method :dependency_name, :external_name
|
11
|
+
|
12
|
+
# @param dependency_name [String]
|
13
|
+
# @param dependency_definition [Proc]
|
14
|
+
# @return [void]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
# @since 0.1.0
|
18
|
+
def initialize(dependency_name, dependency_definition)
|
19
|
+
super(dependency_name)
|
20
|
+
@dependency_definition = dependency_definition
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [Any]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
# @since 0.1.0
|
27
|
+
def reveal
|
28
|
+
dependency_definition.call
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# @return [Proc]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
# @since 0.1.0
|
37
|
+
attr_reader :dependency_definition
|
38
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Container::Entities::DependencyBuilder
|
6
|
+
class << self
|
7
|
+
# @param dependency_name [String]
|
8
|
+
# @param dependency_definition [Proc]
|
9
|
+
# @return [SmartCore::Container::Entities::Dependency]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
# @since 0.1.0
|
13
|
+
def build(dependency_name, dependency_definition)
|
14
|
+
new(dependency_name, dependency_definition).build
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# @param dependency_name [String]
|
19
|
+
# @param dependency_definition [Proc]
|
20
|
+
# @return [void]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
# @since 0.1.0
|
24
|
+
def initialize(dependency_name, dependency_definition)
|
25
|
+
@dependency_name = dependency_name
|
26
|
+
@dependency_definition = dependency_definition
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [SmartCore::Container::Entities::Dependency]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.1.0
|
33
|
+
def build
|
34
|
+
SmartCore::Container::Entities::Dependency.new(dependency_name, dependency_definition)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# @return [String]
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
# @since 0.1.0
|
43
|
+
attr_reader :dependency_name
|
44
|
+
|
45
|
+
# @return [Proc]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
# @since 0.1.0
|
49
|
+
attr_reader :dependency_definition
|
50
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Container::Entities::Namespace < SmartCore::Container::Entities::Base
|
6
|
+
# @return [String]
|
7
|
+
#
|
8
|
+
# @api private
|
9
|
+
# @since 0.1.0
|
10
|
+
alias_method :namespace_name, :external_name
|
11
|
+
|
12
|
+
# @param namespace_name [String]
|
13
|
+
# @return [void]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
# @since 0.1.0
|
17
|
+
def initialize(namespace_name)
|
18
|
+
super(namespace_name)
|
19
|
+
@container_klass = Class.new(SmartCore::Container)
|
20
|
+
@container_instance = nil
|
21
|
+
@lock = SmartCore::Container::ArbitaryLock.new
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [SmartCore::Container]
|
25
|
+
#
|
26
|
+
# @api private
|
27
|
+
# @since 0.1.0
|
28
|
+
def reveal
|
29
|
+
thread_safe { container_instance }
|
30
|
+
end
|
31
|
+
|
32
|
+
# @param dependencies_definition [Proc]
|
33
|
+
# @return [void]
|
34
|
+
#
|
35
|
+
# @api private
|
36
|
+
# @since 0.1.0
|
37
|
+
def append_definitions(dependencies_definition)
|
38
|
+
thread_safe { container_klass.instance_eval(&dependencies_definition) }
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [void]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
# @since 0.1.0
|
45
|
+
def freeze!
|
46
|
+
thread_safe { container_instance.freeze! }
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
# @return [Class<SmartCore::Container>]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
# @since 0.1.0
|
55
|
+
attr_reader :container_klass
|
56
|
+
|
57
|
+
# @return [SmartCore::Container]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
# @since 0.1.0
|
61
|
+
def container_instance
|
62
|
+
@container_instance ||= container_klass.new
|
63
|
+
end
|
64
|
+
|
65
|
+
# @param block [Block]
|
66
|
+
# @return [Any]
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
# @since 0.1.0
|
70
|
+
def thread_safe(&block)
|
71
|
+
@lock.thread_safe(&block)
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
class SmartCore::Container::Entities::NamespaceBuilder
|
6
|
+
class << self
|
7
|
+
# @param namespace_name [String]
|
8
|
+
# @return [SmartCore::Container::Entities::Namespace]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
# @since 0.1.0
|
12
|
+
def build(namespace_name)
|
13
|
+
new(namespace_name).build
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param namespace_name [String]
|
18
|
+
# @return [void]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
# @since 0.1.0
|
22
|
+
def initialize(namespace_name)
|
23
|
+
@namespace_name = namespace_name
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [SmartCore::Container::Entities::Namespace]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
# @since 0.1.0
|
30
|
+
def build
|
31
|
+
SmartCore::Container::Entities::Namespace.new(namespace_name)
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
# @return [String]
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
# @since 0.1.0
|
40
|
+
attr_reader :namespace_name
|
41
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class SmartCore::Container
|
4
|
+
# @api public
|
5
|
+
# @since 0.1.0
|
6
|
+
Error = Class.new(SmartCore::Error)
|
7
|
+
|
8
|
+
# @api public
|
9
|
+
# @since 0.1.0
|
10
|
+
ArgumentError = Class.new(SmartCore::ArgumentError)
|
11
|
+
|
12
|
+
# @api public
|
13
|
+
# @since 0.1.0
|
14
|
+
IncompatibleEntityNameError = Class.new(ArgumentError)
|
15
|
+
|
16
|
+
# @see SmartCore::Container::Registry
|
17
|
+
#
|
18
|
+
# @api public
|
19
|
+
# @since 0.1.0
|
20
|
+
FrozenRegistryError = Class.new(SmartCore::FrozenError)
|
21
|
+
|
22
|
+
# @api public
|
23
|
+
# @since 0.1.0
|
24
|
+
FetchError = Class.new(Error)
|
25
|
+
|
26
|
+
# @see SmartCore::Container::DependencyCompatability::General
|
27
|
+
# @see SmartCore::Container::DependencyCompatability::Definition
|
28
|
+
# @see SmartCore::Container::DependencyCompatability::Registry
|
29
|
+
#
|
30
|
+
# @api public
|
31
|
+
# @since 0.1.0
|
32
|
+
DependencyOverNamespaceOverlapError = Class.new(Error)
|
33
|
+
|
34
|
+
# @see SmartCore::Container::DependencyCompatability::General
|
35
|
+
# @see SmartCore::Container::DependencyCompatability::Definition
|
36
|
+
# @see SmartCore::Container::DependencyCompatability::Registry
|
37
|
+
#
|
38
|
+
# @api public
|
39
|
+
# @since 0.1.0
|
40
|
+
NamespaceOverDependencyOverlapError = Class.new(Error)
|
41
|
+
|
42
|
+
# @see SmartCore::Container::DependencyResolver
|
43
|
+
# @see SmartCore::Container::Registry
|
44
|
+
#
|
45
|
+
# @api public
|
46
|
+
# @since 0.1.0
|
47
|
+
class ResolvingError < FetchError
|
48
|
+
# @return [String]
|
49
|
+
#
|
50
|
+
# @api private
|
51
|
+
# @since 0.1.0
|
52
|
+
attr_reader :path_part
|
53
|
+
|
54
|
+
# @param message [String]
|
55
|
+
# @param path_part [String]
|
56
|
+
# @return [void]
|
57
|
+
#
|
58
|
+
# @api private
|
59
|
+
# @since 0.1.0
|
60
|
+
def initialize(messegae = nil, path_part:)
|
61
|
+
@path_part = path_part
|
62
|
+
super(message)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api priavate
|
4
|
+
# @since 0.1.0
|
5
|
+
module SmartCore::Container::KeyGuard
|
6
|
+
class << self
|
7
|
+
# @param key [Symbol, String]
|
8
|
+
# @return [void]
|
9
|
+
#
|
10
|
+
# @raise [SmartCore::Container::IncompatibleEntityNameError]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
# @since 0.1.0
|
14
|
+
def prevent_incomparabilities!(key)
|
15
|
+
raise(
|
16
|
+
SmartCore::Container::IncompatibleEntityNameError,
|
17
|
+
'Namespace/Dependency name should be a symbol or a string'
|
18
|
+
) unless key.is_a?(String) || key.is_a?(Symbol)
|
19
|
+
end
|
20
|
+
|
21
|
+
# @param key [Symbol, String]
|
22
|
+
# @return [String]
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
# @since 0.1.0
|
26
|
+
def indifferently_accessable_key(key)
|
27
|
+
prevent_incomparabilities!(key)
|
28
|
+
key.to_s
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api public
|
4
|
+
# @since 0.1.0
|
5
|
+
module SmartCore::Container::Mixin
|
6
|
+
class << self
|
7
|
+
# @param base_klass [Class]
|
8
|
+
# @return [void]
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
# @since 0.1.0
|
12
|
+
def included(base_klass)
|
13
|
+
# rubocop:disable Layout/LineLength
|
14
|
+
base_klass.instance_variable_set(:@__smart_core_container_access_lock__, SmartCore::Container::ArbitaryLock.new)
|
15
|
+
base_klass.instance_variable_set(:@__smart_core_container_klass__, Class.new(SmartCore::Container))
|
16
|
+
base_klass.instance_variable_set(:@__smart_core_container__, nil)
|
17
|
+
# rubocop:enable Layout/LineLength
|
18
|
+
|
19
|
+
base_klass.extend(ClassMethods)
|
20
|
+
base_klass.include(InstanceMethods)
|
21
|
+
base_klass.singleton_class.prepend(ClassInheritance)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# @api private
|
26
|
+
# @since 0.1.0
|
27
|
+
module ClassInheritance
|
28
|
+
# @param child_klass [CLass]
|
29
|
+
# @return [void]
|
30
|
+
#
|
31
|
+
# @api private
|
32
|
+
# @since 0.1.0
|
33
|
+
def inherited(child_klass)
|
34
|
+
inherited_container_klass = Class.new(@__smart_core_container_klass__)
|
35
|
+
|
36
|
+
# rubocop:disable Layout/LineLength
|
37
|
+
child_klass.instance_variable_set(:@__smart_core_container_access_lock__, SmartCore::Container::ArbitaryLock.new)
|
38
|
+
child_klass.instance_variable_set(:@__smart_core_container_klass__, inherited_container_klass)
|
39
|
+
child_klass.instance_variable_set(:@__smart_core_container__, nil)
|
40
|
+
# rubocop:enable Layout/LineLength
|
41
|
+
super
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @api private
|
46
|
+
# @since 0.1.0
|
47
|
+
module ClassMethods
|
48
|
+
# @param freeze_state [Boolean]
|
49
|
+
# @param block [Proc]
|
50
|
+
# @return [void]
|
51
|
+
#
|
52
|
+
# @api public
|
53
|
+
# @since 0.1.0
|
54
|
+
def dependencies(freeze_state: false, &block)
|
55
|
+
@__smart_core_container_access_lock__.thread_safe do
|
56
|
+
@__smart_core_container_klass__.instance_eval(&block) if block_given?
|
57
|
+
@__smart_core_container_klass__.instance_eval { freeze_state! } if freeze_state
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# @return [SmartCore::Container]
|
62
|
+
#
|
63
|
+
# @api public
|
64
|
+
# @since 0.1.0
|
65
|
+
def container
|
66
|
+
@__smart_core_container_access_lock__.thread_safe do
|
67
|
+
@__smart_core_container__ ||= @__smart_core_container_klass__.new
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# @api private
|
73
|
+
# @since 0.1.0
|
74
|
+
module InstanceMethods
|
75
|
+
# @return [SmartCore::Container]
|
76
|
+
#
|
77
|
+
# @api public
|
78
|
+
# @since 0.1.0
|
79
|
+
def container
|
80
|
+
self.class.container
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,250 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# @api private
|
4
|
+
# @since 0.1.0
|
5
|
+
# rubocop:disable Metrics/ClassLength
|
6
|
+
class SmartCore::Container::Registry
|
7
|
+
# @since 0.1.0
|
8
|
+
include Enumerable
|
9
|
+
|
10
|
+
# @return [Hash<Symbol,SmartCore::Container::Entity>]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
# @since 0.1.0
|
14
|
+
attr_reader :registry
|
15
|
+
|
16
|
+
# @return [void]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
# @since 0.1.0
|
20
|
+
def initialize
|
21
|
+
@registry = {}
|
22
|
+
@access_lock = SmartCore::Container::ArbitaryLock.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param entity_path [String, Symbol]
|
26
|
+
# @return [SmartCore::Container::Entity]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
# @since 0.1.0
|
30
|
+
def resolve(entity_path)
|
31
|
+
thread_safe { fetch_entity(entity_path) }
|
32
|
+
end
|
33
|
+
|
34
|
+
# @param name [String, Symbol]
|
35
|
+
# @param dependency_definition [Block]
|
36
|
+
# @return [void]
|
37
|
+
#
|
38
|
+
# @api private
|
39
|
+
# @since 0.1.0
|
40
|
+
def register_dependency(name, &dependency_definition)
|
41
|
+
thread_safe { add_dependency(name, dependency_definition) }
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param name [String, Symbol]
|
45
|
+
# @param dependencies_definition [Block]
|
46
|
+
# @return [void]
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
# @since 0.1.0
|
50
|
+
def register_namespace(name, &dependencies_definition)
|
51
|
+
thread_safe { add_namespace(name, dependencies_definition) }
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [void]
|
55
|
+
#
|
56
|
+
# @api private
|
57
|
+
# @since 0.1.0
|
58
|
+
def freeze!
|
59
|
+
thread_safe { freeze_state! }
|
60
|
+
end
|
61
|
+
|
62
|
+
# @return [Boolean]
|
63
|
+
#
|
64
|
+
# @api private
|
65
|
+
# @since 0.1.0
|
66
|
+
def frozen?
|
67
|
+
thread_safe { state_frozen? }
|
68
|
+
end
|
69
|
+
|
70
|
+
# @param block [Block]
|
71
|
+
# @return [Enumerable]
|
72
|
+
#
|
73
|
+
# @api private
|
74
|
+
# @since 0.1.0
|
75
|
+
def each(&block)
|
76
|
+
thread_safe { enumerate(&block) }
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [Hash<String|Symbol,SmartCore::Container::Entities::Base|Any>]
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
# @since 0.1.0
|
83
|
+
def hash_tree(resolve_dependencies: false)
|
84
|
+
thread_safe { build_hash_tree(resolve_dependencies: resolve_dependencies) }
|
85
|
+
end
|
86
|
+
alias_method :to_h, :hash_tree
|
87
|
+
alias_method :to_hash, :hash_tree
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
# @return [Mutex]
|
92
|
+
#
|
93
|
+
# @api private
|
94
|
+
# @since 0.1.0
|
95
|
+
attr_reader :lock
|
96
|
+
|
97
|
+
# @return [Boolean]
|
98
|
+
#
|
99
|
+
# @api private
|
100
|
+
# @since 0.1.0
|
101
|
+
def state_frozen?
|
102
|
+
registry.frozen?
|
103
|
+
end
|
104
|
+
|
105
|
+
# @return [Hash<String|Symbol,SmartCore::Container::Entities::Base|Any>]
|
106
|
+
#
|
107
|
+
# @api private
|
108
|
+
# @since 0.1.0
|
109
|
+
def build_hash_tree(resolve_dependencies: false)
|
110
|
+
{}.tap do |tree|
|
111
|
+
enumerate do |(entity_name, entity)|
|
112
|
+
case entity
|
113
|
+
when SmartCore::Container::Entities::Namespace
|
114
|
+
tree[entity_name] = entity.reveal.hash_tree(resolve_dependencies: resolve_dependencies)
|
115
|
+
when SmartCore::Container::Entities::Dependency
|
116
|
+
tree[entity_name] = resolve_dependencies ? entity.reveal : entity
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @return [void]
|
123
|
+
#
|
124
|
+
# @api private
|
125
|
+
# @since 0.1.0
|
126
|
+
def freeze_state!
|
127
|
+
registry.freeze.tap do
|
128
|
+
enumerate do |(entity_name, entity)|
|
129
|
+
entity.freeze! if entity.is_a?(SmartCore::Container::Entities::Namespace)
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# @param block
|
135
|
+
# @return [Enumerable]
|
136
|
+
#
|
137
|
+
# @api private
|
138
|
+
# @since 0.1.0
|
139
|
+
def enumerate(&block)
|
140
|
+
block_given? ? registry.each(&block) : registry.each
|
141
|
+
end
|
142
|
+
|
143
|
+
# @paramm entity_path [String, Symbol]
|
144
|
+
# @return [SmartCore::Container::Entity]
|
145
|
+
#
|
146
|
+
# @api private
|
147
|
+
# @since 0.1.0
|
148
|
+
# @version 0.1.0
|
149
|
+
def fetch_entity(entity_path)
|
150
|
+
dependency_name = indifferently_accessable_name(entity_path)
|
151
|
+
registry.fetch(dependency_name)
|
152
|
+
rescue KeyError
|
153
|
+
raise(SmartCore::Container::ResolvingError.new(<<~MESSAGE, path_part: dependency_name))
|
154
|
+
Entity with \"#{dependency_name}\" name does not exist
|
155
|
+
MESSAGE
|
156
|
+
end
|
157
|
+
|
158
|
+
# @param dependency_name [String, Symbol]
|
159
|
+
# @param dependency_definition [Proc]
|
160
|
+
# @return [SmartCore::Container::Entities::Dependency]
|
161
|
+
#
|
162
|
+
# @raise [SmartCore::Container::DependencyOverNamespaceOverlapError]
|
163
|
+
#
|
164
|
+
# @api private
|
165
|
+
# @since 0.1.0
|
166
|
+
def add_dependency(dependency_name, dependency_definition)
|
167
|
+
if state_frozen?
|
168
|
+
raise(SmartCore::Container::FrozenRegistryError, 'Can not modify frozen registry!')
|
169
|
+
end
|
170
|
+
dependency_name = indifferently_accessable_name(dependency_name)
|
171
|
+
prevent_namespace_overlap!(dependency_name)
|
172
|
+
|
173
|
+
dependency_entity = SmartCore::Container::Entities::DependencyBuilder.build(
|
174
|
+
dependency_name, dependency_definition
|
175
|
+
)
|
176
|
+
|
177
|
+
dependency_entity.tap { registry[dependency_name] = dependency_entity }
|
178
|
+
end
|
179
|
+
|
180
|
+
# @param namespace_name [String, Symbol]
|
181
|
+
# @param dependencies_definition [Proc]
|
182
|
+
# @return [SmartCore::Container::Entities::Namespace]
|
183
|
+
#
|
184
|
+
# @raise [SmartCore::Container::NamespaceOverDependencyOverlapError]
|
185
|
+
#
|
186
|
+
# @api private
|
187
|
+
# @since 0.1.0
|
188
|
+
def add_namespace(namespace_name, dependencies_definition)
|
189
|
+
if state_frozen?
|
190
|
+
raise(SmartCore::Container::FrozenRegistryError, 'Can not modify frozen registry!')
|
191
|
+
end
|
192
|
+
namespace_name = indifferently_accessable_name(namespace_name)
|
193
|
+
prevent_dependency_overlap!(namespace_name)
|
194
|
+
|
195
|
+
# rubocop:disable Layout/RescueEnsureAlignment
|
196
|
+
namespace_entity = begin
|
197
|
+
fetch_entity(namespace_name)
|
198
|
+
rescue SmartCore::Container::FetchError
|
199
|
+
registry[namespace_name] = SmartCore::Container::Entities::NamespaceBuilder.build(
|
200
|
+
namespace_name
|
201
|
+
)
|
202
|
+
end
|
203
|
+
# rubocop:enable Layout/RescueEnsureAlignment
|
204
|
+
|
205
|
+
namespace_entity.tap { namespace_entity.append_definitions(dependencies_definition) }
|
206
|
+
end
|
207
|
+
|
208
|
+
# @param name [String, Symbol]
|
209
|
+
# @return [void]
|
210
|
+
#
|
211
|
+
# @see [SmartCore::Container::KeyGuard]
|
212
|
+
#
|
213
|
+
# @api private
|
214
|
+
# @since 0.1.0
|
215
|
+
def indifferently_accessable_name(name)
|
216
|
+
SmartCore::Container::KeyGuard.indifferently_accessable_key(name)
|
217
|
+
end
|
218
|
+
|
219
|
+
# @param dependency_name [String]
|
220
|
+
# @return [void]
|
221
|
+
#
|
222
|
+
# @api private
|
223
|
+
# @since 0.1.0
|
224
|
+
def prevent_namespace_overlap!(dependency_name)
|
225
|
+
SmartCore::Container::DependencyCompatability::Registry.prevent_namespace_overlap!(
|
226
|
+
self, dependency_name
|
227
|
+
)
|
228
|
+
end
|
229
|
+
|
230
|
+
# @param namespace_name [String]
|
231
|
+
# @return [void]
|
232
|
+
#
|
233
|
+
# @api private
|
234
|
+
# @since 0.1.0
|
235
|
+
def prevent_dependency_overlap!(namespace_name)
|
236
|
+
SmartCore::Container::DependencyCompatability::Registry.prevent_dependency_overlap!(
|
237
|
+
self, namespace_name
|
238
|
+
)
|
239
|
+
end
|
240
|
+
|
241
|
+
# @param block [Proc]
|
242
|
+
# @return [Any]
|
243
|
+
#
|
244
|
+
# @api private
|
245
|
+
# @since 0.1.0
|
246
|
+
def thread_safe(&block)
|
247
|
+
@access_lock.thread_safe(&block)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
# rubocop:enable Metrics/ClassLength
|