smart_types 0.2.0 → 0.3.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/Gemfile.lock +33 -32
  4. data/README.md +161 -16
  5. data/lib/smart_core/types.rb +2 -0
  6. data/lib/smart_core/types/errors.rb +12 -0
  7. data/lib/smart_core/types/primitive.rb +49 -4
  8. data/lib/smart_core/types/primitive/caster.rb +5 -2
  9. data/lib/smart_core/types/primitive/checker.rb +5 -2
  10. data/lib/smart_core/types/primitive/factory.rb +64 -6
  11. data/lib/smart_core/types/primitive/factory/definition_context.rb +37 -11
  12. data/lib/smart_core/types/primitive/factory/runtime_type_builder.rb +53 -0
  13. data/lib/smart_core/types/primitive/invariant_control.rb +6 -3
  14. data/lib/smart_core/types/primitive/invariant_control/chain.rb +5 -2
  15. data/lib/smart_core/types/primitive/invariant_control/single.rb +5 -2
  16. data/lib/smart_core/types/primitive/mult_factory.rb +40 -6
  17. data/lib/smart_core/types/primitive/mult_factory/definition_context.rb +23 -1
  18. data/lib/smart_core/types/primitive/mult_validator.rb +8 -0
  19. data/lib/smart_core/types/primitive/nilable_factory.rb +10 -3
  20. data/lib/smart_core/types/primitive/runtime_attributes_checker.rb +77 -0
  21. data/lib/smart_core/types/primitive/sum_factory.rb +40 -6
  22. data/lib/smart_core/types/primitive/sum_factory/definition_context.rb +23 -1
  23. data/lib/smart_core/types/primitive/sum_validator.rb +18 -2
  24. data/lib/smart_core/types/primitive/undefined_caster.rb +4 -1
  25. data/lib/smart_core/types/primitive/validator.rb +16 -7
  26. data/lib/smart_core/types/protocol.rb +7 -0
  27. data/lib/smart_core/types/protocol/instance_of.rb +19 -0
  28. data/lib/smart_core/types/value/array.rb +3 -0
  29. data/lib/smart_core/types/value/big_decimal.rb +4 -1
  30. data/lib/smart_core/types/value/boolean.rb +3 -0
  31. data/lib/smart_core/types/value/class.rb +3 -0
  32. data/lib/smart_core/types/value/date.rb +3 -0
  33. data/lib/smart_core/types/value/date_time.rb +3 -0
  34. data/lib/smart_core/types/value/enumerable.rb +1 -1
  35. data/lib/smart_core/types/value/float.rb +3 -0
  36. data/lib/smart_core/types/value/hash.rb +3 -0
  37. data/lib/smart_core/types/value/integer.rb +3 -0
  38. data/lib/smart_core/types/value/module.rb +3 -0
  39. data/lib/smart_core/types/value/numeric.rb +3 -0
  40. data/lib/smart_core/types/value/proc.rb +3 -0
  41. data/lib/smart_core/types/value/set.rb +11 -3
  42. data/lib/smart_core/types/value/string.rb +3 -0
  43. data/lib/smart_core/types/value/string_io.rb +2 -0
  44. data/lib/smart_core/types/value/symbol.rb +3 -0
  45. data/lib/smart_core/types/value/text.rb +6 -4
  46. data/lib/smart_core/types/value/time.rb +3 -0
  47. data/lib/smart_core/types/value/time_based.rb +8 -5
  48. data/lib/smart_core/types/variadic.rb +7 -0
  49. data/lib/smart_core/types/variadic/tuple.rb +23 -0
  50. data/lib/smart_core/types/version.rb +2 -2
  51. data/smart_types.gemspec +3 -3
  52. metadata +15 -10
  53. data/.travis.yml +0 -21
@@ -10,4 +10,6 @@ module SmartCore::Types
10
10
  require_relative 'types/system'
11
11
  require_relative 'types/primitive'
12
12
  require_relative 'types/value'
13
+ require_relative 'types/protocol'
14
+ require_relative 'types/variadic'
13
15
  end
