smart_types 0.1.0.alpha5 → 0.4.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -1
  3. data/CHANGELOG.md +46 -0
  4. data/Gemfile.lock +80 -52
  5. data/README.md +437 -27
  6. data/Rakefile +1 -1
  7. data/bin/console +2 -2
  8. data/lib/smart_core/types.rb +2 -0
  9. data/lib/smart_core/types/errors.rb +16 -0
  10. data/lib/smart_core/types/primitive.rb +109 -24
  11. data/lib/smart_core/types/primitive/caster.rb +5 -2
  12. data/lib/smart_core/types/primitive/checker.rb +5 -2
  13. data/lib/smart_core/types/primitive/factory.rb +105 -8
  14. data/lib/smart_core/types/primitive/factory/definition_context.rb +142 -6
  15. data/lib/smart_core/types/primitive/factory/runtime_type_builder.rb +53 -0
  16. data/lib/smart_core/types/primitive/invariant_control.rb +67 -0
  17. data/lib/smart_core/types/primitive/invariant_control/chain.rb +61 -0
  18. data/lib/smart_core/types/primitive/invariant_control/chain/result.rb +64 -0
  19. data/lib/smart_core/types/primitive/invariant_control/factory.rb +54 -0
  20. data/lib/smart_core/types/primitive/invariant_control/factory/chain_definition_context.rb +39 -0
  21. data/lib/smart_core/types/primitive/invariant_control/result.rb +104 -0
  22. data/lib/smart_core/types/primitive/invariant_control/single.rb +57 -0
  23. data/lib/smart_core/types/primitive/invariant_control/single/result.rb +63 -0
  24. data/lib/smart_core/types/primitive/mult_factory.rb +59 -10
  25. data/lib/smart_core/types/primitive/mult_factory/definition_context.rb +27 -3
  26. data/lib/smart_core/types/primitive/mult_validator.rb +42 -0
  27. data/lib/smart_core/types/primitive/mult_validator/result.rb +8 -0
  28. data/lib/smart_core/types/primitive/nilable_factory.rb +31 -9
  29. data/lib/smart_core/types/primitive/nilable_validator.rb +83 -0
  30. data/lib/smart_core/types/primitive/nilable_validator/result.rb +78 -0
  31. data/lib/smart_core/types/primitive/runtime_attributes_checker.rb +77 -0
  32. data/lib/smart_core/types/primitive/sum_factory.rb +59 -10
  33. data/lib/smart_core/types/primitive/sum_factory/definition_context.rb +26 -2
  34. data/lib/smart_core/types/primitive/sum_validator.rb +117 -0
  35. data/lib/smart_core/types/primitive/sum_validator/result.rb +100 -0
  36. data/lib/smart_core/types/primitive/undefined_caster.rb +7 -5
  37. data/lib/smart_core/types/primitive/validator.rb +93 -0
  38. data/lib/smart_core/types/primitive/validator/result.rb +78 -0
  39. data/lib/smart_core/types/protocol.rb +7 -0
  40. data/lib/smart_core/types/protocol/instance_of.rb +19 -0
  41. data/lib/smart_core/types/system.rb +21 -5
  42. data/lib/smart_core/types/value.rb +16 -0
  43. data/lib/smart_core/types/value/array.rb +3 -0
  44. data/lib/smart_core/types/value/big_decimal.rb +31 -0
  45. data/lib/smart_core/types/value/boolean.rb +3 -0
  46. data/lib/smart_core/types/value/class.rb +3 -0
  47. data/lib/smart_core/types/value/comparable.rb +13 -0
  48. data/lib/smart_core/types/value/date.rb +24 -0
  49. data/lib/smart_core/types/value/date_time.rb +24 -0
  50. data/lib/smart_core/types/value/enumerable.rb +13 -0
  51. data/lib/smart_core/types/value/enumerator.rb +13 -0
  52. data/lib/smart_core/types/value/enumerator_chain.rb +13 -0
  53. data/lib/smart_core/types/value/float.rb +9 -2
  54. data/lib/smart_core/types/value/hash.rb +11 -1
  55. data/lib/smart_core/types/value/integer.rb +13 -3
  56. data/lib/smart_core/types/value/io.rb +13 -0
  57. data/lib/smart_core/types/value/method.rb +9 -0
  58. data/lib/smart_core/types/value/module.rb +3 -0
  59. data/lib/smart_core/types/value/nil.rb +3 -3
  60. data/lib/smart_core/types/value/numeric.rb +16 -3
  61. data/lib/smart_core/types/value/proc.rb +14 -1
  62. data/lib/smart_core/types/value/range.rb +9 -0
  63. data/lib/smart_core/types/value/rational.rb +13 -0
  64. data/lib/smart_core/types/value/set.rb +21 -0
  65. data/lib/smart_core/types/value/string.rb +10 -1
  66. data/lib/smart_core/types/value/string_io.rb +15 -0
  67. data/lib/smart_core/types/value/symbol.rb +10 -1
  68. data/lib/smart_core/types/value/text.rb +21 -4
  69. data/lib/smart_core/types/value/time.rb +24 -0
  70. data/lib/smart_core/types/value/time_based.rb +32 -0
  71. data/lib/smart_core/types/value/unbound_method.rb +9 -0
  72. data/lib/smart_core/types/variadic.rb +7 -0
  73. data/lib/smart_core/types/variadic/tuple.rb +23 -0
  74. data/lib/smart_core/types/version.rb +2 -2
  75. data/smart_types.gemspec +6 -5
  76. metadata +69 -23
  77. data/.travis.yml +0 -20
  78. data/lib/smart_core/types/primitive/mult_checker.rb +0 -31
  79. data/lib/smart_core/types/primitive/nilable_checker.rb +0 -37
  80. data/lib/smart_core/types/primitive/sum_checker.rb +0 -31
  81. data/lib/smart_core/types/system/definition_dsl.rb +0 -40
  82. data/lib/smart_core/types/system/producer_dsl.rb +0 -30
