smart_types 0.1.0 → 0.2.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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -1
  3. data/CHANGELOG.md +17 -0
  4. data/Gemfile.lock +59 -48
  5. data/README.md +178 -31
  6. data/Rakefile +0 -1
  7. data/bin/console +2 -2
  8. data/lib/smart_core/types/primitive.rb +54 -15
  9. data/lib/smart_core/types/primitive/factory.rb +46 -7
  10. data/lib/smart_core/types/primitive/factory/definition_context.rb +114 -4
  11. data/lib/smart_core/types/primitive/invariant_control.rb +64 -0
  12. data/lib/smart_core/types/primitive/invariant_control/chain.rb +58 -0
  13. data/lib/smart_core/types/primitive/invariant_control/chain/result.rb +64 -0
  14. data/lib/smart_core/types/primitive/invariant_control/factory.rb +54 -0
  15. data/lib/smart_core/types/primitive/invariant_control/factory/chain_definition_context.rb +39 -0
  16. data/lib/smart_core/types/primitive/invariant_control/result.rb +104 -0
  17. data/lib/smart_core/types/primitive/invariant_control/single.rb +54 -0
  18. data/lib/smart_core/types/primitive/invariant_control/single/result.rb +63 -0
  19. data/lib/smart_core/types/primitive/mult_factory.rb +25 -10
  20. data/lib/smart_core/types/primitive/mult_factory/definition_context.rb +4 -2
  21. data/lib/smart_core/types/primitive/mult_validator.rb +34 -0
  22. data/lib/smart_core/types/primitive/mult_validator/result.rb +8 -0
  23. data/lib/smart_core/types/primitive/nilable_factory.rb +24 -9
  24. data/lib/smart_core/types/primitive/nilable_validator.rb +83 -0
  25. data/lib/smart_core/types/primitive/nilable_validator/result.rb +78 -0
  26. data/lib/smart_core/types/primitive/sum_factory.rb +25 -10
  27. data/lib/smart_core/types/primitive/sum_factory/definition_context.rb +3 -1
  28. data/lib/smart_core/types/primitive/sum_validator.rb +101 -0
  29. data/lib/smart_core/types/primitive/sum_validator/result.rb +100 -0
  30. data/lib/smart_core/types/primitive/validator.rb +84 -0
  31. data/lib/smart_core/types/primitive/validator/result.rb +78 -0
  32. data/lib/smart_core/types/value.rb +9 -0
  33. data/lib/smart_core/types/value/enumerator.rb +13 -0
  34. data/lib/smart_core/types/value/enumerator_chain.rb +13 -0
  35. data/lib/smart_core/types/value/io.rb +13 -0
  36. data/lib/smart_core/types/value/method.rb +9 -0
  37. data/lib/smart_core/types/value/nil.rb +0 -2
  38. data/lib/smart_core/types/value/range.rb +9 -0
  39. data/lib/smart_core/types/value/rational.rb +13 -0
  40. data/lib/smart_core/types/value/set.rb +13 -0
  41. data/lib/smart_core/types/value/string_io.rb +13 -0
  42. data/lib/smart_core/types/value/unbound_method.rb +9 -0
  43. data/lib/smart_core/types/version.rb +2 -1
  44. data/smart_types.gemspec +5 -4
  45. metadata +53 -17
  46. data/lib/smart_core/types/primitive/mult_checker.rb +0 -31
  47. data/lib/smart_core/types/primitive/nilable_checker.rb +0 -37
  48. data/lib/smart_core/types/primitive/sum_checker.rb +0 -31
data/Rakefile CHANGED
@@ -4,7 +4,6 @@ require 'bundler/gem_tasks'
4
4
  require 'rspec/core/rake_task'
5
5
  require 'rubocop'
6
6
  require 'rubocop/rake_task'
7
- require 'rubocop-rails'
8
7
  require 'rubocop-performance'
9
8
  require 'rubocop-rspec'
10
9
  require 'rubocop-rake'
@@ -4,5 +4,5 @@
4
4
  require 'bundler/setup'
5
5
  require 'smart_core/types'
6
6
 
