csvlint 1.0.0 → 1.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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +4 -0
  3. data/.github/workflows/push.yml +14 -2
  4. data/.pre-commit-hooks.yaml +5 -0
  5. data/.ruby-version +1 -1
  6. data/.standard_todo.yml +43 -0
  7. data/CHANGELOG.md +84 -32
  8. data/Dockerfile +16 -0
  9. data/Gemfile +2 -2
  10. data/README.md +30 -9
  11. data/Rakefile +7 -7
  12. data/csvlint.gemspec +14 -16
  13. data/docker_notes_for_windows.txt +20 -0
  14. data/features/step_definitions/cli_steps.rb +11 -11
  15. data/features/step_definitions/information_steps.rb +4 -4
  16. data/features/step_definitions/parse_csv_steps.rb +11 -11
  17. data/features/step_definitions/schema_validation_steps.rb +10 -10
  18. data/features/step_definitions/sources_steps.rb +1 -1
  19. data/features/step_definitions/validation_errors_steps.rb +19 -19
  20. data/features/step_definitions/validation_info_steps.rb +9 -9
  21. data/features/step_definitions/validation_warnings_steps.rb +11 -11
  22. data/features/support/aruba.rb +6 -6
  23. data/features/support/earl_formatter.rb +39 -39
  24. data/features/support/env.rb +10 -11
  25. data/features/support/load_tests.rb +107 -103
  26. data/features/support/webmock.rb +2 -2
  27. data/lib/csvlint/cli.rb +133 -130
  28. data/lib/csvlint/csvw/column.rb +279 -280
  29. data/lib/csvlint/csvw/date_format.rb +90 -92
  30. data/lib/csvlint/csvw/metadata_error.rb +1 -3
  31. data/lib/csvlint/csvw/number_format.rb +40 -32
  32. data/lib/csvlint/csvw/property_checker.rb +714 -717
  33. data/lib/csvlint/csvw/table.rb +49 -52
  34. data/lib/csvlint/csvw/table_group.rb +24 -23
  35. data/lib/csvlint/error_collector.rb +2 -0
  36. data/lib/csvlint/error_message.rb +0 -1
  37. data/lib/csvlint/field.rb +153 -141
  38. data/lib/csvlint/schema.rb +34 -42
  39. data/lib/csvlint/validate.rb +161 -143
  40. data/lib/csvlint/version.rb +1 -1
  41. data/lib/csvlint.rb +22 -23
  42. data/spec/csvw/column_spec.rb +15 -16
  43. data/spec/csvw/date_format_spec.rb +5 -7
  44. data/spec/csvw/number_format_spec.rb +2 -4
  45. data/spec/csvw/table_group_spec.rb +103 -105
  46. data/spec/csvw/table_spec.rb +71 -73
  47. data/spec/field_spec.rb +116 -121
  48. data/spec/schema_spec.rb +129 -139
  49. data/spec/spec_helper.rb +6 -6
  50. data/spec/validator_spec.rb +167 -190
  51. metadata +23 -55
@@ -1,6 +1,6 @@
1
- require 'json'
2
- require 'open-uri'
3
- require 'uri'
1
+ require "json"
2
+ require "open-uri"
3
+ require "uri"
4
4
 
5
5
  BASE_URI = "https://w3c.github.io/csvw/tests/"
6
6
  BASE_PATH = File.join(File.dirname(__FILE__), "..", "fixtures", "csvw")
