smart_types 0.1.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -1
  3. data/CHANGELOG.md +57 -0
  4. data/Gemfile.lock +71 -58
  5. data/LICENSE.txt +1 -1
  6. data/README.md +363 -34
  7. data/Rakefile +0 -1
  8. data/bin/console +2 -2
  9. data/lib/smart_core/types/errors.rb +12 -0
  10. data/lib/smart_core/types/primitive/caster.rb +5 -2
  11. data/lib/smart_core/types/primitive/checker.rb +5 -2
  12. data/lib/smart_core/types/primitive/factory/definition_context.rb +140 -4
  13. data/lib/smart_core/types/primitive/factory/runtime_type_builder.rb +53 -0
  14. data/lib/smart_core/types/primitive/factory.rb +104 -7
  15. data/lib/smart_core/types/primitive/invariant_control/chain/result.rb +64 -0
  16. data/lib/smart_core/types/primitive/invariant_control/chain.rb +61 -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/factory.rb +54 -0
  19. data/lib/smart_core/types/primitive/invariant_control/result.rb +104 -0
  20. data/lib/smart_core/types/primitive/invariant_control/single/result.rb +63 -0
  21. data/lib/smart_core/types/primitive/invariant_control/single.rb +57 -0
  22. data/lib/smart_core/types/primitive/invariant_control.rb +67 -0
  23. data/lib/smart_core/types/primitive/mult_factory/definition_context.rb +26 -2
  24. data/lib/smart_core/types/primitive/mult_factory.rb +59 -10
  25. data/lib/smart_core/types/primitive/mult_validator/result.rb +8 -0
  26. data/lib/smart_core/types/primitive/mult_validator.rb +42 -0
  27. data/lib/smart_core/types/primitive/nilable_factory.rb +31 -9
  28. data/lib/smart_core/types/primitive/nilable_validator/result.rb +78 -0
  29. data/lib/smart_core/types/primitive/nilable_validator.rb +83 -0
  30. data/lib/smart_core/types/primitive/runtime_attributes_checker.rb +77 -0
  31. data/lib/smart_core/types/primitive/sum_factory/definition_context.rb +25 -1
  32. data/lib/smart_core/types/primitive/sum_factory.rb +59 -10
  33. data/lib/smart_core/types/primitive/sum_validator/result.rb +100 -0
  34. data/lib/smart_core/types/primitive/sum_validator.rb +117 -0
  35. data/lib/smart_core/types/primitive/undefined_caster.rb +4 -1
  36. data/lib/smart_core/types/primitive/validator/result.rb +78 -0
  37. data/lib/smart_core/types/primitive/validator.rb +93 -0
  38. data/lib/smart_core/types/primitive.rb +99 -15
  39. data/lib/smart_core/types/protocol/instance_of.rb +19 -0
  40. data/lib/smart_core/types/protocol.rb +7 -0
  41. data/lib/smart_core/types/value/array.rb +3 -0
  42. data/lib/smart_core/types/value/big_decimal.rb +4 -1
  43. data/lib/smart_core/types/value/boolean.rb +3 -0
  44. data/lib/smart_core/types/value/class.rb +3 -0
  45. data/lib/smart_core/types/value/date.rb +3 -0
  46. data/lib/smart_core/types/value/date_time.rb +3 -0
  47. data/lib/smart_core/types/value/enumerable.rb +1 -1
  48. data/lib/smart_core/types/value/enumerator.rb +13 -0
  49. data/lib/smart_core/types/value/enumerator_chain.rb +13 -0
  50. data/lib/smart_core/types/value/float.rb +3 -0
  51. data/lib/smart_core/types/value/hash.rb +3 -0
  52. data/lib/smart_core/types/value/integer.rb +3 -0
  53. data/lib/smart_core/types/value/io.rb +13 -0
  54. data/lib/smart_core/types/value/method.rb +9 -0
  55. data/lib/smart_core/types/value/module.rb +3 -0
  56. data/lib/smart_core/types/value/nil.rb +0 -2
  57. data/lib/smart_core/types/value/numeric.rb +3 -0
  58. data/lib/smart_core/types/value/proc.rb +3 -0
  59. data/lib/smart_core/types/value/range.rb +9 -0
  60. data/lib/smart_core/types/value/rational.rb +13 -0
  61. data/lib/smart_core/types/value/set.rb +21 -0
  62. data/lib/smart_core/types/value/string.rb +3 -0
  63. data/lib/smart_core/types/value/string_io.rb +15 -0
  64. data/lib/smart_core/types/value/symbol.rb +3 -0
  65. data/lib/smart_core/types/value/text.rb +6 -4
  66. data/lib/smart_core/types/value/time.rb +3 -0
  67. data/lib/smart_core/types/value/time_based.rb +8 -5
  68. data/lib/smart_core/types/value/unbound_method.rb +9 -0
  69. data/lib/smart_core/types/value.rb +9 -0
  70. data/lib/smart_core/types/variadic/array_of.rb +23 -0
  71. data/lib/smart_core/types/variadic/enum.rb +11 -0
  72. data/lib/smart_core/types/variadic/tuple.rb +23 -0
  73. data/lib/smart_core/types/variadic.rb +10 -0
  74. data/lib/smart_core/types/version.rb +2 -1
  75. data/lib/smart_core/types.rb +2 -0
  76. data/smart_types.gemspec +5 -4
  77. metadata +61 -18
  78. data/.travis.yml +0 -21
  79. data/lib/smart_core/types/primitive/mult_checker.rb +0 -31
  80. data/lib/smart_core/types/primitive/nilable_checker.rb +0 -37
  81. data/lib/smart_core/types/primitive/sum_checker.rb +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12c87a28e4cb88c84907c5d811253c4cb70e3e4aad462010c47c1a6d88c21d81
