smart_types 0.1.0.alpha6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -1
  3. data/.travis.yml +6 -5
  4. data/Gemfile.lock +43 -28
  5. data/README.md +117 -13
  6. data/Rakefile +2 -1
  7. data/lib/smart_core/types/errors.rb +4 -0
  8. data/lib/smart_core/types/primitive.rb +14 -24
  9. data/lib/smart_core/types/primitive/factory.rb +1 -1
  10. data/lib/smart_core/types/primitive/factory/definition_context.rb +4 -4
  11. data/lib/smart_core/types/primitive/mult_factory/definition_context.rb +2 -2
  12. data/lib/smart_core/types/primitive/sum_factory/definition_context.rb +2 -2
  13. data/lib/smart_core/types/primitive/undefined_caster.rb +3 -4
  14. data/lib/smart_core/types/system.rb +21 -5
  15. data/lib/smart_core/types/value.rb +7 -0
  16. data/lib/smart_core/types/value/big_decimal.rb +28 -0
  17. data/lib/smart_core/types/value/comparable.rb +13 -0
  18. data/lib/smart_core/types/value/date.rb +21 -0
  19. data/lib/smart_core/types/value/date_time.rb +21 -0
  20. data/lib/smart_core/types/value/enumerable.rb +13 -0
  21. data/lib/smart_core/types/value/float.rb +6 -2
  22. data/lib/smart_core/types/value/hash.rb +8 -1
  23. data/lib/smart_core/types/value/integer.rb +10 -3
  24. data/lib/smart_core/types/value/nil.rb +3 -1
  25. data/lib/smart_core/types/value/numeric.rb +13 -3
  26. data/lib/smart_core/types/value/proc.rb +11 -1
  27. data/lib/smart_core/types/value/string.rb +7 -1
  28. data/lib/smart_core/types/value/symbol.rb +7 -1
  29. data/lib/smart_core/types/value/text.rb +18 -2
  30. data/lib/smart_core/types/value/time.rb +21 -0
  31. data/lib/smart_core/types/value/time_based.rb +29 -0
  32. data/lib/smart_core/types/version.rb +1 -2
  33. data/smart_types.gemspec +4 -4
  34. metadata +18 -13
  35. data/lib/smart_core/types/system/definition_dsl.rb +0 -40
  36. data/lib/smart_core/types/system/producer_dsl.rb +0 -30
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d7ed742470e7ce794fc75f9e90e9e4b6eaa705658ab15404416f38798fc43822
4
- data.tar.gz: e5cf9c4b207739ca7bc09ae46708b00676a2adb60a71cc679391238cbc696d4b
3
+ metadata.gz: 12c87a28e4cb88c84907c5d811253c4cb70e3e4aad462010c47c1a6d88c21d81
4
+ data.tar.gz: af0155909d10f02369aa5b60c97de4b0b91fbfad92ba79d1f94b5b3333ede373
5
5
  SHA512:
6
- metadata.gz: 957613e5f2b4d3adde721c39c35ad4b934f74463812768e232a0496313a0fdbe9e1a1cf335b4184adc7e14473bce5a062fd2c2e553834ac964381ae435c2fc9b
7
- data.tar.gz: 77ab18057ad5a66326a911caca44b19446cfe97f5bf961bf92e2efcecc109dbfbc45d4d7bfb70bdf83002eddffd6ca4b16631270d77cf2015b2ca990de229fbe
6
+ metadata.gz: aa5eb3001d7909b30e9fe2df27b92bff6ee22d9e92ef27f37dfbe11c18f968ee932cf0e064ecb2db808d8a0913d3c5fe7650d0d7b15af51bbe4591afeef39670
7
+ data.tar.gz: e0fa90c1783113d8d702414596cf001e0e54b786c6d21248e52f5e2401901eddebb09d182349abccda301998782242fa02d4a94e61eb2a3f301fe982a7d5ceff
@@ -5,7 +5,7 @@ inherit_gem:
5
5
  - lib/rubocop.rspec.yml
6
6
 
7
7
  AllCops:
8
- TargetRubyVersion: 2.4.9
8
+ TargetRubyVersion: 2.7.1
9
9
  Include:
10
10
  - lib/**/*.rb
11
11
  - spec/**/*.rb
@@ -13,3 +13,7 @@ AllCops:
13
13
  - Rakefile
14
14
  - smart_types.gemspec
15
15
  - bin/console
16
+
17
+ # NOTE: support for old ruby versions
18
+ Style/RedundantBegin:
19
+ Enabled: false
@@ -2,17 +2,18 @@
2
2
  language: ruby
3
3
  cache: bundler
4
4
  os: linux
5
- before_install: gem install bundler -v 2.1.2
5
+ dist: xenial
6
+ before_install: gem install bundler
6
7
  script:
7
8
  - bundle exec rake rubocop
8
9
  - bundle exec rake rspec
9
10
  jobs:
10
11
  fast_finish: true
11
12
  include:
12
- - rvm: 2.4.9
13
- - rvm: 2.5.7
14
- - rvm: 2.6.5
15
- - rvm: 2.7.0
13
+ - rvm: 2.4.10
14
+ - rvm: 2.5.8
15
+ - rvm: 2.6.6
16
+ - rvm: 2.7.1
16
17
  - rvm: ruby-head
17
18
  - rvm: jruby-head
18
19
  allow_failures:
