json-schema 0.9.1 → 0.9.2
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.
- data/lib/json-schema/attributes/format.rb +68 -68
- data/test/test_jsonschema_draft1.rb +3 -60
- data/test/test_jsonschema_draft2.rb +3 -60
- data/test/test_jsonschema_draft3.rb +5 -70
- metadata +4 -5
- data/lib/json-schema/validator.rb.orig +0 -391
@@ -6,98 +6,98 @@ module JSON
|
|
6
6
|
|
7
7
|
# Timestamp in restricted ISO-8601 YYYY-MM-DDThh:mm:ssZ
|
8
8
|
when 'date-time'
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
9
|
+
if data.is_a?(String)
|
10
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a date/time in the ISO-8601 format of YYYY-MM-DDThh:mm:ssZ"
|
11
|
+
raise ValidationError.new(error_message, fragments, current_schema) if !data.is_a?(String)
|
12
|
+
r = Regexp.new('^\d\d\d\d-\d\d-\d\dT(\d\d):(\d\d):(\d\d)Z$')
|
13
|
+
if (m = r.match(data))
|
14
|
+
parts = data.split("T")
|
15
|
+
begin
|
16
|
+
Date.parse(parts[0])
|
17
|
+
rescue Exception
|
18
|
+
raise ValidationError.new(error_message, fragments, current_schema)
|
19
|
+
end
|
20
|
+
begin
|
21
|
+
raise ValidationError.new(error_message, fragments, current_schema) if m[1].to_i > 23
|
22
|
+
raise ValidationError.new(error_message, fragments, current_schema) if m[2].to_i > 59
|
23
|
+
raise ValidationError.new(error_message, fragments, current_schema) if m[3].to_i > 59
|
24
|
+
rescue Exception
|
25
|
+
raise ValidationError.new(error_message, fragments, current_schema)
|
26
|
+
end
|
27
|
+
else
|
24
28
|
raise ValidationError.new(error_message, fragments, current_schema)
|
25
29
|
end
|
26
|
-
else
|
27
|
-
raise ValidationError.new(error_message, fragments, current_schema)
|
28
30
|
end
|
29
31
|
|
30
32
|
# Date in the format of YYYY-MM-DD
|
31
33
|
when 'date'
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
if data.is_a?(String)
|
35
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a date in the format of YYYY-MM-DD"
|
36
|
+
raise ValidationError.new(error_message, fragments, current_schema) if !data.is_a?(String)
|
37
|
+
r = Regexp.new('^\d\d\d\d-\d\d-\d\d$')
|
38
|
+
if (m = r.match(data))
|
39
|
+
begin
|
40
|
+
Date.parse(data)
|
41
|
+
rescue Exception
|
42
|
+
raise ValidationError.new(error_message, fragments, current_schema)
|
43
|
+
end
|
44
|
+
else
|
39
45
|
raise ValidationError.new(error_message, fragments, current_schema)
|
40
46
|
end
|
41
|
-
else
|
42
|
-
raise ValidationError.new(error_message, fragments, current_schema)
|
43
47
|
end
|
44
48
|
|
45
49
|
# Time in the format of HH:MM:SS
|
46
50
|
when 'time'
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
51
|
+
if data.is_a?(String)
|
52
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a time in the format of hh:mm:ss"
|
53
|
+
raise ValidationError.new(error_message, fragments, current_schema) if !data.is_a?(String)
|
54
|
+
r = Regexp.new('^(\d\d):(\d\d):(\d\d)$')
|
55
|
+
if (m = r.match(data))
|
56
|
+
raise ValidationError.new(error_message, fragments, current_schema) if m[1].to_i > 23
|
57
|
+
raise ValidationError.new(error_message, fragments, current_schema) if m[2].to_i > 59
|
58
|
+
raise ValidationError.new(error_message, fragments, current_schema) if m[3].to_i > 59
|
59
|
+
else
|
60
|
+
raise ValidationError.new(error_message, fragments, current_schema)
|
61
|
+
end
|
56
62
|
end
|
57
63
|
|
58
64
|
# IPv4 in dotted-quad format
|
59
65
|
when 'ip-address', 'ipv4'
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
+
if data.is_a?(String)
|
67
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a valid IPv4 address"
|
68
|
+
raise ValidationError.new(error_message, fragments, current_schema) if !data.is_a?(String)
|
69
|
+
r = Regexp.new('^(\d+){1,3}\.(\d+){1,3}\.(\d+){1,3}\.(\d+){1,3}$')
|
70
|
+
if (m = r.match(data))
|
71
|
+
1.upto(4) do |x|
|
72
|
+
raise ValidationError.new(error_message, fragments, current_schema) if m[x].to_i > 255
|
73
|
+
end
|
74
|
+
else
|
75
|
+
raise ValidationError.new(error_message, fragments, current_schema)
|
66
76
|
end
|
67
|
-
else
|
68
|
-
raise ValidationError.new(error_message, fragments, current_schema)
|
69
77
|
end
|
70
78
|
|
71
79
|
# IPv6 in standard format (including abbreviations)
|
72
80
|
when 'ipv6'
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
if data.is_a?(String)
|
82
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a valid IPv6 address"
|
83
|
+
raise ValidationError.new(error_message, fragments, current_schema) if !data.is_a?(String)
|
84
|
+
r = Regexp.new('^[a-f0-9:]+$')
|
85
|
+
if (m = r.match(data))
|
86
|
+
# All characters are valid, now validate structure
|
87
|
+
parts = data.split(":")
|
88
|
+
raise ValidationError.new(error_message, fragments, current_schema) if parts.length > 8
|
89
|
+
condensed_zeros = false
|
90
|
+
parts.each do |part|
|
91
|
+
if part.length == 0
|
92
|
+
raise ValidationError.new(error_message, fragments, current_schema) if condensed_zeros
|
93
|
+
condensed_zeros = true
|
94
|
+
end
|
95
|
+
raise ValidationError.new(error_message, fragments, current_schema) if part.length > 4
|
85
96
|
end
|
86
|
-
|
97
|
+
else
|
98
|
+
raise ValidationError.new(error_message, fragments, current_schema)
|
87
99
|
end
|
88
|
-
else
|
89
|
-
raise ValidationError.new(error_message, fragments, current_schema)
|
90
100
|
end
|
91
|
-
|
92
|
-
# Milliseconds since the epoch. Must be an integer or a float
|
93
|
-
when 'utc-millisec'
|
94
|
-
error_message = "The property '#{build_fragment(fragments)}' must be an integer or a float"
|
95
|
-
raise ValidationError.new(error_message, fragments, current_schema) if (!data.is_a?(Numeric))
|
96
|
-
|
97
|
-
# Must be a string
|
98
|
-
when 'regex','color','style','phone','uri','email','host-name'
|
99
|
-
error_message = "The property '#{build_fragment(fragments)}' must be a string"
|
100
|
-
raise ValidationError.new(error_message, fragments, current_schema) if (!data.is_a?(String))
|
101
101
|
end
|
102
102
|
end
|
103
103
|
end
|
@@ -687,73 +687,16 @@ class JSONSchemaDraft1Test < Test::Unit::TestCase
|
|
687
687
|
end
|
688
688
|
|
689
689
|
|
690
|
-
def
|
690
|
+
def test_format_union
|
691
691
|
data1 = {"a" => "boo"}
|
692
|
-
data2 = {"a" =>
|
692
|
+
data2 = {"a" => nil}
|
693
693
|
|
694
694
|
schema = {
|
695
695
|
"type" => "object",
|
696
|
-
"properties" => { "a" => {"format" => "
|
697
|
-
}
|
698
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft1))
|
699
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft1))
|
700
|
-
|
701
|
-
schema = {
|
702
|
-
"type" => "object",
|
703
|
-
"properties" => { "a" => {"format" => "color"}}
|
704
|
-
}
|
705
|
-
assert(JSON::Validator.validate(schema,data1))
|
706
|
-
assert(!JSON::Validator.validate(schema,data2))
|
707
|
-
|
708
|
-
schema = {
|
709
|
-
"type" => "object",
|
710
|
-
"properties" => { "a" => {"format" => "style"}}
|
711
|
-
}
|
712
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft1))
|
713
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft1))
|
714
|
-
|
715
|
-
schema = {
|
716
|
-
"type" => "object",
|
717
|
-
"properties" => { "a" => {"format" => "phone"}}
|
718
|
-
}
|
719
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft1))
|
720
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft1))
|
721
|
-
|
722
|
-
schema = {
|
723
|
-
"type" => "object",
|
724
|
-
"properties" => { "a" => {"format" => "uri"}}
|
725
|
-
}
|
726
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft1))
|
727
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft1))
|
728
|
-
|
729
|
-
schema = {
|
730
|
-
"type" => "object",
|
731
|
-
"properties" => { "a" => {"format" => "email"}}
|
732
|
-
}
|
733
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft1))
|
734
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft1))
|
735
|
-
|
736
|
-
schema = {
|
737
|
-
"type" => "object",
|
738
|
-
"properties" => { "a" => {"format" => "host-name"}}
|
739
|
-
}
|
740
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft1))
|
741
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft1))
|
742
|
-
end
|
743
|
-
|
744
|
-
|
745
|
-
def test_format_numeric
|
746
|
-
data1 = {"a" => "boo"}
|
747
|
-
data2 = {"a" => 5}
|
748
|
-
data3 = {"a" => 5.4}
|
749
|
-
|
750
|
-
schema = {
|
751
|
-
"type" => "object",
|
752
|
-
"properties" => { "a" => {"format" => "utc-millisec"}}
|
696
|
+
"properties" => { "a" => {"type" => ["string","null"], "format" => "ip-address"}}
|
753
697
|
}
|
754
698
|
assert(!JSON::Validator.validate(schema,data1,:version => :draft1))
|
755
699
|
assert(JSON::Validator.validate(schema,data2,:version => :draft1))
|
756
|
-
assert(JSON::Validator.validate(schema,data3,:version => :draft1))
|
757
700
|
end
|
758
701
|
|
759
702
|
end
|
@@ -759,73 +759,16 @@ class JSONSchemaDraft2Test < Test::Unit::TestCase
|
|
759
759
|
end
|
760
760
|
|
761
761
|
|
762
|
-
def
|
762
|
+
def test_format_union
|
763
763
|
data1 = {"a" => "boo"}
|
764
|
-
data2 = {"a" =>
|
764
|
+
data2 = {"a" => nil}
|
765
765
|
|
766
766
|
schema = {
|
767
767
|
"type" => "object",
|
768
|
-
"properties" => { "a" => {"format" => "
|
769
|
-
}
|
770
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft2))
|
771
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft2))
|
772
|
-
|
773
|
-
schema = {
|
774
|
-
"type" => "object",
|
775
|
-
"properties" => { "a" => {"format" => "color"}}
|
776
|
-
}
|
777
|
-
assert(JSON::Validator.validate(schema,data1))
|
778
|
-
assert(!JSON::Validator.validate(schema,data2))
|
779
|
-
|
780
|
-
schema = {
|
781
|
-
"type" => "object",
|
782
|
-
"properties" => { "a" => {"format" => "style"}}
|
783
|
-
}
|
784
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft2))
|
785
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft2))
|
786
|
-
|
787
|
-
schema = {
|
788
|
-
"type" => "object",
|
789
|
-
"properties" => { "a" => {"format" => "phone"}}
|
790
|
-
}
|
791
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft2))
|
792
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft2))
|
793
|
-
|
794
|
-
schema = {
|
795
|
-
"type" => "object",
|
796
|
-
"properties" => { "a" => {"format" => "uri"}}
|
797
|
-
}
|
798
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft2))
|
799
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft2))
|
800
|
-
|
801
|
-
schema = {
|
802
|
-
"type" => "object",
|
803
|
-
"properties" => { "a" => {"format" => "email"}}
|
804
|
-
}
|
805
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft2))
|
806
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft2))
|
807
|
-
|
808
|
-
schema = {
|
809
|
-
"type" => "object",
|
810
|
-
"properties" => { "a" => {"format" => "host-name"}}
|
811
|
-
}
|
812
|
-
assert(JSON::Validator.validate(schema,data1,:version => :draft2))
|
813
|
-
assert(!JSON::Validator.validate(schema,data2,:version => :draft2))
|
814
|
-
end
|
815
|
-
|
816
|
-
|
817
|
-
def test_format_numeric
|
818
|
-
data1 = {"a" => "boo"}
|
819
|
-
data2 = {"a" => 5}
|
820
|
-
data3 = {"a" => 5.4}
|
821
|
-
|
822
|
-
schema = {
|
823
|
-
"type" => "object",
|
824
|
-
"properties" => { "a" => {"format" => "utc-millisec"}}
|
768
|
+
"properties" => { "a" => {"type" => ["string","null"], "format" => "ip-address"}}
|
825
769
|
}
|
826
770
|
assert(!JSON::Validator.validate(schema,data1,:version => :draft2))
|
827
771
|
assert(JSON::Validator.validate(schema,data2,:version => :draft2))
|
828
|
-
assert(JSON::Validator.validate(schema,data3,:version => :draft2))
|
829
772
|
end
|
830
773
|
|
831
774
|
end
|
@@ -902,81 +902,16 @@ class JSONSchemaDraft3Test < Test::Unit::TestCase
|
|
902
902
|
end
|
903
903
|
|
904
904
|
|
905
|
-
def
|
905
|
+
def test_format_union
|
906
906
|
data1 = {"a" => "boo"}
|
907
|
-
data2 = {"a" =>
|
907
|
+
data2 = {"a" => nil}
|
908
908
|
|
909
909
|
schema = {
|
910
|
-
"$schema" => "http://json-schema.org/draft-03/schema#",
|
911
|
-
"type" => "object",
|
912
|
-
"properties" => { "a" => {"format" => "regex"}}
|
913
|
-
}
|
914
|
-
assert(JSON::Validator.validate(schema,data1))
|
915
|
-
assert(!JSON::Validator.validate(schema,data2))
|
916
|
-
|
917
|
-
schema = {
|
918
|
-
"$schema" => "http://json-schema.org/draft-03/schema#",
|
919
|
-
"type" => "object",
|
920
|
-
"properties" => { "a" => {"format" => "color"}}
|
921
|
-
}
|
922
|
-
assert(JSON::Validator.validate(schema,data1))
|
923
|
-
assert(!JSON::Validator.validate(schema,data2))
|
924
|
-
|
925
|
-
schema = {
|
926
|
-
"$schema" => "http://json-schema.org/draft-03/schema#",
|
927
|
-
"type" => "object",
|
928
|
-
"properties" => { "a" => {"format" => "style"}}
|
929
|
-
}
|
930
|
-
assert(JSON::Validator.validate(schema,data1))
|
931
|
-
assert(!JSON::Validator.validate(schema,data2))
|
932
|
-
|
933
|
-
schema = {
|
934
|
-
"$schema" => "http://json-schema.org/draft-03/schema#",
|
935
|
-
"type" => "object",
|
936
|
-
"properties" => { "a" => {"format" => "phone"}}
|
937
|
-
}
|
938
|
-
assert(JSON::Validator.validate(schema,data1))
|
939
|
-
assert(!JSON::Validator.validate(schema,data2))
|
940
|
-
|
941
|
-
schema = {
|
942
|
-
"$schema" => "http://json-schema.org/draft-03/schema#",
|
943
|
-
"type" => "object",
|
944
|
-
"properties" => { "a" => {"format" => "uri"}}
|
945
|
-
}
|
946
|
-
assert(JSON::Validator.validate(schema,data1))
|
947
|
-
assert(!JSON::Validator.validate(schema,data2))
|
948
|
-
|
949
|
-
schema = {
|
950
|
-
"$schema" => "http://json-schema.org/draft-03/schema#",
|
951
|
-
"type" => "object",
|
952
|
-
"properties" => { "a" => {"format" => "email"}}
|
953
|
-
}
|
954
|
-
assert(JSON::Validator.validate(schema,data1))
|
955
|
-
assert(!JSON::Validator.validate(schema,data2))
|
956
|
-
|
957
|
-
schema = {
|
958
|
-
"$schema" => "http://json-schema.org/draft-03/schema#",
|
959
|
-
"type" => "object",
|
960
|
-
"properties" => { "a" => {"format" => "host-name"}}
|
961
|
-
}
|
962
|
-
assert(JSON::Validator.validate(schema,data1))
|
963
|
-
assert(!JSON::Validator.validate(schema,data2))
|
964
|
-
end
|
965
|
-
|
966
|
-
|
967
|
-
def test_format_numeric
|
968
|
-
data1 = {"a" => "boo"}
|
969
|
-
data2 = {"a" => 5}
|
970
|
-
data3 = {"a" => 5.4}
|
971
|
-
|
972
|
-
schema = {
|
973
|
-
"$schema" => "http://json-schema.org/draft-03/schema#",
|
974
910
|
"type" => "object",
|
975
|
-
"properties" => { "a" => {"format" => "
|
911
|
+
"properties" => { "a" => {"type" => ["string","null"], "format" => "ip-address"}}
|
976
912
|
}
|
977
|
-
assert(!JSON::Validator.validate(schema,data1))
|
978
|
-
assert(JSON::Validator.validate(schema,data2))
|
979
|
-
assert(JSON::Validator.validate(schema,data3))
|
913
|
+
assert(!JSON::Validator.validate(schema,data1,:version => :draft3))
|
914
|
+
assert(JSON::Validator.validate(schema,data2,:version => :draft3))
|
980
915
|
end
|
981
916
|
|
982
917
|
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 63
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
version: 0.9.
|
9
|
+
- 2
|
10
|
+
version: 0.9.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kenny Hoxworth
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-03-
|
18
|
+
date: 2011-03-30 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -57,7 +57,6 @@ files:
|
|
57
57
|
- lib/json-schema/uri/file.rb
|
58
58
|
- lib/json-schema/uri/uuid.rb
|
59
59
|
- lib/json-schema/validator.rb
|
60
|
-
- lib/json-schema/validator.rb.orig
|
61
60
|
- lib/json-schema/validators/draft1.rb
|
62
61
|
- lib/json-schema/validators/draft2.rb
|
63
62
|
- lib/json-schema/validators/draft3.rb
|
@@ -1,391 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
require 'open-uri'
|
3
|
-
require 'pathname'
|
4
|
-
require 'bigdecimal'
|
5
|
-
require 'digest/sha1'
|
6
|
-
require 'date'
|
7
|
-
|
8
|
-
module JSON
|
9
|
-
|
10
|
-
class Schema
|
11
|
-
class ValidationError < Exception
|
12
|
-
attr_reader :fragments, :schema
|
13
|
-
|
14
|
-
def initialize(message, fragments, schema)
|
15
|
-
@fragments = fragments
|
16
|
-
@schema = schema
|
17
|
-
message = "#{message} in schema #{schema.uri}"
|
18
|
-
super(message)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
class SchemaError < Exception
|
23
|
-
end
|
24
|
-
|
25
|
-
class JsonParseError < Exception
|
26
|
-
end
|
27
|
-
|
28
|
-
class Attribute
|
29
|
-
def self.validate(current_schema, data, fragments, validator, options = {})
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.build_fragment(fragments)
|
33
|
-
"#/#{fragments.join('/')}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
class Validator
|
38
|
-
attr_accessor :attributes, :uri
|
39
|
-
|
40
|
-
def initialize()
|
41
|
-
@attributes = {}
|
42
|
-
@uri = nil
|
43
|
-
end
|
44
|
-
|
45
|
-
def extend_schema_definition(schema_uri)
|
46
|
-
u = URI.parse(schema_uri)
|
47
|
-
validator = JSON::Validator.validators["#{u.scheme}://#{u.host}#{u.path}"]
|
48
|
-
if validator.nil?
|
49
|
-
raise SchemaError.new("Schema not found: #{u.scheme}://#{u.host}#{u.path}")
|
50
|
-
end
|
51
|
-
@attributes.merge!(validator.attributes)
|
52
|
-
end
|
53
|
-
|
54
|
-
def to_s
|
55
|
-
"#{@uri.scheme}://#{uri.host}#{uri.path}"
|
56
|
-
end
|
57
|
-
|
58
|
-
def validate(current_schema, data, fragments)
|
59
|
-
current_schema.schema.each do |attr_name,attribute|
|
60
|
-
|
61
|
-
if @attributes.has_key?(attr_name.to_s)
|
62
|
-
@attributes[attr_name.to_s].validate(current_schema, data, fragments, self)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
data
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
|
71
|
-
class Validator
|
72
|
-
|
73
|
-
@@schemas = {}
|
74
|
-
@@cache_schemas = false
|
75
|
-
@@default_opts = {
|
76
|
-
:list => false,
|
77
|
-
:version => nil
|
78
|
-
}
|
79
|
-
@@validators = {}
|
80
|
-
@@default_validator = nil
|
81
|
-
@@available_json_backends = []
|
82
|
-
@@json_backend = nil
|
83
|
-
|
84
|
-
def initialize(schema_data, data, opts={})
|
85
|
-
@options = @@default_opts.clone.merge(opts)
|
86
|
-
|
87
|
-
# I'm not a fan of this, but it's quick and dirty to get it working for now
|
88
|
-
if @options[:version]
|
89
|
-
@options[:version] = case @options[:version].to_s
|
90
|
-
when "draft3"
|
91
|
-
"draft-03"
|
92
|
-
when "draft2"
|
93
|
-
"draft-02"
|
94
|
-
when "draft1"
|
95
|
-
"draft-01"
|
96
|
-
else
|
97
|
-
raise JSON::Schema::SchemaError.new("The requested JSON schema version is not supported")
|
98
|
-
end
|
99
|
-
u = URI.parse("http://json-schema.org/#{@options[:version]}/schema#")
|
100
|
-
validator = JSON::Validator.validators["#{u.scheme}://#{u.host}#{u.path}"]
|
101
|
-
@options[:version] = validator
|
102
|
-
end
|
103
|
-
@base_schema = initialize_schema(schema_data)
|
104
|
-
@data = initialize_data(data)
|
105
|
-
build_schemas(@base_schema)
|
106
|
-
end
|
107
|
-
|
108
|
-
|
109
|
-
# Run a simple true/false validation of data against a schema
|
110
|
-
def validate()
|
111
|
-
begin
|
112
|
-
@base_schema.validate(@data,[])
|
113
|
-
Validator.clear_cache
|
114
|
-
rescue JSON::Schema::ValidationError
|
115
|
-
Validator.clear_cache
|
116
|
-
raise $!
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
|
121
|
-
def load_ref_schema(parent_schema,ref)
|
122
|
-
uri = URI.parse(ref)
|
123
|
-
if uri.relative?
|
124
|
-
uri = parent_schema.uri.clone
|
125
|
-
|
126
|
-
# Check for absolute path
|
127
|
-
path = ref.split("#")[0]
|
128
|
-
|
129
|
-
# This is a self reference and thus the schema does not need to be re-loaded
|
130
|
-
if path.nil? || path == ''
|
131
|
-
return
|
132
|
-
end
|
133
|
-
|
134
|
-
if path && path[0,1] == '/'
|
135
|
-
uri.path = Pathname.new(path).cleanpath.to_s
|
136
|
-
else
|
137
|
-
uri.path = (Pathname.new(parent_schema.uri.path).parent + path).cleanpath.to_s
|
138
|
-
end
|
139
|
-
uri.fragment = nil
|
140
|
-
end
|
141
|
-
|
142
|
-
if Validator.schemas[uri.to_s].nil?
|
143
|
-
begin
|
144
|
-
schema = JSON::Schema.new(JSON::Validator.parse(open(uri.to_s).read), uri, @options[:version])
|
145
|
-
Validator.add_schema(schema)
|
146
|
-
build_schemas(schema)
|
147
|
-
rescue JSON::ParserError
|
148
|
-
# Don't rescue this error, we want JSON formatting issues to bubble up
|
149
|
-
raise $!
|
150
|
-
rescue Exception
|
151
|
-
# Failures will occur when this URI cannot be referenced yet. Don't worry about it,
|
152
|
-
# the proper error will fall out if the ref isn't ever defined
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
|
158
|
-
# Build all schemas with IDs, mapping out the namespace
|
159
|
-
def build_schemas(parent_schema)
|
160
|
-
# Check for schemas in union types
|
161
|
-
["type", "disallow"].each do |key|
|
162
|
-
if parent_schema.schema[key] && parent_schema.schema[key].is_a?(Array)
|
163
|
-
parent_schema.schema[key].each_with_index do |type,i|
|
164
|
-
if type.is_a?(Hash)
|
165
|
-
handle_schema(parent_schema, type)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
end
|
169
|
-
end
|
170
|
-
|
171
|
-
# All properties are schemas
|
172
|
-
if parent_schema.schema["properties"]
|
173
|
-
parent_schema.schema["properties"].each do |k,v|
|
174
|
-
handle_schema(parent_schema, v)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
# Items are always schemas
|
179
|
-
if parent_schema.schema["items"]
|
180
|
-
items = parent_schema.schema["items"].clone
|
181
|
-
single = false
|
182
|
-
if !items.is_a?(Array)
|
183
|
-
items = [items]
|
184
|
-
single = true
|
185
|
-
end
|
186
|
-
items.each_with_index do |item,i|
|
187
|
-
handle_schema(parent_schema, item)
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
# Each of these might be schemas
|
192
|
-
["additionalProperties", "additionalItems", "dependencies", "extends"].each do |key|
|
193
|
-
if parent_schema.schema[key].is_a?(Hash)
|
194
|
-
handle_schema(parent_schema, parent_schema.schema[key])
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
end
|
199
|
-
|
200
|
-
# Either load a reference schema or create a new schema
|
201
|
-
def handle_schema(parent_schema, obj)
|
202
|
-
if obj['$ref']
|
203
|
-
load_ref_schema(parent_schema, obj['$ref'])
|
204
|
-
else
|
205
|
-
schema_uri = parent_schema.uri.clone
|
206
|
-
schema = JSON::Schema.new(obj,schema_uri,@options[:version])
|
207
|
-
if obj['id']
|
208
|
-
Validator.add_schema(schema)
|
209
|
-
end
|
210
|
-
build_schemas(schema)
|
211
|
-
end
|
212
|
-
end
|
213
|
-
|
214
|
-
|
215
|
-
class << self
|
216
|
-
def validate(schema, data,opts={})
|
217
|
-
begin
|
218
|
-
validator = JSON::Validator.new(schema, data, opts)
|
219
|
-
validator.validate
|
220
|
-
return true
|
221
|
-
rescue JSON::Schema::ValidationError, JSON::Schema::SchemaError
|
222
|
-
return false
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
def validate!(schema, data,opts={})
|
227
|
-
validator = JSON::Validator.new(schema, data, opts)
|
228
|
-
validator.validate
|
229
|
-
end
|
230
|
-
alias_method 'validate2', 'validate!'
|
231
|
-
|
232
|
-
def clear_cache
|
233
|
-
@@schemas = {} if @@cache_schemas == false
|
234
|
-
end
|
235
|
-
|
236
|
-
def schemas
|
237
|
-
@@schemas
|
238
|
-
end
|
239
|
-
|
240
|
-
def add_schema(schema)
|
241
|
-
@@schemas[schema.uri.to_s] = schema if @@schemas[schema.uri.to_s].nil?
|
242
|
-
end
|
243
|
-
|
244
|
-
def cache_schemas=(val)
|
245
|
-
@@cache_schemas = val == true ? true : false
|
246
|
-
end
|
247
|
-
|
248
|
-
def validators
|
249
|
-
@@validators
|
250
|
-
end
|
251
|
-
|
252
|
-
def default_validator
|
253
|
-
@@default_validator
|
254
|
-
end
|
255
|
-
|
256
|
-
def register_validator(v)
|
257
|
-
@@validators[v.to_s] = v
|
258
|
-
end
|
259
|
-
|
260
|
-
def register_default_validator(v)
|
261
|
-
@@default_validator = v
|
262
|
-
end
|
263
|
-
|
264
|
-
def json_backend
|
265
|
-
@@json_backend
|
266
|
-
end
|
267
|
-
|
268
|
-
def json_backend=(backend)
|
269
|
-
backend = backend.to_s
|
270
|
-
if @@available_json_backend.include?(backend)
|
271
|
-
@@json_backend = backend
|
272
|
-
else
|
273
|
-
raise JSON::Schema::JsonParseError.new("The JSON backend '#{backend}' could not be found.")
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
def parse(s)
|
278
|
-
case @@json_backend.to_s
|
279
|
-
when 'json'
|
280
|
-
JSON.parse(s)
|
281
|
-
when 'yajl'
|
282
|
-
json = StringIO.new(s)
|
283
|
-
parser = Yajl::Parser.new
|
284
|
-
parser.parse(json)
|
285
|
-
else
|
286
|
-
raise JSON::Schema::JsonParseError.new("No supported JSON parsers found. The following parsers are suported:\n * yajl-ruby\n * json")
|
287
|
-
end
|
288
|
-
end
|
289
|
-
end
|
290
|
-
|
291
|
-
if Gem.available?('json')
|
292
|
-
require 'json'
|
293
|
-
@@available_json_backends << 'json'
|
294
|
-
@@json_backend = 'json'
|
295
|
-
end
|
296
|
-
|
297
|
-
if Gem.available?('yajl-ruby')
|
298
|
-
require 'yajl'
|
299
|
-
@@available_json_backends << 'yajl'
|
300
|
-
@@json_backend = 'yajl'
|
301
|
-
end
|
302
|
-
|
303
|
-
|
304
|
-
private
|
305
|
-
<<<<<<< HEAD
|
306
|
-
|
307
|
-
=======
|
308
|
-
|
309
|
-
if Gem.available?('uuidtools')
|
310
|
-
require 'uuidtools'
|
311
|
-
@@fake_uri_generator = lambda{|s| UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, s).to_s }
|
312
|
-
else
|
313
|
-
require 'uri/uuid'
|
314
|
-
@@fake_uri_generator = lambda{|s| UUID.create_v5(s,UUID::Nil).to_s }
|
315
|
-
end
|
316
|
-
|
317
|
-
def fake_uri schema
|
318
|
-
@@fake_uri_generator.call(schema)
|
319
|
-
end
|
320
|
-
|
321
|
-
>>>>>>> bcd72ee... added optional dependency on uuidtools gem, to resolve UUID constant overload warning
|
322
|
-
def initialize_schema(schema)
|
323
|
-
if schema.is_a?(String)
|
324
|
-
begin
|
325
|
-
# Build a fake URI for this
|
326
|
-
schema_uri = URI.parse(fake_uri(schema))
|
327
|
-
schema = JSON::Validator.parse(schema)
|
328
|
-
if @options[:list]
|
329
|
-
schema = {"type" => "array", "items" => schema}
|
330
|
-
end
|
331
|
-
schema = JSON::Schema.new(schema,schema_uri,@options[:version])
|
332
|
-
Validator.add_schema(schema)
|
333
|
-
rescue
|
334
|
-
# Build a uri for it
|
335
|
-
schema_uri = URI.parse(schema)
|
336
|
-
if schema_uri.relative?
|
337
|
-
# Check for absolute path
|
338
|
-
if schema[0,1] == '/'
|
339
|
-
schema_uri = URI.parse("file://#{schema}")
|
340
|
-
else
|
341
|
-
schema_uri = URI.parse("file://#{Dir.pwd}/#{schema}")
|
342
|
-
end
|
343
|
-
end
|
344
|
-
if Validator.schemas[schema_uri.to_s].nil?
|
345
|
-
schema = JSON::Validator.parse(open(schema_uri.to_s).read)
|
346
|
-
if @options[:list]
|
347
|
-
schema = {"type" => "array", "items" => schema}
|
348
|
-
end
|
349
|
-
schema = JSON::Schema.new(schema,schema_uri,@options[:version])
|
350
|
-
Validator.add_schema(schema)
|
351
|
-
else
|
352
|
-
schema = Validator.schemas[schema_uri.to_s]
|
353
|
-
end
|
354
|
-
end
|
355
|
-
elsif schema.is_a?(Hash)
|
356
|
-
if @options[:list]
|
357
|
-
schema = {"type" => "array", "items" => schema}
|
358
|
-
end
|
359
|
-
schema_uri = URI.parse(fake_uri(schema.inspect))
|
360
|
-
schema = JSON::Schema.new(schema,schema_uri,@options[:version])
|
361
|
-
Validator.add_schema(schema)
|
362
|
-
else
|
363
|
-
raise "Invalid schema - must be either a string or a hash"
|
364
|
-
end
|
365
|
-
|
366
|
-
schema
|
367
|
-
end
|
368
|
-
|
369
|
-
|
370
|
-
def initialize_data(data)
|
371
|
-
# Parse the data, if any
|
372
|
-
if data.is_a?(String)
|
373
|
-
begin
|
374
|
-
data = JSON::Validator.parse(data)
|
375
|
-
rescue
|
376
|
-
json_uri = URI.parse(data)
|
377
|
-
if json_uri.relative?
|
378
|
-
if data[0,1] == '/'
|
379
|
-
schema_uri = URI.parse("file://#{data}")
|
380
|
-
else
|
381
|
-
schema_uri = URI.parse("file://#{Dir.pwd}/#{data}")
|
382
|
-
end
|
383
|
-
end
|
384
|
-
data = JSON::Validator.parse(open(json_uri.to_s).read)
|
385
|
-
end
|
386
|
-
end
|
387
|
-
data
|
388
|
-
end
|
389
|
-
|
390
|
-
end
|
391
|
-
end
|