7
- require 'irb'
8
- IRB.start(__FILE__)
7
+ require 'pry'
8
+ Pry.start
@@ -2,16 +2,19 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
+ # @version 0.2.0
5
6
  class SmartCore::Types::Primitive
7
+ require_relative 'primitive/checker'
6
8
  require_relative 'primitive/caster'
7
9
  require_relative 'primitive/undefined_caster'
8
- require_relative 'primitive/checker'
9
- require_relative 'primitive/nilable_checker'
10
- require_relative 'primitive/sum_checker'
11
- require_relative 'primitive/mult_checker'
10
+ require_relative 'primitive/invariant_control'
11
+ require_relative 'primitive/validator'
12
12
  require_relative 'primitive/factory'
13
+ require_relative 'primitive/sum_validator'
13
14
  require_relative 'primitive/sum_factory'
15
+ require_relative 'primitive/mult_validator'
14
16
  require_relative 'primitive/mult_factory'
17
+ require_relative 'primitive/nilable_validator'
15
18
  require_relative 'primitive/nilable_factory'
16
19
 
17
20
  class << self
@@ -26,11 +29,12 @@ class SmartCore::Types::Primitive
26
29
  end
27
30
  end
28
31
 
29
- # @return [SmartCore::Types::Primitive::Checker]
32
+ # @note NilClass is suitable for sum-types, mult-types and nilable types.
33
+ # @return [String, NilClass]
30
34
  #
31
- # @api private
32
- # @since 0.1.0
33
- attr_reader :checker
35
+ # @api public
36
+ # @since 0.2.0
37
+ attr_reader :name
34
38
 
35
39
  # @return [SmartCore::Types::Primitive::Caster]
36
40
  #
@@ -38,17 +42,34 @@ class SmartCore::Types::Primitive
38
42
  # @since 0.1.0
39
43
  attr_reader :caster
40
44
 
41
- # @param checker [SmartCore::Types::Primitive::Checker]
45
+ # @return [SmartCore::Types::Primitive::Validator]
46
+ # @return [SmartCore::Types::Primitive::SumValidator]
47
+ # @return [SmartCore::Types::Primitive::MultValidator]
48
+ # @return [SmartCore::Types::primitive::NilableValidator]
49
+ #
50
+ # @api private
51
+ # @since 0.2.0
52
+ attr_reader :validator
53
+
54
+ # @param name [String, NilClass] NilClass is suitable for sum-types, mult-types and nilable types.
55
+ # @param validator [
56
+ # SmartCore::Types::Primitive::Validator,
57
+ # SmartCore::Types::Primitive::SumValidator,
58
+ # SmartCore::Types::Primitive::MultValidator,
59
+ # SmartCore::Types::Primitive::NilableValidator
60
+ # ]
42
61
  # @param caster [SmartCore::Types::Primitive::Caster]
43
62
  # @return [void]
44
63
  #
45
64
  # @api private
46
65
  # @since 0.1.0
47
- def initialize(checker, caster)
48
- @lock = SmartCore::Engine::Lock.new
49
- @checker = checker
66
+ # @version 0.2.0
67
+ def initialize(name, validator, caster)
68
+ @name = name
69
+ @validator = validator
50
70
  @caster = caster
51
71
  @nilable = nil
72
+ @lock = SmartCore::Engine::Lock.new
52
73
  end
53
74
 
54
75
  # @param value [Any]
@@ -56,20 +77,38 @@ class SmartCore::Types::Primitive
56
77
  #
57
78
  # @api public
58
79
  # @since 0.1.0
80
+ # @since 0.2.0
59
81
  def valid?(value)
60
- checker.call(value)
82
+ validator.valid?(value)
61
83
  end
62
84
 
63
85
  # @param value [Any]
64
86
  # @return [void]
65
87
  #
66
88
  # @raise [SmartCore::Types::TypeError]
89
+ # @see SmartCore::Primitive::Validator
90
+ # @see SmartCore::Primitive::MultValidator
91
+ # @see SmartCore::Primitive::SumValidator
92
+ # @see SmartCore::Primitive::NilableValidator
67
93
  #
68
94
  # @api public
69
95
  # @since 0.1.0
96
+ # @version 0.2.0
70
97
  def validate!(value)
