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