emery 0.0.2 → 0.0.3
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/lib/emery/dataclass.rb +63 -65
- data/lib/emery/enum.rb +73 -75
- data/lib/emery/jsoner.rb +162 -164
- data/lib/emery/tod.rb +202 -204
- data/lib/emery/type.rb +149 -151
- data/lib/emery.rb +1 -2
- data/test/dataclass_test.rb +80 -83
- data/test/enum_test.rb +29 -33
- data/test/jsoner_test.rb +189 -192
- data/test/tod_test.rb +23 -28
- data/test/type_test.rb +153 -155
- metadata +1 -1
data/lib/emery/jsoner.rb
CHANGED
@@ -3,211 +3,209 @@ require "date"
|
|
3
3
|
|
4
4
|
require "emery/type"
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
class JsonerError < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
module Jsoner
|
10
|
+
T::StringFormatted.class_eval do
|
11
|
+
def jsoner_deserialize(json_value)
|
12
|
+
T.check(self, json_value)
|
13
|
+
end
|
14
|
+
def jsoner_serialize(value)
|
15
|
+
T.check(self, value)
|
16
|
+
end
|
8
17
|
end
|
9
18
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
19
|
+
T::ArrayType.class_eval do
|
20
|
+
def jsoner_deserialize(json_value)
|
21
|
+
T.check_not_nil(self, json_value)
|
22
|
+
if !json_value.is_a?(Array)
|
23
|
+
raise JsonerError.new("JSON value type #{json_value.class} is not Array")
|
14
24
|
end
|
15
|
-
|
16
|
-
|
25
|
+
json_value.map { |item_json_value| Jsoner.deserialize(self.item_type, item_json_value) }
|
26
|
+
end
|
27
|
+
def jsoner_serialize(value)
|
28
|
+
if !value.is_a?(Array)
|
29
|
+
raise JsonerError.new("Value type #{json_value.class} is not Array")
|
17
30
|
end
|
31
|
+
value.map { |item| Jsoner.serialize(self.item_type, item) }
|
18
32
|
end
|
33
|
+
end
|
19
34
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
end
|
26
|
-
json_value.map { |item_json_value| Jsoner.deserialize(self.item_type, item_json_value) }
|
35
|
+
T::HashType.class_eval do
|
36
|
+
def jsoner_deserialize(json_value)
|
37
|
+
T.check_not_nil(self, json_value)
|
38
|
+
if self.key_type != String
|
39
|
+
raise JsonerError.new("Hash key type #{self.key_type} is not supported for JSON (de)serialization - key should be String")
|
27
40
|
end
|
28
|
-
|
29
|
-
|
30
|
-
raise JsonerError.new("Value type #{json_value.class} is not Array")
|
31
|
-
end
|
32
|
-
value.map { |item| Jsoner.serialize(self.item_type, item) }
|
41
|
+
if !json_value.is_a?(Hash)
|
42
|
+
raise JsonerError.new("JSON value type #{json_value.class} is not Hash")
|
33
43
|
end
|
44
|
+
json_value.map do |key, value|
|
45
|
+
[T.check(self.key_type, key), Jsoner.deserialize(self.value_type, value)]
|
46
|
+
end.to_h
|
34
47
|
end
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
T.check_not_nil(self, json_value)
|
39
|
-
if self.key_type != String
|
40
|
-
raise JsonerError.new("Hash key type #{self.key_type} is not supported for JSON (de)serialization - key should be String")
|
41
|
-
end
|
42
|
-
if !json_value.is_a?(Hash)
|
43
|
-
raise JsonerError.new("JSON value type #{json_value.class} is not Hash")
|
44
|
-
end
|
45
|
-
json_value.map do |key, value|
|
46
|
-
[T.check(self.key_type, key), Jsoner.deserialize(self.value_type, value)]
|
47
|
-
end.to_h
|
48
|
+
def jsoner_serialize(value)
|
49
|
+
if self.key_type != String
|
50
|
+
raise JsonerError.new("Hash key type #{self.key_type} is not supported for JSON (de)serialization - key should be String")
|
48
51
|
end
|
49
|
-
|
50
|
-
|
51
|
-
raise JsonerError.new("Hash key type #{self.key_type} is not supported for JSON (de)serialization - key should be String")
|
52
|
-
end
|
53
|
-
if !value.is_a?(Hash)
|
54
|
-
raise JsonerError.new("Value type #{value.class} is not Hash")
|
55
|
-
end
|
56
|
-
value.map do |key, value|
|
57
|
-
[T.check(self.key_type, key), Jsoner.serialize(self.value_type, value)]
|
58
|
-
end.to_h
|
52
|
+
if !value.is_a?(Hash)
|
53
|
+
raise JsonerError.new("Value type #{value.class} is not Hash")
|
59
54
|
end
|
55
|
+
value.map do |key, value|
|
56
|
+
[T.check(self.key_type, key), Jsoner.serialize(self.value_type, value)]
|
57
|
+
end.to_h
|
60
58
|
end
|
59
|
+
end
|
61
60
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
end
|
61
|
+
T::AnyType.class_eval do
|
62
|
+
def jsoner_deserialize(json_value)
|
63
|
+
types.each do |type|
|
64
|
+
begin
|
65
|
+
return Jsoner.deserialize(type, json_value)
|
66
|
+
rescue TypeError
|
69
67
|
end
|
70
|
-
raise JsonerError.new("Value '#{json_value.inspect.to_s}' can not be deserialized as any of #{@types.map { |t| t.to_s}.join(', ')}")
|
71
|
-
end
|
72
|
-
def jsoner_serialize(value)
|
73
|
-
T.check(self, value)
|
74
|
-
type = types.find {|t| T.instance_of?(t, value) }
|
75
|
-
Jsoner.serialize(type, value)
|
76
68
|
end
|
69
|
+
raise JsonerError.new("Value '#{json_value.inspect.to_s}' can not be deserialized as any of #{@types.map { |t| t.to_s}.join(', ')}")
|
77
70
|
end
|
71
|
+
def jsoner_serialize(value)
|
72
|
+
T.check(self, value)
|
73
|
+
type = types.find {|t| T.instance_of?(t, value) }
|
74
|
+
Jsoner.serialize(type, value)
|
75
|
+
end
|
76
|
+
end
|
78
77
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
end
|
84
|
-
if json_value.keys.length != 1
|
85
|
-
raise JsonerError.new("JSON value #{json_value} should have only one key to represent union type, found #{json_value.keys.length}")
|
86
|
-
end
|
87
|
-
case_key = json_value.keys[0]
|
88
|
-
if not cases.key? case_key.to_sym
|
89
|
-
raise JsonerError.new("JSON key '#{case_key}' does not match any case in union type #{self}")
|
90
|
-
end
|
91
|
-
type = cases[case_key.to_sym]
|
92
|
-
case_json_value = json_value[case_key]
|
93
|
-
return Jsoner.deserialize(type, case_json_value)
|
78
|
+
T::UnionType.class_eval do
|
79
|
+
def jsoner_deserialize(json_value)
|
80
|
+
if !json_value.is_a?(Hash)
|
81
|
+
raise JsonerError.new("JSON value type #{json_value.class} is not Hash")
|
94
82
|
end
|
95
|
-
|
96
|
-
|
97
|
-
type = types.find {|t| T.instance_of?(t, value) }
|
98
|
-
case_key = cases.key(type)
|
99
|
-
result = { case_key => Jsoner.serialize(type, value) }
|
100
|
-
result
|
83
|
+
if json_value.keys.length != 1
|
84
|
+
raise JsonerError.new("JSON value #{json_value} should have only one key to represent union type, found #{json_value.keys.length}")
|
101
85
|
end
|
86
|
+
case_key = json_value.keys[0]
|
87
|
+
if not cases.key? case_key.to_sym
|
88
|
+
raise JsonerError.new("JSON key '#{case_key}' does not match any case in union type #{self}")
|
89
|
+
end
|
90
|
+
type = cases[case_key.to_sym]
|
91
|
+
case_json_value = json_value[case_key]
|
92
|
+
return Jsoner.deserialize(type, case_json_value)
|
93
|
+
end
|
94
|
+
def jsoner_serialize(value)
|
95
|
+
T.check(self, value)
|
96
|
+
type = types.find {|t| T.instance_of?(t, value) }
|
97
|
+
case_key = cases.key(type)
|
98
|
+
result = { case_key => Jsoner.serialize(type, value) }
|
99
|
+
result
|
102
100
|
end
|
101
|
+
end
|
103
102
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
end
|
103
|
+
T::Nilable.class_eval do
|
104
|
+
def jsoner_deserialize(json_value)
|
105
|
+
if json_value != nil
|
106
|
+
Jsoner.deserialize(self.type, json_value)
|
107
|
+
else
|
108
|
+
nil
|
111
109
|
end
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
110
|
+
end
|
111
|
+
def jsoner_serialize(value)
|
112
|
+
if value != nil
|
113
|
+
Jsoner.serialize(self.type, value)
|
114
|
+
else
|
115
|
+
nil
|
118
116
|
end
|
119
117
|
end
|
118
|
+
end
|
120
119
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
end
|
120
|
+
module FloatSerializer
|
121
|
+
def self.jsoner_deserialize(json_value)
|
122
|
+
T.check(T.any(Float, Integer), json_value)
|
123
|
+
json_value.to_f
|
124
|
+
end
|
125
|
+
def self.jsoner_serialize(value)
|
126
|
+
T.check(Float, value)
|
129
127
|
end
|
128
|
+
end
|
130
129
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
end
|
139
|
-
end
|
140
|
-
def self.jsoner_serialize(value)
|
141
|
-
T.check(DateTime, value)
|
142
|
-
value.strftime('%Y-%m-%dT%H:%M:%S')
|
130
|
+
module DateTimeSerializer
|
131
|
+
def self.jsoner_deserialize(json_value)
|
132
|
+
T.check(String, json_value)
|
133
|
+
begin
|
134
|
+
DateTime.strptime(json_value, '%Y-%m-%dT%H:%M:%S')
|
135
|
+
rescue
|
136
|
+
raise JsonerError.new("Failed to parse DateTime from '#{json_value.inspect.to_s}' format %Y-%m-%dT%H:%M:%S is required")
|
143
137
|
end
|
144
138
|
end
|
139
|
+
def self.jsoner_serialize(value)
|
140
|
+
T.check(DateTime, value)
|
141
|
+
value.strftime('%Y-%m-%dT%H:%M:%S')
|
142
|
+
end
|
143
|
+
end
|
145
144
|
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
end
|
154
|
-
end
|
155
|
-
def self.jsoner_serialize(value)
|
156
|
-
T.check(Date, value)
|
157
|
-
value.strftime('%Y-%m-%d')
|
145
|
+
module DateSerializer
|
146
|
+
def self.jsoner_deserialize(json_value)
|
147
|
+
T.check(String, json_value)
|
148
|
+
begin
|
149
|
+
Date.strptime(json_value, '%Y-%m-%d')
|
150
|
+
rescue
|
151
|
+
raise JsonerError.new("Failed to parse Date from '#{json_value.inspect.to_s}' format %Y-%m-%d is required")
|
158
152
|
end
|
159
153
|
end
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
Date => DateSerializer,
|
164
|
-
DateTime => DateTimeSerializer
|
165
|
-
}
|
166
|
-
def self.add_serializer(type, serializer)
|
167
|
-
@@serializers[type] = serializer
|
154
|
+
def self.jsoner_serialize(value)
|
155
|
+
T.check(Date, value)
|
156
|
+
value.strftime('%Y-%m-%d')
|
168
157
|
end
|
158
|
+
end
|
169
159
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
160
|
+
@@serializers = {
|
161
|
+
Float => FloatSerializer,
|
162
|
+
Date => DateSerializer,
|
163
|
+
DateTime => DateTimeSerializer
|
164
|
+
}
|
165
|
+
def self.add_serializer(type, serializer)
|
166
|
+
@@serializers[type] = serializer
|
167
|
+
end
|
174
168
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
169
|
+
def Jsoner.from_json(type, json)
|
170
|
+
data = JSON.parse(json)
|
171
|
+
return deserialize(type, data)
|
172
|
+
end
|
173
|
+
|
174
|
+
def Jsoner.deserialize(type, json_value)
|
175
|
+
begin
|
176
|
+
if type.methods.include? :jsoner_deserialize
|
177
|
+
return type.jsoner_deserialize(json_value)
|
178
|
+
elsif @@serializers.include? type
|
179
|
+
return @@serializers[type].jsoner_deserialize(json_value)
|
180
|
+
else
|
181
|
+
if ![String, Float, Integer, TrueClass, FalseClass, NilClass].include? type
|
182
|
+
raise JsonerError.new("Type #{type} is not supported in Jsoner deserialization")
|
186
183
|
end
|
187
|
-
|
188
|
-
raise JsonerError.new(error.message)
|
184
|
+
return T.check(type, json_value)
|
189
185
|
end
|
186
|
+
rescue StandardError => error
|
187
|
+
raise JsonerError.new(error.message)
|
190
188
|
end
|
189
|
+
end
|
191
190
|
|
192
|
-
|
193
|
-
|
194
|
-
|
191
|
+
def Jsoner.to_json(type, value)
|
192
|
+
JSON.dump(serialize(type, value))
|
193
|
+
end
|
195
194
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
end
|
206
|
-
return T.check(type, value)
|
195
|
+
def Jsoner.serialize(type, value)
|
196
|
+
begin
|
197
|
+
if type.methods.include? :jsoner_serialize
|
198
|
+
return type.jsoner_serialize(value)
|
199
|
+
elsif @@serializers.include? type
|
200
|
+
return @@serializers[type].jsoner_serialize(value)
|
201
|
+
else
|
202
|
+
if ![String, Float, Integer, TrueClass, FalseClass, NilClass].include? type
|
203
|
+
raise JsonerError.new("Type #{type} is not supported in Jsoner serialization")
|
207
204
|
end
|
208
|
-
|
209
|
-
raise JsonerError.new(error.message)
|
205
|
+
return T.check(type, value)
|
210
206
|
end
|
207
|
+
rescue StandardError => error
|
208
|
+
raise JsonerError.new(error.message)
|
211
209
|
end
|
212
210
|
end
|
213
|
-
end
|
211
|
+
end
|