rdf-tabular 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/lib/rdf/tabular/metadata.rb +611 -659
- data/lib/rdf/tabular/reader.rb +59 -54
- data/spec/metadata_spec.rb +191 -376
- data/spec/suite_helper.rb +5 -0
- data/spec/suite_spec.rb +53 -39
- metadata +2 -2
data/lib/rdf/tabular/reader.rb
CHANGED
@@ -30,6 +30,8 @@ module RDF::Tabular
|
|
30
30
|
# @option options [Metadata, Hash, String, RDF::URI] :metadata user supplied metadata, merged on top of extracted metadata. If provided as a URL, Metadata is loade from that location
|
31
31
|
# @option options [Boolean] :minimal includes only the information gleaned from the cells of the tabular data
|
32
32
|
# @option options [Boolean] :noProv do not output optional provenance information
|
33
|
+
# @option options [Array] :warnings
|
34
|
+
# array for placing warnings found when processing metadata. If not set, and validating, warnings are output to `$stderr`
|
33
35
|
# @yield [reader] `self`
|
34
36
|
# @yieldparam [RDF::Reader] reader
|
35
37
|
# @yieldreturn [void] ignored
|
@@ -64,33 +66,38 @@ module RDF::Tabular
|
|
64
66
|
if @options[:base] =~ /\.json(?:ld)?$/ ||
|
65
67
|
@input.respond_to?(:content_type) && @input.content_type =~ %r(application/(?:ld+)json)
|
66
68
|
@metadata = Metadata.new(@input, @options.merge(filenames: @options[:base]))
|
67
|
-
# If @metadata is for a Table,
|
68
|
-
if @metadata.is_a?(
|
69
|
-
|
70
|
-
else
|
71
|
-
@metadata = @metadata.merge(TableGroup.new({}))
|
72
|
-
end
|
69
|
+
# If @metadata is for a Table, turn it into a TableGroup
|
70
|
+
@metadata = @metadata.to_table_group if @metadata.is_a?(Table)
|
71
|
+
@metadata.normalize!
|
73
72
|
@input = @metadata
|
74
73
|
elsif @options[:no_found_metadata]
|
75
74
|
# Extract embedded metadata and merge
|
76
|
-
|
77
|
-
dialect =
|
75
|
+
dialect_metadata = @options[:metadata] || Table.new({}, context: "http://www.w3.org/ns/csvw")
|
76
|
+
dialect = dialect_metadata.dialect.dup
|
78
77
|
|
79
78
|
# HTTP flags for setting header values
|
80
79
|
dialect.header = false if (input.headers.fetch(:content_type, '').split(';').include?('header=absent') rescue false)
|
81
80
|
dialect.encoding = input.charset if (input.charset rescue nil)
|
82
81
|
dialect.separator = "\t" if (input.content_type == "text/tsv" rescue nil)
|
82
|
+
embed_options = {base: "http://example.org/default-metadata"}.merge(@options)
|
83
|
+
embedded_metadata = dialect.embedded_metadata(input, @options[:metadata], embed_options)
|
83
84
|
|
84
|
-
|
85
|
-
|
86
|
-
|
85
|
+
if (@metadata = @options[:metadata]) && @metadata.tableSchema
|
86
|
+
@metadata.verify_compatible!(embedded_metadata)
|
87
|
+
else
|
88
|
+
@metadata = embedded_metadata.normalize!
|
87
89
|
end
|
88
90
|
|
89
|
-
|
91
|
+
lang = input.headers[:content_language] rescue nil
|
92
|
+
lang = nil if lang.to_s.include?(',') # Not for multiple languages
|
93
|
+
# Set language, if unset and provided
|
94
|
+
@metadata.lang ||= lang if lang
|
95
|
+
|
96
|
+
@metadata.dialect = dialect
|
90
97
|
else
|
91
98
|
# It's tabluar data. Find metadata and proceed as if it was specified in the first place
|
92
99
|
@options[:original_input] = @input
|
93
|
-
@input = @metadata = Metadata.for_input(@input, @options)
|
100
|
+
@input = @metadata = Metadata.for_input(@input, @options).normalize!
|
94
101
|
end
|
95
102
|
|
96
103
|
debug("Reader#initialize") {"input: #{input}, metadata: #{metadata.inspect}"}
|
@@ -139,11 +146,10 @@ module RDF::Tabular
|
|
139
146
|
end unless minimal?
|
140
147
|
|
141
148
|
# If we were originally given tabular data as input, simply use that, rather than opening the table URL. This allows buffered data to be used as input
|
142
|
-
if input.tables.empty? && options[:original_input]
|
149
|
+
if Array(input.tables).empty? && options[:original_input]
|
143
150
|
table_resource = RDF::Node.new
|
144
151
|
add_statement(0, table_group, CSVW.table, table_resource) unless minimal?
|
145
152
|
Reader.new(options[:original_input], options.merge(
|
146
|
-
metadata: Table.new({url: options.fetch(:base, "http://example.org/default-metadata")}),
|
147
153
|
no_found_metadata: true,
|
148
154
|
table_resource: table_resource
|
149
155
|
)) do |r|
|
@@ -196,8 +202,9 @@ module RDF::Tabular
|
|
196
202
|
end
|
197
203
|
end
|
198
204
|
ensure
|
199
|
-
|
200
|
-
|
205
|
+
warnings = @options.fetch(:warnings, []).concat(input.warnings)
|
206
|
+
if validate? && !warnings.empty? && !@options[:warnings]
|
207
|
+
$stderr.puts "Warnings: #{warnings.join("\n")}"
|
201
208
|
end
|
202
209
|
end
|
203
210
|
when :Table
|
@@ -218,14 +225,6 @@ module RDF::Tabular
|
|
218
225
|
add_statement(0, table_resource, CSVW.url, RDF::URI(metadata.url))
|
219
226
|
end
|
220
227
|
|
221
|
-
# Common Properties
|
222
|
-
metadata.each do |key, value|
|
223
|
-
next unless key.to_s.include?(':') || key == :notes
|
224
|
-
metadata.common_properties(table_resource, key, value) do |statement|
|
225
|
-
add_statement(0, statement)
|
226
|
-
end
|
227
|
-
end unless minimal?
|
228
|
-
|
229
228
|
# Input is file containing CSV data.
|
230
229
|
# Output ROW-Level statements
|
231
230
|
last_row_num = 0
|
@@ -269,6 +268,14 @@ module RDF::Tabular
|
|
269
268
|
end
|
270
269
|
end
|
271
270
|
end
|
271
|
+
|
272
|
+
# Common Properties
|
273
|
+
metadata.each do |key, value|
|
274
|
+
next unless key.to_s.include?(':') || key == :notes
|
275
|
+
metadata.common_properties(table_resource, key, value) do |statement|
|
276
|
+
add_statement(0, statement)
|
277
|
+
end
|
278
|
+
end unless minimal?
|
272
279
|
end
|
273
280
|
enum_for(:each_statement)
|
274
281
|
end
|
@@ -373,9 +380,7 @@ module RDF::Tabular
|
|
373
380
|
table_group['table'] = tables
|
374
381
|
|
375
382
|
if input.tables.empty? && options[:original_input]
|
376
|
-
md = Table.new({url: options.fetch(:base, "http://example.org/default-metadata")})
|
377
383
|
Reader.new(options[:original_input], options.merge(
|
378
|
-
metadata: md,
|
379
384
|
base: options.fetch(:base, "http://example.org/default-metadata"),
|
380
385
|
minimal: minimal?,
|
381
386
|
no_found_metadata: true
|
@@ -406,8 +411,9 @@ module RDF::Tabular
|
|
406
411
|
# Result is table_group or array
|
407
412
|
minimal? ? tables : table_group
|
408
413
|
ensure
|
409
|
-
|
410
|
-
|
414
|
+
warnings = options.fetch(:warnings, []).concat(input.warnings)
|
415
|
+
if validate? && !warnings.empty? && !@options[:warnings]
|
416
|
+
$stderr.puts "Warnings: #{warnings.join("\n")}"
|
411
417
|
end
|
412
418
|
end
|
413
419
|
when :Table
|
@@ -433,13 +439,6 @@ module RDF::Tabular
|
|
433
439
|
table['@id'] = metadata.id.to_s if metadata.id
|
434
440
|
table['url'] = metadata.url.to_s
|
435
441
|
|
436
|
-
# Use string values notes and common properties
|
437
|
-
metadata.each do |key, value|
|
438
|
-
next unless key.to_s.include?(':') || key == :notes
|
439
|
-
table[key] = metadata.common_properties(nil, key, value)
|
440
|
-
table[key] = [table[key]] if key == :notes && !table[key].is_a?(Array)
|
441
|
-
end unless minimal?
|
442
|
-
|
443
442
|
table.merge!("row" => rows)
|
444
443
|
|
445
444
|
# Input is file containing CSV data.
|
@@ -521,6 +520,13 @@ module RDF::Tabular
|
|
521
520
|
end
|
522
521
|
end
|
523
522
|
|
523
|
+
# Use string values notes and common properties
|
524
|
+
metadata.each do |key, value|
|
525
|
+
next unless key.to_s.include?(':') || key == :notes
|
526
|
+
table[key] = metadata.common_properties(nil, key, value)
|
527
|
+
table[key] = [table[key]] if key == :notes && !table[key].is_a?(Array)
|
528
|
+
end unless minimal?
|
529
|
+
|
524
530
|
minimal? ? table["row"] : table
|
525
531
|
end
|
526
532
|
end
|
@@ -537,21 +543,22 @@ module RDF::Tabular
|
|
537
543
|
case input.type
|
538
544
|
when :TableGroup
|
539
545
|
table_group = input.to_atd
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
metadata: table,
|
545
|
-
base: table.url,
|
546
|
-
no_found_metadata: true, # FIXME: remove
|
547
|
-
noProv: true
|
546
|
+
if input.tables.empty? && options[:original_input]
|
547
|
+
Reader.new(options[:original_input], options.merge(
|
548
|
+
base: options.fetch(:base, "http://example.org/default-metadata"),
|
549
|
+
no_found_metadata: true
|
548
550
|
)) do |r|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
551
|
+
table_group["tables"] << r.to_atd(options)
|
552
|
+
end
|
553
|
+
else
|
554
|
+
input.each_table do |table|
|
555
|
+
Reader.open(table.url, options.merge(
|
556
|
+
metadata: table,
|
557
|
+
base: table.url,
|
558
|
+
no_found_metadata: true
|
559
|
+
)) do |r|
|
560
|
+
table_group["tables"] << r.to_atd(options)
|
561
|
+
end
|
555
562
|
end
|
556
563
|
end
|
557
564
|
|
@@ -560,11 +567,9 @@ module RDF::Tabular
|
|
560
567
|
when :Table
|
561
568
|
table = nil
|
562
569
|
Reader.open(input.url, options.merge(
|
563
|
-
format: :tabular,
|
564
570
|
metadata: input,
|
565
571
|
base: input.url,
|
566
|
-
no_found_metadata: true
|
567
|
-
noProv: true
|
572
|
+
no_found_metadata: true
|
568
573
|
)) do |r|
|
569
574
|
table = r.to_atd(options)
|
570
575
|
end
|
@@ -584,7 +589,7 @@ module RDF::Tabular
|
|
584
589
|
metadata.each_row(input) do |row|
|
585
590
|
rows << row.to_atd
|
586
591
|
row.values.each_with_index do |cell, colndx|
|
587
|
-
columns[colndx]["cells"] << cell.
|
592
|
+
columns[colndx]["cells"] << cell.to_atd
|
588
593
|
end
|
589
594
|
end
|
590
595
|
table
|
data/spec/metadata_spec.rb
CHANGED
@@ -29,40 +29,32 @@ describe RDF::Tabular::Metadata do
|
|
29
29
|
|
30
30
|
shared_examples "inherited properties" do |allowed = true|
|
31
31
|
{
|
32
|
-
|
33
|
-
valid: ["
|
34
|
-
invalid: [1, true,
|
32
|
+
aboutUrl: {
|
33
|
+
valid: ["http://example.org/example.csv#row={_row}", "http://example.org/tree/{on%2Dstreet}/{GID}", "#row.{_row}"],
|
34
|
+
invalid: [1, true, nil, %w(foo bar)]
|
35
|
+
},
|
36
|
+
datatype: {
|
37
|
+
valid: (%w(anyAtomicType string token language Name NCName boolean gYear number binary datetime any xml html json) +
|
38
|
+
[{"base" => "string"}]
|
39
|
+
),
|
40
|
+
invalid: [1, true, "foo", "anyType", "anySimpleType", "IDREFS"]
|
41
|
+
},
|
42
|
+
default: {
|
43
|
+
valid: ["foo"],
|
44
|
+
invalid: [1, %w(foo bar), true, nil]
|
35
45
|
},
|
36
46
|
lang: {
|
37
47
|
valid: %w(en en-US),
|
38
48
|
invalid: %w(1 foo)
|
39
49
|
},
|
40
|
-
|
41
|
-
valid: %w(
|
42
|
-
invalid:
|
43
|
-
},
|
44
|
-
separator: {
|
45
|
-
valid: %w(, a | :) + [nil],
|
46
|
-
invalid: [1, false] + %w(foo ::)
|
50
|
+
null: {
|
51
|
+
valid: ["foo", %w(foo bar)],
|
52
|
+
invalid: [1, true, {}]
|
47
53
|
},
|
48
54
|
ordered: {
|
49
55
|
valid: [true, false],
|
50
56
|
invalid: [nil, "foo", 1, 0, "true", "false", "TrUe", "fAlSe", "1", "0"],
|
51
57
|
},
|
52
|
-
default: {
|
53
|
-
valid: ["foo"],
|
54
|
-
invalid: [1, %w(foo bar), true, nil]
|
55
|
-
},
|
56
|
-
datatype: {
|
57
|
-
valid: (%w(anyAtomicType string token language Name NCName boolean gYear number binary datetime any xml html json) +
|
58
|
-
[{"base" => "string"}]
|
59
|
-
),
|
60
|
-
invalid: [1, true, "foo", "anyType", "anySimpleType", "IDREFS"]
|
61
|
-
},
|
62
|
-
aboutUrl: {
|
63
|
-
valid: ["http://example.org/example.csv#row={_row}", "http://example.org/tree/{on%2Dstreet}/{GID}", "#row.{_row}"],
|
64
|
-
invalid: [1, true, nil, %w(foo bar)]
|
65
|
-
},
|
66
58
|
propertyUrl: {
|
67
59
|
valid: [
|
68
60
|
"http://example.org/example.csv#col={_name}",
|
@@ -71,6 +63,18 @@ describe RDF::Tabular::Metadata do
|
|
71
63
|
],
|
72
64
|
invalid: [1, true, %w(foo bar)]
|
73
65
|
},
|
66
|
+
required: {
|
67
|
+
valid: [true, false],
|
68
|
+
invalid: [nil, "foo", 1, 0, "true", "false", "TrUe", "fAlSe", "1", "0"],
|
69
|
+
},
|
70
|
+
separator: {
|
71
|
+
valid: %w(, a | :) + [nil],
|
72
|
+
invalid: [1, false] + %w(foo ::)
|
73
|
+
},
|
74
|
+
"textDirection" => {
|
75
|
+
valid: %w(rtl ltr),
|
76
|
+
invalid: %w(foo default)
|
77
|
+
},
|
74
78
|
valueUrl: {
|
75
79
|
valid: [
|
76
80
|
"http://example.org/example.csv#row={_row}",
|
@@ -178,7 +182,7 @@ describe RDF::Tabular::Metadata do
|
|
178
182
|
end
|
179
183
|
|
180
184
|
describe RDF::Tabular::Column do
|
181
|
-
subject {described_class.new({"name" => "foo"}, base: RDF::URI("http://example.org/base"), debug: @debug)}
|
185
|
+
subject {described_class.new({"name" => "foo"}, context: "http://www.w3.org/ns/csvw", base: RDF::URI("http://example.org/base"), debug: @debug)}
|
182
186
|
specify {is_expected.to be_valid}
|
183
187
|
it_behaves_like("inherited properties")
|
184
188
|
it_behaves_like("common properties")
|
@@ -190,7 +194,10 @@ describe RDF::Tabular::Metadata do
|
|
190
194
|
end
|
191
195
|
|
192
196
|
it "detects invalid names" do
|
193
|
-
[1, true, nil, "_foo", "_col=1"].each
|
197
|
+
[1, true, nil, "_foo", "_col=1"].each do |v|
|
198
|
+
md = described_class.new("name" => v)
|
199
|
+
expect(md.warnings).not_to be_empty
|
200
|
+
end
|
194
201
|
end
|
195
202
|
|
196
203
|
it "allows absence of name" do
|
@@ -203,11 +210,7 @@ describe RDF::Tabular::Metadata do
|
|
203
210
|
{
|
204
211
|
titles: {
|
205
212
|
valid: ["foo", %w(foo bar), {"en" => "foo", "de" => "bar"}],
|
206
|
-
|
207
|
-
},
|
208
|
-
required: {
|
209
|
-
valid: [true, false],
|
210
|
-
warning: [nil, "foo", 1, 0, "true", "false", "TrUe", "fAlSe", "1", "0"],
|
213
|
+
warning: [1, true, nil]
|
211
214
|
},
|
212
215
|
suppressOutput: {
|
213
216
|
valid: [true, false],
|
@@ -247,14 +250,14 @@ describe RDF::Tabular::Metadata do
|
|
247
250
|
}.each do |name, (input, output)|
|
248
251
|
it name do
|
249
252
|
subject.titles = input
|
250
|
-
expect(subject.titles).to produce(output)
|
253
|
+
expect(subject.normalize!.titles).to produce(output)
|
251
254
|
end
|
252
255
|
end
|
253
256
|
end
|
254
257
|
end
|
255
258
|
|
256
259
|
describe RDF::Tabular::Schema do
|
257
|
-
subject {described_class.new({}, base: RDF::URI("http://example.org/base"), debug: @debug)}
|
260
|
+
subject {described_class.new({}, context: "http://www.w3.org/ns/csvw", base: RDF::URI("http://example.org/base"), debug: @debug)}
|
258
261
|
specify {is_expected.to be_valid}
|
259
262
|
it_behaves_like("inherited properties")
|
260
263
|
it_behaves_like("common properties")
|
@@ -274,7 +277,7 @@ describe RDF::Tabular::Metadata do
|
|
274
277
|
|
275
278
|
it "is invalid with an invalid column" do
|
276
279
|
v = described_class.new({"columns" => [{"name" => "_invalid"}]}, base: RDF::URI("http://example.org/base"), debug: @debug)
|
277
|
-
expect(v.
|
280
|
+
expect(v.warnings).not_to be_empty
|
278
281
|
end
|
279
282
|
|
280
283
|
it "is invalid with an non-unique columns" do
|
@@ -425,7 +428,15 @@ describe RDF::Tabular::Metadata do
|
|
425
428
|
describe RDF::Tabular::Transformation do
|
426
429
|
let(:targetFormat) {"http://example.org/targetFormat"}
|
427
430
|
let(:scriptFormat) {"http://example.org/scriptFormat"}
|
428
|
-
subject {
|
431
|
+
subject {
|
432
|
+
described_class.new({
|
433
|
+
"url" => "http://example/",
|
434
|
+
"targetFormat" => targetFormat,
|
435
|
+
"scriptFormat" => scriptFormat},
|
436
|
+
context: "http://www.w3.org/ns/csvw",
|
437
|
+
base: RDF::URI("http://example.org/base"),
|
438
|
+
debug: @debug)
|
439
|
+
}
|
429
440
|
specify {is_expected.to be_valid}
|
430
441
|
it_behaves_like("inherited properties", false)
|
431
442
|
it_behaves_like("common properties")
|
@@ -434,7 +445,7 @@ describe RDF::Tabular::Metadata do
|
|
434
445
|
{
|
435
446
|
source: {
|
436
447
|
valid: %w(json rdf) + [nil],
|
437
|
-
|
448
|
+
warning: [1, true, {}]
|
438
449
|
},
|
439
450
|
}.each do |prop, params|
|
440
451
|
context prop.to_s do
|
@@ -444,10 +455,10 @@ describe RDF::Tabular::Metadata do
|
|
444
455
|
expect(subject).to be_valid
|
445
456
|
end
|
446
457
|
end
|
447
|
-
it "
|
448
|
-
params[:
|
458
|
+
it "warnings" do
|
459
|
+
params[:warning].each do |v|
|
449
460
|
subject.send("#{prop}=".to_sym, v)
|
450
|
-
expect(subject).not_to
|
461
|
+
expect(subject.warnings).not_to be_empty
|
451
462
|
end
|
452
463
|
end
|
453
464
|
end
|
@@ -459,20 +470,20 @@ describe RDF::Tabular::Metadata do
|
|
459
470
|
}.each do |name, (input, output)|
|
460
471
|
it name do
|
461
472
|
subject.titles = input
|
462
|
-
expect(subject.titles).to produce(output)
|
473
|
+
expect(subject.normalize!.titles).to produce(output)
|
463
474
|
end
|
464
475
|
end
|
465
476
|
end
|
466
477
|
end
|
467
478
|
|
468
479
|
describe RDF::Tabular::Dialect do
|
469
|
-
subject {described_class.new({}, base: RDF::URI("http://example.org/base"), debug: @debug)}
|
480
|
+
subject {described_class.new({}, context: "http://www.w3.org/ns/csvw", base: RDF::URI("http://example.org/base"), debug: @debug)}
|
470
481
|
specify {is_expected.to be_valid}
|
471
482
|
it_behaves_like("inherited properties", false)
|
472
483
|
it_behaves_like("common properties", false)
|
473
484
|
its(:type) {is_expected.to eql :Dialect}
|
474
485
|
|
475
|
-
described_class.const_get(:
|
486
|
+
described_class.const_get(:DEFAULTS).each do |p, v|
|
476
487
|
context "#{p}" do
|
477
488
|
it "retrieves #{v.inspect} by default" do
|
478
489
|
expect(subject.send(p)).to eql v
|
@@ -545,12 +556,12 @@ describe RDF::Tabular::Metadata do
|
|
545
556
|
}.each do |name, props|
|
546
557
|
it name do
|
547
558
|
dialect = if props[:dialect]
|
548
|
-
described_class.new(props[:dialect],
|
559
|
+
described_class.new(props[:dialect], debug: @debug)
|
549
560
|
else
|
550
561
|
subject
|
551
562
|
end
|
552
563
|
|
553
|
-
result = dialect.embedded_metadata(props[:input])
|
564
|
+
result = dialect.embedded_metadata(props[:input], nil, base: RDF::URI("http://example.org/base"))
|
554
565
|
expect(::JSON.parse(result.to_json(JSON_STATE))).to produce(::JSON.parse(props[:result]), @debug)
|
555
566
|
end
|
556
567
|
end
|
@@ -558,16 +569,19 @@ describe RDF::Tabular::Metadata do
|
|
558
569
|
end
|
559
570
|
|
560
571
|
describe RDF::Tabular::Table do
|
561
|
-
subject {described_class.new({"url" => "http://example.org/table.csv"}, base: RDF::URI("http://example.org/base"), debug: @debug)}
|
572
|
+
subject {described_class.new({"url" => "http://example.org/table.csv"}, context: "http://www.w3.org/ns/csvw", base: RDF::URI("http://example.org/base"), debug: @debug)}
|
562
573
|
specify {is_expected.to be_valid}
|
563
574
|
it_behaves_like("inherited properties")
|
564
575
|
it_behaves_like("common properties")
|
565
576
|
its(:type) {is_expected.to eql :Table}
|
566
577
|
|
578
|
+
describe "#to_table_group" do
|
579
|
+
end
|
580
|
+
|
567
581
|
{
|
568
582
|
tableSchema: {
|
569
583
|
valid: [RDF::Tabular::Schema.new({})],
|
570
|
-
|
584
|
+
warning: [1, true, nil]
|
571
585
|
},
|
572
586
|
notes: {
|
573
587
|
valid: [{}, [{}]],
|
@@ -575,16 +589,16 @@ describe RDF::Tabular::Metadata do
|
|
575
589
|
},
|
576
590
|
tableDirection: {
|
577
591
|
valid: %w(rtl ltr default),
|
578
|
-
|
592
|
+
warning: %w(foo true 1)
|
579
593
|
},
|
580
594
|
transformations: {
|
581
595
|
valid: [[RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")]],
|
582
|
-
|
596
|
+
warning: [RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")] +
|
583
597
|
%w(foo true 1)
|
584
598
|
},
|
585
599
|
dialect: {
|
586
600
|
valid: [{skipRows: 1}],
|
587
|
-
|
601
|
+
warning: [1]
|
588
602
|
},
|
589
603
|
suppressOutput: {
|
590
604
|
valid: [true, false],
|
@@ -617,30 +631,28 @@ describe RDF::Tabular::Metadata do
|
|
617
631
|
|
618
632
|
describe RDF::Tabular::TableGroup do
|
619
633
|
let(:table) {{"url" => "http://example.org/table.csv"}}
|
620
|
-
subject {described_class.new({"tables" => [table]}, base: RDF::URI("http://example.org/base"), debug: @debug)}
|
634
|
+
subject {described_class.new({"tables" => [table]}, context: "http://www.w3.org/ns/csvw", base: RDF::URI("http://example.org/base"), debug: @debug)}
|
621
635
|
specify {is_expected.to be_valid}
|
622
636
|
|
623
637
|
it_behaves_like("inherited properties")
|
624
638
|
it_behaves_like("common properties")
|
625
639
|
its(:type) {is_expected.to eql :TableGroup}
|
626
|
-
|
627
|
-
|
628
640
|
{
|
629
641
|
tableSchema: {
|
630
642
|
valid: [RDF::Tabular::Schema.new({})],
|
631
|
-
|
643
|
+
warning: [1, true, nil]
|
632
644
|
},
|
633
645
|
tableDirection: {
|
634
646
|
valid: %w(rtl ltr default),
|
635
|
-
|
647
|
+
warning: %w(foo true 1)
|
636
648
|
},
|
637
649
|
dialect: {
|
638
650
|
valid: [{skipRows: 1}],
|
639
|
-
|
651
|
+
warning: [1]
|
640
652
|
},
|
641
653
|
transformations: {
|
642
654
|
valid: [[RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")]],
|
643
|
-
|
655
|
+
warning: [RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")] +
|
644
656
|
%w(foo true 1)
|
645
657
|
},
|
646
658
|
notes: {
|
@@ -660,7 +672,14 @@ describe RDF::Tabular::Metadata do
|
|
660
672
|
subject.send("#{prop}=".to_sym, v)
|
661
673
|
expect(subject).not_to be_valid
|
662
674
|
end
|
663
|
-
end
|
675
|
+
end if params[:invalid]
|
676
|
+
it "warnings" do
|
677
|
+
params[:warning].each do |v|
|
678
|
+
subject.send("#{prop}=".to_sym, v)
|
679
|
+
expect(subject).to be_valid
|
680
|
+
expect(subject.warnings).not_to be_empty
|
681
|
+
end
|
682
|
+
end if params[:warning]
|
664
683
|
end
|
665
684
|
end
|
666
685
|
end
|
@@ -759,7 +778,6 @@ describe RDF::Tabular::Metadata do
|
|
759
778
|
"columns Schema" => [{"columns" => []}, RDF::Tabular::Schema],
|
760
779
|
"primaryKey Schema" => [{"primaryKey" => "foo"}, RDF::Tabular::Schema],
|
761
780
|
"foreignKeys Schema" => [{"foreignKeys" => []}, RDF::Tabular::Schema],
|
762
|
-
"urlTemplate Schema" => [{"urlTemplate" => "foo"}, RDF::Tabular::Schema],
|
763
781
|
"commentPrefix Dialect" => [{"commentPrefix" => "#"}, RDF::Tabular::Dialect],
|
764
782
|
"delimiter Dialect" => [{"delimiter" => ","}, RDF::Tabular::Dialect],
|
765
783
|
"doubleQuote Dialect" => [{"doubleQuote" => true}, RDF::Tabular::Dialect],
|
@@ -862,7 +880,7 @@ describe RDF::Tabular::Metadata do
|
|
862
880
|
|
863
881
|
context "URL expansion" do
|
864
882
|
subject {
|
865
|
-
|
883
|
+
JSON.parse(%({
|
866
884
|
"url": "https://example.org/countries.csv",
|
867
885
|
"tableSchema": {
|
868
886
|
"columns": [
|
@@ -872,7 +890,7 @@ describe RDF::Tabular::Metadata do
|
|
872
890
|
{"titles": "name"}
|
873
891
|
]
|
874
892
|
}
|
875
|
-
}))
|
893
|
+
}))
|
876
894
|
}
|
877
895
|
let(:input) {RDF::Util::File.open_file("https://example.org/countries.csv")}
|
878
896
|
|
@@ -881,33 +899,16 @@ describe RDF::Tabular::Metadata do
|
|
881
899
|
aboutUrl: [RDF::Node, RDF::Node, RDF::Node, RDF::Node],
|
882
900
|
propertyUrl: [nil, nil, nil, nil],
|
883
901
|
valueUrl: [nil, nil, nil, nil],
|
884
|
-
md: {
|
885
|
-
"columns" => [
|
886
|
-
{"titles" => "addressCountry"},
|
887
|
-
{"titles" => "latitude"},
|
888
|
-
{"titles" => "longitude"},
|
889
|
-
{"titles" => "name"}
|
890
|
-
]
|
891
|
-
}
|
892
|
-
}
|
902
|
+
md: {}
|
893
903
|
},
|
894
904
|
"schema transformations" => {
|
895
905
|
aboutUrl: %w(#addressCountry #latitude #longitude #name),
|
896
906
|
propertyUrl: %w(?_name=addressCountry ?_name=latitude ?_name=longitude ?_name=name),
|
897
907
|
valueUrl: %w(addressCountry latitude longitude name),
|
898
908
|
md: {
|
899
|
-
"
|
900
|
-
"
|
901
|
-
|
902
|
-
"propertyUrl" => '{?_name}',
|
903
|
-
"valueUrl" => '{_name}',
|
904
|
-
"columns" => [
|
905
|
-
{"titles" => "addressCountry"},
|
906
|
-
{"titles" => "latitude"},
|
907
|
-
{"titles" => "longitude"},
|
908
|
-
{"titles" => "name"}
|
909
|
-
]
|
910
|
-
}
|
909
|
+
"aboutUrl" => "{#_name}",
|
910
|
+
"propertyUrl" => '{?_name}',
|
911
|
+
"valueUrl" => '{_name}'
|
911
912
|
}
|
912
913
|
},
|
913
914
|
"PNames" => {
|
@@ -915,23 +916,14 @@ describe RDF::Tabular::Metadata do
|
|
915
916
|
propertyUrl: [RDF::SCHEMA.addressCountry, RDF::SCHEMA.latitude, RDF::SCHEMA.longitude, RDF::SCHEMA.name],
|
916
917
|
valueUrl: [RDF::SCHEMA.addressCountry, RDF::SCHEMA.latitude, RDF::SCHEMA.longitude, RDF::SCHEMA.name],
|
917
918
|
md: {
|
918
|
-
"
|
919
|
-
"
|
920
|
-
|
921
|
-
"propertyUrl" => 'schema:{_name}',
|
922
|
-
"valueUrl" => 'schema:{_name}',
|
923
|
-
"columns" => [
|
924
|
-
{"titles" => "addressCountry"},
|
925
|
-
{"titles" => "latitude"},
|
926
|
-
{"titles" => "longitude"},
|
927
|
-
{"titles" => "name"}
|
928
|
-
]
|
929
|
-
}
|
919
|
+
"aboutUrl" => "http://schema.org/{_name}",
|
920
|
+
"propertyUrl" => 'schema:{_name}',
|
921
|
+
"valueUrl" => 'schema:{_name}'
|
930
922
|
}
|
931
923
|
},
|
932
924
|
}.each do |name, props|
|
933
925
|
context name do
|
934
|
-
let(:md) {RDF::Tabular::Table.new(props[:md]).
|
926
|
+
let(:md) {RDF::Tabular::Table.new(subject.merge(props[:md]), base: RDF::URI("http://example.org/base")).normalize!}
|
935
927
|
let(:cells) {md.to_enum(:each_row, input).to_a.first.values}
|
936
928
|
let(:aboutUrls) {props[:aboutUrl].map {|u| u.is_a?(String) ? md.url.join(u) : u}}
|
937
929
|
let(:propertyUrls) {props[:propertyUrl].map {|u| u.is_a?(String) ? md.url.join(u) : u}}
|
@@ -1048,12 +1040,12 @@ describe RDF::Tabular::Metadata do
|
|
1048
1040
|
},
|
1049
1041
|
"decimal with matching pattern" => {
|
1050
1042
|
base: "decimal",
|
1051
|
-
pattern: '\d{3}',
|
1043
|
+
format: {pattern: '\d{3}'},
|
1052
1044
|
value: "123"
|
1053
1045
|
},
|
1054
1046
|
"decimal with wrong pattern" => {
|
1055
1047
|
base: "decimal",
|
1056
|
-
pattern: '\d{4}',
|
1048
|
+
format: {pattern: '\d{4}'},
|
1057
1049
|
value: "123",
|
1058
1050
|
errors: [/123 does not match pattern/]
|
1059
1051
|
},
|
@@ -1064,20 +1056,20 @@ describe RDF::Tabular::Metadata do
|
|
1064
1056
|
},
|
1065
1057
|
"decimal with explicit groupChar" => {
|
1066
1058
|
base: "decimal",
|
1067
|
-
groupChar: ";",
|
1059
|
+
format: {groupChar: ";"},
|
1068
1060
|
value: "123;456.789",
|
1069
1061
|
result: "123456.789"
|
1070
1062
|
},
|
1071
1063
|
"decimal with repeated groupChar" => {
|
1072
1064
|
base: "decimal",
|
1073
|
-
groupChar: ";",
|
1065
|
+
format: {groupChar: ";"},
|
1074
1066
|
value: "123;;456.789",
|
1075
1067
|
result: "123;;456.789",
|
1076
1068
|
errors: [/has repeating/]
|
1077
1069
|
},
|
1078
1070
|
"decimal with explicit decimalChar" => {
|
1079
1071
|
base: "decimal",
|
1080
|
-
decimalChar: ";",
|
1072
|
+
format: {decimalChar: ";"},
|
1081
1073
|
value: "123456;789",
|
1082
1074
|
result: "123456.789"
|
1083
1075
|
},
|
@@ -1149,7 +1141,7 @@ describe RDF::Tabular::Metadata do
|
|
1149
1141
|
"validate date dd-MM-yyyy" => {base: "date", value: "22-03-2015", format: "dd-MM-yyyy", result: "2015-03-22"},
|
1150
1142
|
"validate date d-M-yyyy" => {base: "date", value: "22-3-2015", format: "d-M-yyyy", result: "2015-03-22"},
|
1151
1143
|
"validate date MM-dd-yyyy" => {base: "date", value: "03-22-2015", format: "MM-dd-yyyy", result: "2015-03-22"},
|
1152
|
-
"validate date M
|
1144
|
+
"validate date M-d-yyyy" => {base: "date", value: "3-22-2015", format: "M-d-yyyy", result: "2015-03-22"},
|
1153
1145
|
"validate date dd/MM/yyyy" => {base: "date", value: "22/03/2015", format: "dd/MM/yyyy", result: "2015-03-22"},
|
1154
1146
|
"validate date d/M/yyyy" => {base: "date", value: "22/3/2015", format: "d/M/yyyy", result: "2015-03-22"},
|
1155
1147
|
"validate date MM/dd/yyyy" => {base: "date", value: "03/22/2015", format: "MM/dd/yyyy", result: "2015-03-22"},
|
@@ -1356,356 +1348,179 @@ describe RDF::Tabular::Metadata do
|
|
1356
1348
|
end
|
1357
1349
|
end
|
1358
1350
|
|
1359
|
-
describe "#
|
1351
|
+
describe "#verify_compatible!" do
|
1360
1352
|
{
|
1361
1353
|
"two tables with same id" => {
|
1362
1354
|
A: %({
|
1355
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1363
1356
|
"@type": "Table",
|
1364
|
-
"url": "http://example.org/table"
|
1357
|
+
"url": "http://example.org/table",
|
1358
|
+
"tableSchema": {"columns": []}
|
1365
1359
|
}),
|
1366
|
-
B:
|
1360
|
+
B: %({
|
1361
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1367
1362
|
"@type": "Table",
|
1368
|
-
"url": "http://example.org/table"
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
"tables": [{
|
1373
|
-
"@type": "Table",
|
1374
|
-
"url": "http://example.org/table"
|
1375
|
-
}],
|
1376
|
-
"@context": "http://www.w3.org/ns/csvw"
|
1377
|
-
})
|
1363
|
+
"url": "http://example.org/table",
|
1364
|
+
"tableSchema": {"columns": []}
|
1365
|
+
}),
|
1366
|
+
R: true
|
1378
1367
|
},
|
1379
1368
|
"two tables with different id" => {
|
1380
1369
|
A: %({
|
1370
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1381
1371
|
"@type": "Table",
|
1382
|
-
"url": "http://example.org/table1"
|
1372
|
+
"url": "http://example.org/table1",
|
1373
|
+
"tableSchema": {"columns": []}
|
1383
1374
|
}),
|
1384
|
-
B:
|
1385
|
-
"@
|
1386
|
-
"url": "http://example.org/table2"
|
1387
|
-
})],
|
1388
|
-
R: %({
|
1389
|
-
"@type": "TableGroup",
|
1390
|
-
"tables": [{
|
1391
|
-
"@type": "Table",
|
1392
|
-
"url": "http://example.org/table1"
|
1393
|
-
}, {
|
1394
|
-
"@type": "Table",
|
1395
|
-
"url": "http://example.org/table2"
|
1396
|
-
}],
|
1397
|
-
"@context": "http://www.w3.org/ns/csvw"
|
1398
|
-
})
|
1399
|
-
},
|
1400
|
-
"table and table-group" => {
|
1401
|
-
A: %({
|
1375
|
+
B: %({
|
1376
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1402
1377
|
"@type": "Table",
|
1403
|
-
"url": "http://example.org/
|
1378
|
+
"url": "http://example.org/table2",
|
1379
|
+
"tableSchema": {"columns": []}
|
1404
1380
|
}),
|
1405
|
-
|
1406
|
-
"@type": "TableGroup",
|
1407
|
-
"tables": [{
|
1408
|
-
"@type": "Table",
|
1409
|
-
"url": "http://example.org/table2"
|
1410
|
-
}]
|
1411
|
-
})],
|
1412
|
-
R: %({
|
1413
|
-
"@type": "TableGroup",
|
1414
|
-
"tables": [{
|
1415
|
-
"@type": "Table",
|
1416
|
-
"url": "http://example.org/table1"
|
1417
|
-
}, {
|
1418
|
-
"@type": "Table",
|
1419
|
-
"url": "http://example.org/table2"
|
1420
|
-
}],
|
1421
|
-
"@context": "http://www.w3.org/ns/csvw"
|
1422
|
-
})
|
1381
|
+
R: false
|
1423
1382
|
},
|
1424
|
-
"table-group and table" => {
|
1383
|
+
"table-group and table with same url" => {
|
1425
1384
|
A: %({
|
1385
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1426
1386
|
"@type": "TableGroup",
|
1427
1387
|
"tables": [{
|
1428
1388
|
"@type": "Table",
|
1429
|
-
"url": "http://example.org/table1"
|
1389
|
+
"url": "http://example.org/table1",
|
1390
|
+
"tableSchema": {"columns": []}
|
1430
1391
|
}]
|
1431
1392
|
}),
|
1432
|
-
B:
|
1393
|
+
B: %({
|
1394
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1433
1395
|
"@type": "Table",
|
1434
|
-
"url": "http://example.org/
|
1435
|
-
|
1436
|
-
|
1437
|
-
|
1438
|
-
"tables": [{
|
1439
|
-
"@type": "Table",
|
1440
|
-
"url": "http://example.org/table1"
|
1441
|
-
}, {
|
1442
|
-
"@type": "Table",
|
1443
|
-
"url": "http://example.org/table2"
|
1444
|
-
}],
|
1445
|
-
"@context": "http://www.w3.org/ns/csvw"
|
1446
|
-
})
|
1396
|
+
"url": "http://example.org/table1",
|
1397
|
+
"tableSchema": {"columns": []}
|
1398
|
+
}),
|
1399
|
+
R: true
|
1447
1400
|
},
|
1448
|
-
"table-group and
|
1401
|
+
"table-group and table with different url" => {
|
1449
1402
|
A: %({
|
1403
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1450
1404
|
"@type": "TableGroup",
|
1451
1405
|
"tables": [{
|
1452
1406
|
"@type": "Table",
|
1453
|
-
"url": "http://example.org/table1"
|
1407
|
+
"url": "http://example.org/table1",
|
1408
|
+
"tableSchema": {"columns": []}
|
1454
1409
|
}]
|
1455
1410
|
}),
|
1456
|
-
B:
|
1457
|
-
"@
|
1458
|
-
"url": "http://example.org/table2",
|
1459
|
-
"dc:label": "foo"
|
1460
|
-
}), %({
|
1411
|
+
B: %({
|
1412
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1461
1413
|
"@type": "Table",
|
1462
1414
|
"url": "http://example.org/table2",
|
1463
|
-
"
|
1464
|
-
})
|
1465
|
-
R:
|
1415
|
+
"tableSchema": {"columns": []}
|
1416
|
+
}),
|
1417
|
+
R: false
|
1418
|
+
},
|
1419
|
+
"table-group with two tables" => {
|
1420
|
+
A: %({
|
1421
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1466
1422
|
"@type": "TableGroup",
|
1467
1423
|
"tables": [{
|
1468
1424
|
"@type": "Table",
|
1469
|
-
"url": "http://example.org/table1"
|
1425
|
+
"url": "http://example.org/table1",
|
1426
|
+
"tableSchema": {"columns": []}
|
1470
1427
|
}, {
|
1471
1428
|
"@type": "Table",
|
1472
1429
|
"url": "http://example.org/table2",
|
1473
|
-
"
|
1474
|
-
}],
|
1475
|
-
"@context": "http://www.w3.org/ns/csvw"
|
1476
|
-
})
|
1477
|
-
},
|
1478
|
-
}.each do |name, props|
|
1479
|
-
it name do
|
1480
|
-
a = described_class.new(::JSON.parse(props[:A]))
|
1481
|
-
b = props[:B].map {|md| described_class.new(::JSON.parse(md))}
|
1482
|
-
r = described_class.new(::JSON.parse(props[:R]))
|
1483
|
-
expect(a.merge(*b)).to produce(r, @debug)
|
1484
|
-
end
|
1485
|
-
end
|
1486
|
-
|
1487
|
-
%w(Transformation Schema Transformation Column Dialect).each do |t|
|
1488
|
-
it "does not merge into a #{t}" do
|
1489
|
-
a = described_class.new({}, type: t.to_sym)
|
1490
|
-
b = described_class.new({}, type: :TableGroup)
|
1491
|
-
expect {a.merge(b)}.to raise_error
|
1492
|
-
end
|
1493
|
-
|
1494
|
-
it "does not merge from a #{t}" do
|
1495
|
-
a = described_class.new({}, type: :TableGroup)
|
1496
|
-
b = described_class.new({}, type: t.to_sym)
|
1497
|
-
expect {a.merge(b)}.to raise_error
|
1498
|
-
end
|
1499
|
-
end
|
1500
|
-
end
|
1501
|
-
|
1502
|
-
describe "#merge!" do
|
1503
|
-
{
|
1504
|
-
"TableGroup with and without @id" => {
|
1505
|
-
A: %({"@id": "http://example.org/foo", "tables": [], "@type": "TableGroup"}),
|
1506
|
-
B: %({"tables": [], "@type": "TableGroup"}),
|
1507
|
-
R: %({"@id": "http://example.org/foo", "tables": [], "@type": "TableGroup"})
|
1508
|
-
},
|
1509
|
-
"TableGroup with and without @type" => {
|
1510
|
-
A: %({"tables": []}),
|
1511
|
-
B: %({"tables": [], "@type": "TableGroup"}),
|
1512
|
-
R: %({"tables": [], "@type": "TableGroup"})
|
1513
|
-
},
|
1514
|
-
"TableGroup with matching tables" => {
|
1515
|
-
A: %({"tables": [{"url": "http://example.org/foo", "dc:title": "foo"}]}),
|
1516
|
-
B: %({"tables": [{"url": "http://example.org/foo", "dc:description": "bar"}]}),
|
1517
|
-
R: %({"tables": [{
|
1518
|
-
"url": "http://example.org/foo",
|
1519
|
-
"dc:title": {"@value": "foo"},
|
1520
|
-
"dc:description": {"@value": "bar"}
|
1521
|
-
}]})
|
1522
|
-
},
|
1523
|
-
"TableGroup with differing tables" => {
|
1524
|
-
A: %({"tables": [{"url": "http://example.org/foo", "dc:title": "foo"}]}),
|
1525
|
-
B: %({"tables": [{"url": "http://example.org/bar", "dc:description": "bar"}]}),
|
1526
|
-
R: %({
|
1527
|
-
"tables": [
|
1528
|
-
{"url": "http://example.org/foo", "dc:title": {"@value": "foo"}},
|
1529
|
-
{"url": "http://example.org/bar", "dc:description": {"@value": "bar"}}
|
1530
|
-
]})
|
1531
|
-
},
|
1532
|
-
"Table with tableDirection always takes A" => {
|
1533
|
-
A: %({"@type": "Table", "url": "http://example.com/foo", "tableDirection": "ltr"}),
|
1534
|
-
B: %({"@type": "Table", "url": "http://example.com/foo", "tableDirection": "rtl"}),
|
1535
|
-
R: %({"@type": "Table", "url": "http://example.com/foo", "tableDirection": "ltr"}),
|
1536
|
-
},
|
1537
|
-
"Table with dialect merges A and B" => {
|
1538
|
-
A: %({"@type": "Table", "url": "http://example.com/foo", "dialect": {"encoding": "utf-8"}}),
|
1539
|
-
B: %({"@type": "Table", "url": "http://example.com/foo", "dialect": {"skipRows": 0}}),
|
1540
|
-
R: %({"@type": "Table", "url": "http://example.com/foo", "dialect": {"encoding": "utf-8", "skipRows": 0}}),
|
1541
|
-
},
|
1542
|
-
"Table with equivalent transformations uses A" => {
|
1543
|
-
A: %({
|
1544
|
-
"@type": "Table",
|
1545
|
-
"url": "http://example.com/foo",
|
1546
|
-
"transformations": [{
|
1547
|
-
"url": "http://example.com/foo",
|
1548
|
-
"targetFormat": "http://example.com/target",
|
1549
|
-
"scriptFormat": "http://example.com/template",
|
1550
|
-
"source": "json"
|
1430
|
+
"tableSchema": {"columns": []}
|
1551
1431
|
}]
|
1552
1432
|
}),
|
1553
1433
|
B: %({
|
1434
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1554
1435
|
"@type": "Table",
|
1555
|
-
"url": "http://example.
|
1556
|
-
"
|
1557
|
-
"url": "http://example.com/foo",
|
1558
|
-
"targetFormat": "http://example.com/target",
|
1559
|
-
"scriptFormat": "http://example.com/template",
|
1560
|
-
"source": "html"
|
1561
|
-
}]
|
1562
|
-
}),
|
1563
|
-
R: %({
|
1564
|
-
"@type": "Table",
|
1565
|
-
"url": "http://example.com/foo",
|
1566
|
-
"transformations": [{
|
1567
|
-
"url": "http://example.com/foo",
|
1568
|
-
"targetFormat": "http://example.com/target",
|
1569
|
-
"scriptFormat": "http://example.com/template",
|
1570
|
-
"source": "json"
|
1571
|
-
}]
|
1436
|
+
"url": "http://example.org/table2",
|
1437
|
+
"tableSchema": {"columns": []}
|
1572
1438
|
}),
|
1439
|
+
R: true
|
1573
1440
|
},
|
1574
|
-
"
|
1441
|
+
"tables with matching columns" => {
|
1575
1442
|
A: %({
|
1443
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1576
1444
|
"@type": "Table",
|
1577
|
-
"url": "http://example.
|
1578
|
-
"
|
1579
|
-
"url": "http://example.com/foo",
|
1580
|
-
"targetFormat": "http://example.com/target",
|
1581
|
-
"scriptFormat": "http://example.com/template"
|
1582
|
-
}]
|
1445
|
+
"url": "http://example.org/table1",
|
1446
|
+
"tableSchema": {"columns": [{"name": "foo"}]}
|
1583
1447
|
}),
|
1584
1448
|
B: %({
|
1449
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1585
1450
|
"@type": "Table",
|
1586
|
-
"url": "http://example.
|
1587
|
-
"
|
1588
|
-
"url": "http://example.com/bar",
|
1589
|
-
"targetFormat": "http://example.com/targetb",
|
1590
|
-
"scriptFormat": "http://example.com/templateb"
|
1591
|
-
}]
|
1451
|
+
"url": "http://example.org/table1",
|
1452
|
+
"tableSchema": {"columns": [{"name": "foo"}]}
|
1592
1453
|
}),
|
1593
|
-
R:
|
1454
|
+
R: true
|
1455
|
+
},
|
1456
|
+
"tables with virtual columns otherwise matching" => {
|
1457
|
+
A: %({
|
1458
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1594
1459
|
"@type": "Table",
|
1595
|
-
"url": "http://example.
|
1596
|
-
"
|
1597
|
-
"url": "http://example.com/foo",
|
1598
|
-
"targetFormat": "http://example.com/target",
|
1599
|
-
"scriptFormat": "http://example.com/template"
|
1600
|
-
}, {
|
1601
|
-
"url": "http://example.com/bar",
|
1602
|
-
"targetFormat": "http://example.com/targetb",
|
1603
|
-
"scriptFormat": "http://example.com/templateb"
|
1604
|
-
}]
|
1460
|
+
"url": "http://example.org/table1",
|
1461
|
+
"tableSchema": {"columns": [{"name": "foo"}, {"virtual": true}]}
|
1605
1462
|
}),
|
1606
|
-
|
1607
|
-
|
1608
|
-
A: %({"@type": "Table", "url": "http://example.com/foo", "rdfs:label": "foo"}),
|
1609
|
-
B: %({"@type": "Table", "url": "http://example.com/foo", "rdfs:label": "bar"}),
|
1610
|
-
R: %({
|
1463
|
+
B: %({
|
1464
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1611
1465
|
"@type": "Table",
|
1612
|
-
"url": "http://example.
|
1613
|
-
"
|
1466
|
+
"url": "http://example.org/table1",
|
1467
|
+
"tableSchema": {"columns": [{"name": "foo"}]}
|
1614
1468
|
}),
|
1469
|
+
R: true
|
1615
1470
|
},
|
1616
|
-
"
|
1471
|
+
"tables with differing columns" => {
|
1617
1472
|
A: %({
|
1618
|
-
"@context":
|
1473
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1619
1474
|
"@type": "Table",
|
1620
|
-
"url": "http://example.
|
1621
|
-
"
|
1475
|
+
"url": "http://example.org/table1",
|
1476
|
+
"tableSchema": {"columns": [{"name": "foo"}]}
|
1622
1477
|
}),
|
1623
1478
|
B: %({
|
1624
|
-
"@context": {"@language": "fr"},
|
1625
|
-
"@type": "Table",
|
1626
|
-
"url": "http://example.com/foo",
|
1627
|
-
"rdfs:label": "foo"
|
1628
|
-
}),
|
1629
|
-
R: %({
|
1630
1479
|
"@context": "http://www.w3.org/ns/csvw",
|
1631
1480
|
"@type": "Table",
|
1632
|
-
"url": "http://example.
|
1633
|
-
"
|
1481
|
+
"url": "http://example.org/table1",
|
1482
|
+
"tableSchema": {"columns": [{"name": "bar"}]}
|
1634
1483
|
}),
|
1484
|
+
R: false
|
1635
1485
|
},
|
1636
|
-
"
|
1486
|
+
"tables with different column count" => {
|
1637
1487
|
A: %({
|
1638
|
-
"@context":
|
1488
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1639
1489
|
"@type": "Table",
|
1640
|
-
"url": "http://example.
|
1641
|
-
"tableSchema": {
|
1642
|
-
"columns": [{"titles": "foo"}]
|
1643
|
-
}
|
1490
|
+
"url": "http://example.org/table1",
|
1491
|
+
"tableSchema": {"columns": [{"name": "foo"}, {"name": "bar"}]}
|
1644
1492
|
}),
|
1645
1493
|
B: %({
|
1494
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1646
1495
|
"@type": "Table",
|
1647
|
-
"url": "http://example.
|
1648
|
-
"tableSchema": {
|
1649
|
-
"columns": [{"titles": "foo"}]
|
1650
|
-
}
|
1496
|
+
"url": "http://example.org/table1",
|
1497
|
+
"tableSchema": {"columns": [{"name": "bar"}]}
|
1651
1498
|
}),
|
1652
|
-
R:
|
1499
|
+
R: false
|
1500
|
+
},
|
1501
|
+
"tables with matching columns on name/titles" => {
|
1502
|
+
A: %({
|
1653
1503
|
"@context": "http://www.w3.org/ns/csvw",
|
1654
1504
|
"@type": "Table",
|
1655
|
-
"url": "http://example.
|
1656
|
-
"tableSchema": {
|
1657
|
-
"columns": [{"titles": {"en": ["foo"]}}]
|
1658
|
-
}
|
1505
|
+
"url": "http://example.org/table1",
|
1506
|
+
"tableSchema": {"columns": [{"name": "foo"}]}
|
1659
1507
|
}),
|
1660
|
-
|
1661
|
-
|
1662
|
-
|
1663
|
-
|
1664
|
-
|
1665
|
-
|
1666
|
-
|
1667
|
-
A: %({"@type": "Schema", "columns": [{"titles": "Foo"}]}),
|
1668
|
-
B: %({"@type": "Schema", "columns": [{"name": "foo", "titles": "Foo"}]}),
|
1669
|
-
R: %({"@type": "Schema", "columns": [{"name": "foo", "titles": {"und": ["Foo"]}}]}),
|
1670
|
-
},
|
1671
|
-
"Schema with primaryKey always takes A" => {
|
1672
|
-
A: %({"@type": "Schema", "primaryKey": "foo"}),
|
1673
|
-
B: %({"@type": "Schema", "primaryKey": "bar"}),
|
1674
|
-
R: %({"@type": "Schema", "primaryKey": "foo"}),
|
1675
|
-
},
|
1676
|
-
"Schema with matching foreignKey uses A" => {
|
1677
|
-
A: %({"@type": "Schema", "columns": [{"name": "foo"}], "foreignKeys": [{"columnReference": "foo", "reference": {"columnReference": "foo"}}]}),
|
1678
|
-
B: %({"@type": "Schema", "columns": [{"name": "foo"}], "foreignKeys": [{"columnReference": "foo", "reference": {"columnReference": "foo"}}]}),
|
1679
|
-
R: %({"@type": "Schema", "columns": [{"name": "foo"}], "foreignKeys": [{"columnReference": "foo", "reference": {"columnReference": "foo"}}]}),
|
1680
|
-
},
|
1681
|
-
"Schema with differing foreignKey uses A and B" => {
|
1682
|
-
A: %({"@type": "Schema", "columns": [{"name": "foo"}, {"name": "bar"}], "foreignKeys": [{"columnReference": "foo", "reference": {"columnReference": "foo"}}]}),
|
1683
|
-
B: %({"@type": "Schema", "columns": [{"name": "foo"}, {"name": "bar"}], "foreignKeys": [{"columnReference": "bar", "reference": {"columnReference": "bar"}}]}),
|
1684
|
-
R: %({"@type": "Schema", "columns": [{"name": "foo"}, {"name": "bar"}], "foreignKeys": [{"columnReference": "foo", "reference": {"columnReference": "foo"}}, {"columnReference": "bar", "reference": {"columnReference": "bar"}}]}),
|
1685
|
-
},
|
1686
|
-
"Schema with urlTemplate always takes A" => {
|
1687
|
-
A: %({"@type": "Schema", "urlTemplate": "foo"}),
|
1688
|
-
B: %({"@type": "Schema", "urlTemplate": "bar"}),
|
1689
|
-
R: %({"@type": "Schema", "urlTemplate": "foo"}),
|
1508
|
+
B: %({
|
1509
|
+
"@context": "http://www.w3.org/ns/csvw",
|
1510
|
+
"@type": "Table",
|
1511
|
+
"url": "http://example.org/table1",
|
1512
|
+
"tableSchema": {"columns": [{"titles": "foo"}]}
|
1513
|
+
}),
|
1514
|
+
R: true
|
1690
1515
|
},
|
1691
1516
|
}.each do |name, props|
|
1692
1517
|
it name do
|
1693
|
-
a = described_class.new(::JSON.parse(props[:A])
|
1518
|
+
a = described_class.new(::JSON.parse(props[:A]))
|
1694
1519
|
b = described_class.new(::JSON.parse(props[:B]))
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
end
|
1700
|
-
end
|
1701
|
-
|
1702
|
-
%w(TableGroup Table Transformation Schema Transformation Column Dialect).each do |ta|
|
1703
|
-
%w(TableGroup Table Transformation Schema Transformation Column Dialect).each do |tb|
|
1704
|
-
next if ta == tb
|
1705
|
-
it "does not merge #{tb} into #{ta}" do
|
1706
|
-
a = described_class.new({}, type: ta.to_sym)
|
1707
|
-
b = described_class.new({}, type: tb.to_sym)
|
1708
|
-
expect {a.merge!(b)}.to raise_error
|
1520
|
+
if props[:R]
|
1521
|
+
expect {a.verify_compatible!(b)}.not_to raise_error
|
1522
|
+
else
|
1523
|
+
expect {a.verify_compatible!(b)}.to raise_error(RDF::Tabular::Error)
|
1709
1524
|
end
|
1710
1525
|
end
|
1711
1526
|
end
|