@@ -1,77 +1,92 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_types (0.1.0.alpha5)
5
- smart_engine (~> 0.5)
4
+ smart_types (0.1.0)
5
+ smart_engine (~> 0.6)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- armitage-rubocop (0.79.0)
11
- rubocop (= 0.79.0)
10
+ activesupport (6.0.2.2)
11
+ concurrent-ruby (~> 1.0, >= 1.0.2)
12
+ i18n (>= 0.7, < 2)
13
+ minitest (~> 5.1)
14
+ tzinfo (~> 1.1)
15
+ zeitwerk (~> 2.2)
16
+ armitage-rubocop (0.82.0.2)
17
+ rubocop (= 0.82.0)
12
18
  rubocop-performance (= 1.5.2)
13
- rubocop-rails (= 2.4.1)
14
- rubocop-rake (= 0.5.0)
15
- rubocop-rspec (= 1.37.1)
19
+ rubocop-rails (= 2.5.2)
20
+ rubocop-rake (= 0.5.1)
21
+ rubocop-rspec (= 1.39.0)
16
22
  ast (2.4.0)
23
+ concurrent-ruby (1.1.6)
17
24
  diff-lcs (1.3)
18
25
  docile (1.3.2)
26
+ i18n (1.8.2)
27
+ concurrent-ruby (~> 1.0)
19
28
  jaro_winkler (1.5.4)
20
- json (2.3.0)
29
+ minitest (5.14.0)
21
30
  parallel (1.19.1)
22
- parser (2.7.0.2)
31
+ parser (2.7.1.2)
23
32
  ast (~> 2.4.0)
24
- rack (2.1.1)
33
+ rack (2.2.2)
25
34
  rainbow (3.0.0)
26
35
  rake (13.0.1)
36
+ rexml (3.2.4)
27
37
  rspec (3.9.0)
28
38
  rspec-core (~> 3.9.0)
29
39
  rspec-expectations (~> 3.9.0)
30
40
  rspec-mocks (~> 3.9.0)
31
- rspec-core (3.9.1)
32
- rspec-support (~> 3.9.1)
33
- rspec-expectations (3.9.0)
41
+ rspec-core (3.9.2)
42
+ rspec-support (~> 3.9.3)
43
+ rspec-expectations (3.9.1)
34
44
  diff-lcs (>= 1.2.0, < 2.0)
35
45
  rspec-support (~> 3.9.0)
36
46
  rspec-mocks (3.9.1)
37
47
  diff-lcs (>= 1.2.0, < 2.0)
38
48
  rspec-support (~> 3.9.0)
39
- rspec-support (3.9.2)
40
- rubocop (0.79.0)
49
+ rspec-support (3.9.3)
50
+ rubocop (0.82.0)
41
51
  jaro_winkler (~> 1.5.1)
42
52
  parallel (~> 1.10)
43
53
  parser (>= 2.7.0.1)
44
54
  rainbow (>= 2.2.2, < 4.0)
55
+ rexml
45
56
  ruby-progressbar (~> 1.7)
46
- unicode-display_width (>= 1.4.0, < 1.7)
57
+ unicode-display_width (>= 1.4.0, < 2.0)
47
58
  rubocop-performance (1.5.2)
48
59
  rubocop (>= 0.71.0)
49
- rubocop-rails (2.4.1)
60
+ rubocop-rails (2.5.2)
61
+ activesupport
50
62
  rack (>= 1.1)
51
63
  rubocop (>= 0.72.0)
52
- rubocop-rake (0.5.0)
64
+ rubocop-rake (0.5.1)
53
65
  rubocop
54
- rubocop-rspec (1.37.1)
66
+ rubocop-rspec (1.39.0)
55
67
  rubocop (>= 0.68.1)
56
68
  ruby-progressbar (1.10.1)
57
- simplecov (0.17.1)
69
+ simplecov (0.18.5)
58
70
  docile (~> 1.1)
59
- json (>= 1.8, < 3)
60
- simplecov-html (~> 0.10.0)
61
- simplecov-html (0.10.2)
62
- smart_engine (0.5.0)
63
- unicode-display_width (1.6.0)
71
+ simplecov-html (~> 0.11)
72
+ simplecov-html (0.12.2)
73
+ smart_engine (0.6.0)
74
+ thread_safe (0.3.6)
75
+ tzinfo (1.2.7)
76
+ thread_safe (~> 0.1)
77
+ unicode-display_width (1.7.0)
78
+ zeitwerk (2.3.0)
64
79
 
65
80
  PLATFORMS
66
81
  ruby
67
82
 
68
83
  DEPENDENCIES
69
- armitage-rubocop (~> 0.78)
84
+ armitage-rubocop (~> 0.82)
70
85
  bundler (~> 2.1)
71
86
  rake (~> 13.0)
72
87
  rspec (~> 3.9)
73
- simplecov (~> 0.17)
88
+ simplecov (~> 0.18)
74
89
  smart_types!
75
90
 
76
91
  BUNDLED WITH
77
- 2.1.2
92
+ 2.1.4
data/README.md CHANGED
@@ -2,12 +2,10 @@
2
2
 
3
3
  > A set of objects that acts like types (type checking and type casting) with a support for basic type algebra.
4
4
 
5
- Full-featured type system for any ruby project. Supports custom type definitioning,
5
+ Minimalistic type system for any ruby project. Supports custom type definitioning,
6
6
  type validation, type casting and type categorizing. Provides a set of commonly used type
7
7
  categories and general purpose types. Has a flexible and simplest type definition toolchain.
8
8
 
9
- Just add and use :) Enjoy! :)
10
-
11
9
  ## Installation