@@ -2,26 +2,101 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
+ # @version 0.3.0
5
6
  class SmartCore::Types::Primitive::Factory::DefinitionContext
6
- # @return [Proc]
7
+ class << self
8
+ # @param name [String, Symbol]
9
+ # @param definition [Block]
10
+ # @return [void]
11
+ #
12
+ # @api private
13
+ # @since 0.2.0
14
+ # @version 0.3.0
15
+ def vaildate_invariant_attributes!(name, &definition)
16
+ unless block_given?
17
+ raise(SmartCore::Types::TypeDefinitionError, 'No invariant block')
18
+ end
19
+
20
+ unless name.is_a?(::String) || name.is_a?(::Symbol)
21
+ raise(SmartCore::Types::TypeDefinitionError, <<~ERROR_MESSAGE)
22
+ Invariant name should be a type of string or symbol.
23
+ ERROR_MESSAGE
24
+ end
25
+
26
+ if name == '' || name == :""
27
+ raise(SmartCore::Types::TypeDefinitionError, <<~ERROR_MESSAGE)
28
+ Invariant name can not be empty.
29
+ ERROR_MESSAGE
30
+ end
31
+ end
32
+
33
+ # @param chain_name [String, Symbol]
34
+ # @param definition [Block]
35
+ # @return [void]
36
+ #
37
+ # @api private
38
+ # @since 0.3.0
39
+ def vaildate_invariant_chain_attributes!(chain_name, &definition)
40
+ unless block_given?
41
+ raise(SmartCore::Types::TypeDefinitionError, 'No invariant chain block')
42
+ end
43
+
44
+ unless chain_name.is_a?(::String) || chain_name.is_a?(::Symbol)
45
+ raise(SmartCore::Types::TypeDefinitionError, <<~ERROR_MESSAGE)
46
+ Invariant chain name should be a type of string or symbol.
47
+ ERROR_MESSAGE
48
+ end
49
+
50
+ if chain_name == '' || chain_name == :""
51
+ raise(SmartCore::Types::TypeDefinitionError, <<~ERROR_MESSAGE)
52
+ Invariant chain name can not be empty.
53
+ ERROR_MESSAGE
54
+ end
55
+ end
56
+ end
57
+
58
+ # @return [Proc, NilClass]
7
59
  #
