smart_types 0.1.0.alpha5 → 0.4.0

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