12
10
 
13
11
  ```ruby
@@ -45,18 +43,24 @@ type4 = type1 & type2
45
43
 
46
44
  ```ruby
47
45
  SmartCore::Types::Value::Any
46
+ SmartCore::Types::Value::Nil
48
47
  SmartCore::Types::Value::String
49
48
  SmartCore::Types::Value::Symbol
50
49
  SmartCore::Types::Value::Text
51
50
  SmartCore::Types::Value::Integer
52
51
  SmartCore::Types::Value::Float
53
52
  SmartCore::Types::Value::Numeric
53
+ SmartCore::Types::Value::BigDecimal
54
54
  SmartCore::Types::Value::Boolean
55
55
  SmartCore::Types::Value::Array
56
56
  SmartCore::Types::Value::Hash
57
57
  SmartCore::Types::Value::Proc
58
58
  SmartCore::Types::Value::Class
59
59
  SmartCore::Types::Value::Module
60
+ SmartCore::Types::Value::Time
61
+ SmartCore::Types::Value::DateTime
62
+ SmartCore::Types::Value::Date
63
+ SmartCore::Types::Value::TimeBased
60
64
  ```
61
65
 
62
66
  ---
@@ -65,34 +69,38 @@ SmartCore::Types::Value::Module
65
69
 
66
70
  ```ruby
67
71
  SmartCore::Types::Value::Any.nilable
72
+ SmartCore::Types::Value::Nil.nilable
68
73
  SmartCore::Types::Value::String.nilable
69
74
  SmartCore::Types::Value::Symbol.nilable
70
75
  SmartCore::Types::Value::Text.nilable
71
76
  SmartCore::Types::Value::Integer.nilable
72
77
  SmartCore::Types::Value::Float.nilable
73
78
  SmartCore::Types::Value::Numeric.nilable
79
+ SmartCore::Types::Value::BigDecimal.nilable
74
80
  SmartCore::Types::Value::Boolean.nilable
75
81
  SmartCore::Types::Value::Array.nilable
76
82
  SmartCore::Types::Value::Hash.nilable
77
83
  SmartCore::Types::Value::Proc.nilable
78
84
  SmartCore::Types::Value::Class.nilable
79
85
  SmartCore::Types::Value::Module.nilable
86
+ SmartCore::Types::Value::Time.nilable.nilable
87
+ SmartCore::Types::Value::DateTime.nilable
88
+ SmartCore::Types::Value::Date.nilable
89
+ SmartCore::Types::Value::TimeBased
80
90
  ```
81
91
 
82
92
  ---
83
93
 
84
- ## Constrained types
94
+ ## Type validation and type casting
85
95
 
86
96
  ```ruby
87
97
  # documentation is coming
88
- ```
89
98
 
90
- ---
91
-
92
- ## Type validation and type casting
99
+ SmartCore::Types::Value::String.valid?('test') # => true
100
+ SmartCore::Types::Value::String.valid?(123.45) # => false
93
101
 
94
- ```ruby
95
- # documentation is coming
102
+ SmartCore::Types::Value::String.cast(123) # => "123"
103
+ SmartCore::Types::Value::Float.cast('55') # => 55.0
96
104
  ```
97
105
 
98
106
  ---
@@ -124,13 +132,109 @@ end
124
132
 
125
133
  ---
126
134
 
127
- ## Type system integration
135
+ ## Roadmap
136
+
137
+ - type configuration:
128
138
 
129
139
  ```ruby