71
- return if valid?(value)
72
- raise(SmartCore::Types::TypeError, 'Invalid type')
98
+ validator.validate!(value)
99
+ end
100
+
101
+ # @return [SmartCore::Types::Primitive::Validator::Result]
102
+ #
103
+ # @see SmartCore::Primitive::Validator
104
+ # @see SmartCore::Primitive::MultValidator
105
+ # @see SmartCore::Primitive::SumValidator
106
+ # @see SmartCore::Primitive::NilableValidator
107
+ #
108
+ # @api public
109
+ # @since 0.2.0
110
+ def validate(value)
111
+ validator.validate(value)
73
112
  end
74
113
 
75
114
  # @param value [Any]
@@ -2,6 +2,7 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
+ # @version 0.2.0
5
6
  class SmartCore::Types::Primitive::Factory
6
7
  require_relative 'factory/definition_context'
7
8
 
@@ -13,12 +14,17 @@ class SmartCore::Types::Primitive::Factory
13
14
  #
14
15
  # @api private
15
16
  # @since 0.1.0
17
+ # @version 0.2.0
16
18
  def create_type(type_category, type_name, type_definition)
17
19
  type_definitions = build_type_definitions(type_definition)
18
20
  type_checker = build_type_checker(type_definitions)
19
21
  type_caster = build_type_caster(type_definitions)
20
- type = build_type(type_category, type_name, type_checker, type_caster)
21
- type.tap { register_new_type(type_category, type_name, type) }
22
+ type_invariant_control = build_type_invariant_control(type_definitions)
23
+ type_validator = build_type_validator(type_checker, type_invariant_control)
24
+ build_type(type_category, type_name, type_validator, type_caster).tap do |type|
25
+ assign_type_validator(type, type_validator)
26
+ register_new_type(type_category, type_name, type)
27
+ end
22
28
  end
23
29
 
24
30
  private
@@ -38,10 +44,22 @@ class SmartCore::Types::Primitive::Factory
38
44
  raise(
39
45
  SmartCore::Types::NoCheckerDefinitionError,
40
46
  'Type checker is not provided. You should define it via .define_checker(&block)'
41
- ) if context.type_checker.nil?
47
+ ) if context.type_checker == nil
42
48
  end
43
49
  end
44
50
 
51
+ # @param type_definitions [SmartCore::Types::Primitive::Factory::DefinitionContext]
52
+ # @return [SmartCore::Types::Primitive::InvariantControl]
53
+ #
54
+ # @api private
55
+ # @since 0.2.0
56
+ def build_type_invariant_control(type_definitions)
57
+ SmartCore::Types::Primitive::InvariantControl.create(
58
+ type_definitions.type_invariant_chains,
59
+ type_definitions.type_invariants
60
+ )
61
+ end
62
+
45
63
  # @param type_definitions [SmartCore::Types::Primitive::Factory::DefinitionContext]
46
64
  # @return [SmartCore::Types::Primitive::Checker]
47
65
  #
@@ -57,23 +75,44 @@ class SmartCore::Types::Primitive::Factory
57
75
  # @api private
58
76
  # @since 0.1.0
59
77
  def build_type_caster(type_definitions)
60
- if type_definitions.type_caster.nil?
78
+ if type_definitions.type_caster == nil
61
79
  SmartCore::Types::Primitive::UndefinedCaster.new
62
80
  else
63
81
  SmartCore::Types::Primitive::Caster.new(type_definitions.type_caster)
64
82
  end
65
83
  end
66
84
 
85
+ # @param checker [SmartCore::Types::Primitive::Checker]
86
+ # @param invariant_control [SmartCore::Types::Primitive::InvariantControl]
87
+ # @return [void]
88
+ #
89
+ # @api private
90
+ # @since 0.2.0
91
+ def build_type_validator(type_checker, type_invariant_control)
92
+ SmartCore::Types::Primitive::Validator.new(type_checker, type_invariant_control)
93
+ end
94
+
67
95
  # @param type_klass [Class<SmartCore::Types::Primitive>]
68
96
  # @param type_name [String, Symbol]
