rdf-tabular 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,221 @@
1
+ # coding: utf-8
2
+ require File.join(File.dirname(__FILE__), 'spec_helper')
3
+ require 'rdf/spec/reader'
4
+
5
+ describe RDF::Tabular::Reader do
6
+ let!(:doap) {File.expand_path("../../etc/doap.ttl", __FILE__)}
7
+ let!(:doap_count) {File.open(doap).each_line.to_a.length}
8
+
9
+ before(:each) do
10
+ @reader = RDF::Tabular::Reader.new(StringIO.new(""), base_uri: "file:#{File.expand_path("..", __FILE__)}")
11
+
12
+ WebMock.stub_request(:any, %r(.*example.org.*)).
13
+ to_return(lambda {|request|
14
+ file = request.uri.to_s.split('/').last
15
+ content_type = case file
16
+ when /\.json/ then 'application/json'
17
+ when /\.csv/ then 'text/csv'
18
+ else 'text/plain'
19
+ end
20
+
21
+ case file
22
+ when "metadata.json", "country-codes-and-names.csv-metadata.json"
23
+ {status: 401}
24
+ else
25
+ {
26
+ body: File.read(File.expand_path("../data/#{file}", __FILE__)),
27
+ status: 200,
28
+ headers: {'Content-Type' => content_type}
29
+ }
30
+ end
31
+ })
32
+
33
+ @debug = []
34
+ end
35
+
36
+ # @see lib/rdf/spec/reader.rb in rdf-spec
37
+ #include RDF_Reader
38
+
39
+ it "should be discoverable" do
40
+ readers = [
41
+ RDF::Reader.for(:tabular),
42
+ RDF::Reader.for("etc/doap.csv"),
43
+ RDF::Reader.for(file_name: "etc/doap.csv"),
44
+ RDF::Reader.for(file_extension: "csv"),
45
+ RDF::Reader.for(content_type: "text/csv"),
46
+ ]
47
+ readers.each { |reader| expect(reader).to eq RDF::Tabular::Reader }
48
+ end
49
+
50
+ context "Test Files" do
51
+ test_files = {
52
+ "tree-ops.csv" => "tree-ops-standard.ttl",
53
+ "tree-ops.csv-metadata.json" => "tree-ops-standard.ttl",
54
+ "tree-ops-ext.json" => "tree-ops-ext-standard.ttl",
55
+ "tree-ops-virtual.json" => "tree-ops-virtual-standard.ttl",
56
+ "country-codes-and-names.csv" => "country-codes-and-names-standard.ttl",
57
+ "countries.json" => "countries-standard.ttl",
58
+ "countries.csv" => "countries.csv-standard.ttl",
59
+ "roles.json" => "roles-standard.ttl",
60
+ }
61
+ context "#each_statement" do
62
+ test_files.each do |csv, ttl|
63
+ context csv do
64
+ let(:about) {RDF::URI("http://example.org").join(csv)}
65
+ let(:input) {File.expand_path("../data/#{csv}", __FILE__)}
66
+
67
+ it "standard mode" do
68
+ expected = File.expand_path("../data/#{ttl}", __FILE__)
69
+ RDF::Reader.open(input, format: :tabular, base_uri: about, noProv: true, validate: true, debug: @debug) do |reader|
70
+ graph = RDF::Graph.new << reader
71
+ graph2 = RDF::Graph.load(expected, base_uri: about)
72
+ expect(graph).to be_equivalent_graph(graph2,
73
+ debug: @debug,
74
+ id: about,
75
+ action: about,
76
+ result: expected,
77
+ metadata: reader.metadata)
78
+ end
79
+ end
80
+
81
+ it "minimal mode" do
82
+ ttl = ttl.sub("standard", "minimal")
83
+ expected = File.expand_path("../data/#{ttl}", __FILE__)
84
+ RDF::Reader.open(input, format: :tabular, base_uri: about, minimal: true, debug: @debug) do |reader|
85
+ graph = RDF::Graph.new << reader
86
+ graph2 = RDF::Graph.load(expected, base_uri: about)
87
+ expect(graph).to be_equivalent_graph(graph2,
88
+ debug: @debug,
89
+ id: about,
90
+ action: about,
91
+ result: expected,
92
+ metadata: reader.metadata)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+
99
+ describe "#to_json" do
100
+ test_files.each do |csv, ttl|
101
+ context csv do
102
+ let(:about) {RDF::URI("http://example.org").join(csv)}
103
+ let(:input) {File.expand_path("../data/#{csv}", __FILE__)}
104
+ it "standard mode" do
105
+ json = ttl.sub("-standard.ttl", "-standard.json")
106
+ expected = File.expand_path("../data/#{json}", __FILE__)
107
+
108
+ RDF::Reader.open(input, format: :tabular, base_uri: about, noProv: true, debug: @debug) do |reader|
109
+ expect(JSON.parse(reader.to_json)).to produce(
110
+ JSON.parse(File.read(expected)),
111
+ debug: @debug,
112
+ id: about,
113
+ action: about,
114
+ result: expected,
115
+ noProv: true,
116
+ metadata: reader.metadata
117
+ )
118
+ end
119
+ end
120
+
121
+ it "minimal mode" do
122
+ json = ttl.sub("-standard.ttl", "-minimal.json")
123
+ expected = File.expand_path("../data/#{json}", __FILE__)
124
+
125
+ RDF::Reader.open(input, format: :tabular, base_uri: about, minimal: true, debug: @debug) do |reader|
126
+ expect(JSON.parse(reader.to_json)).to produce(
127
+ JSON.parse(File.read(expected)),
128
+ debug: @debug,
129
+ id: about,
130
+ action: about,
131
+ result: expected,
132
+ minimal: true,
133
+ metadata: reader.metadata
134
+ )
135
+ end
136
+ end
137
+
138
+ it "ADT mode", skip: true do
139
+ json = ttl.sub("-standard.ttl", "-atd.json")
140
+ expected = File.expand_path("../data/#{json}", __FILE__)
141
+
142
+ RDF::Reader.open(input, format: :tabular, base_uri: about, noProv: true, debug: @debug) do |reader|
143
+ expect(JSON.parse(reader.to_json(atd: true))).to produce(
144
+ JSON.parse(File.read(expected)),
145
+ debug: @debug,
146
+ id: about,
147
+ action: about,
148
+ result: expected,
149
+ noProv: true,
150
+ metadata: reader.metadata
151
+ )
152
+ end
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
158
+
159
+ context "Provenance" do
160
+ {
161
+ "country-codes-and-names.csv" => %(
162
+ PREFIX csvw: <http://www.w3.org/ns/csvw#>
163
+ PREFIX prov: <http://www.w3.org/ns/prov#>
164
+ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
165
+ ASK WHERE {
166
+ [ prov:wasGeneratedBy [
167
+ a prov:Activity;
168
+ prov:wasAssociatedWith <http://rubygems.org/gems/rdf-tabular>;
169
+ prov:startedAtTime ?start;
170
+ prov:endedAtTime ?end;
171
+ prov:qualifiedUsage [
172
+ a prov:Usage ;
173
+ prov:entity <http://example.org/country-codes-and-names.csv> ;
174
+ prov:hadRole csvw:csvEncodedTabularData
175
+ ];
176
+ ]
177
+ ]
178
+ FILTER (
179
+ DATATYPE(?start) = xsd:dateTime &&
180
+ DATATYPE(?end) = xsd:dateTime
181
+ )
182
+ }
183
+ ),
184
+ "countries.json" => %(
185
+ PREFIX csvw: <http://www.w3.org/ns/csvw#>
186
+ PREFIX prov: <http://www.w3.org/ns/prov#>
187
+ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
188
+ ASK WHERE {
189
+ [ prov:wasGeneratedBy [
190
+ a prov:Activity;
191
+ prov:wasAssociatedWith <http://rubygems.org/gems/rdf-tabular>;
192
+ prov:startedAtTime ?start;
193
+ prov:endedAtTime ?end;
194
+ prov:qualifiedUsage [
195
+ a prov:Usage ;
196
+ prov:entity <http://example.org/countries.csv>, <http://example.org/country_slice.csv>;
197
+ prov:hadRole csvw:csvEncodedTabularData
198
+ ], [
199
+ a prov:Usage ;
200
+ prov:entity <http://example.org/countries.json> ;
201
+ prov:hadRole csvw:tabularMetadata
202
+ ];
203
+ ]
204
+ ]
205
+ FILTER (
206
+ DATATYPE(?start) = xsd:dateTime &&
207
+ DATATYPE(?end) = xsd:dateTime
208
+ )
209
+ }
210
+ )
211
+ }.each do |file, query|
212
+ it file do
213
+ about = RDF::URI("http://example.org").join(file)
214
+ input = File.expand_path("../data/#{file}", __FILE__)
215
+ graph = RDF::Graph.load(input, format: :tabular, base_uri: about, debug: @debug)
216
+
217
+ expect(graph).to pass_query(query, debug: @debug, id: about, action: about)
218
+ end
219
+ end
220
+ end
221
+ end
@@ -0,0 +1,47 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $:.unshift File.dirname(__FILE__)
3
+
4
+ require "bundler/setup"
5
+ require 'rspec'
6
+ require 'rspec/its'
7
+ require 'rdf/isomorphic'
8
+ require 'rdf/tabular'
9
+ require 'rdf/turtle'
10
+ require 'rdf/spec/matchers'
11
+ require 'json'
12
+ require 'webmock/rspec'
13
+ require 'matchers'
14
+ require 'suite_helper'
15
+ require 'simplecov'
16
+ SimpleCov.start
17
+
18
+ JSON_STATE = JSON::State.new(
19
+ :indent => " ",
20
+ :space => " ",
21
+ :space_before => "",
22
+ :object_nl => "\n",
23
+ :array_nl => "\n"
24
+ )
25
+
26
+ ::RSpec.configure do |c|
27
+ c.filter_run focus: true
28
+ c.run_all_when_everything_filtered = true
29
+ c.include(RDF::Spec::Matchers)
30
+ end
31
+
32
+ # Heuristically detect the input stream
33
+ def detect_format(stream)
34
+ # Got to look into the file to see
35
+ if stream.is_a?(IO) || stream.is_a?(StringIO)
36
+ stream.rewind
37
+ string = stream.read(1000)
38
+ stream.rewind
39
+ else
40
+ string = stream.to_s
41
+ end
42
+ case string
43
+ when /<html/i then RDF::Microdatea::Reader
44
+ when /@prefix/i then RDF::Turtle::Reader
45
+ else RDF::Turtle::Reader
46
+ end
47
+ end
@@ -0,0 +1,161 @@
1
+ $:.unshift "."
2
+ require 'spec_helper'
3
+ require 'rdf/turtle'
4
+ require 'json/ld'
5
+ require 'open-uri'
6
+
7
+ # For now, override RDF::Utils::File.open_file to look for the file locally before attempting to retrieve it
8
+ module RDF::Util
9
+ module File
10
+ REMOTE_PATH = "http://w3c.github.io/csvw/"
11
+ LOCAL_PATH = ::File.expand_path("../w3c-csvw", __FILE__) + '/'
12
+
13
+ class << self
14
+ alias_method :original_open_file, :open_file
15
+ end
16
+
17
+ ##
18
+ # Override to use Patron for http and https, Kernel.open otherwise.
19
+ #
20
+ # @param [String] filename_or_url to open
21
+ # @param [Hash{Symbol => Object}] options
22
+ # @option options [Array, String] :headers
23
+ # HTTP Request headers.
24
+ # @return [IO] File stream
25
+ # @yield [IO] File stream
26
+ def self.open_file(filename_or_url, options = {}, &block)
27
+ case filename_or_url.to_s
28
+ when /^file:/
29
+ path = filename_or_url.to_s[5..-1]
30
+ Kernel.open(path.to_s, &block)
31
+ when -> (k) {k =~ %r{^#{REMOTE_PATH}} && ::File.exist?(filename_or_url.to_s.sub(REMOTE_PATH, LOCAL_PATH))}
32
+ begin
33
+ #puts "attempt to open #{filename_or_url} locally"
34
+ localpath = filename_or_url.to_s.sub(REMOTE_PATH, LOCAL_PATH)
35
+ response = begin
36
+ ::File.open(localpath)
37
+ rescue Errno::ENOENT
38
+ Kernel.open(filename_or_url.to_s, "r:utf-8", 'Accept' => "application/ld+json, application/json, text/csv")
39
+ end
40
+ document_options = {
41
+ base_uri: RDF::URI(filename_or_url),
42
+ charset: Encoding::UTF_8,
43
+ code: 200,
44
+ headers: {}
45
+ }
46
+ #puts "use #{filename_or_url} locally"
47
+ document_options[:headers][:content_type] = case filename_or_url.to_s
48
+ when /\.csv$/ then 'text/csv'
49
+ when /\.json$/ then 'application/json'
50
+ when /\.jsonld$/ then 'application/ld+json'
51
+ else 'unknown'
52
+ end
53
+
54
+ document_options[:headers][:content_type] = response.content_type if response.respond_to?(:content_type)
55
+ # For overriding content type from test data
56
+ document_options[:headers][:content_type] = options[:contentType] if options[:contentType]
57
+
58
+ # For overriding Link header from test data
59
+ document_options[:headers][:link] = options[:httpLink] if options[:httpLink]
60
+
61
+ remote_document = RDF::Util::File::RemoteDocument.new(response.read, document_options)
62
+ if block_given?
63
+ yield remote_document
64
+ else
65
+ remote_document
66
+ end
67
+ end
68
+ else
69
+ original_open_file(filename_or_url, options, &block)
70
+ end
71
+ end
72
+ end
73
+ end
74
+
75
+ module Fixtures
76
+ module SuiteTest
77
+ BASE = "http://w3c.github.io/csvw/tests/"
78
+ class Manifest < JSON::LD::Resource
79
+ def self.open(file, base)
80
+ #puts "open: #{file}"
81
+ RDF::Util::File.open_file(file) do |file|
82
+ json = ::JSON.load(file.read)
83
+ yield Manifest.new(json, context: json['@context'].merge('@base' => base))
84
+ end
85
+ end
86
+
87
+ def entries
88
+ # Map entries to resources
89
+ attributes['entries'].map {|e| Entry.new(e, context: context)}
90
+ end
91
+ end
92
+
93
+ class Entry < JSON::LD::Resource
94
+ attr_accessor :debug
95
+ attr_accessor :metadata
96
+
97
+ def id
98
+ attributes['id']
99
+ end
100
+
101
+ def base
102
+ action
103
+ end
104
+
105
+ # Apply base to action and result
106
+ def action
107
+ RDF::URI(context['@base']).join(attributes["action"]).to_s
108
+ end
109
+
110
+ def result
111
+ RDF::URI(context['@base']).join(attributes["result"]).to_s
112
+ end
113
+
114
+ def input
115
+ @input ||= RDF::Util::File.open_file(action) {|f| f.read}
116
+ end
117
+
118
+ def expected
119
+ @expected ||= RDF::Util::File.open_file(result) {|f| f.read}
120
+ end
121
+
122
+ def evaluate?
123
+ type.include?("To")
124
+ end
125
+
126
+ def sparql?
127
+ type.include?("Sparql")
128
+ end
129
+
130
+ def rdf?
131
+ result.to_s.end_with?(".ttl")
132
+ end
133
+
134
+ def json?
135
+ result.to_s.end_with?(".json")
136
+ end
137
+
138
+ def validation?
139
+ type.include?("Validation")
140
+ end
141
+
142
+ def positive_test?
143
+ !negative_test?
144
+ end
145
+
146
+ def negative_test?
147
+ type.include?("Negative")
148
+ end
149
+
150
+ def reader_options
151
+ res = {}
152
+ res[:noProv] = option['noProv'] if option
153
+ res[:metadata] = RDF::URI(context['@base']).join(option['metadata']).to_s if option && option.has_key?('metadata')
154
+ res[:httpLink] = httpLink if attributes['httpLink']
155
+ res[:minimal] = option['minimal'] if option
156
+ res[:contentType] = contentType if attributes['contentType']
157
+ res
158
+ end
159
+ end
160
+ end
161
+ end
@@ -0,0 +1,76 @@
1
+ $:.unshift "."
2
+ require 'spec_helper'
3
+ require 'fileutils'
4
+
5
+ WebMock.allow_net_connect!(net_http_connect_on_start: true)
6
+ describe RDF::Tabular::Reader do
7
+ require 'suite_helper'
8
+
9
+ before(:all) {WebMock.allow_net_connect!(net_http_connect_on_start: true)}
10
+ after(:all) {WebMock.allow_net_connect!(net_http_connect_on_start: false)}
11
+
12
+ %w(rdf json validation).each do |variant|
13
+ describe "w3c csvw #{variant.upcase} tests" do
14
+ manifest = Fixtures::SuiteTest::BASE + "manifest-#{variant}.jsonld"
15
+
16
+ Fixtures::SuiteTest::Manifest.open(manifest, manifest[0..-8]) do |m|
17
+ describe m.comment do
18
+ m.entries.each do |t|
19
+ specify "#{t.id.split("/").last}: #{t.name} - #{t.comment}" do
20
+ t.debug = []
21
+ RDF::Tabular::Reader.open(t.action,
22
+ t.reader_options.merge(
23
+ base_uri: t.base,
24
+ validate: t.validation?,
25
+ debug: t.debug
26
+ )
27
+ ) do |reader|
28
+ expect(reader).to be_a RDF::Reader
29
+
30
+ t.metadata = reader.metadata # for debug output
31
+ t.metadata = t.metadata.parent if t.metadata && t.metadata.parent
32
+
33
+ graph = RDF::Repository.new
34
+
35
+ if t.positive_test?
36
+ if t.json?
37
+ result = reader.to_json
38
+ if t.evaluate?
39
+ RDF::Util::File.open_file(t.result) do |res|
40
+ expect(::JSON.parse(result)).to produce(::JSON.parse(res.read), t)
41
+ end
42
+ else
43
+ expect(::JSON.parse(result)).to be_a(Hash)
44
+ end
45
+ else # RDF or Validation
46
+ begin
47
+ graph << reader
48
+ rescue Exception => e
49
+ expect(e.message).to produce("Not exception #{e.inspect}\n#{e.backtrace.join("\n")}", t.debug)
50
+ end
51
+
52
+ if t.sparql?
53
+ RDF::Util::File.open_file(t.result) do |query|
54
+ expect(graph).to pass_query(query, t)
55
+ end
56
+ elsif t.evaluate?
57
+ output_graph = RDF::Repository.load(t.result, format: :ttl, base_uri: t.base)
58
+ expect(graph).to be_equivalent_graph(output_graph, t)
59
+ else
60
+ expect(graph).to be_a(RDF::Enumerable)
61
+ end
62
+ end
63
+ else
64
+ expect {
65
+ graph << reader
66
+ expect(graph.dump(:ntriples)).to produce("not this", t.debug)
67
+ }.to raise_error(RDF::Tabular::Error)
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end unless ENV['CI'] # Skip for continuous integration