130
- # documentation is coming
140
+ SmartCore::Types::Value.type(:Time) do |type|
141
+ type.configuration do |config| # config definition
142
+ setting :iso, :rfc2822
143
+ # TODO: think about a more convinient DSL
144
+ end
145
+
146
+ type.define_caster do |value, config| # config usage
147
+ case config.standard
148
+ when :rfc2822
149
+ ::Time.rfc2822(value)
150
+ else
151
+ # ...
152
+ end
153
+ end
154
+ end
131
155
  ```
132
156
 
133
- ---
157
+ - pipelined type caster definition for the sum-based types:
158
+
159
+ ```ruby
160
+ SmartCore::Types::Value::TimeLike = SmartCore::Types::System.type_sum(
161
+ SmartCore::Types::Time,
162
+ SmartCore::Types::DateTime,
163
+ SmartCore::Types::Date,
164
+ ) do |type|
165
+ type.define_caster(:pipelined) # try Time.cast => try DateTime.cast => try Date.cast
166
+ end
167
+ ```
168
+
169
+ - namespaced type errors:
170
+
171
+ ```ruby
172
+ # before:
173
+ SmartCore::Types::Value::Boolean.validate!(123)
174
+ # => SmartCore::Types::TypeError
175
+ SmartCore::Types::Value::Class.cast(123)
176
+ # => SmartCore::Types::TypeCastingError
177
+
178
+ # after:
179
+ SmartCore::Types::Value::Boolean.validate!(123)
180
+ # => SmartCore::Types::Value::Boolean::TypeError
181
+ # (inheritance tree: Types::Value::<Type>::TypeError => Types::Value::TypeError => Types::TypeError)
182
+
183
+ SmartCore::Types::Value::Class.cast(123)
184
+ # => SmartCore::Types::Value::Class::TypeCastingError
185
+ # (inheritance tree: the same as above)
186
+ ```
187
+
188
+ - type refinements:
189
+
190
+ ```ruby
191
+ SmartCore::Types::Value::Time.refine_checker do |value, original_checker|
192
+ # new type checker
193
+ end
194
+
195
+ SmartCore::Types::Value::Time.refine_caster do |value, original_caster|
196
+ # new type caster
197
+ end
198
+ ```
199
+
200
+ - options for type casters:
201
+
202
+ ```ruby
203
+ SmartCore::Types::Value.define_type(:Date) do |type|
204
+ type.define_caster do |value, options = {}| # options goes here
205
+ iso = options.fetch(:iso, nil)
206
+ iso ? ::Date.pasre(value, iso) : ::Date.parse(value)
207
+ end
208
+ end
209
+
210
+ # usage:
211
+ SmartCore::Types::Value::Date.cast('2020-01-01', { iso: :rfc3339 })
212
+ ```
213
+
214
+ - new types:
215
+
216
+ ```ruby
217
+ SmartCore::Types::Value::Method
218
+ SmartCore::Types::Value::UnboundMethod
219
+ SmartCore::Types::Value::Enumerable
220
+ SmartCore::Types::Value::Comparable
221
+ SmartCore::Types::Struct::Schema
222
+ SmartCore::Types::Struct::StrictArray
223
+ SmartCore::Types::Struct::StrictHash
224
+ SmartCore::Types::Struct::Map
225
+ SmartCore::Types::Variative::Enum
226
+ SmartCore::Types::Variative::Variant
227
+ SmartCore::Types::Protocol::InstanceOf
228
+ SmartCore::Types::Protocol::Interface
229
+ SmartCore::Types::Protocol::Ancestors
230
+ SmartCore::Types::Protocol::Enumerable
231
+ SmartCore::Types::Protocol::Comparable
232
+ SmartCore::Types::Protocol::Forwardable
233
+ ```
234
+
235
+ - constrained types;
236
+
237
+ - module-based integration;
134
238
 
135
239
  ## Contributing
136
240
 
data/Rakefile CHANGED
@@ -4,6 +4,7 @@ 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'
7
8
  require 'rubocop-performance'
8
9
  require 'rubocop-rspec'
9
10
  require 'rubocop-rake'
@@ -11,8 +12,8 @@ require 'rubocop-rake'
11
12
  RuboCop::RakeTask.new(:rubocop) do |t|
12
13
  config_path = File.expand_path(File.join('.rubocop.yml'), __dir__)
13
14
  t.options = ['--config', config_path]
14
- t.requires << 'rubocop-performance'
15
15
  t.requires << 'rubocop-rspec'
16
+ t.requires << 'rubocop-performance'
16
17
  t.requires << 'rubocop-rake'
17
18
  end
18
19
 
@@ -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)
@@ -14,8 +14,17 @@ class SmartCore::Types::Primitive
14
14
  require_relative 'primitive/mult_factory'
15
15
  require_relative 'primitive/nilable_factory'
16
16
 
17
- # @since 0.1.0
18
- include SmartCore::Types::System::ProducerDSL
17
+ class << self
18
+ # @param type_name [String, Symbol]
19
+ # @param type_definition [Block]
20
+ # @return [SmartCore::Types::Primitive]
21
+ #
22
+ # @api public
23
+ # @since 0.1.0
24
+ def define_type(type_name, &type_definition)
25
+ self::Factory.create_type(self, type_name, type_definition)
26
+ end
27
+ end
19
28
 
20
29
  # @return [SmartCore::Types::Primitive::Checker]
21
30
  #
@@ -31,7 +40,6 @@ class SmartCore::Types::Primitive
31
40
 
32
41
  # @param checker [SmartCore::Types::Primitive::Checker]
33
42
  # @param caster [SmartCore::Types::Primitive::Caster]
34
- # @param name [String]
35
43
  # @return [void]
36
44
  #
37
45
  # @api private
@@ -43,14 +51,6 @@ class SmartCore::Types::Primitive
43
51
  @nilable = nil
44
52
  end
45
53
 
46
- # @return [String]
47
- #
48
- # @api public
49
- # @since 0.1.0
50
- def name
51
- self.class.name
52
- end
53
-
54
54
  # @param value [Any]
55
55
  # @return [Boolean]
56
56
  #
@@ -60,26 +60,16 @@ class SmartCore::Types::Primitive
60
60
  checker.call(value)
61
61
  end
62
62
 
63
+ # @param value [Any]
63
64
  # @return [void]
64
65
  #
65
- # @raise [SmartCore::TypeError]
66
+ # @raise [SmartCore::Types::TypeError]
66
67
  #
67
68
  # @api public
68
69
  # @since 0.1.0
69
70
  def validate!(value)
70
71
  return if valid?(value)
71
-
72
- # rubocop:disable Layout/RescueEnsureAlignment
73
- value_type = begin
74
- value.class.name
75
- rescue NoMethodError
76
- (class << value; superclass; end).name
77
- end
78
- # rubocop:enable Layout/RescueEnsureAlignment
79
-
80
- raise(SmartCore::Types::TypeError, <<~ERROR_MESSAGE)
81
- Invalid type (given #{value_type}, expects #{self.class.name}/SmartCore)
82
- ERROR_MESSAGE
72
+ raise(SmartCore::Types::TypeError, 'Invalid type')
83
73
  end
84
74
 
85
75
  # @param value [Any]
@@ -37,7 +37,7 @@ class SmartCore::Types::Primitive::Factory
37
37
  end.tap do |context|
38
38
  raise(
39
39
  SmartCore::Types::NoCheckerDefinitionError,
40
- 'Type checker is not provided (use .define_checker for it)'
40
+ 'Type checker is not provided. You should define it via .define_checker(&block)'
41
41
  ) if context.type_checker.nil?
42
42
  end
43
43
  end
@@ -3,13 +3,13 @@
3
3
  # @api private
4
4
  # @since 0.1.0
5
5
  class SmartCore::Types::Primitive::Factory::DefinitionContext
6
- # @return [Proc]
6
+ # @return [Proc, NilClass]
7
7
  #
8
8
  # @api private
9
9
  # @since 0.1.0
10
10
  attr_reader :type_checker
11
11
 
12
- # @return [Proc]
12
+ # @return [Proc, NilClass]
13
13
  #
14
14
  # @api private
15
15
  # @since 0.1.0
@@ -30,7 +30,7 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
30
30
  # @api public
31
31
  # @since 0.1.0
32
32
  def define_checker(&checker)
33
- raise 'No checker definition block' unless block_given?
33
+ raise(SmartCore::ArgumentError, 'No checker definition block') unless block_given?
34
34
  @type_checker = checker
35
35
  end
36
36
 
@@ -40,7 +40,7 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
40
40
  # @api public
41
41
  # @since 0.1.0
42
42
  def define_caster(&caster)
43
- raise 'No caster definition block' unless block_given?
43
+ raise(SmartCore::ArgumentError, 'No caster definition block') unless block_given?
44
44
  @type_caster = caster
45
45
  end
46
46
  end
@@ -3,7 +3,7 @@
3
3
  # @api private
4
4
  # @since 0.1.0
5
5
  class SmartCore::Types::Primitive::Factory::DefinitionContext
6
- # @return [Proc]
6
+ # @return [Proc, NilClass]
7
7
  #
8
8
  # @api private
9
9
  # @since 0.1.0
@@ -23,7 +23,7 @@ class SmartCore::Types::Primitive::Factory::DefinitionContext
23
23
  # @api public
24
24
  # @since 0.1.0
25
25
  def define_caster(&caster)
26
- raise 'No caster definition block' unless block_given?
26
+ raise(SmartCore::ArgumentError, 'No caster definition block') unless block_given?
27
27
  @type_caster = caster
28
28
  end
29
29
  end
@@ -3,7 +3,7 @@
3
3
  # @api private
4
4
  # @since 0.1.0
5
5
  class SmartCore::Types::Primitive::SumFactory::DefinitionContext
6
- # @return [Proc]
6
+ # @return [Proc, NilClass]
7
7
  #
8
8
  # @api private
9
9
  # @since 0.1.0
@@ -23,7 +23,7 @@ class SmartCore::Types::Primitive::SumFactory::DefinitionContext
23
23
  # @api public
24
24
  # @since 0.1.0
25
25
  def define_caster(&caster)
26
- raise 'No caster definition block' unless block_given?
26
+ raise(SmartCore::ArgumentError, 'No caster definition block') unless block_given?
27
27
  @type_caster = caster
28
28
  end
29
29
  end
@@ -15,14 +15,13 @@ class SmartCore::Types::Primitive::UndefinedCaster < SmartCore::Types::Primitive
15
15
  # @param value [Any]
16
16
  # @return [void]
17
17
  #
18
- # @raise [SmartCore::Types::TypeCastingError]
18
+ # @raise [SmartCore::Types::TypeCastingUnsupportedError]
19
19
  #
20
20
  # @pai private
21
21
  # @since 0.1.0
22
22
  def call(value)
23
- raise(
24
- SmartCore::Types::TypeCastingError,
23
+ raise(SmartCore::Types::TypeCastingUnsupportedError, <<~ERROR_MESSAGE)
25
24
  'This type has no support for type casting'
26
- )
25
+ ERROR_MESSAGE
27
26
  end
28
27
  end
@@ -1,11 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # @api private
3
+ # @api public
4
4
  # @since 0.1.0
5
5
  module SmartCore::Types::System
6
- require_relative 'system/producer_dsl'
7
- require_relative 'system/definition_dsl'
6
+ class << self
7
+ # @param types [Array<SmartCore::Types::Pirmitive>]
8
+ # @param type_definition [Block]
9
+ # @return [SmartCore::Types::Primitive]
10
+ #
11
+ # @api public
12
+ # @since 0.1.0
13
+ def type_sum(*types, &type_definition)
14
+ SmartCore::Types::Primitive::SumFactory.create_type(types, type_definition)
15
+ end
8
16
 
9
- # @since 0.1.0
10
- include SmartCore::Types::System::DefinitionDSL
17
+ # @param types [Array<SmartCore::Types::Pirmitive>]
18
+ # @param type_definition [Block]
19
+ # @return [SmartCore::Types::Primitive]
20
+ #
21
+ # @api public
22
+ # @since 0.1.0
23
+ def type_mult(*types, &type_definition)
24
+ SmartCore::Types::Primitive::MultFactory.create_type(types, type_definition)
25
+ end
26
+ end
11
27
  end
@@ -17,4 +17,11 @@ class SmartCore::Types::Value < SmartCore::Types::Primitive
17
17
  require_relative 'value/class'
18
18
  require_relative 'value/module'
19
19
  require_relative 'value/any'
20
+ require_relative 'value/time'
21
+ require_relative 'value/date'
22
+ require_relative 'value/date_time'
23
+ require_relative 'value/time_based'
24
+ require_relative 'value/enumerable'
25
+ require_relative 'value/comparable'
26
+ require_relative 'value/big_decimal'
20
27
  end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bigdecimal'
4
+ require 'bigdecimal/util'
5
+
6
+ # @api public
7
+ # @since 0.1.0
8
+ SmartCore::Types::Value.define_type(:BigDecimal) do |type|
9
+ type.define_checker do |value|
10
+ value.is_a?(::BigDecimal)
11
+ end
12
+
13
+ type.define_caster do |value|
14
+ if SmartCore::Types::Value::Float.valid?(value)
15
+ value = SmartCore::Types::Value::String.cast(value)
16
+ end
17
+
18
+ begin
19
+ ::Kernel.BigDecimal(value)
20
+ rescue ::ArgumentError, ::TypeError
21
+ begin
22
+ ::Kernel.BigDecimal(value.to_d)
23
+ rescue ::ArgumentError, ::TypeError, ::NoMethodError
24
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to BigDecimal')
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ SmartCore::Types::Value.define_type(:Comparable) do |type|
6
+ type.define_checker do |value|
7
+ # TODO: realize
8
+ end
9
+
10
+ type.define_caster do |value|
11
+ # TODO: realize
12
+ end
13
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ # @api public
6
+ # @since 0.1.0
7
+ SmartCore::Types::Value.define_type(:Date) do |type|
8
+ type.define_checker do |value|
9
+ value.is_a?(::Date) || value == ::Date::Infinity
10
+ end
11
+
12
+ type.define_caster do |value|
13
+ next value if value.is_a?(::Date) || value == ::Date::Infinity
14
+
15
+ begin
16
+ ::Date.parse(value)
17
+ rescue ::Date::Error, ::TypeError
18
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to Date')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'date'
4
+
5
+ # @api public
6
+ # @since 0.1.0
7
+ SmartCore::Types::Value.define_type(:DateTime) do |type|
8
+ type.define_checker do |value|
9
+ value.is_a?(::DateTime) || value == ::DateTime::Infinity
10
+ end
11
+
12
+ type.define_caster do |value|
13
+ next value if value.is_a?(::DateTime) || value == ::DateTime::Infinity
14
+
15
+ begin
16
+ ::DateTime.parse(value)
17
+ rescue ::Date::Error, ::TypeError
18
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to DateTime')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ SmartCore::Types::Value.define_type(:Enumerable) do |type|
6
+ type.define_checker do |value|
7
+ # TODO: realize
8
+ end
9
+
10
+ type.define_caster do |value|
11
+ # TODO: realize
12
+ end
13
+ end
@@ -9,9 +9,13 @@ SmartCore::Types::Value.define_type(:Float) do |type|
9
9
 
10
10
  type.define_caster do |value|
11
11
  begin
12
- Float(value)
12
+ ::Kernel.Float(value)
13
13
  rescue ::TypeError, ::ArgumentError
14
- value.to_f
14
+ begin
15
+ ::Kernel.Float(value.to_f)
16
+ rescue ::NoMethodError, ::TypeError, ::ArgumentError
17
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to Float')
18
+ end
15
19
  end
16
20
  end
17
21
  end
@@ -11,7 +11,14 @@ SmartCore::Types::Value.define_type(:Hash) do |type|
11
11
  begin
12
12
  ::Kernel.Hash(value)
13
13
  rescue ::TypeError
14
- {}
14
+ begin
15
+ # NOTE:
16
+ # - ::Kernel.Hash does not invoke `#to_h` under the hood (it invokes `#to_hash`)
17
+ # - ::Kernel.Hash is used to validate the returned value from `#to_h`
18
+ ::Kernel.Hash(value.to_h)
19
+ rescue ::TypeError, ::NoMethodError, ::ArgumentError
20
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to Hash')
21
+ end
15
22
  end
