smart_initializer 0.1.0.alpha4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/.travis.yml +36 -5
  4. data/CHANGELOG.md +3 -0
  5. data/Gemfile.lock +48 -31
  6. data/README.md +151 -22
  7. data/Rakefile +1 -1
  8. data/bin/rspec +54 -0
  9. data/gemfiles/with_external_deps.gemfile +7 -0
  10. data/gemfiles/with_external_deps.gemfile.lock +99 -0
  11. data/gemfiles/without_external_deps.gemfile +5 -0
  12. data/gemfiles/without_external_deps.gemfile.lock +97 -0
  13. data/lib/smart_core/initializer.rb +38 -35
  14. data/lib/smart_core/initializer/attribute.rb +12 -4
  15. data/lib/smart_core/initializer/attribute/factory.rb +47 -27
  16. data/lib/smart_core/initializer/attribute/parameters.rb +12 -4
  17. data/lib/smart_core/initializer/configurable_module.rb +27 -0
  18. data/lib/smart_core/initializer/configuration.rb +33 -0
  19. data/lib/smart_core/initializer/constructor.rb +9 -6
  20. data/lib/smart_core/initializer/constructor/definer.rb +34 -11
  21. data/lib/smart_core/initializer/dsl.rb +23 -6
  22. data/lib/smart_core/initializer/errors.rb +44 -0
  23. data/lib/smart_core/initializer/plugins.rb +17 -0
  24. data/lib/smart_core/initializer/plugins/abstract.rb +55 -0
  25. data/lib/smart_core/initializer/plugins/access_mixin.rb +47 -0
  26. data/lib/smart_core/initializer/plugins/registry.rb +166 -0
  27. data/lib/smart_core/initializer/plugins/registry_interface.rb +77 -0
  28. data/lib/smart_core/initializer/plugins/thy_types.rb +30 -0
  29. data/lib/smart_core/initializer/plugins/thy_types/errors.rb +11 -0
  30. data/lib/smart_core/initializer/plugins/thy_types/thy_types.rb +23 -0
  31. data/lib/smart_core/initializer/plugins/thy_types/thy_types/abstract_factory.rb +78 -0
  32. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation.rb +12 -0
  33. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation/base.rb +9 -0
  34. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation/cast.rb +21 -0
  35. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation/valid.rb +16 -0
  36. data/lib/smart_core/initializer/plugins/thy_types/thy_types/operation/validate.rb +19 -0
  37. data/lib/smart_core/initializer/settings.rb +49 -0
  38. data/lib/smart_core/initializer/settings/duplicator.rb +20 -0
  39. data/lib/smart_core/initializer/settings/type_system.rb +69 -0
  40. data/lib/smart_core/initializer/type_system.rb +16 -0
  41. data/lib/smart_core/initializer/type_system/interop.rb +103 -0
  42. data/lib/smart_core/initializer/type_system/interop/abstract_factory.rb +70 -0
  43. data/lib/smart_core/initializer/type_system/interop/aliasing.rb +72 -0
  44. data/lib/smart_core/initializer/type_system/interop/aliasing/alias_list.rb +141 -0
  45. data/lib/smart_core/initializer/type_system/interop/operation.rb +30 -0
  46. data/lib/smart_core/initializer/type_system/registry.rb +174 -0
  47. data/lib/smart_core/initializer/type_system/registry_interface.rb +102 -0
  48. data/lib/smart_core/initializer/type_system/smart_types.rb +48 -0
  49. data/lib/smart_core/initializer/type_system/smart_types/abstract_factory.rb +72 -0
  50. data/lib/smart_core/initializer/type_system/smart_types/operation.rb +13 -0
  51. data/lib/smart_core/initializer/type_system/smart_types/operation/base.rb +8 -0
  52. data/lib/smart_core/initializer/type_system/smart_types/operation/cast.rb +16 -0
  53. data/lib/smart_core/initializer/type_system/smart_types/operation/valid.rb +16 -0
  54. data/lib/smart_core/initializer/type_system/smart_types/operation/validate.rb +16 -0
  55. data/lib/smart_core/initializer/version.rb +1 -1
  56. data/smart_initializer.gemspec +13 -9
  57. metadata +67 -17
  58. data/lib/smart_core/initializer/attribute/init_extension.rb +0 -4
  59. data/lib/smart_core/initializer/type_aliasing.rb +0 -50
  60. data/lib/smart_core/initializer/type_aliasing/alias_list.rb +0 -101
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module SmartCore::Initializer::Plugins::AccessMixin
6
+ # @param plugin_name [Symbol, String]
7
+ # @return [void]
8
+ #
9
+ # @see SmartCore::Initializer::Plugins
10
+ #
11
+ # @api public
12
+ # @since 0.1.0
13
+ def plugin(plugin_name)
14
+ SmartCore::Initializer::Plugins.load(plugin_name)
15
+ end
16
+
17
+ # @return [Array<String>]
18
+ #
19
+ # @see SmartCore::Initializer::Plugins
20
+ #
21
+ # @api public
22
+ # @since 0.1.0
23
+ def plugins
24
+ SmartCore::Initializer::Plugins.names
25
+ end
26
+
27
+ # @return [Hash<String,Class<SmartCore::Initializer::Plugins::Abstract>>]
28
+ #
29
+ # @api private
30
+ # @since 0.1.0
31
+ def loaded_plugins
32
+ SmartCore::Initializer::Plugins.loaded_plugins
33
+ end
34
+ alias_method :enabled_plugins, :loaded_plugins
35
+
36
+ # @param plugin_name [String, Symbol]
37
+ # @param plugin_klass [Class<SmartCore::Initializer::Plugins::Abstract>]
38
+ # @return [void]
39
+ #
40
+ # @see SmartCore::Initializer::Plugins
41
+ #
42
+ # @api public
43
+ # @since 0.1.0
44
+ def register_plugin(plugin_name, plugin_klass)
45
+ SmartCore::Initializer::Plugins.register_plugin(plugin_name, plugin_klass)
46
+ end
47
+ end
@@ -0,0 +1,166 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Initializer::Plugins::Registry
6
+ # @since 0.1.0
7
+ include Enumerable
8
+
9
+ # @return [void]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ def initialize
14
+ @plugin_set = {}
15
+ @access_lock = Mutex.new
16
+ end
17
+
18
+ # @param plugin_name [Symbol, String]
19
+ # @return [SmartCore::Initializer::Plugins::Abstract]
20
+ #
21
+ # @api private
22
+ # @since 0.1.0
23
+ def [](plugin_name)
24
+ thread_safe { fetch(plugin_name) }
25
+ end
26
+
27
+ # @param plugin_name [Symbol, String]
28
+ # @param plugin_module [SmartCore::Initializer::Plugins::Abstract]
29
+ # @return [void]
30
+ #
31
+ # @api private
32
+ # @since 0.1.0
33
+ def register(plugin_name, plugin_module)
34
+ thread_safe { apply(plugin_name, plugin_module) }
35
+ end
36
+ alias_method :[]=, :register
37
+
38
+ # @return [Array<String>]
39
+ #
40
+ # @api private
41
+ # @since 0.1.0
42
+ def names
43
+ thread_safe { plugin_names }
44
+ end
45
+
46
+ # @return [Hash<String,Class<SmartCore::Initializer::Plugins::Abstract>>]
47
+ #
48
+ # @api private
49
+ # @since 0.1.0
50
+ def loaded
51
+ thread_safe { loaded_plugins }
52
+ end
53
+
54
+ # @param block [Block]
55
+ # @return [Enumerable]
56
+ #
57
+ # @api private
58
+ # @since 0.1.0
59
+ def each(&block)
60
+ thread_safe { iterate(&block) }
61
+ end
62
+
63
+ private
64
+
65
+ # @return [Hash]
66
+ #
67
+ # @api private
68
+ # @since 0.1.0
69
+ attr_reader :plugin_set
70
+
71
+ # @return [Mutex]
72
+ #
73
+ # @api private
74
+ # @since 0.1.0
75
+ attr_reader :access_lock
76
+
77
+ # @return [void]
78
+ #
79
+ # @api private
80
+ # @since 0.1.0
81
+ def thread_safe
82
+ access_lock.synchronize { yield if block_given? }
83
+ end
84
+
85
+ # @return [Array<String>]
86
+ #
87
+ # @api private
88
+ # @since 0.1.0
89
+ def plugin_names
90
+ plugin_set.keys
91
+ end
92
+
93
+ # @param block [Block]
94
+ # @return [Enumerable]
95
+ #
96
+ # @api private
97
+ # @since 0.1.0
98
+ def iterate(&block)
99
+ block_given? ? plugin_set.each_pair(&block) : plugin_set.each_pair
100
+ end
101
+
102
+ # @param plugin_name [String]
103
+ # @return [Boolean]
104
+ #
105
+ # @api private
106
+ # @since 0.1.0
107
+ def registered?(plugin_name)
108
+ plugin_set.key?(plugin_name)
109
+ end
110
+
111
+ # @return [Array<SmartCore::Initializer::Plugins::Abstract>]
112
+ #
113
+ # @api private
114
+ # @since 0.1.0
115
+ def loaded_plugins
116
+ plugin_set.select { |_plugin_name, plugin_module| plugin_module.loaded? }
117
+ end
118
+
119
+ # @param plugin_name [Symbol, String]
120
+ # @param plugin_module [SmartCore::Initializer::Plugins::Abstract]
121
+ # @return [void]
122
+ #
123
+ # @raise [SmartCore::Initializer::AlreadyRegisteredPluginError]
124
+ #
125
+ # @api private
126
+ # @since 0.1.0
127
+ def apply(plugin_name, plugin_module)
128
+ plugin_name = indifferently_accessible_plugin_name(plugin_name)
129
+
130
+ if registered?(plugin_name)
131
+ raise(SmartCore::Initializer::AlreadyRegisteredPluginError, <<~ERROR_MESSAGE)
132
+ #{plugin_name} plugin already exists
133
+ ERROR_MESSAGE
134
+ end
135
+
136
+ plugin_set[plugin_name] = plugin_module
137
+ end
138
+
139
+ # @param plugin_name [Symbol, String]
140
+ # @return [SmartCore::Initializer::Plugins::Abstract]
141
+ #
142
+ # @raise [SmartCore::Initializer::UnregisteredPluginError]
143
+ #
144
+ # @api private
145
+ # @since 0.1.0
146
+ def fetch(plugin_name)
147
+ plugin_name = indifferently_accessible_plugin_name(plugin_name)
148
+
149
+ unless registered?(plugin_name)
150
+ raise(SmartCore::Initializer::UnregisteredPluginError, <<~ERROR_MESSAGE)
151
+ #{plugin_name} plugin is not registered
152
+ ERROR_MESSAGE
153
+ end
154
+
155
+ plugin_set[plugin_name]
156
+ end
157
+
158
+ # @param key [Symbol, String]
159
+ # @return [String]
160
+ #
161
+ # @api private
162
+ # @since 0.1.0
163
+ def indifferently_accessible_plugin_name(plugin_name)
164
+ plugin_name.to_s
165
+ end
166
+ end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module SmartCore::Initializer::Plugins::RegistryInterface
6
+ class << self
7
+ # @param base_module [Class, Module]
8
+ # @return [void]
9
+ #
10
+ # @api private
11
+ # @since 0.1.0
12
+ def extended(base_module)
13
+ base_module.instance_variable_set(
14
+ :@plugin_registry, SmartCore::Initializer::Plugins::Registry.new
15
+ )
16
+ base_module.instance_variable_set(
17
+ :@access_lock, SmartCore::Engine::Lock.new
18
+ )
19
+ end
20
+ end
21
+
22
+ # @param plugin_name [Symbol, String]
23
+ # @return [void]
24
+ #
25
+ # @api public
26
+ # @since 0.1.0
27
+ def load(plugin_name)
28
+ thread_safe { plugin_registry[plugin_name].load! }
29
+ end
30
+
31
+ # @return [Array<String>]
32
+ #
33
+ # @api public
34
+ # @since 0.1.0
35
+ def loaded_plugins
36
+ thread_safe { plugin_registry.loaded.keys }
37
+ end
38
+
39
+ # @return [Array<String>]
40
+ #
41
+ # @api public
42
+ # @since 0.1.0
43
+ def names
44
+ thread_safe { plugin_registry.names }
45
+ end
46
+
47
+ # @param plugin_name [Symbol, String]
48
+ # @return [void]
49
+ #
50
+ # @api private
51
+ # @since 0.1.0
52
+ def register_plugin(plugin_name, plugin_module)
53
+ thread_safe { plugin_registry[plugin_name] = plugin_module }
54
+ end
55
+
56
+ private
57
+
58
+ # @return [SmartCore::Initializer::Plugins::Registry]
59
+ #
60
+ # @api private
61
+ # @since 0.1.0
62
+ attr_reader :plugin_registry
63
+
64
+ # @return [SmartCore::Engine::Lock]
65
+ #
66
+ # @api private
67
+ # @since 0.1.0
68
+ attr_reader :access_lock
69
+
70
+ # @return [void]
71
+ #
72
+ # @api private
73
+ # @since 0.1.0
74
+ def thread_safe
75
+ access_lock.synchronize { yield if block_given? }
76
+ end
77
+ end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Initializer::Plugins::ThyTypes < SmartCore::Initializer::Plugins::Abstract
6
+ class << self
7
+ # @return [void]
8
+ #
9
+ # @api private
10
+ # @since 0.1.0
11
+ def install!
12
+ raise(
13
+ SmartCore::Initializer::UnresolvedPluginDependencyError,
14
+ '::Thy does not exist or "thy" gem is not loaded'
15
+ ) unless const_defined?('::Thy')
16
+
17
+ # NOTE: require necessary dependencies
18
+ require 'date'
19
+
20
+ # NOTE: add thy-types type system implementation
21
+ require_relative 'thy_types/errors'
22
+ require_relative 'thy_types/thy_types'
23
+
24
+ # NOTE: register thy-types type system
25
+ SmartCore::Initializer::TypeSystem.register(
26
+ :thy_types, SmartCore::Initializer::TypeSystem::ThyTypes
27
+ )
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartCore::Initializer
4
+ # @api public
5
+ # @since 0.1.0
6
+ ThyTypesError = Class.new(SmartCore::Initializer::Error)
7
+
8
+ # @api public
9
+ # @since 0.1.0
10
+ ThyTypeValidationError = Class.new(ThyTypesError)
11
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartCore::Initializer::TypeSystem
4
+ # @api public
5
+ # @since 0.1.0
6
+ class ThyTypes < Interop
7
+ require_relative 'thy_types/abstract_factory'
8
+ require_relative 'thy_types/operation'
9
+
10
+ type_alias(:any, AbstractFactory.generic_type_object)
11
+ type_alias(:nil, ::Thy::Types::Nil)
12
+ type_alias(:string, ::Thy::Types::String)
13
+ type_alias(:symbol, ::Thy::Types::Symbol)
14
+ type_alias(:integer, ::Thy::Types::Integer)
15
+ type_alias(:float, ::Thy::Types::Float)
16
+ type_alias(:numeric, ::Thy::Types::Numeric)
17
+ type_alias(:boolean, ::Thy::Types::Boolean)
18
+ type_alias(:time, ::Thy::Types::Time)
19
+ type_alias(:date_time, ::Thy::Types::DateTime)
20
+ type_alias(:untyped_array, ::Thy::Types::UntypedArray)
21
+ type_alias(:untyped_hash, ::Thy::Types::UntypedHash)
22
+ end
23
+ end
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartCore::Initializer::TypeSystem
4
+ # @api private
5
+ # @since 0.1.0
6
+ class ThyTypes::AbstractFactory < Interop::AbstractFactory
7
+ # @return [Thy::Type]
8
+ #
9
+ # @api private
10
+ # @since 0.1.0
11
+ GENERIC_TYPE = ::Thy::Type.new { true }
12
+
13
+ class << self
14
+ # @param type [Thy::Type, #check]
15
+ # @return [void]
16
+ #
17
+ # @raise [SmartCore::Initializer::IncorrectTypeObjectError]
18
+ #
19
+ # @api private
20
+ # @since 0.1.0
21
+ def prevent_incompatible_type!(type)
22
+ unless type.respond_to?(:check) || type.is_a?(::Thy::Type)
23
+ raise(
24
+ SmartCore::Initializer::IncorrectTypeObjectError,
25
+ 'Incorrect Thy::Type primitive ' \
26
+ '(type object should respond to :check method)'
27
+ )
28
+ end
29
+ end
30
+
31
+ # @param type [Thy::Type, #check]
32
+ # @return [SmartCore::Initializer::TypeSystem::ThyTypes::Operation::Valid]
33
+ #
34
+ # @api private
35
+ # @since 0.1.0
36
+ def build_valid_operation(type)
37
+ ThyTypes::Operation::Valid.new(type)
38
+ end
39
+
40
+ # @return [Thy::Type, #check]
41
+ #
42
+ # @api private
43
+ # @since 0.1.0
44
+ def generic_type_object
45
+ GENERIC_TYPE
46
+ end
47
+
48
+ # @param type [Thy::Type, #check]
49
+ # @return [SmartCore::Initializer::TypeSystem::ThyTypes::Operation::Validate]
50
+ #
51
+ # @api private
52
+ # @since 0.1.0
53
+ def build_validate_operation(type)
54
+ ThyTypes::Operation::Validate.new(type)
55
+ end
56
+
57
+ # @param type [Thy::Type, #check]
58
+ # @return [SmartCore::Initializer::TypeSystem::ThyTypes::Operation::Cast]
59
+ #
60
+ # @api private
61
+ # @since 0.1.0
62
+ def build_cast_operation(type)
63
+ ThyTypes::Operation::Cast.new(type)
64
+ end
65
+
66
+ # @param valid_op [SmartCore::Initializer::TypeSystem::ThyTypes::Operation::Valid]
67
+ # @param valid_op [SmartCore::Initializer::TypeSystem::ThyTypes::Operation::Validate]
68
+ # @param valid_op [SmartCore::Initializer::TypeSystem::ThyTypes::Operation::Cast]
69
+ # @return [SmartCore::Initializer::TypeSystem::ThyTypes]
70
+ #
71
+ # @api private
72
+ # @since 0.1.0
73
+ def build_interop(valid_op, validate_op, cast_op)
74
+ ThyTypes.new(valid_op, validate_op, cast_op)
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartCore::Initializer::TypeSystem
4
+ # @api private
5
+ # @since 0.1.0
6
+ module ThyTypes::Operation
7
+ require_relative 'operation/base'
8
+ require_relative 'operation/valid'
9
+ require_relative 'operation/validate'
10
+ require_relative 'operation/cast'
11
+ end
12
+ end