4
- data.tar.gz: af0155909d10f02369aa5b60c97de4b0b91fbfad92ba79d1f94b5b3333ede373
3
+ metadata.gz: 7d46db58ce368955b324f4acb5fbfa74100789abe263c8e83fa8a73c482b6dd4
4
+ data.tar.gz: f5377e4cc8693855b885d197f1d5b8429ba78efc30b781703a2ba95230d58d2b
5
5
  SHA512:
6
- metadata.gz: aa5eb3001d7909b30e9fe2df27b92bff6ee22d9e92ef27f37dfbe11c18f968ee932cf0e064ecb2db808d8a0913d3c5fe7650d0d7b15af51bbe4591afeef39670
7
- data.tar.gz: e0fa90c1783113d8d702414596cf001e0e54b786c6d21248e52f5e2401901eddebb09d182349abccda301998782242fa02d4a94e61eb2a3f301fe982a7d5ceff
6
+ metadata.gz: 294f3ef4a287aef01cbf48c6250ece9190effee142b42596a453657f7ed541080d964c4d22e56113c8a7fc80298f2dfd5fefe92159a8499829b34d5a993b0ddb
7
+ data.tar.gz: a515dad1255bf4b3e757d12011f8c4eedde8a79fd265e5acba10e5a19282c40f3f61d85aa094cb962c1029329b06cd225a828aa9bd23bfaec6e575b89bd945a0
data/.rubocop.yml CHANGED
@@ -5,7 +5,8 @@ inherit_gem:
5
5
  - lib/rubocop.rspec.yml
6
6
 
7
7
  AllCops:
8
- TargetRubyVersion: 2.7.1
8
+ TargetRubyVersion: 3.0.0
9
+ NewCops: enable
9
10
  Include:
10
11
  - lib/**/*.rb
11
12
  - spec/**/*.rb
@@ -17,3 +18,7 @@ AllCops:
17
18
  # NOTE: support for old ruby versions
18
19
  Style/RedundantBegin:
19
20
  Enabled: false