@@ -11,109 +11,113 @@ SCRIPT_FILE_PATH = File.join(File.dirname(__FILE__), "..", "..", "bin", "run-csv
11
11
  Dir.mkdir(BASE_PATH) unless Dir.exist?(BASE_PATH)
12
12
 
13
13
  def cache_file(filename)
14
- file = File.join(BASE_PATH, filename)
15
- uri = URI.join(BASE_URI, filename)
16
- unless File.exist?(file)
17
- if filename.include? "/"
18
- levels = filename.split("/")[0..-2]
19
- for i in 0..levels.length
20
- dir = File.join(BASE_PATH, levels[0..i].join("/"))
21
- Dir.mkdir(dir) unless Dir.exist?(dir)
22
- end
23
- end
24
- STDERR.puts("storing #{file} locally")
25
- File.open(file, 'wb') do |f|
26
- f.puts URI.open(uri, 'rb').read
27
- end
28
- end
29
- return uri, file
14
+ file = File.join(BASE_PATH, filename)
15
+ uri = URI.join(BASE_URI, filename)
16
+ unless File.exist?(file)
17
+ if filename.include? "/"
18
+ levels = filename.split("/")[0..-2]
19
+ for i in 0..levels.length
20
+ dir = File.join(BASE_PATH, levels[0..i].join("/"))
21
+ Dir.mkdir(dir) unless Dir.exist?(dir)
22
+ end
23
+ end
24
+ warn("storing #{file} locally")
25
+ File.open(file, "wb") do |f|
26
+ f.puts URI.open(uri, "rb").read
27
+ end
28
+ end
29
+ [uri, file]
30
30
  end
31
31
 
32
- File.open(SCRIPT_FILE_PATH, 'w') do |file|
33
- File.chmod(0755, SCRIPT_FILE_PATH)
34
- manifest = JSON.parse( URI.open("#{BASE_URI}manifest-validation.jsonld").read )
35
- manifest["entries"].each do |entry|
36
- type = "valid"
37
- case entry["type"]
38
- when "csvt:WarningValidationTest"
39
- type = "warnings"
40
- when "csvt:NegativeValidationTest"
41
- type = "errors"
42
- end
43
- file.puts "echo \"#{entry["id"].split("#")[-1]}: #{entry["name"].gsub("`", "'")}\""
44
- file.puts "echo \"#{type}: #{entry["comment"].gsub("\"", "\\\"").gsub("`", "'")}\""
45
- if entry["action"].end_with?(".json")
46
- file.puts "csvlint --schema=features/fixtures/csvw/#{entry["action"]}"
47
- elsif entry["option"] && entry["option"]["metadata"]
48
- file.puts "csvlint features/fixtures/csvw/#{entry["action"]} --schema=features/fixtures/csvw/#{entry["option"]["metadata"]}"
49
- else
50
- file.puts "csvlint features/fixtures/csvw/#{entry["action"]}"
51
- end
52
- file.puts "echo"
53
- end
54
- end unless File.exist? SCRIPT_FILE_PATH
32
+ unless File.exist? SCRIPT_FILE_PATH
33
+ File.open(SCRIPT_FILE_PATH, "w") do |file|
34
+ File.chmod(0o755, SCRIPT_FILE_PATH)
35
+ manifest = JSON.parse(URI.open("#{BASE_URI}manifest-validation.jsonld").read)
36
+ manifest["entries"].each do |entry|
37
+ type = "valid"
38
+ case entry["type"]
39
+ when "csvt:WarningValidationTest"
40
+ type = "warnings"
41
+ when "csvt:NegativeValidationTest"
42
+ type = "errors"
43
+ end
44
+ file.puts "echo \"#{entry["id"].split("#")[-1]}: #{entry["name"].tr("`", "'")}\""
45
+ file.puts "echo \"#{type}: #{entry["comment"].gsub("\"", "\\\"").tr("`", "'")}\""
46
+ if entry["action"].end_with?(".json")
47
+ file.puts "csvlint --schema=features/fixtures/csvw/#{entry["action"]}"
48
+ elsif entry["option"] && entry["option"]["metadata"]
49
+ file.puts "csvlint features/fixtures/csvw/#{entry["action"]} --schema=features/fixtures/csvw/#{entry["option"]["metadata"]}"
50
+ else
51
+ file.puts "csvlint features/fixtures/csvw/#{entry["action"]}"
52
+ end
53
+ file.puts "echo"
54
+ end
55
+ end
56
+ end
55
57
 
56
- File.open(VALIDATION_FEATURE_FILE_PATH, 'w') do |file|
57
- file.puts "# Auto-generated file based on standard validation CSVW tests from #{BASE_URI}manifest-validation.jsonld"
58
- file.puts ""
58
+ unless File.exist? VALIDATION_FEATURE_FILE_PATH
59
+ File.open(VALIDATION_FEATURE_FILE_PATH, "w") do |file|
60
+ file.puts "# Auto-generated file based on standard validation CSVW tests from #{BASE_URI}manifest-validation.jsonld"
61
+ file.puts ""
59
62
 
60
- manifest = JSON.parse( URI.open("#{BASE_URI}manifest-validation.jsonld").read )
63
+ manifest = JSON.parse(URI.open("#{BASE_URI}manifest-validation.jsonld").read)
61
64
 
62
- file.puts "Feature: #{manifest["label"]}"
63
- file.puts ""
65
+ file.puts "Feature: #{manifest["label"]}"
66
+ file.puts ""
64
67
 
