smart_types 0.1.0.alpha3 → 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 (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