smart_initializer 0.5.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +46 -1
  4. data/Gemfile.lock +45 -44
  5. data/LICENSE.txt +1 -1
  6. data/README.md +283 -40
  7. data/bin/console +2 -2
  8. data/gemfiles/with_external_deps.gemfile.lock +38 -38
  9. data/gemfiles/without_external_deps.gemfile.lock +50 -45
  10. data/lib/smart_core/initializer/attribute/factory/base.rb +145 -0
  11. data/lib/smart_core/initializer/attribute/factory/option.rb +107 -0
  12. data/lib/smart_core/initializer/attribute/factory/param.rb +63 -0
  13. data/lib/smart_core/initializer/attribute/factory.rb +5 -199
  14. data/lib/smart_core/initializer/attribute/finalizer/abstract.rb +2 -0
  15. data/lib/smart_core/initializer/attribute/finalizer/instance_method.rb +1 -1
  16. data/lib/smart_core/initializer/attribute/finalizer.rb +5 -5
  17. data/lib/smart_core/initializer/attribute/list.rb +20 -0
  18. data/lib/smart_core/initializer/attribute/{parameters.rb → value/base.rb} +35 -65
  19. data/lib/smart_core/initializer/attribute/value/option.rb +101 -0
  20. data/lib/smart_core/initializer/attribute/value/param.rb +24 -0
  21. data/lib/smart_core/initializer/attribute/value.rb +9 -0
  22. data/lib/smart_core/initializer/attribute.rb +3 -112
  23. data/lib/smart_core/initializer/configuration.rb +9 -0
  24. data/lib/smart_core/initializer/constructor/definer.rb +135 -46
  25. data/lib/smart_core/initializer/constructor.rb +29 -14
  26. data/lib/smart_core/initializer/dsl.rb +38 -24
  27. data/lib/smart_core/initializer/errors.rb +20 -0
  28. data/lib/smart_core/initializer/functionality.rb +7 -8
  29. data/lib/smart_core/initializer/plugins/thy_types/thy_types/abstract_factory.rb +13 -2
  30. data/lib/smart_core/initializer/settings/auto_cast.rb +40 -0
  31. data/lib/smart_core/initializer/settings/base.rb +49 -0
  32. data/lib/smart_core/initializer/settings/duplicator.rb +5 -0
  33. data/lib/smart_core/initializer/settings/strict_options.rb +40 -0
  34. data/lib/smart_core/initializer/settings/type_system.rb +10 -28
  35. data/lib/smart_core/initializer/settings.rb +40 -0
  36. data/lib/smart_core/initializer/type_system/interop/abstract_factory.rb +12 -2
  37. data/lib/smart_core/initializer/type_system/interop.rb +10 -1
  38. data/lib/smart_core/initializer/type_system/registry.rb +2 -1
  39. data/lib/smart_core/initializer/type_system/smart_types/abstract_factory.rb +13 -2
  40. data/lib/smart_core/initializer/type_system/smart_types.rb +2 -2
  41. data/lib/smart_core/initializer/version.rb +2 -2
  42. data/lib/smart_core/initializer.rb +14 -4
  43. data/smart_initializer.gemspec +3 -3
  44. metadata +18 -9