@@ -13,6 +13,18 @@ module SmartCore::Types
13
13
  # @since 0.1.0
14
14
  NameError = Class.new(SmartCore::NameError)
15
15
 
16
+ # @api public
17
+ # @since 0.3.0
18
+ TypeDefinitionError = Class.new(ArgumentError)
19
+
20
+ # @api public
21
+ # @since 0.3.0
22
+ IncorrectRuntimeAttributesError = Class.new(TypeDefinitionError)
23
+
24
+ # @api public
25
+ # @since 0.3.0
26
+ RuntimeAttriburtesUnsupportedError = Class.new(TypeDefinitionError)
27
+
16
28
  # @api public
17
29
  # @since 0.1.0
18
30
  TypeError = Class.new(SmartCore::TypeError)
@@ -2,10 +2,11 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
- # @version 0.2.0
5
+ # @version 0.3.0
6
6
  class SmartCore::Types::Primitive
7
7
  require_relative 'primitive/checker'
8
8
  require_relative 'primitive/caster'
9
+ require_relative 'primitive/runtime_attributes_checker'
9
10
  require_relative 'primitive/undefined_caster'
10
11
  require_relative 'primitive/invariant_control'
11
12
  require_relative 'primitive/validator'
@@ -20,6 +21,9 @@ class SmartCore::Types::Primitive
20
21
  class << self
21
22
  # @param type_name [String, Symbol]
22
23
  # @param type_definition [Block]
24
+ # @yield [type]
25
+ # @yieldparam type [SmartCore::Types::Primitive::DefinitionContext]
26
+ # @yieldreturn [void]
23
27
  # @return [SmartCore::Types::Primitive]
24
28
  #
25
29
  # @api public
@@ -36,6 +40,24 @@ class SmartCore::Types::Primitive
36
40
  # @since 0.2.0
37
41
  attr_reader :name
38
42
 
43
+ # @return [Class<SmartCore::Types::Primitive>]
44
+ #
45
+ # @api private
46
+ # @since 0.3.0
47
+ attr_reader :category
48
+
49
+ # @return [Array<Any>]
50
+ #
51
+ # @api private
52
+ # @since 0.3.0
53
+ attr_reader :runtime_attributes
54
+
55
+ # @return [SmartCore::Types::Primitive::RuntimeAttributesChecker]
56
+ #
57
+ # @api private
58
+ # @since 0.3.0
59
+ attr_reader :runtime_attributes_checker
60
+
39
61
  # @return [SmartCore::Types::Primitive::Caster]
40
62
  #
41
63
  # @api private
@@ -52,6 +74,7 @@ class SmartCore::Types::Primitive
52
74
  attr_reader :validator
53
75
 
54
76
  # @param name [String, NilClass] NilClass is suitable for sum-types, mult-types and nilable types.
77
+ # @param category [Class<SmartCore::Types::Primitive>, NilClass]
55
78
  # @param validator [
56
79
  # SmartCore::Types::Primitive::Validator,
57
80
  # SmartCore::Types::Primitive::SumValidator,
@@ -59,18 +82,36 @@ class SmartCore::Types::Primitive
59
82
  # SmartCore::Types::Primitive::NilableValidator
60
83
  # ]
61
84
  # @param caster [SmartCore::Types::Primitive::Caster]
85
+ # @param runtime_attributes_checker [SmartCore::Types::Primitive::RuntimeAttributesChecker]
86
+ # @param runtime_attributes [Array<Any>]
62
87
  # @return [void]
63
88
  #
64
89
  # @api private
65
90
  # @since 0.1.0
66
- # @version 0.2.0
67
- def initialize(name, validator, caster)
91
+ # @version 0.3.0
92
+ # rubocop:disable Metrics/ParameterLists
93
+ def initialize(name, category, validator, caster, runtime_attributes_checker, *runtime_attributes)
68
94
  @name = name
95
+ @category = category
69
96
  @validator = validator
70
97
  @caster = caster
71
98
  @nilable = nil