21
+
22
+ # NOTE: used only in specs and it is ok in specs
23
+ Lint/EmptyBlock:
24
+ Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,2 +1,59 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
+
4
+ # [0.6.0] - 2021-04-29
5
+ ### Added
6
+ - New type of `SmartCode::Types::Variadic` category:
7
+ - `SmartCore::Types::Variadic::ArrayOf` (`Array` with element types validation)
8
+
9
+
10
+ # [0.5.0] - 2021-01-28
11
+ ### Added
12
+ - New types of `SmartCore::Types::Variadic` category:
13
+ - `SmartCore::Types::Variadic::Enum` (a simple enumeration on plain values);
14
+
15
+ # [0.4.0] - 2021-01-18
16
+ ### Added
17
+ - Support for *Ruby 3*;
18
+
19
+ ## [0.3.0] - 2020-12-22
20
+ ### Added
21
+ - Extended **Type Definition API**: support for **runtime attributes**:
22
+ - Type checkers, type casters and type invariants now receives runtime attributes (you can omit these);
23
+ - Type definitioning extended with `runtime_attribute_checker`-checker definition (runtime attributes validator);
24
+ - Types with incorrect runtime attributes will raise `SmartCore::Types::IncorrectRuntimeAttributesError` exception;
25
+ - Types which has no support for runtime attributes will raise `SmartCore::Types::RuntimeAttributesUnsupportedError` excpetion;
26
+ - All types by default has a method alias (`()`) which does not allow runtime attributes (for example: `SmartCore::Types::Value::String` has
27
+ a runtime-based alias `SmartCore::Types::Value::String()` which does not accept any attribute
28
+ (`SmartCore::Types::Value::String('test')` will raise `SmartCore::Types::RuntimeAttributesUnsupportedError` respectively));
29
+ - Extended Internal **Type Development API**:
30
+ - all types has a reference to it's type category;
31
+ - Brand new `SmartCore::Types::Protocol` type category and new types:
32
+ - `SmartCore::Types::Protocol::InstanceOf` (runtime-based type);
33
+ - Brand new `SmartCore::Types::Variadic` type category and new types:
34
+ - `SmartCore::Types::Variadic::Tuple` (runtime-based type);
35
+ - New types of `SmartCore::Types::Value` category:
36
+ - `SmartCore::Types::Value::Set` (based on `Set` type with a support for type casting);
37
+ - Support for BasicObject values inside type checkers that can not be checked correctly via `#is_a?/#kind_of?` before;
38
+
39
+ ### Changed
40
+ - Updated development dependencies;
41
+ - Drop `Travis CI` (TODO: migrate to `Github Actions`);
42
+ - **Ruby@2.4** is no longer supported;
43
+
44
+ ## [0.2.0] - 2020-11-21
45
+ ### Added
46
+ - Brand new **Type invariant API**:
47
+ - globally refactored validation logic (with backward compatability for `#valid?(value)` method);
48
+ - new type definition DSL: `.invariant(name)` and `.invariant_chain(name)`;
49
+ - chained invariants will be invoked according to the definition order (second invokation
50
+ depends on previous successful invariant check);
51
+ - new validation API: `validate(value)` (with `#errors` support based on invariant names);
52
+ - at this moment Invariant API is supported only by primitive types (type sum and type multiplication support coming soon);
53
+
54
+ ### Changed
55
+
56
+ - Updated `smart_engine` dependency (to `~> 0.7`) (need `SmartCore::Engine::Atom`);
57
+
58
+ ## [0.1.0] - 2020-05-05
59
+ - Release :)
data/Gemfile.lock CHANGED
@@ -1,92 +1,105 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_types (0.1.0)
5
- smart_engine (~> 0.6)
4
+ smart_types (0.6.0)
5
+ smart_engine (~> 0.11)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (6.0.2.2)
10
+ activesupport (6.1.1)
11
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)
18
- rubocop-performance (= 1.5.2)
19
- rubocop-rails (= 2.5.2)
12
+ i18n (>= 1.6, < 2)
13
+ minitest (>= 5.1)
14
+ tzinfo (~> 2.0)
15
+ zeitwerk (~> 2.3)
16
+ armitage-rubocop (1.7.0.1)
17
+ rubocop (= 1.7.0)
18
+ rubocop-performance (= 1.9.1)
19
+ rubocop-rails (= 2.9.1)
20
20
  rubocop-rake (= 0.5.1)
21
- rubocop-rspec (= 1.39.0)
22
- ast (2.4.0)
23
- concurrent-ruby (1.1.6)
24
- diff-lcs (1.3)
25
- docile (1.3.2)
26
- i18n (1.8.2)
21
+ rubocop-rspec (= 2.1.0)
22
+ ast (2.4.1)
23
+ coderay (1.1.3)
24
+ concurrent-ruby (1.1.7)
25
+ diff-lcs (1.4.4)
26
+ docile (1.3.5)
27
+ i18n (1.8.7)
27
28
  concurrent-ruby (~> 1.0)
28
- jaro_winkler (1.5.4)
29
- minitest (5.14.0)
30
- parallel (1.19.1)
31
- parser (2.7.1.2)
32
- ast (~> 2.4.0)
33
- rack (2.2.2)
29
+ method_source (1.0.0)
30
+ minitest (5.14.3)
31
+ parallel (1.20.1)
32
+ parser (3.0.0.0)
33
+ ast (~> 2.4.1)
34
+ pry (0.13.1)
35
+ coderay (~> 1.1)
36
+ method_source (~> 1.0)
37
+ rack (2.2.3)
34
38
  rainbow (3.0.0)
35
- rake (13.0.1)
39
+ rake (13.0.3)
40
+ regexp_parser (2.0.3)
36
41
  rexml (3.2.4)
37
- rspec (3.9.0)
38
- rspec-core (~> 3.9.0)
39
- rspec-expectations (~> 3.9.0)
40
- rspec-mocks (~> 3.9.0)
41
- rspec-core (3.9.2)
42
- rspec-support (~> 3.9.3)
43
- rspec-expectations (3.9.1)
42
+ rspec (3.10.0)
43
+ rspec-core (~> 3.10.0)
44
+ rspec-expectations (~> 3.10.0)
45
+ rspec-mocks (~> 3.10.0)
46
+ rspec-core (3.10.1)
47
+ rspec-support (~> 3.10.0)
48
+ rspec-expectations (3.10.1)
44
49
  diff-lcs (>= 1.2.0, < 2.0)
45
- rspec-support (~> 3.9.0)
46
- rspec-mocks (3.9.1)
50
+ rspec-support (~> 3.10.0)
51
+ rspec-mocks (3.10.1)
47
52
  diff-lcs (>= 1.2.0, < 2.0)