@@ -2,203 +2,9 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
- # rubocop:disable Metrics/ClassLength
6
- class SmartCore::Initializer::Attribute::Factory
7
- class << self
8
- # @param name [String, Symbol]
9
- # @param type [String, Symbol, Any]
10
- # @param type_system [String, Symbol]
11
- # @param privacy [String, Symbol]
12
- # @param finalize [String, Symbol, Proc]
13
- # @param cast [Boolean]
14
- # @param read_only [Boolean]
15
- # @param as [String, Symbol, NilClass]
16
- # @param dynamic_options [Hash<Symbol,Any>]
17
- # @return [SmartCore::Initializer::Attribute]
18
- #
19
- # @api private
20
- # @since 0.1.0
21
- def create(name, type, type_system, privacy, finalize, cast, read_only, as, dynamic_options)
22
- prepared_name = prepare_name_param(name)
23
- prepared_privacy = prepare_privacy_param(privacy)
24
- prepared_finalize = prepare_finalize_param(finalize)
25
- prepared_cast = prepare_cast_param(cast)
26
- prepared_type_system = prepare_type_system_param(type_system)
27
- prepared_type = prepare_type_param(type, prepared_type_system)
28
- prepared_read_only = prepare_read_only_param(read_only)
29
- prepared_as = preapre_as_param(as)
30
- prepared_dynamic_options = prepare_dynamic_options_param(dynamic_options)
31
-
32
- create_attribute(
33
- prepared_name,
34
- prepared_type,
35
- prepared_type_system,
36
- prepared_privacy,
37
- prepared_finalize,
38
- prepared_cast,
39
- prepared_read_only,
40
- prepared_as,
41
- prepared_dynamic_options
42
- )
43
- end
44
-
45
- private
46
-
47
- # @param name [String, Symbol]
48
- # @return [Symbol]
49
- #
50
- # @api private
51
- # @since 0.1.0
52
- def prepare_name_param(name)
53
- unless name.is_a?(String) || name.is_a?(Symbol)
54
- raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
55
- Attribute name should be a type of String or Symbol
56
- ERROR_MESSAGE
57
- end
58
-
59
- name.to_sym
60
- end
61
-
62
- # @param type [String, Symbol, Any]
63
- # @param type_system [Class<SmartCore::Initializer::TypeSystem::Interop>]
64
- # @return [SmartCore::Initializer::TypeSystem::Interop]
65
- #
66
- # @api private
67
- # @since 0.1.0
68
- def prepare_type_param(type, type_system)
69
- type_primitive =
70
- if type.is_a?(String) || type.is_a?(Symbol)
71
- type_system.type_from_alias(type)
72
- else
73
- type
74
- end
75
-
76
- type_system.create(type_primitive)
77
- end
78
-
79
- # @param cast [Boolean]
80
- # @return [Boolean]
81
- #
82
- # @api private
83
- # @since 0.1.0
84
- def prepare_cast_param(cast)
85
- unless cast.is_a?(TrueClass) || cast.is_a?(FalseClass)
86
- raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
87
- Attribute cast should be a type of boolean
88
- ERROR_MESSAGE
89
- end
90
-
91
- cast
92
- end
93
-
94
- # @param privacy [String, Symbol]
95
- # @return [Symbol]
96
- #
97
- # @api private
98
- # @since 0.1.0
99
- def prepare_privacy_param(privacy)
100
- unless privacy.is_a?(String) || privacy.is_a?(Symbol)
101
- raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
102
- Attribute privacy should be a type of String or Symbol
103
- ERROR_MESSAGE
104
- end
105
-
106
- SmartCore::Initializer::Attribute::Parameters::PRIVACY_MODES.fetch(privacy.to_sym) do
107
- raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
108
- Incorrect attribute privacy identifier "#{privacy}"
109
- ERROR_MESSAGE
110
- end
111
- end
112
-
113
- # @param finalize [String, Symbol, Proc]
114
- # @return [SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock/InstanceMethod]
115
- #
116
- # @api private
117
- # @since 0.1.0
118
- def prepare_finalize_param(finalize)
119
- unless finalize.is_a?(String) || finalize.is_a?(Symbol) || finalize.is_a?(Proc)
120
- raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
121
- Attribute finalizer should be a type of String, Symbol or Proc
122
- ERROR_MESSAGE
123
- end
124
-
125
- SmartCore::Initializer::Attribute::Finalizer.create(finalize)
126
- end
127
-
128
- # @param read_only [Boolean]
129
- # @return [Boolean]
130
- #
131
- # @api private
132
- # @since 0.4.0
133
- def prepare_read_only_param(read_only)
134
- unless read_only.is_a?(FalseClass) || read_only.is_a?(TrueClass)
135
- raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
136
- :read_only attribute should be a type of boolean
137
- ERROR_MESSAGE
138
- end
139
-
140
- read_only
141
- end
142
-
143
- # @param [String, Symbol, NilClass]
144
- # @return [String, Symbol, NilClass]
145
- #
146
- # @api private
147
- # @since 0.4.0
148
- def preapre_as_param(as)
149
- unless as.is_a?(NilClass) || as.is_a?(String) || as.is_a?(Symbol)
150
- raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
151
- Attribute alias should be a type of String or Symbol
152
- ERROR_MESSAGE
153
- end
154
-
155
- as
156
- end
157
-
158
- # @param dynamic_options [Hash<Symbol,Any>]
159
- # @return [Hash<Symbol,Any>]
160
- #
161
- # @api private
162
- # @since 0.1.0
163
- def prepare_dynamic_options_param(dynamic_options)
164
- # :nocov:
165
- unless dynamic_options.is_a?(Hash)
166
- raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
167
- Attribute dynamic options should be a type of Hash
168
- ERROR_MESSAGE
169
- end
170
- # :nocov:
171
-
172
- dynamic_options
173
- end
174
-
175
- # @param type_system [String, Symbol]
176
- # @return [Class<SmartCore::Initializer::TypeSystem::Interop>]
177
- #
178
- # @api private
179
- # @since 0.1.0
180
- def prepare_type_system_param(type_system)
181
- SmartCore::Initializer::TypeSystem.resolve(type_system)
182
- end
183
-
184
- # @param name [String]
185
- # @param type [SmartCore::Initializer::TypeSystem::Interop]
186
- # @param type_system [Class<SmartCore::Initializer::TypeSystem::Interop>]
187
- # @param privacy [Symbol]
188
- # @param finalize [SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock/InstanceMethod]
189
- # @param cast [Boolean]
190
- # @param dynamic_options [Hash<Symbol,String>]
191
- # @return [SmartCore::Initializer::Attribute]
192
- #
193
- # @api private
194
- # @since 0.1.0
195
- # rubocop:disable Layout/LineLength
196
- def create_attribute(name, type, type_system, privacy, finalize, cast, read_only, as, dynamic_options)
197
- SmartCore::Initializer::Attribute.new(
198
- name, type, type_system, privacy, finalize, cast, read_only, as, dynamic_options
199
- )
200
- end
201
- # rubocop:enable Layout/LineLength
202
- end
5
+ # @version 0.8.0
6
+ module SmartCore::Initializer::Attribute::Factory
7
+ require_relative 'factory/base'
8
+ require_relative 'factory/option'
9
+ require_relative 'factory/param'
203
10
  end