16
23
  end
17
24
  end
@@ -9,9 +9,16 @@ SmartCore::Types::Value.define_type(:Integer) do |type|
9
9
 
10
10
  type.define_caster do |value|
11
11
  begin
12
- Integer(value)
13
- rescue ::TypeError, ::ArgumentError
14
- value.to_i
12
+ ::Kernel.Integer(value)
13
+ rescue ::TypeError, ::ArgumentError, ::FloatDomainError
14
+ begin
15
+ # NOTE: for cases like this:
16
+ # => ::Kernel.Integer(nil) # => ::TypeError
17
+ # => ::Kernel.Integer(nil.to_i) # => 0 (::Kernel.Integer used as validation layer)
18
+ ::Kernel.Integer(value.to_i)
19
+ rescue ::TypeError, ::NoMethodError, ::ArgumentError, ::FloatDomainError
20
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to Integer')
21
+ end
15
22
  end
16
23
  end
17
24
  end
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # @api public
4
+ # @since 0.1.0
3
5
  SmartCore::Types::Value.define_type(:Nil) do |type|
4
6
  type.define_checker do |value|
5
7
  # rubocop:disable Style/NilComparison
6
- value == nil # NOTE: #nil? is not used cuz BasicObject has no #nil? method
8
+ value == nil # NOTE: #nil? is not used cuz BasicObject hasn't #nil? method
7
9
  # rubocop:enable Style/NilComparison