8
60
  # @api private
9
61
  # @since 0.1.0
10
62
  attr_reader :type_checker
11
63
 
12
- # @return [Proc]
64
+ # @return [Proc, NilClass]
13
65
  #
14
66
  # @api private
15
67
  # @since 0.1.0
16
68
  attr_reader :type_caster
17
69
 
70
+ # @return [Hash<String,Array<Proc>>]
71
+ #
72
+ # @api private
73
+ # @since 0.2.0
74
+ attr_reader :type_invariant_chains
75
+
76
+ # @return [Hash<String,Proc>]
77
+ #
78
+ # @api private
79
+ # @since 0.2.0
80
+ attr_reader :type_invariants
81
+
82
+ # @return [Proc, NilClass]
83
+ #
84
+ # @api private
85
+ # @since 0.3.0
86
+ attr_reader :type_runtime_attributes_checker
87
+
18
88
  # @return [void]
19
89
  #
20
90
  # @api private
21
91
  # @since 0.1.0
92
+ # @version 0.2.0
22
93
  def initialize
94
+ @type_invariant_chains = Hash.new { |h, k| h[k] = [] }
95
+ @type_invariants = {}
23
96
  @type_checker = nil
24
97
  @type_caster = nil
98
+ @type_runtime_attributes_checker = nil
99
+ @definition_lock = SmartCore::Engine::Lock.new
25
100
  end
26
101
 
27
102
  # @param checker [Block]
@@ -29,9 +104,14 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
29
104
  #
30
105
  # @api public
31
106
  # @since 0.1.0
107
+ # @version 0.3.0
32
108
  def define_checker(&checker)
33
- raise 'No checker definition block' unless block_given?
34
- @type_checker = checker
109
+ thread_safe do
110
+ unless block_given?
111
+ raise(SmartCore::Types::TypeDefinitionError, 'No checker definition block')
112
+ end
113
+ @type_checker = checker
114
+ end
35
115
  end
36
116
 
37
117
  # @param caster [Block]
@@ -39,8 +119,64 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
39
119
  #
40
120
  # @api public
41
121
  # @since 0.1.0
122
+ # @version 0.3.0
42
123
  def define_caster(&caster)
43
- raise 'No caster definition block' unless block_given?
44
- @type_caster = caster
124
+ thread_safe do
125
+ unless block_given?
126
+ raise(SmartCore::Types::TypeDefinitionError, 'No caster definition block')
127
+ end
128
+ @type_caster = caster
129
+ end
130
+ end
131
+
132
+ # @param chain_name [String, Symbol]
133
+ # @param definitions [Block]
134
+ # @return [void]
135
+ #
136
+ # @api public
137
+ # @since 0.2.0
138
+ def invariant_chain(chain_name, &definitions)
139
+ thread_safe do
140
+ self.class.vaildate_invariant_chain_attributes!(chain_name, &definitions)
141
+ @type_invariant_chains[chain_name.to_s] << definitions
142
+ end
143
+ end
144
+
145
+ # @param name [String, Symbol]
146
+ # @param definition [Block]
147
+ # @return [void]
148
+ #
149
+ # @api public
150
+ # @since 0.2.0
151
+ def invariant(name, &definition)
152
+ thread_safe do
153
+ self.class.vaildate_invariant_attributes!(name, &definition)
154
+ @type_invariants[name.to_s] = definition
155
+ end
156
+ end
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
+
172
+ private
173
+
174
+ # @param block [Block]
175
+ # @return [Any]
176
+ #
177
+ # @api private
178
+ # @since 0.2.0
179
+ def thread_safe(&block)
180
+ @definition_lock.synchronize(&block)
45
181
  end
46
182
  end