65
- manifest["entries"].each do |entry|
66
- action_uri, action_file = cache_file(entry["action"])
67
- metadata = nil
68
- provided_files = []
69
- missing_files = []
70
- file.puts "\t# #{entry["id"]}"
71
- file.puts "\t# #{entry["comment"]}"
72
- file.puts "\tScenario: #{entry["id"]} #{entry["name"].gsub("<", "less than")}"
73
- if entry["action"].end_with?(".json")
74
- file.puts "\t\tGiven I have a metadata file called \"csvw/#{entry["action"]}\""
75
- file.puts "\t\tAnd the metadata is stored at the url \"#{action_uri}\""
76
- else
77
- file.puts "\t\tGiven I have a CSV file called \"csvw/#{entry["action"]}\""
78
- file.puts "\t\tAnd it has a Link header holding \"#{entry["httpLink"]}\"" if entry["httpLink"]
79
- file.puts "\t\tAnd it is stored at the url \"#{action_uri}\""
80
- if entry["option"] && entry["option"]["metadata"]
81
- # no need to store the file here, as it will be listed in the 'implicit' list, which all get stored
82
- metadata = URI.join(BASE_URI, entry["option"]["metadata"])
83
- file.puts "\t\tAnd I have a metadata file called \"csvw/#{entry["option"]["metadata"]}\""
84
- file.puts "\t\tAnd the metadata is stored at the url \"#{metadata}\""
85
- end
86
- provided_files << action_uri.to_s
87
- if entry["name"].include?("/.well-known/csvm")
88
- file.puts "\t\tAnd I have a file called \"w3.org/.well-known/csvm\" at the url \"https://www.w3.org/.well-known/csvm\""
89
- missing_files << "#{action_uri}.json"
90
- missing_files << URI.join(action_uri, 'csvm.json').to_s
91
- else
92
- missing_files << URI.join(action_uri, '/.well-known/csvm').to_s
93
- end
94
- missing_files << "#{action_uri}-metadata.json"
95
- missing_files << URI.join(action_uri, 'csv-metadata.json').to_s
96
- end
97
- entry["implicit"].each do |implicit|
98
- implicit_uri, implicit_file = cache_file(implicit)
99
- provided_files << implicit_uri.to_s
100
- unless implicit_uri == metadata
101
- file.puts "\t\tAnd I have a file called \"csvw/#{implicit}\" at the url \"#{implicit_uri}\""
102
- end
103
- end if entry["implicit"]
104
- missing_files.each do |uri|
105
- file.puts "\t\tAnd there is no file at the url \"#{uri}\"" unless provided_files.include? uri
106
- end
107
- file.puts "\t\tWhen I carry out CSVW validation"
108
- if entry["type"] == "csvt:WarningValidationTest"
109
- file.puts "\t\tThen there should not be errors"
110
- file.puts "\t\tAnd there should be warnings"
111
- elsif entry["type"] == "csvt:NegativeValidationTest"
112
- file.puts "\t\tThen there should be errors"
113
- else
114
- file.puts "\t\tThen there should not be errors"
115
- file.puts "\t\tAnd there should not be warnings"
116
- end
117
- file.puts "\t"
118
- end
119
- end unless File.exist? VALIDATION_FEATURE_FILE_PATH
68
+ manifest["entries"].each do |entry|
69
+ action_uri, action_file = cache_file(entry["action"])
70
+ metadata = nil
71
+ provided_files = []
72
+ missing_files = []
73
+ file.puts "\t# #{entry["id"]}"
74
+ file.puts "\t# #{entry["comment"]}"
75
+ file.puts "\tScenario: #{entry["id"]} #{entry["name"].gsub("<", "less than")}"
76
+ if entry["action"].end_with?(".json")
77
+ file.puts "\t\tGiven I have a metadata file called \"csvw/#{entry["action"]}\""
78
+ file.puts "\t\tAnd the metadata is stored at the url \"#{action_uri}\""
79
+ else
80
+ file.puts "\t\tGiven I have a CSV file called \"csvw/#{entry["action"]}\""
81
+ file.puts "\t\tAnd it has a Link header holding \"#{entry["httpLink"]}\"" if entry["httpLink"]
82
+ file.puts "\t\tAnd it is stored at the url \"#{action_uri}\""
83
+ if entry["option"] && entry["option"]["metadata"]
84
+ # no need to store the file here, as it will be listed in the 'implicit' list, which all get stored
85
+ metadata = URI.join(BASE_URI, entry["option"]["metadata"])
86
+ file.puts "\t\tAnd I have a metadata file called \"csvw/#{entry["option"]["metadata"]}\""
87
+ file.puts "\t\tAnd the metadata is stored at the url \"#{metadata}\""
88
+ end
89
+ provided_files << action_uri.to_s
90
+ if entry["name"].include?("/.well-known/csvm")
91
+ file.puts "\t\tAnd I have a file called \"w3.org/.well-known/csvm\" at the url \"https://www.w3.org/.well-known/csvm\""
92
+ missing_files << "#{action_uri}.json"
93
+ missing_files << URI.join(action_uri, "csvm.json").to_s
94
+ else
95
+ missing_files << URI.join(action_uri, "/.well-known/csvm").to_s
96
+ end
97
+ missing_files << "#{action_uri}-metadata.json"
98
+ missing_files << URI.join(action_uri, "csv-metadata.json").to_s
99
+ end
100
+ entry["implicit"]&.each do |implicit|
101
+ implicit_uri, implicit_file = cache_file(implicit)
102
+ provided_files << implicit_uri.to_s
103
+ unless implicit_uri == metadata
104
+ file.puts "\t\tAnd I have a file called \"csvw/#{implicit}\" at the url \"#{implicit_uri}\""
105
+ end
106
+ end
107
+ missing_files.each do |uri|
108
+ file.puts "\t\tAnd there is no file at the url \"#{uri}\"" unless provided_files.include? uri
109
+ end
110
+ file.puts "\t\tWhen I carry out CSVW validation"
111
+ if entry["type"] == "csvt:WarningValidationTest"
112
+ file.puts "\t\tThen there should not be errors"
113
+ file.puts "\t\tAnd there should be warnings"
114
+ elsif entry["type"] == "csvt:NegativeValidationTest"
115
+ file.puts "\t\tThen there should be errors"
116
+ else
117
+ file.puts "\t\tThen there should not be errors"
118
+ file.puts "\t\tAnd there should not be warnings"
119
+ end
120
+ file.puts "\t"
121
+ end
122
+ end
123
+ end
@@ -1,3 +1,3 @@
1
- require 'webmock/cucumber'
1
+ require "webmock/cucumber"
2
2
 
