smart_types 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -1
  3. data/CHANGELOG.md +17 -0
  4. data/Gemfile.lock +59 -48
  5. data/README.md +178 -31
  6. data/Rakefile +0 -1
  7. data/bin/console +2 -2
  8. data/lib/smart_core/types/primitive.rb +54 -15
  9. data/lib/smart_core/types/primitive/factory.rb +46 -7
  10. data/lib/smart_core/types/primitive/factory/definition_context.rb +114 -4
  11. data/lib/smart_core/types/primitive/invariant_control.rb +64 -0
  12. data/lib/smart_core/types/primitive/invariant_control/chain.rb +58 -0
  13. data/lib/smart_core/types/primitive/invariant_control/chain/result.rb +64 -0
  14. data/lib/smart_core/types/primitive/invariant_control/factory.rb +54 -0
  15. data/lib/smart_core/types/primitive/invariant_control/factory/chain_definition_context.rb +39 -0
  16. data/lib/smart_core/types/primitive/invariant_control/result.rb +104 -0
  17. data/lib/smart_core/types/primitive/invariant_control/single.rb +54 -0
  18. data/lib/smart_core/types/primitive/invariant_control/single/result.rb +63 -0
  19. data/lib/smart_core/types/primitive/mult_factory.rb +25 -10
  20. data/lib/smart_core/types/primitive/mult_factory/definition_context.rb +4 -2
  21. data/lib/smart_core/types/primitive/mult_validator.rb +34 -0
  22. data/lib/smart_core/types/primitive/mult_validator/result.rb +8 -0
  23. data/lib/smart_core/types/primitive/nilable_factory.rb +24 -9
  24. data/lib/smart_core/types/primitive/nilable_validator.rb +83 -0
  25. data/lib/smart_core/types/primitive/nilable_validator/result.rb +78 -0
  26. data/lib/smart_core/types/primitive/sum_factory.rb +25 -10
  27. data/lib/smart_core/types/primitive/sum_factory/definition_context.rb +3 -1
  28. data/lib/smart_core/types/primitive/sum_validator.rb +101 -0
  29. data/lib/smart_core/types/primitive/sum_validator/result.rb +100 -0
  30. data/lib/smart_core/types/primitive/validator.rb +84 -0
  31. data/lib/smart_core/types/primitive/validator/result.rb +78 -0
  32. data/lib/smart_core/types/value.rb +9 -0
  33. data/lib/smart_core/types/value/enumerator.rb +13 -0
  34. data/lib/smart_core/types/value/enumerator_chain.rb +13 -0
  35. data/lib/smart_core/types/value/io.rb +13 -0
  36. data/lib/smart_core/types/value/method.rb +9 -0
  37. data/lib/smart_core/types/value/nil.rb +0 -2
  38. data/lib/smart_core/types/value/range.rb +9 -0
  39. data/lib/smart_core/types/value/rational.rb +13 -0
  40. data/lib/smart_core/types/value/set.rb +13 -0
  41. data/lib/smart_core/types/value/string_io.rb +13 -0
  42. data/lib/smart_core/types/value/unbound_method.rb +9 -0
  43. data/lib/smart_core/types/version.rb +2 -1
  44. data/smart_types.gemspec +5 -4
  45. metadata +53 -17
  46. data/lib/smart_core/types/primitive/mult_checker.rb +0 -31
  47. data/lib/smart_core/types/primitive/nilable_checker.rb +0 -37
  48. 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: d5f0c7f2b54ceaa7fe20e85d7d280b64b8310eb5f4fa802d11052074e6b10f96
4
+ data.tar.gz: 021c3c6194fb4f54246f4a44a7c548ce9da0790a66b95e0a060547e73efeaf3f
5
5
  SHA512:
