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.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +21 -0
  3. data/.travis.yml +15 -1
  4. data/README.md +164 -129
  5. data/Rakefile +10 -1
  6. data/bin/console +2 -6
  7. data/{etc/schemas → lib/profiles}/geojson.json +0 -1
  8. data/lib/profiles/table-schema.json +1625 -0
  9. data/lib/profiles/topojson.json +311 -0
  10. data/lib/tableschema.rb +5 -3
  11. data/lib/tableschema/constraints/constraints.rb +12 -24
  12. data/lib/tableschema/constraints/enum.rb +6 -2
  13. data/lib/tableschema/constraints/max_length.rb +6 -2
  14. data/lib/tableschema/constraints/maximum.rb +12 -2
  15. data/lib/tableschema/constraints/min_length.rb +6 -2
  16. data/lib/tableschema/constraints/minimum.rb +12 -2
  17. data/lib/tableschema/constraints/pattern.rb +9 -2
  18. data/lib/tableschema/constraints/required.rb +6 -15
  19. data/lib/tableschema/constraints/unique.rb +12 -0
  20. data/lib/tableschema/defaults.rb +9 -0
  21. data/lib/tableschema/exceptions.rb +15 -2
  22. data/lib/tableschema/field.rb +39 -20
  23. data/lib/tableschema/helpers.rb +32 -15
  24. data/lib/tableschema/infer.rb +31 -28
  25. data/lib/tableschema/model.rb +57 -34
  26. data/lib/tableschema/schema.rb +40 -6
  27. data/lib/tableschema/table.rb +75 -26
  28. data/lib/tableschema/types/any.rb +1 -0
  29. data/lib/tableschema/types/array.rb +2 -1
  30. data/lib/tableschema/types/base.rb +9 -21
  31. data/lib/tableschema/types/date.rb +1 -0
  32. data/lib/tableschema/types/datetime.rb +1 -0
  33. data/lib/tableschema/types/duration.rb +31 -0
  34. data/lib/tableschema/types/geojson.rb +27 -5
  35. data/lib/tableschema/types/geopoint.rb +4 -3
  36. data/lib/tableschema/types/integer.rb +1 -0
  37. data/lib/tableschema/types/number.rb +40 -25
  38. data/lib/tableschema/types/object.rb +2 -1
  39. data/lib/tableschema/types/string.rb +8 -0
  40. data/lib/tableschema/types/time.rb +1 -0
  41. data/lib/tableschema/types/year.rb +34 -0
  42. data/lib/tableschema/types/yearmonth.rb +52 -0
  43. data/lib/tableschema/validate.rb +45 -29
  44. data/lib/tableschema/version.rb +1 -1
  45. data/tableschema.gemspec +2 -1
  46. metadata +31 -12
  47. data/etc/schemas/json-table-schema.json +0 -102
  48. data/lib/tableschema/data.rb +0 -60
  49. 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 = @field['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['type']}` does not support the `#{constraint}` constraint"))
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 is_supported_type?(constraint)
51
- klass = get_class_for_type(@field['type'])
52
- Kernel.const_get(klass).supported_constraints.include?(constraint)
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 parse_constraint(constraint)
56
- if @value.is_a?(::Integer) && constraint.is_a?(::String)
57
- constraint.to_i
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
- if !parse_constraint(@constraints['enum']).include?(@value)
7
- raise TableSchema::ConstraintError.new("The value for the field `#{@field['name']}` must be in the enum array")
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 > @constraints['maxLength'].to_i
8
- raise TableSchema::ConstraintError.new("The field `#{@field['name']}` must have a maximum length of #{@constraints['maxLength']}")
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