48
- rspec-support (~> 3.9.0)
49
- rspec-support (3.9.3)
50
- rubocop (0.82.0)
51
- jaro_winkler (~> 1.5.1)
53
+ rspec-support (~> 3.10.0)
54
+ rspec-support (3.10.1)
55
+ rubocop (1.7.0)
52
56
  parallel (~> 1.10)
53
- parser (>= 2.7.0.1)
57
+ parser (>= 2.7.1.5)
54
58
  rainbow (>= 2.2.2, < 4.0)
59
+ regexp_parser (>= 1.8, < 3.0)
55
60
  rexml
61
+ rubocop-ast (>= 1.2.0, < 2.0)
56
62
  ruby-progressbar (~> 1.7)
57
63
  unicode-display_width (>= 1.4.0, < 2.0)
58
- rubocop-performance (1.5.2)
59
- rubocop (>= 0.71.0)
60
- rubocop-rails (2.5.2)
61
- activesupport
64
+ rubocop-ast (1.4.0)
65
+ parser (>= 2.7.1.5)
66
+ rubocop-performance (1.9.1)
67
+ rubocop (>= 0.90.0, < 2.0)
68
+ rubocop-ast (>= 0.4.0)
69
+ rubocop-rails (2.9.1)
70
+ activesupport (>= 4.2.0)
62
71
  rack (>= 1.1)
63
- rubocop (>= 0.72.0)
72
+ rubocop (>= 0.90.0, < 2.0)
64
73
  rubocop-rake (0.5.1)
65
74
  rubocop
66
- rubocop-rspec (1.39.0)
67
- rubocop (>= 0.68.1)
68
- ruby-progressbar (1.10.1)
69
- simplecov (0.18.5)
75
+ rubocop-rspec (2.1.0)
76
+ rubocop (~> 1.0)
77
+ rubocop-ast (>= 1.1.0)
78
+ ruby-progressbar (1.11.0)
79
+ simplecov (0.21.2)
70
80
  docile (~> 1.1)
71
81
  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)
82
+ simplecov_json_formatter (~> 0.1)
83
+ simplecov-html (0.12.3)
84
+ simplecov_json_formatter (0.1.2)
85
+ smart_engine (0.11.0)
86
+ tzinfo (2.0.4)
87
+ concurrent-ruby (~> 1.0)
77
88
  unicode-display_width (1.7.0)
78
- zeitwerk (2.3.0)
89
+ zeitwerk (2.4.2)
79
90
 
80
91
  PLATFORMS
81
- ruby
92
+ x86_64-darwin-19
93
+ x86_64-darwin-20
82
94
 
83
95
  DEPENDENCIES
84
- armitage-rubocop (~> 0.82)
96
+ armitage-rubocop (~> 1.7)
85
97
  bundler (~> 2.1)
98
+ pry (~> 0.13)
86
99
  rake (~> 13.0)
87
- rspec (~> 3.9)
88
- simplecov (~> 0.18)
100
+ rspec (~> 3.10)
101
+ simplecov (~> 0.21)
89
102
  smart_types!
90
103
 
91
104
  BUNDLED WITH
92
- 2.1.4
105
+ 2.2.3
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2020 Rustam Ibragimov
3
+ Copyright (c) 2020-2021 Rustam Ibragimov
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # SmartCore::Types &middot; [![Gem Version](https://badge.fury.io/rb/smart_types.svg)](https://badge.fury.io/rb/smart_types) [![Build Status](https://travis-ci.org/smart-rb/smart_types.svg?branch=master)](https://travis-ci.org/smart-rb/smart_types)
1
+ # SmartCore::Types &middot; [![Supporting](https://github.com/Cado-Labs/cado-labs-logos/blob/main/cado_labs_badge.png)](https://github.com/Cado-Labs/) &middot; [![Gem Version](https://badge.fury.io/rb/smart_types.svg)](https://badge.fury.io/rb/smart_types)
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
 
@@ -6,6 +6,16 @@ Minimalistic type system for any ruby project. Supports custom type definitionin
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
+ ---
10
+
11
+ <p>
12
+ <a href="https://github.com/Cado-Labs">
13
+ <img src="https://github.com/Cado-Labs/cado-labs-logos/blob/main/cado_labs_supporting.svg" alt="Supported by Cado Labs" />
14
+ </a>
15
+ </p>
16
+
17
+ ---
18
+
9
19
  ## Installation
10
20
 
11
21
  ```ruby
@@ -24,7 +34,28 @@ require 'smart_core/types'
24
34
 
25
35
  ---
26
36
 
27
- ## Type Interface
37
+ ## Usage
38
+
39
+ - [Type interface and basic type algebra](#type-interface-and-basic-type-algebra)
40
+ - [Supported types](#supported-types)
41
+ - [Primitives](#primitives) (`SmartCore::Types::Value`)
42
+ - [Protocols](#protocols) (`SmartCore::Types::Protocol`)
43
+ - [Variadic](#variadic) (`SmartCore::Types::Variadic`)
44
+ - [Nilable types](#nilable-types)
45
+ - [Custom type definition](#custom-type-definition)
46
+ - [Primitive type definition](#primitive-type-definition)
47
+ - [With type invariants](#with-type-invariants)
48
+ - [Type validation](#type-validation)
49
+ - [Type casting](#type-casting)
50
+ - [Roadmap](#roadmap)
51
+ - [Contributing](#contributing)
52
+ - [Build](#build)
53
+ - [License](#license)
54
+ - [Authors](#authors)
55
+
56
+ ---
57
+
58
+ ## Type Interface and basic type algebra
28
59
 
29
60
  ```ruby