99
+ @runtime_attributes_checker = runtime_attributes_checker
100
+ @runtime_attributes = runtime_attributes
72
101
  @lock = SmartCore::Engine::Lock.new
73
102
  end
103
+ # rubocop:enable Metrics/ParameterLists
104
+
105
+ # @param cloneable_instance [SmartCore::Types::Primitive]
106
+ # @return [SmartCore::Types::Primitive]
107
+ #
108
+ # @api private
109
+ # @since 0.3.0
110
+ def initialize_copy(cloneable_instance)
111
+ lock.synchronize do
112
+ self.class::Factory::RuntimeTypeBuilder.initialize_clone(self, cloneable_instance)
113
+ end
114
+ end
74
115
 
75
116
  # @param value [Any]
76
117
  # @return [Boolean]
@@ -116,8 +157,12 @@ class SmartCore::Types::Primitive
116
157
  #
117
158
  # @api public
118
159
  # @since 0.1.0
160
+ # @version 0.3.0
119
161
  def cast(value)
120
- caster.call(value)
162
+ # TODO (0.x.0):
163
+ # refactor with ValueTransformer with internal reference to the type object
164
+ # in Validator manner (in order to avoid explicit #runtime_attributes passing)
165
+ caster.call(value, runtime_attributes)
121
166
  end
122
167
 
123
168
  # @return [SmartCore::Types::Primitive]
@@ -2,6 +2,7 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
+ # @version 0.3.0
5
6
  class SmartCore::Types::Primitive::Caster
6
7
  # @param expression [Proc]
7
8
  # @return [void]
@@ -13,12 +14,14 @@ class SmartCore::Types::Primitive::Caster
13
14
  end
14
15
 
15
16
  # @param value [Any]
17
+ # @param runtime_attributes [Array<Any>]
16
18
  # @return [Any]
17
19
  #
18
20
  # @api private
19
21
  # @since 0.1.0
20
- def call(value)
21
- expression.call(value)
22
+ # @version 0.3.0
23
+ def call(value, runtime_attributes)
24
+ expression.call(value, runtime_attributes)
22
25
  end
23
26
 
24
27
  private
@@ -2,6 +2,7 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
+ # @version 0.3.0
5
6
  class SmartCore::Types::Primitive::Checker
6
7
  # @param expression [Proc]
7
8
  # @return [void]
@@ -13,12 +14,14 @@ class SmartCore::Types::Primitive::Checker
13
14
  end
14
15
 
15
16
  # @param value [Any]
17
+ # @param runtime_attributes [Array<Any>]
16
18
  # @return [Boolean]
17
19
  #
18
20
  # @api private
19
21
  # @since 0.1.0
20
- def call(value)
21
- !!expression.call(value)
22
+ # @version 0.3.0
23
+ def call(value, runtime_attributes)
24
+ !!expression.call(value, runtime_attributes)
22
25
  end
23
26
 
24
27
  private
@@ -2,9 +2,10 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
- # @version 0.2.0
5
+ # @version 0.3.0
6
6
  class SmartCore::Types::Primitive::Factory
7
7
  require_relative 'factory/definition_context'
8
+ require_relative 'factory/runtime_type_builder'
8
9
 
9
10
  class << self
10
11
  # @param type_category [Class<SmartCore::Types::Primitive>]
@@ -14,16 +15,25 @@ class SmartCore::Types::Primitive::Factory
14
15
  #
15
16
  # @api private
16
17
  # @since 0.1.0
17
- # @version 0.2.0
18
+ # @version 0.3.0
18
19
  def create_type(type_category, type_name, type_definition)
19
20
  type_definitions = build_type_definitions(type_definition)
21
+ type_runtime_attributes_checker = build_type_runtime_attributes_checker(type_definitions)
20
22
  type_checker = build_type_checker(type_definitions)
21
23
  type_caster = build_type_caster(type_definitions)
22
24
  type_invariant_control = build_type_invariant_control(type_definitions)
23
25
  type_validator = build_type_validator(type_checker, type_invariant_control)
