smart_initializer 0.0.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.
@@ -0,0 +1,180 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Initializer::Attribute::Definer
6
+ # @param klass [Class]
7
+ # @return [void]
8
+ #
9
+ # @api private
10
+ # @since 0.1.0
11
+ def initialize(klass)
12
+ @klass = klass
13
+ @lock = SmartCore::Engine::Lock.new
14
+ end
15
+
16
+ # @param name [String, Symbol]
17
+ # @param type [String, Symbol, SmartCore::Types::Primitive]
18
+ # @param privacy [String, Symbol]
19
+ # @param finalize [String, Symbol, Proc]
20
+ # @param cast [Boolean]
21
+ # @param dynamic_options [Hash<Symbol,Any>]
22
+ # @return [void]
23
+ #
24
+ # @api private
25
+ # @since 0.1.0
26
+ def define_parameter(name, type, privacy, finalize, cast, dynamic_options)
27
+ thread_safe do
28
+ attribute = build_attribute(name, type, privacy, finalize, cast, dynamic_options)
29
+ prevent_option_overlap(attribute)
30
+ add_parameter(attribute)
31
+ end
32
+ end
33
+
34
+ # @param names [Array<String, Symbol>]
35
+ # @return [void]
36
+ #
37
+ # @api private
38
+ # @since 0.1.0
39
+ def define_parameters(*names)
40
+ thread_safe do
41
+ names.map do |name|
42
+ build_attribute(
43
+ name,
44
+ SmartCore::Types::Any,
45
+ SmartCore::Initializer::Attribute::Parameters::DEFAULT_PRIVACY_MODE,
46
+ SmartCore::Initializer::Attribute::Parameters::DEFAULT_FINALIZER,
47
+ SmartCore::Initializer::Attribute::Parameters::DEFAULT_CAST_BEHAVIOUR,
48
+ SmartCore::Initializer::Attribute::Parameters::DEFAULT_DYNAMIC_OPTIONS.dup
49
+ ).tap do |attribute|
50
+ prevent_option_overlap(attribute)
51
+ end
52
+ end.each do |attribute|
53
+ add_parameter(attribute)
54
+ end
55
+ end
56
+ end
57
+
58
+ # @param name [String, Symbol]
59
+ # @param type [String, Symbol, SmartCore::Types::Primitive]
60
+ # @param privacy [String, Symbol]
61
+ # @param finalize [String, Symbol, Proc]
62
+ # @param cast [Boolean]
63
+ # @param dynamic_options [Hash<Symbol,Any>]
64
+ # @return [void]
65
+ #
66
+ # @api private
67
+ # @since 0.1.0
68
+ def define_option(name, type, privacy, finalize, cast, dynamic_options)
69
+ thread_safe do
70
+ attribute = build_attribute(name, type, privacy, finalize, cast, dynamic_options)
71
+ prevent_parameter_overlap(attribute)
72
+ add_option(attribute)
73
+ end
74
+ end
75
+
76
+ # @param names [Array<String, Symbol>]
77
+ # @return [void]
78
+ #
79
+ # @api private
80
+ # @since 0.1.0
81
+ def define_options(*names)
82
+ thread_safe do
83
+ names.map do |name|
84
+ build_attribute(
85
+ name,
86
+ SmartCore::Types::Any,
87
+ SmartCore::Initializer::Attribute::Parameters::DEFAULT_PRIVACY_MODE,
88
+ SmartCore::Initializer::Attribute::Parameters::DEFAULT_FINALIZER,
89
+ SmartCore::Initializer::Attribute::Parameters::DEFAULT_CAST_BEHAVIOUR,
90
+ SmartCore::Initializer::Attribute::Parameters::DEFAULT_DYNAMIC_OPTIONS.dup
91
+ ).tap do |attribute|
92
+ prevent_parameter_overlap(attribute)
93
+ end
94
+ end.each do |attribute|
95
+ add_option(attribute)
96
+ end
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ # @return [Class]
103
+ #
104
+ # @api private
105
+ # @since 0.1.0
106
+ attr_reader :klass
107
+
108
+ # @param name [String, Symbol]
109
+ # @param type [String, Symbol, SmartCore::Types::Primitive]
110
+ # @param privacy [String, Symbol]
111
+ # @param finalize [String, Symbol, Proc]
112
+ # @param cast [Boolean]
113
+ # @param dynamic_options [Hash<Symbol,Any>]
114
+ # @return [SmartCore::Initializer::Attribute]
115
+ #
116
+ # @api private
117
+ # @since 0.1.0
118
+ def build_attribute(name, type, privacy, finalize, cast, dynamic_options)
119
+ SmartCore::Initializer::Attribute::Factory.create(
120
+ name, type, privacy, finalize, cast, dynamic_options
121
+ )
122
+ end
123
+
124
+ # @param parameter [SmartCore::Initializer::Attribute]
125
+ # @return [void]
126
+ #
127
+ # @api private
128
+ # @since 0.1.0
129
+ def add_parameter(parameter)
130
+ klass.__params__ << parameter
131
+ klass.send(:attr_reader, parameter.name)
132
+ klass.send(parameter.privacy, parameter.name)
133
+ end
134
+
135
+ # @param option [SmartCore::Initializer::Attribute]
136
+ # @return [void]
137
+ #
138
+ # @api private
139
+ # @since 0.1.0
140
+ def add_option(option)
141
+ klass.__options__ << option
142
+ klass.send(:attr_reader, option.name)
143
+ klass.send(option.privacy, option.name)
144
+ end
145
+
146
+ # @param parameter [SmartCore::Initializer::Attribute]
147
+ # @return [void]
148
+ #
149
+ # @api private
150
+ # @since 0.1.0
151
+ def prevent_option_overlap(parameter)
152
+ if klass.__options__.include?(parameter)
153
+ raise(SmartCore::Initializer::OptionOverlapError, <<~ERROR_MESSAGE)
154
+ You have already defined option with name :#{parameter.name}
155
+ ERROR_MESSAGE
156
+ end
157
+ end
158
+
159
+ # @param option [SmartCore::Initializer::Attribute]
160
+ # @return [void]
161
+ #
162
+ # @api private
163
+ # @since 0.1.0
164
+ def prevent_parameter_overlap(option)
165
+ if klass.__params__.include?(option)
166
+ raise(SmartCore::Initializer::ParameterOverlapError, <<~ERROR_MESSAGE)
167
+ You have already defined parameter with name :#{option.name}
168
+ ERROR_MESSAGE
169
+ end
170
+ end
171
+
172
+ # @param block [Block]
173
+ # @return [Any]
174
+ #
175
+ # @api private
176
+ # @since 0.1.0
177
+ def thread_safe(&block)
178
+ @lock.synchronize(&block)
179
+ end
180
+ end
@@ -0,0 +1,140 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Initializer::Attribute::Factory
6
+ class << self
7
+ # @param name [String, Symbol]
8
+ # @param type [String, Symbol, SmartCore::Types::Primitive]
9
+ # @param privacy [String, Symbol]
10
+ # @param finalize [String, Symbol, Proc]
11
+ # @param cast [Boolean]
12
+ # @param dynamic_options [Hash<Symbol,Any>]
13
+ # @return [SmartCore::Initializer::Attribute]
14
+ #
15
+ # @api private
16
+ # @since 0.1.0
17
+ def create(name, type, privacy, finalize, cast, dynamic_options)
18
+ name = prepare_name_param(name)
19
+ type = prepare_type_param(type)
20
+ privacy = prepare_privacy_param(privacy)
21
+ finalize = prepare_finalize_param(finalize)
22
+ cast = prepare_cast_param(cast)
23
+ dynamic_options = prepare_dynamic_options_param(dynamic_options)
24
+
25
+ create_attribute(name, type, privacy, finalize, cast, dynamic_options)
26
+ end
27
+
28
+ private
29
+
30
+ # @param name [String, Symbol]
31
+ # @return [String]
32
+ #
33
+ # @api private
34
+ # @since 0.1.0
35
+ def prepare_name_param(name)
36
+ unless name.is_a?(String) || name.is_a?(Symbol)
37
+ raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
38
+ Attribute name should be a type of String or Symbol
39
+ ERROR_MESSAGE
40
+ end
41
+
42
+ name.to_s
43
+ end
44
+
45
+ # @param type [String, Symbol, SmartCore::Types::Primitive]
46
+ # @return [SmartCore::Types::Primitive]
47
+ #
48
+ # @api private
49
+ # @since 0.1.0
50
+ def prepare_type_param(type)
51
+ unless type.is_a?(String) || type.is_a?(Symbol) || type.is_a?(SmartCore::Types::Primitive)
52
+ raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
53
+ Attribute type should be a type of String, Symbol or SmartCore::Types::Primitive
54
+ ERROR_MESSAGE
55
+ end
56
+
57
+ type
58
+ end
59
+
60
+ # @param cast [Boolean]
61
+ # @return [Boolean]
62
+ #
63
+ # @api private
64
+ # @since 0.1.0
65
+ def prepare_cast_param(cast)
66
+ unless cast.is_a?(TrueClass) || cast.is_a?(FalseClass)
67
+ raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
68
+ Attribute cast should be a type of boolean
69
+ ERROR_MESSAGE
70
+ end
71
+
72
+ cast
73
+ end
74
+
75
+ # @param privacy [String, Symbol]
76
+ # @return [Symbol]
77
+ #
78
+ # @api private
79
+ # @since 0.1.0
80
+ def prepare_privacy_param(privacy)
81
+ unless privacy.is_a?(String) || privacy.is_a?(Symbol)
82
+ raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
83
+ Attribute privacy should be a type of String or Symbol
84
+ ERROR_MESSAGE
85
+ end
86
+
87
+ SmartCore::Initializer::Attribute::Parameters::PRIVACY_MODES.fetch(privacy.to_sym) do
88
+ raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
89
+ Incorrect attribute privacy identifier "#{privacy}"
90
+ ERROR_MESSAGE
91
+ end
92
+ end
93
+
94
+ # @param finalize [String, Symbol, Proc]
95
+ # @return [SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock/InstanceMethod]
96
+ #
97
+ # @api private
98
+ # @since 0.1.0
99
+ def prepare_finalize_param(finalize)
100
+ unless finalize.is_a?(String) || finalize.is_a?(Symbol) || finalize.is_a?(Proc)
101
+ raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
102
+ Attribute finalizer should be a type of String, Symbol or Proc
103
+ ERROR_MESSAGE
104
+ end
105
+
106
+ SmartCore::Initializer::Attribute::Finalizer.create(finalize)
107
+ end
108
+
109
+ # @param dynamic_options [Hash<Symbol,Any>]
110
+ # @return [Hash<Symbol,Any>]
111
+ #
112
+ # @api private
113
+ # @since 0.1.0
114
+ def prepare_dynamic_options_param(dynamic_options)
115
+ # :nocov:
116
+ unless dynamic_options.is_a?(Hash)
117
+ raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
118
+ Attribute dynamic options should be a type of Hash
119
+ ERROR_MESSAGE
120
+ end
121
+ # :nocov:
122
+
123
+ dynamic_options
124
+ end
125
+
126
+ # @param name [String]
127
+ # @param type [SmartCore::Types::Primitive]
128
+ # @param privacy [Symbol]
129
+ # @param finalize [SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock/InstanceMethod]
130
+ # @param cast [Boolean]
131
+ # @param dynamic_options [Hash<Symbol,String>]
132
+ # @return [SmartCore::Initializer::Attribute]
133
+ #
134
+ # @api private
135
+ # @since 0.1.0
136
+ def create_attribute(name, type, privacy, finalize, cast, dynamic_options)
137
+ SmartCore::Initializer::Attribute.new(name, type, privacy, finalize, cast, dynamic_options)
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ module SmartCore::Initializer::Attribute::Finalizer
6
+ require_relative 'finalizer/instance_method'
7
+ require_relative 'finalizer/anonymous_block'
8
+
9
+ # @return [Proc]
10
+ #
11
+ # @api private
12
+ # @since 0.1.0
13
+ DEFAULT_FINALIZER = proc { |value| value }.freeze
14
+
15
+ class << self
16
+ # @param finalization_approach [String, Symbol, Proc]
17
+ # @return [SmartCore::Initializer::Attribute::Finalizer::InstanceMethod]
18
+ # @return [SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock]
19
+ #
20
+ # @api private
21
+ # @since 0.1.0
22
+ def create(finalization_approach)
23
+ case finalization_approach
24
+ when String, Symbol
25
+ InstanceMethod.new(finalization_approach)
26
+ when Proc
27
+ AnonymousBlock.new(finalization_approach)
28
+ else
29
+ # :nocov:
30
+ raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
31
+ Finalization approach should be a type of Proc, Symbol or String'
32
+ ERROR_MESSAGE
33
+ # :nocov:
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @pai private
4
+ # @since 0.1.0
5
+ class SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock
6
+ # @param finalizer [Proc]
7
+ # @return [void]
8
+ #
9
+ # @api private
10
+ # @since 0.1.0
11
+ def initialize(finalizer)
12
+ @finalizer = finalizer
13
+ end
14
+
15
+ # @param value [Any]
16
+ # @param isntance [Any]
17
+ # @return [value]
18
+ #
19
+ # @pai private
20
+ # @since 0.1.0
21
+ def call(value, instance)
22
+ instance.instance_exec(value, &finalizer)
23
+ end
24
+
25
+ private
26
+
27
+ # @return [NilClass, Any]
28
+ #
29
+ # @api private
30
+ # @since 0.1.0
31
+ attr_reader :finalizer
32
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @pai private
4
+ # @since 0.1.0
5
+ class SmartCore::Initializer::Attribute::Finalizer::InstanceMethod
6
+ # @param finalizer [String, Symbol]
7
+ # @return [void]
8
+ #
9
+ # @api private
10
+ # @since 0.1.0
11
+ def initialize(finalizer)
12
+ @finalizer = finalizer
13
+ end
14
+
15
+ # @param value [Any]
16
+ # @param instance [Any]
17
+ # @return [value]
18
+ #
19
+ # @pai private
20
+ # @since 0.1.0
21
+ def call(value, instance)
22
+ instance.send(finalizer, value)
23
+ end
24
+
25
+ private
26
+
27
+ # @return [NilClass, Any]
28
+ #
29
+ # @api private
30
+ # @since 0.1.0
31
+ attr_reader :finalizer
32
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.1.0
5
+ class SmartCore::Initializer::Attribute::List
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
+ @attributes = {}
15
+ @lock = SmartCore::Engine::Lock.new
16
+ end
17
+
18
+ # @param attribute [SmartCore::Initializer::Attribute]
19
+ # @return [void]
20
+ #
21
+ # @api private
22
+ # @since 0.1.0
23
+ def add(attribute)
24
+ thread_safe { attributes[attribute.name] = attribute }
25
+ end
26
+ alias_method :<<, :add
27
+
28
+ # @param attribute [SmartCore::Initializer::Attribute]
29
+ # @return [void]
30
+ #
31
+ # @api private
32
+ # @since 0.1.0
33
+ def include?(attribute)
34
+ thread_safe { attributes.key?(attribute.name) }
35
+ end
36
+
37
+ # @param block [Block]
38
+ # @return [Enumerable]
39
+ #
40
+ # @api private
41
+ # @since 0.1.0
42
+ def each(&block)
43
+ thread_safe do
44
+ block_given? ? attributes.values.each(&block) : attributes.values.each
45
+ end
46
+ end
47
+
48
+ private
49
+
50
+ # @return [Hash<String,SmartCore::Initializer::Attribute>]
51
+ #
52
+ # @api private
53
+ # @since 0.1.0
54
+ attr_reader :attributes
55
+
56
+ # @param block [Block]
57
+ # @return [Any]
58
+ #
59
+ # @api private
60
+ # @since 0.1.0
61
+ def thread_safe(&block)
62
+ @lock.synchronize(&block)
63
+ end
64
+ end