smart_types 0.2.0 → 0.3.0

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