6
- metadata.gz: aa5eb3001d7909b30e9fe2df27b92bff6ee22d9e92ef27f37dfbe11c18f968ee932cf0e064ecb2db808d8a0913d3c5fe7650d0d7b15af51bbe4591afeef39670
7
- data.tar.gz: e0fa90c1783113d8d702414596cf001e0e54b786c6d21248e52f5e2401901eddebb09d182349abccda301998782242fa02d4a94e61eb2a3f301fe982a7d5ceff
6
+ metadata.gz: 6e2fc86bcea2292570d2c51e9b95ead6ecc30f8251db75a61fda088c1a84bdb15cea65fdc478728869fb5e5e56b7cddb774938cae38c60e4dee70197e6c1c7f3
7
+ data.tar.gz: c7b27e2f70f3f8eac851f63365b3287a2c7aeb8f7f999679daa715d5ff7de93b32bd6204ea67f6af2c2ea1e5ccd569027051674c9266c62ff7d425c55692619a
@@ -5,7 +5,8 @@ inherit_gem:
5
5
  - lib/rubocop.rspec.yml
6
6
 
7
7
  AllCops:
8
- TargetRubyVersion: 2.7.1
8
+ TargetRubyVersion: 2.7.2
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
@@ -1,2 +1,19 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
+
4
+ ## [0.2.0] - 2020-11-21
5
+ ### Added
6
+ - Brand new **Type invariant API**:
7
+ - globally refactored validation logic (with backward compatability for `#valid?(value)` method);
8
+ - new type definition DSL: `.invariant(name)` and `.invariant_chain(name)`;
9
+ - chained invariants will be invoked according to the definition order (second invokation
10
+ depends on previous successful invariant check);
11
+ - new validation API: `validate(value)` (with `#errors` support based on invariant names);
12
+ - at this moment Invariant API is supported only by primitive types (type sum and type multiplication support coming soon);
13
+
14
+ ### Changed
15
+
16
+ - Updated `smart_engine` dependency (to `~> 0.7`) (need `SmartCore::Engine::Atom`);
17
+
18
+ ## [0.1.0] - 2020-05-05
19
+ - Release :)
@@ -1,91 +1,102 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- smart_types (0.1.0)
5
- smart_engine (~> 0.6)
4
+ smart_types (0.2.0)
5
+ smart_engine (~> 0.7)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activesupport (6.0.2.2)
10
+ activesupport (6.0.3.4)
11
11
  concurrent-ruby (~> 1.0, >= 1.0.2)
12
12
  i18n (>= 0.7, < 2)
13
13
  minitest (~> 5.1)
14
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)
15
+ zeitwerk (~> 2.2, >= 2.2.2)
16
+ armitage-rubocop (1.3.1.1)
17
+ rubocop (= 1.3.1)
18
+ rubocop-performance (= 1.9.0)
19
+ rubocop-rails (= 2.8.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)
21
+ rubocop-rspec (= 2.0.0)
22
+ ast (2.4.1)
23
+ coderay (1.1.3)
24
+ concurrent-ruby (1.1.7)
25
+ diff-lcs (1.4.4)
25
26
  docile (1.3.2)
26
- i18n (1.8.2)
27
+ i18n (1.8.5)
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.2)
31
+ parallel (1.20.0)
32
+ parser (2.7.2.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
39
  rake (13.0.1)
40
+ regexp_parser (1.8.2)
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.0)
47
+ rspec-support (~> 3.10.0)
48
+ rspec-expectations (3.10.0)
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.0)
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.0)
55
+ rubocop (1.3.1)
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)
55
60
  rexml
61
+ rubocop-ast (>= 1.1.1)
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.1.1)
65
+ parser (>= 2.7.1.5)
66
+ rubocop-performance (1.9.0)
67
+ rubocop (>= 0.90.0, < 2.0)
68
+ rubocop-ast (>= 0.4.0)
69
+ rubocop-rails (2.8.1)
70
+ activesupport (>= 4.2.0)
62
71
  rack (>= 1.1)
63
- rubocop (>= 0.72.0)
72
+ rubocop (>= 0.87.0)
64
73
  rubocop-rake (0.5.1)
65
74
  rubocop
66
- rubocop-rspec (1.39.0)
67
- rubocop (>= 0.68.1)
75
+ rubocop-rspec (2.0.0)
76
+ rubocop (~> 1.0)
77
+ rubocop-ast (>= 1.1.0)
68
78
  ruby-progressbar (1.10.1)