30
61
  # documentation is coming
@@ -37,9 +68,24 @@ type3 = type1 | type2
37
68
  type4 = type1 & type2
38
69
  ```
39
70
 
71
+ Types with runtime:
72
+
73
+ ```ruby
74
+ # get a type object with a custom runtime (instances of String or Symbol):
75
+ type = SmartCore::Types::Protocol::InstanceOf(::String, ::Symbol)
76
+ type.valid?(:test) # => true
77
+ type.valid?('test') # => true
78
+ type.valid?(123.456) # => false
79
+
80
+ # another type object with a custom runtime (tuple (String, Integer, Time)):
81
+ type = SmartCore::Types::Variadic::Tuple(::String, ::Integer, ::DateTime)
82
+ type.valid?(['test', 1, DateTime.new]) # => true
83
+ type.valid?([:test, 2]) # => false
84
+ ```
85
+
40
86
  ## Supported types
41
87
 
42
- - Primitive Value Types:
88
+ #### Primitives:
43
89
 
44
90
  ```ruby
45
91
  SmartCore::Types::Value::Any
@@ -53,6 +99,7 @@ SmartCore::Types::Value::Numeric
53
99
  SmartCore::Types::Value::BigDecimal
54
100
  SmartCore::Types::Value::Boolean
55
101
  SmartCore::Types::Value::Array
102
+ SmartCore::Types::Value::Set
56
103
  SmartCore::Types::Value::Hash
57
104
  SmartCore::Types::Value::Proc
58
105
  SmartCore::Types::Value::Class
@@ -65,52 +112,188 @@ SmartCore::Types::Value::TimeBased
65
112
 
66
113
  ---
67
114
 
68
- ## Nilable types
115
+ #### Protocols:
69
116
 
70
117
  ```ruby
71
- SmartCore::Types::Value::Any.nilable
72
- SmartCore::Types::Value::Nil.nilable
73
- SmartCore::Types::Value::String.nilable
74
- SmartCore::Types::Value::Symbol.nilable
75
- SmartCore::Types::Value::Text.nilable
76
- SmartCore::Types::Value::Integer.nilable
77
- SmartCore::Types::Value::Float.nilable
78
- SmartCore::Types::Value::Numeric.nilable
79
- SmartCore::Types::Value::BigDecimal.nilable
80
- SmartCore::Types::Value::Boolean.nilable
81
- SmartCore::Types::Value::Array.nilable
82
- SmartCore::Types::Value::Hash.nilable
83
- SmartCore::Types::Value::Proc.nilable
84
- SmartCore::Types::Value::Class.nilable
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
118
+ SmartCore::Types::Protocol::InstanceOf
119
+ ```
120
+
121
+ ```ruby
122
+ # examples (SmartCore::Types::Protocol::InstanceOf):
123
+ SmartCore::Types::Protocol::InstanceOf(::Integer) # only integer
124
+ SmartCore::Types::Protocol::InstanceOf(::String, ::Symbol) # string or symbol
125
+ SmartCore::Types::Protocol::InstanceOf(::Time, ::DateTime, ::Date) # time or datetime or date
90
126
  ```
91
127
 
92
128
  ---
93
129
 
94
- ## Type validation and type casting
130
+ #### Variadic:
95
131
 
96
132
  ```ruby
97
- # documentation is coming
133
+ SmartCore::Types::Variadic::ArrayOf
134
+ SmartCore::Types::Variadic::Enum
135
+ SmartCore::Types::Variadic::Tuple
136
+ ```
98
137
 