69
- # @param type_checker [SmartCore::Types::Primitive::Checker]
97
+ # @param type_validator [SmartCore::Types::Primitive::Validator]
70
98
  # @param type_caster [SmartCore::Types::Primitive::Caster]
71
99
  # @return [SmartCore::Types::Primitive]
72
100
  #
73
101
  # @api private
74
102
  # @since 0.1.0
75
- def build_type(type_category, type_name, type_checker, type_caster)
76
- Class.new(type_category).new(type_checker, type_caster)
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)
106
+ end
107
+
108
+ # @param type [SmartCore::Types::Primitive]
109
+ # @param type_validator [SmartCore::Types::Primitive::Validator]
110
+ # @return [void]
111
+ #
112
+ # @api private
113
+ # @since 0.2.0
114
+ def assign_type_validator(type, type_validator)
115
+ type_validator.___assign_type___(type)
77
116
  end
78
117
 
79
118
  # @param type_category [Class<SmartCore::Types::Primitive>]
@@ -2,7 +2,58 @@
2
2
 
3
3
  # @api private
4
4
  # @since 0.1.0
5
+ # @version 0.2.0
5
6
  class SmartCore::Types::Primitive::Factory::DefinitionContext
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
+ def vaildate_invariant_attributes!(name, &definition)
15
+ unless block_given?
16
+ raise(SmartCore::Types::ArgumentError, 'No invariant block')
17
+ end
18
+
19
+ unless name.is_a?(::String) || name.is_a?(::Symbol)
20
+ raise(SmartCore::Types::ArgumentError, <<~ERROR_MESSAGE)
21
+ Invariant name should be a type of string or symbol.
22
+ ERROR_MESSAGE
23
+ end
24
+
25
+ if name == '' || name == :""
26
+ raise(SmartCore::Types::ArgumentError, <<~ERROR_MESSAGE)
27
+ Invariant name can not be empty.
28
+ ERROR_MESSAGE
29
+ end
30
+ end
31
+
32
+ # @param chain_name [String, Symbol]
33
+ # @param definition [Block]
34
+ # @return [void]
35
+ #
36
+ # @api private
37
+ # @since 0.3.0
38
+ def vaildate_invariant_chain_attributes!(chain_name, &definition)
39
+ unless block_given?
40
+ raise(SmartCore::Types::ArgumentError, 'No invariant chain block')
41
+ end
42
+
43
+ unless chain_name.is_a?(::String) || chain_name.is_a?(::Symbol)
44
+ raise(SmartCore::Types::ArgumentError, <<~ERROR_MESSAGE)
45
+ Invariant chain name should be a type of string or symbol.
46
+ ERROR_MESSAGE
47
+ end
48
+
49
+ if chain_name == '' || chain_name == :""
50
+ raise(SmartCore::Types::ArgumentError, <<~ERROR_MESSAGE)
51
+ Invariant chain name can not be empty.
52
+ ERROR_MESSAGE
53
+ end
54
+ end
55
+ end
56
+
6
57
  # @return [Proc, NilClass]
7
58
  #
8
59
  # @api private
@@ -15,13 +66,29 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
15
66
  # @since 0.1.0
16
67
  attr_reader :type_caster
17
68
 
69
+ # @return [Hash<String,Array<Proc>>]
70
+ #
71
+ # @api private
72
+ # @since 0.2.0
73
+ attr_reader :type_invariant_chains
74
+
75
+ # @return [Hash<String,Proc>]
76
+ #
77
+ # @api private
78
+ # @since 0.2.0
79
+ attr_reader :type_invariants
80
+
18
81
  # @return [void]
19
82
  #
20
83
  # @api private
21
84
  # @since 0.1.0
85
+ # @version 0.2.0
22
86
  def initialize
87
+ @type_invariant_chains = Hash.new { |h, k| h[k] = [] }
88
+ @type_invariants = {}
23
89
  @type_checker = nil
24
90
  @type_caster = nil
91
+ @definition_lock = SmartCore::Engine::Lock.new
25
92
  end
26
93
 
27
94
  # @param checker [Block]
@@ -29,9 +96,12 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
29
96
  #
30
97
  # @api public
31
98
  # @since 0.1.0