8
10
  end
9
11
  end
@@ -8,10 +8,20 @@ SmartCore::Types::Value.define_type(:Numeric) do |type|
8
8
  end
9
9
 
10
10
  type.define_caster do |value|
11
+ next value if value.is_a?(::Numeric)
12
+
11
13
  begin
12
- Float(value)
13
- rescue ::TypeError, ::ArgumentError
14
- value.to_f
14
+ SmartCore::Types::Value::Float.cast(value)
15
+ rescue SmartCore::Types::TypeCastingError
16
+ begin
17
+ SmartCore::Types::Value::Integer.cast(value)
18
+ rescue SmartCore::Types::TypeCastingError
19
+ begin
20
+ SmartCore::Types::Value::BigDecimal.cast(value)
21
+ rescue SmartCore::Types::TypeCastingError
22
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to Numeric')
23
+ end
24
+ end
15
25
  end
16
26
  end
17
27
  end
@@ -7,5 +7,15 @@ SmartCore::Types::Value.define_type(:Proc) do |type|
7
7
  value.is_a?(::Proc)
8
8
  end
9
9
 
10
- type.define_caster(&:to_proc)
10
+ type.define_caster do |value|
11
+ begin
12
+ value.to_proc.tap do |result|
13
+ unless result.is_a?(::Proc)
14
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to Proc')
15
+ end
16
+ end
17
+ rescue ::NoMethodError
18
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to Proc')
19
+ end
20
+ end
11
21
  end
