smart_core 0.6.0 → 0.7.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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/.rubocop.yml +1 -1
  4. data/.travis.yml +5 -8
  5. data/CHANGELOG.md +5 -0
  6. data/README.md +14 -4
  7. data/lib/smart_core.rb +2 -2
  8. data/lib/smart_core/container.rb +49 -56
  9. data/lib/smart_core/container/arbitary_lock.rb +22 -0
  10. data/lib/smart_core/container/definition_dsl.rb +105 -55
  11. data/lib/smart_core/container/{command_set.rb → definition_dsl/command_set.rb} +20 -26
  12. data/lib/smart_core/container/definition_dsl/commands.rb +12 -0
  13. data/lib/smart_core/container/{commands → definition_dsl/commands}/base.rb +3 -3
  14. data/lib/smart_core/container/definition_dsl/commands/definition/compose.rb +46 -0
  15. data/lib/smart_core/container/definition_dsl/commands/definition/namespace.rb +51 -0
  16. data/lib/smart_core/container/{commands → definition_dsl/commands/definition}/register.rb +13 -25
  17. data/lib/smart_core/container/definition_dsl/commands/instantiation/compose.rb +50 -0
  18. data/lib/smart_core/container/definition_dsl/commands/instantiation/freeze_state.rb +24 -0
  19. data/lib/smart_core/container/dependency_compatability.rb +3 -3
  20. data/lib/smart_core/container/dependency_compatability/definition.rb +42 -0
  21. data/lib/smart_core/container/dependency_compatability/general.rb +61 -0
  22. data/lib/smart_core/container/dependency_compatability/registry.rb +28 -29
  23. data/lib/smart_core/container/dependency_resolver.rb +9 -4
  24. data/lib/smart_core/container/entities.rb +11 -0
  25. data/lib/smart_core/container/{entity.rb → entities/base.rb} +7 -7
  26. data/lib/smart_core/container/entities/dependency.rb +38 -0
  27. data/lib/smart_core/container/entities/dependency_builder.rb +50 -0
  28. data/lib/smart_core/container/entities/namespace.rb +73 -0
  29. data/lib/smart_core/container/entities/namespace_builder.rb +41 -0
  30. data/lib/smart_core/container/errors.rb +43 -0
  31. data/lib/smart_core/container/key_guard.rb +5 -5
  32. data/lib/smart_core/container/mixin.rb +20 -16
  33. data/lib/smart_core/container/registry.rb +224 -201
  34. data/lib/smart_core/container/registry_builder.rb +38 -5
  35. data/lib/smart_core/{exceptions.rb → errors.rb} +0 -0
  36. data/lib/smart_core/operation.rb +3 -1
  37. data/lib/smart_core/operation/{custom.rb → callback.rb} +7 -7
  38. data/lib/smart_core/operation/result.rb +1 -1
  39. data/lib/smart_core/operation/result_interface.rb +3 -3
  40. data/lib/smart_core/version.rb +1 -1
  41. data/smart_core.gemspec +6 -5
  42. metadata +28 -38
  43. data/lib/smart_core/container/command_definer.rb +0 -117
  44. data/lib/smart_core/container/commands.rb +0 -9
  45. data/lib/smart_core/container/commands/namespace.rb +0 -53
  46. data/lib/smart_core/container/dependency.rb +0 -44
  47. data/lib/smart_core/container/dependency_builder.rb +0 -48
  48. data/lib/smart_core/container/dependency_compatability/abstract.rb +0 -59
  49. data/lib/smart_core/container/dependency_compatability/command_set.rb +0 -35
  50. data/lib/smart_core/container/exceptions.rb +0 -31
  51. data/lib/smart_core/container/memoized_dependency.rb +0 -28
  52. data/lib/smart_core/container/namespace.rb +0 -51
@@ -1,227 +1,250 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class SmartCore::Container
4
- # @api private
5
- # @since 0.5.0
6
- class Registry
7
- # @since 0.5.0
8
- include Enumerable
9
-
10
- # @return [void]
11
- #
12
- # @api private
13
- # @since 0.5.0
14
- def initialize
15
- @access_lock = Mutex.new
16
- @registry = {}
17
- end
3
+ # @api private
4
+ # @since 0.7.0
5
+ # rubocop:disable Metrics/ClassLength
6
+ class SmartCore::Container::Registry
7
+ # @since 0.7.0
8
+ include Enumerable
9
+
10
+ # @return [Hash<Symbol,SmartCore::Container::Entity>]
11
+ #
12
+ # @api private
13
+ # @since 0.7.0
14
+ attr_reader :registry
18
15
 