24
- build_type(type_category, type_name, type_validator, type_caster).tap do |type|
26
+ build_type(
27
+ type_category,
28
+ type_name,
29
+ type_validator,
30
+ type_caster,
31
+ type_runtime_attributes_checker
32
+ ).tap do |type|
25
33
  assign_type_validator(type, type_validator)
34
+ assign_type_runtime_attributes_checker(type, type_runtime_attributes_checker)
26
35
  register_new_type(type_category, type_name, type)
36
+ register_runtime_type_builder(type_category, type_name)
27
37
  end
28
38
  end
29
39
 
@@ -48,6 +58,17 @@ class SmartCore::Types::Primitive::Factory
48
58
  end
49
59
  end
50
60
 
61
+ # @param type_definitions [SmartCore::Types::Primitive::Factory::DefinitionContext]
62
+ # @return [SmartCore::Types::Primitive::RuntimeAttributesChecker]
63
+ #
64
+ # @api private
65
+ # @since 0.3.0
66
+ def build_type_runtime_attributes_checker(type_definitions)
67
+ SmartCore::Types::Primitive::RuntimeAttributesChecker.new(
68
+ type_definitions.type_runtime_attributes_checker
69
+ )
70
+ end
71
+
51
72
  # @param type_definitions [SmartCore::Types::Primitive::Factory::DefinitionContext]
52
73
  # @return [SmartCore::Types::Primitive::InvariantControl]
53
74
  #
@@ -96,13 +117,26 @@ class SmartCore::Types::Primitive::Factory
96
117
  # @param type_name [String, Symbol]
97
118
  # @param type_validator [SmartCore::Types::Primitive::Validator]
98
119
  # @param type_caster [SmartCore::Types::Primitive::Caster]
120
+ # @param type_runtime_attributes_checker [SmartCore::Types::Primitive::RuntimeAttributesChecker]
99
121
  # @return [SmartCore::Types::Primitive]
100
122
  #
101
123
  # @api private
102
124
  # @since 0.1.0
103
- # @version 0.2.0
104
- def build_type(type_category, type_name, type_validator, type_caster)
105
- Class.new(type_category).new(type_name, type_validator, type_caster)
125
+ # @version 0.3.0
126
+ def build_type(
127
+ type_category,
128
+ type_name,
129
+ type_validator,
130
+ type_caster,
131
+ type_runtime_attributes_checker
132
+ )
133
+ Class.new(type_category).new(
134
+ type_name,
135
+ type_category,
136
+ type_validator,
137
+ type_caster,
138
+ type_runtime_attributes_checker
139
+ )
106
140
  end
107
141
 
108
142
  # @param type [SmartCore::Types::Primitive]
@@ -115,6 +149,16 @@ class SmartCore::Types::Primitive::Factory
115
149
  type_validator.___assign_type___(type)
116
150
  end
117
151
 
152
+ # @param type [SmartCore::Types::Primitive]
153
+ # @param type_runtime_attributes_checker [SmartCore::Types::Primitive::RuntimeAttributesChecker]
154
+ # @return [void]
155
+ #
156
+ # @api private
157
+ # @since 0.3.0
158
+ def assign_type_runtime_attributes_checker(type, type_runtime_attributes_checker)
159
+ type_runtime_attributes_checker.___assign_type___(type)
160
+ end
161
+
118
162
  # @param type_category [Class<SmartCore::Types::Primitive>]
119
163
  # @param type_name [String, Symbol]
120
164
  # @param type [SmartCore::Types::Primitive]
@@ -132,5 +176,19 @@ class SmartCore::Types::Primitive::Factory
132
176
  "Incorrect constant name for new type (#{type_name})"
133
177
  )
134
178
  end
179
+
180
+ # @param type_category [Class<SmartCore::Types::Primitive>]
181
+ # @param type_name [String, Symbol]
182
+ # @return [void]
183
+ #
184
+ # @raise [SmartCore::Types::IncorrectTypeNameError]
185
+ #
186
+ # @api private
187
+ # @since 0.3.0
188
+ def register_runtime_type_builder(type_category, type_name)
189
+ type_category.define_singleton_method(type_name) do |*runtime_attributes|
190
+ RuntimeTypeBuilder.build_with_runtime(type_name, type_category, runtime_attributes)
191
+ end
192
+ end
135
193
  end
