sk-api 1.0.0

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.
@@ -0,0 +1,434 @@
1
+ # vim: fileencoding=utf-8
2
+
3
+ module JSON
4
+ class Schema
5
+ VERSION = '1.0.0'
6
+ class ValueError < Exception;end
7
+ TypesMap = {
8
+ "string" => String,
9
+ "integer" => Integer,
10
+ "number" => [Integer, Float],
11
+ "boolean" => [TrueClass, FalseClass],
12
+ "object" => Hash,
13
+ "array" => Array,
14
+ "null" => NilClass,
15
+ "any" => nil
16
+ }
17
+ TypesList = [String, Integer, Float, TrueClass, FalseClass, Hash, Array, NilClass]
18
+ DefaultSchema = {
19
+ "id" => nil,
20
+ "type" => nil,
21
+ "properties" => nil,
22
+ "items" => nil,
23
+ "optional" => false,
24
+ "additionalProperties" => nil,
25
+ "requires" => nil,
26
+ "identity" => nil,
27
+ "minimum" => nil,
28
+ "maximum" => nil,
29
+ "minItems" => nil,
30
+ "maxItems" => nil,
31
+ "pattern" => nil,
32
+ "maxLength" => nil,
33
+ "minLength" => nil,
34
+ "enum" => nil,
35
+ "options" => nil,
36
+ "readonly" => nil,
37
+ "title" => nil,
38
+ "description" => nil,
39
+ "format" => nil,
40
+ "default" => nil,
41
+ "transient" => nil,
42
+ "maxDecimal" => nil,
43
+ "hidden" => nil,
44
+ "disallow" => nil,
45
+ "extends" => nil
46
+ }
47
+ def initialize interactive=true
48
+ @interactive = interactive
49
+ @refmap = {}
50
+ end
51
+
52
+ def validate data, schema
53
+ @refmap = {
54
+ '$' => schema
55
+ }
56
+ _validate(data, schema)
57
+ end
58
+
59
+ private
60
+ def validate_id x, fieldname, schema, id=nil
61
+ unless id.nil?
62
+ if id == '$'
63
+ raise ValueError, "Reference id for field '#{fieldname}' cannot equal '$'"
64
+ end
65
+ @refmap[id] = schema
66
+ end
67
+ return x
68
+ end
69
+
70
+ def validate_type x, fieldname, schema, fieldtype=nil
71
+ converted_fieldtype = convert_type(fieldtype)
72
+ fieldexists = true
73
+ begin
74
+ val = x.fetch(fieldname)
75
+ rescue IndexError
76
+ fieldexists = false
77
+ ensure
78
+ val = x[fieldname]
79
+ end
80
+
81
+ if converted_fieldtype && fieldexists
82
+ # fld is optional, type is not nil, and field is nil
83
+ return x if val == nil && schema['optional'] && converted_fieldtype != NilClass
84
+ if converted_fieldtype.kind_of? Array
85
+ datavalid = false
86
+ converted_fieldtype.each do |type|
87
+ begin
88
+ validate_type(x, fieldname, type, type)
89
+ datavalid = true
90
+ break
91
+ rescue ValueError
92
+ next
93
+ end
94
+ end
95
+ unless datavalid
96
+ raise ValueError, "Value #{val} for field '#{fieldname}' is not of type #{fieldtype}"
97
+ end
98
+ elsif converted_fieldtype.kind_of? Hash
99
+ begin
100
+ __validate(fieldname, x, converted_fieldtype)
101
+ rescue ValueError => e
102
+ raise e
103
+ end
104
+ else
105
+ unless val.kind_of? converted_fieldtype
106
+ raise ValueError, "Value #{val} for field '#{fieldname}' is not of type #{fieldtype}"
107
+ end
108
+ end
109
+ end
110
+ return x
111
+ end
112
+
113
+ def validate_properties x, fieldname, schema, properties=nil
114
+ if !properties.nil? && x[fieldname]
115
+ value = x[fieldname]
116
+ if value
117
+ if value.kind_of? Hash
118
+ if properties.kind_of? Hash
119
+ properties.each do |key, val|
120
+ __validate(key, value, val)
121
+ end
122
+ else
123
+ raise ValueError, "Properties definition of field '#{fieldname}' is not an object"
124
+ end
125
+ end
126
+ end
127
+ end
128
+ return x
129
+ end
130
+
131
+ def validate_items x, fieldname, schema, items=nil
132
+ if !items.nil? && x[fieldname]
133
+ value = x[fieldname]
134
+ unless value.nil?
135
+ if value.kind_of? Array
136
+ if items.kind_of? Array
137
+ if items.size == value.size
138
+ items.each_with_index do |item, index|
139
+ begin
140
+ validate(value[index], item)
141
+ rescue ValueError => e
142
+ raise ValueError, "Failed to validate field '#{fieldname}' list schema: #{e.message}"
143
+ end
144
+ end
145
+ else
146
+ raise ValueError, "Length of list #{value} for field '#{fieldname}' is not equal to length of schema list"
147
+ end
148
+ elsif items.kind_of? Hash
149
+ value.each do |val|
150
+ begin
151
+ _validate(val, items)
152
+ rescue ValueError => e
153
+ raise ValueError, "Failed to validate field '#{fieldname}' list schema: #{e.message}"
154
+ end
155
+ end
156
+ else
157
+ raise ValueError, "Properties definition of field '#{fieldname}' is not a list or an object"
158
+ end
159
+ end
160
+ end
161
+ end
162
+ return x
163
+ end
164
+
165
+ def validate_optional x, fieldname, schema, optional=false
166
+ if !x.include?(fieldname) && !optional
167
+ raise ValueError, "Required field '#{fieldname}' is missing"
168
+ end
169
+ return x
170
+ end
171
+
172
+ def validate_additionalProperties x, fieldname, schema, additional_properties=nil
173
+ unless additional_properties.nil?
174
+ if additional_properties.kind_of? TrueClass
175
+ return x
176
+ end
177
+ value = x[fieldname]
178
+ if additional_properties.kind_of?(Hash) || additional_properties.kind_of?(FalseClass)
179
+ properties = schema["properties"]
180
+ unless properties
181
+ properties = {}
182
+ end
183
+ value.keys.each do |key|
184
+ unless properties.include? key
185
+ if additional_properties.kind_of? FalseClass
186
+ raise ValueError, "Additional properties not defined by 'properties' are not allowed in field '#{fieldname}'"
187
+ else
188
+ __validate(key, value, additional_properties)
189
+ end
190
+ end
191
+ end
192
+ else
193
+ raise ValueError, "additionalProperties schema definition for field '#{fieldname}' is not an object"
194
+ end
195
+ end
196
+ return x
197
+ end
198
+
199
+ def validate_requires x, fieldname, schema, requires=nil
200
+ if x[fieldname] && !requires.nil?
201
+ unless x[requires]
202
+ raise ValueError, "Field '#{requires}' is required by field '#{fieldname}'"
203
+ end
204
+ end
205
+ return x
206
+ end
207
+
208
+ def validate_identity x, fieldname, schema, unique=false
209
+ return x
210
+ end
211
+
212
+ def validate_minimum x, fieldname, schema, minimum=nil
213
+ if !minimum.nil? && x[fieldname]
214
+ value = x[fieldname]
215
+ if value
216
+ if (value.kind_of?(Integer) || value.kind_of?(Float)) && value < minimum
217
+ raise ValueError, "Value #{value} for field '#{fieldname}' is less than minimum value: #{minimum}"
218
+ elsif value.kind_of?(Array) && value.size < minimum
219
+ raise ValueError, "Value #{value} for field '#{fieldname}' has fewer values than the minimum: #{minimum}"
220
+ end
221
+ end
222
+ end
223
+ return x
224
+ end
225
+
226
+ def validate_maximum x, fieldname, schema, maximum=nil
227
+ if !maximum.nil? && x[fieldname]
228
+ value = x[fieldname]
229
+ if value
230
+ if (value.kind_of?(Integer) || value.kind_of?(Float)) && value > maximum
231
+ raise ValueError, "Value #{value} for field '#{fieldname}' is greater than maximum value: #{maximum}"
232
+ elsif value.kind_of?(Array) && value.size > maximum
233
+ raise ValueError, "Value #{value} for field '#{fieldname}' has more values than the maximum: #{maximum}"
234
+ end
235
+ end
236
+ end
237
+ return x
238
+ end
239
+
240
+ def validate_minItems x, fieldname, schema, minitems=nil
241
+ if !minitems.nil? && x[fieldname]
242
+ value = x[fieldname]
243
+ if value
244
+ if value.kind_of?(Array) && value.size < minitems
245
+ raise ValueError, "Value #{value} for field '#{fieldname}' must have a minimum of #{minitems} items"
246
+ end
247
+ end
248
+ end
249
+ return x
250
+ end
251
+
252
+ def validate_maxItems x, fieldname, schema, maxitems=nil
253
+ if !maxitems.nil? && x[fieldname]
254
+ value = x[fieldname]
255
+ if value
256
+ if value.kind_of?(Array) && value.size > maxitems
257
+ raise ValueError, "Value #{value} for field '#{fieldname}' must have a maximum of #{maxitems} items"
258
+ end
259
+ end
260
+ end
261
+ return x
262
+ end
263
+
264
+ def validate_pattern x, fieldname, schema, pattern=nil
265
+ value = x[fieldname]
266
+ if !pattern.nil? && value && value.kind_of?(String)
267
+ p = Regexp.new(pattern)
268
+ if !p.match(value)
269
+ raise ValueError, "Value #{value} for field '#{fieldname}' does not match regular expression '#{pattern}'"
270
+ end
271
+ end
272
+ return x
273
+ end
274
+
275
+ def validate_maxLength x, fieldname, schema, length=nil
276
+ value = x[fieldname]
277
+ if !length.nil? && value && value.kind_of?(String)
278
+ # string length => 正規表現で分割して計測
279
+ if value.split(//).size > length
280
+ raise ValueError, "Length of value #{value} for field '#{fieldname}' must be less than or equal to #{length}"
281
+ end
282
+ end
283
+ return x
284
+ end
285
+
286
+ def validate_minLength x, fieldname, schema, length=nil
287
+ value = x[fieldname]
288
+ if !length.nil? && value && value.kind_of?(String)
289
+ if value.split(//).size < length
290
+ raise ValueError, "Length of value #{value} for field '#{fieldname}' must be more than or equal to #{length}"
291
+ end
292
+ end
293
+ return x
294
+ end
295
+
296
+ def validate_enum x, fieldname, schema, options=nil
297
+ value = x[fieldname]
298
+ if !options.nil? && value
299
+ unless options.kind_of? Array
300
+ raise ValueError, "Enumeration #{options} for field '#{fieldname}' is not a list type"
301
+ end
302
+ unless options.include? value
303
+ raise ValueError, "Value #{value} for field '#{fieldname}' is not in the enumeration: #{options}"
304
+ end
305
+ end
306
+ return x
307
+ end
308
+
309
+ def validate_options x, fieldname, schema, options=nil
310
+ return x
311
+ end
312
+
313
+ def validate_readonly x, fieldname, schema, readonly=false
314
+ return x
315
+ end
316
+
317
+ def validate_title x, fieldname, schema, title=nil
318
+ if !title.nil? && !title.kind_of?(String)
319
+ raise ValueError, "The title for field '#{fieldname}' must be a string"
320
+ end
321
+ return x
322
+ end
323
+
324
+ def validate_description x, fieldname, schema, description=nil
325
+ if !description.nil? && !description.kind_of?(String)
326
+ raise ValueError, "The description for field '#{fieldname}' must be a string"
327
+ end
328
+ return x
329
+ end
330
+
331
+ def validate_format x, fieldname, schema, format=nil
332
+ return x
333
+ end
334
+
335
+ def validate_default x, fieldname, schema, default=nil
336
+ if @interactive && !x.include?(fieldname) && !default.nil?
337
+ unless schema["readonly"]
338
+ x[fieldname] = default
339
+ end
340
+ end
341
+ return x
342
+ end
343
+
344
+ def validate_transient x, fieldname, schema, transient=false
345
+ return x
346
+ end
347
+
348
+ def validate_maxDecimal x, fieldname, schema, maxdecimal=nil
349
+ value = x[fieldname]
350
+ if !maxdecimal.nil? && value
351
+ maxdecstring = value.to_s
352
+ index = maxdecstring.index('.')
353
+ if index && maxdecstring[(index+1)...maxdecstring.size].split(//u).size > maxdecimal
354
+ raise ValueError, "Value #{value} for field '#{fieldname}' must not have more than #{maxdecimal} decimal places"
355
+ end
356
+ end
357
+ return x
358
+ end
359
+
360
+ def validate_hidden x, fieldname, schema, hidden=false
361
+ return x
362
+ end
363
+
364
+ def validate_disallow x, fieldname, schema, disallow=nil
365
+ if !disallow.nil?
366
+ begin
367
+ validate_type(x, fieldname, schema, disallow)
368
+ rescue ValueError
369
+ return x
370
+ end
371
+ raise ValueError, "Value #{x[fieldname]} of type #{disallow} is disallowed for field '#{fieldname}'"
372
+ end
373
+ return x
374
+ end
375
+
376
+ def validate_extends x, fieldname, schema, extends=nil
377
+ return x
378
+ end
379
+
380
+ def convert_type fieldtype
381
+ if TypesList.include?(fieldtype) || fieldtype.kind_of?(Hash)
382
+ return fieldtype
383
+ elsif fieldtype.kind_of? Array
384
+ converted_fields = []
385
+ fieldtype.each do |subfieldtype|
386
+ converted_fields << convert_type(subfieldtype)
387
+ end
388
+ return converted_fields
389
+ elsif !fieldtype
390
+ return nil
391
+ else
392
+ fieldtype = fieldtype.to_s
393
+ if TypesMap.include?(fieldtype)
394
+ return TypesMap[fieldtype]
395
+ else
396
+ raise ValueError, "Field type '#{fieldtype}' is not supported."
397
+ end
398
+ end
399
+ end
400
+
401
+ def __validate fieldname, data, schema
402
+ if schema
403
+ if !schema.kind_of?(Hash)
404
+ raise ValueError, "Schema structure is invalid"
405
+ end
406
+ # copy
407
+ new_schema = Marshal.load(Marshal.dump(schema))
408
+ DefaultSchema.each do |key, val|
409
+ new_schema[key] = val unless new_schema.include?(key)
410
+ end
411
+ new_schema.each do |key ,val|
412
+ validatorname = "validate_"+key
413
+ begin
414
+ __send__(validatorname, data, fieldname, schema, new_schema[key])
415
+ rescue NoMethodError => e
416
+ raise ValueError, "Schema property '#{e.message}' is not supported"
417
+ end
418
+ end
419
+ end
420
+ return data
421
+ end
422
+
423
+ def _validate data, schema
424
+ __validate("_data", {"_data" => data}, schema)
425
+ end
426
+
427
+ class << self
428
+ def validate data, schema, interactive=true
429
+ validator = JSON::Schema.new(interactive)
430
+ validator.validate(data, schema)
431
+ end
432
+ end
433
+ end
434
+ end
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{jsonschema}
5
+ s.version = "1.0.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Constellation"]
9
+ s.date = %q{2009-09-13}
10
+ s.description = %q{json schema library ruby porting from http://code.google.com/p/jsonschema/}
11
+ s.email = %q{utatane.tea@gmail.com}
12
+ s.extra_rdoc_files = ["README.rdoc"]
13
+ s.files = ["README.rdoc", "Rakefile", "test/jsonschema_test.rb", "lib/jsonschema.rb"]
14
+ s.homepage = %q{http://github.com/Constellation/jsonschema/tree/master}
15
+ s.rdoc_options = ["--main", "README.rdoc", "--charset", "utf-8", "--line-numbers", "--inline-source"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{jsonschema}
18
+ s.rubygems_version = %q{1.3.5}
19
+ s.summary = %q{json schema library ruby porting from http://code.google.com/p/jsonschema/}
20
+ s.test_files = ["test/jsonschema_test.rb"]
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ else
28
+ end
29
+ else
30
+ end
31
+ end