json_model_rb 0.1.12 → 0.1.14
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/lib/json_model/properties.rb +8 -0
- data/lib/json_model/schema.rb +1 -1
- data/lib/json_model/type_spec/composition/all_of.rb +1 -1
- data/lib/json_model/type_spec/composition/any_of.rb +1 -1
- data/lib/json_model/type_spec/composition/one_of.rb +1 -1
- data/lib/json_model/type_spec/composition.rb +45 -4
- data/lib/json_model/type_spec/const.rb +4 -2
- data/lib/json_model/type_spec/enum.rb +4 -2
- data/lib/json_model/type_spec/object.rb +5 -3
- data/lib/json_model/version.rb +1 -1
- data/spec/examples/file_system_spec.rb +14 -9
- data/spec/schema_spec.rb +20 -7
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 55a34992353fa6800b488fba56a9516d78c0b1c256c987ea7f22cb61782477dc
|
|
4
|
+
data.tar.gz: c3d0b4289612c86e3e7ba805b26209534099503947df12885591decb2942a647
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 128cceae1c36a9b9f130013417d2e0131a8b3b673b6cedde600297bb1d1d327fa7cfb91ebecf974af72f05e6efe96849ee2477f3e734b2b5e90ee6b0f2655c09
|
|
7
|
+
data.tar.gz: bb21f9d7ff5ccedcd7448f148d69ce78502b7f7200d0e6cb90edf5b54d77afae0284a3729c9d4dcba9fbac82253b3a95d957bd1aef56bc8a641453f0971a5283
|
data/README.md
CHANGED
|
@@ -623,7 +623,7 @@ class PaymentMethod
|
|
|
623
623
|
title "Payment Method"
|
|
624
624
|
description "Must specify exactly one payment method"
|
|
625
625
|
|
|
626
|
-
property :payment, type: T::OneOf[CreditCardPayment, PayPalPayment, BankTransferPayment]
|
|
626
|
+
property :payment, type: T::OneOf[CreditCardPayment, PayPalPayment, BankTransferPayment], discriminator: :payment_type
|
|
627
627
|
end
|
|
628
628
|
|
|
629
629
|
# Generate the JSON Schema
|
|
@@ -25,6 +25,14 @@ module JsonModel
|
|
|
25
25
|
@aliased_properties ||= {}
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
# @param [Symbol] name
|
|
29
|
+
# @return [Symbol, nil]
|
|
30
|
+
def invert_alias(name)
|
|
31
|
+
aliased_properties[name]&.name || superclass&.invert_alias(name)
|
|
32
|
+
rescue NoMethodError
|
|
33
|
+
nil
|
|
34
|
+
end
|
|
35
|
+
|
|
28
36
|
# @param [Symbol] name
|
|
29
37
|
# @param [Object, Class] type
|
|
30
38
|
# @param [Hash] options
|
data/lib/json_model/schema.rb
CHANGED
|
@@ -38,7 +38,7 @@ module JsonModel
|
|
|
38
38
|
# @param [::Object] json
|
|
39
39
|
# @return [::Object, nil]
|
|
40
40
|
def from_json(json)
|
|
41
|
-
attributes = json.transform_keys { |key|
|
|
41
|
+
attributes = json.transform_keys { |key| invert_alias(key) || raise_unknown_attribute_error(key) }
|
|
42
42
|
new(attributes)
|
|
43
43
|
end
|
|
44
44
|
|
|
@@ -3,25 +3,28 @@
|
|
|
3
3
|
module JsonModel
|
|
4
4
|
class TypeSpec
|
|
5
5
|
class Composition < TypeSpec
|
|
6
|
+
attr_reader(:types, :modifier, :discriminator)
|
|
7
|
+
|
|
6
8
|
# @param [Symbol] modifier
|
|
7
|
-
# @param [TypeSpec] types
|
|
8
|
-
def initialize(modifier, *types)
|
|
9
|
+
# @param [::Array<TypeSpec>] types
|
|
10
|
+
def initialize(modifier, *types, discriminator: nil)
|
|
9
11
|
super()
|
|
10
12
|
@types = types
|
|
11
13
|
@modifier = modifier
|
|
14
|
+
@discriminator = discriminator
|
|
12
15
|
end
|
|
13
16
|
|
|
14
17
|
# @param [Hash] options
|
|
15
18
|
# @return [Hash]
|
|
16
19
|
def as_schema(**options)
|
|
17
20
|
{
|
|
18
|
-
|
|
21
|
+
modifier => types.map { |type| type.as_schema(**options) },
|
|
19
22
|
}
|
|
20
23
|
end
|
|
21
24
|
|
|
22
25
|
# @return [Array<TypeSpec>]
|
|
23
26
|
def referenced_schemas
|
|
24
|
-
|
|
27
|
+
types.flat_map(&:referenced_schemas)
|
|
25
28
|
end
|
|
26
29
|
|
|
27
30
|
# @param [::Object] json
|
|
@@ -29,6 +32,44 @@ module JsonModel
|
|
|
29
32
|
def cast(json)
|
|
30
33
|
raise(NotImplementedError)
|
|
31
34
|
end
|
|
35
|
+
|
|
36
|
+
protected
|
|
37
|
+
|
|
38
|
+
# @return [Hash, nil]
|
|
39
|
+
def type_map
|
|
40
|
+
if discriminator.nil?
|
|
41
|
+
return nil
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
@type_map ||= types.each_with_object({}) do |type, hash|
|
|
45
|
+
if !type.is_a?(Object)
|
|
46
|
+
raise('Discriminator property can only be used with Object types')
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
discriminator_property = type.type.properties[discriminator]
|
|
50
|
+
discriminator_values = if discriminator_property&.type.is_a?(Const)
|
|
51
|
+
[discriminator_property.type.value]
|
|
52
|
+
elsif discriminator_property&.type.is_a?(Enum)
|
|
53
|
+
discriminator_property.type.values
|
|
54
|
+
else
|
|
55
|
+
raise('Discriminator property must be of type Const or Enum')
|
|
56
|
+
end
|
|
57
|
+
discriminator_values.each do |value|
|
|
58
|
+
hash[value] ||= []
|
|
59
|
+
hash[value] << type
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @param [::Object] json
|
|
65
|
+
# @return [::Array<TypeSpec>]
|
|
66
|
+
def types_for(json)
|
|
67
|
+
if type_map.nil?
|
|
68
|
+
types
|
|
69
|
+
else
|
|
70
|
+
type_map[json[discriminator]]
|
|
71
|
+
end
|
|
72
|
+
end
|
|
32
73
|
end
|
|
33
74
|
end
|
|
34
75
|
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module JsonModel
|
|
4
4
|
class TypeSpec
|
|
5
5
|
class Const < TypeSpec
|
|
6
|
+
attr_reader(:value)
|
|
7
|
+
|
|
6
8
|
# @param [String] value
|
|
7
9
|
def initialize(value)
|
|
8
10
|
super()
|
|
@@ -17,7 +19,7 @@ module JsonModel
|
|
|
17
19
|
# @return [Hash]
|
|
18
20
|
def as_schema(**_options)
|
|
19
21
|
{
|
|
20
|
-
const:
|
|
22
|
+
const: value,
|
|
21
23
|
}.compact
|
|
22
24
|
end
|
|
23
25
|
|
|
@@ -26,7 +28,7 @@ module JsonModel
|
|
|
26
28
|
def register_validations(name, klass)
|
|
27
29
|
super
|
|
28
30
|
|
|
29
|
-
klass.validates(name, inclusion: { in:
|
|
31
|
+
klass.validates(name, inclusion: { in: value }, allow_nil: true)
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module JsonModel
|
|
4
4
|
class TypeSpec
|
|
5
5
|
class Enum < TypeSpec
|
|
6
|
+
attr_reader(:values)
|
|
7
|
+
|
|
6
8
|
# @param [Array<Object, nil>] values
|
|
7
9
|
def initialize(*values)
|
|
8
10
|
super()
|
|
@@ -17,7 +19,7 @@ module JsonModel
|
|
|
17
19
|
# @return [Hash]
|
|
18
20
|
def as_schema(**_options)
|
|
19
21
|
{
|
|
20
|
-
enum:
|
|
22
|
+
enum: values,
|
|
21
23
|
}.compact
|
|
22
24
|
end
|
|
23
25
|
|
|
@@ -26,7 +28,7 @@ module JsonModel
|
|
|
26
28
|
def register_validations(name, klass)
|
|
27
29
|
super
|
|
28
30
|
|
|
29
|
-
klass.validates(name, inclusion: { in:
|
|
31
|
+
klass.validates(name, inclusion: { in: values }, allow_nil: true)
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
end
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
module JsonModel
|
|
4
4
|
class TypeSpec
|
|
5
5
|
class Object < TypeSpec
|
|
6
|
+
attr_reader(:type)
|
|
7
|
+
|
|
6
8
|
# @param [Schema] type
|
|
7
9
|
def initialize(type)
|
|
8
10
|
super()
|
|
@@ -12,18 +14,18 @@ module JsonModel
|
|
|
12
14
|
# @param [Hash] options
|
|
13
15
|
# @return [Hash]
|
|
14
16
|
def as_schema(**options)
|
|
15
|
-
|
|
17
|
+
type.as_schema(**options)
|
|
16
18
|
end
|
|
17
19
|
|
|
18
20
|
# @return [Array<TypeSpec>]
|
|
19
21
|
def referenced_schemas
|
|
20
|
-
[
|
|
22
|
+
[type]
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
# @param [::Object] json
|
|
24
26
|
# @return [::Object, nil]
|
|
25
27
|
def cast(json)
|
|
26
|
-
|
|
28
|
+
type.from_json(**json)
|
|
27
29
|
end
|
|
28
30
|
end
|
|
29
31
|
end
|
data/lib/json_model/version.rb
CHANGED
|
@@ -9,7 +9,7 @@ RSpec.describe('File system schema') do
|
|
|
9
9
|
Class.new do
|
|
10
10
|
include(JsonModel::Schema)
|
|
11
11
|
|
|
12
|
-
property(:type, type: T::
|
|
12
|
+
property(:type, type: T::Const['disk'])
|
|
13
13
|
property(:device, type: String, pattern: %r{\A/dev/[^/]+(/[^/]+)*\z})
|
|
14
14
|
end,
|
|
15
15
|
)
|
|
@@ -19,7 +19,7 @@ RSpec.describe('File system schema') do
|
|
|
19
19
|
Class.new do
|
|
20
20
|
include(JsonModel::Schema)
|
|
21
21
|
|
|
22
|
-
property(:type, type: T::Enum['
|
|
22
|
+
property(:type, type: T::Enum['diskUUID', 'diskuuid'])
|
|
23
23
|
property(
|
|
24
24
|
:label,
|
|
25
25
|
type: String,
|
|
@@ -33,7 +33,7 @@ RSpec.describe('File system schema') do
|
|
|
33
33
|
Class.new do
|
|
34
34
|
include(JsonModel::Schema)
|
|
35
35
|
|
|
36
|
-
property(:type, type: T::
|
|
36
|
+
property(:type, type: T::Const['nfs'])
|
|
37
37
|
property(:remote_path, type: String, pattern: %r{\A(/[^/]+)+\z}, as: :remotePath)
|
|
38
38
|
property(:server, type: String, format: :ipv4)
|
|
39
39
|
end,
|
|
@@ -44,7 +44,7 @@ RSpec.describe('File system schema') do
|
|
|
44
44
|
Class.new do
|
|
45
45
|
include(JsonModel::Schema)
|
|
46
46
|
|
|
47
|
-
property(:type, type: T::
|
|
47
|
+
property(:type, type: T::Const['tmpfs'])
|
|
48
48
|
property(:size_in_mb, type: Integer, minimum: 16, maximum: 512, as: :sizeInMB)
|
|
49
49
|
end,
|
|
50
50
|
)
|
|
@@ -55,7 +55,12 @@ RSpec.describe('File system schema') do
|
|
|
55
55
|
include(JsonModel::Schema)
|
|
56
56
|
|
|
57
57
|
description('JSON Schema for an fstab entry')
|
|
58
|
-
property(
|
|
58
|
+
property(
|
|
59
|
+
:storage,
|
|
60
|
+
type: T::OneOf[DiskDevice, DiskUuid, Nfs, Tmpfs],
|
|
61
|
+
ref_mode: JsonModel::RefMode::LOCAL,
|
|
62
|
+
discriminator: :type,
|
|
63
|
+
)
|
|
59
64
|
property(:fstype, type: T::Enum['ext3', 'ext4', 'btrfs'], optional: true)
|
|
60
65
|
property(:options, type: T::Array[String], min_items: 1, unique_items: true, optional: true)
|
|
61
66
|
property(:readonly, type: T::Boolean, optional: true)
|
|
@@ -100,7 +105,7 @@ RSpec.describe('File system schema') do
|
|
|
100
105
|
DiskDevice: {
|
|
101
106
|
properties: {
|
|
102
107
|
type: {
|
|
103
|
-
|
|
108
|
+
const: 'disk',
|
|
104
109
|
},
|
|
105
110
|
device: {
|
|
106
111
|
type: 'string',
|
|
@@ -113,7 +118,7 @@ RSpec.describe('File system schema') do
|
|
|
113
118
|
},
|
|
114
119
|
DiskUuid: {
|
|
115
120
|
properties: {
|
|
116
|
-
type: { enum:
|
|
121
|
+
type: { enum: %w(diskUUID diskuuid) },
|
|
117
122
|
label: {
|
|
118
123
|
type: 'string',
|
|
119
124
|
pattern: '\\A[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}\\z',
|
|
@@ -125,7 +130,7 @@ RSpec.describe('File system schema') do
|
|
|
125
130
|
},
|
|
126
131
|
Nfs: {
|
|
127
132
|
properties: {
|
|
128
|
-
type: {
|
|
133
|
+
type: { const: 'nfs' },
|
|
129
134
|
remotePath: {
|
|
130
135
|
type: 'string',
|
|
131
136
|
pattern: '\\A(/[^/]+)+\\z',
|
|
@@ -141,7 +146,7 @@ RSpec.describe('File system schema') do
|
|
|
141
146
|
},
|
|
142
147
|
Tmpfs: {
|
|
143
148
|
properties: {
|
|
144
|
-
type: {
|
|
149
|
+
type: { const: 'tmpfs' },
|
|
145
150
|
sizeInMB: { type: 'integer', minimum: 16, maximum: 512 },
|
|
146
151
|
},
|
|
147
152
|
required: %i(sizeInMB type),
|
data/spec/schema_spec.rb
CHANGED
|
@@ -64,16 +64,29 @@ RSpec.describe(JsonModel::Schema) do
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
describe('.from_json') do
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
before do
|
|
68
|
+
stub_const(
|
|
69
|
+
'Foo',
|
|
70
|
+
Class.new do
|
|
71
|
+
include(JsonModel::Schema)
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
property(:foo_bar, type: String, as: :fooBar)
|
|
74
|
+
end,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
stub_const(
|
|
78
|
+
'Bar',
|
|
79
|
+
Class.new(Foo),
|
|
80
|
+
)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it('parent can be instantiated from json') do
|
|
84
|
+
instance = Foo.from_json({ fooBar: 'baz' })
|
|
85
|
+
expect(instance.foo_bar).to(eq('baz'))
|
|
73
86
|
end
|
|
74
87
|
|
|
75
|
-
it('can be instantiated from json') do
|
|
76
|
-
instance =
|
|
88
|
+
it('child can be instantiated from json') do
|
|
89
|
+
instance = Bar.from_json({ fooBar: 'baz' })
|
|
77
90
|
expect(instance.foo_bar).to(eq('baz'))
|
|
78
91
|
end
|
|
79
92
|
end
|