json_check 0.0.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 +7 -0
- data/lib/json_check.rb +710 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 155a43ba532fc1253d8470bc7f727f6ea2e80a3f
|
4
|
+
data.tar.gz: 2ec63dd1523ec1f75f82acf5a168e60e92099c21
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 018e9c191ce7367b585d16a5b7f7e854640ff4edd0f00618ea1dcc75434f0ce311003eba0d7a95ff4e54205d91c7662340236793cab1a7a84b7c2def6913c4cb
|
7
|
+
data.tar.gz: de8091a6ef46c3da6db5e3347a8a3e5cabdc9a7c20fd0780bb1ae2c2d6f47c4aa9383ba36d1537765d6ff5c1b397e3a88a8c1ae2239b3c46434bdbbe7a66e778
|
data/lib/json_check.rb
ADDED
@@ -0,0 +1,710 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "json"
|
4
|
+
require "net/http"
|
5
|
+
require "uri"
|
6
|
+
|
7
|
+
module JSON_check
|
8
|
+
|
9
|
+
@@classes = [
|
10
|
+
'Integer',
|
11
|
+
'Float',
|
12
|
+
'String',
|
13
|
+
'Boolean',
|
14
|
+
'URL',
|
15
|
+
'Array',
|
16
|
+
'Hash',
|
17
|
+
'NULL'
|
18
|
+
]
|
19
|
+
|
20
|
+
@@permissible_params = {
|
21
|
+
'Integer' => ['null', 'required', 'enum', 'compare'],
|
22
|
+
'Float' => ['null', 'required', 'enum', 'compare'],
|
23
|
+
'String' => ['null', 'required', 'enum', 'mask'],
|
24
|
+
'Boolean' => ['null', 'required', 'enum'],
|
25
|
+
'URL' => ['null', 'required', 'mask'],
|
26
|
+
'Array' => ['null', 'required', 'empty', 'pattern', 'patterns'],
|
27
|
+
'Hash' => ['null', 'required', 'pattern', 'patterns', 'dynamic_key'],
|
28
|
+
'NULL' => ['required']
|
29
|
+
}
|
30
|
+
|
31
|
+
@@permissible_values = {
|
32
|
+
'null' => [true, false],
|
33
|
+
'required' => [true, false],
|
34
|
+
'enum' => Array,
|
35
|
+
'mask' => String,
|
36
|
+
'pattern' => Hash,
|
37
|
+
'patterns' => Array,
|
38
|
+
'empty' => [true, false],
|
39
|
+
'dynamic_key' => [true, false],
|
40
|
+
'compare' => /^(!=|<=|>=|==|<|>)(-?\d+\.\d+|-?\d+)( (or|and) (!=|<=|>=|==|<|>)(-?\d+\.\d+|-?\d+))?$/
|
41
|
+
}
|
42
|
+
|
43
|
+
@@valid_enum_classes = {
|
44
|
+
'Integer' => [Fixnum, Float],
|
45
|
+
'Float' => [Fixnum, Float],
|
46
|
+
'Boolean' => [FalseClass, TrueClass],
|
47
|
+
'String' => [String]
|
48
|
+
}
|
49
|
+
|
50
|
+
@@classes_of_types = {
|
51
|
+
'Integer' => [Fixnum],
|
52
|
+
'Float' => [Fixnum, Float],
|
53
|
+
'Boolean' => [FalseClass, TrueClass],
|
54
|
+
'String' => [String],
|
55
|
+
'URL' => [String],
|
56
|
+
'Hash' => [Hash],
|
57
|
+
'Array' => [Array],
|
58
|
+
'NULL' => [NilClass]
|
59
|
+
}
|
60
|
+
|
61
|
+
def self.associate patterns, json
|
62
|
+
matches = []
|
63
|
+
count = 0
|
64
|
+
patterns.each do |ptn|
|
65
|
+
ptn.each do |key, value|
|
66
|
+
if json.has_key?(key) and (@@classes_of_types[value['type']].include?(json[key].class) or (json[key].class == NilClass and value.has_key?('null') and value['null'] == true))
|
67
|
+
count += 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
matches << count
|
71
|
+
count = 0
|
72
|
+
end
|
73
|
+
return patterns[matches.rindex(matches.max)]
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.change_status
|
77
|
+
@@status = false
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.init
|
81
|
+
@@log = ""
|
82
|
+
@@print_level = 0
|
83
|
+
@@redirect_level = 0
|
84
|
+
@@log_level = 0
|
85
|
+
@@status = true
|
86
|
+
end
|
87
|
+
|
88
|
+
def self.collate json, pattern, log_level = 0
|
89
|
+
unless [0, 1].include? log_level
|
90
|
+
raise 'Invalid log_level parameter!'
|
91
|
+
end
|
92
|
+
init
|
93
|
+
@@log_level = log_level
|
94
|
+
begin
|
95
|
+
json = JSON.parse(json)
|
96
|
+
rescue
|
97
|
+
raise 'Invalid JSON format of input data'
|
98
|
+
end
|
99
|
+
begin
|
100
|
+
ptn = JSON.parse(pattern)
|
101
|
+
rescue
|
102
|
+
raise 'Invalid JSON format of pattern'
|
103
|
+
end
|
104
|
+
if ptn.class == Array
|
105
|
+
raise 'Invalid pattern' unless [1,2].include? ptn.size
|
106
|
+
raise 'Invalid pattern' if ptn.size == 2 and ![true, false, 'dynamic_key'].include? ptn[1]
|
107
|
+
check_pattern({"[:pattern:]" => ptn[0]})
|
108
|
+
else
|
109
|
+
check_pattern ptn
|
110
|
+
end
|
111
|
+
if ptn.class == Array
|
112
|
+
|
113
|
+
raise 'JSON not match the pattern!' if json.class != Array
|
114
|
+
|
115
|
+
if ptn[1] == false and json.size == 0
|
116
|
+
@@log += "[\n\n] <= This array must be not empty"
|
117
|
+
change_status
|
118
|
+
else
|
119
|
+
array json, ptn[0], false
|
120
|
+
end
|
121
|
+
else
|
122
|
+
pattern_keys = []
|
123
|
+
ptn.keys.each do |key|
|
124
|
+
unless ptn[key].has_key?('required') and ptn[key]['required'] == false
|
125
|
+
pattern_keys << key
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
json_keys = json.keys
|
130
|
+
|
131
|
+
if pattern_keys-json_keys == pattern_keys and !pattern_keys.empty?
|
132
|
+
raise 'JSON not match the pattern!'
|
133
|
+
end
|
134
|
+
|
135
|
+
@@log += "{\n"
|
136
|
+
@@print_level += 1
|
137
|
+
|
138
|
+
hash json, ptn
|
139
|
+
missing_keys json, ptn
|
140
|
+
|
141
|
+
@@print_level -= 1
|
142
|
+
@@log += "}"
|
143
|
+
end
|
144
|
+
unless @@status
|
145
|
+
raise "\n#{@@log}"
|
146
|
+
else
|
147
|
+
return true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def self.hash json, ptn, dynamic_key = nil
|
152
|
+
last = json.keys.size
|
153
|
+
num = 1
|
154
|
+
json.each do |key, value|
|
155
|
+
unless ptn.has_key?(key) or dynamic_key
|
156
|
+
add({key => value}, num != last, "Undefined key!")
|
157
|
+
change_status
|
158
|
+
else
|
159
|
+
if dynamic_key
|
160
|
+
regex = Regexp.new ptn.keys[0]
|
161
|
+
unless regex === key
|
162
|
+
add({key => value}, num != last, "This key does not satisfy the regular expression /#{ptn.keys[0]}/")
|
163
|
+
change_status
|
164
|
+
num += 1
|
165
|
+
next
|
166
|
+
end
|
167
|
+
c_p = ptn.values[0]
|
168
|
+
else
|
169
|
+
c_p = ptn[key] #current pattern
|
170
|
+
end
|
171
|
+
failure = false
|
172
|
+
case c_p['type']
|
173
|
+
when 'Integer'
|
174
|
+
unless check_int value, c_p["null"]
|
175
|
+
add({key=>value}, num != last, "It must be Integer")
|
176
|
+
failure = true
|
177
|
+
change_status
|
178
|
+
end
|
179
|
+
when 'Float'
|
180
|
+
unless check_float value, c_p["null"]
|
181
|
+
add({key=>value}, num != last, "It must be Float")
|
182
|
+
failure = true
|
183
|
+
change_status
|
184
|
+
end
|
185
|
+
when 'NULL'
|
186
|
+
if check_null value
|
187
|
+
add({key => value}, num != last)
|
188
|
+
else
|
189
|
+
add({key=>value}, num != last, "It must be null")
|
190
|
+
change_status
|
191
|
+
end
|
192
|
+
num += 1
|
193
|
+
next
|
194
|
+
when 'String'
|
195
|
+
unless check_str value, c_p["null"]
|
196
|
+
add({key=>value}, num != last, "It must be String")
|
197
|
+
failure = true
|
198
|
+
change_status
|
199
|
+
end
|
200
|
+
when 'Boolean'
|
201
|
+
unless check_bool value, c_p["null"]
|
202
|
+
add({key=>value}, num != last, "It must be Boolean")
|
203
|
+
failure = true
|
204
|
+
change_status
|
205
|
+
end
|
206
|
+
when 'URL'
|
207
|
+
unless check_url value, c_p["null"]
|
208
|
+
add({key=>value}, num != last, "It must be URL")
|
209
|
+
failure = true
|
210
|
+
change_status
|
211
|
+
end
|
212
|
+
unless failure or value.nil?
|
213
|
+
status = 0
|
214
|
+
attempt = 0
|
215
|
+
while status != 200 and attempt < 4
|
216
|
+
status = url_status(value)
|
217
|
+
attempt += 1
|
218
|
+
end
|
219
|
+
unless status == 200
|
220
|
+
failure = true
|
221
|
+
change_status
|
222
|
+
if status.class == String
|
223
|
+
add({key=>value}, num != last, "Error: #{status}")
|
224
|
+
elsif status == -1
|
225
|
+
add({key=>value}, num != last, "Too many redirect!")
|
226
|
+
else
|
227
|
+
add({key=>value}, num != last, "Status: #{status}")
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
when 'Array'
|
232
|
+
unless check_array value, c_p["null"]
|
233
|
+
add({key=>value}, num != last, "It must be Array")
|
234
|
+
failure = true
|
235
|
+
change_status
|
236
|
+
end
|
237
|
+
if value.nil? and !failure
|
238
|
+
add({key => value}, num != last)
|
239
|
+
num += 1
|
240
|
+
next
|
241
|
+
end
|
242
|
+
if c_p.has_key?('empty') and c_p['empty'] == false
|
243
|
+
if value.empty?
|
244
|
+
change_status
|
245
|
+
failure = true
|
246
|
+
add({key=>value}, num != last, "This array must not be empty")
|
247
|
+
end
|
248
|
+
end
|
249
|
+
unless failure
|
250
|
+
array value, (c_p.has_key?('pattern') ? c_p['pattern'] : c_p['patterns']), num != last, key
|
251
|
+
end
|
252
|
+
num += 1
|
253
|
+
next
|
254
|
+
when 'Hash'
|
255
|
+
unless check_hash value, c_p["null"]
|
256
|
+
add({key=>value}, num != last, "It must be Hash")
|
257
|
+
failure = true
|
258
|
+
change_status
|
259
|
+
end
|
260
|
+
if value.nil? and !failure
|
261
|
+
add({key => value}, num != last)
|
262
|
+
num += 1
|
263
|
+
next
|
264
|
+
end
|
265
|
+
unless failure
|
266
|
+
@@log += ' '*@@print_level+"\"#{key}\":{\n"
|
267
|
+
@@print_level += 1
|
268
|
+
if c_p.has_key?('patterns')
|
269
|
+
hash value, associate(c_p['patterns'], value)
|
270
|
+
else
|
271
|
+
hash value, c_p['pattern'], c_p['dynamic_key']
|
272
|
+
end
|
273
|
+
unless c_p['dynamic_key']
|
274
|
+
if c_p.has_key?('patterns')
|
275
|
+
missing_keys value, associate(c_p['patterns'], value)
|
276
|
+
else
|
277
|
+
missing_keys value, c_p['pattern']
|
278
|
+
end
|
279
|
+
end
|
280
|
+
@@print_level -= 1
|
281
|
+
@@log += ' '*@@print_level+"}#{num != last ? "," : ""}\n"
|
282
|
+
end
|
283
|
+
num += 1
|
284
|
+
next
|
285
|
+
end
|
286
|
+
|
287
|
+
#addition checks
|
288
|
+
unless failure
|
289
|
+
if c_p.has_key? 'enum'
|
290
|
+
unless enum value, c_p['enum']
|
291
|
+
add({key=>value}, num != last, "This value is not included in the list #{c_p['enum'].to_s}")
|
292
|
+
change_status
|
293
|
+
else
|
294
|
+
add({key => value}, num != last)
|
295
|
+
end
|
296
|
+
elsif c_p.has_key? 'compare'
|
297
|
+
next if value.nil?
|
298
|
+
unless compare value, c_p['compare']
|
299
|
+
add({key=>value}, num != last, "This value does not satisfy the condition #{c_p['compare']}")
|
300
|
+
change_status
|
301
|
+
else
|
302
|
+
add({key => value}, num != last)
|
303
|
+
end
|
304
|
+
elsif c_p.has_key? 'mask'
|
305
|
+
next if value.nil?
|
306
|
+
unless mask value, c_p['mask']
|
307
|
+
add({key => value}, num != last, "This value does not satisfy the regular expression \\#{c_p['mask']}\\")
|
308
|
+
change_status
|
309
|
+
else
|
310
|
+
add({key => value}, num != last)
|
311
|
+
end
|
312
|
+
else
|
313
|
+
add({key => value}, num != last)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|
318
|
+
num += 1
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def self.array json, ptn, comma, key=nil
|
323
|
+
last = json.size
|
324
|
+
ptn_list = ptn if ptn.class == Array
|
325
|
+
num = 1
|
326
|
+
if !ptn_list.nil? and ptn_list.size > json.size
|
327
|
+
add([json], num != last, "This array does not match the pattern")
|
328
|
+
change_status
|
329
|
+
failure = true
|
330
|
+
return
|
331
|
+
end
|
332
|
+
@@log += ' '*@@print_level+"#{key.nil? ? '' : wrap(key)+":"}[\n"
|
333
|
+
@@print_level += 1
|
334
|
+
json.each do |value|
|
335
|
+
failure = false
|
336
|
+
ptn = ptn_list[num-1] if ptn_list
|
337
|
+
if ptn.nil?
|
338
|
+
add([value], num != last, "This value is not included in the list of patterns")
|
339
|
+
change_status
|
340
|
+
failure = true
|
341
|
+
num += 1
|
342
|
+
next
|
343
|
+
end
|
344
|
+
case ptn['type']
|
345
|
+
when 'Integer'
|
346
|
+
unless check_int value, false
|
347
|
+
add([value], num != last, "It must be Integer")
|
348
|
+
failure = true
|
349
|
+
change_status
|
350
|
+
end
|
351
|
+
when 'Float'
|
352
|
+
unless check_float value,false
|
353
|
+
add([value], num != last, "It must be Float")
|
354
|
+
failure = true
|
355
|
+
change_status
|
356
|
+
end
|
357
|
+
when 'String'
|
358
|
+
unless check_str value, false
|
359
|
+
add([value], num != last, "It must be String")
|
360
|
+
failure = true
|
361
|
+
change_status
|
362
|
+
end
|
363
|
+
when 'Boolean'
|
364
|
+
unless check_bool value, false
|
365
|
+
add([value], num != last, "It must be Boolean")
|
366
|
+
failure = true
|
367
|
+
change_status
|
368
|
+
end
|
369
|
+
when 'URL'
|
370
|
+
unless check_url value, false
|
371
|
+
add([value], num != last, "It must be URL")
|
372
|
+
failure = true
|
373
|
+
change_status
|
374
|
+
end
|
375
|
+
unless failure
|
376
|
+
status = 0
|
377
|
+
attempt = 0
|
378
|
+
while status != 200 and attempt < 4
|
379
|
+
status = url_status(value)
|
380
|
+
attempt += 1
|
381
|
+
end
|
382
|
+
unless status == 200
|
383
|
+
failure = true
|
384
|
+
change_status
|
385
|
+
if status.class == String
|
386
|
+
add([value], num != last, "Error: #{status}")
|
387
|
+
elsif status == -1
|
388
|
+
add([value], num != last, "Too many redirect!")
|
389
|
+
else
|
390
|
+
add([value], num != last, "Status: #{status}")
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
when 'Array'
|
395
|
+
unless check_array value, false
|
396
|
+
add([value], num != last, "It must be Array")
|
397
|
+
failure = true
|
398
|
+
change_status
|
399
|
+
end
|
400
|
+
if ptn.has_key?('empty') and ptn['empty'] == false
|
401
|
+
if value.empty?
|
402
|
+
change_status
|
403
|
+
failure = true
|
404
|
+
add([[]], num != last, "This array must not be empty")
|
405
|
+
end
|
406
|
+
end
|
407
|
+
unless failure
|
408
|
+
array value, (ptn.has_key?('pattern') ? ptn['pattern'] : ptn['patterns']), num != last
|
409
|
+
end
|
410
|
+
num += 1
|
411
|
+
next
|
412
|
+
when 'Hash'
|
413
|
+
unless check_hash value, false
|
414
|
+
add([value], num != last, "It must be Hash")
|
415
|
+
failure = true
|
416
|
+
change_status
|
417
|
+
end
|
418
|
+
unless failure
|
419
|
+
@@log += ' '*@@print_level+"{\n"
|
420
|
+
@@print_level += 1
|
421
|
+
if ptn.has_key?('patterns')
|
422
|
+
hash value, associate(ptn['patterns'], value)
|
423
|
+
else
|
424
|
+
hash value, ptn['pattern'], ptn['dynamic_key']
|
425
|
+
end
|
426
|
+
unless ptn['dynamic_key']
|
427
|
+
if ptn.has_key?('patterns')
|
428
|
+
missing_keys value, associate(ptn['patterns'], value)
|
429
|
+
else
|
430
|
+
missing_keys value, ptn['pattern']
|
431
|
+
end
|
432
|
+
end
|
433
|
+
@@print_level -= 1
|
434
|
+
@@log += ' '*@@print_level+"}#{num != last ? "," : ""}\n"
|
435
|
+
end
|
436
|
+
num += 1
|
437
|
+
next
|
438
|
+
end
|
439
|
+
|
440
|
+
#addition checks
|
441
|
+
unless failure
|
442
|
+
if ptn.has_key? 'enum'
|
443
|
+
unless enum value, ptn['enum']
|
444
|
+
add([value], num != last, "This value is not included in the list #{ptn['enum'].to_s}")
|
445
|
+
change_status
|
446
|
+
else
|
447
|
+
add([value], num != last)
|
448
|
+
end
|
449
|
+
elsif ptn.has_key? 'compare'
|
450
|
+
if value.nil?
|
451
|
+
num += 1
|
452
|
+
next
|
453
|
+
end
|
454
|
+
unless compare value, ptn['compare']
|
455
|
+
add([value], num != last, "This value does not satisfy the condition #{ptn['compare']}")
|
456
|
+
change_status
|
457
|
+
else
|
458
|
+
add([value], num != last)
|
459
|
+
end
|
460
|
+
elsif ptn.has_key? 'mask'
|
461
|
+
next if value.nil?
|
462
|
+
unless mask value, ptn['mask']
|
463
|
+
add([value], num != last, "This value does not satisfy the regular expression \\#{ptn['mask']}\\")
|
464
|
+
change_status
|
465
|
+
else
|
466
|
+
add([value], num != last)
|
467
|
+
end
|
468
|
+
else
|
469
|
+
add([value], num != last)
|
470
|
+
end
|
471
|
+
end
|
472
|
+
num += 1
|
473
|
+
end
|
474
|
+
@@print_level -= 1
|
475
|
+
@@log += ' '*@@print_level+"]#{comma ? ',' : ''}\n"
|
476
|
+
end
|
477
|
+
|
478
|
+
def self.missing_keys json, ptn
|
479
|
+
keys = []
|
480
|
+
ptn.each_key do |key|
|
481
|
+
unless ptn[key].has_key?('required') and ptn[key]['required'] == false
|
482
|
+
keys << key
|
483
|
+
end
|
484
|
+
end
|
485
|
+
keys = keys - json.keys
|
486
|
+
if keys.size>0
|
487
|
+
change_status
|
488
|
+
keys.each do |key|
|
489
|
+
add({key => 'This key is declared, but not found!'}, true, "Key is missing!")
|
490
|
+
end
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
def self.add data, comma, message = nil
|
495
|
+
for_print = JSON.pretty_generate(data)
|
496
|
+
for_print.gsub! /^(\{\n|\[\n|\}|\])/, ""
|
497
|
+
for_print.gsub! /^[ ]{2}/, " "*@@print_level
|
498
|
+
for_print.gsub! /[ ]{2}/, " "
|
499
|
+
if message
|
500
|
+
lines = for_print.split("\n")
|
501
|
+
max_length = lines.max_by(&:length).length
|
502
|
+
if lines.size > 1
|
503
|
+
if comma
|
504
|
+
last_line = lines.pop
|
505
|
+
lines.push last_line+","
|
506
|
+
end
|
507
|
+
lines.collect! do |line|
|
508
|
+
line+" "*(max_length-line.length+1)+" #"
|
509
|
+
end
|
510
|
+
@@log += lines.join("\n") + " <= #{message}\n"
|
511
|
+
else
|
512
|
+
@@log += lines.join("\n") + (comma ? "," : "") + " <= #{message}\n"
|
513
|
+
end
|
514
|
+
else
|
515
|
+
@@log += for_print.chomp + (comma ? ",\n" : "\n")
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
def self.check_int arg, null
|
520
|
+
return true if null && arg.class == NilClass
|
521
|
+
return arg.class == Fixnum
|
522
|
+
end
|
523
|
+
|
524
|
+
def self.check_float arg, null
|
525
|
+
return true if null && arg.class == NilClass
|
526
|
+
return (arg.class == Float or arg.class == Fixnum)
|
527
|
+
end
|
528
|
+
|
529
|
+
def self.check_null arg
|
530
|
+
arg.class == NilClass
|
531
|
+
end
|
532
|
+
|
533
|
+
def self.check_str arg, null
|
534
|
+
return true if null && arg.class == NilClass
|
535
|
+
return arg.class == String
|
536
|
+
end
|
537
|
+
|
538
|
+
def self.check_bool arg, null
|
539
|
+
return true if null && arg.class == NilClass
|
540
|
+
return (arg.class == TrueClass or arg.class == FalseClass)
|
541
|
+
end
|
542
|
+
|
543
|
+
def self.check_url arg, null
|
544
|
+
return true if null && arg.class == NilClass
|
545
|
+
return false unless arg.class == String
|
546
|
+
# return true if arg == ""
|
547
|
+
return false unless /^((https?|ftp):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.?:-]*)*\/?$/ === arg
|
548
|
+
return true
|
549
|
+
end
|
550
|
+
|
551
|
+
def self.check_array arg, null
|
552
|
+
return true if null && arg.class == NilClass
|
553
|
+
arg.class == Array
|
554
|
+
end
|
555
|
+
|
556
|
+
def self.check_hash arg, null
|
557
|
+
return true if null && arg.class == NilClass
|
558
|
+
arg.class == Hash
|
559
|
+
end
|
560
|
+
|
561
|
+
def self.compare value, conditions
|
562
|
+
unless conditions.include?('or') or conditions.include?('and')
|
563
|
+
return compare_action value, conditions
|
564
|
+
else
|
565
|
+
result = false
|
566
|
+
or_parts = conditions.split(' or ')
|
567
|
+
or_parts.each do |part|
|
568
|
+
and_parts = part.split(' and ')
|
569
|
+
subresult = true
|
570
|
+
while and_parts.size != 0
|
571
|
+
condition = and_parts.shift
|
572
|
+
subresult &&= compare_action(value, condition)
|
573
|
+
end
|
574
|
+
result ||= subresult
|
575
|
+
end
|
576
|
+
return result
|
577
|
+
end
|
578
|
+
end
|
579
|
+
|
580
|
+
def self.compare_action value, condition
|
581
|
+
params = (/(!=|<=|>=|==|<|>)(-?\d+\.\d+|-?\d+)/.match condition).to_a
|
582
|
+
case params[1]
|
583
|
+
when '!='
|
584
|
+
value != params[2].to_f
|
585
|
+
when '<='
|
586
|
+
value <= params[2].to_f
|
587
|
+
when '>='
|
588
|
+
value >= params[2].to_f
|
589
|
+
when '=='
|
590
|
+
value == params[2].to_f
|
591
|
+
when '>'
|
592
|
+
value > params[2].to_f
|
593
|
+
when '<'
|
594
|
+
value < params[2].to_f
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
598
|
+
def self.enum value, list_of_values
|
599
|
+
list_of_values.include? value
|
600
|
+
end
|
601
|
+
|
602
|
+
def self.mask value, regex
|
603
|
+
mask = Regexp.new regex
|
604
|
+
return mask === value
|
605
|
+
end
|
606
|
+
|
607
|
+
def self.reset
|
608
|
+
@@redirect_level = 0
|
609
|
+
end
|
610
|
+
|
611
|
+
def self.url_status url
|
612
|
+
begin
|
613
|
+
link = URI.parse(url)
|
614
|
+
resp = Net::HTTP.start(link.host){|http|
|
615
|
+
http.read_timeout = 10
|
616
|
+
http.head(link)
|
617
|
+
}
|
618
|
+
http_status = resp.code.to_i
|
619
|
+
case http_status
|
620
|
+
when 200
|
621
|
+
reset
|
622
|
+
return 200
|
623
|
+
when 302, 301
|
624
|
+
@@redirect_level += 1
|
625
|
+
if @@redirect_level > 10
|
626
|
+
reset
|
627
|
+
return -1
|
628
|
+
end
|
629
|
+
tmp_url = resp['location']
|
630
|
+
tmp_link = URI.parse(tmp_url)
|
631
|
+
if tmp_link.host == nil
|
632
|
+
tmp_url = link.scheme+'://'+link.host+tmp_url
|
633
|
+
end
|
634
|
+
return url_status tmp_url
|
635
|
+
else
|
636
|
+
reset
|
637
|
+
return http_status
|
638
|
+
end
|
639
|
+
rescue Exception => e
|
640
|
+
reset
|
641
|
+
return e.to_s
|
642
|
+
end
|
643
|
+
end
|
644
|
+
|
645
|
+
def self.check_pattern ptn, subkey = nil
|
646
|
+
raise "Invalid pattert" if ptn.keys.size == 0
|
647
|
+
ptn.each do |key, value|
|
648
|
+
if value.class != Hash
|
649
|
+
raise "Invalid pattern"
|
650
|
+
end
|
651
|
+
unless value.has_key? 'type'
|
652
|
+
raise "Type is not decleared for #{wrap(subkey.to_s+key)}" # тип должен быть указан для всех ключей
|
653
|
+
end
|
654
|
+
unless @@classes.include? value['type']
|
655
|
+
raise "Invalid type value #{wrap(value['type'])} for #{wrap(subkey.to_s+key)}" # тип должен быть валидным
|
656
|
+
end
|
657
|
+
keys = value.keys - ['type'] - @@permissible_params[value['type']]
|
658
|
+
raise "Invalid key(s) \"#{keys.join('", "')}\" for #{wrap(subkey.to_s+key)}" unless keys.empty?
|
659
|
+
raise "Pattern is not decleared for \"#{subkey.to_s+key}\"" if ['Hash', 'Array'].include?(value['type']) and !(value.has_key?('pattern') or value.has_key?('patterns'))
|
660
|
+
keys = value.keys - ['type']
|
661
|
+
keys.each do |i|
|
662
|
+
mask = @@permissible_values[i]
|
663
|
+
failure = false
|
664
|
+
case mask.class.to_s
|
665
|
+
when 'Array'
|
666
|
+
failure = true unless mask.include?(value[i])
|
667
|
+
when 'Class'
|
668
|
+
failure = true unless mask == value[i].class
|
669
|
+
if i == 'enum' and !failure
|
670
|
+
raise "Empty enum array for #{wrap(subkey.to_s+key)}" if value[i].size == 0
|
671
|
+
value[i].each do |elem|
|
672
|
+
raise "Invalid value #{wrap(elem)} in enum for #{wrap(subkey.to_s+key)}" unless (@@valid_enum_classes[value['type']]+((value.has_key?("null") and value['null'] == true) ? [NilClass] : [])).include?(elem.class)
|
673
|
+
end
|
674
|
+
end
|
675
|
+
if i == 'pattern' and !failure
|
676
|
+
if value['type'] == 'Hash'
|
677
|
+
check_pattern value['pattern'], "#{subkey ? subkey.to_s+" > " : ""}#{key} > "
|
678
|
+
if value.has_key?('dynamic_key') and value['dynamic_key']
|
679
|
+
raise "Hash with dynamic_key=true must has one key in pattern" if value['pattern'].keys.size != 1
|
680
|
+
raise "Invalid dynamic key value #{value['pattern'].keys[0]}" unless value['pattern'].keys[0].class == String and check_regex value['pattern'].keys[0]
|
681
|
+
end
|
682
|
+
else
|
683
|
+
check_pattern({"[:pattern:]" => value['pattern']}, "#{subkey ? subkey.to_s+" > " : ""}#{key} > ")
|
684
|
+
end
|
685
|
+
end
|
686
|
+
if i == 'mask'
|
687
|
+
raise "Invalid value #{wrap(value['mask'])} of mask for #{wrap(subkey.to_s+key)}" unless check_regex value['mask']
|
688
|
+
end
|
689
|
+
when 'Regexp'
|
690
|
+
failure = true unless (value[i].class == String and mask === value[i])
|
691
|
+
end
|
692
|
+
raise "Invalid value #{wrap(value[i])} of \"#{i}\" for \"#{subkey.to_s+key}\"" if failure
|
693
|
+
end
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
def self.wrap val
|
698
|
+
val.nil? ? 'null' : (val.class == String ? '"'+val+'"': val.to_s )
|
699
|
+
end
|
700
|
+
|
701
|
+
def self.check_regex val
|
702
|
+
begin
|
703
|
+
Regexp.new val
|
704
|
+
rescue
|
705
|
+
return false
|
706
|
+
end
|
707
|
+
return true
|
708
|
+
end
|
709
|
+
|
710
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json_check
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Motin Artem
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-06-15 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.8.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.8'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.8.1
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.6'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.6'
|
47
|
+
description: ''
|
48
|
+
email:
|
49
|
+
- a.motin@inventos.ru
|
50
|
+
executables: []
|
51
|
+
extensions: []
|
52
|
+
extra_rdoc_files: []
|
53
|
+
files:
|
54
|
+
- lib/json_check.rb
|
55
|
+
homepage:
|
56
|
+
licenses:
|
57
|
+
- MIT
|
58
|
+
metadata: {}
|
59
|
+
post_install_message:
|
60
|
+
rdoc_options: []
|
61
|
+
require_paths:
|
62
|
+
- lib
|
63
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
requirements:
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '0'
|
73
|
+
requirements: []
|
74
|
+
rubyforge_project:
|
75
|
+
rubygems_version: 2.4.5
|
76
|
+
signing_key:
|
77
|
+
specification_version: 4
|
78
|
+
summary: Gem for check JSON.
|
79
|
+
test_files: []
|
80
|
+
has_rdoc:
|