204
- # rubocop:enable Metrics/ClassLength
@@ -19,7 +19,9 @@ class SmartCore::Initializer::Attribute::Finalizer::Abstract
19
19
  # @api private
20
20
  # @since 0.1.0
21
21
  def call(value, instance)
22
+ # :nocov:
22
23
  raise NoMethodError
24
+ # :nocov:
23
25
  end
24
26
 
25
27
  # @return [SmartCore::Initializer::Attribute::Finalizer::Abstract]
@@ -20,7 +20,7 @@ module SmartCore::Initializer::Attribute::Finalizer
20
20
  # @pai private
21
21
  # @since 0.1.0
22
22
  def call(value, instance)
23
- instance.send(finalizer, value)
23
+ instance.__send__(finalizer, value)
24
24
  end
25
25
 
26
26
  private
@@ -14,6 +14,7 @@ module SmartCore::Initializer::Attribute::Finalizer
14
14
  #
15
15
  # @api private
16
16
  # @since 0.1.0
17
+ # @version 0.8.0
17
18
  def create(finalization_approach)
18
19
  case finalization_approach
19
20
  when String, Symbol
@@ -21,11 +22,10 @@ module SmartCore::Initializer::Attribute::Finalizer
21
22
  when Proc
22
23
  AnonymousBlock.new(finalization_approach)
23
24
  else