99
- SmartCore::Types::Value::String.valid?('test') # => true
100
- SmartCore::Types::Value::String.valid?(123.45) # => false
138
+ ```ruby
139
+ # example (SmartCore::Types::Variadic::ArrayOf):
140
+ SmartCore::Types::Variadic::ArrayOf(::String, ::Array) # array of strings or arrays
101
141
 
102
- SmartCore::Types::Value::String.cast(123) # => "123"
103
- SmartCore::Types::Value::Float.cast('55') # => 55.0
142
+ # example (SmartCore::Types::Variadic::Enum):
143
+ SmartCore::Types::Variadic::Enum('string', 1337, :symbol) # one of enumerated values
144
+
145
+ # examples (SmartCore::Types::Variadic::Tuple):
146
+ SmartCore::Types::Variadic::Tuple(::String, ::Integer, ::Time) # array with signature [<string>, <integer>, <time>]
147
+ SmartCore::Types::Variadic::Tuple(::Symbol, ::Float) # array with signature [<symbol>, <float>]
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Nilable types
153
+
154
+ - invoke `.nilable` on any type object:
155
+
156
+ ```ruby
157
+ SmartCore::Types::Value::String.nilable
158
+ # -- or --
159
+ SmartCore::Types::Value::Time.nilable
160
+ # and etc.
104
161
  ```
105
162
 
106
163
  ---
107
164
 
108
165
  ## Custom type definition
109
166
 
167
+ Type definition is a composition of:
168
+
169
+ - type checker (required);
170
+ - type caster (optional);
171
+ - type invariants (optional);
172
+ - type invariant chains (optional);
173
+
174
+ Invariant is a custom validation block that will work as a logical value checker. You can have as much invariants as you want.
175
+
176
+ Type invariants does not depends on each other (invariant defined out from chain does not depends on other invariants);
177
+
178
+ Invariants inside invariant chains will be invoked in order they was defined and each internal invariant depends on the valid previous invairant check.
179
+
180
+ **!IMPORTANT!** Type sum and type multiplication does not support invariant checking and custom invariant definitioning at this moment.
181
+ Type sum and type mult ignores type invariants in their validation logic (currently this functionality in development yet).
182
+
183
+ Invariant checking is a special validation layer (see [#type validation](#type-validation) readme section). Invariant error code pattern:
184
+ - for invariant chains: `TypeName.invariant_chain_name.invariant_name`;
185
+ - for single invariant: `TypeName.invariant_name`;
186
+
187
+ #### Primitive type definition
188
+
110
189
  ```ruby
111
190
  # documentation is coming
112
191
 
113
192
  # example:
193
+ SmartCore::Types::Value.define_type(:String) do |type|
194
+ type.define_checker do |value, runtime_attrs| # runtime attributes are optional
195
+ value.is_a?(::String)
196
+ end
197
+
198
+ type.define_caster do |value, runtime_attrs| # runtime attributes are optional
199
+ value.to_s
200
+ end
201
+ end
202
+
203
+ # get a type object:
204
+ SmartCore::Types::Value::String
205
+ # --- or ---
206
+ SmartCore::Types::Value::String() # without runtime attributes
207
+ # --- or ---
208
+ SmartCore::Types::Value::String('some_attr', :another_attr) # with runtime attributes
209
+
210
+ # work with type object: see documentation below
211
+ ```
212
+
213
+ #### With type invariants
214
+
215
+ ```ruby
216
+ SmartCore::Types::Value.define_type(:String) do |type|
217
+ type.define_checker do |value, runtime_attrs|
218
+ value.is_a?(::String)
219
+ end
220
+
221
+ type.define_caster do |value, runtime_attrs|
222
+ value.to_s
223
+ end
224
+
225
+ # NOTE:
226
+ # invariant defined out from chain does not depends on other invariants
227
+ type.invariant(:uncensored_content) do |value, runtime_attrs|
228
+ !value.include?('uncensored_word')
229
+ end
230
+
231
+ type.invariant(:filled) do |value, runtime_attrs|
232
+ value != ''
233
+ end
234
+
235
+ type.invariant_chain(:password) do
236
+ invariant(:should_present) do |value, runtime_attrs|
237
+ value != ''
238
+ end
239
+
240
+ invariant(:should_have_numbers) do |value, runtime_attrs|
241
+ v.match?(/[0-9]+/)
242
+ end
243
+
244
+ # NOTE:
245
+ # inside a chain each next invariant invokation
246
+ # depends on previous successful invariant check
247
+ end
248
+ end
249
+ ```
250
+
251
+ ---
252
+
253
+ ## Type validation
254
+
255
+ Type validation reflects on two APIs:
256
+
257
+ - type checker ([how to define type checkers](#custom-type-definition));
258
+ - type invariants (invariants and invariant chains) ([how to define type invariants](#custom-type-definition));
259
+
260
+ Type invariants does not depends on each other (invariant defined out from the chain does not depends on other invariants);
261
+
262
+ Invariants inside invariant chains will be invoked in order they was defined and each internal invariant depends on the valid previous invairant check.
263
+
264
+ **!IMPORTANT!** Type sum and type multiplication does not support invariant checking and custom invariant definitioning at this moment.
265
+ Type sum and type mult ignores type invariants in their validation logic (currently this functionality in development yet).
266
+
267
+ Invariant checking is a special validation layer (see [#type validation](#type-validation) readme section) and represents a set of error codes in result object;
268
+
269
+ Type valdiation interface:
270
+
271
+ - `valid?(value)` - validates value and returns `true` or `false`;
272
+ - returns `ture` only if the type checker returns `true` and all invariants are valid;
273
+ - `validate(value)` - validates value and returns the monadic result object:
274
+ - `SmartCore::Types::Primitive::Validator::Result` for primitive types;
275
+ - `SmartCore::Types::Primitive::SumValidator::Result` for sum-based types;
276
+ - `SmartCore::Types::Primitive::MultValidator::Result` for mult-based types;
277
+ - `SmartCore::Types::Primitive::NilableValidator::Result` for nilable types;
278
+ - `validate!(value)` - validates value and returns nothing (for successful validation) or
279
+ raises an exception (`SmartCore::Types::TypeError`) (for unsuccessful validation);
280
+
281
+ Validation result object interface:
282
+
283
+ - `#success?` / `#failure?` (`#success?` is a combination of `valid_check? && valid_invariants?`; `#failure?` - is an opposite of `#success?`);
284
+ - `#valid_check?` (valid type checker or not);
285
+ - `#valid_invariants?` (`false` if at least one invariant is invalid);
286
+ - `#errors` (the same as `#invariant_errors` and the same as `#error_codes`) - an array of failed invariant names;
287
+ - error code patterns:
288
+ - for invariant chains: `TypeName.invariant_chain_name.invariant_name`;
289
+ - for single invariant: `TypeName.invariant_name`;
290
+ - `#checked_value` (the same as `#value`) - checked value :)
291
+
292
+ ---
293
+
294
+ Imagine that we have `String` type like this:
295
+
296
+ ```ruby
114
297
  SmartCore::Types::Value.define_type(:String) do |type|
115
298
  type.define_checker do |value|
116
299
  value.is_a?(::String)
@@ -119,21 +302,94 @@ SmartCore::Types::Value.define_type(:String) do |type|
119
302
  type.define_caster do |value|
120
303
  value.to_s
121
304
  end
305
+
306
+ type.invariant(:uncensored_content) do |value|
307
+ !value.include?('uncensored_word')
308
+ end
309
+
310
+ type.invariant(:filled) do |value|
311
+ value != ''
312
+ end
313
+
314
+ type.invariant_chain(:password) do
315
+ invariant(:should_present) { |value| value != '' }
316
+ invariant(:should_have_numbers) { |value| v.match?(/[0-9]+/) }
317
+ end
122
318
  end
123
319
  ```