69
- simplecov (0.18.5)
79
+ simplecov (0.19.1)
70
80
  docile (~> 1.1)
71
81
  simplecov-html (~> 0.11)
72
- simplecov-html (0.12.2)
73
- smart_engine (0.6.0)
82
+ simplecov-html (0.12.3)
83
+ smart_engine (0.8.0)
74
84
  thread_safe (0.3.6)
75
- tzinfo (1.2.7)
85
+ tzinfo (1.2.8)
76
86
  thread_safe (~> 0.1)
77
87
  unicode-display_width (1.7.0)
78
- zeitwerk (2.3.0)
88
+ zeitwerk (2.4.1)
79
89
 
80
90
  PLATFORMS
81
91
  ruby
82
92
 
83
93
  DEPENDENCIES
84
- armitage-rubocop (~> 0.82)
94
+ armitage-rubocop (~> 1.3)
85
95
  bundler (~> 2.1)
96
+ pry (~> 0.13)
86
97
  rake (~> 13.0)
87
- rspec (~> 3.9)
88
- simplecov (~> 0.18)
98
+ rspec (~> 3.10)
99
+ simplecov (~> 0.19)
89
100
  smart_types!
90
101
 
91
102
  BUNDLED WITH
data/README.md CHANGED
@@ -39,7 +39,7 @@ type4 = type1 & type2
39
39
 
40
40
  ## Supported types
41
41
 
42
- - Primitive Value Types:
42
+ - Primitives
43
43
 
44
44
  ```ruby
45
45
  SmartCore::Types::Value::Any
@@ -67,45 +67,40 @@ SmartCore::Types::Value::TimeBased
67
67
 
68
68
  ## Nilable types
69
69
 
70
+ - invoke `.nilable` on any type object:
71
+
70
72
  ```ruby
71
- SmartCore::Types::Value::Any.nilable
72
- SmartCore::Types::Value::Nil.nilable
73
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
74
+ # -- or --
75
+ SmartCore::Types::Value::Time.nilable
76
+ # and etc.
90
77
  ```
91
78
 
92
79
  ---
93
80
 
94
- ## Type validation and type casting
81
+ ## Custom type definition
95
82
 
96
- ```ruby
97
- # documentation is coming
83
+ Type definition is a composition of:
98
84
 
99
- SmartCore::Types::Value::String.valid?('test') # => true
100
- SmartCore::Types::Value::String.valid?(123.45) # => false
85
+ - type checker (required);
86
+ - type caster (optional);
87
+ - type invariants (optional);
88
+ - type invariant chains (optional);
101
89
 
102
- SmartCore::Types::Value::String.cast(123) # => "123"
103
- SmartCore::Types::Value::Float.cast('55') # => 55.0
104
- ```
90
+ Invariant is a custom validation block that will work as a logical value checker. You can have as much invariants as you want.
105
91
 
106
- ---
92
+ Type invariants does not depends on each other (invariant defined out from chain does not depends on other invariants);
107
93
 
108
- ## Custom type definition
94
+ Invariants inside invariant chains will be invoked in order they was defined and each internal invariant depends on the valid previous invairant check.
95
+
96
+ **!IMPORTANT!** Type sum and type multiplication does not support invariant checking and custom invariant definitioning at this moment.
97
+ Type sum and type mult ignores type invariants in their validation logic (currently this functionality in development yet).
98
+
99
+ Invariant checking is a special validation layer (see [#type validation](#type-validation) readme section). Invariant error code pattern:
100
+ - for invariant chains: `TypeName.invariant_chain_name.invariant_name`;
101
+ - for single invariant: `TypeName.invariant_name`;
102
+
103
+ #### Primitive type definition
109
104
 
110
105
  ```ruby
111
106
  # documentation is coming
@@ -122,12 +117,140 @@ SmartCore::Types::Value.define_type(:String) do |type|
122
117
  end