19
- # @return [void]
20
- #
21
- # @api private
22
- # @since 0.5.0
23
- def freeze
24
- thread_safe { freeze_state }
25
- end
16
+ # @return [void]
17
+ #
18
+ # @api private
19
+ # @since 0.7.0
20
+ def initialize
21
+ @registry = {}
22
+ @access_lock = SmartCore::Container::ArbitaryLock.new
23
+ end
26
24
 
27
- # @return [void]
28
- #
29
- # @api private
30
- # @since 0.5.0
31
- def frozen?
32
- thread_safe { state_frozen? }
33
- end
25
+ # @param entity_path [String, Symbol]
26
+ # @return [SmartCore::Container::Entity]
27
+ #
28
+ # @api private
29
+ # @since 0.7.0
30
+ def resolve(entity_path)
31
+ thread_safe { fetch_entity(entity_path) }
32
+ end
34
33
 
35
- # @param dependency_path [String, Symbol]
36
- # @return [SmartCore::Container::Namespace, SmartCore::Container::Dependnecy]
37
- #
38
- # @api private
39
- # @since 0.5.0
40
- def resolve(dependency_path)
41
- thread_safe { fetch_dependency(dependency_path) }
42
- end
34
+ # @param name [String, Symbol]
35
+ # @param dependency_definition [Block]
36
+ # @return [void]
37
+ #
38
+ # @api private
39
+ # @since 0.7.0
40
+ def register_dependency(name, &dependency_definition)
41
+ thread_safe { add_dependency(name, dependency_definition) }
42
+ end
43
43
 
44
- # @param name [String, Symbol]
45
- # @param options [Hash<Symbol,Any>]
46
- # @param dependency_definition [Block]
47
- # @return [void]
48
- #
49
- # @todo option list
50
- #
51
- # @api private
52
- # @since 0.5.0
53
- def register(name, **options, &dependency_definition)
54
- thread_safe do
55
- raise(
56
- SmartCore::Container::FrozenRegistryError,
57
- 'Can not modify frozen registry'
58
- ) if state_frozen?
59
-
60
- append_dependency(name, dependency_definition, **options)
61
- end
62
- end
44
+ # @param name [String, Symbol]
45
+ # @param dependencies_definition [Block]
46
+ # @return [void]
47
+ #
48
+ # @api private
49
+ # @since 0.7.0
50
+ def register_namespace(name, &dependencies_definition)
51
+ thread_safe { add_namespace(name, dependencies_definition) }
52
+ end
63
53
 
64
- # @param name [String, Symbol]
65
- # @param dependency_definitions [Block]
66
- # @return [void]
67
- #
68
- # @api private
69
- # @since 0.5.0
70
- def namespace(name, &dependency_definitions)
71
- thread_safe do
72
- raise(
73
- SmartCore::Container::FrozenRegistryError,
74
- 'Can not modify frozen registry'
75
- ) if state_frozen?
76
-
77
- append_namespace(name, dependency_definitions)
78
- end
79
- end
54
+ # @return [void]
55
+ #
56
+ # @api private
57
+ # @since 0.7.0
58
+ def freeze!
59
+ thread_safe { freeze_state }
60
+ end
80
61
 
81
- # @param block [Block]
82
- # @return [Enumerable]
83
- #
84
- # @api private
85
- # @since 0.5.0
86
- def each(&block)
87
- thread_safe { block_given? ? registry.each_value(&block) : registry.each_value }
88
- end
62
+ # @return [Boolean]
63
+ #
64
+ # @api private
65
+ # @since 0.7.0
66
+ def frozen?
67
+ thread_safe { state_frozen? }
68
+ end
89
69
 
90
- # @return [Hash<Symbol,Any>]
91
- #
92
- # @api private
93
- # @since 0.5.0
94
- def to_h
95
- # TODO: implement :)
96
- end
70
+ # @param block [Block]
71
+ # @return [Enumerable]
72
+ #
73
+ # @api private
74
+ # @since 0.7.0
75
+ def each(&block)
76
+ thread_safe { enumerate(&block) }
77
+ end
97
78
 
