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.
@@ -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, merge with something empty to create a TableGroup metadata
68
- if @metadata.is_a?(TableGroup)
69
- @metadata.normalize!
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
- table_metadata = @options[:metadata]
77
- dialect = table_metadata.dialect.dup
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
- embedded_metadata = dialect.embedded_metadata(input, @options)
85
- if lang = (input.headers[:content_language] rescue "")
86
- embedded_metadata.lang = lang unless lang.include?(',')
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
- @metadata = table_metadata.dup.merge!(embedded_metadata)
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
- if validate? && !input.warnings.empty?
200
- $stderr.puts "Warnings: #{input.warnings.join("\n")}"
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
- if validate? && !input.warnings.empty?
410
- $stderr.puts "Warnings: #{input.warnings.join("\n")}"
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
- input.each_table do |table|
542
- Reader.open(table.url, options.merge(
543
- format: :tabular,
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
- table = r.to_atd(options)
550
-
551
- # Fill in columns and rows in table_group entry from returned table
552
- t = table_group[:tables].detect {|tab| tab["url"] == table["url"]}
553
- t["columns"] = table["columns"]
554
- t["rows"] = table["rows"]
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.id
592
+ columns[colndx]["cells"] << cell.to_atd
588
593
  end
589
594
  end
590
595
  table
@@ -29,40 +29,32 @@ describe RDF::Tabular::Metadata do
29
29
 
30
30
  shared_examples "inherited properties" do |allowed = true|
31
31
  {
32
- null: {
33
- valid: ["foo", %w(foo bar)],
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
- "textDirection" => {
41
- valid: %w(rtl ltr),
42
- invalid: %w(foo default)
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 {|v| expect(described_class.new("name" => v)).not_to be_valid}
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
- invalid: [1, true, nil]
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.errors).not_to be_empty
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 {described_class.new({"url" => "http://example/", "targetFormat" => targetFormat, "scriptFormat" => scriptFormat}, base: RDF::URI("http://example.org/base"), debug: @debug)}
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
- invalid: [1, true, {}]
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 "invalidates" do
448
- params[:invalid].each do |v|
458
+ it "warnings" do
459
+ params[:warning].each do |v|
449
460
  subject.send("#{prop}=".to_sym, v)
450
- expect(subject).not_to be_valid
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(:DIALECT_DEFAULTS).each do |p, v|
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], base: RDF::URI("http://example.org/base"), debug: @debug)
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
- invalid: [1, true, nil]
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
- invalid: %w(foo true 1)
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
- invalid: [RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")] +
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
- invalid: ["http://location-of-dialect", "foo"]
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
- invalid: [1, true, nil]
643
+ warning: [1, true, nil]
632
644
  },
633
645
  tableDirection: {
634
646
  valid: %w(rtl ltr default),
635
- invalid: %w(foo true 1)
647
+ warning: %w(foo true 1)
636
648
  },
637
649
  dialect: {
638
650
  valid: [{skipRows: 1}],
639
- invalid: ["http://location-of-dialect", "foo"]
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
- invalid: [RDF::Tabular::Transformation.new(url: "http://example", targetFormat: "http://example", scriptFormat: "http://example/")] +
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
- described_class.new(JSON.parse(%({
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
- })), base: RDF::URI("http://example.org/base"), debug: @debug)
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: {"url" => "https://example.org/countries.csv", "tableSchema" => {
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
- "url" => "https://example.org/countries.csv",
900
- "tableSchema" => {
901
- "aboutUrl" => "{#_name}",
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
- "url" => "https://example.org/countries.csv",
919
- "tableSchema" => {
920
- "aboutUrl" => 'http://schema.org/{_name}',
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]).merge(subject).tables.first}
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/d/yyyy" => {base: "date", value: "3/22/2015", format: "M-d-yyyy", result: "2015-03-22"},
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 "#merge" do
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
- R: %({
1371
- "@type": "TableGroup",
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
- "@type": "Table",
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/table1"
1378
+ "url": "http://example.org/table2",
1379
+ "tableSchema": {"columns": []}
1404
1380
  }),
1405
- B: [%({
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/table2"
1435
- })],
1436
- R: %({
1437
- "@type": "TableGroup",
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 two tables" => {
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
- "@type": "Table",
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
- "dc:label": "bar"
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
- "dc:label": {"@value": "foo"}
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.com/foo",
1556
- "transformations": [{
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
- "Table with differing transformations appends B to A" => {
1441
+ "tables with matching columns" => {
1575
1442
  A: %({
1443
+ "@context": "http://www.w3.org/ns/csvw",
1576
1444
  "@type": "Table",
1577
- "url": "http://example.com/foo",
1578
- "transformations": [{
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.com/foo",
1587
- "transformations": [{
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.com/foo",
1596
- "transformations": [{
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
- "Table with common properties keeps A" => {
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.com/foo",
1613
- "rdfs:label": {"@value": "foo"}
1466
+ "url": "http://example.org/table1",
1467
+ "tableSchema": {"columns": [{"name": "foo"}]}
1614
1468
  }),
1469
+ R: true
1615
1470
  },
1616
- "Table with common properties in different languages keeps A" => {
1471
+ "tables with differing columns" => {
1617
1472
  A: %({
1618
- "@context": {"@language": "en"},
1473
+ "@context": "http://www.w3.org/ns/csvw",
1619
1474
  "@type": "Table",
1620
- "url": "http://example.com/foo",
1621
- "rdfs:label": "foo"
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.com/foo",
1633
- "rdfs:label": {"@value": "foo", "@language": "en"}
1481
+ "url": "http://example.org/table1",
1482
+ "tableSchema": {"columns": [{"name": "bar"}]}
1634
1483
  }),
1484
+ R: false
1635
1485
  },
1636
- "Table with different languages merges A and B" => {
1486
+ "tables with different column count" => {
1637
1487
  A: %({
1638
- "@context": {"@language": "en"},
1488
+ "@context": "http://www.w3.org/ns/csvw",
1639
1489
  "@type": "Table",
1640
- "url": "http://example.com/foo",
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.com/foo",
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.com/foo",
1656
- "tableSchema": {
1657
- "columns": [{"titles": {"en": ["foo"]}}]
1658
- }
1505
+ "url": "http://example.org/table1",
1506
+ "tableSchema": {"columns": [{"name": "foo"}]}
1659
1507
  }),
1660
- },
1661
- "Schema with matching columns merges A and B" => {
1662
- A: %({"@type": "Schema", "columns": [{"name": "foo", "required": true}]}),
1663
- B: %({"@type": "Schema", "columns": [{"name": "foo", "required": false}]}),
1664
- R: %({"@type": "Schema", "columns": [{"name": "foo", "required": true}]}),
1665
- },
1666
- "Schema with matching column titles" => {
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]), debug: @debug)
1518
+ a = described_class.new(::JSON.parse(props[:A]))
1694
1519
  b = described_class.new(::JSON.parse(props[:B]))
1695
- r = described_class.new(::JSON.parse(props[:R]))
1696
- m = a.merge!(b)
1697
- expect(m).to produce(r, @debug)
1698
- expect(a).to equal m
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