csvlint 0.2.6 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitattributes +1 -1
- data/.gitignore +1 -1
- data/csvlint.gemspec +2 -0
- data/features/fixtures/w3.org/.well-known/csvm +4 -0
- data/features/step_definitions/validation_errors_steps.rb +1 -1
- data/features/support/earl_formatter.rb +66 -0
- data/features/support/load_tests.rb +20 -15
- data/lib/csvlint/csvw/column.rb +103 -55
- data/lib/csvlint/csvw/date_format.rb +49 -16
- data/lib/csvlint/csvw/number_format.rb +36 -21
- data/lib/csvlint/csvw/property_checker.rb +90 -45
- data/lib/csvlint/csvw/table.rb +57 -39
- data/lib/csvlint/csvw/table_group.rb +9 -9
- data/lib/csvlint/schema.rb +2 -2
- data/lib/csvlint/validate.rb +10 -13
- data/lib/csvlint/version.rb +1 -1
- data/spec/csvw/column_spec.rb +6 -6
- data/spec/csvw/date_format_spec.rb +10 -10
- data/spec/csvw/number_format_spec.rb +29 -0
- metadata +34 -2
@@ -20,22 +20,22 @@ module Csvlint
|
|
20
20
|
@warnings += @tables.map{|url,table| table.warnings}.flatten
|
21
21
|
end
|
22
22
|
|
23
|
-
def validate_header(header, table_url)
|
23
|
+
def validate_header(header, table_url, strict)
|
24
24
|
reset
|
25
25
|
table_url = "file:#{File.absolute_path(table_url)}" if table_url.instance_of? File
|
26
26
|
table = tables[table_url]
|
27
|
-
table.validate_header(header)
|
27
|
+
table.validate_header(header, strict)
|
28
28
|
@errors += table.errors
|
29
29
|
@warnings += table.warnings
|
30
30
|
return valid?
|
31
31
|
end
|
32
32
|
|
33
|
-
def validate_row(values, row=nil, all_errors=[], table_url)
|
33
|
+
def validate_row(values, row=nil, all_errors=[], table_url, validate)
|
34
34
|
reset
|
35
35
|
table_url = "file:#{File.absolute_path(table_url)}" if table_url.instance_of? File
|
36
36
|
@validated_tables[table_url] = true
|
37
37
|
table = tables[table_url]
|
38
|
-
table.validate_row(values, row)
|
38
|
+
table.validate_row(values, row, validate)
|
39
39
|
@errors += table.errors
|
40
40
|
@warnings += table.warnings
|
41
41
|
return valid?
|
@@ -93,10 +93,10 @@ module Csvlint
|
|
93
93
|
annotations[property] = v
|
94
94
|
elsif type == :common
|
95
95
|
common_properties[property] = v
|
96
|
-
elsif type == :
|
97
|
-
warnings << Csvlint::ErrorMessage.new(:invalid_property, :metadata, nil, nil, "#{property}", nil)
|
98
|
-
else
|
96
|
+
elsif type == :inherited
|
99
97
|
inherited_properties[property] = v
|
98
|
+
else
|
99
|
+
warnings << Csvlint::ErrorMessage.new(:invalid_property, :metadata, nil, nil, "#{property}", nil)
|
100
100
|
end
|
101
101
|
end
|
102
102
|
end
|
@@ -118,7 +118,7 @@ module Csvlint
|
|
118
118
|
end
|
119
119
|
table_url = URI.join(base_url, table_url).to_s
|
120
120
|
table_desc["url"] = table_url
|
121
|
-
table = Csvlint::Csvw::Table.from_json(table_desc, base_url, lang, inherited_properties)
|
121
|
+
table = Csvlint::Csvw::Table.from_json(table_desc, base_url, lang, common_properties, inherited_properties)
|
122
122
|
tables[table_url] = table
|
123
123
|
else
|
124
124
|
warnings << Csvlint::ErrorMessage.new(:invalid_table_description, :metadata, nil, nil, "#{table_desc}", nil)
|
@@ -154,7 +154,7 @@ module Csvlint
|
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
157
|
-
return self.new(base_url, id: id, tables: tables, notes:
|
157
|
+
return self.new(base_url, id: id, tables: tables, notes: common_properties["notes"] || [], annotations: annotations, warnings: warnings)
|
158
158
|
end
|
159
159
|
|
160
160
|
private
|
data/lib/csvlint/schema.rb
CHANGED
@@ -54,7 +54,7 @@ module Csvlint
|
|
54
54
|
|
55
55
|
end
|
56
56
|
|
57
|
-
def validate_header(header, source_url=nil)
|
57
|
+
def validate_header(header, source_url=nil, validate=true)
|
58
58
|
reset
|
59
59
|
|
60
60
|
found_header = header.to_csv(:row_sep => '')
|
@@ -65,7 +65,7 @@ module Csvlint
|
|
65
65
|
return valid?
|
66
66
|
end
|
67
67
|
|
68
|
-
def validate_row(values, row=nil, all_errors=[], source_url=nil)
|
68
|
+
def validate_row(values, row=nil, all_errors=[], source_url=nil, validate=true)
|
69
69
|
reset
|
70
70
|
if values.length < fields.length
|
71
71
|
fields[values.size..-1].each_with_index do |field, i|
|
data/lib/csvlint/validate.rb
CHANGED
@@ -68,6 +68,7 @@ module Csvlint
|
|
68
68
|
@csv_header = true
|
69
69
|
@headers = {}
|
70
70
|
@lambda = options[:lambda]
|
71
|
+
@validate = options[:validate].nil? ? true : options[:validate]
|
71
72
|
@leading = ""
|
72
73
|
|
73
74
|
@limit_lines = options[:limit_lines]
|
@@ -151,6 +152,7 @@ module Csvlint
|
|
151
152
|
end
|
152
153
|
rescue ArgumentError => ae
|
153
154
|
build_errors(:invalid_encoding, :structure, @current_line, nil, @current_line) unless @reported_invalid_encoding
|
155
|
+
@current_line = @current_line+1
|
154
156
|
@reported_invalid_encoding = true
|
155
157
|
end
|
156
158
|
|
@@ -181,7 +183,6 @@ module Csvlint
|
|
181
183
|
build_exception_messages(e, stream, current_line)
|
182
184
|
end
|
183
185
|
|
184
|
-
@data << row
|
185
186
|
if row
|
186
187
|
if current_line <= 1 && @csv_header
|
187
188
|
# this conditional should be refactored somewhere
|
@@ -195,7 +196,7 @@ module Csvlint
|
|
195
196
|
build_errors(:blank_rows, :structure, current_line, nil, stream.to_s) if row.reject { |c| c.nil? || c.empty? }.size == 0
|
196
197
|
# Builds errors and warnings related to the provided schema file
|
197
198
|
if @schema
|
198
|
-
@schema.validate_row(row, current_line, all_errors, @source)
|
199
|
+
@schema.validate_row(row, current_line, all_errors, @source, @validate)
|
199
200
|
@errors += @schema.errors
|
200
201
|
all_errors += @schema.errors
|
201
202
|
@warnings += @schema.warnings
|
@@ -204,6 +205,7 @@ module Csvlint
|
|
204
205
|
end
|
205
206
|
end
|
206
207
|
end
|
208
|
+
@data << row
|
207
209
|
end
|
208
210
|
|
209
211
|
def finish
|
@@ -214,7 +216,7 @@ module Csvlint
|
|
214
216
|
# return expected_columns to calling class
|
215
217
|
build_warnings(:check_options, :structure) if @expected_columns == 1
|
216
218
|
check_consistency
|
217
|
-
check_foreign_keys
|
219
|
+
check_foreign_keys if @validate
|
218
220
|
check_mixed_linebreaks
|
219
221
|
validate_encoding
|
220
222
|
end
|
@@ -250,7 +252,7 @@ module Csvlint
|
|
250
252
|
schema = Schema.load_from_json(url)
|
251
253
|
if schema.instance_of? Csvlint::Csvw::TableGroup
|
252
254
|
if schema.tables[@source_url]
|
253
|
-
|
255
|
+
@schema = schema
|
254
256
|
else
|
255
257
|
warn_if_unsuccessful = true
|
256
258
|
build_warnings(:schema_mismatch, :context, nil, nil, @source_url, schema)
|
@@ -293,6 +295,7 @@ module Csvlint
|
|
293
295
|
end
|
294
296
|
@dialect = {
|
295
297
|
"header" => true,
|
298
|
+
"headerRowCount" => 1,
|
296
299
|
"delimiter" => ",",
|
297
300
|
"skipInitialSpace" => true,
|
298
301
|
"lineTerminator" => :auto,
|
@@ -358,7 +361,7 @@ module Csvlint
|
|
358
361
|
end
|
359
362
|
end
|
360
363
|
if @schema
|
361
|
-
@schema.validate_header(header, @source)
|
364
|
+
@schema.validate_header(header, @source, @validate)
|
362
365
|
@errors += @schema.errors
|
363
366
|
@warnings += @schema.warnings
|
364
367
|
end
|
@@ -441,15 +444,11 @@ module Csvlint
|
|
441
444
|
@schema = nil
|
442
445
|
end
|
443
446
|
end
|
444
|
-
link_schema = nil
|
445
|
-
@schema = link_schema if link_schema
|
446
|
-
|
447
447
|
paths = []
|
448
448
|
if @source_url =~ /^http(s)?/
|
449
449
|
begin
|
450
450
|
well_known_uri = URI.join(@source_url, "/.well-known/csvm")
|
451
|
-
|
452
|
-
# TODO
|
451
|
+
paths = open(well_known_uri).read.split("\n")
|
453
452
|
rescue OpenURI::HTTPError, URI::BadURIError
|
454
453
|
end
|
455
454
|
end
|
@@ -464,6 +463,7 @@ module Csvlint
|
|
464
463
|
if schema.instance_of? Csvlint::Csvw::TableGroup
|
465
464
|
if schema.tables[@source_url]
|
466
465
|
@schema = schema
|
466
|
+
return
|
467
467
|
else
|
468
468
|
warn_if_unsuccessful = true
|
469
469
|
build_warnings(:schema_mismatch, :context, nil, nil, @source_url, schema)
|
@@ -472,9 +472,6 @@ module Csvlint
|
|
472
472
|
rescue Errno::ENOENT
|
473
473
|
rescue OpenURI::HTTPError, URI::BadURIError, ArgumentError
|
474
474
|
rescue => e
|
475
|
-
STDERR.puts e.class
|
476
|
-
STDERR.puts e.message
|
477
|
-
STDERR.puts e.backtrace
|
478
475
|
raise e
|
479
476
|
end
|
480
477
|
end
|
data/lib/csvlint/version.rb
CHANGED
data/spec/csvw/column_spec.rb
CHANGED
@@ -4,21 +4,21 @@ describe Csvlint::Csvw::Column do
|
|
4
4
|
|
5
5
|
it "shouldn't generate errors for string values" do
|
6
6
|
column = Csvlint::Csvw::Column.new(1, "foo")
|
7
|
-
|
8
|
-
expect(
|
7
|
+
value = column.validate("bar", 2)
|
8
|
+
expect(value).to eq("bar")
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should generate errors for string values that aren't long enough" do
|
12
12
|
column = Csvlint::Csvw::Column.new(1, "foo", datatype: { "base" => "http://www.w3.org/2001/XMLSchema#string", "minLength" => 4 })
|
13
|
-
|
14
|
-
expect(
|
13
|
+
value = column.validate("bar", 2)
|
14
|
+
expect(value).to eq({ :invalid => "bar" })
|
15
15
|
expect(column.errors.length).to eq(1)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "shouldn't generate errors for string values that are long enough" do
|
19
19
|
column = Csvlint::Csvw::Column.new(1, "foo", datatype: { "base" => "http://www.w3.org/2001/XMLSchema#string", "minLength" => 4 })
|
20
|
-
|
21
|
-
expect(
|
20
|
+
value = column.validate("barn", 2)
|
21
|
+
expect(value).to eq("barn")
|
22
22
|
expect(column.errors.length).to eq(0)
|
23
23
|
end
|
24
24
|
|
@@ -1,40 +1,40 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Csvlint::Csvw::
|
3
|
+
describe Csvlint::Csvw::DateFormat do
|
4
4
|
|
5
5
|
it "should parse dates that match yyyy-MM-dd correctly" do
|
6
6
|
format = Csvlint::Csvw::DateFormat.new("yyyy-MM-dd")
|
7
|
-
expect(format.parse("2015-03-22")).to eql(Date.new(2015, 3, 22))
|
7
|
+
expect(format.parse("2015-03-22")[:dateTime]).to eql(Date.new(2015, 3, 22))
|
8
8
|
expect(format.parse("2015-02-30")).to eql(nil)
|
9
9
|
expect(format.parse("22/03/2015")).to eq(nil)
|
10
10
|
end
|
11
11
|
|
12
12
|
it "should parse times that match HH:mm:ss correctly" do
|
13
13
|
format = Csvlint::Csvw::DateFormat.new("HH:mm:ss")
|
14
|
-
expect(format.parse("12:34:56")).to eql({
|
14
|
+
expect(format.parse("12:34:56")).to eql({ :hour => 12, :minute => 34, :second => 56.0, :string => "12:34:56", :dateTime => DateTime.new(0,1,1,12,34,56.0,"+00:00") })
|
15
15
|
expect(format.parse("22/03/2015")).to eq(nil)
|
16
16
|
end
|
17
17
|
|
18
18
|
it "should parse times that match HH:mm:ss.SSS correctly" do
|
19
19
|
format = Csvlint::Csvw::DateFormat.new("HH:mm:ss.SSS")
|
20
|
-
expect(format.parse("12:34:56")).to eql({
|
21
|
-
expect(format.parse("12:34:56.78")).to eql({
|
22
|
-
expect(format.parse("12:34:56.789")).to eql({
|
20
|
+
expect(format.parse("12:34:56")).to eql({ :hour => 12, :minute => 34, :second => 56.0, :string => "12:34:56", :dateTime => DateTime.new(0,1,1,12,34,56.0,"+00:00") })
|
21
|
+
expect(format.parse("12:34:56.78")).to eql({ :hour => 12, :minute => 34, :second => 56.78, :string => "12:34:56.78", :dateTime => DateTime.new(0,1,1,12,34,56.78,"+00:00") })
|
22
|
+
expect(format.parse("12:34:56.789")).to eql({ :hour => 12, :minute => 34, :second => 56.789, :string => "12:34:56.789", :dateTime => DateTime.new(0,1,1,12,34,56.789,"+00:00") })
|
23
23
|
expect(format.parse("12:34:56.7890")).to eql(nil)
|
24
24
|
expect(format.parse("22/03/2015")).to eq(nil)
|
25
25
|
end
|
26
26
|
|
27
27
|
it "should parse dateTimes that match yyyy-MM-ddTHH:mm:ss correctly" do
|
28
28
|
format = Csvlint::Csvw::DateFormat.new("yyyy-MM-ddTHH:mm:ss")
|
29
|
-
expect(format.parse("2015-03-15T15:02:37")).to eql(DateTime.new(2015, 3, 15, 15, 2, 37))
|
29
|
+
expect(format.parse("2015-03-15T15:02:37")[:dateTime]).to eql(DateTime.new(2015, 3, 15, 15, 2, 37))
|
30
30
|
expect(format.parse("12:34:56")).to eql(nil)
|
31
31
|
expect(format.parse("22/03/2015")).to eq(nil)
|
32
32
|
end
|
33
33
|
|
34
34
|
it "should parse dateTimes that match yyyy-MM-ddTHH:mm:ss.S correctly" do
|
35
35
|
format = Csvlint::Csvw::DateFormat.new("yyyy-MM-ddTHH:mm:ss.S")
|
36
|
-
expect(format.parse("2015-03-15T15:02:37")).to eql(DateTime.new(2015, 3, 15, 15, 2, 37.0))
|
37
|
-
expect(format.parse("2015-03-15T15:02:37.4")).to eql(DateTime.new(2015, 3, 15, 15, 2, 37.4))
|
36
|
+
expect(format.parse("2015-03-15T15:02:37")[:dateTime]).to eql(DateTime.new(2015, 3, 15, 15, 2, 37.0))
|
37
|
+
expect(format.parse("2015-03-15T15:02:37.4")[:dateTime]).to eql(DateTime.new(2015, 3, 15, 15, 2, 37.4))
|
38
38
|
expect(format.parse("2015-03-15T15:02:37.45")).to eql(nil)
|
39
39
|
expect(format.parse("12:34:56")).to eql(nil)
|
40
40
|
expect(format.parse("22/03/2015")).to eq(nil)
|
@@ -43,7 +43,7 @@ describe Csvlint::Csvw::NumberFormat do
|
|
43
43
|
it "should parse dateTimes that match M/d/yyyy HH:mm correctly" do
|
44
44
|
format = Csvlint::Csvw::DateFormat.new("M/d/yyyy HH:mm")
|
45
45
|
expect(format.parse("2015-03-15T15:02:37")).to eql(nil)
|
46
|
-
expect(format.parse("3/15/2015 15:02")).to eql(DateTime.new(2015, 3, 15, 15, 2))
|
46
|
+
expect(format.parse("3/15/2015 15:02")[:dateTime]).to eql(DateTime.new(2015, 3, 15, 15, 2))
|
47
47
|
end
|
48
48
|
|
49
49
|
end
|
@@ -152,6 +152,7 @@ describe Csvlint::Csvw::NumberFormat do
|
|
152
152
|
|
153
153
|
it "should parse numbers that match ##0 correctly" do
|
154
154
|
format = Csvlint::Csvw::NumberFormat.new("##0")
|
155
|
+
expect(format.parse("-1")).to eql(-1)
|
155
156
|
expect(format.parse("1")).to eql(1)
|
156
157
|
expect(format.parse("12")).to eql(12)
|
157
158
|
expect(format.parse("123")).to eql(123)
|
@@ -380,6 +381,21 @@ describe Csvlint::Csvw::NumberFormat do
|
|
380
381
|
expect(format.parse("12.34E5")).to eql(12.34E5)
|
381
382
|
end
|
382
383
|
|
384
|
+
it "should parse numbers that match %000 correctly" do
|
385
|
+
format = Csvlint::Csvw::NumberFormat.new("%000")
|
386
|
+
expect(format.parse("%001")).to eq(0.01)
|
387
|
+
expect(format.parse("%012")).to eq(0.12)
|
388
|
+
expect(format.parse("%123")).to eq(1.23)
|
389
|
+
expect(format.parse("%1234")).to eq(12.34)
|
390
|
+
end
|
391
|
+
|
392
|
+
it "should parse numbers that match -0 correctly" do
|
393
|
+
format = Csvlint::Csvw::NumberFormat.new("-0")
|
394
|
+
expect(format.parse("1")).to eq(nil)
|
395
|
+
expect(format.parse("-1")).to eq(-1)
|
396
|
+
expect(format.parse("-12")).to eq(-12)
|
397
|
+
end
|
398
|
+
|
383
399
|
it "should parse numbers normally when there is no pattern" do
|
384
400
|
format = Csvlint::Csvw::NumberFormat.new()
|
385
401
|
expect(format.parse("1")).to eql(1)
|
@@ -414,4 +430,17 @@ describe Csvlint::Csvw::NumberFormat do
|
|
414
430
|
expect(format.parse("-INF")).to eql(-Float::INFINITY)
|
415
431
|
end
|
416
432
|
|
433
|
+
it "should parse numbers including decimal separators when they are specified" do
|
434
|
+
format = Csvlint::Csvw::NumberFormat.new(nil, " ", ",")
|
435
|
+
expect(format.parse("1")).to eql(1)
|
436
|
+
expect(format.parse("12,3")).to eql(12.3)
|
437
|
+
expect(format.parse("12,34")).to eql(12.34)
|
438
|
+
expect(format.parse("12,3E4")).to eql(12.3E4)
|
439
|
+
expect(format.parse("12,3E45")).to eql(12.3E45)
|
440
|
+
expect(format.parse("12,34E5")).to eql(12.34E5)
|
441
|
+
expect(format.parse("1 234")).to eql(1234)
|
442
|
+
expect(format.parse("1 234 567")).to eql(1234567)
|
443
|
+
expect(format.parse("1 234")).to eq(nil)
|
444
|
+
end
|
445
|
+
|
417
446
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: csvlint
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- pezholio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-01-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: mime-types
|
@@ -332,6 +332,34 @@ dependencies:
|
|
332
332
|
- - ! '>='
|
333
333
|
- !ruby/object:Gem::Version
|
334
334
|
version: '0'
|
335
|
+
- !ruby/object:Gem::Dependency
|
336
|
+
name: rdf
|
337
|
+
requirement: !ruby/object:Gem::Requirement
|
338
|
+
requirements:
|
339
|
+
- - ! '>='
|
340
|
+
- !ruby/object:Gem::Version
|
341
|
+
version: '0'
|
342
|
+
type: :development
|
343
|
+
prerelease: false
|
344
|
+
version_requirements: !ruby/object:Gem::Requirement
|
345
|
+
requirements:
|
346
|
+
- - ! '>='
|
347
|
+
- !ruby/object:Gem::Version
|
348
|
+
version: '0'
|
349
|
+
- !ruby/object:Gem::Dependency
|
350
|
+
name: rdf-turtle
|
351
|
+
requirement: !ruby/object:Gem::Requirement
|
352
|
+
requirements:
|
353
|
+
- - ! '>='
|
354
|
+
- !ruby/object:Gem::Version
|
355
|
+
version: '0'
|
356
|
+
type: :development
|
357
|
+
prerelease: false
|
358
|
+
version_requirements: !ruby/object:Gem::Requirement
|
359
|
+
requirements:
|
360
|
+
- - ! '>='
|
361
|
+
- !ruby/object:Gem::Version
|
362
|
+
version: '0'
|
335
363
|
description: CSV Validator
|
336
364
|
email:
|
337
365
|
- pezholio@gmail.com
|
@@ -371,6 +399,7 @@ files:
|
|
371
399
|
- features/fixtures/title-row.csv
|
372
400
|
- features/fixtures/valid.csv
|
373
401
|
- features/fixtures/valid_many_rows.csv
|
402
|
+
- features/fixtures/w3.org/.well-known/csvm
|
374
403
|
- features/fixtures/windows-line-endings.csv
|
375
404
|
- features/information.feature
|
376
405
|
- features/parse_csv.feature
|
@@ -386,6 +415,7 @@ files:
|
|
386
415
|
- features/step_definitions/validation_info_steps.rb
|
387
416
|
- features/step_definitions/validation_warnings_steps.rb
|
388
417
|
- features/support/aruba.rb
|
418
|
+
- features/support/earl_formatter.rb
|
389
419
|
- features/support/env.rb
|
390
420
|
- features/support/load_tests.rb
|
391
421
|
- features/support/webmock.rb
|
@@ -458,6 +488,7 @@ test_files:
|
|
458
488
|
- features/fixtures/title-row.csv
|
459
489
|
- features/fixtures/valid.csv
|
460
490
|
- features/fixtures/valid_many_rows.csv
|
491
|
+
- features/fixtures/w3.org/.well-known/csvm
|
461
492
|
- features/fixtures/windows-line-endings.csv
|
462
493
|
- features/information.feature
|
463
494
|
- features/parse_csv.feature
|
@@ -473,6 +504,7 @@ test_files:
|
|
473
504
|
- features/step_definitions/validation_info_steps.rb
|
474
505
|
- features/step_definitions/validation_warnings_steps.rb
|
475
506
|
- features/support/aruba.rb
|
507
|
+
- features/support/earl_formatter.rb
|
476
508
|
- features/support/env.rb
|
477
509
|
- features/support/load_tests.rb
|
478
510
|
- features/support/webmock.rb
|