csvlint 0.3.2 → 1.0.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.
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,32 @@
1
+ # Contributing to CSVlint.rb
2
+
3
+ The CSVlint library is open source, and contributions are gratefully accepted!
4
+ Details on how to contribute are below. By participating in this project, you agree to abide by our [Code of Conduct](https://github.com/theodi/csvlint.rb/blob/CODE_OF_CONDUCT.md).
5
+
6
+ Before you start coding, please reach out to us either on our [gitter channel](https://gitter.im/theodi/toolbox) or by tagging a repository administrator on the issue ticket you are interested in contributing towards to indicate your interest in helping.
7
+
8
+ If this is your first time contributing to the ODI’s codebase you will need to [create a fork of this repository](https://help.github.com/articles/fork-a-repo/).
9
+
10
+ Consult our [Getting Started Guide](https://github.com/theodi/toolbox/wiki/Developers-Guide:-Getting-Started) (if necessary) and then follow the [readme instructions](https://github.com/theodi/csvlint.rb/blob/master/README.md#development) to get your Development environment running locally
11
+
12
+ Ensure that the [tests](https://github.com/theodi/csvlint.rb/blob/master/README.md#tests) pass before working on your contribution
13
+
14
+ ## Code Review Process
15
+
16
+ All contributions to the codebase - whether fork or pull request - will be reviewed per the below criteria.
17
+ To increase your chances of your push being accepted please be aware of the following
18
+ - Write [well formed commit messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
19
+ - Follow our [style guide recommendations](https://github.com/theodi/toolbox/blob/README.md#code-style-guide)
20
+ - Write tests for all changes (additions or refactors of existing code).
21
+ - Of the github integrations we use two will be utilised to check appraise your contribution. In order of priority these are
22
+ - Travis ensures that all tests (existing and additions) pass
23
+ - Travis/Coveralls ensures that overall test coverage for lines of code meets a certain threshold. If this metric dips below what it previously was for the repository you’re pushing to then your PR will be rejected
24
+ - Gemnasium ensures dependencies are up to date
25
+ - Once your PR is published and passes the above checks a repository administrator will review your contribution. Where appropriate comments may be provided and amendments suggested before your PR is merged into Master.
26
+ - Once your PR is accepted you will be granted push access to the repository you have contributed to! Congratulations on joining our community, you’ll no longer need to work from forks.
27
+
28
+ If you make a contribution to another repository in the Toolbox you will be expected to repeat this process. Read more about that [here](https://github.com/theodi/toolbox/blob/master/README.md#push-access).
29
+
30
+ ## Code Style Guide
31
+
32
+ We follow the same code style conventions as detailed in Github’s [Ruby Style Guide](https://github.com/github/rubocop-github/blob/master/STYLEGUIDE.md)
data/Gemfile CHANGED
@@ -1,6 +1,3 @@
1
- #ruby=ruby-2.0.0
2
- #ruby-gemset=csvlintrb
3
-
4
1
  source 'https://rubygems.org'
5
2
 
6
3
  # Specify your gem's dependencies in csvlint.rb.gemspec
data/README.md CHANGED
@@ -6,7 +6,46 @@
6
6
 
7
7
  # CSV Lint
8
8
 
9
- A ruby gem to support validating CSV files to check their syntax and contents.
9
+ A ruby gem to support validating CSV files to check their syntax and contents. You can either use this gem within your own Ruby code, or as a standalone command line application
10
+
11
+ ## Summary of features
12
+
13
+ * Validation that checks the structural formatting of a CSV file
14
+ * Validation of a delimiter-separated values (dsv) file accesible via URL, File, or an IO-style object (e.g. StringIO)
15
+ * Validation against [CSV dialects](http://dataprotocols.org/csv-dialect/)
16
+ * Validation against multiple schema standards; [JSON Table Schema](https://github.com/theodi/csvlint.rb/blob/master/README.md#json-table-schema-support) and [CSV on the Web](https://github.com/theodi/csvlint.rb/blob/master/README.md#csv-on-the-web-validation-support)
17
+
18
+ ## Development
19
+
20
+ `ruby version 2.1.4`
21
+
22
+ ### Tests
23
+
24
+ The codebase includes both rspec and cucumber tests, which can be run together using:
25
+
26
+ $ rake
27
+
28
+ or separately:
29
+
30
+ $ rake spec
31
+ $ rake features
32
+
33
+ When the cucumber tests are first run, a script will create tests based on the latest version of the [CSV on the Web test suite](http://w3c.github.io/csvw/tests/), including creating a local cache of the test files. This requires an internet connection and some patience. Following that download, the tests will run locally; there's also a batch script:
34
+
35
+ $ bin/run-csvw-tests
36
+
37
+ which will run the tests from the command line.
38
+
39
+ If you need to refresh the CSV on the Web tests:
40
+
41
+ $ rm bin/run-csvw-tests
42
+ $ rm features/csvw_validation_tests.feature
43
+ $ rm -r features/fixtures/csvw
44
+
45
+ and then run the cucumber tests again or:
46
+
47
+ $ ruby features/support/load_tests.rb
48
+
10
49
 
11
50
  ## Installation
12
51
 
@@ -24,7 +63,7 @@ Or install it yourself as:
24
63
 
25
64
  ## Usage
26
65
 
27
- You can either use this gem within your own Ruby code, or as a standolone command line application
66
+ You can either use this gem within your own Ruby code, or as a standalone command line application
28
67
 
29
68
  ## On the command line
30
69
 
@@ -32,6 +71,9 @@ After installing the gem, you can validate a CSV on the command line like so:
32
71
 
33
72
  csvlint myfile.csv
34
73
 
74
+ You may need to add the gem exectuable directory to your path, by adding '/usr/local/lib/ruby/gems/2.6.0/bin'
75
+ or whatever your version is, to your .bash_profile PATH entry. [like so](https://stackoverflow.com/questions/2392293/ruby-gems-returns-command-not-found)
76
+
35
77
  You will then see the validation result, together with any warnings or errors e.g.
36
78
 
37
79
  ```
@@ -265,7 +307,7 @@ Schema validation provides some additional types of error and warning messages:
265
307
  * `:below_minimum` (error) -- a column with a `minimum` constraint contains a value that is below the minimum
266
308
  * `:above_maximum` (error) -- a column with a `maximum` constraint contains a value that is above the maximum
267
309
 
268
- ## Other validation options
310
+ ### Other validation options
269
311
 
270
312
  You can also provide an optional options hash as the fourth argument to Validator#new. Supported options are:
271
313
 
@@ -281,48 +323,13 @@ validator = Csvlint::Validator.new( "http://example.org/data.csv", nil, nil, opt
281
323
  * :lambda -- Pass a block of code to be called when each line is validated, this will give you access to the `Validator` object. For example, this will return the current line number for every line validated:
282
324
 
283
325
  ```
284
- options = {
285
- lambda: ->(validator) { puts validator.current_line }
286
- }
287
- validator = Csvlint::Validator.new( "http://example.org/data.csv", nil, nil, options )
288
- => 1
289
- 2
290
- 3
291
- 4
292
- .....
326
+ options = {
327
+ lambda: ->(validator) { puts validator.current_line }
328
+ }
329
+ validator = Csvlint::Validator.new( "http://example.org/data.csv", nil, nil, options )
330
+ => 1
331
+ 2
332
+ 3
333
+ 4
334
+ .....
293
335
  ```
294
-
295
- ## Contributing
296
-
297
- 1. Fork it
298
- 2. Create your feature branch (`git checkout -b my-new-feature`)
299
- 3. Commit your changes (`git commit -am 'Add some feature'`)
300
- 4. Push to the branch (`git push origin my-new-feature`)
301
- 5. Create new Pull Request
302
-
303
- ### Testing
304
-
305
- The codebase includes both rspec and cucumber tests, which can be run together using:
306
-
307
- $ rake
308
-
309
- or separately:
310
-
311
- $ rake spec
312
- $ rake features
313
-
314
- When the cucumber tests are first run, a script will create tests based on the latest version of the [CSV on the Web test suite](http://w3c.github.io/csvw/tests/), including creating a local cache of the test files. This requires an internet connection and some patience. Following that download, the tests will run locally; there's also a batch script:
315
-
316
- $ bin/run-csvw-tests
317
-
318
- which will run the tests from the command line.
319
-
320
- If you need to refresh the CSV on the Web tests:
321
-
322
- $ rm bin/run-csvw-tests
323
- $ rm features/csvw_validation_tests.feature
324
- $ rm -r features/fixtures/csvw
325
-
326
- and then run the cucumber tests again or:
327
-
328
- $ ruby features/support/load_tests.rb
data/bin/create_schema CHANGED
@@ -5,7 +5,7 @@ require 'csvlint'
5
5
 
6
6
  begin
7
7
  puts ARGV[0]
8
- csv = CSV.new( open(ARGV[0]) )
8
+ csv = CSV.new( URI.open(ARGV[0]) )
9
9
  headers = csv.shift
10
10
 
11
11
  name = File.basename( ARGV[0] )
@@ -29,4 +29,4 @@ rescue => e
29
29
  puts e
30
30
  puts e.backtrace
31
31
  puts "Unable to parse CSV file"
32
- end
32
+ end
data/csvlint.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["pezholio@gmail.com"]
11
11
  spec.description = %q{CSV Validator}
12
12
  spec.summary = %q{CSV Validator}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/theodi/csvlint.rb"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -18,8 +18,9 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "mime-types"
22
- spec.add_dependency "colorize"
21
+ spec.required_ruby_version = ['>= 2.5', '< 3.2']
22
+
23
+ spec.add_dependency "rainbow"
23
24
  spec.add_dependency "open_uri_redirections"
24
25
  spec.add_dependency "activesupport"
25
26
  spec.add_dependency "addressable"
@@ -27,8 +28,10 @@ Gem::Specification.new do |spec|
27
28
  spec.add_dependency "escape_utils"
28
29
  spec.add_dependency "uri_template"
29
30
  spec.add_dependency "thor"
31
+ spec.add_dependency "rack"
32
+ spec.add_dependency "net-http-persistent"
30
33
 
31
- spec.add_development_dependency "bundler", "~> 1.3"
34
+ spec.add_development_dependency "bundler", ">= 1.3"
32
35
  spec.add_development_dependency "rake"
33
36
  spec.add_development_dependency "cucumber"
34
37
  spec.add_development_dependency "simplecov"
@@ -39,10 +42,10 @@ Gem::Specification.new do |spec|
39
42
  spec.add_development_dependency "rspec-pride"
40
43
  spec.add_development_dependency "rspec-expectations"
41
44
  spec.add_development_dependency "coveralls"
42
- spec.add_development_dependency "pry"
45
+ spec.add_development_dependency "byebug"
43
46
  spec.add_development_dependency "github_changelog_generator"
44
47
  spec.add_development_dependency "aruba"
45
- spec.add_development_dependency "rdf"
48
+ spec.add_development_dependency "rdf", "< 4.0"
46
49
  spec.add_development_dependency "rdf-turtle"
47
50
  spec.add_development_dependency "henry"
48
51
 
@@ -0,0 +1,3 @@
1
+ "Foo","Bar","Baz"
2
+ "1","2","3"
3
+ "3","2","1"
@@ -1,5 +1,4 @@
1
1
  require 'aruba'
2
- require 'aruba/in_process'
3
2
  require 'aruba/cucumber'
4
3
 
5
4
  require 'csvlint/cli'
@@ -52,5 +51,7 @@ module Csvlint
52
51
  end
53
52
  end
54
53
 
55
- Aruba.process = Aruba::Processes::InProcess
56
- Aruba.process.main_class = Csvlint::CliRunner
54
+ Aruba.configure do |config|
55
+ config.command_launcher = :in_process
56
+ config.main_class = Csvlint::CliRunner
57
+ end
@@ -6,7 +6,7 @@ $:.unshift File.join( File.dirname(__FILE__), "..", "..", "lib")
6
6
  require 'rspec/expectations'
7
7
  require 'cucumber/rspec/doubles'
8
8
  require 'csvlint'
9
- require 'pry'
9
+ require 'byebug'
10
10
 
11
11
  require 'spork'
12
12
 
@@ -2,7 +2,7 @@ require 'json'
2
2
  require 'open-uri'
3
3
  require 'uri'
4
4
 
5
- BASE_URI = "http://www.w3.org/2013/csvw/tests/"
5
+ BASE_URI = "https://w3c.github.io/csvw/tests/"
6
6
  BASE_PATH = File.join(File.dirname(__FILE__), "..", "fixtures", "csvw")
7
7
  FEATURE_BASE_PATH = File.join(File.dirname(__FILE__), "..")
8
8
  VALIDATION_FEATURE_FILE_PATH = File.join(FEATURE_BASE_PATH, "csvw_validation_tests.feature")
@@ -23,7 +23,7 @@ def cache_file(filename)
23
23
  end
24
24
  STDERR.puts("storing #{file} locally")
25
25
  File.open(file, 'wb') do |f|
26
- f.puts open(uri, 'rb').read
26
+ f.puts URI.open(uri, 'rb').read
27
27
  end
28
28
  end
29
29
  return uri, file
@@ -31,14 +31,14 @@ end
31
31
 
32
32
  File.open(SCRIPT_FILE_PATH, 'w') do |file|
33
33
  File.chmod(0755, SCRIPT_FILE_PATH)
34
- manifest = JSON.parse( open("http://www.w3.org/2013/csvw/tests/manifest-validation.jsonld").read )
34
+ manifest = JSON.parse( URI.open("#{BASE_URI}manifest-validation.jsonld").read )
35
35
  manifest["entries"].each do |entry|
36
36
  type = "valid"
37
- case entry["type"]
38
- when "csvt:WarningValidationTest"
39
- type = "warnings"
40
- when "csvt:NegativeValidationTest"
41
- type = "errors"
37
+ case entry["type"]
38
+ when "csvt:WarningValidationTest"
39
+ type = "warnings"
40
+ when "csvt:NegativeValidationTest"
41
+ type = "errors"
42
42
  end
43
43
  file.puts "echo \"#{entry["id"].split("#")[-1]}: #{entry["name"].gsub("`", "'")}\""
44
44
  file.puts "echo \"#{type}: #{entry["comment"].gsub("\"", "\\\"").gsub("`", "'")}\""
@@ -54,14 +54,14 @@ File.open(SCRIPT_FILE_PATH, 'w') do |file|
54
54
  end unless File.exist? SCRIPT_FILE_PATH
55
55
 
56
56
  File.open(VALIDATION_FEATURE_FILE_PATH, 'w') do |file|
57
- file.puts "# Auto-generated file based on standard validation CSVW tests from http://www.w3.org/2013/csvw/tests/manifest-validation.jsonld"
57
+ file.puts "# Auto-generated file based on standard validation CSVW tests from #{BASE_URI}manifest-validation.jsonld"
58
58
  file.puts ""
59
59
 
60
- manifest = JSON.parse( open("http://www.w3.org/2013/csvw/tests/manifest-validation.jsonld").read )
60
+ manifest = JSON.parse( URI.open("#{BASE_URI}manifest-validation.jsonld").read )
61
61
 
62
62
  file.puts "Feature: #{manifest["label"]}"
63
63
  file.puts ""
64
-
64
+
65
65
  manifest["entries"].each do |entry|
66
66
  action_uri, action_file = cache_file(entry["action"])
67
67
  metadata = nil
@@ -85,7 +85,7 @@ File.open(VALIDATION_FEATURE_FILE_PATH, 'w') do |file|
85
85
  end
86
86
  provided_files << action_uri.to_s
87
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 \"http://www.w3.org/.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
89
  missing_files << "#{action_uri}.json"
90
90
  missing_files << URI.join(action_uri, 'csvm.json').to_s
91
91
  else
@@ -1 +1,3 @@
1
1
  require 'webmock/cucumber'
2
+
3
+ WebMock.disable_net_connect!(allow: %r{csvw/tests})
data/lib/csvlint/cli.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'csvlint'
2
- require 'colorize'
2
+ require 'rainbow'
3
+ require 'active_support/json'
3
4
  require 'json'
4
5
  require 'pp'
5
6
  require 'thor'
@@ -10,15 +11,20 @@ module Csvlint
10
11
  class Cli < Thor
11
12
 
12
13
  desc "myfile.csv OR csvlint http://example.com/myfile.csv", "Supports validating CSV files to check their syntax and contents"
14
+
13
15
  option :dump_errors, desc: "Pretty print error and warning objects.", type: :boolean, aliases: :d
14
16
  option :schema, banner: "FILENAME OR URL", desc: "Schema file", aliases: :s
15
17
  option :json, desc: "Output errors as JSON", type: :boolean, aliases: :j
18
+ option :werror, desc: "Make all warnings into errors", type: :boolean, aliases: :w
19
+
16
20
  def validate(source = nil)
17
21
  source = read_source(source)
18
22
  @schema = get_schema(options[:schema]) if options[:schema]
19
23
  fetch_schema_tables(@schema, options) if source.nil?
20
24
 
21
- valid = validate_csv(source, @schema, options[:dump], options[:json])
25
+ Rainbow.enabled = $stdout.tty?
26
+
27
+ valid = validate_csv(source, @schema, options[:dump_errors], options[:json], options[:werror])
22
28
  exit 1 unless valid
23
29
  end
24
30
 
@@ -53,7 +59,7 @@ module Csvlint
53
59
 
54
60
  def get_schema(schema)
55
61
  begin
56
- schema = Csvlint::Schema.load_from_json(schema, false)
62
+ schema = Csvlint::Schema.load_from_uri(schema, false)
57
63
  rescue Csvlint::Csvw::MetadataError => e
58
64
  return_error "invalid metadata: #{e.message}#{" at " + e.path if e.path}"
59
65
  rescue OpenURI::HTTPError, Errno::ENOENT
@@ -80,7 +86,7 @@ module Csvlint
80
86
  rescue Errno::ENOENT
81
87
  return_error "#{source} not found"
82
88
  end unless source =~ /^http(s)?/
83
- valid &= validate_csv(source, schema, options[:dump], nil)
89
+ valid &= validate_csv(source, schema, options[:dump_errors], nil, options[:werror])
84
90
  end
85
91
 
86
92
  exit 1 unless valid
@@ -103,11 +109,7 @@ module Csvlint
103
109
  output_string += ". #{location}" unless location.empty?
104
110
  output_string += ". #{error.content}" if error.content
105
111
 
106
- if $stdout.tty?
107
- puts output_string.colorize(color)
108
- else
109
- puts output_string
110
- end
112
+ puts Rainbow(output_string).color(color)
111
113
 
112
114
  if dump
113
115
  pp error
@@ -121,15 +123,11 @@ module Csvlint
121
123
  end
122
124
 
123
125
  def return_error(message)
124
- if $stdout.tty?
125
- puts message.colorize(:red)
126
- else
127
- puts message
128
- end
126
+ puts Rainbow(message).red
129
127
  exit 1
130
128
  end
131
129
 
132
- def validate_csv(source, schema, dump, json)
130
+ def validate_csv(source, schema, dump, json, werror)
133
131
  @error_count = 0
134
132
 
135
133
  if json === true
@@ -157,16 +155,12 @@ module Csvlint
157
155
  }.to_json
158
156
  print json
159
157
  else
160
- if $stdout.tty?
161
- puts "\r\n#{csv} is #{validator.valid? ? "VALID".green : "INVALID".red}"
162
- else
163
- puts "\r\n#{csv} is #{validator.valid? ? "VALID" : "INVALID"}"
164
- end
165
-
166
- print_errors(validator.errors, dump)
158
+ puts "\r\n#{csv} is #{validator.valid? ? Rainbow("VALID").green : Rainbow("INVALID").red}"
159
+ print_errors(validator.errors, dump)
167
160
  print_errors(validator.warnings, dump)
168
161
  end
169
162
 
163
+ return false if werror && validator.warnings.size > 0
170
164
  return validator.valid?
171
165
  end
172
166
 
@@ -191,9 +185,9 @@ module Csvlint
191
185
  lambda do |row|
192
186
  new_errors = row.errors.count
193
187
  if new_errors > @error_count
194
- print "!".red
188
+ print Rainbow("!").red
195
189
  else
196
- print ".".green
190
+ print Rainbow(".").green
197
191
  end
198
192
  @error_count = new_errors
199
193
  end
@@ -11,7 +11,14 @@ module Csvlint
11
11
  value, warnings = check_common_property_value(value, base_url, lang)
12
12
  return value, warnings, :annotation
13
13
  else
14
- return value, :invalid_property, nil
14
+ # property name must be an absolute URI
15
+ begin
16
+ return value, :invalid_property, nil if URI(property).scheme.nil?
17
+ value, warnings = check_common_property_value(value, base_url, lang)
18
+ return value, warnings, :annotation
19
+ rescue
20
+ return value, :invalid_property, nil
21
+ end
15
22
  end
16
23
  end
17
24
 
@@ -448,7 +455,7 @@ module Csvlint
448
455
  schema_url = URI.join(base_url, value).to_s
449
456
  schema_base_url = schema_url
450
457
  schema_ref = schema_url.start_with?("file:") ? File.new(schema_url[5..-1]) : schema_url
451
- schema = JSON.parse( open(schema_ref).read )
458
+ schema = JSON.parse( URI.open(schema_ref).read )
452
459
  schema["@id"] = schema["@id"] ? URI.join(schema_url, schema["@id"]).to_s : schema_url
453
460
  if schema["@context"]
454
461
  if schema["@context"].instance_of?(Array) && schema["@context"].length > 1
@@ -62,7 +62,8 @@ module Csvlint
62
62
  if validate
63
63
  unless @primary_key.nil?
64
64
  key = @primary_key.map { |column| column.validate(values[column.number - 1], row) }
65
- build_errors(:duplicate_key, :schema, row, nil, key.join(","), @primary_key_values[key]) if @primary_key_values.include?(key)
65
+ colnum = if primary_key.length == 1 then primary_key[0].number else nil end
66
+ build_errors(:duplicate_key, :schema, row, colnum, key.join(","), @primary_key_values[key]) if @primary_key_values.include?(key)
66
67
  @primary_key_values[key] = row
67
68
  end
68
69
  # build a record of the unique values that are referenced by foreign keys from other tables
@@ -103,11 +104,12 @@ module Csvlint
103
104
  reset
104
105
  local = @foreign_key_reference_values[foreign_key]
105
106
  context = { "from" => { "url" => remote_url.to_s.split("/")[-1], "columns" => foreign_key["columnReference"] }, "to" => { "url" => @url.to_s.split("/")[-1], "columns" => foreign_key["reference"]["columnReference"] }}
106
- remote.each do |r|
107
+ colnum = if foreign_key["referencing_columns"].length == 1 then foreign_key["referencing_columns"][0].number else nil end
108
+ remote.each_with_index do |r,i|
107
109
  if local[r]
108
- build_errors(:multiple_matched_rows, :schema, nil, nil, r, context) if local[r].length > 1
110
+ build_errors(:multiple_matched_rows, :schema, i+1, colnum, r, context) if local[r].length > 1
109
111
  else
110
- build_errors(:unmatched_foreign_key_reference, :schema, nil, nil, r, context)
112
+ build_errors(:unmatched_foreign_key_reference, :schema, i+1, colnum, r, context)
111
113
  end
112
114
  end
113
115
  return valid?
@@ -16,6 +16,8 @@ module Csvlint
16
16
 
17
17
  class << self
18
18
 
19
+ extend Gem::Deprecate
20
+
19
21
  def from_json_table(uri, json)
20
22
  fields = []
21
23
  json["fields"].each do |field_desc|
@@ -29,19 +31,32 @@ module Csvlint
29
31
  return Csvlint::Csvw::TableGroup.from_json(uri, json)
30
32
  end
31
33
 
34
+ # Deprecated method signature
32
35
  def load_from_json(uri, output_errors = true)
36
+ load_from_uri(uri, output_errors)
37
+ end
38
+ deprecate :load_from_json, :load_from_uri, 2018, 1
39
+
40
+ def load_from_uri(uri, output_errors = true)
41
+ load_from_string(uri, URI.open(uri).read, output_errors)
42
+ rescue OpenURI::HTTPError, Errno::ENOENT => e
43
+ raise e
44
+ end
45
+
46
+ def load_from_string(uri, string, output_errors = true)
33
47
  begin
34
- json = JSON.parse( open(uri).read )
48
+ json = JSON.parse( string )
35
49
  if json["@context"]
36
50
  uri = "file:#{File.expand_path(uri)}" unless uri.to_s =~ /^http(s)?/
37
51
  return Schema.from_csvw_metadata(uri,json)
38
52
  else
39
53
  return Schema.from_json_table(uri,json)
40
54
  end
55
+ rescue TypeError => e
56
+ # NO IDEA what this was even trying to do - SP 20160526
57
+
41
58
  rescue Csvlint::Csvw::MetadataError => e
42
59
  raise e
43
- rescue OpenURI::HTTPError, Errno::ENOENT => e
44
- raise e
45
60
  rescue => e
46
61
  if output_errors === true
47
62
  STDERR.puts e.class
@@ -38,13 +38,15 @@ module Csvlint
38
38
  ESCAPE_RE[@re_chars][@re_esc][str]
39
39
  end
40
40
 
41
- # Optimization: Disable the CSV library's converters feature.
42
- # @see https://github.com/ruby/ruby/blob/v2_2_3/lib/csv.rb#L2100
43
- def init_converters(options, field_name = :converters)
44
- @converters = []
45
- @header_converters = []
46
- options.delete(:unconverted_fields)
47
- options.delete(field_name)
41
+ if RUBY_VERSION < '2.5'
42
+ # Optimization: Disable the CSV library's converters feature.
43
+ # @see https://github.com/ruby/ruby/blob/v2_2_3/lib/csv.rb#L2100
44
+ def init_converters(options, field_name = :converters)
45
+ @converters = []
46
+ @header_converters = []
47
+ options.delete(:unconverted_fields)
48
+ options.delete(field_name)
49
+ end
48
50
  end
49
51
  end
50
52
 
@@ -56,6 +58,7 @@ module Csvlint
56
58
  "Missing or stray quote" => :stray_quote,
57
59
  "Illegal quoting" => :whitespace,
58
60
  "Unclosed quoted field" => :unclosed_quote,
61
+ "Any value after quoted field isn't allowed" => :unclosed_quote,
59
62
  "Unquoted fields do not allow \\r or \\n" => :line_breaks,
60
63
  }
61
64
 
@@ -123,6 +126,7 @@ module Csvlint
123
126
  validate_metadata
124
127
  end
125
128
  request.on_body do |chunk|
129
+ chunk.force_encoding(Encoding::UTF_8) if chunk.encoding == Encoding::ASCII_8BIT
126
130
  io = StringIO.new(chunk)
127
131
  io.each_line do |line|
128
132
  break if line_limit_reached?
@@ -178,9 +182,9 @@ module Csvlint
178
182
  @csv_options[:encoding] = @encoding
179
183
 
180
184
  begin
181
- row = LineCSV.parse_line(stream, @csv_options)
185
+ row = LineCSV.parse_line(stream, **@csv_options)
182
186
  rescue LineCSV::MalformedCSVError => e
183
- build_exception_messages(e, stream, current_line)
187
+ build_exception_messages(e, stream, current_line) unless e.message.include?("UTF") && @reported_invalid_encoding
184
188
  end
185
189
 
186
190
  if row
@@ -249,7 +253,7 @@ module Csvlint
249
253
  if rel == "describedby" && param == "type" && ["application/csvm+json", "application/ld+json", "application/json"].include?(param_value)
250
254
  begin
251
255
  url = URI.join(@source_url, uri)
252
- schema = Schema.load_from_json(url)
256
+ schema = Schema.load_from_uri(url)
253
257
  if schema.instance_of? Csvlint::Csvw::TableGroup
254
258
  if schema.tables[@source_url]
255
259
  @schema = schema
@@ -433,7 +437,8 @@ module Csvlint
433
437
  when StringIO
434
438
  return
435
439
  when File
436
- @source_url = "file:#{File.expand_path(@source)}"
440
+ uri_parser = URI::Parser.new
441
+ @source_url = "file:#{uri_parser.escape(File.expand_path(@source))}"
437
442
  else
438
443
  @source_url = @source
439
444
  end
@@ -448,7 +453,7 @@ module Csvlint
448
453
  if @source_url =~ /^http(s)?/
449
454
  begin
450
455
  well_known_uri = URI.join(@source_url, "/.well-known/csvm")
451
- paths = open(well_known_uri).read.split("\n")
456
+ paths = URI.open(well_known_uri.to_s).read.split("\n")
452
457
  rescue OpenURI::HTTPError, URI::BadURIError
453
458
  end
454
459
  end
@@ -459,7 +464,7 @@ module Csvlint
459
464
  path = template.expand('url' => @source_url)
460
465
  url = URI.join(@source_url, path)
461
466
  url = File.new(url.to_s.sub(/^file:/, "")) if url.to_s =~ /^file:/
462
- schema = Schema.load_from_json(url)
467
+ schema = Schema.load_from_uri(url)
463
468
  if schema.instance_of? Csvlint::Csvw::TableGroup
464
469
  if schema.tables[@source_url]
465
470
  @schema = schema
@@ -1,3 +1,3 @@
1
1
  module Csvlint
2
- VERSION = "0.3.2"
2
+ VERSION = "1.0.0"
3
3
  end
data/lib/csvlint.rb CHANGED
@@ -7,7 +7,7 @@ require 'typhoeus'
7
7
 
8
8
  require 'active_support/core_ext/date/conversions'
9
9
  require 'active_support/core_ext/time/conversions'
10
- require 'mime/types'
10
+ require 'active_support/core_ext/object'
11
11
  require 'open_uri_redirections'
12
12
  require 'uri_template'
13
13