jsontableschema 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1cf851281ccf698eb2f50ce29916e8b2632e841a
4
- data.tar.gz: 253a669fbee44572cb3af3e9ed68592f444f08a1
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OWU5YWEyM2JmOTY3ZTY0ZGJmN2I5Mjc1ODQzN2M4ZjA2YTZhOTcxNw==
5
+ data.tar.gz: !binary |-
6
+ NWIyNWRjNGQzMjU0NmM2MjkzNmMwZGE0ZDJhMzg1YjQxNWMyYTUzOQ==
5
7
  SHA512:
6
- metadata.gz: 3215fdb1aa97951f83dc9f69484fc054befe9c9f0e9c8441692c011659fb5035bb8d41c42cd01863d8d474fd6f899caa48513d264872443e77961dd66f696635
7
- data.tar.gz: 2cc35932e7a71d369e75c5818e979d2a6db0c0ad26217f856b98f663dba9bafc2f8fbb2a8516324dbd6209764bb5dce6a0f0e7a348077e31cf6c8c146b0fbee7
8
+ metadata.gz: !binary |-
9
+ NDMyNzcwNzQ0ZjRiYjdhZDgzMjczNzYxMDY0ZWQ2OTI5MGEyZGFlMmYxMTI5
10
+ ZTEzMjE5MGQzMGE0NWFhY2E5OWU5NTJmYWRjMmI5MTExMjIxNTRlNzM5MGE5
11
+ NDcxMjE1MDhlZmI3YTgwMGNiMGNkZTc3N2FmZmUyMWY3M2VhZDM=
12
+ data.tar.gz: !binary |-
13
+ OWI5ZWY5ZDNmZDQ2MzY3N2RmNjVkMTQyNTZiODI4MDg1YTkwOTBhNzc1OWNj
14
+ MDZiYmU2YjU0NGQ4OTE2YTNiMTFiZjFjN2NkODNlMThiZDM3NGE0OTU5MTA0
15
+ YTA2ZmJkNmM2MDlkYmFmNTIyNTY0NmE5Y2E1NGFmN2ZmMDEwZTg=
data/README.md CHANGED
@@ -164,8 +164,6 @@ schema.primary_keys
164
164
  #=> ["id"]
165
165
  schema.foreign_keys
166
166
  #=> [{"fields" => "state", "reference" => { "datapackage" => "http://data.okfn.org/data/mydatapackage/", "resource" => "the-resource", "fields" => "state_id" } } ]
167
- schema.cast('height', '10')
168
- #=> 10.0
169
167
  schema.get_field('id')
170
168
  #=> {"name"=>"id", "constraints"=>{"required"=>true}, "type"=>"string", "format"=>"default"}
171
169
  schema.has_field?('foo')
@@ -176,13 +174,13 @@ schema.get_fields_by_type('string')
176
174
  #=> [{"name"=>"id", "constraints"=>{"required"=>true}, "type"=>"string", "format"=>"default"}, {"name"=>"height", "type"=>"string", "format"=>"default"}]
177
175
  schema.get_constraints('id')
178
176
  #=> {"required" => true}
179
- schema.convert_row(['string', '10.0'])
177
+ schema.cast_row(['string', '10.0'])
180
178
  #=> ['string', 10.0]
181
- schema.convert([['foo', '12.0'],['bar', '10.0']])
179
+ schema.cast([['foo', '12.0'],['bar', '10.0']])
182
180
  #=> [['foo', 12.0],['bar', 10.0]]
183
181
  ```
184
182
 
185
- When converting a row (using `convert_row`), or a number of rows (using `convert`), by default the converter will fail on the first error it finds. If you pass `false` as the second argument, the errors will be collected into a `errors` attribute for you to review later. For example:
183
+ When casting a row (using `cast_row`), or a number of rows (using `cast`), by default the converter will fail on the first error it finds. If you pass `false` as the second argument, the errors will be collected into a `errors` attribute for you to review later. For example:
186
184
 
187
185
  ```ruby