24
- # :nocov:
25
- raise(SmartCore::Initializer::ArgumentError, <<~ERROR_MESSAGE)
26
- Finalization approach should be a type of Proc, Symbol or String'
27
- ERROR_MESSAGE
28
- # :nocov:
25
+ raise(
26
+ SmartCore::Initializer::ArgumentError,
27
+ 'Finalization approach object should be a type of Proc, Symbol or String'
28
+ )
29
29
  end
30
30
  end
31
31
  end
@@ -15,6 +15,26 @@ class SmartCore::Initializer::Attribute::List
15
15
  @lock = SmartCore::Engine::Lock.new
16
16
  end
17
17
 
18
+ # @param attribute_name [Symbol]
19
+ # @return [SmartCore::Initializer::Atribute]
20
+ #
21
+ # @raise [SmartCore::Initializer::UndefinedAttributeError]
22
+ #
23
+ # @api private
24
+ # @since 0.8.0
25
+ def fetch(attribute_name)
26
+ thread_safe do
27
+ attributes.fetch(attribute_name)
28
+ rescue ::KeyError
29
+ raise(
30
+ ::SmartCore::Initializer::UndefinedAttributeError,
31
+ "Attribute with `#{attribute_name}` name is not defined in your constructor. " \
32
+ "Please, check your attribute definitions inside your class."
33
+ )
34
+ end
35
+ end
36
+ alias_method :[], :fetch
37
+
18
38
  # @param attribute [SmartCore::Initializer::Attribute]
19
39
  # @return [void]
20
40
  #
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # @api private
4
- # @since 0.1.0
5
- class SmartCore::Initializer::Attribute::Parameters
4
+ # @since 0.8.0
5
+ class SmartCore::Initializer::Attribute::Value::Base
6
6
  # @return [Hash<Symbol,Symbol>]
7
7
  #
8
8
  # @api private