98
- private
99
-
100
- # @return [Mutex]
101
- #
102
- # @api private
103
- # @since 0.5.0
104
- attr_reader :access_lock
105
-
106
- # @return [Hash<Symbol,SmartCore::Container::Entity>]
107
- #
108
- # @api private
109
- # @since 0.5.0
110
- attr_reader :registry
111
-
112
- # @return [Boolean]
113
- #
114
- # @api private
115
- # @since 0.5.0
116
- def state_frozen?
117
- registry.frozen?
118
- end
79
+ # @return [Hash<String|Symbol,SmartCore::Container::Entities::Base|Any>]
80
+ #
81
+ # @api private
82
+ # @since 0.7.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
119
88
 
120
- # @return [void]
121
- #
122
- # @api private
123
- # @since 0.5.0
124
- def freeze_state
125
- registry.freeze
126
- end
89
+ private
127
90
 
128
- # @paramm dependency_path [String, Symbol]
129
- # @return [SmartCore::Container::Namespace, SmartCore::Container::Dependency]
130
- #
131
- # @api private
132
- # @since 0.5.0
133
- def fetch_dependency(dependency_path)
134
- # TODO: rabbit style dependnecy path
135
- name = indifferently_accessable_name(dependency_path)
136
- registry.fetch(name)
137
- rescue KeyError
138
- raise(
139
- SmartCore::Container::UnexistentDependencyError,
140
- "Dependencny with '#{name}' name does not exist!"
141
- )
142
- end
91
+ # @return [Mutex]
92
+ #
93
+ # @api private
94
+ # @since 0.7.0
95
+ attr_reader :lock
143
96
 
144
- # @param dependency_name [String, Symbol]
145
- # @param dependency_definition [Proc]
146
- # @param options [Hash<Symbol,Any>]
147
- # @return [void]
148
- #
149
- # @todo option list
150
- # @raise [SmartCore::Container::NamespaceOverlapError]
151
- #
152
- # @api private
153
- # @since 0.5.0
154
- def append_dependency(dependency_name, dependency_definition, **options)
155
- dependency_name = indifferently_accessable_name(dependency_name)
156
- prevent_namespace_overlap!(dependency_name)
157
- dependency = DependencyBuilder.build(dependency_name, dependency_definition, **options)
158
-
159
- registry[dependency_name] = dependency
160
- end
97
+ # @return [Boolean]
98
+ #
99
+ # @api private
100
+ # @since 0.7.0
101
+ def state_frozen?
102
+ registry.frozen?
103
+ end
161
104
 
162
- # @param namespace_name [String, Symbol]
163
- # @param dependency_definitions [Proc]
164
- # @return [void]
165
- #
166
- # @raise [SmartCore::Container::DependencyOverlapError]
167
- #
168
- # @api private
169
- # @since 0.5.0
170
- def append_namespace(namespace_name, dependency_definitions)
171
- namespace_name = indifferently_accessable_name(namespace_name)
172
- prevent_dependency_overlap!(namespace_name)
173
-
174
- # rubocop:disable Layout/RescueEnsureAlignment
175
- namespace = begin
176
- registry.fetch(namespace_name)
177
- rescue KeyError
178
- registry[namespace_name] = SmartCore::Container::Namespace.new(namespace_name)
105
+ # @return [Hash<String|Symbol,SmartCore::Container::Entities::Base|Any>]
106
+ #
107
+ # @api private
108
+ # @since 0.7.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.resolve.hash_tree(resolve_dependencies: resolve_dependencies)
115
+ when SmartCore::Container::Entities::Dependency
116
+ tree[entity_name] = resolve_dependencies ? entity.resolve : entity
117
+ end
179
118
  end
180
- # rubocop:enable Layout/RescueEnsureAlignment
181
-
182
- namespace.append_definitions(dependency_definitions)
183
119
  end
120
+ end
184
121
 
185
- # @param name [String, Symbol]
186
- # @return [void]
187
- #
188
- # @see [SmartCore::Container::KeyGuard]
189
- #
190
- # @api private
191
- # @since 0.5.0
192
- def indifferently_accessable_name(name)
193
- SmartCore::Container::KeyGuard.indifferently_accessable_key(name)
122
+ # @return [void]
123
+ #
124
+ # @api private
125
+ # @since 0.7.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
194
131
  end
132
+ end
195
133
 