188
186
  schema_hash = {
@@ -209,14 +207,31 @@ rows = [
209
207
  ['wrong column count']
210
208
  ]
211
209
 
212
- schema.convert(rows)
210
+ schema.cast(rows)
213
211
  #=> JsonTableSchema::InvalidCast: notanumber is not a number
214
- schema.convert(rows, false)
212
+ schema.cast(rows, false)
215
213
  #=> JsonTableSchema::MultipleInvalid
216
214
  schema.errors
217
215
  #=> [#<JsonTableSchema::InvalidCast: notanumber is not a number>, #<JsonTableSchema::InvalidCast: notanumber is not a number>, #<JsonTableSchema::ConversionError: The number of items to convert (1) does not match the number of headers in the schema (2)>]
218
216
  ```
219
217
 
218
+ ## Field
219
+
220
+ ```ruby
221
+ # Init field
222
+ field = JsonTableSchema::Field.new({'type': 'number'})
223
+
224
+ # Cast a value
225
+ field.cast_value('12345')
226
+ #=> 12345.0
227
+ ```
228
+
229
+ Data values can be cast to native Ruby objects with a Field instance. Type instances can be initialized with f[ield descriptors](http://dataprotocols.org/json-table-schema/#field-descriptors). This allows formats and constraints to be defined.
230
+
231
+ Casting a value will check the value is of the expected type, is in the correct format, and complies with any constraints imposed by a schema. E.g. a date value (in ISO 8601 format) can be cast with a DateType instance. Values that can't be cast will raise an `InvalidCast` exception.
232
+
233
+ Casting a value that doesn't meet the constraints will raise a `ConstraintError` exception.
234
+
220
235
  ## Development
221
236
 
222
237
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -227,7 +242,6 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
227
242
 
228
243
  Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/jsontableschema. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
229
244
 
230
-
231
245
  ## License
232
246
 
233
247
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -28,6 +28,7 @@ require "jsontableschema/types/object"
28
28
  require "jsontableschema/types/string"
29
29
  require "jsontableschema/types/time"
30
30
 
31
+ require "jsontableschema/field"
31
32
  require "jsontableschema/validate"
32
33
  require "jsontableschema/model"
33
34
  require "jsontableschema/data"
@@ -3,33 +3,36 @@ module JsonTableSchema
3
3
 
4
4
  attr_reader :errors
5
5
 
6
- def convert(rows, fail_fast = true)
6
+ def cast_rows(rows, fail_fast = true, limit = nil)
7
7
  @errors ||= []
8
- rows.map! do |r|
8
+ parsed_rows = []
9
+ rows.each_with_index do |r, i|
9
10
  begin
10
- convert_row(r, fail_fast)
11
+ break if limit && (limit <= i)
12
+ r = r.fields if r.class == CSV::Row
13
+ parsed_rows << cast_row(r, fail_fast)
11
14
  rescue MultipleInvalid, ConversionError => e
12
15
  raise e if fail_fast == true
13
16
  @errors << e if e.is_a?(ConversionError)
14
17
  end
15
18
  end
16
19
  check_for_errors
17
- rows
20
+ parsed_rows
18
21
  end
19
22
 
20
- def convert_row(row, fail_fast = true)
23
+ alias_method :convert, :cast_rows
24
+
25
+ def cast_row(row, fail_fast = true)
21
26
  @errors ||= []
22
27
  raise_header_error(row) if row.count != fields.count
23
28
  fields.each_with_index do |field,i|
24
- row[i] = convert_column(row[i], field, fail_fast)
29
+ row[i] = cast_column(field, row[i], fail_fast)
25
30
  end
26
31
  check_for_errors
27
32
  row
28
33
  end
29
34
 
30
- def cast(field_name, value)
31
- convert_column(value, get_field(field_name), true)
32
- end
35
+ alias_method :convert_row, :cast_row
33
36
 
34
37
  private
35
38
 
@@ -41,10 +44,8 @@ module JsonTableSchema
41
44
  raise(JsonTableSchema::MultipleInvalid.new("There were errors parsing the data")) if @errors.count > 0
42
45
  end
43
46
 
44
- def convert_column(col, field, fail_fast)
45
- klass = get_class_for_type(field['type'] || 'string')
46
- converter = Kernel.const_get(klass).new(field)
47
- converter.cast(col)
47
+ def cast_column(field, col, fail_fast)
48
+ field.cast_value(col)
48
49
  rescue Exception => e
49
50
  if fail_fast == true
50
51
  raise e
@@ -53,5 +54,7 @@ module JsonTableSchema
53
54
  end
54
55
  end
55
56
 
57
+ alias_method :convert_column, :cast_column
58
+
56
59
  end
57
60
  end
@@ -0,0 +1,41 @@
1
+ module JsonTableSchema
2
+ class Field < Hash
3
+ include JsonTableSchema::Helpers
4
+
5
+ attr_reader :type_class
6
+
7
+ def initialize(descriptor)
8
+ self.merge! descriptor
9
+ @type_class = get_type
10
+ end
11
+
12
+ def name
13
+ self['name']
14
+ end
15
+
16
+ def type
17
+ self['type'] || 'string'
18
+ end
19
+
20
+ def format
21
+ self['format'] || 'default'
22
+ end
23
+
24
+ def constraints
25
+ self['constraints'] || {}
26
+ end
27
+
28
+ def cast_value(col)
29
+ klass = get_class_for_type(type)
30
+ converter = Kernel.const_get(klass).new(self)
31
+ converter.cast(col)
32
+ end
33
+
34
+ private
35
+
36
+ def get_type
37
+ Object.const_get get_class_for_type(type)
38
+ end
39
+
40
+ end
41
+ end
@@ -22,7 +22,7 @@ module JsonTableSchema
22
22
  end
23
23
 
24
24
  def get_class_for_type(type)
25
- "JsonTableSchema::Types::#{type_class_lookup[type]}"
25
+ "JsonTableSchema::Types::#{type_class_lookup[type] || 'String'}"
26
26
  end
27
27
 
28
28
  def type_class_lookup
@@ -40,6 +40,7 @@ module JsonTableSchema
40
40
  type_matches = []
41
41
  @rows.each_with_index do |row, i|
42
42
  break if @row_limit && i > @row_limit
43
+ row = row.fields if row.class == CSV::Row
43
44
 
44
45
  row_length = row.count
45
46
  headers_length = @headers.count
@@ -53,10 +53,6 @@ module JsonTableSchema
53
53
 
54
54
  private
55
55
 
56
- def fields
57
- self['fields']
58
- end
59
-
60
56
  def transform(name)
61
57
  name.downcase! if @opts[:case_insensitive_headers]
62
58
  name
@@ -69,5 +65,9 @@ module JsonTableSchema
69
65
  end
70
66
  end
71
67
 
68
+ def load_fields!
69
+ self['fields'] = (self['fields'] || []).map { |f| JsonTableSchema::Field.new(f) }
70
+ end
71
+
72
72
  end
73
73
  end
@@ -5,26 +5,27 @@ module JsonTableSchema
5
5
  include JsonTableSchema::Data
6
6
  include JsonTableSchema::Helpers
7
7
 
8
- def initialize(schema, opts = {})
9
- self.merge! parse_schema(schema)
8
+ def initialize(descriptor, opts = {})
9
+ self.merge! parse_schema(descriptor)
10
10
  @messages = []
11
11
  @opts = opts
12
+ load_fields!
12
13
  load_validator!
13
14
  expand!
14
15
  end
15
16
 
16
- def parse_schema(schema)
17
- if schema.class == Hash
18
- schema
19
- elsif schema.class == String
17
+ def parse_schema(descriptor)
18
+ if descriptor.class == Hash
19
+ descriptor
20
+ elsif descriptor.class == String
20
21
  begin
21
- JSON.parse open(schema).read
22
+ JSON.parse open(descriptor).read
22
23
  rescue Errno::ENOENT
23
- raise SchemaException.new("File not found at `#{schema}`")
24
+ raise SchemaException.new("File not found at `#{descriptor}`")
24
25
  rescue OpenURI::HTTPError => e
25
- raise SchemaException.new("URL `#{schema}` returned #{e.message}")
26
+ raise SchemaException.new("URL `#{descriptor}` returned #{e.message}")
26
27
  rescue JSON::ParserError
27
- raise SchemaException.new("File at `#{schema}` is not valid JSON")
28
+ raise SchemaException.new("File at `#{descriptor}` is not valid JSON")
28
29
  end
29
30
  else
30
31
  raise SchemaException.new("A schema must be a hash, path or URL")
@@ -7,15 +7,15 @@ module JsonTableSchema
7
7
  JsonTableSchema::Table.new(csv, nil, opts)
8
8
  end
9
9
 
10
- def initialize(csv, schema, opts = {})
10
+ def initialize(csv, descriptor, opts = {})
11
11
  @opts = opts
12
12
  @csv = parse_csv(csv)
13
- @schema = schema.nil? ? infer_schema(@csv) : JsonTableSchema::Schema.new(schema)
13
+ @schema = descriptor.nil? ? infer_schema(@csv) : JsonTableSchema::Schema.new(descriptor)
14
14
  end
15
15
 
16
16
  def parse_csv(csv)
17
- csv_string = csv.is_a?(Array) ? array_to_csv(csv) : open(csv).read
18
- CSV.parse(csv_string, csv_options)
17
+ csv = csv.is_a?(Array) ? StringIO.new(array_to_csv csv) : open(csv)
18
+ CSV.new(csv, csv_options)
19
19
  end
20
20
 
21
21
  def csv_options
@@ -24,8 +24,7 @@ module JsonTableSchema
24
24
 
25
25
  def rows(opts = {})
26
26
  fail_fast = opts[:fail_fast] || opts[:fail_fast].nil?
27
- rows = opts[:limit] ? @csv.to_a.drop(1).take(opts[:limit]) : @csv.to_a.drop(1)
28
- converted = @schema.convert(rows, fail_fast)
27
+ converted = @schema.cast_rows(@csv, fail_fast, opts[:limit])
29
28
  opts[:keyed] ? coverted_to_hash(@csv.headers, converted) : converted
30
29
  end
31
30
 
@@ -42,7 +41,9 @@ module JsonTableSchema
42
41
  end
43
42
 
44
43
  def infer_schema(csv)
45
- inferer = JsonTableSchema::Infer.new(csv.headers, csv.to_a)
44
+ headers = csv.first.to_h.keys
45
+ csv.rewind
46
+ inferer = JsonTableSchema::Infer.new(headers, csv)
46
47
  inferer.schema
47
48
  end
48
49
 
@@ -1,3 +1,3 @@
1
1
  module JsonTableSchema
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,153 +1,153 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsontableschema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - pezholio
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2016-09-19 00:00:00.000000000 Z
11
+ date: 2016-10-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ~>
18
18
  - !ruby/object:Gem::Version
19
19
  version: '1.11'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ~>
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.11'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rake
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '10.0'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - "~>"
38
+ - - ~>
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ~>
46
46
  - !ruby/object:Gem::Version
47
47
  version: '3.0'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ~>
53
53
  - !ruby/object:Gem::Version
54
54
  version: '3.0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: pry
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ~>
60
60
  - !ruby/object:Gem::Version
61
61
  version: 0.10.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ~>
67
67
  - !ruby/object:Gem::Version
68
68
  version: 0.10.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: webmock
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - ~>
74
74
  - !ruby/object:Gem::Version
75
75
  version: 2.1.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - ~>
81
81
  - !ruby/object:Gem::Version
82
82
  version: 2.1.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: coveralls
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - "~>"
87
+ - - ~>
88
88
  - !ruby/object:Gem::Version
89
89
  version: 0.8.13
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - "~>"
94
+ - - ~>
95
95
  - !ruby/object:Gem::Version
96
96
  version: 0.8.13
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: json-schema
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - "~>"
101
+ - - ~>
102
102
  - !ruby/object:Gem::Version
103
103
  version: 2.6.0
104
104
  type: :runtime
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - "~>"
108
+ - - ~>
109
109
  - !ruby/object:Gem::Version
110
110
  version: 2.6.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: uuid
113
113
  requirement: !ruby/object:Gem::Requirement
114
114
  requirements:
115
- - - "~>"
115
+ - - ~>
116
116
  - !ruby/object:Gem::Version
117
117
  version: 2.3.8
118
118
  type: :runtime
119
119
  prerelease: false
120
120
  version_requirements: !ruby/object:Gem::Requirement
121
121
  requirements:
122
- - - "~>"
122
+ - - ~>
123
123
  - !ruby/object:Gem::Version
124
124
  version: 2.3.8
125
125
  - !ruby/object:Gem::Dependency
126
126
  name: currencies
127
127
  requirement: !ruby/object:Gem::Requirement
128
128
  requirements:
129
- - - "~>"
129
+ - - ~>
130
130
  - !ruby/object:Gem::Version
131
131
  version: 0.4.2
132
132
  type: :runtime
133
133
  prerelease: false
134
134
  version_requirements: !ruby/object:Gem::Requirement
135
135
  requirements:
136
- - - "~>"
136
+ - - ~>
137
137
  - !ruby/object:Gem::Version
138
138
  version: 0.4.2
139
139
  - !ruby/object:Gem::Dependency
140
140
  name: tod
141
141
  requirement: !ruby/object:Gem::Requirement
142
142
  requirements:
143
- - - "~>"
143
+ - - ~>
144
144
  - !ruby/object:Gem::Version
145
145
  version: 2.1.0
146
146
  type: :runtime
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
- - - "~>"
150
+ - - ~>
151
151
  - !ruby/object:Gem::Version
152
152
  version: 2.1.0
153
153
  description:
@@ -157,9 +157,9 @@ executables: []
157
157
  extensions: []
158
158
  extra_rdoc_files: []
159
159
  files:
160
- - ".gitignore"
161
- - ".rspec"
162
- - ".travis.yml"
160
+ - .gitignore
161
+ - .rspec
162
+ - .travis.yml
163
163
  - CHANGELOG.md
164
164
  - CODE_OF_CONDUCT.md
165
165
  - Gemfile
@@ -182,6 +182,7 @@ files:
182
182
  - lib/jsontableschema/constraints/required.rb
183
183
  - lib/jsontableschema/data.rb
184
184
  - lib/jsontableschema/exceptions.rb
185
+ - lib/jsontableschema/field.rb
185
186
  - lib/jsontableschema/helpers.rb
186
187
  - lib/jsontableschema/infer.rb
187
188
  - lib/jsontableschema/model.rb
@@ -213,17 +214,17 @@ require_paths:
213
214
  - lib
214
215
  required_ruby_version: !ruby/object:Gem::Requirement
215
216
  requirements:
216
- - - ">="
217
+ - - ! '>='
217
218
  - !ruby/object:Gem::Version
218
219
  version: '0'
219
220
  required_rubygems_version: !ruby/object:Gem::Requirement
220
221
  requirements:
221
- - - ">="
222
+ - - ! '>='
222
223
  - !ruby/object:Gem::Version
223
224
  version: '0'
224
225
  requirements: []
225
226
  rubyforge_project:
226
- rubygems_version: 2.5.1
227
+ rubygems_version: 2.4.5
227
228
  signing_key:
228
229
  specification_version: 4
229
230
  summary: A Ruby library for working with JSON Table Schema