@@ -7,5 +7,11 @@ SmartCore::Types::Value.define_type(:String) do |type|
7
7
  value.is_a?(::String)
8
8
  end
9
9
 
10
- type.define_caster(&:to_s)
10
+ type.define_caster do |value|
11
+ begin
12
+ ::Kernel.String(value)
13
+ rescue ::TypeError, ::ArgumentError
14
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to String')
15
+ end
16
+ end
11
17
  end
@@ -7,5 +7,11 @@ SmartCore::Types::Value.define_type(:Symbol) do |type|
7
7
  value.is_a?(::Symbol)
8
8
  end
9
9
 
10
- type.define_caster(&:to_sym)
10
+ type.define_caster do |value|
11
+ begin
12
+ value.to_sym
13
+ rescue ::NoMethodError, ::ArgumentError
14
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to Symbol')
15
+ end
16
+ end
11
17
  end
@@ -3,5 +3,21 @@
3
3
  # @api public
4
4
  # @since 0.1.0
5
5
  SmartCore::Types::Value::Text = SmartCore::Types::System.type_sum(
6
- SmartCore::Types::Value::String, SmartCore::Types::Value::Symbol
7
- ) { |type| type.define_caster(&:to_s) }
6
+ SmartCore::Types::Value::String,
7
+ SmartCore::Types::Value::Symbol
8
+ ) do |type|
9
+ type.define_caster do |value|
10
+ next value if SmartCore::Types::Value::String.valid?(value)
11
+ next value if SmartCore::Types::Value::Symbol.valid?(value)
12
+
13
+ begin
14
+ SmartCore::Types::Value::String.cast(value)
15
+ rescue SmartCore::Types::TypeCastingError
16
+ begin
17
+ SmartCore::Types::Value::Symbol.cast(value)
18
+ rescue SmartCore::Types::TypeCastingError
19
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to text')
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'time'
4
+
5
+ # @api public
6
+ # @since 0.1.0
7
+ SmartCore::Types::Value.define_type(:Time) do |type|
8
+ type.define_checker do |value|
9
+ value.is_a?(::Time)
10
+ end
11
+
12
+ type.define_caster do |value|
13
+ next value if value.is_a?(::Time)
14
+
15
+ begin
16
+ SmartCore::Types::Value::Integer.valid?(value) ? ::Time.at(value) : ::Time.parse(value)
17
+ rescue ::TypeError, ::ArgumentError
18
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to Time')
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # @api public
4
+ # @since 0.1.0
5
+ SmartCore::Types::Value::TimeBased = SmartCore::Types::System.type_sum(
6
+ SmartCore::Types::Value::Time,
7
+ SmartCore::Types::Value::DateTime,
8
+ SmartCore::Types::Value::Date
9
+ ) do |type|
10
+ type.define_caster do |value|
11
+ next value if SmartCore::Types::Value::Time.valid?(value)
12
+ next value if SmartCore::Types::Value::DateTime.valid?(value)
13
+ next value if SmartCore::Types::Value::Date.valid?(value)
14
+
15
+ begin
16
+ SmartCore::Types::Value::Time.cast(value)
17
+ rescue SmartCore::Types::TypeCastingError
18
+ begin
19
+ SmartCore::Types::Value::DateTime.cast(value)
20
+ rescue SmartCore::Types::TypeCastingError
21
+ begin
22
+ SmartCore::Types::Value::Date.cast(value)
23
+ rescue SmartCore::Types::TypeCastingError
24
+ raise(SmartCore::Types::TypeCastingError, 'Non-castable to time-based type')
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -6,7 +6,6 @@ module SmartCore
6
6
  #
7
7
  # @api public
8
8
  # @since 0.1.0
9
- # @version 0.1.0
10
- VERSION = '0.1.0.alpha6'
9
+ VERSION = '0.1.0'
11
10
  end
12
11
  end
@@ -3,7 +3,7 @@
3
3
  require_relative 'lib/smart_core/types/version'
4
4
 
5
5
  Gem::Specification.new do |spec|
6
- spec.required_ruby_version = Gem::Requirement.new('>= 2.4.9')
6
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.4.10')
7
7
 
8
8
  spec.name = 'smart_types'
9
9
  spec.version = SmartCore::Types::VERSION
@@ -32,11 +32,11 @@ Gem::Specification.new do |spec|
32
32
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
33
33
  spec.require_paths = ['lib']
34
34
 
35
- spec.add_dependency 'smart_engine', '~> 0.5'
35
+ spec.add_dependency 'smart_engine', '~> 0.6'
36
36
 