3
- WebMock.disable_net_connect!(allow: %r{csvw/tests})
3
+ WebMock.disable_net_connect!(allow: %r{csvw/tests})
data/lib/csvlint/cli.rb CHANGED
@@ -1,15 +1,13 @@
1
- require 'csvlint'
2
- require 'rainbow'
3
- require 'active_support/json'
4
- require 'json'
5
- require 'pp'
6
- require 'thor'
1
+ require "csvlint"
2
+ require "rainbow"
3
+ require "active_support/json"
4
+ require "json"
5
+ require "thor"
7
6
 
8
- require 'active_support/inflector'
7
+ require "active_support/inflector"
9
8
 
10
9
  module Csvlint
11
10
  class Cli < Thor
12
-
13
11
  desc "myfile.csv OR csvlint http://example.com/myfile.csv", "Supports validating CSV files to check their syntax and contents"
14
12
 
15
13
  option :dump_errors, desc: "Pretty print error and warning objects.", type: :boolean, aliases: :d
@@ -36,162 +34,167 @@ module Csvlint
36
34
 
37
35
  private
38
36
 
39
- def read_source(source)
40
- if source.nil?
41
- # If no source is present, try reading from stdin
42
- if !$stdin.tty?
43
- source = StringIO.new(STDIN.read) rescue nil
44
- return_error "No CSV data to validate" if !options[:schema] && source.nil?
37
+ def read_source(source)
38
+ if source.nil?
39
+ # If no source is present, try reading from stdin
40
+ if !$stdin.tty?
41
+ source = begin
42
+ StringIO.new($stdin.read)
43
+ rescue
44
+ nil
45
45
  end
46
- else
47
- # If the source isn't a URL, it's a file
48
- unless source =~ /^http(s)?/
49
- begin
50
- source = File.new( source )
51
- rescue Errno::ENOENT
52
- return_error "#{source} not found"
53
- end
46
+ return_error "No CSV data to validate" if !options[:schema] && source.nil?
47
+ end
48
+ else
49
+ # If the source isn't a URL, it's a file
50
+ unless /^http(s)?/.match?(source)
51
+ begin
52
+ source = File.new(source)
53
+ rescue Errno::ENOENT
54
+ return_error "#{source} not found"
54
55
  end
55
56
  end
56
-
57
- source
58
57
  end
59
58
 
