smart_types 0.1.0.alpha3 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -1
  3. data/.travis.yml +6 -5
  4. data/CHANGELOG.md +17 -0
  5. data/Gemfile.lock +74 -48
  6. data/README.md +292 -22
  7. data/Rakefile +1 -1
  8. data/bin/console +2 -2
  9. data/lib/smart_core/types/errors.rb +4 -0
  10. data/lib/smart_core/types/primitive.rb +67 -20
  11. data/lib/smart_core/types/primitive/factory.rb +48 -8
  12. data/lib/smart_core/types/primitive/factory/definition_context.rb +116 -6
  13. data/lib/smart_core/types/primitive/invariant_control.rb +64 -0
  14. data/lib/smart_core/types/primitive/invariant_control/chain.rb +58 -0
  15. data/lib/smart_core/types/primitive/invariant_control/chain/result.rb +64 -0
  16. data/lib/smart_core/types/primitive/invariant_control/factory.rb +54 -0
  17. data/lib/smart_core/types/primitive/invariant_control/factory/chain_definition_context.rb +39 -0
  18. data/lib/smart_core/types/primitive/invariant_control/result.rb +104 -0
  19. data/lib/smart_core/types/primitive/invariant_control/single.rb +54 -0
  20. data/lib/smart_core/types/primitive/invariant_control/single/result.rb +63 -0
  21. data/lib/smart_core/types/primitive/mult_factory.rb +25 -10
  22. data/lib/smart_core/types/primitive/mult_factory/definition_context.rb +5 -3
  23. data/lib/smart_core/types/primitive/mult_validator.rb +34 -0
  24. data/lib/smart_core/types/primitive/mult_validator/result.rb +8 -0
  25. data/lib/smart_core/types/primitive/nilable_factory.rb +24 -9
  26. data/lib/smart_core/types/primitive/nilable_validator.rb +83 -0
  27. data/lib/smart_core/types/primitive/nilable_validator/result.rb +78 -0
  28. data/lib/smart_core/types/primitive/sum_factory.rb +25 -10
  29. data/lib/smart_core/types/primitive/sum_factory/definition_context.rb +4 -2
  30. data/lib/smart_core/types/primitive/sum_validator.rb +101 -0
  31. data/lib/smart_core/types/primitive/sum_validator/result.rb +100 -0
  32. data/lib/smart_core/types/primitive/undefined_caster.rb +3 -4
  33. data/lib/smart_core/types/primitive/validator.rb +84 -0
  34. data/lib/smart_core/types/primitive/validator/result.rb +78 -0
  35. data/lib/smart_core/types/system.rb +21 -5
  36. data/lib/smart_core/types/value.rb +17 -0
  37. data/lib/smart_core/types/value/big_decimal.rb +28 -0
  38. data/lib/smart_core/types/value/comparable.rb +13 -0
  39. data/lib/smart_core/types/value/date.rb +21 -0
  40. data/lib/smart_core/types/value/date_time.rb +21 -0
  41. data/lib/smart_core/types/value/enumerable.rb +13 -0
  42. data/lib/smart_core/types/value/enumerator.rb +13 -0
  43. data/lib/smart_core/types/value/enumerator_chain.rb +13 -0
  44. data/lib/smart_core/types/value/float.rb +6 -2
  45. data/lib/smart_core/types/value/hash.rb +8 -1
  46. data/lib/smart_core/types/value/integer.rb +10 -3
  47. data/lib/smart_core/types/value/io.rb +13 -0
  48. data/lib/smart_core/types/value/method.rb +9 -0
  49. data/lib/smart_core/types/value/nil.rb +9 -0
  50. data/lib/smart_core/types/value/numeric.rb +13 -3
  51. data/lib/smart_core/types/value/proc.rb +11 -1
  52. data/lib/smart_core/types/value/range.rb +9 -0
  53. data/lib/smart_core/types/value/rational.rb +13 -0
  54. data/lib/smart_core/types/value/set.rb +13 -0
  55. data/lib/smart_core/types/value/string.rb +7 -1
  56. data/lib/smart_core/types/value/string_io.rb +13 -0
  57. data/lib/smart_core/types/value/symbol.rb +7 -1
  58. data/lib/smart_core/types/value/text.rb +16 -1
  59. data/lib/smart_core/types/value/time.rb +21 -0
  60. data/lib/smart_core/types/value/time_based.rb +29 -0
  61. data/lib/smart_core/types/value/unbound_method.rb +9 -0
  62. data/lib/smart_core/types/version.rb +2 -2
  63. data/smart_types.gemspec +6 -5
  64. metadata +64 -22
  65. data/lib/smart_core/types/primitive/mult_checker.rb +0 -31
  66. data/lib/smart_core/types/primitive/nilable_checker.rb +0 -37
  67. data/lib/smart_core/types/primitive/sum_checker.rb +0 -31
  68. data/lib/smart_core/types/system/definition_dsl.rb +0 -40
  69. data/lib/smart_core/types/system/producer_dsl.rb +0 -30
data/Rakefile CHANGED
@@ -11,8 +11,8 @@ require 'rubocop-rake'
11
11
  RuboCop::RakeTask.new(:rubocop) do |t|