123
118
  ```
124
119
 
120
+ #### With type invariants
121
+
122
+ ```ruby
123
+ SmartCore::Types::Value.define_type(:String) do |type|
124
+ type.define_checker do |value|
125
+ value.is_a?(::String)
126
+ end
127
+
128
+ type.define_caster do |value|
129
+ value.to_s
130
+ end
131
+
132
+ # NOTE:
133
+ # invariant defined out from chain does not depends on other invariants
134
+ type.invariant(:uncensored_content) do |value|
135
+ !value.include?('uncensored_word')
136
+ end
137
+
138
+ type.invariant(:filled) do |value|
139
+ value != ''
140
+ end
141
+
142
+ type.invariant_chain(:password) do
143
+ invariant(:should_present) { |value| value != '' }
144
+ invariant(:should_have_numbers) { |value| v.match?(/[0-9]+/) }
145
+ # NOTE:
146
+ # inside a chain each next invariant invokation
147
+ # depends on previous successful invariant check
148
+ end
149
+ end
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Type validation
155
+
156
+ Type validation reflects on two APIs:
157
+
158
+ - type checker ([how to define type checkers](#custom-type-definition));
159
+ - type invariants (invariants and invariant chains) ([how to define type invariants](#custom-type-definition));
160
+
161
+ Type invariants does not depends on each other (invariant defined out from the chain does not depends on other invariants);
162
+
163
+ Invariants inside invariant chains will be invoked in order they was defined and each internal invariant depends on the valid previous invairant check.
164
+
165
+ **!IMPORTANT!** Type sum and type multiplication does not support invariant checking and custom invariant definitioning at this moment.
166
+ Type sum and type mult ignores type invariants in their validation logic (currently this functionality in development yet).
167
+
168
+ Invariant checking is a special validation layer (see [#type validation](#type-validation) readme section) and represents a set of error codes in result object;
169
+
170
+ Type valdiation interface:
171
+
172
+ - `valid?(value)` - validates value and returns `true` or `false`;
173
+ - returns `ture` only if the type checker returns `true` and all invariants are valid;
174
+ - `validate(value)` - validates value and returns the monadic result object:
175
+ - `SmartCore::Types::Primitive::Validator::Result` for primitive types;
176
+ - `SmartCore::Types::Primitive::SumValidator::Result` for sum-based types;
177
+ - `SmartCore::Types::Primitive::MultValidator::Result` for mult-based types;
178
+ - `SmartCore::Types::Primitive::NilableValidator::Result` for nilable types;
179
+ - `validate!(value)` - validates value and returns nothing (for successful validation) or
180
+ raises an exception (`SmartCore::Types::TypeError`) (for unsuccessful validation);
181
+
182
+ Validation result object interface:
183
+
184
+ - `#success?` / `#failure?` (`#success?` is a combination of `valid_check? && valid_invariants?`; `#failure?` - is an opposite of `#success?`);
185
+ - `#valid_check?` (valid type checker or not);
186
+ - `#valid_invariants?` (`false` if at least one invariant is invalid);
187
+ - `#errors` (the same as `#invariant_errors` and the same as `#error_codes`) - an array of failed invariant names;
188
+ - error code patterns:
189
+ - for invariant chains: `TypeName.invariant_chain_name.invariant_name`;
190
+ - for single invariant: `TypeName.invariant_name`;
191
+ - `#checked_value` (the same as `#value`) - checked value :)
192
+
193
+
194
+ ```ruby
195
+ SmartCore::Types::Value::String.valid?('test123') # => true
196
+ SmartCore::Types::Value::String.valid?(123.45) # => false
197
+ ```
198
+
199
+ ```ruby
200
+ result = SmartCore::Types::Value::String.validate('test')
201
+
202
+ result.checked_value # => 'test'
203
+ # --- same as: ---
204
+ result.value
205
+
206
+ result.success? # => false (valid_check? && valid_invariants?)
207
+ result.failure? # => true
208
+
209
+ result.valid_check? # => true
210
+ result.valid_invariants? # => false
211
+
212
+ # invariant errors:
213
+ result.errors # => ['String.password.should_have_numbers']
214
+ # -- same as: ---
215
+ result.invariant_errors
216
+ # -- same as: ---
217
+ result.error_codes
218
+ ```
219
+
220
+ ```ruby
221
+ result = SmartCore::Types::Value::String.validate('test1234')
222
+ result.success? # => true
223
+ result.errors # => []
224
+ ```
225
+
226
+ ```ruby
227
+ SmartCore::Types::Value::String.validate!('test') # => SmartCore::Types::TypeError
228
+ ```
229
+
230
+ ---
231
+
232
+ ## Type casting
233
+
234
+ ```
235
+ SmartCore::Types::Value::String.cast(123) # => "123"
236
+ SmartCore::Types::Value::Float.cast('55') # => 55.0
237
+ ```
238
+
125
239
  ---
126
240
 
127
241
  ## Basic type algebra
128
242
 
243
+ > (type sum and type multiplication does not support invariants at this moment (in development yet));
244
+
129
245
  ```ruby
130
246
  # documentation is coming
247
+
248
+ # how to define primitive type sum:
249
+ SmartCore::Types::Value::Text = SmartCore::Types::Value::String | SmartCore::Types::Value::Symbol
250
+ SmartCore::Types::Value::Numeric = SmartCore::Types::Value::Float | SmartCore::Types::Value::Integer
251
+
252
+ # how to define primitive type multiplication:
253
+ SmartCore::Types::Value::CryptoString = SmartCore::Types::Value::NumberdString & SmartCore::Types::Value::SymbolicString
131
254
  ```
132
255
 
133
256
  ---
@@ -195,6 +318,9 @@ end
195
318
  SmartCore::Types::Value::Time.refine_caster do |value, original_caster|
196
319
  # new type caster
197
320
  end
321
+
322
+ # .refine_invariant
323
+ # .refine_invariant_chain
198
324
  ```
199
325
 
200
326
  - options for type casters:
@@ -218,7 +344,16 @@ SmartCore::Types::Value::Method
218
344
  SmartCore::Types::Value::UnboundMethod
219
345
  SmartCore::Types::Value::Enumerable
220
346
  SmartCore::Types::Value::Comparable
347
+ SmartCore::Types::Value::Enumerator
348
+ SmartCore::Types::Value::EnumeratorChain
349
+ SmartCore::Types::Value::Range
350
+ SmartCore::Types::Value::Rational
351
+ SmartCore::Types::Value::Set
352
+ SmartCore::Types::Value::SortedSet
353
+ SmartCore::Types::Value::IO
354
+ SmartCore::Types::Value::StringIO
221
355
  SmartCore::Types::Struct::Schema
356
+ SmartCore::Types::Struct::JSONSchema
222
357
  SmartCore::Types::Struct::StrictArray
223
358
  SmartCore::Types::Struct::StrictHash
224
359
  SmartCore::Types::Struct::Map
@@ -230,11 +365,23 @@ SmartCore::Types::Protocol::Ancestors
230
365
  SmartCore::Types::Protocol::Enumerable
231
366
  SmartCore::Types::Protocol::Comparable
232
367
  SmartCore::Types::Protocol::Forwardable
368
+ SmartCore::Types::Protocol::Callable
233
369
  ```
234
370
 
371
+ - support for type of empty non-defined type (`SmartCore::Types::Primitive::Undefined`);
235
372
  - constrained types;
236
-
237
- - module-based integration;
373
+ - moudle-based type system integration;
374
+ - constructor implementation and support;
375
+ - support for invariant checking (and custom definitioning) in sum-types;
376
+ - to provide a type comparability and compatability between all passed types
377
+ you should provide `type.reconcilable { |value, *types| .... }` setting;
378
+ - `type.reconcilable` should be accesible for type sum and type mult definitions;
379
+ - (**preliminarily**) invariants of the concrete passed type should be valid for sucessful invariant check;
380
+ - support for invariant checking (and definitioning) in mult-types;
381
+ - to provide a type comparability and compatability between all passed types
382
+ you should provide `type.reconcilable { |value, *types| .... }` setting;
383
+ - `type.reconcilable` should be accesible for type sum and type mult definitions;
384
+ - (**preliminarily**) all invariants of all types should be valid for sucessful invariant check;
238
385
 
239
386
  ## Contributing
240
387