sorbet-schema 0.4.0 → 0.4.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +20 -0
- data/Gemfile.lock +17 -17
- data/lib/sorbet-schema/version.rb +1 -1
- data/lib/typed/coercion/boolean_coercer.rb +5 -5
- data/lib/typed/coercion/coercer.rb +2 -2
- data/lib/typed/coercion/coercer_registry.rb +2 -1
- data/lib/typed/coercion/date_coercer.rb +29 -0
- data/lib/typed/coercion/enum_coercer.rb +7 -5
- data/lib/typed/coercion/float_coercer.rb +4 -2
- data/lib/typed/coercion/integer_coercer.rb +5 -3
- data/lib/typed/coercion/string_coercer.rb +5 -3
- data/lib/typed/coercion/struct_coercer.rb +10 -8
- data/lib/typed/coercion/typed_array_coercer.rb +4 -4
- data/lib/typed/coercion.rb +1 -1
- data/lib/typed/field.rb +45 -9
- data/lib/typed/hash_serializer.rb +1 -3
- data/lib/typed/json_serializer.rb +1 -1
- data/lib/typed/schema.rb +14 -0
- data/lib/typed/serializer.rb +7 -0
- data/lib/typed/validations/type_mismatch_error.rb +1 -1
- data/sorbet/rbi/gems/{minitest@5.22.2.rbi → minitest@5.22.3.rbi} +19 -18
- data/sorbet/rbi/gems/{rubocop-ast@1.31.1.rbi → rubocop-ast@1.31.2.rbi} +70 -70
- data/sorbet/rbi/gems/{rubocop@1.61.0.rbi → rubocop@1.62.1.rbi} +276 -233
- data/sorbet/rbi/gems/{standard@1.34.0.rbi → standard@1.35.1.rbi} +56 -56
- metadata +8 -7
- /data/sorbet/rbi/gems/{rubocop-sorbet@0.7.7.rbi → rubocop-sorbet@0.7.8.rbi} +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3fc3ec89812a6517931d09a61a6f4049b85db1661b92e5cb7353c7c62207afab
|
4
|
+
data.tar.gz: 45daa92727807fb2c80bff1fad0b84684c435cde7c1460478741da74fcc0d9c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ad688ac1f0b61c309d9e016baffcab03b61f6c1c0b17b86721580d9f9ed75b86901f9c31a2b3407356f3abaf0ed64c75294d8a6a60a39d11220320c80253308
|
7
|
+
data.tar.gz: d4ec8208184dfe939122d345ec1e1cbb2a8b3f9d840af984e772c6c85d7985fe34f5678ba6b2fa7ef9f85157af90c4e5990f1f2472a025c195255f0d9a5527fe
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,26 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## [0.4.2](https://github.com/maxveldink/sorbet-schema/compare/v0.4.1...v0.4.2) (2024-03-21)
|
8
|
+
|
9
|
+
|
10
|
+
### Features
|
11
|
+
|
12
|
+
* Add Schema#add_serializer to easily update serializer ([f665a2a](https://github.com/maxveldink/sorbet-schema/commit/f665a2ab3afbdaa3757c2d9fa489602edbdf8f8f))
|
13
|
+
|
14
|
+
|
15
|
+
### Bug Fixes
|
16
|
+
|
17
|
+
* Field equality factors in inline serializer ([8049ddf](https://github.com/maxveldink/sorbet-schema/commit/8049ddf2e1a2af45d6591c2689f2fde60afb5839))
|
18
|
+
|
19
|
+
## [0.4.1](https://github.com/maxveldink/sorbet-schema/compare/v0.4.0...v0.4.1) (2024-03-21)
|
20
|
+
|
21
|
+
|
22
|
+
### Features
|
23
|
+
|
24
|
+
* Add DateCoercer ([ef8c1db](https://github.com/maxveldink/sorbet-schema/commit/ef8c1dbdf3bd87ab2e64102fbd1434811aa353d8))
|
25
|
+
* Add inline serializer to fields ([dd8042d](https://github.com/maxveldink/sorbet-schema/commit/dd8042d8d88d67d530c7619ee3cbb108957990d1))
|
26
|
+
|
7
27
|
## [0.4.0](https://github.com/maxveldink/sorbet-schema/compare/v0.3.0...v0.4.0) (2024-03-14)
|
8
28
|
|
9
29
|
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
sorbet-schema (0.4.
|
4
|
+
sorbet-schema (0.4.2)
|
5
5
|
sorbet-result (~> 1.1)
|
6
6
|
sorbet-runtime (~> 0.5)
|
7
7
|
sorbet-struct-comparable (~> 1.3)
|
@@ -18,13 +18,13 @@ GEM
|
|
18
18
|
reline (>= 0.3.8)
|
19
19
|
erubi (1.12.0)
|
20
20
|
io-console (0.7.2)
|
21
|
-
irb (1.
|
21
|
+
irb (1.12.0)
|
22
22
|
rdoc
|
23
23
|
reline (>= 0.4.2)
|
24
24
|
json (2.7.1)
|
25
25
|
language_server-protocol (3.17.0.3)
|
26
26
|
lint_roller (1.1.0)
|
27
|
-
minitest (5.22.
|
27
|
+
minitest (5.22.3)
|
28
28
|
minitest-focus (1.4.0)
|
29
29
|
minitest (>= 4, < 6)
|
30
30
|
minitest-reporters (1.6.1)
|
@@ -53,7 +53,7 @@ GEM
|
|
53
53
|
reline (0.4.3)
|
54
54
|
io-console (~> 0.5)
|
55
55
|
rexml (3.2.6)
|
56
|
-
rubocop (1.
|
56
|
+
rubocop (1.62.1)
|
57
57
|
json (~> 2.3)
|
58
58
|
language_server-protocol (>= 3.17.0)
|
59
59
|
parallel (~> 1.10)
|
@@ -61,27 +61,27 @@ GEM
|
|
61
61
|
rainbow (>= 2.2.2, < 4.0)
|
62
62
|
regexp_parser (>= 1.8, < 3.0)
|
63
63
|
rexml (>= 3.2.5, < 4.0)
|
64
|
-
rubocop-ast (>= 1.
|
64
|
+
rubocop-ast (>= 1.31.1, < 2.0)
|
65
65
|
ruby-progressbar (~> 1.7)
|
66
66
|
unicode-display_width (>= 2.4.0, < 3.0)
|
67
|
-
rubocop-ast (1.31.
|
67
|
+
rubocop-ast (1.31.2)
|
68
68
|
parser (>= 3.3.0.4)
|
69
69
|
rubocop-performance (1.20.2)
|
70
70
|
rubocop (>= 1.48.1, < 2.0)
|
71
71
|
rubocop-ast (>= 1.30.0, < 2.0)
|
72
|
-
rubocop-sorbet (0.7.
|
72
|
+
rubocop-sorbet (0.7.8)
|
73
73
|
rubocop (>= 0.90.0)
|
74
74
|
ruby-progressbar (1.13.0)
|
75
|
-
sorbet (0.5.
|
76
|
-
sorbet-static (= 0.5.
|
75
|
+
sorbet (0.5.11295)
|
76
|
+
sorbet-static (= 0.5.11295)
|
77
77
|
sorbet-result (1.1.0)
|
78
78
|
sorbet-runtime (~> 0.5)
|
79
|
-
sorbet-runtime (0.5.
|
80
|
-
sorbet-static (0.5.
|
81
|
-
sorbet-static (0.5.
|
82
|
-
sorbet-static-and-runtime (0.5.
|
83
|
-
sorbet (= 0.5.
|
84
|
-
sorbet-runtime (= 0.5.
|
79
|
+
sorbet-runtime (0.5.11295)
|
80
|
+
sorbet-static (0.5.11295-universal-darwin)
|
81
|
+
sorbet-static (0.5.11295-x86_64-linux)
|
82
|
+
sorbet-static-and-runtime (0.5.11295)
|
83
|
+
sorbet (= 0.5.11295)
|
84
|
+
sorbet-runtime (= 0.5.11295)
|
85
85
|
sorbet-struct-comparable (1.3.0)
|
86
86
|
sorbet-runtime (>= 0.5)
|
87
87
|
spoom (1.2.4)
|
@@ -89,10 +89,10 @@ GEM
|
|
89
89
|
sorbet-static-and-runtime (>= 0.5.10187)
|
90
90
|
syntax_tree (>= 6.1.1)
|
91
91
|
thor (>= 0.19.2)
|
92
|
-
standard (1.
|
92
|
+
standard (1.35.1)
|
93
93
|
language_server-protocol (~> 3.17.0.2)
|
94
94
|
lint_roller (~> 1.0)
|
95
|
-
rubocop (~> 1.
|
95
|
+
rubocop (~> 1.62.0)
|
96
96
|
standard-custom (~> 1.0.0)
|
97
97
|
standard-performance (~> 1.3)
|
98
98
|
standard-custom (1.0.2)
|
@@ -7,14 +7,16 @@ module Typed
|
|
7
7
|
|
8
8
|
Target = type_member { {fixed: T::Boolean} }
|
9
9
|
|
10
|
-
sig { override.params(type:
|
10
|
+
sig { override.params(type: T::Types::Base).returns(T::Boolean) }
|
11
11
|
def used_for_type?(type)
|
12
12
|
type == T::Utils.coerce(T::Boolean)
|
13
13
|
end
|
14
14
|
|
15
|
-
sig { override.params(type:
|
15
|
+
sig { override.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
|
16
16
|
def coerce(type:, value:)
|
17
|
-
|
17
|
+
return Failure.new(CoercionError.new("Type must be a T::Boolean.")) unless used_for_type?(type)
|
18
|
+
|
19
|
+
if type.recursively_valid?(value)
|
18
20
|
Success.new(value)
|
19
21
|
elsif value == "true"
|
20
22
|
Success.new(true)
|
@@ -23,8 +25,6 @@ module Typed
|
|
23
25
|
else
|
24
26
|
Failure.new(CoercionError.new)
|
25
27
|
end
|
26
|
-
rescue TypeError
|
27
|
-
Failure.new(CoercionError.new("Field type must be a T::Boolean."))
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
@@ -10,11 +10,11 @@ module Typed
|
|
10
10
|
|
11
11
|
Target = type_member(:out)
|
12
12
|
|
13
|
-
sig { abstract.params(type:
|
13
|
+
sig { abstract.params(type: T::Types::Base).returns(T::Boolean) }
|
14
14
|
def used_for_type?(type)
|
15
15
|
end
|
16
16
|
|
17
|
-
sig { abstract.params(type:
|
17
|
+
sig { abstract.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
|
18
18
|
def coerce(type:, value:)
|
19
19
|
end
|
20
20
|
end
|
@@ -17,6 +17,7 @@ module Typed
|
|
17
17
|
BooleanCoercer,
|
18
18
|
IntegerCoercer,
|
19
19
|
FloatCoercer,
|
20
|
+
DateCoercer,
|
20
21
|
EnumCoercer,
|
21
22
|
StructCoercer,
|
22
23
|
TypedArrayCoercer
|
@@ -39,7 +40,7 @@ module Typed
|
|
39
40
|
@available = DEFAULT_COERCERS.clone
|
40
41
|
end
|
41
42
|
|
42
|
-
sig { params(type:
|
43
|
+
sig { params(type: T::Types::Base).returns(T.nilable(T.class_of(Coercer))) }
|
43
44
|
def select_coercer_by(type:)
|
44
45
|
@available.find { |coercer| coercer.new.used_for_type?(type) }
|
45
46
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# typed: strict
|
2
|
+
|
3
|
+
require "date"
|
4
|
+
|
5
|
+
module Typed
|
6
|
+
module Coercion
|
7
|
+
class DateCoercer < Coercer
|
8
|
+
extend T::Generic
|
9
|
+
|
10
|
+
Target = type_member { {fixed: Date} }
|
11
|
+
|
12
|
+
sig { override.params(type: T::Types::Base).returns(T::Boolean) }
|
13
|
+
def used_for_type?(type)
|
14
|
+
T::Utils.coerce(type) == T::Utils.coerce(Date)
|
15
|
+
end
|
16
|
+
|
17
|
+
sig { override.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
|
18
|
+
def coerce(type:, value:)
|
19
|
+
return Failure.new(CoercionError.new("Type must be a Date.")) unless used_for_type?(type)
|
20
|
+
|
21
|
+
return Success.new(value) if value.is_a?(Date)
|
22
|
+
|
23
|
+
Success.new(Date.parse(value))
|
24
|
+
rescue Date::Error, TypeError
|
25
|
+
Failure.new(CoercionError.new("'#{value}' cannot be coerced into Date."))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -7,16 +7,18 @@ module Typed
|
|
7
7
|
|
8
8
|
Target = type_member { {fixed: T::Enum} }
|
9
9
|
|
10
|
-
sig { override.params(type:
|
10
|
+
sig { override.params(type: T::Types::Base).returns(T::Boolean) }
|
11
11
|
def used_for_type?(type)
|
12
|
-
type.
|
12
|
+
return false unless type.respond_to?(:raw_type)
|
13
|
+
|
14
|
+
!!(T.cast(type, T::Types::Simple).raw_type < T::Enum)
|
13
15
|
end
|
14
16
|
|
15
|
-
sig { override.params(type:
|
17
|
+
sig { override.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
|
16
18
|
def coerce(type:, value:)
|
17
|
-
return Failure.new(CoercionError.new("Field type must inherit from T::Enum for Enum coercion.")) unless
|
19
|
+
return Failure.new(CoercionError.new("Field type must inherit from T::Enum for Enum coercion.")) unless used_for_type?(type)
|
18
20
|
|
19
|
-
Success.new(type.from_serialized(value))
|
21
|
+
Success.new(T.cast(type, T::Types::Simple).raw_type.from_serialized(value))
|
20
22
|
rescue KeyError => e
|
21
23
|
Failure.new(CoercionError.new(e.message))
|
22
24
|
end
|
@@ -7,13 +7,15 @@ module Typed
|
|
7
7
|
|
8
8
|
Target = type_member { {fixed: Float} }
|
9
9
|
|
10
|
-
sig { override.params(type:
|
10
|
+
sig { override.params(type: T::Types::Base).returns(T::Boolean) }
|
11
11
|
def used_for_type?(type)
|
12
12
|
T::Utils.coerce(type) == T::Utils.coerce(Float)
|
13
13
|
end
|
14
14
|
|
15
|
-
sig { override.params(type:
|
15
|
+
sig { override.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
|
16
16
|
def coerce(type:, value:)
|
17
|
+
return Failure.new(CoercionError.new("Type must be a Float.")) unless used_for_type?(type)
|
18
|
+
|
17
19
|
Success.new(Float(value))
|
18
20
|
rescue ArgumentError, TypeError
|
19
21
|
Failure.new(CoercionError.new("'#{value}' cannot be coerced into Float."))
|
@@ -7,13 +7,15 @@ module Typed
|
|
7
7
|
|
8
8
|
Target = type_member { {fixed: Integer} }
|
9
9
|
|
10
|
-
sig { override.params(type:
|
10
|
+
sig { override.params(type: T::Types::Base).returns(T::Boolean) }
|
11
11
|
def used_for_type?(type)
|
12
|
-
type == Integer
|
12
|
+
type == T::Utils.coerce(Integer)
|
13
13
|
end
|
14
14
|
|
15
|
-
sig { override.params(type:
|
15
|
+
sig { override.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
|
16
16
|
def coerce(type:, value:)
|
17
|
+
return Failure.new(CoercionError.new("Type must be a Integer.")) unless used_for_type?(type)
|
18
|
+
|
17
19
|
Success.new(Integer(value))
|
18
20
|
rescue ArgumentError, TypeError
|
19
21
|
Failure.new(CoercionError.new("'#{value}' cannot be coerced into Integer."))
|
@@ -7,13 +7,15 @@ module Typed
|
|
7
7
|
|
8
8
|
Target = type_member { {fixed: String} }
|
9
9
|
|
10
|
-
sig { override.params(type:
|
10
|
+
sig { override.params(type: T::Types::Base).returns(T::Boolean) }
|
11
11
|
def used_for_type?(type)
|
12
|
-
type == String
|
12
|
+
type == T::Utils.coerce(String)
|
13
13
|
end
|
14
14
|
|
15
|
-
sig { override.params(type:
|
15
|
+
sig { override.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
|
16
16
|
def coerce(type:, value:)
|
17
|
+
return Failure.new(CoercionError.new("Type must be a String.")) unless used_for_type?(type)
|
18
|
+
|
17
19
|
Success.new(String(value))
|
18
20
|
end
|
19
21
|
end
|
@@ -7,21 +7,23 @@ module Typed
|
|
7
7
|
|
8
8
|
Target = type_member { {fixed: T::Struct} }
|
9
9
|
|
10
|
-
sig { override.params(type:
|
10
|
+
sig { override.params(type: T::Types::Base).returns(T::Boolean) }
|
11
11
|
def used_for_type?(type)
|
12
|
-
type.
|
12
|
+
return false unless type.respond_to?(:raw_type)
|
13
|
+
|
14
|
+
!!(T.cast(type, T::Types::Simple).raw_type < T::Struct)
|
13
15
|
end
|
14
16
|
|
15
|
-
sig { override.params(type:
|
17
|
+
sig { override.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
|
16
18
|
def coerce(type:, value:)
|
17
|
-
return Failure.new(CoercionError.new("Field type must inherit from T::Struct for Struct coercion.")) unless
|
18
|
-
return Success.new(value) if
|
19
|
+
return Failure.new(CoercionError.new("Field type must inherit from T::Struct for Struct coercion.")) unless used_for_type?(type)
|
20
|
+
return Success.new(value) if type.recursively_valid?(value)
|
19
21
|
|
20
22
|
return Failure.new(CoercionError.new("Value of type '#{value.class}' cannot be coerced to #{type} Struct.")) unless value.is_a?(Hash)
|
21
23
|
|
22
|
-
Success.new(type.from_hash!(HashTransformer.new.deep_stringify_keys(value)))
|
23
|
-
rescue ArgumentError
|
24
|
-
Failure.new(CoercionError.new(
|
24
|
+
Success.new(T.cast(type, T::Types::Simple).raw_type.from_hash!(HashTransformer.new.deep_stringify_keys(value)))
|
25
|
+
rescue ArgumentError, RuntimeError
|
26
|
+
Failure.new(CoercionError.new("Given hash could not be coerced to #{type}."))
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
@@ -7,20 +7,20 @@ module Typed
|
|
7
7
|
|
8
8
|
Target = type_member { {fixed: T::Array[T.untyped]} }
|
9
9
|
|
10
|
-
sig { override.params(type:
|
10
|
+
sig { override.params(type: T::Types::Base).returns(T::Boolean) }
|
11
11
|
def used_for_type?(type)
|
12
12
|
type.is_a?(T::Types::TypedArray)
|
13
13
|
end
|
14
14
|
|
15
|
-
sig { override.params(type:
|
15
|
+
sig { override.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
|
16
16
|
def coerce(type:, value:)
|
17
|
-
return Failure.new(CoercionError.new("Field type must be a T::Array.")) unless
|
17
|
+
return Failure.new(CoercionError.new("Field type must be a T::Array.")) unless used_for_type?(type)
|
18
18
|
return Failure.new(CoercionError.new("Value must be an Array.")) unless value.is_a?(Array)
|
19
19
|
|
20
20
|
return Success.new(value) if type.recursively_valid?(value)
|
21
21
|
|
22
22
|
coerced_results = value.map do |item|
|
23
|
-
Coercion.coerce(type: type.type
|
23
|
+
Coercion.coerce(type: T.cast(type, T::Types::TypedArray).type, value: item)
|
24
24
|
end
|
25
25
|
|
26
26
|
if coerced_results.all?(&:success?)
|
data/lib/typed/coercion.rb
CHANGED
@@ -9,7 +9,7 @@ module Typed
|
|
9
9
|
CoercerRegistry.instance.register(coercer)
|
10
10
|
end
|
11
11
|
|
12
|
-
sig { type_parameters(:U).params(type:
|
12
|
+
sig { type_parameters(:U).params(type: T::Types::Base, value: Value).returns(Result[Value, CoercionError]) }
|
13
13
|
def self.coerce(type:, value:)
|
14
14
|
coercer = CoercerRegistry.instance.select_coercer_by(type: type)
|
15
15
|
|
data/lib/typed/field.rb
CHANGED
@@ -1,16 +1,45 @@
|
|
1
1
|
# typed: strict
|
2
2
|
|
3
3
|
module Typed
|
4
|
-
class Field
|
4
|
+
class Field
|
5
5
|
extend T::Sig
|
6
6
|
|
7
|
-
|
7
|
+
InlineSerializer = T.type_alias { T.proc.params(arg0: T.untyped).returns(T.untyped) }
|
8
8
|
|
9
|
-
|
9
|
+
sig { returns(Symbol) }
|
10
|
+
attr_reader :name
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
12
|
+
sig { returns(T::Types::Base) }
|
13
|
+
attr_reader :type
|
14
|
+
|
15
|
+
sig { returns(T::Boolean) }
|
16
|
+
attr_reader :required
|
17
|
+
|
18
|
+
sig { returns(T.nilable(InlineSerializer)) }
|
19
|
+
attr_reader :inline_serializer
|
20
|
+
|
21
|
+
sig do
|
22
|
+
params(
|
23
|
+
name: Symbol,
|
24
|
+
type: T.any(T::Class[T.anything], T::Types::Base),
|
25
|
+
required: T::Boolean,
|
26
|
+
inline_serializer: T.nilable(InlineSerializer)
|
27
|
+
).void
|
28
|
+
end
|
29
|
+
def initialize(name:, type:, required: true, inline_serializer: nil)
|
30
|
+
@name = name
|
31
|
+
@type = T.let(T::Utils.coerce(type), T::Types::Base)
|
32
|
+
@required = required
|
33
|
+
@inline_serializer = inline_serializer
|
34
|
+
end
|
35
|
+
|
36
|
+
sig { params(other: Field).returns(T.nilable(T::Boolean)) }
|
37
|
+
def ==(other)
|
38
|
+
name == other.name &&
|
39
|
+
type == other.type &&
|
40
|
+
required == other.required &&
|
41
|
+
inline_serializer == other.inline_serializer
|
42
|
+
end
|
14
43
|
|
15
44
|
sig { returns(T::Boolean) }
|
16
45
|
def required?
|
@@ -22,6 +51,15 @@ module Typed
|
|
22
51
|
!required
|
23
52
|
end
|
24
53
|
|
54
|
+
sig { params(value: Value).returns(Value) }
|
55
|
+
def serialize(value)
|
56
|
+
if inline_serializer && value
|
57
|
+
T.must(inline_serializer).call(value)
|
58
|
+
else
|
59
|
+
value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
25
63
|
sig { params(value: Value).returns(Validations::ValidationResult) }
|
26
64
|
def validate(value)
|
27
65
|
Validations::FieldTypeValidator.new.validate(field: self, value: value)
|
@@ -29,9 +67,7 @@ module Typed
|
|
29
67
|
|
30
68
|
sig { params(value: Value).returns(T::Boolean) }
|
31
69
|
def works_with?(value)
|
32
|
-
|
33
|
-
rescue TypeError
|
34
|
-
false
|
70
|
+
type.recursively_valid?(value)
|
35
71
|
end
|
36
72
|
end
|
37
73
|
end
|
@@ -22,9 +22,7 @@ module Typed
|
|
22
22
|
def serialize(struct)
|
23
23
|
return Failure.new(SerializeError.new("'#{struct.class}' cannot be serialized to target type of '#{schema.target}'.")) if struct.class != schema.target
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
Success.new(HashTransformer.new(should_serialize_values: should_serialize_values).deep_symbolize_keys(hsh.compact))
|
25
|
+
Success.new(serialize_from_struct(struct: struct, should_serialize_values: should_serialize_values))
|
28
26
|
end
|
29
27
|
|
30
28
|
private
|
@@ -24,7 +24,7 @@ module Typed
|
|
24
24
|
def serialize(struct)
|
25
25
|
return Failure.new(SerializeError.new("'#{struct.class}' cannot be serialized to target type of '#{schema.target}'.")) if struct.class != schema.target
|
26
26
|
|
27
|
-
Success.new(JSON.generate(struct
|
27
|
+
Success.new(JSON.generate(serialize_from_struct(struct: struct, should_serialize_values: true)))
|
28
28
|
end
|
29
29
|
end
|
30
30
|
end
|
data/lib/typed/schema.rb
CHANGED
@@ -27,5 +27,19 @@ module Typed
|
|
27
27
|
def from_json(json)
|
28
28
|
Typed::JSONSerializer.new(schema: self).deserialize(json)
|
29
29
|
end
|
30
|
+
|
31
|
+
sig { params(field_name: Symbol, serializer: Field::InlineSerializer).returns(Schema) }
|
32
|
+
def add_serializer(field_name, serializer)
|
33
|
+
self.class.new(
|
34
|
+
target: target,
|
35
|
+
fields: fields.map do |field|
|
36
|
+
if field.name == field_name
|
37
|
+
Field.new(name: field.name, type: field.type, required: field.required, inline_serializer: serializer)
|
38
|
+
else
|
39
|
+
field
|
40
|
+
end
|
41
|
+
end
|
42
|
+
)
|
43
|
+
end
|
30
44
|
end
|
31
45
|
end
|
data/lib/typed/serializer.rb
CHANGED
@@ -55,5 +55,12 @@ module Typed
|
|
55
55
|
Success.new(schema.target.new(**validated_params))
|
56
56
|
end
|
57
57
|
end
|
58
|
+
|
59
|
+
sig { params(struct: T::Struct, should_serialize_values: T::Boolean).returns(T::Hash[Symbol, T.untyped]) }
|
60
|
+
def serialize_from_struct(struct:, should_serialize_values: false)
|
61
|
+
hsh = schema.fields.each_with_object({}) { |field, hsh| hsh[field.name] = field.serialize(struct.send(field.name)) }.compact
|
62
|
+
|
63
|
+
HashTransformer.new(should_serialize_values: should_serialize_values).deep_symbolize_keys(hsh)
|
64
|
+
end
|
58
65
|
end
|
59
66
|
end
|
@@ -5,7 +5,7 @@ module Typed
|
|
5
5
|
class TypeMismatchError < ValidationError
|
6
6
|
extend T::Sig
|
7
7
|
|
8
|
-
sig { params(field_name: Symbol, field_type:
|
8
|
+
sig { params(field_name: Symbol, field_type: T::Types::Base, given_type: T::Class[T.anything]).void }
|
9
9
|
def initialize(field_name:, field_type:, given_type:)
|
10
10
|
super("Invalid type given to #{field_name}. Expected #{field_type}, got #{given_type}.")
|
11
11
|
end
|
@@ -1988,27 +1988,27 @@ class Minitest::Test < ::Minitest::Runnable
|
|
1988
1988
|
|
1989
1989
|
# LifecycleHooks
|
1990
1990
|
#
|
1991
|
-
# source://minitest//lib/minitest/test.rb#
|
1991
|
+
# source://minitest//lib/minitest/test.rb#191
|
1992
1992
|
def capture_exceptions; end
|
1993
1993
|
|
1994
1994
|
# source://minitest//lib/minitest/test.rb#15
|
1995
1995
|
def class_name; end
|
1996
1996
|
|
1997
|
-
# source://minitest//lib/minitest/test.rb#
|
1997
|
+
# source://minitest//lib/minitest/test.rb#208
|
1998
1998
|
def neuter_exception(e); end
|
1999
1999
|
|
2000
|
-
# source://minitest//lib/minitest/test.rb#
|
2000
|
+
# source://minitest//lib/minitest/test.rb#219
|
2001
2001
|
def new_exception(klass, msg, bt, kill = T.unsafe(nil)); end
|
2002
2002
|
|
2003
2003
|
# Runs a single test with setup/teardown hooks.
|
2004
2004
|
#
|
2005
|
-
# source://minitest//lib/minitest/test.rb#
|
2005
|
+
# source://minitest//lib/minitest/test.rb#87
|
2006
2006
|
def run; end
|
2007
2007
|
|
2008
|
-
# source://minitest//lib/minitest/test.rb#
|
2008
|
+
# source://minitest//lib/minitest/test.rb#201
|
2009
2009
|
def sanitize_exception(e); end
|
2010
2010
|
|
2011
|
-
# source://minitest//lib/minitest/test.rb#
|
2011
|
+
# source://minitest//lib/minitest/test.rb#233
|
2012
2012
|
def with_info_handler(&block); end
|
2013
2013
|
|
2014
2014
|
class << self
|
@@ -2048,18 +2048,19 @@ class Minitest::Test < ::Minitest::Runnable
|
|
2048
2048
|
# source://minitest//lib/minitest/test.rb#48
|
2049
2049
|
def make_my_diffs_pretty!; end
|
2050
2050
|
|
2051
|
-
# Call this at the top of your tests
|
2052
|
-
#
|
2053
|
-
#
|
2051
|
+
# Call this at the top of your tests (inside the +Minitest::Test+
|
2052
|
+
# subclass or +describe+ block) when you want to run your tests in
|
2053
|
+
# parallel. In doing so, you're admitting that you rule and your
|
2054
|
+
# tests are awesome.
|
2054
2055
|
#
|
2055
|
-
# source://minitest//lib/minitest/test.rb#
|
2056
|
+
# source://minitest//lib/minitest/test.rb#60
|
2056
2057
|
def parallelize_me!; end
|
2057
2058
|
|
2058
2059
|
# Returns all instance methods starting with "test_". Based on
|
2059
2060
|
# #test_order, the methods are either sorted, randomized
|
2060
2061
|
# (default), or run in parallel.
|
2061
2062
|
#
|
2062
|
-
# source://minitest//lib/minitest/test.rb#
|
2063
|
+
# source://minitest//lib/minitest/test.rb#70
|
2063
2064
|
def runnable_methods; end
|
2064
2065
|
|
2065
2066
|
# source://minitest-focus/1.4.0/lib/minitest/focus.rb#52
|
@@ -2071,7 +2072,7 @@ end
|
|
2071
2072
|
# meant for library writers, NOT for regular test authors. See
|
2072
2073
|
# #before_setup for an example.
|
2073
2074
|
#
|
2074
|
-
# source://minitest//lib/minitest/test.rb#
|
2075
|
+
# source://minitest//lib/minitest/test.rb#114
|
2075
2076
|
module Minitest::Test::LifecycleHooks
|
2076
2077
|
# Runs before every test, after setup. This hook is meant for
|
2077
2078
|
# libraries to extend minitest. It is not meant to be used by
|
@@ -2079,7 +2080,7 @@ module Minitest::Test::LifecycleHooks
|
|
2079
2080
|
#
|
2080
2081
|
# See #before_setup for an example.
|
2081
2082
|
#
|
2082
|
-
# source://minitest//lib/minitest/test.rb#
|
2083
|
+
# source://minitest//lib/minitest/test.rb#164
|
2083
2084
|
def after_setup; end
|
2084
2085
|
|
2085
2086
|
# Runs after every test, after teardown. This hook is meant for
|
@@ -2088,7 +2089,7 @@ module Minitest::Test::LifecycleHooks
|
|
2088
2089
|
#
|
2089
2090
|
# See #before_setup for an example.
|
2090
2091
|
#
|
2091
|
-
# source://minitest//lib/minitest/test.rb#
|
2092
|
+
# source://minitest//lib/minitest/test.rb#188
|
2092
2093
|
def after_teardown; end
|
2093
2094
|
|
2094
2095
|
# Runs before every test, before setup. This hook is meant for
|
@@ -2123,7 +2124,7 @@ module Minitest::Test::LifecycleHooks
|
|
2123
2124
|
# include MyMinitestPlugin
|
2124
2125
|
# end
|
2125
2126
|
#
|
2126
|
-
# source://minitest//lib/minitest/test.rb#
|
2127
|
+
# source://minitest//lib/minitest/test.rb#149
|
2127
2128
|
def before_setup; end
|
2128
2129
|
|
2129
2130
|
# Runs after every test, before teardown. This hook is meant for
|
@@ -2132,19 +2133,19 @@ module Minitest::Test::LifecycleHooks
|
|
2132
2133
|
#
|
2133
2134
|
# See #before_setup for an example.
|
2134
2135
|
#
|
2135
|
-
# source://minitest//lib/minitest/test.rb#
|
2136
|
+
# source://minitest//lib/minitest/test.rb#173
|
2136
2137
|
def before_teardown; end
|
2137
2138
|
|
2138
2139
|
# Runs before every test. Use this to set up before each test
|
2139
2140
|
# run.
|
2140
2141
|
#
|
2141
|
-
# source://minitest//lib/minitest/test.rb#
|
2142
|
+
# source://minitest//lib/minitest/test.rb#155
|
2142
2143
|
def setup; end
|
2143
2144
|
|
2144
2145
|
# Runs after every test. Use this to clean up after each test
|
2145
2146
|
# run.
|
2146
2147
|
#
|
2147
|
-
# source://minitest//lib/minitest/test.rb#
|
2148
|
+
# source://minitest//lib/minitest/test.rb#179
|
2148
2149
|
def teardown; end
|
2149
2150
|
end
|
2150
2151
|
|