124
320
 
321
+ Validation interface and usage:
322
+
323
+ ```ruby
324
+ SmartCore::Types::Value::String.valid?('test123') # => true
325
+ SmartCore::Types::Value::String.valid?(123.45) # => false
326
+ ```
327
+
328
+ ```ruby
329
+ result = SmartCore::Types::Value::String.validate('test')
330
+
331
+ result.checked_value # => 'test'
332
+ # --- same as: ---
333
+ result.value
334
+
335
+ result.success? # => false (valid_check? && valid_invariants?)
336
+ result.failure? # => true
337
+
338
+ result.valid_check? # => true
339
+ result.valid_invariants? # => false
340
+
341
+ # invariant errors:
342
+ result.errors # => ['String.password.should_have_numbers']
343
+ # -- same as: ---
344
+ result.invariant_errors
345
+ # -- same as: ---
346
+ result.error_codes
347
+ ```
348
+
349
+ ```ruby
350
+ result = SmartCore::Types::Value::String.validate('test1234')
351
+ result.success? # => true
352
+ result.errors # => []
353
+ ```
354
+
355
+ ```ruby
356
+ SmartCore::Types::Value::String.validate!('test') # => SmartCore::Types::TypeError
357
+ ```
358
+
359
+ ---
360
+
361
+ ## Type casting
362
+
363
+ ```ruby
364
+ SmartCore::Types::Value::String.cast(123) # => "123"
365
+ SmartCore::Types::Value::Float.cast('55') # => 55.0
366
+ ```
367
+
125
368
  ---
126
369
 
127
370
  ## Basic type algebra
128
371
 
372
+ > (type sum and type multiplication does not support invariants at this moment (in development yet));
373
+
129
374
  ```ruby
130
375
  # documentation is coming
376
+
377
+ # how to define primitive type sum:
378
+ SmartCore::Types::Value::Text = SmartCore::Types::Value::String | SmartCore::Types::Value::Symbol
379
+ SmartCore::Types::Value::Numeric = SmartCore::Types::Value::Float | SmartCore::Types::Value::Integer
380
+
381
+ # how to define primitive type multiplication:
382
+ SmartCore::Types::Value::CryptoString = SmartCore::Types::Value::NumberdString & SmartCore::Types::Value::SymbolicString
131
383
  ```
132
384
 
133
385
  ---
134
386
 
135
387
  ## Roadmap
136
388
 
389
+ - migrate to `Github Actions`;
390
+
391
+ - support for `block`-attribute in runtime attributes;
392
+
137
393
  - type configuration:
138
394
 
