rdf-tabular 0.1.1

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.
@@ -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