smart_initializer 0.7.0 → 0.8.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.
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