smart_initializer 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +35 -3
  4. data/Gemfile.lock +38 -38
  5. data/README.md +260 -46
  6. data/bin/console +2 -2
  7. data/gemfiles/with_external_deps.gemfile.lock +38 -38
  8. data/lib/smart_core/initializer/attribute/factory/base.rb +145 -0
  9. data/lib/smart_core/initializer/attribute/factory/option.rb +107 -0
  10. data/lib/smart_core/initializer/attribute/factory/param.rb +63 -0
  11. data/lib/smart_core/initializer/attribute/factory.rb +5 -199
  12. data/lib/smart_core/initializer/attribute/finalizer/abstract.rb +2 -0
  13. data/lib/smart_core/initializer/attribute/finalizer/instance_method.rb +1 -1
  14. data/lib/smart_core/initializer/attribute/finalizer.rb +5 -5
  15. data/lib/smart_core/initializer/attribute/list.rb +20 -0
  16. data/lib/smart_core/initializer/attribute/{parameters.rb → value/base.rb} +35 -65
  17. data/lib/smart_core/initializer/attribute/value/option.rb +101 -0
  18. data/lib/smart_core/initializer/attribute/value/param.rb +24 -0
  19. data/lib/smart_core/initializer/attribute/value.rb +9 -0
  20. data/lib/smart_core/initializer/attribute.rb +3 -125
  21. data/lib/smart_core/initializer/configuration.rb +7 -3
  22. data/lib/smart_core/initializer/constructor/definer.rb +135 -46
  23. data/lib/smart_core/initializer/constructor.rb +30 -12
  24. data/lib/smart_core/initializer/dsl.rb +38 -24
  25. data/lib/smart_core/initializer/errors.rb +20 -4
  26. data/lib/smart_core/initializer/functionality.rb +7 -8
  27. data/lib/smart_core/initializer/settings/auto_cast.rb +40 -0
  28. data/lib/smart_core/initializer/settings/base.rb +49 -0
  29. data/lib/smart_core/initializer/settings/duplicator.rb +5 -0
  30. data/lib/smart_core/initializer/settings/strict_options.rb +40 -0
  31. data/lib/smart_core/initializer/settings/type_system.rb +10 -28
  32. data/lib/smart_core/initializer/settings.rb +40 -0
  33. data/lib/smart_core/initializer/type_system/registry.rb +2 -1
  34. data/lib/smart_core/initializer/type_system/smart_types.rb +2 -2
  35. data/lib/smart_core/initializer/version.rb +2 -2
  36. data/lib/smart_core/initializer.rb +14 -4
  37. data/smart_initializer.gemspec +2 -2
  38. metadata +16 -7
@@ -31,13 +31,13 @@ class SmartCore::Initializer::Constructor::Definer
31
31
  # @param privacy [String, Symbol]
32
32
  # @param finalize [String, Symbol, Proc]
33
33
  # @param cast [Boolean]
34
- # @param read_only [Boolean]
34
+ # @param mutable [Boolean]
35
35
  # @param as [String, Symbol, NilClass]
36
- # @param dynamic_options [Hash<Symbol,Any>]
37
36
  # @return [void]
38
37
  #
39
38
  # @api private
40
39
  # @since 0.1.0
40
+ # @version 0.8.0
41
41
  def define_parameter(
42
42
  name,
43
43
  type,
@@ -45,21 +45,19 @@ class SmartCore::Initializer::Constructor::Definer
45
45
  privacy,
46
46
  finalize,
47
47
  cast,
48
- read_only,
49
- as,
50
- dynamic_options
48
+ mutable,
49
+ as
51
50
  )
52
51
  thread_safe do