60
- def get_schema(schema)
61
- begin
62
- schema = Csvlint::Schema.load_from_uri(schema, false)
63
- rescue Csvlint::Csvw::MetadataError => e
64
- return_error "invalid metadata: #{e.message}#{" at " + e.path if e.path}"
65
- rescue OpenURI::HTTPError, Errno::ENOENT
66
- return_error "#{options[:schema]} not found"
67
- end
59
+ source
60
+ end
68
61
 
69
- if schema.class == Csvlint::Schema && schema.description == "malformed"
70
- return_error "invalid metadata: malformed JSON"
71
- end
62
+ def get_schema(schema)
63
+ begin
64
+ schema = Csvlint::Schema.load_from_uri(schema, false)
65
+ rescue Csvlint::Csvw::MetadataError => e
66
+ return_error "invalid metadata: #{e.message}#{" at " + e.path if e.path}"
67
+ rescue OpenURI::HTTPError, Errno::ENOENT
68
+ return_error "#{options[:schema]} not found"
69
+ end
72
70
 
73
- schema
71
+ if schema.instance_of?(Csvlint::Schema) && schema.description == "malformed"
72
+ return_error "invalid metadata: malformed JSON"
74
73
  end
75
74
 
76
- def fetch_schema_tables(schema, options)
77
- valid = true
75
+ schema
76
+ end
78
77
 
79
- unless schema.instance_of? Csvlint::Csvw::TableGroup
80
- return_error "No CSV data to validate."
81
- end
82
- schema.tables.keys.each do |source|
78
+ def fetch_schema_tables(schema, options)
79
+ valid = true
80
+
81
+ unless schema.instance_of? Csvlint::Csvw::TableGroup
82
+ return_error "No CSV data to validate."
83
+ end
84
+ schema.tables.keys.each do |source|
85
+ unless /^http(s)?/.match?(source)
83
86
  begin
84
- source = source.sub("file:","")
85
- source = File.new( source )
87
+ source = source.sub("file:", "")
88
+ source = File.new(source)
86
89
  rescue Errno::ENOENT
87
90
  return_error "#{source} not found"
88
- end unless source =~ /^http(s)?/
89
- valid &= validate_csv(source, schema, options[:dump_errors], nil, options[:werror])
90
- end
91
-
92
- exit 1 unless valid
93
- end
94
-
95
- def print_error(index, error, dump, color)
96
- location = ""
97
- location += error.row.to_s if error.row
98
- location += "#{error.row ? "," : ""}#{error.column.to_s}" if error.column
99
- if error.row || error.column
100
- location = "#{error.row ? "Row" : "Column"}: #{location}"
101
- end
102
- output_string = "#{index+1}. "
103
- if error.column && @schema && @schema.class == Csvlint::Schema
104
- if @schema.fields[error.column - 1] != nil
105
- output_string += "#{@schema.fields[error.column - 1].name}: "
106
91
  end
107
92
  end
108
- output_string += "#{error.type}"
109
- output_string += ". #{location}" unless location.empty?
110
- output_string += ". #{error.content}" if error.content
93
+ valid &= validate_csv(source, schema, options[:dump_errors], nil, options[:werror])
94
+ end
111
95
 
112
- puts Rainbow(output_string).color(color)
96
+ exit 1 unless valid
97
+ end
113
98
 
114
- if dump
115
- pp error
99
+ def print_error(index, error, dump, color)
100
+ location = ""
101
+ location += error.row.to_s if error.row
102
+ location += "#{error.row ? "," : ""}#{error.column}" if error.column
103
+ if error.row || error.column
104
+ location = "#{error.row ? "Row" : "Column"}: #{location}"
105
+ end
106
+ output_string = "#{index + 1}. "
107
+ if error.column && @schema && @schema.instance_of?(Csvlint::Schema)
108
+ if @schema.fields[error.column - 1] != nil
109
+ output_string += "#{@schema.fields[error.column - 1].name}: "
116
110
  end
117
111
  end
112
+ output_string += error.type.to_s
113
+ output_string += ". #{location}" unless location.empty?
114
+ output_string += ". #{error.content}" if error.content
118
115
 
119
- def print_errors(errors, dump)
120
- if errors.size > 0
121
- errors.each_with_index { |error, i| print_error(i, error, dump, :red) }
122
- end
116
+ puts Rainbow(output_string).color(color)
117
+
118
+ if dump
119
+ pp error
123
120
  end
121
+ end
124
122
 
