tableschema 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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