module Csvlint class Schema include Csvlint::ErrorCollector attr_reader :uri, :fields, :title, :description def initialize(uri, fields=[], title=nil, description=nil) @uri = uri @fields = fields @title = title @description = description reset end class << self def from_json_table(uri, json) fields = [] json["fields"].each do |field_desc| fields << Csvlint::Field.new( field_desc["name"] , field_desc["constraints"], field_desc["title"], field_desc["description"] ) end if json["fields"] return Schema.new( uri , fields, json["title"], json["description"] ) end def from_csvw_metadata(uri, json) return Csvlint::Csvw::TableGroup.from_json(uri, json) end def load_from_json(uri, output_errors = true) begin json = JSON.parse( open(uri).read ) if json["@context"] uri = "file:#{File.expand_path(uri)}" unless uri.to_s =~ /^http(s)?/ return Schema.from_csvw_metadata(uri,json) else return Schema.from_json_table(uri,json) end rescue Csvlint::Csvw::MetadataError => e raise e rescue OpenURI::HTTPError, Errno::ENOENT => e raise e rescue => e if output_errors === true STDERR.puts e.class STDERR.puts e.message STDERR.puts e.backtrace end return Schema.new(nil, [], "malformed", "malformed") end end end def validate_header(header, source_url=nil) reset found_header = header.to_csv(:row_sep => '') expected_header = @fields.map{ |f| f.name }.to_csv(:row_sep => '') if found_header != expected_header build_warnings(:malformed_header, :schema, 1, nil, found_header, "expectedHeader" => expected_header) end return valid? end def validate_row(values, row=nil, all_errors=[], source_url=nil) reset if values.length < fields.length fields[values.size..-1].each_with_index do |field, i| build_warnings(:missing_column, :schema, row, values.size+i+1) end end if values.length > fields.length values[fields.size..-1].each_with_index do |data_column, i| build_warnings(:extra_column, :schema, row, fields.size+i+1) end end fields.each_with_index do |field,i| value = values[i] || "" result = field.validate_column(value, row, i+1, all_errors) @errors += fields[i].errors @warnings += fields[i].warnings end return valid? end end end