smart_core 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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