99
+ # @version 0.2.0
32
100
  def define_checker(&checker)
33
- raise(SmartCore::ArgumentError, 'No checker definition block') unless block_given?
34
- @type_checker = checker
101
+ thread_safe do
102
+ raise(SmartCore::Types::ArgumentError, 'No checker definition block') unless block_given?
103
+ @type_checker = checker
104
+ end
35
105
  end
36
106
 
37
107
  # @param caster [Block]
@@ -39,8 +109,48 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
39
109
  #
40
110
  # @api public
41
111
  # @since 0.1.0
112
+ # @version 0.2.0
42
113
  def define_caster(&caster)
43
- raise(SmartCore::ArgumentError, 'No caster definition block') unless block_given?
44
- @type_caster = caster
114
+ thread_safe do
115
+ raise(SmartCore::Types::ArgumentError, 'No caster definition block') unless block_given?
116
+ @type_caster = caster
117
+ end
118
+ end
119
+
120
+ # @param chain_name [String, Symbol]
121
+ # @param definitions [Block]
122
+ # @return [void]
123
+ #
124
+ # @api public
125
+ # @since 0.2.0
126
+ def invariant_chain(chain_name, &definitions)
127
+ thread_safe do
128
+ self.class.vaildate_invariant_chain_attributes!(chain_name, &definitions)
129
+ @type_invariant_chains[chain_name.to_s] << definitions
130
+ end
131
+ end
132
+
133
+ # @param name [String, Symbol]
134
+ # @param definition [Block]
135
+ # @return [void]
136
+ #
137
+ # @api public
138
+ # @since 0.2.0
139
+ def invariant(name, &definition)
140
+ thread_safe do
141
+ self.class.vaildate_invariant_attributes!(name, &definition)
142
+ @type_invariants[name.to_s] = definition
143
+ end
144
+ end
145
+
146
+ private
147
+
148
+ # @param block [Block]
149
+ # @return [Any]
150
+ #
151
+ # @api private
152
+ # @since 0.2.0
153
+ def thread_safe(&block)
154
+ @definition_lock.synchronize(&block)
45
155
  end
46
156
  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
6
+ require_relative 'invariant_control/result'
7
+ require_relative 'invariant_control/single'
8
+ require_relative 'invariant_control/chain'
9
+ require_relative 'invariant_control/factory'
10
+
11
+ class << self
12
+ # @param invariant_chains [Hash<String,Array<Proc>>]
13
+ # @param invariants [Hash<String,Proc>]
14
+ # @return [SmartCore::Types::Primitive::InvariantControl]
15
+ #
16
+ # @api private
17
+ # @since 0.2.0
18
+ def create(invariant_chains, invariants)
19
+ Factory.create(invariant_chains, invariants)
20
+ end
21
+ end
22
+
23
+ # @param invariant_chains [Array<SmartCore::Types::Primitive::InvariantControl::Chain>]
24
+ # @param invariants [Array<SmartCore::Types::Primitive::InvariantControl::Single>]
25
+ # @return [void]
26
+ #
27
+ # @api private
28
+ # @since 0.2.0
29
+ def initialize(invariant_chains, invariants)
30
+ @invariant_chains = invariant_chains
31
+ @invariants = invariants
32
+ end
33
+
34
+ # @param value [Any]
35
+ # @return [SmartCore::Types::Primitive::InvariantControl::Result]
36
+ #
37
+ # @api private
38
+ # @since 0.2.0
39
+ def check(value)
40
+ Result.new(self, value).tap do |result|
41
+ invariant_chains.each do |chain|
42
+ result.add_chain_result(chain.check(value))
43
+ end
44
+
45
+ invariants.each do |invariant|
46
+ result.add_single_result(invariant.check(value))
47
+ end
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ # @return [Array<SmartCore::Types::Primitive::InvariantControl::Chain>]
54
+ #
55
+ # @api private
56
+ # @since 0.2.0
57
+ attr_reader :invariant_chains
58
+
59
+ # @return [Array<SmartCore::Types::Primitive::InvariantControl::Single>]
60
+ #
61
+ # @api private
62
+ # @since 0.2.0
63
+ attr_reader :invariants
64
+ end