@@ -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
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.2.0
5
+ # @version 0.3.0
6
+ class SmartCore::Types::Primitive::InvariantControl
7
+ require_relative 'invariant_control/result'
8
+ require_relative 'invariant_control/single'
9
+ require_relative 'invariant_control/chain'
10
+ require_relative 'invariant_control/factory'
11
+
12
+ class << self
13
+ # @param invariant_chains [Hash<String,Array<Proc>>]
14
+ # @param invariants [Hash<String,Proc>]
15
+ # @return [SmartCore::Types::Primitive::InvariantControl]
16
+ #
17
+ # @api private
18
+ # @since 0.2.0
19
+ def create(invariant_chains, invariants)
20
+ Factory.create(invariant_chains, invariants)
21
+ end
22
+ end
23
+
24
+ # @param invariant_chains [Array<SmartCore::Types::Primitive::InvariantControl::Chain>]
25
+ # @param invariants [Array<SmartCore::Types::Primitive::InvariantControl::Single>]
26
+ # @return [void]
27
+ #
28
+ # @api private
29
+ # @since 0.2.0
30
+ def initialize(invariant_chains, invariants)
31
+ @invariant_chains = invariant_chains
32
+ @invariants = invariants
33
+ end
34
+
35
+ # @param value [Any]
36
+ # @param runtime_attributes [Array<Any>]
37
+ # @return [SmartCore::Types::Primitive::InvariantControl::Result]
38
+ #
39
+ # @api private
40
+ # @since 0.2.0
41
+ # @version 0.3.0
42
+ def check(value, runtime_attributes)
43
+ Result.new(self, value).tap do |result|
44
+ invariant_chains.each do |chain|
45
+ result.add_chain_result(chain.check(value, runtime_attributes))
46
+ end
47
+
48
+ invariants.each do |invariant|
49
+ result.add_single_result(invariant.check(value, runtime_attributes))
50
+ end
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ # @return [Array<SmartCore::Types::Primitive::InvariantControl::Chain>]
57
+ #
58
+ # @api private
59
+ # @since 0.2.0
60
+ attr_reader :invariant_chains
61
+
62
+ # @return [Array<SmartCore::Types::Primitive::InvariantControl::Single>]
63
+ #
64
+ # @api private
65
+ # @since 0.2.0
66
+ attr_reader :invariants
67
+ end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.2.0
5
+ # @version 0.3.0
6
+ class SmartCore::Types::Primitive::InvariantControl::Chain
7
+ require_relative 'chain/result'
8
+
9
+ # @return [String]
10
+ #
11
+ # @api private
12
+ # @since 0.2.0
13
+ attr_reader :name
14
+
15
+ # @param name [String]
16
+ # @return [void]
17
+ #
18
+ # @api private
19
+ # @since 0.1.0
20
+ def initialize(name)
21
+ @name = name.dup.tap(&:freeze)
22
+ @invariants = []
23
+ end
24
+
25
+ # @param invariant [SmartCore::Types::Primitive::InvariantControl::Single]
26
+ # @return [void]
27
+ #
28
+ # @api private
29
+ # @since 0.2.0
30
+ def add_invariant(invariant)
31
+ invariants << invariant
32
+ end
33
+
34
+ # @param value [Any]
35
+ # @param runtime_attributes [Array<Any>]
36
+ # @return [SmartCore::Types::Primitive::InvariantControl::Chain::Result]
37
+ #
38
+ # @api private
39
+ # @since 0.2.0
40
+ # @version 0.3.0
41
+ def check(value, runtime_attributes)
42
+ invariant_results = [].tap do |results|
43
+ invariants.each do |invariant|
44
+ result = invariant.check(value, runtime_attributes).tap { |res| results << res }
45
+ break if result.failure?
46
+ end
47
+ end
48
+
49
+ SmartCore::Types::Primitive::InvariantControl::Chain::Result.new(
50
+ self, value, invariant_results
51
+ )
52
+ end
53
+
54
+ private
55
+
56
+ # @return [Array<SmartCore::Types::Primitive::InvariantControl::Single>]
57
+ #
58
+ # @api private
59
+ # @since 0.2.0
60
+ attr_reader :invariants
61
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.2.0
5
+ class SmartCore::Types::Primitive::InvariantControl::Chain::Result
6
+ # @return [SmartCore::Types::Primitive::invariantControl::Chain]
7
+ #
8
+ # @api private
9
+ # @since 0.2.0
10
+ attr_reader :invariant_chain
11
+
12
+ # @return [Any]
13
+ #
14
+ # @api private
15
+ # @since 0.2.0
16
+ attr_reader :checked_value
17
+
18
+ # @param invariant_chain [SmartCore::Types::Primitive::invariantControl::Chain]
19
+ # @param checked_value [Any]
20
+ # @param invariant_results [Array<SmartCore::Types::Primitive::InvariantControl::Single::Result>]
21
+ # @return [void]
22
+ #
23
+ # @api private
24
+ # @since 0.2.0
25
+ def initialize(invariant_chain, checked_value, invariant_results)
26
+ @invariant_chain = invariant_chain
27
+ @checked_value = checked_value
28
+ @invariant_results = invariant_results
29
+ end
30
+
31
+ # @return [Boolean]
32
+ #
33
+ # @api private
34
+ # @since 0.2.0
35
+ def success?
36
+ invariant_results.all?(&:success?)
37
+ end
38
+
39
+ # @return [Boolean]
40
+ #
41
+ # @api private
42
+ # @since 0.2.0
43
+ def failure?
44
+ invariant_results.any?(&:failure?)
45
+ end
46
+
47
+ # @return [Array<String>]
48
+ #
49
+ # @api private
50
+ # @since 0.1.0
51
+ def error_codes
52
+ invariant_results.select(&:failure?).map do |invariant_result|
53
+ "#{invariant_chain.name}.#{invariant_result.invariant.name}".tap(&:freeze)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ # @return [Array<SmartCore::Types::Primitive::InvariantControl::Single::Result>]
60
+ #
61
+ # @api private
62
+ # @since 0.2.0
63
+ attr_reader :invariant_results
64
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api private
4
+ # @since 0.2.0
5
+ module SmartCore::Types::Primitive::InvariantControl::Factory
6
+ require_relative 'factory/chain_definition_context'
7
+
8
+ class << self
9
+ # @param invariant_chains [Hash<String,Array<Proc>]
10
+ # @param invariants [Hash<String,Proc>]
11
+ # @return [SmartCore::Types::Primitive::InvariantControl]
12
+ #
13
+ # @api private
14
+ # @since 0.2.0
15
+ def create(invariant_chains, invariants)
16
+ completed_invariant_chains = build_invariant_chains(invariant_chains)
17
+ completed_invariants = build_invariants(invariants)
18
+
19
+ SmartCore::Types::Primitive::InvariantControl.new(
20
+ completed_invariant_chains,
21
+ completed_invariants
22
+ )
23
+ end
24
+
25
+ private
26
+
27
+ # @param invariant_chains [Hash<String,Array<Proc>]
28
+ # @return [Array<SmartCore::Types::Primitive::InvariantControl::Chain>]
29
+ #
30
+ # @api private
31
+ # @since 0.2.0
32
+ def build_invariant_chains(invariant_chains)
33
+ invariant_chains.map do |chain_name, chain_invariants|
34
+ context = ChainDefinitionContext.new(chain_name)
35
+ chain_invariants.each { |invariant_logic| context.instance_eval(&invariant_logic) }
36
+ context.___chain___
37
+ end
38
+ end
39
+
40
+ # @param invariants [Hash<String,Proc>]
41
+ # @return [Array<SmartCore::Types::Primitive::InvariantControl::Single>]
42
+ #
43
+ # @api private
44
+ # @since 0.2.0
45
+ def build_invariants(invariants)
46
+ invariants.map do |invariant_name, invariant_logics|
47
+ SmartCore::Types::Primitive::InvariantControl::Single.create(
48
+ invariant_name,
49
+ invariant_logics
50
+ )
51
+ end
52
+ end
53
+ end
54
+ end