json_schema-faker 0.1.0 → 0.1.1
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/CHANGELOG.md +8 -0
- data/VERSION +1 -1
- data/lib/json_schema/faker.rb +8 -275
- data/lib/json_schema/faker/strategy/simple.rb +311 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d295d3dfb065608b9af8b1bfcd4336ea16a7de1
|
4
|
+
data.tar.gz: 08969d39f4b51f7c4fc07fd0c7ec3cb9408d3995
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a3360dae5813be93b1c4aa5ac9cdd04c5c1e7c5151d90529811d4e5530c48a022c187967a2d1e92bd5d395c3660c2978dedcabbd46114d7d37d7dc3823698e3
|
7
|
+
data.tar.gz: b07858fa1b121b06e58d3dd27342a76e2cc03e27fde3137ffd73d6a50c1ec15a9bf0c8cb9289795d08cd4f525ae86800022a1cfce2c456478f954bef5881d312
|
data/CHANGELOG.md
ADDED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/lib/json_schema/faker.rb
CHANGED
@@ -10,293 +10,26 @@ module JsonSchema
|
|
10
10
|
module_function :logger, :logger=
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
@schema = schema
|
13
|
+
module Strategy
|
14
|
+
require "json_schema/faker/strategy/simple"
|
15
|
+
end
|
17
16
|
|
17
|
+
def initialize(schema, options = {})
|
18
|
+
@schema = schema
|
18
19
|
@options = options
|
19
20
|
end
|
20
21
|
|
21
22
|
def generate(hint: nil)
|
22
|
-
|
23
|
+
strategy = @options[:strategy] || Strategy::Simple.new
|
23
24
|
|
24
25
|
Configuration.logger.debug "to generate against #{@schema.inspect_schema}" if Configuration.logger
|
26
|
+
|
27
|
+
generated = strategy.call(@schema, hint: nil, position: "")
|
25
28
|
Configuration.logger.debug "generated: #{generated.inspect}" if Configuration.logger
|
26
29
|
|
27
30
|
generated
|
28
31
|
end
|
29
32
|
|
30
33
|
protected
|
31
|
-
def _generate(schema, hint: nil, position:)
|
32
|
-
Configuration.logger.debug "current position: #{position}" if Configuration.logger
|
33
|
-
|
34
|
-
raise "here comes nil for schema at #{position}" unless schema
|
35
|
-
|
36
|
-
return schema.default if schema.default
|
37
|
-
|
38
|
-
if schema.not
|
39
|
-
hint ||= {}
|
40
|
-
# too difficult
|
41
|
-
# TODO: support one_of/any_of/all_of
|
42
|
-
hint[:not_have_keys] = schema.not.required if schema.not.required
|
43
|
-
hint[:not_be_values] = schema.not.enum if schema.not.enum
|
44
|
-
end
|
45
|
-
|
46
|
-
# TODO: should support the combinations of them
|
47
|
-
# http://json-schema.org/latest/json-schema-validation.html#anchor75
|
48
|
-
# Notes:
|
49
|
-
# one_of, any_of, all_of, properties and type is given default and never be nil
|
50
|
-
if !schema.one_of.empty?
|
51
|
-
generate_for_one_of(schema, hint: hint, position: position)
|
52
|
-
elsif !schema.any_of.empty?
|
53
|
-
generate_for_any_of(schema, hint: hint, position: position)
|
54
|
-
elsif !schema.all_of.empty?
|
55
|
-
generate_for_all_of(schema, hint: hint, position: position)
|
56
|
-
elsif schema.enum
|
57
|
-
generate_by_enum(schema, hint: hint, position: position)
|
58
|
-
elsif !schema.type.empty?
|
59
|
-
generate_by_type(schema, position: position)
|
60
|
-
else # consider as object
|
61
|
-
generate_for_object(schema, hint: hint, position: position)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def generate_for_one_of(schema, hint: nil, position:)
|
66
|
-
merged_schema = JsonSchema::Schema.new
|
67
|
-
merged_schema.copy_from(schema)
|
68
|
-
|
69
|
-
merged_schema.one_of = []
|
70
|
-
|
71
|
-
# TODO: treat rest as not
|
72
|
-
_generate(merge_schema(merged_schema, schema.one_of.first), hint: hint, position: "position/one_of[0]")
|
73
|
-
end
|
74
|
-
|
75
|
-
def generate_for_any_of(schema, hint: nil, position:)
|
76
|
-
merged_schema = JsonSchema::Schema.new
|
77
|
-
merged_schema.copy_from(schema)
|
78
|
-
|
79
|
-
merged_schema.any_of = []
|
80
|
-
|
81
|
-
_generate(merge_schema(merged_schema, schema.any_of.first), hint: hint, position: "position/any_of[0]")
|
82
|
-
end
|
83
|
-
|
84
|
-
def generate_for_all_of(schema, hint: nil, position:)
|
85
|
-
# deep_merge all_of
|
86
|
-
merged_schema = JsonSchema::Schema.new
|
87
|
-
merged_schema.copy_from(schema)
|
88
|
-
|
89
|
-
merged_schema.all_of = []
|
90
|
-
|
91
|
-
schema.all_of.each do |sub_schema|
|
92
|
-
merge_schema(merged_schema, sub_schema)
|
93
|
-
end
|
94
|
-
|
95
|
-
_generate(merged_schema, hint: hint, position: "position/all_of")
|
96
|
-
end
|
97
|
-
|
98
|
-
def generate_for_object(schema, hint: nil, position:)
|
99
|
-
# http://json-schema.org/latest/json-schema-validation.html#anchor53
|
100
|
-
if schema.required
|
101
|
-
keys = schema.required
|
102
|
-
required_length = schema.min_properties || keys.length
|
103
|
-
|
104
|
-
object = keys.each.with_object({}) do |key, hash|
|
105
|
-
hash[key] = _generate(schema.properties[key], hint: hint, position: "#{position}/#{key}") # TODO: pass hint
|
106
|
-
end
|
107
|
-
else
|
108
|
-
required_length = schema.min_properties || schema.max_properties || 0
|
109
|
-
|
110
|
-
keys = (schema.properties || {}).keys
|
111
|
-
keys -= (hint[:not_have_keys] || []) if hint
|
112
|
-
|
113
|
-
object = keys.first(required_length).each.with_object({}) do |key, hash|
|
114
|
-
hash[key] = _generate(schema.properties[key], hint: hint, position: "#{position}/#{key}") # TODO: pass hint
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
# if length is not enough
|
119
|
-
if schema.additional_properties === false
|
120
|
-
(required_length - object.keys.length).times.each.with_object(object) do |i, hash|
|
121
|
-
if schema.pattern_properties.empty?
|
122
|
-
key = (schema.properties.keys - object.keys).first
|
123
|
-
hash[key] = _generate(schema.properties[key], hint: hint, position: "#{position}/#{key}")
|
124
|
-
else
|
125
|
-
name = Pxeger.new(schema.pattern_properties.keys.first).generate
|
126
|
-
hash[name] = _generate(schema.pattern_properties.values.first, hint: hint, position: "#{position}/#{name}")
|
127
|
-
end
|
128
|
-
end
|
129
|
-
else
|
130
|
-
# FIXME: key confilct with properties
|
131
|
-
(required_length - object.keys.length).times.each.with_object(object) do |i, hash|
|
132
|
-
hash[i.to_s] = i
|
133
|
-
end
|
134
|
-
end
|
135
|
-
|
136
|
-
# consider dependency
|
137
|
-
depended_keys = object.keys & schema.dependencies.keys
|
138
|
-
|
139
|
-
# FIXME: circular dependency is not supported
|
140
|
-
depended_keys.each.with_object(object) do |key, hash|
|
141
|
-
dependency = schema.dependencies[key]
|
142
|
-
|
143
|
-
if dependency.is_a?(JsonSchema::Schema)
|
144
|
-
# too difficult we just merge
|
145
|
-
hash.update(_generate(schema.dependencies[key], hint: nil, position: "#{position}/dependencies/#{key}"))
|
146
|
-
else
|
147
|
-
dependency.each do |additional_key|
|
148
|
-
object[additional_key] = _generate(schema.properties[additional_key], hint: hint, position: "#{position}/dependencies/#{key}/#{additional_key}") unless object.has_key?(additional_key)
|
149
|
-
end
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
def generate_by_enum(schema, hint: nil, position:)
|
155
|
-
black_list = (hint ? hint[:not_be_values] : nil)
|
156
|
-
|
157
|
-
if Configuration.logger
|
158
|
-
Configuration.logger.info "generate by enum at #{position}"
|
159
|
-
Configuration.logger.debug schema.inspect_schema
|
160
|
-
Configuration.logger.debug "black list: #{black_list}" if black_list
|
161
|
-
end
|
162
|
-
|
163
|
-
if black_list
|
164
|
-
(schema.enum - black_list).first
|
165
|
-
else
|
166
|
-
schema.enum.first
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def generate_by_type(schema, hint: nil, position:)
|
171
|
-
if Configuration.logger
|
172
|
-
Configuration.logger.info "generate by type at #{position}"
|
173
|
-
Configuration.logger.debug schema.inspect_schema
|
174
|
-
end
|
175
|
-
|
176
|
-
# http://json-schema.org/latest/json-schema-core.html#anchor8
|
177
|
-
# TODO: use include? than first
|
178
|
-
case schema.type.first
|
179
|
-
when "array"
|
180
|
-
generate_for_array(schema, hint: hint, position: position)
|
181
|
-
when "boolean"
|
182
|
-
true
|
183
|
-
when "integer", "number"
|
184
|
-
generate_for_number(schema, hint: hint)
|
185
|
-
when "null"
|
186
|
-
nil
|
187
|
-
when "object"
|
188
|
-
# here comes object without properties
|
189
|
-
generate_for_object(schema, hint: hint, position: position)
|
190
|
-
when "string"
|
191
|
-
generate_for_string(schema, hint: hint)
|
192
|
-
else
|
193
|
-
raise "unknown type for #{schema.inspect_schema}"
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
def generate_for_array(schema, hint: nil, position:)
|
198
|
-
# http://json-schema.org/latest/json-schema-validation.html#anchor36
|
199
|
-
# additionalItems items maxItems minItems uniqueItems
|
200
|
-
length = schema.min_items || 0
|
201
|
-
|
202
|
-
# if "items" is not present, or its value is an object, validation of the instance always succeeds, regardless of the value of "additionalItems";
|
203
|
-
# if the value of "additionalItems" is boolean value true or an object, validation of the instance always succeeds;
|
204
|
-
item = if (schema.items.nil? || schema.items.is_a?(JsonSchema::Schema)) || ( schema.additional_items === true || schema.additional_items.is_a?(JsonSchema::Schema))
|
205
|
-
length.times.map.with_index {|i| i }
|
206
|
-
else # in case schema.items is array and schema.additional_items is true
|
207
|
-
# if the value of "additionalItems" is boolean value false and the value of "items" is an array
|
208
|
-
# the instance is valid if its size is less than, or equal to, the size of "items".
|
209
|
-
raise "#{position}: item length(#{schema.items.length} is shorter than minItems(#{schema.min_items}))" unless schema.items.length <= length
|
210
|
-
|
211
|
-
# TODO: consider unique items
|
212
|
-
length.times.map.with_index {|i| _generate(schema.items[i], position: position + "[#{i}]") }
|
213
|
-
end
|
214
|
-
end
|
215
|
-
|
216
|
-
def generate_for_number(schema, hint: nil)
|
217
|
-
# http://json-schema.org/latest/json-schema-validation.html#anchor13
|
218
|
-
# TODO: use hint[:not_be_values]
|
219
|
-
min = schema.min
|
220
|
-
max = schema.max
|
221
|
-
|
222
|
-
if schema.multiple_of
|
223
|
-
min = (min + schema.multiple_of - min % schema.multiple_of) if min
|
224
|
-
max = (max - max % schema.multiple_of) if max
|
225
|
-
end
|
226
|
-
|
227
|
-
delta = schema.multiple_of ? schema.multiple_of : 1
|
228
|
-
|
229
|
-
# TODO: more sophisticated caluculation
|
230
|
-
min, max = [ (min || (max ? max - delta * 2 : 0)), (max || (min ? min + delta * 2 : 0)) ]
|
231
|
-
|
232
|
-
# to get average of min and max can avoid exclusive*
|
233
|
-
if schema.type.first == "integer"
|
234
|
-
(min / delta + max / delta) / 2 * delta
|
235
|
-
else
|
236
|
-
(min + max) / 2.0
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
def generate_for_string(schema, hint: nil)
|
241
|
-
# http://json-schema.org/latest/json-schema-validation.html#anchor25
|
242
|
-
# TODO: use hint[:not_be_values]
|
243
|
-
# TODO: support format
|
244
|
-
if schema.pattern
|
245
|
-
Pxeger.new(schema.pattern).generate
|
246
|
-
else
|
247
|
-
length = schema.min_length || 0
|
248
|
-
"a" * length
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
def merge_schema(a, b)
|
253
|
-
# attr not supported now
|
254
|
-
# any_of: too difficult...
|
255
|
-
# enum/items: TODO: just get and of array
|
256
|
-
# not: too difficult (if `not` is not wrapped by all_of wrap it?)
|
257
|
-
# multiple_of TODO: least common multiple
|
258
|
-
# pattern: too difficult...
|
259
|
-
# format TODO: just override
|
260
|
-
|
261
|
-
# array properties
|
262
|
-
%i[ type one_of all_of ].each do |attr|
|
263
|
-
a.__send__("#{attr}=", a.__send__(attr) + b.__send__(attr))
|
264
|
-
end
|
265
|
-
a.required = (a.required ? a.required + b.required : b.required) if b.required
|
266
|
-
|
267
|
-
# object properties
|
268
|
-
# XXX: key conflict
|
269
|
-
%i[ properties pattern_properties dependencies ].each do |attr|
|
270
|
-
a.__send__("#{attr}=", a.__send__(attr).merge(b.__send__(attr)))
|
271
|
-
end
|
272
|
-
|
273
|
-
# override to stronger validation
|
274
|
-
%i[ additional_items additional_properties ].each do |attr|
|
275
|
-
a.__send__("#{attr}=", false) unless a.__send__(attr) && b.__send__(attr)
|
276
|
-
end
|
277
|
-
%i[ min_exclusive max_exclusive unique_items ].each do |attr|
|
278
|
-
a.__send__("#{attr}=", a.__send__(attr) & b.__send__(attr))
|
279
|
-
end
|
280
|
-
%i[ min min_length min_properties ].each do |attr|
|
281
|
-
if b.__send__(attr)
|
282
|
-
if a.__send__(attr)
|
283
|
-
a.__send__("#{attr}=", b.__send__(attr)) if b.__send__(attr) < a.__send__(attr)
|
284
|
-
else
|
285
|
-
a.__send__("#{attr}=", b.__send__(attr))
|
286
|
-
end
|
287
|
-
end
|
288
|
-
end
|
289
|
-
%i[ max max_length max_properties ].each do |attr|
|
290
|
-
if b.__send__(attr)
|
291
|
-
if a.__send__(attr)
|
292
|
-
a.__send__("#{attr}=", b.__send__(attr)) if b.__send__(attr) > a.__send__(attr)
|
293
|
-
else
|
294
|
-
a.__send__("#{attr}=", b.__send__(attr))
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
a
|
300
|
-
end
|
301
34
|
end
|
302
35
|
end
|
@@ -0,0 +1,311 @@
|
|
1
|
+
module JsonSchema::Faker::Strategy
|
2
|
+
class Simple
|
3
|
+
def call(schema, hint: nil, position:)
|
4
|
+
::JsonSchema::Faker::Configuration.logger.debug "current position: #{position}" if ::JsonSchema::Faker::Configuration.logger
|
5
|
+
|
6
|
+
raise "here comes nil for schema at #{position}" unless schema
|
7
|
+
|
8
|
+
# merge one_of/any_of/all_of
|
9
|
+
::JsonSchema::Faker::Configuration.logger.debug schema.inspect_schema if ::JsonSchema::Faker::Configuration.logger
|
10
|
+
schema = compact_schema(schema, position: position)
|
11
|
+
|
12
|
+
return schema.default if schema.default
|
13
|
+
|
14
|
+
if schema.not
|
15
|
+
hint ||= {}
|
16
|
+
# too difficult
|
17
|
+
# TODO: support one_of/any_of/all_of
|
18
|
+
hint[:not_have_keys] = schema.not.required if schema.not.required
|
19
|
+
hint[:not_be_values] = schema.not.enum if schema.not.enum
|
20
|
+
end
|
21
|
+
|
22
|
+
# http://json-schema.org/latest/json-schema-validation.html#anchor75
|
23
|
+
if schema.enum
|
24
|
+
generate_by_enum(schema, hint: hint, position: position)
|
25
|
+
else
|
26
|
+
generate_by_type(schema, hint: hint, position: position)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
alias_method :generate, :call
|
30
|
+
|
31
|
+
def generate_for_object(schema, hint: nil, position:)
|
32
|
+
# http://json-schema.org/latest/json-schema-validation.html#anchor53
|
33
|
+
if schema.required
|
34
|
+
keys = schema.required
|
35
|
+
required_length = schema.min_properties || keys.length
|
36
|
+
|
37
|
+
object = keys.each.with_object({}) do |key, hash|
|
38
|
+
hash[key] = generate(schema.properties[key], hint: hint, position: "#{position}/#{key}") # TODO: pass hint
|
39
|
+
end
|
40
|
+
else
|
41
|
+
required_length = schema.min_properties || schema.max_properties || 0
|
42
|
+
|
43
|
+
keys = (schema.properties || {}).keys
|
44
|
+
keys -= (hint[:not_have_keys] || []) if hint
|
45
|
+
|
46
|
+
object = keys.first(required_length).each.with_object({}) do |key, hash|
|
47
|
+
hash[key] = generate(schema.properties[key], hint: hint, position: "#{position}/#{key}") # TODO: pass hint
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# if length is not enough
|
52
|
+
if schema.additional_properties === false
|
53
|
+
(required_length - object.keys.length).times.each.with_object(object) do |i, hash|
|
54
|
+
if schema.pattern_properties.empty?
|
55
|
+
key = (schema.properties.keys - object.keys).first
|
56
|
+
hash[key] = generate(schema.properties[key], hint: hint, position: "#{position}/#{key}")
|
57
|
+
else
|
58
|
+
name = ::Pxeger.new(schema.pattern_properties.keys.first).generate
|
59
|
+
hash[name] = generate(schema.pattern_properties.values.first, hint: hint, position: "#{position}/#{name}")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
else
|
63
|
+
# FIXME: key confilct with properties
|
64
|
+
(required_length - object.keys.length).times.each.with_object(object) do |i, hash|
|
65
|
+
hash[i.to_s] = i
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# consider dependency
|
70
|
+
depended_keys = object.keys & schema.dependencies.keys
|
71
|
+
|
72
|
+
# FIXME: circular dependency is not supported
|
73
|
+
depended_keys.each.with_object(object) do |key, hash|
|
74
|
+
dependency = schema.dependencies[key]
|
75
|
+
|
76
|
+
if dependency.is_a?(::JsonSchema::Schema)
|
77
|
+
# too difficult we just merge
|
78
|
+
hash.update(generate(schema.dependencies[key], hint: nil, position: "#{position}/dependencies/#{key}"))
|
79
|
+
else
|
80
|
+
dependency.each do |additional_key|
|
81
|
+
object[additional_key] = generate(schema.properties[additional_key], hint: hint, position: "#{position}/dependencies/#{key}/#{additional_key}") unless object.has_key?(additional_key)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def generate_by_enum(schema, hint: nil, position:)
|
88
|
+
black_list = (hint ? hint[:not_be_values] : nil)
|
89
|
+
|
90
|
+
if ::JsonSchema::Faker::Configuration.logger
|
91
|
+
::JsonSchema::Faker::Configuration.logger.info "generate by enum at #{position}"
|
92
|
+
::JsonSchema::Faker::Configuration.logger.debug schema.inspect_schema
|
93
|
+
::JsonSchema::Faker::Configuration.logger.debug "black list: #{black_list}" if black_list
|
94
|
+
end
|
95
|
+
|
96
|
+
if black_list
|
97
|
+
(schema.enum - black_list).first
|
98
|
+
else
|
99
|
+
schema.enum.first
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def generate_by_type(schema, hint: nil, position:)
|
104
|
+
if ::JsonSchema::Faker::Configuration.logger
|
105
|
+
::JsonSchema::Faker::Configuration.logger.info "generate by type at #{position}"
|
106
|
+
::JsonSchema::Faker::Configuration.logger.debug schema.inspect_schema
|
107
|
+
end
|
108
|
+
|
109
|
+
# http://json-schema.org/latest/json-schema-core.html#anchor8
|
110
|
+
# TODO: use include? than first
|
111
|
+
case schema.type.first
|
112
|
+
when "array"
|
113
|
+
generate_for_array(schema, hint: hint, position: position)
|
114
|
+
when "boolean"
|
115
|
+
true
|
116
|
+
when "integer", "number"
|
117
|
+
generate_for_number(schema, hint: hint)
|
118
|
+
when "null"
|
119
|
+
nil
|
120
|
+
when "object", nil
|
121
|
+
# here comes object without properties
|
122
|
+
generate_for_object(schema, hint: hint, position: position)
|
123
|
+
when "string"
|
124
|
+
generate_for_string(schema, hint: hint)
|
125
|
+
else
|
126
|
+
raise "unknown type for #{schema.inspect_schema}"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def generate_for_array(schema, hint: nil, position:)
|
131
|
+
# http://json-schema.org/latest/json-schema-validation.html#anchor36
|
132
|
+
# additionalItems items maxItems minItems uniqueItems
|
133
|
+
length = schema.min_items || 0
|
134
|
+
|
135
|
+
if schema.items.nil?
|
136
|
+
length.times.map.with_index {|i| i }
|
137
|
+
else
|
138
|
+
if schema.items.is_a?(Array)
|
139
|
+
items = schema.items.map.with_index {|e, i| generate(e, hint: hint, position: "#{position}/items[#{i}]") }
|
140
|
+
|
141
|
+
items + (length - items.size).map.with_index {|i| schema.additional_items === false ? i : generate(schema.additional_items, hint: hint, position: "#{position}/additional_items[#{i}]") }
|
142
|
+
else
|
143
|
+
length.times.map.with_index {|i| generate(schema.items, hint: hint, position: "#{position}/items[#{i}]") }
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def generate_for_number(schema, hint: nil)
|
149
|
+
# http://json-schema.org/latest/json-schema-validation.html#anchor13
|
150
|
+
# TODO: use hint[:not_be_values]
|
151
|
+
min = schema.min
|
152
|
+
max = schema.max
|
153
|
+
|
154
|
+
if schema.multiple_of
|
155
|
+
min = (min + schema.multiple_of - min % schema.multiple_of) if min
|
156
|
+
max = (max - max % schema.multiple_of) if max
|
157
|
+
end
|
158
|
+
|
159
|
+
delta = schema.multiple_of ? schema.multiple_of : 1
|
160
|
+
|
161
|
+
# TODO: more sophisticated caluculation
|
162
|
+
min, max = [ (min || (max ? max - delta * 2 : 0)), (max || (min ? min + delta * 2 : 0)) ]
|
163
|
+
|
164
|
+
# to get average of min and max can avoid exclusive*
|
165
|
+
if schema.type.first == "integer"
|
166
|
+
(min / delta + max / delta) / 2 * delta
|
167
|
+
else
|
168
|
+
(min + max) / 2.0
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def generate_for_string(schema, hint: nil)
|
173
|
+
# http://json-schema.org/latest/json-schema-validation.html#anchor25
|
174
|
+
# TODO: use hint[:not_be_values]
|
175
|
+
# TODO: support format
|
176
|
+
if schema.pattern
|
177
|
+
::Pxeger.new(schema.pattern).generate
|
178
|
+
else
|
179
|
+
length = schema.min_length || 0
|
180
|
+
"a" * length
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
def compact_and_merge_schema(a, b, a_position:, b_position:)
|
185
|
+
merge_schema!(
|
186
|
+
compact_schema(a, position: a_position),
|
187
|
+
compact_schema(b, position: b_position),
|
188
|
+
a_position: a_position,
|
189
|
+
b_position: b_position
|
190
|
+
)
|
191
|
+
end
|
192
|
+
|
193
|
+
def compact_schema(schema, position:)
|
194
|
+
return schema if schema.one_of.empty? && schema.any_of.empty? && schema.all_of.empty?
|
195
|
+
|
196
|
+
if ::JsonSchema::Faker::Configuration.logger
|
197
|
+
::JsonSchema::Faker::Configuration.logger.info "start to compact at #{position}"
|
198
|
+
::JsonSchema::Faker::Configuration.logger.debug schema.inspect_schema
|
199
|
+
end
|
200
|
+
|
201
|
+
merged_schema = ::JsonSchema::Schema.new
|
202
|
+
merged_schema.copy_from(schema)
|
203
|
+
merged_schema.one_of = []
|
204
|
+
merged_schema.any_of = []
|
205
|
+
merged_schema.all_of = []
|
206
|
+
|
207
|
+
unless schema.one_of.empty?
|
208
|
+
::JsonSchema::Faker::Configuration.logger.info "compact one_of" if ::JsonSchema::Faker::Configuration.logger
|
209
|
+
compact_and_merge_schema(merged_schema, schema.one_of.first, a_position: position, b_position: "#{position}/one_of[0]")
|
210
|
+
end
|
211
|
+
|
212
|
+
unless schema.any_of.empty?
|
213
|
+
::JsonSchema::Faker::Configuration.logger.info "compact any_of" if ::JsonSchema::Faker::Configuration.logger
|
214
|
+
compact_and_merge_schema(merged_schema, schema.any_of.first, a_position: position, b_position: "#{position}/any_of[0]")
|
215
|
+
end
|
216
|
+
|
217
|
+
unless schema.all_of.empty?
|
218
|
+
::JsonSchema::Faker::Configuration.logger.info "compact all_of" if ::JsonSchema::Faker::Configuration.logger
|
219
|
+
all_of = ::JsonSchema::Schema.new
|
220
|
+
all_of.copy_from(schema.all_of.first)
|
221
|
+
|
222
|
+
all_of = schema.all_of[1..-1].each.with_index.inject(all_of) do |(a, _), (b, i)|
|
223
|
+
compact_and_merge_schema(a, b, a_position: "#{position}/all_of", b_position: "#{position}/all_of[#{i+1}]")
|
224
|
+
end
|
225
|
+
|
226
|
+
merge_schema!(merged_schema, all_of, a_position: position, b_position: "#{position}/all_of")
|
227
|
+
end
|
228
|
+
|
229
|
+
::JsonSchema::Faker::Configuration.logger.debug "compacted: #{merged_schema.inspect_schema}" if ::JsonSchema::Faker::Configuration.logger
|
230
|
+
|
231
|
+
merged_schema
|
232
|
+
end
|
233
|
+
|
234
|
+
def merge_schema!(a, b, a_position:, b_position:)
|
235
|
+
if ::JsonSchema::Faker::Configuration.logger
|
236
|
+
::JsonSchema::Faker::Configuration.logger.info "start to merge at #{a_position} with #{b_position}"
|
237
|
+
::JsonSchema::Faker::Configuration.logger.debug "a: #{a.inspect_schema}"
|
238
|
+
::JsonSchema::Faker::Configuration.logger.debug "b: #{b.inspect_schema}"
|
239
|
+
end
|
240
|
+
# attr not supported now
|
241
|
+
# not: too difficult (if `not` is not wrapped by all_of wrap it?)
|
242
|
+
# multiple_of TODO: least common multiple
|
243
|
+
# format TODO: just override
|
244
|
+
|
245
|
+
# array properties
|
246
|
+
a.any_of = (a.any_of.empty? ? b.any_of : a.any_of) # XXX: actually impossible
|
247
|
+
a.enum = (a.enum ? (a.enum & b.enum) : b.enum) if b.enum
|
248
|
+
|
249
|
+
%i[ type one_of all_of ].each do |attr|
|
250
|
+
a.__send__("#{attr}=", a.__send__(attr) + b.__send__(attr))
|
251
|
+
end
|
252
|
+
a.required = (a.required ? (a.required + b.required).uniq : b.required) if b.required
|
253
|
+
|
254
|
+
# object properties
|
255
|
+
# XXX: key conflict
|
256
|
+
%i[ properties pattern_properties dependencies ].each do |attr|
|
257
|
+
a.__send__("#{attr}=", a.__send__(attr).merge(b.__send__(attr)))
|
258
|
+
end
|
259
|
+
|
260
|
+
# array of object
|
261
|
+
if a.items && b.items
|
262
|
+
if a.items.is_a?(Array) && b.items.is_a?(Array)
|
263
|
+
# TODO: zip and merge it
|
264
|
+
elsif a.items.is_a?(Array) && b.items.is_a?(::JsonSchema::Schema)
|
265
|
+
a.items = a.items.map.with_index do |e, i|
|
266
|
+
compact_and_merge_schema(e, b.items, a_position: "#{a_position}/items[#{i}]", b_position: "#{b_position}/items")
|
267
|
+
end
|
268
|
+
elsif a.items.is_a?(::JsonSchema::Schema) && a.items.is_a?(Array)
|
269
|
+
a.items = b.items.map.with_index do |e, i|
|
270
|
+
compact_and_merge_schema(a.items, e, a_position: "#{a_position}/items", b_position: "#{b_position}/items[#{i}]")
|
271
|
+
end
|
272
|
+
else
|
273
|
+
compact_and_merge_schema(a.items, b.items, a_position: "#{a_position}/items", b_position: "#{b_position}/items")
|
274
|
+
end
|
275
|
+
else
|
276
|
+
a.items ||= b.items
|
277
|
+
end
|
278
|
+
|
279
|
+
# override to stronger validation
|
280
|
+
%i[ additional_items additional_properties ].each do |attr|
|
281
|
+
a.__send__("#{attr}=", false) unless a.__send__(attr) && b.__send__(attr)
|
282
|
+
end
|
283
|
+
%i[ min_exclusive max_exclusive unique_items ].each do |attr|
|
284
|
+
a.__send__("#{attr}=", a.__send__(attr) & b.__send__(attr))
|
285
|
+
end
|
286
|
+
%i[ min min_length min_properties min_items ].each do |attr|
|
287
|
+
if b.__send__(attr)
|
288
|
+
if a.__send__(attr)
|
289
|
+
a.__send__("#{attr}=", b.__send__(attr)) if b.__send__(attr) < a.__send__(attr)
|
290
|
+
else
|
291
|
+
a.__send__("#{attr}=", b.__send__(attr))
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
%i[ max max_length max_properties max_items ].each do |attr|
|
296
|
+
if b.__send__(attr)
|
297
|
+
if a.__send__(attr)
|
298
|
+
a.__send__("#{attr}=", b.__send__(attr)) if b.__send__(attr) > a.__send__(attr)
|
299
|
+
else
|
300
|
+
a.__send__("#{attr}=", b.__send__(attr))
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
a.pattern = (a.pattern && b.pattern) ? "(?:#{a.pattern})(?=#{b.pattern})" : (a.pattern || b.pattern)
|
305
|
+
|
306
|
+
::JsonSchema::Faker::Configuration.logger.debug "merged: #{a.inspect_schema}" if ::JsonSchema::Faker::Configuration.logger
|
307
|
+
|
308
|
+
a
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_schema-faker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- okitan
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-06-
|
11
|
+
date: 2016-06-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json_schema
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- ".gitmodules"
|
120
120
|
- ".rspec"
|
121
121
|
- ".travis.yml"
|
122
|
+
- CHANGELOG.md
|
122
123
|
- CODE_OF_CONDUCT.md
|
123
124
|
- Gemfile
|
124
125
|
- Guardfile
|
@@ -130,6 +131,7 @@ files:
|
|
130
131
|
- bin/setup
|
131
132
|
- json_schema-faker.gemspec
|
132
133
|
- lib/json_schema/faker.rb
|
134
|
+
- lib/json_schema/faker/strategy/simple.rb
|
133
135
|
homepage: https://github.com/okitan/json_schema-faker
|
134
136
|
licenses:
|
135
137
|
- MIT
|