136
194
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
- # @version 0.2.0
5
+ # @version 0.3.0
6
6
  class SmartCore::Types::Primitive::Factory::DefinitionContext
7
7
  class << self
8
8
  # @param name [String, Symbol]
@@ -11,19 +11,20 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
11
11
  #
12
12
  # @api private
13
13
  # @since 0.2.0
14
+ # @version 0.3.0
14
15
  def vaildate_invariant_attributes!(name, &definition)
15
16
  unless block_given?
16
- raise(SmartCore::Types::ArgumentError, 'No invariant block')
17
+ raise(SmartCore::Types::TypeDefinitionError, 'No invariant block')
17
18
  end
18
19
 
19
20
  unless name.is_a?(::String) || name.is_a?(::Symbol)
20
- raise(SmartCore::Types::ArgumentError, <<~ERROR_MESSAGE)
21
+ raise(SmartCore::Types::TypeDefinitionError, <<~ERROR_MESSAGE)
21
22
  Invariant name should be a type of string or symbol.
22
23
  ERROR_MESSAGE
23
24
  end
24
25
 
25
26
  if name == '' || name == :""
26
- raise(SmartCore::Types::ArgumentError, <<~ERROR_MESSAGE)
27
+ raise(SmartCore::Types::TypeDefinitionError, <<~ERROR_MESSAGE)
27
28
  Invariant name can not be empty.
28
29
  ERROR_MESSAGE
29
30
  end
@@ -37,17 +38,17 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
37
38
  # @since 0.3.0
38
39
  def vaildate_invariant_chain_attributes!(chain_name, &definition)
39
40
  unless block_given?
40
- raise(SmartCore::Types::ArgumentError, 'No invariant chain block')
41
+ raise(SmartCore::Types::TypeDefinitionError, 'No invariant chain block')
41
42
  end
42
43
 
43
44
  unless chain_name.is_a?(::String) || chain_name.is_a?(::Symbol)
44
- raise(SmartCore::Types::ArgumentError, <<~ERROR_MESSAGE)
45
+ raise(SmartCore::Types::TypeDefinitionError, <<~ERROR_MESSAGE)
45
46
  Invariant chain name should be a type of string or symbol.
46
47
  ERROR_MESSAGE
47
48
  end
48
49
 
49
50
  if chain_name == '' || chain_name == :""
50
- raise(SmartCore::Types::ArgumentError, <<~ERROR_MESSAGE)
51
+ raise(SmartCore::Types::TypeDefinitionError, <<~ERROR_MESSAGE)
51
52
  Invariant chain name can not be empty.
52
53
  ERROR_MESSAGE
53
54
  end
@@ -78,6 +79,12 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
78
79
  # @since 0.2.0
79
80
  attr_reader :type_invariants
80
81
 
82
+ # @return [Proc, NilClass]
83
+ #
84
+ # @api private
85
+ # @since 0.3.0
86
+ attr_reader :type_runtime_attributes_checker
87
+
81
88
  # @return [void]
82
89
  #
83
90
  # @api private
@@ -88,6 +95,7 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
88
95
  @type_invariants = {}
89
96
  @type_checker = nil
90
97
  @type_caster = nil
98
+ @type_runtime_attributes_checker = nil
91
99
  @definition_lock = SmartCore::Engine::Lock.new
92
100
  end
93
101
 
@@ -96,10 +104,12 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
96
104
  #
97
105
  # @api public
98
106
  # @since 0.1.0
99
- # @version 0.2.0
107
+ # @version 0.3.0
100
108
  def define_checker(&checker)
101
109
  thread_safe do
102
- raise(SmartCore::Types::ArgumentError, 'No checker definition block') unless block_given?
110
+ unless block_given?
111
+ raise(SmartCore::Types::TypeDefinitionError, 'No checker definition block')
112
+ end
103
113
  @type_checker = checker