139
395
  ```ruby
@@ -195,6 +451,18 @@ end
195
451
  SmartCore::Types::Value::Time.refine_caster do |value, original_caster|
196
452
  # new type caster
197
453
  end
454
+
455
+ SmartCore::Types::Value::Time.refine_runtime_attributes_checker do |value, original_checker|
456
+ # new runtime attribute checker
457
+ end
458
+
459
+ SmartCore::Types::Value::Time.refine_invariant(:name) do |value|
460
+ # new invariant
461
+ end
462
+
463
+ SmartCore::Types::Value::Time.refine_invariant_chain(:chain_name) do
464
+ # new invariant chain
465
+ end
198
466
  ```
199
467
 
200
468
  - options for type casters:
@@ -218,23 +486,52 @@ SmartCore::Types::Value::Method
218
486
  SmartCore::Types::Value::UnboundMethod
219
487
  SmartCore::Types::Value::Enumerable
220
488
  SmartCore::Types::Value::Comparable
489
+ SmartCore::Types::Value::Enumerator
490
+ SmartCore::Types::Value::EnumeratorChain
491
+ SmartCore::Types::Value::Range
492
+ SmartCore::Types::Value::Rational
493
+ SmartCore::Types::Value::SortedSet
494
+ SmartCore::Types::Value::IO
495
+ SmartCore::Types::Value::StringIO
496
+ SmartCore::Types::Value::BasicObject
221
497
  SmartCore::Types::Struct::Schema
498
+ SmartCore::Types::Struct::JSONSchema
222
499
  SmartCore::Types::Struct::StrictArray
223
500
  SmartCore::Types::Struct::StrictHash
224
501
  SmartCore::Types::Struct::Map
225
- SmartCore::Types::Variative::Enum
226
- SmartCore::Types::Variative::Variant
227
- SmartCore::Types::Protocol::InstanceOf
228
502
  SmartCore::Types::Protocol::Interface
229
503
  SmartCore::Types::Protocol::Ancestors
230
504
  SmartCore::Types::Protocol::Enumerable
231
505
  SmartCore::Types::Protocol::Comparable
232
506
  SmartCore::Types::Protocol::Forwardable
507
+ SmartCore::Types::Protocol::Callable
233
508
  ```
234
509
 
235
- - constrained types;
510
+ - `#sum` alias for `|` and `#mult` alias for `&` (with a support for type name definition and other API);
236
511
 
237
- - module-based integration;
512
+ - type category in invariant error codes:
513
+ ```ruby
514
+ # before:
515
+ 'String.password.should_contain_numbers' # `String` type from `Value` category
516
+
517
+ # after:
518
+ 'Value.String.password.should_contain_numbers' # `Value::String`
519
+ ```
520
+
521
+ - support for type of empty non-defined type (`SmartCore::Types::Primitive::Undefined`);
522
+ - constrained types;
523
+ - moudle-based type system integration;
524
+ - constructor implementation and support;
525
+ - support for invariant checking (and custom definitioning) in sum-types;
526
+ - to provide a type comparability and compatability between all passed types
527
+ you should provide `type.reconcilable { |value, *types| .... }` setting;
528
+ - `type.reconcilable` should be accesible for type sum and type mult definitions;
529
+ - (**preliminarily**) invariants of the concrete passed type should be valid for sucessful invariant check;
530
+ - support for invariant checking (and definitioning) in mult-types;
531
+ - to provide a type comparability and compatability between all passed types
532
+ you should provide `type.reconcilable { |value, *types| .... }` setting;
533
+ - `type.reconcilable` should be accesible for type sum and type mult definitions;
534
+ - (**preliminarily**) all invariants of all types should be valid for sucessful invariant check;
238
535
 
239
536
  ## Contributing
240
537
 
@@ -244,10 +541,42 @@ SmartCore::Types::Protocol::Forwardable
244
541
  - Push to the branch (`git push origin feature/my-new-feature`)
245
542
  - Create new Pull Request
246
543
 
544
+ ## Build
545
+
546
+ - run tests:
547
+
548
+ ```shell
549
+ bundle exec rake rspec
550
+ # --- or ---
551
+ bundle exec rspec
552
+ ```
553
+
554
+ - run code stye linting:
555
+
556
+ ```shell
557
+ bundle exec rake rubocop
558
+ # --- or ---
559
+ bundle exec rubocop
560
+ ```
561
+
562
+ - run code style linting with auto-correction:
563
+
564
+ ```shell
565
+ bundle exec rake rubcoop -A
566
+ # --- or ---
567
+ bundle exec rubocop -A
568
+ ```
569
+
247
570
  ## License
248
571
 
249
572
  Released under MIT License.
250
573
 
574
+ ## Supporting
575
+
576
+ <a href="https://github.com/Cado-Labs">
577
+ <img src="https://github.com/Cado-Labs/cado-labs-logos/blob/main/cado_labs_logo.png" alt="Supported by Cado Labs" />
578
+ </a>
579
+
251
580
  ## Authors
252
581
 
253
582
  [Rustam Ibragimov](https://github.com/0exp)