37
37
  spec.add_development_dependency 'bundler', '~> 2.1'
38
38
  spec.add_development_dependency 'rake', '~> 13.0'
39
39
  spec.add_development_dependency 'rspec', '~> 3.9'
40
- spec.add_development_dependency 'armitage-rubocop', '~> 0.78'
41
- spec.add_development_dependency 'simplecov', '~> 0.17'
40
+ spec.add_development_dependency 'armitage-rubocop', '~> 0.82'
41
+ spec.add_development_dependency 'simplecov', '~> 0.18'
42
42
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: smart_types
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.alpha6
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rustam Ibragimov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-30 00:00:00.000000000 Z
11
+ date: 2020-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: smart_engine
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.5'
19
+ version: '0.6'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.5'
26
+ version: '0.6'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -72,28 +72,28 @@ dependencies:
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '0.78'
75
+ version: '0.82'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '0.78'
82
+ version: '0.82'
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: simplecov
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '0.17'
89
+ version: '0.18'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '0.17'
96
+ version: '0.18'
97
97
  description: |
98
98
  Full-featured type system for any ruby project. Supports custom type definitioning,
99
99
  type validation, type casting and type categorizing. Provides a set of commonly used type
@@ -135,13 +135,16 @@ files:
135
135
  - lib/smart_core/types/primitive/undefined_caster.rb
136
136
  - lib/smart_core/types/struct.rb
137
137
  - lib/smart_core/types/system.rb
138
- - lib/smart_core/types/system/definition_dsl.rb
139
- - lib/smart_core/types/system/producer_dsl.rb
140
138
  - lib/smart_core/types/value.rb
141
139
  - lib/smart_core/types/value/any.rb
142
140
  - lib/smart_core/types/value/array.rb
141
+ - lib/smart_core/types/value/big_decimal.rb
143
142
  - lib/smart_core/types/value/boolean.rb
144
143
  - lib/smart_core/types/value/class.rb
144
+ - lib/smart_core/types/value/comparable.rb
145
+ - lib/smart_core/types/value/date.rb
146
+ - lib/smart_core/types/value/date_time.rb
147
+ - lib/smart_core/types/value/enumerable.rb
145
148
  - lib/smart_core/types/value/float.rb
146
149
  - lib/smart_core/types/value/hash.rb
147
150
  - lib/smart_core/types/value/integer.rb
@@ -152,6 +155,8 @@ files:
152
155
  - lib/smart_core/types/value/string.rb
153
156
  - lib/smart_core/types/value/symbol.rb
154
157
  - lib/smart_core/types/value/text.rb
158
+ - lib/smart_core/types/value/time.rb
159
+ - lib/smart_core/types/value/time_based.rb
155
160
  - lib/smart_core/types/version.rb
156
161
  - smart_types.gemspec
157
162
  homepage: https://github.com/smart-rb/smart_types
@@ -169,12 +174,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
169
174
  requirements:
170
175
  - - ">="
171
176
  - !ruby/object:Gem::Version
172
- version: 2.4.9
177
+ version: 2.4.10
173
178
  required_rubygems_version: !ruby/object:Gem::Requirement
174
179
  requirements:
175
- - - ">"
180
+ - - ">="
176
181
  - !ruby/object:Gem::Version
177
- version: 1.3.1
182
+ version: '0'
178
183
  requirements: []
179
184
  rubygems_version: 3.1.2
180
185
  signing_key:
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- # @since 0.1.0
5
- module SmartCore::Types::System::DefinitionDSL
6
- class << self
7
- # @param base_klass [Class]
8
- # @return [void]
9
- #
10
- # @api private
11
- # @since 0.1.0
12
- def included(base_klass)
13
- base_klass.extend(ClassMethods)
14
- end
15
- end
16
-
17
- # @api private
18
- # @since 0.1.0
19
- module ClassMethods
20
- # @param types [Array<SmartCore::Types::Pirmitive>]
21
- # @param type_definition [Block]
22
- # @return [SmartCore::Types::Primitive]
23
- #
24
- # @api public
25
- # @since 0.1.0
26
- def type_sum(*types, &type_definition)
27
- SmartCore::Types::Primitive::SumFactory.create_type(types, type_definition)
28
- end
29
-
30
- # @param types [Array<SmartCore::Types::Pirmitive>]
31
- # @param type_definition [Block]
32
- # @return [SmartCore::Types::Primitive]
33
- #
34
- # @api public
35
- # @since 0.1.0
36
- def type_mult(*types, &type_definition)
37
- SmartCore::Types::Primitive::MultFactory.create_type(types, type_definition)
38
- end
39
- end
40
- end
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # @api private
4
- # @since 0.1.0
5
- module SmartCore::Types::System::ProducerDSL
6
- class << self
7
- # @param base_klass [Class<SmartCore::Types::Primitive>]
8
- # @return [void]
9
- #
10
- # @api private
11
- # @since 0.1.0
12
- def included(base_klass)
13
- base_klass.extend(ClassMethods)
14
- end
15
- end
16
-
17
- # @api private
18
- # @since 0.1.0
19
- module ClassMethods
20
- # @param type_name [String, Symbol]
21
- # @param type_definition [Block]
22
- # @return [SmartCore::Types::Primitive]
23
- #
24
- # @api public
25
- # @since 0.1.0
26
- def define_type(type_name, &type_definition)
27
- self::Factory.create_type(self, type_name, type_definition)
28
- end
29
- end
30
- end