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