12
12
  config_path = File.expand_path(File.join('.rubocop.yml'), __dir__)
13
13
  t.options = ['--config', config_path]
14
- t.requires << 'rubocop-performance'
15
14
  t.requires << 'rubocop-rspec'
15
+ t.requires << 'rubocop-performance'
16
16
  t.requires << 'rubocop-rake'
17
17
  end
18
18
 
@@ -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
@@ -21,6 +21,10 @@ module SmartCore::Types
21
21
  # @since 0.1.0
22
22
  TypeCastingError = Class.new(Error)
23
23
 
24
+ # @api public
25
+ # @since 0.1.0
26
+ TypeCastingUnsupportedError = Class.new(TypeCastingError)
27
+
24
28
  # @api public
25
29
  # @since 0.1.0
26
30
  NoCheckerDefinitionError = Class.new(Error)
@@ -2,26 +2,39 @@
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
- # @since 0.1.0
18
- include SmartCore::Types::System::ProducerDSL
20
+ class << self
21
+ # @param type_name [String, Symbol]
22
+ # @param type_definition [Block]
23
+ # @return [SmartCore::Types::Primitive]
24
+ #
25
+ # @api public
26
+ # @since 0.1.0
27
+ def define_type(type_name, &type_definition)
28
+ self::Factory.create_type(self, type_name, type_definition)
29
+ end
30
+ end
19
31
 
20
- # @return [SmartCore::Types::Primitive::Checker]
32
+ # @note NilClass is suitable for sum-types, mult-types and nilable types.
33
+ # @return [String, NilClass]
21
34
  #
22
- # @api private
23
- # @since 0.1.0
24
- attr_reader :checker
35
+ # @api public
36
+ # @since 0.2.0
37
+ attr_reader :name
25
38
 
26
39
  # @return [SmartCore::Types::Primitive::Caster]
27
40
  #
@@ -29,18 +42,34 @@ class SmartCore::Types::Primitive
29
42
  # @since 0.1.0
30
43
  attr_reader :caster
31
44
 
32
- # @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
+ # ]
33
61
  # @param caster [SmartCore::Types::Primitive::Caster]
34
- # @param nilable [SmartCore::Types::Primitive]
35
62
  # @return [void]
36
63
  #
37
64
  # @api private
38
65
  # @since 0.1.0
39
- def initialize(checker, caster)
40
- @lock = SmartCore::Engine::Lock.new
41
- @checker = checker
66
+ # @version 0.2.0
67
+ def initialize(name, validator, caster)
68
+ @name = name
69
+ @validator = validator
42
70
  @caster = caster
43
71
  @nilable = nil
72
+ @lock = SmartCore::Engine::Lock.new
44
73
  end
45
74
 
46
75
  # @param value [Any]
@@ -48,20 +77,38 @@ class SmartCore::Types::Primitive
48
77
  #
49
78
  # @api public
50
79
  # @since 0.1.0
80
+ # @since 0.2.0
51
81
  def valid?(value)
52
- checker.call(value)
82
+ validator.valid?(value)
53
83
  end
54
84
 
85
+ # @param value [Any]
55
86
  # @return [void]
56
87
  #
57
- # @raise [SmartCore::TypeError]
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
58
93
  #
59
94
  # @api public
60
95
  # @since 0.1.0
96
+ # @version 0.2.0
61
97
  def validate!(value)
62
- valid?(value) || raise(SmartCore::Types::TypeError, <<~ERROR_MESSAGE)
63
- Invalid type (given #{value.class}, expects #{self}-related)
64
- ERROR_MESSAGE
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)
65
112
  end
66
113
 
67
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_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
@@ -37,11 +43,23 @@ class SmartCore::Types::Primitive::Factory
37
43
  end.tap do |context|
38
44
  raise(
39
45
  SmartCore::Types::NoCheckerDefinitionError,
40
- 'Type checker is not provided (use .define_checker for it)'
41
- ) if context.type_checker.nil?
46
+ 'Type checker is not provided. You should define it via .define_checker(&block)'
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,22 +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
- # @param type_checker [SmartCore::Types::Primitive::Checker]
96
+ # @param type_name [String, Symbol]
97
+ # @param type_validator [SmartCore::Types::Primitive::Validator]
69
98
  # @param type_caster [SmartCore::Types::Primitive::Caster]
70
99
  # @return [SmartCore::Types::Primitive]
71
100
  #
72
101
  # @api private
73
102
  # @since 0.1.0
74
- def build_type(type_category, type_checker, type_caster)
75
- 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)
76
116
  end
77
117
 
78
118
  # @param type_category [Class<SmartCore::Types::Primitive>]
@@ -2,26 +2,93 @@
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
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
+ 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
+
57
+ # @return [Proc, NilClass]
7
58
  #
8
59
  # @api private
9
60
  # @since 0.1.0
10
61
  attr_reader :type_checker
11
62
 
12
- # @return [Proc]
63
+ # @return [Proc, NilClass]
13
64
  #
14
65
  # @api private
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 '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 '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