smart_types 0.1.0 → 0.2.0

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