smart_initializer 0.0.0

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