196
- # @param dependency_name [String]
197
- # @retrun [void]
198
- #
199
- # @api private
200
- # @since 0.5.0
201
- def prevent_namespace_overlap!(dependency_name)
202
- DependencyCompatability::Registry.prevent_namespace_overlap!(
203
- self, dependency_name
204
- )
134
+ # @param block
135
+ # @return [Enumerable]
136
+ #
137
+ # @api private
138
+ # @since 0.7.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.7.0
148
+ def fetch_entity(entity_path)
149
+ dependency_name = indifferently_accessable_name(entity_path)
150
+ registry.fetch(dependency_name)
151
+ rescue KeyError
152
+ raise(
153
+ SmartCore::Container::NonexistentEntityError,
154
+ "Entity with '#{dependency_name}' name does not exist!"
155
+ )
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.7.0
166
+ def add_dependency(dependency_name, dependency_definition)
167
+ if state_frozen?
168
+ raise(SmartCore::Container::FrozenRegistryError, 'Can not modify frozen registry!')
205
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
+ )
206
176
 
207
- # @param namespace_name [String]
208
- # @return [void]
209
- #
210
- # @api private
211
- # @since 0.5.0
212
- def prevent_dependency_overlap!(namespace_name)
213
- DependencyCompatability::Registry.prevent_dependency_overlap!(
214
- self, namespace_name
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.7.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::NonexistentEntityError
199
+ registry[namespace_name] = SmartCore::Container::Entities::NamespaceBuilder.build(
200
+ namespace_name
215
201
  )
216
202
  end
203
+ # rubocop:enable Layout/RescueEnsureAlignment
217
204
 
218
- # @param block [Proc]
219
- # @return [Any]
220
- #
221
- # @api private
222
- # @since 0.5.0
223
- def thread_safe(&block)
224
- @access_lock.synchronize(&block)
225
- end
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.7.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.7.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.7.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.7.0
246
+ def thread_safe(&block)
247
+ @access_lock.thread_safe(&block)
226
248
  end
227
249
  end
250
+ # rubocop:enable Metrics/ClassLength
@@ -1,18 +1,51 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # @api private
4
- # @since 0.5.0
4
+ # @since 0.7.0
5
5
  module SmartCore::Container::RegistryBuilder
6
+ # rubocop:disable Metrics/LineLength
6
7
  class << self
7
- # @param commands [SmartCore::Container::CommandSet]
8
+ # @parma container [SmartCore::Container]
9
+ # @option ignored_definition_commands [Array<Class::SmartCore::Container::DefinitionDSL::Commands::Base>>]
10
+ # @option ignored_instantiation_commands [Array<Class::SmartCore::Container::DefinitionDSL::Commands::Base>>]
8
11
  # @return [SmartCore::Container::Registry]
9
12
  #
10
13
  # @api private
11
- # @since 0.5.0
12
- def build(commands)
14
+ # @since 0.7.0
15
+ def build(container, ignored_definition_commands: [], ignored_instantiation_commands: [])
13
16
  SmartCore::Container::Registry.new.tap do |registry|
14
- commands.each { |command| command.call(registry) }
17
+ build_definitions(container.class, registry, ignored_commands: ignored_definition_commands)
18
+ build_state(container.class, registry, ignored_commands: ignored_instantiation_commands)
19
+ end
20
+ end
21
+
22
+ # @param container_klass [Class<SmartCore::Container>]
23
+ # @param registry [SmartCore::Container::Registry]
24
+ # @option ignored_commands [Array<Class<SmartCore::Container::DefinitionDSL::Commands::Base>>]
25
+ # @return [void]
26
+ #
27
+ # @api private
28
+ # @since 0.7.0
29
+ def build_definitions(container_klass, registry, ignored_commands: [])
30
+ container_klass.__container_definition_commands__.each do |command|
31
+ next if ignored_commands.include?(command.class)
32
+ command.call(registry)
33
+ end
34
+ end
35
+
36
+ # @param container_klass [Class<SmartCore::Container>]
37
+ # @param registry [SmartCore::Container::Registry]
38
+ # @option ignored_commands [Array<Class<SmartCore::Container::DefinitionDSL::Commands::Base>>]
39
+ # @return [void]
40
+ #
41
+ # @api private
42
+ # @since 0.7.0
43
+ def build_state(container_klass, registry, ignored_commands: [])
44
+ container_klass.__container_instantiation_commands__.each do |command|
45
+ next if ignored_commands.include?(command.class)
46
+ command.call(registry)
15
47
  end
16
48
  end
17
49
  end
50
+ # rubocop:enable Metrics/LineLength
18
51
  end