104
114
  end
105
115
  end
@@ -109,10 +119,12 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
109
119
  #
110
120
  # @api public
111
121
  # @since 0.1.0
112
- # @version 0.2.0
122
+ # @version 0.3.0
113
123
  def define_caster(&caster)
114
124
  thread_safe do
115
- raise(SmartCore::Types::ArgumentError, 'No caster definition block') unless block_given?
125
+ unless block_given?
126
+ raise(SmartCore::Types::TypeDefinitionError, 'No caster definition block')
127
+ end
116
128
  @type_caster = caster
117
129
  end
118
130
  end
@@ -143,6 +155,20 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
143
155
  end
144
156
  end
145
157
 
158
+ # @param definition [Block]
159
+ # @return [void]
160
+ #
161
+ # @api public
162
+ # @since 0.3.0
163
+ def runtime_attributes_checker(&definition)
164
+ thread_safe do
165
+ unless block_given?
166
+ raise(SmartCore::Types::TypeDefinitionError, 'No runtime checker definition block')
167
+ end
168
+ @type_runtime_attributes_checker = definition
169
+ end
170
+ end
171
+
146
172
  private
147
173
 
148
174
  # @param block [Block]
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.3.0
5
+ module SmartCore::Types::Primitive::Factory::RuntimeTypeBuilder
6
+ class << self
7
+ # @param type_name [String, Symbol]
8
+ # @param type_category [Class<SmartCore::Types::Primitive>]
9
+ # @param runtime_attributes [Array<Any>]
10
+ # @return [SmartCore::Types::Primitive]
11
+ #
12
+ # @api private
13
+ # @since 0.3.0
14
+ def build_with_runtime(type_name, type_category, runtime_attributes)
15
+ type = type_category.const_get(type_name)
16
+ type.runtime_attributes_checker.check!(runtime_attributes)
17
+
18
+ type.clone.tap do |type_with_custom_runtime|
19
+ type_with_custom_runtime.instance_variable_set(
20
+ :@runtime_attributes, runtime_attributes.freeze
21
+ )
22
+ end
23
+ end
24
+
25
+ # @param new_instance [SmartCore::Types::Primitive]
26
+ # @param cloneable_instance [SmartCore::Types::Primitive]
27
+ # @return [void]
28
+ #
29
+ # @api private
30
+ # @since 0.3.0
31
+ # rubocop:disable Metrics/AbcSize, Layout/LineLength
32
+ def initialize_clone(new_instance, cloneable_instance)
33
+ name_clone = cloneable_instance.instance_variable_get(:@name)
34
+ category_clone = cloneable_instance.instance_variable_get(:@category)
35
+ validator_clone = cloneable_instance.instance_variable_get(:@validator).___copy_for___(new_instance)
36
+ caster_clone = cloneable_instance.instance_variable_get(:@caster)
37
+ runtime_attributes_clone = cloneable_instance.instance_variable_get(:@runtime_attributes).clone
38
+ runtime_attributes_checker_clone = cloneable_instance.instance_variable_get(:@runtime_attributes_checker).___copy_for___(new_instance)
39
+ lock_clone = SmartCore::Engine::Lock.new
40
+ nilable_clone = nil
41
+
42
+ new_instance.instance_variable_set(:@name, name_clone)
43
+ new_instance.instance_variable_set(:@category, category_clone)
44
+ new_instance.instance_variable_set(:@validator, validator_clone)
45
+ new_instance.instance_variable_set(:@caster, caster_clone)
46
+ new_instance.instance_variable_set(:@runtime_attributes, runtime_attributes_clone)
47
+ new_instance.instance_variable_set(:@runtime_attributes_checker, runtime_attributes_checker_clone)
48
+ new_instance.instance_variable_set(:@lock_clone, lock_clone)
49
+ new_instance.instance_variable_set(:@nilable, nilable_clone)
50
+ end
51
+ # rubocop:enable Metrics/AbcSize, Layout/LineLength
52
+ end
53
+ end