9
- # @since 0.1.0
9
+ # @since 0.8.0
10
10
  PRIVACY_MODES = {
11
11
  public: :public,
12
12
  protected: :protected,
@@ -16,93 +16,76 @@ class SmartCore::Initializer::Attribute::Parameters
16
16
  # @return [Symbol]
17
17
  #
18
18
  # @api private
19
- # @since 0.1.0
19
+ # @since 0.8.0
20
20
  DEFAULT_PRIVACY_MODE = PRIVACY_MODES[:public]
21
21
 
22
- # @return [Boolean]
23
- #
24
- # @api private
25
- # @since 0.1.0
26
- DEFAULT_CAST_BEHAVIOUR = false
27
-
28
22
  # @return [Proc]
29
23
  #
30
24
  # @api private
31
- # @since 0.1.0
25
+ # @since 0.8.0
32
26
  DEFAULT_FINALIZER = proc { |value| value }.freeze
33
27
 
34
- # @return [Hash]
28
+ # @return [NilClass]
35
29
  #
36
30
  # @api private
37
- # @since 0.1.0
38
- DEFAULT_DYNAMIC_OPTIONS = {}.freeze
31
+ # @since 0.8.0
32
+ DEFAULT_AS = nil
39
33
 
40
34
  # @return [Boolean]
41
35
  #
42
36
  # @api private
43
- # @since 0.4.0
44
- DEFAULT_READ_ONLY = true
45
-
46
- # @return [NilClass]
47
- #
48
- # @api private
49
- # @since 0.4.0
50
- DEFAULT_AS = nil
37
+ # @since 0.8.0
38
+ DEFAULT_MUTABLE = false
51
39
 
52
40
  # @return [Symbol]
53
41
  #
54
42
  # @api private
55
- # @since 0.1.0
43
+ # @since 0.8.0
56
44
  attr_reader :name
57
45
 
58
46
  # @return [SmartCore::Initializer::TypeSystem::Interop]
59
47
  #
60
48
  # @api private
61
- # @since 0.1.0
49
+ # @since 0.8.0
62
50
  attr_reader :type
63
51
 
64
52
  # @return [Class<SmartCore::Initilizer::TypeSystem::Interop>]
65
53
  #
66
54
  # @api private
67
- # @since 0.1.0
55
+ # @since 0.8.0
68
56
  attr_reader :type_system
69
57
 
70
58
  # @return [Symbol]
71
59
  #
72
60
  # @api private
73
- # @since 0.1.0
61
+ # @since 0.8.0
74
62
  attr_reader :privacy
75
63
 
76
64
  # @return [SmartCore::Initializer::Attribute::Finalizer::AnonymousBlock]
77
65
  # @return [SmartCore::Initializer::Attribute::Finalizer::InstanceMethod]
78
66
  #
79
67
  # @api private
80
- # @since 0.1.0
68
+ # @since 0.8.0
81
69
  attr_reader :finalizer
82
70
 
83
71
  # @return [Boolean]
84
72
  #
85
73
  # @api private
86
- # @since 0.1.0
74
+ # @since 0.8.0
87
75
  attr_reader :cast
88
76
  alias_method :cast?, :cast
89
77
 
90
- # @return [Hash<Symbol,Any>]
91
- #
92
- # @api private
93
- # @since 0.1.0
94
- attr_reader :dynamic_options
95
-
96
78
  # @return [Boolean]
97
79
  #
98
80
  # @api private
99
- # @since 0.4.0
100
- attr_reader :read_only
81
+ # @since 0.8.0
82
+ attr_reader :mutable
83
+ alias_method :mutable?, :mutable
101
84
 
102
85
  # @return [String, Symbol, NilClass]
103
86
  #
104
87
  # @api private
105
- # @since 0.4.0
88
+ # @since 0.8.0
106
89
  attr_reader :as
107
90
 
108
91
  # @param name [Symbol]
@@ -111,48 +94,35 @@ class SmartCore::Initializer::Attribute::Parameters
111
94
  # @param privacy [Symbol]
112
95
  # @param finalizer [SmartCore::Initializer::Attribute::AnonymousBlock/InstanceMethod]
113
96
  # @param cast [Boolean]
114
- # @param read_only [Boolean]
97
+ # @param mutable [Boolean]
115
98
  # @param as [NilClass, Symbol, String]
116
- # @param dynamic_options [Hash<Symbol,Any>]
117
- # - :default - default value (Proc value will be called)
118
99
  # @return [void]
119
100
  #
120
101
  # @api private
121
- # @since 0.1.0
122
- # @version 0.4.0
123
- def initialize(name, type, type_system, privacy, finalizer, cast, read_only, as, dynamic_options)
102
+ # @since 0.8.0
103
+ def initialize(name, type, type_system, privacy, finalizer, cast, mutable, as)
124
104
  @name = name
125
105
  @type = type
126
106
  @type_system = type_system
127
107
  @privacy = privacy
128
108
  @finalizer = finalizer
129
109
  @cast = cast
130
- @read_only = read_only
110
+ @mutable = mutable
131
111
  @as = as
132
- @dynamic_options = dynamic_options
133
112
  end
134
113
 
135
- # @return [Boolean]
136
- #
137
- # @api private
138
- # @since 0.1.0
139
- def has_default?
140
- dynamic_options.key?(:default)
141
- end
142
-
143
- # @return [Any]
144
- #
145
- # @raise [SmartCore::Initializer::NoDefaultValueError]
114
+ # @param value [Any]
115
+ # @return [void]
146
116
  #
147
117
  # @api private
148
- # @since 0.1.0
149
- def default
150
- default_value = dynamic_options.fetch(:default) do
151
- raise(SmartCore::Initializer::NoDefaultValueError, <<~ERROR_MESSAGE)
152
- Attribute #{name} has no default value
153
- ERROR_MESSAGE
154
- end
155
-
156
- default_value.is_a?(Proc) ? default_value.call : default_value
118
+ # @since 0.8.0
119
+ def validate!(value)
120
+ type.validate!(value)
121
+ rescue => error # TODO: move to typesystem interop
122
+ raise(
123
+ SmartCore::Initializer::IncorrectTypeError,
124
+ "Validation of attribute `#{name}` failed:" \
125
+ "(expected: #{type.identifier}, got: #{value.class}) \"#{error.message}\""
126
+ )
157
127
  end
158
128
  end
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartCore::Initializer::Attribute::Value
4
+ # @api private
5
+ # @since 0.8.0
6
+ class Option < Base
7
+ # @return [Object]
8
+ #
9
+ # @api private
10
+ # @since 0.8.0
11
+ UNDEFINED_DEFAULT = ::Object.new.tap(&:freeze)
12
+
13
+ # @return [Boolean]
14
+ #
15
+ # @api private
16
+ # @since 0.8.0
17
+ DEFAULT_OPTIONAL = false
18
+
19
+ # @return [Boolean]
20
+ #
21
+ # @api private
22
+ # @since 0.8.0
23
+ attr_reader :optional
24
+ alias_method :optional?, :optional
25
+
26
+ # @param name [Symbol]
27
+ # @param type [SmartCore::Initializer::TypeSystem::Interop]
28
+ # @param type_system [Class<SmartCore::Initializer::TypeSystem::Interop>]
29
+ # @param privacy [Symbol]
30
+ # @param finalizer [SmartCore::Initializer::Attribute::AnonymousBlock/InstanceMethod]
31
+ # @param cast [Boolean]
32
+ # @param mutable [Boolean]
33
+ # @param as [NilClass, Symbol, String]
34
+ # @param default [Proc, Any]
35
+ # @param optional [Boolean]
36
+ # @return [void]
37
+ #
38
+ # @api private
39
+ # @since 0.8.0
40
+ def initialize(
41
+ name,
42
+ type,
43
+ type_system,
44
+ privacy,
45
+ finalizer,
46
+ cast,
47
+ mutable,
48
+ as,
49
+ default,
50
+ optional
51
+ )
52
+ super(name, type, type_system, privacy, finalizer, cast, mutable, as)
53
+ @default = default
54
+ @optional = optional
55
+ end
56
+
57
+ # @return [Boolean]
58
+ #
59
+ # @api private
60
+ # @since 0.8.0
61
+ def has_default?
62
+ !@default.equal?(UNDEFINED_DEFAULT)
63
+ end
64
+
65
+ # @return [Any]
66
+ #
67
+ # @raise [SmartCore::Initializer::NoDefaultValueError]
68
+ #
69
+ # @api private
70
+ # @since 0.8.0
71
+ def default
72
+ raise(
73
+ SmartCore::Initializer::NoDefaultValueError,
74
+ "Attribute #{name} has no default value"
75
+ ) if @default.equal?(UNDEFINED_DEFAULT)
76
+
77
+ @default.is_a?(Proc) ? @default.call : @default.dup
78
+ end
79
+
80
+ # @return [SmartCore::Initializer::Attribute::Value::Option]
81
+ #
82
+ # @api private
83
+ # @since 0.8.0
84
+ def dup
85
+ default = @default.equal?(UNDEFINED_DEFAULT) ? @default : @default.dup
86
+
87
+ self.class.new(
88
+ name.dup,
89
+ type,
90
+ type_system,
91
+ privacy,
92
+ finalizer.dup,
93
+ cast,
94
+ mutable,
95
+ as,
96
+ default,
97
+ optional
98
+ )
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SmartCore::Initializer::Attribute::Value
4
+ # @api private
5
+ # @since 0.8.0
6
+ class Param < Base
7
+ # @return [SmartCore::Initializer::Attribute::Value::Param]
8
+ #
9
+ # @api private
10
+ # @since 0.8.0
11
+ def dup
12
+ self.class.new(
13
+ name.dup,
14
+ type,
15
+ type_system,
16
+ privacy,
17
+ finalizer.dup,
18
+ cast,
19
+ mutable,
20
+ as
21
+ )
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.8.0
5
+ module SmartCore::Initializer::Attribute::Value
6
+ require_relative 'value/base'
7
+ require_relative 'value/param'
8
+ require_relative 'value/option'
9
+ end