125
- def return_error(message)
126
- puts Rainbow(message).red
127
- exit 1
123
+ def print_errors(errors, dump)
124
+ if errors.size > 0
125
+ errors.each_with_index { |error, i| print_error(i, error, dump, :red) }
128
126
  end
127
+ end
129
128
 
130
- def validate_csv(source, schema, dump, json, werror)
131
- @error_count = 0
129
+ def return_error(message)
130
+ puts Rainbow(message).red
131
+ exit 1
132
+ end
132
133
 
133
- if json === true
134
- validator = Csvlint::Validator.new( source, {}, schema )
135
- else
136
- validator = Csvlint::Validator.new( source, {}, schema, { lambda: report_lines } )
137
- end
134
+ def validate_csv(source, schema, dump, json, werror)
135
+ @error_count = 0
138
136
 
139
- if source.class == String
140
- csv = source
141
- elsif source.class == File
142
- csv = source.path
143
- else
144
- csv = "CSV"
145
- end
137
+ validator = if json === true
138
+ Csvlint::Validator.new(source, {}, schema)
139
+ else
140
+ Csvlint::Validator.new(source, {}, schema, {lambda: report_lines})
141
+ end
146
142
 
147
- if json === true
148
- json = {
149
- validation: {
150
- state: validator.valid? ? "valid" : "invalid",
151
- errors: validator.errors.map { |v| hashify(v) },
152
- warnings: validator.warnings.map { |v| hashify(v) },
153
- info: validator.info_messages.map { |v| hashify(v) },
154
- }
155
- }.to_json
156
- print json
157
- else
158
- puts "\r\n#{csv} is #{validator.valid? ? Rainbow("VALID").green : Rainbow("INVALID").red}"
159
- print_errors(validator.errors, dump)
160
- print_errors(validator.warnings, dump)
161
- end
143
+ csv = if source.instance_of?(String)
144
+ source
145
+ elsif source.instance_of?(File)
146
+ source.path
147
+ else
148
+ "CSV"
149
+ end
162
150
 
163
- return false if werror && validator.warnings.size > 0
164
- return validator.valid?
151
+ if json === true
152
+ json = {
153
+ validation: {
154
+ state: validator.valid? ? "valid" : "invalid",
155
+ errors: validator.errors.map { |v| hashify(v) },
156
+ warnings: validator.warnings.map { |v| hashify(v) },
157
+ info: validator.info_messages.map { |v| hashify(v) }
158
+ }
159
+ }.to_json
160
+ print json
161
+ else
162
+ puts "\r\n#{csv} is #{validator.valid? ? Rainbow("VALID").green : Rainbow("INVALID").red}"
163
+ print_errors(validator.errors, dump)
164
+ print_errors(validator.warnings, dump)
165
165
  end
166
166
 
167
- def hashify(error)
168
- h = {
169
- type: error.type,
170
- category: error.category,
171
- row: error.row,
172
- col: error.column
173
- }
174
-
175
- if error.column && @schema && @schema.class == Csvlint::Schema && @schema.fields[error.column - 1] != nil
176
- field = @schema.fields[error.column - 1]
177
- h[:header] = field.name
178
- h[:constraints] = Hash[field.constraints.map {|k,v| [k.underscore, v] }]
179
- end
167
+ return false if werror && validator.warnings.size > 0
168
+ validator.valid?
169
+ end
180
170
 
181
- h
171
+ def hashify(error)
172
+ h = {
173
+ type: error.type,
174
+ category: error.category,
175
+ row: error.row,
176
+ col: error.column
177
+ }
178
+
179
+ if error.column && @schema && @schema.instance_of?(Csvlint::Schema) && @schema.fields[error.column - 1] != nil
180
+ field = @schema.fields[error.column - 1]
181
+ h[:header] = field.name
182
+ h[:constraints] = field.constraints.map { |k, v| [k.underscore, v] }.to_h
182
183
  end
183
184
 
184
- def report_lines
185
- lambda do |row|
186
- new_errors = row.errors.count
187
- if new_errors > @error_count
188
- print Rainbow("!").red
189
- else
190
- print Rainbow(".").green
191
- end
192
- @error_count = new_errors
185
+ h
186
+ end
187
+
188
+ def report_lines
189
+ lambda do |row|
190
+ new_errors = row.errors.count
191
+ if new_errors > @error_count
192
+ print Rainbow("!").red
193
+ else
194
+ print Rainbow(".").green
193
195
  end
196
+ @error_count = new_errors
194
197
  end
195
-
198
+ end
196
199
  end
197
200
  end