rdf-tabular 0.1.2 → 0.1.3
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.
- 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
|