tableschema 0.3.1 → 0.4.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +21 -0
- data/.travis.yml +15 -1
- data/README.md +164 -129
- data/Rakefile +10 -1
- data/bin/console +2 -6
- data/{etc/schemas → lib/profiles}/geojson.json +0 -1
- data/lib/profiles/table-schema.json +1625 -0
- data/lib/profiles/topojson.json +311 -0
- data/lib/tableschema.rb +5 -3
- data/lib/tableschema/constraints/constraints.rb +12 -24
- data/lib/tableschema/constraints/enum.rb +6 -2
- data/lib/tableschema/constraints/max_length.rb +6 -2
- data/lib/tableschema/constraints/maximum.rb +12 -2
- data/lib/tableschema/constraints/min_length.rb +6 -2
- data/lib/tableschema/constraints/minimum.rb +12 -2
- data/lib/tableschema/constraints/pattern.rb +9 -2
- data/lib/tableschema/constraints/required.rb +6 -15
- data/lib/tableschema/constraints/unique.rb +12 -0
- data/lib/tableschema/defaults.rb +9 -0
- data/lib/tableschema/exceptions.rb +15 -2
- data/lib/tableschema/field.rb +39 -20
- data/lib/tableschema/helpers.rb +32 -15
- data/lib/tableschema/infer.rb +31 -28
- data/lib/tableschema/model.rb +57 -34
- data/lib/tableschema/schema.rb +40 -6
- data/lib/tableschema/table.rb +75 -26
- data/lib/tableschema/types/any.rb +1 -0
- data/lib/tableschema/types/array.rb +2 -1
- data/lib/tableschema/types/base.rb +9 -21
- data/lib/tableschema/types/date.rb +1 -0
- data/lib/tableschema/types/datetime.rb +1 -0
- data/lib/tableschema/types/duration.rb +31 -0
- data/lib/tableschema/types/geojson.rb +27 -5
- data/lib/tableschema/types/geopoint.rb +4 -3
- data/lib/tableschema/types/integer.rb +1 -0
- data/lib/tableschema/types/number.rb +40 -25
- data/lib/tableschema/types/object.rb +2 -1
- data/lib/tableschema/types/string.rb +8 -0
- data/lib/tableschema/types/time.rb +1 -0
- data/lib/tableschema/types/year.rb +34 -0
- data/lib/tableschema/types/yearmonth.rb +52 -0
- data/lib/tableschema/validate.rb +45 -29
- data/lib/tableschema/version.rb +1 -1
- data/tableschema.gemspec +2 -1
- metadata +31 -12
- data/etc/schemas/json-table-schema.json +0 -102
- data/lib/tableschema/data.rb +0 -60
- data/lib/tableschema/types/null.rb +0 -37
@@ -0,0 +1,311 @@
|
|
1
|
+
{
|
2
|
+
"$schema":"http://json-schema.org/draft-04/schema#",
|
3
|
+
"title":"TopoJSON object",
|
4
|
+
"description":"Schema for a TopoJSON object",
|
5
|
+
"type":"object",
|
6
|
+
"required":[
|
7
|
+
"type"
|
8
|
+
],
|
9
|
+
"properties":{
|
10
|
+
"bbox":{
|
11
|
+
"$ref":"#/definitions/bbox"
|
12
|
+
}
|
13
|
+
},
|
14
|
+
"oneOf":[
|
15
|
+
{
|
16
|
+
"$ref":"#/definitions/topology"
|
17
|
+
},
|
18
|
+
{
|
19
|
+
"$ref":"#/definitions/geometry"
|
20
|
+
}
|
21
|
+
],
|
22
|
+
"definitions":{
|
23
|
+
"bbox":{
|
24
|
+
"title":"TopoJSON bounding box",
|
25
|
+
"description":"A bounding box as defined by TopoJSON",
|
26
|
+
"type":"array",
|
27
|
+
"items":{
|
28
|
+
"$ref":"#/definitions/bbox/definitions/dimension"
|
29
|
+
},
|
30
|
+
"minItems":2,
|
31
|
+
"maxItems":2,
|
32
|
+
"definitions":{
|
33
|
+
"dimension":{
|
34
|
+
"type":"array",
|
35
|
+
"description":"This array should have an entry per dimension in the geometries",
|
36
|
+
"items":{
|
37
|
+
"type":"number"
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|
41
|
+
},
|
42
|
+
"geometry":{
|
43
|
+
"title":"Geometry objects",
|
44
|
+
"description":"A Geometry object as defined by TopoJSON",
|
45
|
+
"type":"object",
|
46
|
+
"required":[
|
47
|
+
"type"
|
48
|
+
],
|
49
|
+
"properties":{
|
50
|
+
"id":{
|
51
|
+
"type":[
|
52
|
+
"string",
|
53
|
+
"integer"
|
54
|
+
]
|
55
|
+
},
|
56
|
+
"properties":{
|
57
|
+
"type":"object"
|
58
|
+
}
|
59
|
+
},
|
60
|
+
"oneOf":[
|
61
|
+
{
|
62
|
+
"title":"Point",
|
63
|
+
"description":"A Point Geometry object as defined by TopoJSON",
|
64
|
+
"required":[
|
65
|
+
"type",
|
66
|
+
"coordinates"
|
67
|
+
],
|
68
|
+
"properties":{
|
69
|
+
"type":{
|
70
|
+
"enum":[
|
71
|
+
"Point"
|
72
|
+
]
|
73
|
+
},
|
74
|
+
"coordinates":{
|
75
|
+
"$ref":"#/definitions/geometry/definitions/position"
|
76
|
+
}
|
77
|
+
}
|
78
|
+
},
|
79
|
+
{
|
80
|
+
"title":"MultiPoint",
|
81
|
+
"description":"A MultiPoint Geometry object as defined by TopoJSON",
|
82
|
+
"required":[
|
83
|
+
"type",
|
84
|
+
"coordinates"
|
85
|
+
],
|
86
|
+
"properties":{
|
87
|
+
"type":{
|
88
|
+
"enum":[
|
89
|
+
"MultiPoint"
|
90
|
+
]
|
91
|
+
},
|
92
|
+
"coordinates":{
|
93
|
+
"type":"array",
|
94
|
+
"items":{
|
95
|
+
"$ref":"#/definitions/geometry/definitions/position"
|
96
|
+
}
|
97
|
+
}
|
98
|
+
}
|
99
|
+
},
|
100
|
+
{
|
101
|
+
"title":"LineString",
|
102
|
+
"description":"A LineString Geometry object as defined by TopoJSON",
|
103
|
+
"required":[
|
104
|
+
"type",
|
105
|
+
"arcs"
|
106
|
+
],
|
107
|
+
"properties":{
|
108
|
+
"type":{
|
109
|
+
"enum":[
|
110
|
+
"LineString"
|
111
|
+
]
|
112
|
+
},
|
113
|
+
"arcs":{
|
114
|
+
"type":"array",
|
115
|
+
"items":{
|
116
|
+
"type":"integer"
|
117
|
+
}
|
118
|
+
}
|
119
|
+
}
|
120
|
+
},
|
121
|
+
{
|
122
|
+
"title":"MultiLineString",
|
123
|
+
"description":"A MultiLineString Geometry object as defined by TopoJSON",
|
124
|
+
"required":[
|
125
|
+
"type",
|
126
|
+
"arcs"
|
127
|
+
],
|
128
|
+
"properties":{
|
129
|
+
"type":{
|
130
|
+
"enum":[
|
131
|
+
"MultiLineString"
|
132
|
+
]
|
133
|
+
},
|
134
|
+
"arcs":{
|
135
|
+
"type":"array",
|
136
|
+
"items":{
|
137
|
+
"type":"array",
|
138
|
+
"items":{
|
139
|
+
"type":"integer"
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
},
|
145
|
+
{
|
146
|
+
"title":"Polygon",
|
147
|
+
"description":"A Polygon Geometry object as defined by TopoJSON",
|
148
|
+
"required":[
|
149
|
+
"type",
|
150
|
+
"arcs"
|
151
|
+
],
|
152
|
+
"properties":{
|
153
|
+
"type":{
|
154
|
+
"enum":[
|
155
|
+
"Polygon"
|
156
|
+
]
|
157
|
+
},
|
158
|
+
"arcs":{
|
159
|
+
"TODO":"Check if arcs refer to valid LinearRings",
|
160
|
+
"type":"array",
|
161
|
+
"items":{
|
162
|
+
"type":"array",
|
163
|
+
"items":{
|
164
|
+
"type":"integer"
|
165
|
+
}
|
166
|
+
}
|
167
|
+
}
|
168
|
+
}
|
169
|
+
},
|
170
|
+
{
|
171
|
+
"title":"MultiPolygon",
|
172
|
+
"description":"A MultiPolygon Geometry object as defined by TopoJSON",
|
173
|
+
"required":[
|
174
|
+
"type",
|
175
|
+
"arcs"
|
176
|
+
],
|
177
|
+
"properties":{
|
178
|
+
"type":{
|
179
|
+
"enum":[
|
180
|
+
"MultiPolygon"
|
181
|
+
]
|
182
|
+
},
|
183
|
+
"arcs":{
|
184
|
+
"type":"array",
|
185
|
+
"items":{
|
186
|
+
"type":"array",
|
187
|
+
"items":{
|
188
|
+
"type":"array",
|
189
|
+
"items":{
|
190
|
+
"type":"integer"
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
}
|
195
|
+
}
|
196
|
+
},
|
197
|
+
{
|
198
|
+
"title":"GeometryCollection",
|
199
|
+
"description":"A MultiPolygon Geometry object as defined by TopoJSON",
|
200
|
+
"required":[
|
201
|
+
"type",
|
202
|
+
"geometries"
|
203
|
+
],
|
204
|
+
"properties":{
|
205
|
+
"type":{
|
206
|
+
"enum":[
|
207
|
+
"GeometryCollection"
|
208
|
+
]
|
209
|
+
},
|
210
|
+
"geometries":{
|
211
|
+
"type":"array",
|
212
|
+
"items":{
|
213
|
+
"$ref":"#/definitions/geometry"
|
214
|
+
}
|
215
|
+
}
|
216
|
+
}
|
217
|
+
}
|
218
|
+
],
|
219
|
+
"definitions":{
|
220
|
+
"position":{
|
221
|
+
"type":"array",
|
222
|
+
"items":{
|
223
|
+
"type":"number"
|
224
|
+
},
|
225
|
+
"minItems":2
|
226
|
+
}
|
227
|
+
}
|
228
|
+
|
229
|
+
},
|
230
|
+
"topology":{
|
231
|
+
"title":"Topology",
|
232
|
+
"description":"A Topology object as defined by TopoJSON",
|
233
|
+
"type":"object",
|
234
|
+
"required":[
|
235
|
+
"objects",
|
236
|
+
"arcs"
|
237
|
+
],
|
238
|
+
"properties":{
|
239
|
+
"type":{
|
240
|
+
"enum":[
|
241
|
+
"Topology"
|
242
|
+
]
|
243
|
+
},
|
244
|
+
"objects":{
|
245
|
+
"type":"object",
|
246
|
+
"additionalProperties":{
|
247
|
+
"$ref":"#/definitions/geometry"
|
248
|
+
}
|
249
|
+
},
|
250
|
+
"arcs":{
|
251
|
+
"$ref":"#/definitions/topology/definitions/arcs"
|
252
|
+
},
|
253
|
+
"transform":{
|
254
|
+
"$ref":"#/definitions/topology/definitions/transform"
|
255
|
+
},
|
256
|
+
"bbox":{
|
257
|
+
"$ref":"#/definitions/bbox"
|
258
|
+
}
|
259
|
+
},
|
260
|
+
"definitions":{
|
261
|
+
"transform":{
|
262
|
+
"type":"object",
|
263
|
+
"required":[
|
264
|
+
"scale",
|
265
|
+
"translate"
|
266
|
+
],
|
267
|
+
"properties":{
|
268
|
+
"scale":{
|
269
|
+
"type":"array",
|
270
|
+
"items":{
|
271
|
+
"type":"number"
|
272
|
+
},
|
273
|
+
"minItems":2
|
274
|
+
},
|
275
|
+
"translate":{
|
276
|
+
"type":"array",
|
277
|
+
"items":{
|
278
|
+
"type":"number"
|
279
|
+
},
|
280
|
+
"minItems":2
|
281
|
+
}
|
282
|
+
}
|
283
|
+
},
|
284
|
+
"arcs":{
|
285
|
+
"type":"array",
|
286
|
+
"items":{
|
287
|
+
"type":"array",
|
288
|
+
"items":{
|
289
|
+
"oneOf":[
|
290
|
+
{
|
291
|
+
"$ref":"#/definitions/topology/definitions/position"
|
292
|
+
},
|
293
|
+
{
|
294
|
+
"type":"null"
|
295
|
+
}
|
296
|
+
]
|
297
|
+
},
|
298
|
+
"minItems":2
|
299
|
+
}
|
300
|
+
},
|
301
|
+
"position":{
|
302
|
+
"type":"array",
|
303
|
+
"items":{
|
304
|
+
"type":"number"
|
305
|
+
},
|
306
|
+
"minItems":2
|
307
|
+
}
|
308
|
+
}
|
309
|
+
}
|
310
|
+
}
|
311
|
+
}
|
data/lib/tableschema.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
require "json"
|
2
2
|
require "json-schema"
|
3
3
|
require "uuid"
|
4
|
-
require "currencies"
|
5
4
|
require "date"
|
6
5
|
require "tod"
|
7
6
|
require "tod/core_extensions"
|
8
7
|
require "csv"
|
8
|
+
require "active_support/duration"
|
9
9
|
|
10
10
|
require "tableschema/version"
|
11
11
|
require "tableschema/exceptions"
|
@@ -22,16 +22,18 @@ require "tableschema/types/datetime"
|
|
22
22
|
require "tableschema/types/geojson"
|
23
23
|
require "tableschema/types/geopoint"
|
24
24
|
require "tableschema/types/integer"
|
25
|
-
require "tableschema/types/null"
|
26
25
|
require "tableschema/types/number"
|
27
26
|
require "tableschema/types/object"
|
28
27
|
require "tableschema/types/string"
|
29
28
|
require "tableschema/types/time"
|
29
|
+
require "tableschema/types/year"
|
30
|
+
require "tableschema/types/yearmonth"
|
31
|
+
require "tableschema/types/duration"
|
32
|
+
require "tableschema/defaults"
|
30
33
|
|
31
34
|
require "tableschema/field"
|
32
35
|
require "tableschema/validate"
|
33
36
|
require "tableschema/model"
|
34
|
-
require "tableschema/data"
|
35
37
|
require "tableschema/schema"
|
36
38
|
require "tableschema/table"
|
37
39
|
require "tableschema/infer"
|
@@ -5,6 +5,7 @@ require "tableschema/constraints/minimum"
|
|
5
5
|
require "tableschema/constraints/maximum"
|
6
6
|
require "tableschema/constraints/enum"
|
7
7
|
require "tableschema/constraints/pattern"
|
8
|
+
require "tableschema/constraints/unique"
|
8
9
|
|
9
10
|
module TableSchema
|
10
11
|
class Constraints
|
@@ -17,21 +18,22 @@ module TableSchema
|
|
17
18
|
include TableSchema::Constraints::Maximum
|
18
19
|
include TableSchema::Constraints::Enum
|
19
20
|
include TableSchema::Constraints::Pattern
|
21
|
+
include TableSchema::Constraints::Unique
|
20
22
|
|
21
23
|
def initialize(field, value)
|
22
24
|
@field = field
|
23
25
|
@value = value
|
24
|
-
@constraints =
|
26
|
+
@constraints = ordered_constraints
|
25
27
|
end
|
26
28
|
|
27
29
|
def validate!
|
28
30
|
result = true
|
29
31
|
@constraints.each do |c|
|
30
|
-
constraint = c.first
|
32
|
+
constraint = c.first.to_s
|
31
33
|
if is_supported_type?(constraint)
|
32
34
|
result = self.send("check_#{underscore constraint}")
|
33
35
|
else
|
34
|
-
raise(TableSchema::ConstraintNotSupported.new("The field type `#{@field[
|
36
|
+
raise(TableSchema::ConstraintNotSupported.new("The field type `#{@field[:type]}` does not support the `#{constraint}` constraint"))
|
35
37
|
end
|
36
38
|
end
|
37
39
|
result
|
@@ -47,29 +49,15 @@ module TableSchema
|
|
47
49
|
downcase
|
48
50
|
end
|
49
51
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
52
|
+
def ordered_constraints
|
53
|
+
constraints = @field.fetch(:constraints, {})
|
54
|
+
ordered_constraints = constraints.select{ |key| key == :required}
|
55
|
+
ordered_constraints.merge!(constraints)
|
53
56
|
end
|
54
57
|
|
55
|
-
def
|
56
|
-
|
57
|
-
|
58
|
-
elsif @value.is_a?(::Tod::TimeOfDay)
|
59
|
-
Tod::TimeOfDay.parse(constraint)
|
60
|
-
elsif @value.is_a?(::DateTime)
|
61
|
-
DateTime.parse(constraint)
|
62
|
-
elsif @value.is_a?(::Date) && constraint.is_a?(::String)
|
63
|
-
Date.parse(constraint)
|
64
|
-
elsif @value.is_a?(::Float) && constraint.is_a?(Array)
|
65
|
-
constraint.map { |c| Float(c) }
|
66
|
-
elsif @value.is_a?(Boolean) && constraint.is_a?(Array)
|
67
|
-
constraint.map { |c| convert_to_boolean(c) }
|
68
|
-
elsif @value.is_a?(Date) && constraint.is_a?(Array)
|
69
|
-
constraint.map { |c| Date.parse(c) }
|
70
|
-
else
|
71
|
-
constraint
|
72
|
-
end
|
58
|
+
def is_supported_type?(constraint)
|
59
|
+
klass = get_class_for_type(@field[:type])
|
60
|
+
Kernel.const_get(klass).supported_constraints.include?(constraint)
|
73
61
|
end
|
74
62
|
|
75
63
|
end
|
@@ -3,12 +3,16 @@ module TableSchema
|
|
3
3
|
module Enum
|
4
4
|
|
5
5
|
def check_enum
|
6
|
-
|
7
|
-
raise TableSchema::ConstraintError.new("The value for the field `#{@field[
|
6
|
+
unless parsed_enum.include?(@value)
|
7
|
+
raise TableSchema::ConstraintError.new("The value for the field `#{@field[:name]}` must be in the enum array")
|
8
8
|
end
|
9
9
|
true
|
10
10
|
end
|
11
11
|
|
12
|
+
def parsed_enum
|
13
|
+
@constraints[:enum].map{ |value| @field.cast_type(value) }
|
14
|
+
end
|
15
|
+
|
12
16
|
end
|
13
17
|
end
|
14
18
|
end
|
@@ -4,12 +4,16 @@ module TableSchema
|
|
4
4
|
|
5
5
|
def check_max_length
|
6
6
|
return if @value.nil?
|
7
|
-
if @value.length >
|
8
|
-
raise TableSchema::ConstraintError.new("The field `#{@field[
|
7
|
+
if @value.length > parsed_max_length
|
8
|
+
raise TableSchema::ConstraintError.new("The field `#{@field[:name]}` must have a maximum length of #{@constraints[:maxLength]}")
|
9
9
|
end
|
10
10
|
true
|
11
11
|
end
|
12
12
|
|
13
|
+
def parsed_max_length
|
14
|
+
@constraints[:maxLength].to_i
|
15
|
+
end
|
16
|
+
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|