53
- attribute = build_attribute(
52
+ attribute = build_param_attribute(
54
53
  name,
55
54
  type,
56
55
  type_system,
57
56
  privacy,
58
57
  finalize,
59
58
  cast,
60
- read_only,
61
- as,
62
- dynamic_options
59
+ mutable,
60
+ as
63
61
  )
64
62
  prevent_option_overlap(attribute)
65
63
  add_parameter(attribute)
@@ -67,23 +65,25 @@ class SmartCore::Initializer::Constructor::Definer
67
65
  end
68
66
 
69
67
  # @param names [Array<String, Symbol>]
68
+ # @option mutable [Boolean]
69
+ # @option privacy [String, Symbol]
70
70
  # @return [void]
71
71
  #
72
72
  # @api private
73
73
  # @since 0.1.0
74
- def define_parameters(*names)
74
+ # @version 0.8.0
75
+ def define_parameters(*names, mutable:, privacy:)
75
76
  thread_safe do
76
77
  names.map do |name|
77
- build_attribute(
78
+ build_param_attribute(
78
79
  name,
79
80
  klass.__initializer_settings__.generic_type_object,
80
81
  klass.__initializer_settings__.type_system,
81
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_PRIVACY_MODE,
82
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_FINALIZER,
83
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_CAST_BEHAVIOUR,
84
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_READ_ONLY,
85
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_AS,
86
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_DYNAMIC_OPTIONS.dup
82
+ privacy,
83
+ SmartCore::Initializer::Attribute::Value::Param::DEFAULT_FINALIZER,
84
+ klass.__initializer_settings__.auto_cast,
85
+ mutable,
86
+ SmartCore::Initializer::Attribute::Value::Param::DEFAULT_AS
87
87
  ).tap do |attribute|
88
88
  prevent_option_overlap(attribute)
89
89
  end
@@ -99,13 +99,15 @@ class SmartCore::Initializer::Constructor::Definer
99
99
  # @param privacy [String, Symbol]
100
100
  # @param finalize [String, Symbol, Proc]
101
101
  # @param cast [Boolean]
102
- # @param read_only [Boolean]
102
+ # @param mutable [Boolean]
103
103
  # @param as [String, Symbol, NilClass]
104
- # @param dynamic_options [Hash<Symbol,Any>]
104
+ # @param default [Proc, Any]
105
+ # @param optional [Boolean]
105
106
  # @return [void]
106
107
  #
107
108
  # @api private
108
109
  # @since 0.1.0
110
+ # @version 0.8.0
109
111
  def define_option(
110
112
  name,
111
113
  type,
@@ -113,21 +115,23 @@ class SmartCore::Initializer::Constructor::Definer
113
115
  privacy,
114
116
  finalize,
115
117
  cast,
116
- read_only,
118
+ mutable,
117
119
  as,
118
- dynamic_options
120
+ default,
121
+ optional
119
122
  )
120
123
  thread_safe do
121
- attribute = build_attribute(
124
+ attribute = build_option_attribute(
122
125
  name,
123
126
  type,
124
127
  type_system,
125
128
  privacy,
126
129
  finalize,
127
130
  cast,
128
- read_only,
131
+ mutable,
129
132
  as,
130
- dynamic_options
133
+ default,
134
+ optional
131
135
  )
132
136
  prevent_parameter_overlap(attribute)
133
137
  add_option(attribute)
@@ -135,23 +139,27 @@ class SmartCore::Initializer::Constructor::Definer
135
139
  end
136
140
 
137
141
  # @param names [Array<String, Symbol>]
142
+ # @option mutable [Boolean]
143
+ # @option privacy [String, Symbol]
138
144
  # @return [void]
139
145
  #
140
146
  # @api private
141
147
  # @since 0.1.0
142
- def define_options(*names)
148
+ # @version 0.8.0
149
+ def define_options(*names, mutable:, privacy:)
143
150
  thread_safe do
144
151
  names.map do |name|
145
- build_attribute(
152
+ build_option_attribute(
146
153
  name,
147
154
  klass.__initializer_settings__.generic_type_object,
148
155
  klass.__initializer_settings__.type_system,
149
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_PRIVACY_MODE,
150
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_FINALIZER,
151
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_CAST_BEHAVIOUR,
152
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_READ_ONLY,
153
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_AS,
154
- SmartCore::Initializer::Attribute::Parameters::DEFAULT_DYNAMIC_OPTIONS.dup
156
+ privacy,
157
+ SmartCore::Initializer::Attribute::Value::Option::DEFAULT_FINALIZER,
158
+ klass.__initializer_settings__.auto_cast,
159
+ mutable,
160
+ SmartCore::Initializer::Attribute::Value::Option::DEFAULT_AS,
161
+ SmartCore::Initializer::Attribute::Value::Option::UNDEFINED_DEFAULT,
162
+ SmartCore::Initializer::Attribute::Value::Option::DEFAULT_OPTIONAL
155
163
  ).tap do |attribute|
156
164
  prevent_parameter_overlap(attribute)
157
165
  end
@@ -175,26 +183,57 @@ class SmartCore::Initializer::Constructor::Definer
175
183
  # @param privacy [String, Symbol]
176
184
  # @param finalize [String, Symbol, Proc]
177
185
  # @param cast [Boolean]
178
- # @param read_only [Boolean]
186
+ # @param mutable [Boolean]
187
+ # @param as [String, Symbol, NilClass]
188
+ # @return [SmartCore::Initializer::Attribute::Value::Param]
189
+ #
190
+ # @api private
191
+ # @since 0.1.0
192
+ # @version 0.8.0
193
+ def build_param_attribute(
194
+ name,
195
+ type,
196
+ type_system,
197
+ privacy,
198
+ finalize,
199
+ cast,
200
+ mutable,
201
+ as
202
+ )
203
+ SmartCore::Initializer::Attribute::Factory::Param.create(
204
+ name, type, type_system, privacy, finalize, cast, mutable, as
205
+ )
206
+ end
207
+
208
+ # @param name [String, Symbol]
209
+ # @param type [String, Symbol, Any]
210
+ # @param type_system [String, Symbol]
211
+ # @param privacy [String, Symbol]
212
+ # @param finalize [String, Symbol, Proc]
213
+ # @param cast [Boolean]
214
+ # @param mutable [Boolean]
179
215
  # @param as [String, Symbol, NilClass]
180
- # @param dynamic_options [Hash<Symbol,Any>]
181
- # @return [SmartCore::Initializer::Attribute]
216
+ # @param default [Proc, Any]
217
+ # @param optional [Boolean]
218
+ # @return [SmartCore::Initializer::Attribute::Value::Option]
182
219
  #
183
220
  # @api private
184
221
  # @since 0.1.0
185
- def build_attribute(
222
+ # @version 0.8.0
223
+ def build_option_attribute(
186
224
  name,
187
225
  type,
188
226
  type_system,
189
227
  privacy,
190
228
  finalize,
191
229
  cast,
192
- read_only,
230
+ mutable,
193
231
  as,
194
- dynamic_options
232
+ default,
233
+ optional
195
234
  )
196
- SmartCore::Initializer::Attribute::Factory.create(
197
- name, type, type_system, privacy, finalize, cast, read_only, as, dynamic_options
235
+ SmartCore::Initializer::Attribute::Factory::Option.create(
236
+ name, type, type_system, privacy, finalize, cast, mutable, as, default, optional
198
237
  )
199
238
  end
200
239
 
@@ -207,27 +246,77 @@ class SmartCore::Initializer::Constructor::Definer
207
246
  SmartCore::Initializer::Extensions::ExtInit.new(block)
208
247
  end
209
248
 
210
- # @param parameter [SmartCore::Initializer::Attribute]
249
+ # @param parameter [SmartCore::Initializer::Attribute::Value::Param]
211
250
  # @return [void]
212
251
  #
213
252
  # @api private
214
253
  # @since 0.1.0
254
+ # @version 0.8.0
255
+ # rubocop:disable Metrics/AbcSize
215
256
  def add_parameter(parameter)
216
257
  klass.__params__ << parameter
217
- klass.send(:attr_reader, parameter.name)
218
- klass.send(parameter.privacy, parameter.name)
258
+ klass.__send__(:attr_reader, parameter.name)
259
+ klass.__send__(parameter.privacy, parameter.name)
260
+
261
+ if parameter.mutable?
262
+ # NOTE:
263
+ # code evaluation approach is used instead of `define_method` approach in order
264
+ # to avoid the `clojure`-context binding inside the new method (this context can
265
+ # access the current context or the current variable set and the way to avoid this by
266
+ # ruby method is more diffcult to support and read insead of the real `code` evaluation)
267
+ klass.class_eval(<<~METHOD_CODE, __FILE__, __LINE__ + 1)
268
+ #{parameter.privacy} def #{parameter.name}=(new_value)
269
+ self.class.__params__[:#{parameter.name}].validate!(new_value)
270
+ @#{parameter.name} = new_value
271
+ end
272
+ METHOD_CODE
273
+ end
274
+
275
+ if parameter.as
276
+ klass.__send__(:alias_method, parameter.as, parameter.name)
277
+ klass.__send__(:alias_method, "#{parameter.as}=", "#{parameter.name}=") if parameter.mutable?
278
+
279
+ klass.__send__(parameter.privacy, parameter.as)
280
+ klass.__send__(parameter.privacy, "#{parameter.as}=") if parameter.mutable?
281
+ end
219
282
  end
283
+ # rubocop:enable Metrics/AbcSize
220
284
 
221
- # @param option [SmartCore::Initializer::Attribute]
285
+ # @param option [SmartCore::Initializer::Attribute::Value::Option]
222
286
  # @return [void]
223
287
  #
224
288
  # @api private
225
289
  # @since 0.1.0
290
+ # @version 0.8.0
291
+ # rubocop:disable Metrics/AbcSize
226
292
  def add_option(option)
227
293
  klass.__options__ << option
228
- klass.send(:attr_reader, option.name)
229
- klass.send(option.privacy, option.name)
294
+ klass.__send__(:attr_reader, option.name)
295
+ klass.__send__(option.privacy, option.name)
296
+
297
+ if option.mutable?
298
+ # NOTE:
299
+ # code evaluation approach is used instead of `define_method` approach in order
300
+ # to avoid the `clojure`-context binding inside the new method (this context can
301
+ # access the current context or the current variable set and the way to avoid this by
302
+ # ruby method is more diffcult to support and read insead of the real `code` evaluation)
303
+ klass.class_eval(<<~METHOD_CODE, __FILE__, __LINE__ + 1)
304
+ #{option.privacy} def #{option.name}=(new_value)
305
+ self.class.__options__[:#{option.name}].validate!(new_value)
306
+ @#{option.name} = new_value
307
+ end
308
+ METHOD_CODE
309
+ end
310
+
311
+ if option.as
312
+ klass.__send__(:alias_method, option.as, option.name)
313
+ klass.__send__(:alias_method, "#{option.as}=", "#{option.name}=") if option.mutable?
314
+
315
+ klass.__send__(option.privacy, option.as)
316
+ klass.__send__(option.privacy, "#{option.as}=") if option.mutable?
317
+ end
230
318
  end
319
+ # rubocop:enable Metrics/AbcSize
231
320
 
232
321
  # @param extension [SmartCore::Initializer::Extensions::ExtInit]
233
322
  # @return [void]
@@ -72,7 +72,7 @@ class SmartCore::Initializer::Constructor
72
72
  #
73
73
  # @api private
74
74
  # @since 0.1.0
75
- # @version 0.7.0
75
+ # @version 0.8.0
76
76
  # rubocop:disable Metrics/AbcSize
77
77
  def prevent_attribute_insufficiency
78
78
  required_parameter_count = klass.__params__.size
@@ -83,8 +83,8 @@ class SmartCore::Initializer::Constructor
83
83
  "(given #{parameters.size}, expected #{required_parameter_count})"
84
84
  ) unless parameters.size == required_parameter_count
85
85
 
86
- required_options = klass.__options__.reject(&:has_default?).map(&:name)
87
- missing_options = required_options.reject { |option| options.key?(option) }
86
+ required_options = klass.__options__.reject(&:has_default?).reject(&:optional?).map(&:name)
87
+ missing_options = required_options.reject { |option_name| options.key?(option_name) }
88
88
 
89
89
  raise(
90
90
  SmartCore::Initializer::OptionArgumentError,
@@ -97,7 +97,7 @@ class SmartCore::Initializer::Constructor
97
97
  raise(
98
98
  SmartCore::Initializer::OptionArgumentError,
99
99
  "Unknown options: #{unknown_options.join(', ')}"
100
- ) if unknown_options.any? && SmartCore::Initializer::Configuration[:strict_options]
100
+ ) if klass.__initializer_settings__.strict_options && unknown_options.any?
101
101
  end
102
102
  # rubocop:enable Metrics/AbcSize
103
103
 
@@ -124,8 +124,9 @@ class SmartCore::Initializer::Constructor
124
124
  end
125
125
 
126
126
  attribute.validate!(parameter_value)
127
-
128
127
  final_value = attribute.finalizer.call(parameter_value, instance)
128
+ attribute.validate!(final_value)
129
+
129
130
  instance.instance_variable_set("@#{attribute.name}", final_value)
130
131
  end
131
132
  end
@@ -135,21 +136,38 @@ class SmartCore::Initializer::Constructor
135
136
  #
136
137
  # @api private
137
138
  # @since 0.1.0
138
- # @version 0.5.1
139
+ # @version 0.8.0
140
+ # rubocop:disable Metrics/AbcSize
139
141
  def initialize_options(instance)
140
142
  klass.__options__.each do |attribute|
141
- option_value = options.fetch(attribute.name) { attribute.default }
142
-
143
- if !attribute.type.valid?(option_value) && attribute.cast?
144
- option_value = attribute.type.cast(option_value)
143
+ option_value = options.fetch(attribute.name) do
144
+ # NOTE: `nil` case is a case when an option is `optional`
145
+ attribute.has_default? ? attribute.default : nil
145
146
  end
146
147
 
147
- attribute.validate!(option_value)
148
+ if options.key?(attribute.name) || attribute.has_default?
149
+ if !attribute.type.valid?(option_value) && attribute.cast?
150
+ option_value = attribute.type.cast(option_value)
151
+ end
152
+
153
+ attribute.validate!(option_value)
154
+ end
155
+ # NOTE: (if-block: what if `if` receives `false`?):
156
+ # For other case passed `attribute` is optional and
157
+ # should not be type-checked/type-casted/etc.
158
+ # But optional attributes with defined `default` setting should be
159
+ # type-checked and type-casted.
160
+ #
161
+ # TODO: it should be covered by tests
148
162
 
149
163
  final_value = attribute.finalizer.call(option_value, instance)
164
+ # NOTE: validae `final_value` if only the `option` is provided (passed to constructor)
165
+ attribute.validate!(final_value) if options.key?(attribute.name)
166
+
150
167
  instance.instance_variable_set("@#{attribute.name}", final_value)
151
168
  end
152
169
  end
170
+ # rubocop:enable Metrics/AbcSize
153
171
 
154
172
  # @param instance [Any]
155
173
  # @return [void]
@@ -157,7 +175,7 @@ class SmartCore::Initializer::Constructor
157
175
  # @api private
158
176
  # @since 0.1.0
159
177
  def process_original_initializer(instance)
160
- instance.send(:initialize, *arguments, &block)
178
+ instance.__send__(:initialize, *arguments, &block)
161
179
  end
162
180
 
163
181
  # @param instance [Any]
@@ -108,37 +108,42 @@ module SmartCore::Initializer::DSL
108
108
  # @option cast [Boolean]
109
109
  # @option privacy [String, Symbol]
110
110
  # @option finalize [String, Symbol, Proc]
111
- # @option read_only [Boolean]
111
+ # @option mutable [Boolean]
112
112
  # @option as [NilClass, String, Symbol]
113
- # @param dynamic_options [Hash<Symbol,Any>]
114
113
  # @return [void]
115
114
  #
116
115
  # @api public
117
116
  # @since 0.1.0
118
- # @version 0.4.0
117
+ # @version 0.8.0
119
118
  def param(
120
119
  name,
121
120
  type = __initializer_settings__.generic_type_object,
122
- privacy: SmartCore::Initializer::Attribute::Parameters::DEFAULT_PRIVACY_MODE,
123
- finalize: SmartCore::Initializer::Attribute::Parameters::DEFAULT_FINALIZER,
124
- cast: SmartCore::Initializer::Attribute::Parameters::DEFAULT_CAST_BEHAVIOUR,
121
+ privacy: SmartCore::Initializer::Attribute::Value::Param::DEFAULT_PRIVACY_MODE,
122
+ finalize: SmartCore::Initializer::Attribute::Value::Param::DEFAULT_FINALIZER,
123
+ cast: __initializer_settings__.auto_cast,
125
124
  type_system: __initializer_settings__.type_system,
126
- read_only: SmartCore::Initializer::Attribute::Parameters::DEFAULT_READ_ONLY,
127
- as: SmartCore::Initializer::Attribute::Parameters::DEFAULT_AS,
128
- **dynamic_options
125
+ mutable: SmartCore::Initializer::Attribute::Value::Param::DEFAULT_MUTABLE,
126
+ as: SmartCore::Initializer::Attribute::Value::Param::DEFAULT_AS
129
127
  )
130
128
  __definer__.define_parameter(
131
- name, type, type_system, privacy, finalize, cast, read_only, as, dynamic_options
129
+ name, type, type_system, privacy, finalize, cast, mutable, as
132
130
  )
133
131
  end
134
132
 
135
133
  # @param names [Array<String, Symbol>]
134
+ # @option mutable [Boolean]
135
+ # @option privacy [String, Symbol]
136
136
  # @return [void]
137
137
  #
138
138
  # @api public
139
139
  # @since 0.1.0
140
- def params(*names)
141
- __definer__.define_parameters(*names)
140
+ # @verison 0.8.0
141
+ def params(
142
+ *names,
143
+ mutable: SmartCore::Initializer::Attribute::Value::Param::DEFAULT_MUTABLE,
144
+ privacy: SmartCore::Initializer::Attribute::Value::Param::DEFAULT_PRIVACY_MODE
145
+ )
146
+ __definer__.define_parameters(*names, mutable: mutable, privacy: privacy)
142
147
  end
143
148
 
144
149
  # @param name [String, Symbol]
@@ -147,37 +152,46 @@ module SmartCore::Initializer::DSL
147
152
  # @option privacy [String, Symbol]
148
153
  # @option finalize [String, Symbol, Proc]
149
154
  # @option type_system [String, Symbol]
150
- # @option read_only [Boolean]
155
+ # @option mutable [Boolean]
151
156
  # @option as [NilClass, String, Symbol]
152
- # @param dynamic_options [Hash<Symbol,Any>]
157
+ # @option default [Proc, Any]
158
+ # @option optional [Boolean]
153
159
  # @return [void]
154
160
  #
155
161
  # @api public
156
162
  # @since 0.1.0
157
- # @version 0.4.0
163
+ # @version 0.8.0
158
164
  def option(
159
165
  name,
160
166
  type = __initializer_settings__.generic_type_object,
161
- privacy: SmartCore::Initializer::Attribute::Parameters::DEFAULT_PRIVACY_MODE,
162
- finalize: SmartCore::Initializer::Attribute::Parameters::DEFAULT_FINALIZER,
163
- cast: SmartCore::Initializer::Attribute::Parameters::DEFAULT_CAST_BEHAVIOUR,
167
+ privacy: SmartCore::Initializer::Attribute::Value::Option::DEFAULT_PRIVACY_MODE,
168
+ finalize: SmartCore::Initializer::Attribute::Value::Option::DEFAULT_FINALIZER,
169
+ cast: __initializer_settings__.auto_cast,
164
170
  type_system: __initializer_settings__.type_system,
165
- read_only: SmartCore::Initializer::Attribute::Parameters::DEFAULT_READ_ONLY,
166
- as: SmartCore::Initializer::Attribute::Parameters::DEFAULT_AS,
167
- **dynamic_options
171
+ mutable: SmartCore::Initializer::Attribute::Value::Option::DEFAULT_MUTABLE,
172
+ as: SmartCore::Initializer::Attribute::Value::Option::DEFAULT_AS,
173
+ default: SmartCore::Initializer::Attribute::Value::Option::UNDEFINED_DEFAULT,
174
+ optional: SmartCore::Initializer::Attribute::Value::Option::DEFAULT_OPTIONAL
168
175
  )
169
176
  __definer__.define_option(
170
- name, type, type_system, privacy, finalize, cast, read_only, as, dynamic_options
177
+ name, type, type_system, privacy, finalize, cast, mutable, as, default, optional
171
178
  )
172
179
  end
173
180
 
174
181
  # @param names [Array<String, Symbol>]
182
+ # @option mutable [Boolean]
183
+ # @option privacy [String, Symbol]
175
184
  # @return [void]
176
185
  #
177
186
  # @api public
178
187
  # @since 0.1.0
179
- def options(*names)
180
- __definer__.define_options(*names)
188
+ # @version 0.8.0
189
+ def options(
190
+ *names,
191
+ mutable: SmartCore::Initializer::Attribute::Value::Option::DEFAULT_MUTABLE,
192
+ privacy: SmartCore::Initializer::Attribute::Value::Option::DEFAULT_PRIVACY_MODE
193
+ )
194
+ __definer__.define_options(*names, mutable: mutable, privacy: privacy)
181
195
  end
182
196
 
183
197
  # @param block [Block]
@@ -9,6 +9,14 @@ module SmartCore::Initializer
9
9
  # @since 0.1.0
10
10
  ArgumentError = Class.new(SmartCore::ArgumentError)
11
11
 
12
+ # @api public
13
+ # @since 0.8.0
14
+ AttributeError = Class.new(Error)
15
+
16
+ # @api public
17
+ # @since 0.8.0
18
+ UndefinedAttributeError = Class.new(AttributeError)
19
+
12
20
  # @api public
13
21
  # @since 0.1.0
14
22
  ParameterArgumentError = Class.new(ArgumentError)
@@ -17,6 +25,14 @@ module SmartCore::Initializer
17
25
  # @since 0.1.0
18
26
  OptionArgumentError = Class.new(ArgumentError)
19
27
 
28
+ # @api public
29
+ # @since 0.8.0
30
+ AliasArgumentError = Class.new(ArgumentError)
31
+
32
+ # @api public
33
+ # @since 0.8.0
34
+ SettingArgumentError = Class.new(ArgumentError)
35
+
20
36
  # @api public
21
37
  # @since 0.1.0
22
38
  NoDefaultValueError = Class.new(Error)
@@ -53,6 +69,10 @@ module SmartCore::Initializer
53
69
  # @since 0.1.0
54
70
  TypeSystemError = Class.new(Error)
55
71
 
72
+ # @api public
73
+ # @since 0.5.1
74
+ IncorrectTypeError = Class.new(TypeSystemError)
75
+
56
76
  # @api public
57
77
  # @since 0.1.0
58
78
  TypeAliasNotFoundError = Class.new(TypeSystemError)
@@ -73,10 +93,6 @@ module SmartCore::Initializer
73
93
  # @since 0.1.0
74
94
  UnsupportedTypeOperationError = Class.new(TypeSystemError)
75
95
 
76
- # @api public
77
- # @since 0.5.1
78
- IncorrectTypeError = Class.new(TypeSystemError)
79
-
80
96
  # @api public
81
97
  # @since 0.1.0
82
98
  TypeCastingUnsupportedError = Class.new(UnsupportedTypeOperationError)
@@ -3,23 +3,22 @@
3
3
  # @api private
4
4
  # @since 0.3.0
5
5
  module SmartCore::Initializer::Functionality
6
- # @return [NilClass]
7
- #
8
- # @api private
9
- # @since 0.3.0
10
- INITIAL_TYPE_SYSTEM = nil
11
-
12
6
  class << self
13
- # @option type_system [String, Symbol, NilClass]
7
+ # @option type_system [String, Symbol]
8
+ # @option strict_option [Boolean]
9
+ # @option auto_cast [Boolean]
14
10
  # @return [Module]
15
11
  #
16
12
  # @api private
17
13
  # @since 0.3.0
18
- def includable_module(type_system: INITIAL_TYPE_SYSTEM)
14
+ # @version 0.8.0
15
+ def includable_module(type_system:, strict_options:, auto_cast:)
19
16
  Module.new.tap do |extension|
20
17
  extension.singleton_class.define_method(:included) do |base_klass|
21
18
  base_klass.include(::SmartCore::Initializer)
22
19
  base_klass.__initializer_settings__.type_system = type_system
20
+ base_klass.__initializer_settings__.strict_options = strict_options
21
+ base_klass.__initializer_settings__.auto_cast = auto_cast
23
22
  end
24
23
  end
25
24
  end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.8.0
5
+ class SmartCore::Initializer::Settings::AutoCast < SmartCore::Initializer::Settings::Base
6
+ # @return [void]
7
+ #
8
+ # @api private
9
+ # @since 0.8.0
10
+ def initialize
11
+ @value = nil
12
+ @lock = SmartCore::Engine::Lock.new
13
+ end
14
+
15
+ # @return [Boolean]
16
+ #
17
+ # @api private
18
+ # @since 0.8.0
19
+ def resolve
20
+ thread_safe do
21
+ @value == nil ? SmartCore::Initializer::Configuration[:auto_cast] : @value
22
+ end
23
+ end
24
+
25
+ # @param value [Boolean]
26
+ # @return [void]
27
+ #
28
+ # @api private
29
+ # @since 0.8.0
30
+ def assign(value)
31
+ thread_safe do
32
+ raise(
33
+ SmartCore::Initializer::SettingArgumentError,
34
+ ":auto_cast setting should be a type of boolean (got: `#{value.class}`)"
35
+ ) unless value.is_a?(::TrueClass) || value.is_a?(::FalseClass)
36
+
37
+ @value = value
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,49 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.8.0
5
+ class SmartCore::Initializer::Settings::Base
6
+ # @return [void]
7
+ #
8
+ # @api private
9
+ # @since 0.8.0
10
+ def initialize
11
+ @value = nil
12
+ @lock = SmartCore::Engine::Lock.new
13
+ end
14
+
15
+ # @!method resolve
16
+ # @return [Any]
17
+ # @api private
18
+ # @since 0.8.0
19
+
20
+ # @!method assign(value)
21
+ # @param value [Any]
22
+ # @return [void]
23
+ # @raise [SmartCore::Initializer::SettingArgumentError]
24
+ # @api private
25
+ # @since 0.8.0
26
+
27
+ # @return [SmartCore::Initializer::Settings::Base]
28
+ #
29
+ # @api private
30
+ # @since 0.8.0
31
+ def dup
32
+ thread_safe do
33
+ self.class.new.tap do |duplicate|
34
+ duplicate.instance_variable_set(:@value, @value)
35
+ end
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ # @param block [Block]
42
+ # @return [Any]
43
+ #
44
+ # @api private
45
+ # @since 0.8.0
46
+ def thread_safe(&block)
47
+ @lock.synchronize(&block)
48
+ end
49
+ end