json-ld 2.1.2 → 2.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -24,7 +24,7 @@ end
24
24
 
25
25
  describe JSON::LD::Context do
26
26
  let(:logger) {RDF::Spec.logger}
27
- let(:context) {JSON::LD::Context.new(logger: logger, validate: true)}
27
+ let(:context) {JSON::LD::Context.new(logger: logger, validate: true, processingMode: "json-ld-1.1")}
28
28
  let(:remote_doc) do
29
29
  JSON::LD::API::RemoteDocument.new("http://example.com/context", %q({
30
30
  "@context": {
@@ -98,7 +98,7 @@ describe JSON::LD::Context do
98
98
  let(:ctx) {["http://example.com/context", {"integer" => "xsd:integer"}]}
99
99
  it "retrieves and parses a remote context document" do
100
100
  expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(remote_doc)
101
- ec = subject.parse(ctx)
101
+ subject.parse(ctx)
102
102
  end
103
103
 
104
104
  it "does not use passed context as provided_context" do
@@ -112,13 +112,13 @@ describe JSON::LD::Context do
112
112
  let(:ctx) {"http://example.com/preloaded"}
113
113
  before(:all) {
114
114
  JSON::LD::Context.add_preloaded("http://example.com/preloaded",
115
- JSON::LD::Context.new().parse({'foo' => "http://example.com/"})
115
+ JSON::LD::Context.parse({'foo' => "http://example.com/"})
116
116
  )}
117
117
  after(:all) {JSON::LD::Context::PRELOADED.clear}
118
118
 
119
119
  it "does not load referenced context" do
120
120
  expect(JSON::LD::API).not_to receive(:documentLoader).with(ctx, anything)
121
- ec = subject.parse(ctx)
121
+ subject.parse(ctx)
122
122
  end
123
123
 
124
124
  it "uses loaded context" do
@@ -192,7 +192,7 @@ describe JSON::LD::Context do
192
192
  }, logger)
193
193
  end
194
194
 
195
- it "associates @list container mapping with predicate" do
195
+ it "associates @list container mapping with term" do
196
196
  expect(subject.parse({
197
197
  "foo" => {"@id" => "http://example.com/", "@container" => "@list"}
198
198
  }).containers).to produce({
@@ -200,7 +200,7 @@ describe JSON::LD::Context do
200
200
  }, logger)
201
201
  end
202
202
 
203
- it "associates @set container mapping with predicate" do
203
+ it "associates @set container mapping with term" do
204
204
  expect(subject.parse({
205
205
  "foo" => {"@id" => "http://example.com/", "@container" => "@set"}
206
206
  }).containers).to produce({
@@ -208,7 +208,23 @@ describe JSON::LD::Context do
208
208
  }, logger)
209
209
  end
210
210
 
211
- it "associates @id container mapping with predicate" do
211
+ it "associates @type container mapping with term" do
212
+ expect(subject.parse({
213
+ "foo" => {"@id" => "http://example.com/", "@container" => "@type"}
214
+ }).containers).to produce({
215
+ "foo" => "@type"
216
+ }, logger)
217
+ end
218
+
219
+ it "associates @id container mapping with term" do
220
+ expect(subject.parse({
221
+ "foo" => {"@id" => "http://example.com/", "@container" => "@id"}
222
+ }).containers).to produce({
223
+ "foo" => "@id"
224
+ }, logger)
225
+ end
226
+
227
+ it "associates @id type mapping with term" do
212
228
  expect(subject.parse({
213
229
  "foo" => {"@id" => "http://example.com/", "@type" => "@id"}
214
230
  }).coercions).to produce({
@@ -216,7 +232,7 @@ describe JSON::LD::Context do
216
232
  }, logger)
217
233
  end
218
234
 
219
- it "associates type mapping with predicate" do
235
+ it "associates type mapping with term" do
220
236
  expect(subject.parse({
221
237
  "foo" => {"@id" => "http://example.com/", "@type" => RDF::XSD.string.to_s}
222
238
  }).coercions).to produce({
@@ -224,7 +240,7 @@ describe JSON::LD::Context do
224
240
  }, logger)
225
241
  end
226
242
 
227
- it "associates language mapping with predicate" do
243
+ it "associates language mapping with term" do
228
244
  expect(subject.parse({
229
245
  "foo" => {"@id" => "http://example.com/", "@language" => "en"}
230
246
  }).send(:languages)).to produce({
@@ -316,6 +332,7 @@ describe JSON::LD::Context do
316
332
  "@container as object" => {"foo" => {"@container" => {}}},
317
333
  "@container as array" => {"foo" => {"@container" => []}},
318
334
  "@container as string" => {"foo" => {"@container" => "true"}},
335
+ "@context which is invalid" => {"foo" => {"@context" => {"bar" => []}}},
319
336
  "@language as @id" => {"@language" => {"@id" => "http://example.com/"}},
320
337
  "@vocab as @id" => {"@vocab" => {"@id" => "http://example.com/"}},
321
338
  }.each do |title, context|
@@ -345,9 +362,50 @@ describe JSON::LD::Context do
345
362
  end
346
363
  end
347
364
 
365
+ describe "#processingMode" do
366
+ it "sets to json-ld-1.0 if not specified" do
367
+ [
368
+ %({}),
369
+ %([{}]),
370
+ ].each do |str|
371
+ ctx = JSON::LD::Context.parse(::JSON.parse(str))
372
+ expect(ctx.processingMode).to eql "json-ld-1.0"
373
+ end
374
+ end
375
+
376
+ it "sets to json-ld-1.1 if @version: 1.1" do
377
+ [
378
+ %({"@version": 1.1}),
379
+ %([{"@version": 1.1}]),
380
+ ].each do |str|
381
+ ctx = JSON::LD::Context.parse(::JSON.parse(str))
382
+ expect(ctx.processingMode).to eql "json-ld-1.1"
383
+ end
384
+ end
385
+
386
+ it "raises InvalidVersionValue if @version out of scope" do
387
+ [
388
+ "1.1",
389
+ "1.0",
390
+ 1.0,
391
+ "foo"
392
+ ].each do |vers|
393
+ expect {JSON::LD::Context.parse({"@version" => vers})}.to raise_error(JSON::LD::JsonLdError::InvalidVersionValue)
394
+ end
395
+ end
396
+
397
+ it "raises ProcessingModeConflict if provided processing mode conflicts with context" do
398
+ expect {JSON::LD::Context.parse({"@version" => 1.1}, processingMode: "json-ld-1.0")}.to raise_error(JSON::LD::JsonLdError::ProcessingModeConflict)
399
+ end
400
+
401
+ it "raises ProcessingModeConflict nested context is different from starting context" do
402
+ expect {JSON::LD::Context.parse([{}, {"@version" => 1.1}])}.to raise_error(JSON::LD::JsonLdError::ProcessingModeConflict)
403
+ end
404
+ end
405
+
348
406
  describe "#merge" do
349
407
  it "creates a new context with components of each" do
350
- c2 = JSON::LD::Context.new().parse({'foo' => "http://example.com/"})
408
+ c2 = JSON::LD::Context.parse({'foo' => "http://example.com/"})
351
409
  cm = context.merge(c2)
352
410
  expect(cm).not_to equal context
353
411
  expect(cm).not_to equal c2
@@ -357,7 +415,7 @@ describe JSON::LD::Context do
357
415
 
358
416
  describe "#merge!" do
359
417
  it "updates context with components from new" do
360
- c2 = JSON::LD::Context.new().parse({'foo' => "http://example.com/"})
418
+ c2 = JSON::LD::Context.parse({'foo' => "http://example.com/"})
361
419
  cm = context.merge!(c2)
362
420
  expect(cm).to equal context
363
421
  expect(cm).not_to equal c2
@@ -414,6 +472,20 @@ describe JSON::LD::Context do
414
472
  expect(c.to_rb).not_to be_empty
415
473
  end
416
474
 
475
+ it "@context" do
476
+ expect(subject.parse({
477
+ "foo" => {"@id" => "http://example.com/", "@context" => {"bar" => "http://example.com/baz"}}
478
+ }).send(:clear_provided_context).
479
+ serialize).to produce({
480
+ "@context" => {
481
+ "foo" => {
482
+ "@id" => "http://example.com/",
483
+ "@context" => {"bar" => "http://example.com/baz"}
484
+ }
485
+ }
486
+ }, logger)
487
+ end
488
+
417
489
  it "@type with dependent prefixes in a single context" do
418
490
  expect(subject.parse({
419
491
  'xsd' => "http://www.w3.org/2001/XMLSchema#",
@@ -648,8 +720,7 @@ describe JSON::LD::Context do
648
720
  }
649
721
  }.each do |title, params|
650
722
  it title do
651
- ec = subject.parse(params[:input])
652
- expect(ec.serialize).to produce(params[:result], logger)
723
+ expect {subject.parse(params[:input])}.to raise_error(JSON::LD::JsonLdError::InvalidTermDefinition)
653
724
  end
654
725
  end
655
726
  end
@@ -902,11 +973,11 @@ describe JSON::LD::Context do
902
973
  [{"@value" => "foo"}, {"@value" => "bar"}, {"@value" => 1}],
903
974
  [{"@value" => "de", "@language" => "de"}, {"@value" => "jp", "@language" => "jp"}],
904
975
  [{"@value" => true}], [{"@value" => false}],
905
- [[{"@value" => 1}], [{"@value" => 1.1}],
976
+ [{"@value" => 1}], [{"@value" => 1.1}],
906
977
  ],
907
978
  "listlang" => [[{"@value" => "en", "@language" => "en"}]],
908
979
  "listbool" => [[{"@value" => "true", "@type" => RDF::XSD.boolean.to_s}]],
909
- "listinteger" => [{"@value" => "1", "@type" => RDF::XSD.integer.to_s}]],
980
+ "listinteger" => [[{"@value" => "1", "@type" => RDF::XSD.integer.to_s}]],
910
981
  "listdouble" => [[{"@value" => "1", "@type" => RDF::XSD.double.to_s}]],
911
982
  "listdate" => [[{"@value" => "2012-04-17", "@type" => RDF::XSD.date.to_s}]],
912
983
  }.each do |prop, values|
@@ -1284,26 +1355,43 @@ describe JSON::LD::Context do
1284
1355
  describe "#container" do
1285
1356
  subject {
1286
1357
  ctx = context.parse({
1287
- "ex" => "http://example.org/",
1288
- "list" => {"@id" => "ex:list", "@container" => "@list"},
1289
- "set" => {"@id" => "ex:set", "@container" => "@set"},
1290
- "ndx" => {"@id" => "ex:ndx", "@container" => "@index"},
1358
+ "ex" => "http://example.org/",
1359
+ "list" => {"@id" => "ex:list", "@container" => "@list"},
1360
+ "set" => {"@id" => "ex:set", "@container" => "@set"},
1361
+ "language" => {"@id" => "ex:language", "@container" => "@language"},
1362
+ "ndx" => {"@id" => "ex:ndx", "@container" => "@index"},
1363
+ "id" => {"@id" => "ex:id", "@container" => "@id"},
1364
+ "type" => {"@id" => "ex:type", "@container" => "@type"}
1291
1365
  })
1292
1366
  logger.clear
1293
1367
  ctx
1294
1368
  }
1295
1369
  it "uses TermDefinition" do
1296
- expect(subject.container(subject.term_definitions['ex'])).to be_nil
1297
- expect(subject.container(subject.term_definitions['list'])).to eq '@list'
1298
- expect(subject.container(subject.term_definitions['set'])).to eq '@set'
1299
- expect(subject.container(subject.term_definitions['ndx'])).to eq '@index'
1370
+ {
1371
+ "ex" => nil,
1372
+ "list" => "@list",
1373
+ "set" => "@set",
1374
+ "language" => "@language",
1375
+ "ndx" => "@index",
1376
+ "id" => "@id",
1377
+ "type" => "@type",
1378
+ }.each do |defn, container|
1379
+ expect(subject.container(subject.term_definitions[defn])).to eq container
1380
+ end
1300
1381
  end
1301
1382
 
1302
1383
  it "uses string" do
1303
- expect(subject.container('ex')).to be_nil
1304
- expect(subject.container('list')).to eq '@list'
1305
- expect(subject.container('set')).to eq '@set'
1306
- expect(subject.container('ndx')).to eq '@index'
1384
+ {
1385
+ "ex" => nil,
1386
+ "list" => "@list",
1387
+ "set" => "@set",
1388
+ "language" => "@language",
1389
+ "ndx" => "@index",
1390
+ "id" => "@id",
1391
+ "type" => "@type",
1392
+ }.each do |defn, container|
1393
+ expect(subject.container(defn)).to eq container
1394
+ end
1307
1395
  end
1308
1396
  end
1309
1397
 
@@ -1350,6 +1438,44 @@ describe JSON::LD::Context do
1350
1438
  end
1351
1439
  end
1352
1440
 
1441
+ describe "#nest" do
1442
+ subject {
1443
+ ctx = context.parse({
1444
+ "ex" => "http://example.org/",
1445
+ "nest" => {"@id" => "ex:nest", "@nest" => "@nest"},
1446
+ "nest2" => {"@id" => "ex:nest2", "@nest" => "nest-alias"},
1447
+ "nest-alias" => "@nest"
1448
+ })
1449
+ logger.clear
1450
+ ctx
1451
+ }
1452
+
1453
+ it "uses term" do
1454
+ {
1455
+ "ex" => nil,
1456
+ "nest" => "@nest",
1457
+ "nest2" => "nest-alias",
1458
+ "nest-alias" => nil,
1459
+ }.each do |defn, nest|
1460
+ expect(subject.nest(defn)).to eq nest
1461
+ end
1462
+ end
1463
+
1464
+ context "detects error" do
1465
+ it "does not allow a keyword other than @nest for the value of @nest" do
1466
+ expect {
1467
+ context.parse({"no-keyword-nest" => {"@id" => "http://example/f", "@nest" => "@id"}})
1468
+ }.to raise_error JSON::LD::JsonLdError::InvalidNestValue
1469
+ end
1470
+
1471
+ it "does not allow @nest with @reverse" do
1472
+ expect {
1473
+ context.parse({"no-reverse-nest" => {"@reverse" => "http://example/f", "@nest" => "@nest"}})
1474
+ }.to raise_error JSON::LD::JsonLdError::InvalidReverseProperty
1475
+ end
1476
+ end
1477
+ end
1478
+
1353
1479
  describe "#reverse_term" do
1354
1480
  subject {
1355
1481
  ctx = context.parse({
@@ -85,10 +85,7 @@ describe JSON::LD::API do
85
85
  output: [{"http://example.com/ex" => [{"@value" => false}]}]
86
86
  }
87
87
  }.each_pair do |title, params|
88
- it title do
89
- jld = JSON::LD::API.expand(params[:input], logger: logger)
90
- expect(jld).to produce(params[:output], logger)
91
- end
88
+ it(title) {run_expand params}
92
89
  end
93
90
 
94
91
  context "with relative IRIs" do
@@ -96,31 +93,31 @@ describe JSON::LD::API do
96
93
  "base" => {
97
94
  input: {
98
95
  "@id" => "",
99
- "@type" => "#{RDF::RDFS.Resource}"
96
+ "@type" => "http://www.w3.org/2000/01/rdf-schema#Resource"
100
97
  },
101
98
  output: [{
102
99
  "@id" => "http://example.org/",
103
- "@type" => ["#{RDF::RDFS.Resource}"]
100
+ "@type" => ["http://www.w3.org/2000/01/rdf-schema#Resource"]
104
101
  }]
105
102
  },
106
103
  "relative" => {
107
104
  input: {
108
105
  "@id" => "a/b",
109
- "@type" => "#{RDF::RDFS.Resource}"
106
+ "@type" => "http://www.w3.org/2000/01/rdf-schema#Resource"
110
107
  },
111
108
  output: [{
112
109
  "@id" => "http://example.org/a/b",
113
- "@type" => ["#{RDF::RDFS.Resource}"]
110
+ "@type" => ["http://www.w3.org/2000/01/rdf-schema#Resource"]
114
111
  }]
115
112
  },
116
113
  "hash" => {
117
114
  input: {
118
115
  "@id" => "#a",
119
- "@type" => "#{RDF::RDFS.Resource}"
116
+ "@type" => "http://www.w3.org/2000/01/rdf-schema#Resource"
120
117
  },
121
118
  output: [{
122
119
  "@id" => "http://example.org/#a",
123
- "@type" => ["#{RDF::RDFS.Resource}"]
120
+ "@type" => ["http://www.w3.org/2000/01/rdf-schema#Resource"]
124
121
  }]
125
122
  },
126
123
  "unmapped @id" => {
@@ -132,10 +129,7 @@ describe JSON::LD::API do
132
129
  }]
133
130
  },
134
131
  }.each do |title, params|
135
- it title do
136
- jld = JSON::LD::API.expand(params[:input], base: "http://example.org/", logger: logger)
137
- expect(jld).to produce(params[:output], logger)
138
- end
132
+ it(title) {run_expand params.merge(base: "http://example.org/")}
139
133
  end
140
134
  end
141
135
 
@@ -145,21 +139,21 @@ describe JSON::LD::API do
145
139
  input: {
146
140
  "@context" => {"id" => "@id"},
147
141
  "id" => "",
148
- "@type" => "#{RDF::RDFS.Resource}"
142
+ "@type" => "http://www.w3.org/2000/01/rdf-schema#Resource"
149
143
  },
150
144
  output: [{
151
145
  "@id" => "",
152
- "@type" =>[ "#{RDF::RDFS.Resource}"]
146
+ "@type" =>[ "http://www.w3.org/2000/01/rdf-schema#Resource"]
153
147
  }]
154
148
  },
155
149
  "@type" => {
156
150
  input: {
157
151
  "@context" => {"type" => "@type"},
158
- "type" => RDF::RDFS.Resource.to_s,
152
+ "type" => "http://www.w3.org/2000/01/rdf-schema#Resource",
159
153
  "http://example.com/foo" => {"@value" => "bar", "type" => "http://example.com/baz"}
160
154
  },
161
155
  output: [{
162
- "@type" => [RDF::RDFS.Resource.to_s],
156
+ "@type" => ["http://www.w3.org/2000/01/rdf-schema#Resource"],
163
157
  "http://example.com/foo" => [{"@value" => "bar", "@type" => "http://example.com/baz"}]
164
158
  }]
165
159
  },
@@ -191,10 +185,7 @@ describe JSON::LD::API do
191
185
  }]
192
186
  },
193
187
  }.each do |title, params|
194
- it title do
195
- jld = JSON::LD::API.expand(params[:input], logger: logger)
196
- expect(jld).to produce(params[:output], logger)
197
- end
188
+ it(title) {run_expand params}
198
189
  end
199
190
  end
200
191
 
@@ -246,10 +237,7 @@ describe JSON::LD::API do
246
237
  }]
247
238
  },
248
239
  }.each do |title, params|
249
- it title do
250
- jld = JSON::LD::API.expand(params[:input], logger: logger)
251
- expect(jld).to produce(params[:output], logger)
252
- end
240
+ it(title) {run_expand params}
253
241
  end
254
242
  end
255
243
 
@@ -257,27 +245,24 @@ describe JSON::LD::API do
257
245
  {
258
246
  "boolean" => {
259
247
  input: {
260
- "@context" => {"foo" => {"@id" => "http://example.org/foo", "@type" => RDF::XSD.boolean.to_s}},
248
+ "@context" => {"foo" => {"@id" => "http://example.org/foo", "@type" => "http://www.w3.org/2001/XMLSchema#boolean"}},
261
249
  "foo" => "true"
262
250
  },
263
251
  output: [{
264
- "http://example.org/foo" => [{"@value" => "true", "@type" => RDF::XSD.boolean.to_s}]
252
+ "http://example.org/foo" => [{"@value" => "true", "@type" => "http://www.w3.org/2001/XMLSchema#boolean"}]
265
253
  }]
266
254
  },
267
255
  "date" => {
268
256
  input: {
269
- "@context" => {"foo" => {"@id" => "http://example.org/foo", "@type" => RDF::XSD.date.to_s}},
257
+ "@context" => {"foo" => {"@id" => "http://example.org/foo", "@type" => "http://www.w3.org/2001/XMLSchema#date"}},
270
258
  "foo" => "2011-03-26"
271
259
  },
272
260
  output: [{
273
- "http://example.org/foo" => [{"@value" => "2011-03-26", "@type" => RDF::XSD.date.to_s}]
261
+ "http://example.org/foo" => [{"@value" => "2011-03-26", "@type" => "http://www.w3.org/2001/XMLSchema#date"}]
274
262
  }]
275
263
  },
276
264
  }.each do |title, params|
277
- it title do
278
- jld = JSON::LD::API.expand(params[:input], logger: logger)
279
- expect(jld).to produce(params[:output], logger)
280
- end
265
+ it(title) {run_expand params}
281
266
  end
282
267
  end
283
268
 
@@ -318,10 +303,7 @@ describe JSON::LD::API do
318
303
  }]
319
304
  }
320
305
  }.each do |title, params|
321
- it title do
322
- jld = JSON::LD::API.expand(params[:input], logger: logger)
323
- expect(jld).to produce(params[:output], logger)
324
- end
306
+ it(title) {run_expand params}
325
307
  end
326
308
  end
327
309
 
@@ -346,10 +328,7 @@ describe JSON::LD::API do
346
328
  ]
347
329
  },
348
330
  }.each do |title, params|
349
- it title do
350
- jld = JSON::LD::API.expand(params[:input], logger: logger)
351
- expect(jld).to produce(params[:output], logger)
352
- end
331
+ it(title) {run_expand params}
353
332
  end
354
333
  end
355
334
 
@@ -412,12 +391,7 @@ describe JSON::LD::API do
412
391
  ]
413
392
  }
414
393
  }.each do |title, params|
415
- it title do
416
- jld = JSON::LD::API.expand(params[:input],
417
- base: "http://foo/bar/",
418
- logger: logger)
419
- expect(jld).to produce(params[:output], logger)
420
- end
394
+ it(title) {run_expand params.merge(base: "http://foo/bar/")}
421
395
  end
422
396
  end
423
397
 
@@ -469,14 +443,43 @@ describe JSON::LD::API do
469
443
  }
470
444
  ]}
471
445
  }.each do |title, params|
472
- it title do
473
- jld = JSON::LD::API.expand(params[:input], logger: logger, base: 'http://example/')
474
- expect(jld).to produce(params[:output], logger)
475
- end
446
+ it(title) {run_expand params.merge(base: "http://example/")}
447
+ end
448
+ end
449
+
450
+ context "@container: @index" do
451
+ {
452
+ "string annotation" => {
453
+ input: {
454
+ "@context" => {
455
+ "container" => {
456
+ "@id" => "http://example.com/container",
457
+ "@container" => "@index"
458
+ }
459
+ },
460
+ "@id" => "http://example.com/annotationsTest",
461
+ "container" => {
462
+ "en" => "The Queen",
463
+ "de" => [ "Die Königin", "Ihre Majestät" ]
464
+ }
465
+ },
466
+ output: [
467
+ {
468
+ "@id" => "http://example.com/annotationsTest",
469
+ "http://example.com/container" => [
470
+ {"@value" => "Die Königin", "@index" => "de"},
471
+ {"@value" => "Ihre Majestät", "@index" => "de"},
472
+ {"@value" => "The Queen", "@index" => "en"}
473
+ ]
474
+ }
475
+ ]
476
+ },
477
+ }.each do |title, params|
478
+ it(title) {run_expand params}
476
479
  end
477
480
  end
478
481
 
479
- context "lists" do
482
+ context "@container: @list" do
480
483
  {
481
484
  "empty" => {
482
485
  input: {"http://example.com/foo" => {"@list" => []}},
@@ -505,6 +508,14 @@ describe JSON::LD::API do
505
508
  "http://example.com/foo" => [{"@list" => [ {"@value" => "foo"}, {"@value" => "bar"} ]}]
506
509
  }]
507
510
  },
511
+ "native values in list" => {
512
+ input: {
513
+ "http://example.com/foo" => {"@list" => [1, 2]}
514
+ },
515
+ output: [{
516
+ "http://example.com/foo" => [{"@list" => [{"@value" => 1}, {"@value" => 2}]}]
517
+ }]
518
+ },
508
519
  "explicit list with coerced @id values" => {
509
520
  input: {
510
521
  "@context" => {"http://example.com/foo" => {"@type" => "@id"}},
@@ -524,7 +535,7 @@ describe JSON::LD::API do
524
535
  }]
525
536
  },
526
537
  "expand-0004" => {
527
- input: ::JSON.parse(%({
538
+ input: %({
528
539
  "@context": {
529
540
  "mylist1": {"@id": "http://example.com/mylist1", "@container": "@list"},
530
541
  "mylist2": {"@id": "http://example.com/mylist2", "@container": "@list"},
@@ -532,8 +543,8 @@ describe JSON::LD::API do
532
543
  "myset3": {"@id": "http://example.com/myset3", "@container": "@set"}
533
544
  },
534
545
  "http://example.org/property": { "@list": "one item" }
535
- })),
536
- output: ::JSON.parse(%([
546
+ }),
547
+ output: %([
537
548
  {
538
549
  "http://example.org/property": [
539
550
  {
@@ -545,17 +556,34 @@ describe JSON::LD::API do
545
556
  }
546
557
  ]
547
558
  }
548
- ]))
549
- }
559
+ ])
560
+ },
561
+ "@list containing @list" => {
562
+ input: {
563
+ "http://example.com/foo" => {"@list" => [{"@list" => ["baz"]}]}
564
+ },
565
+ exception: JSON::LD::JsonLdError::ListOfLists
566
+ },
567
+ "@list containing @list (with coercion)" => {
568
+ input: {
569
+ "@context" => {"foo" => {"@id" => "http://example.com/foo", "@container" => "@list"}},
570
+ "foo" => [{"@list" => ["baz"]}]
571
+ },
572
+ exception: JSON::LD::JsonLdError::ListOfLists
573
+ },
574
+ "coerced @list containing an array" => {
575
+ input: {
576
+ "@context" => {"foo" => {"@id" => "http://example.com/foo", "@container" => "@list"}},
577
+ "foo" => [["baz"]]
578
+ },
579
+ exception: JSON::LD::JsonLdError::ListOfLists
580
+ },
550
581
  }.each do |title, params|
551
- it title do
552
- jld = JSON::LD::API.expand(params[:input], logger: logger)
553
- expect(jld).to produce(params[:output], logger)
554
- end
582
+ it(title) {run_expand params}
555
583
  end
556
584
  end
557
585
 
558
- context "sets" do
586
+ context "@container: @set" do
559
587
  {
560
588
  "empty" => {
561
589
  input: {
@@ -601,14 +629,11 @@ describe JSON::LD::API do
601
629
  }]
602
630
  },
603
631
  }.each do |title, params|
604
- it title do
605
- jld = JSON::LD::API.expand(params[:input], logger: logger)
606
- expect(jld).to produce(params[:output], logger)
607
- end
632
+ it(title) {run_expand params}
608
633
  end
609
634
  end
610
635
 
611
- context "language maps" do
636
+ context "@container: @language" do
612
637
  {
613
638
  "simple map" => {
614
639
  input: {
@@ -669,17 +694,795 @@ describe JSON::LD::API do
669
694
  ]
670
695
  }
671
696
  }.each do |title, params|
672
- it title do
673
- jld = JSON::LD::API.expand(params[:input], logger: logger)
674
- expect(jld).to produce(params[:output], logger)
675
- end
697
+ it(title) {run_expand params}
698
+ end
699
+ end
700
+
701
+ context "@container: @id" do
702
+ {
703
+ "Adds @id to object not having an @id" => {
704
+ input: %({
705
+ "@context": {
706
+ "@vocab": "http://example/",
707
+ "idmap": {"@container": "@id"}
708
+ },
709
+ "idmap": {
710
+ "http://example.org/foo": {"label": "Object with @id <foo>"},
711
+ "_:bar": {"label": "Object with @id _:bar"}
712
+ }
713
+ }),
714
+ output: %([{
715
+ "http://example/idmap": [
716
+ {"http://example/label": [{"@value": "Object with @id _:bar"}], "@id": "_:bar"},
717
+ {"http://example/label": [{"@value": "Object with @id <foo>"}], "@id": "http://example.org/foo"}
718
+ ]
719
+ }])
720
+ },
721
+ "Retains @id in object already having an @id" => {
722
+ input: %({
723
+ "@context": {
724
+ "@vocab": "http://example/",
725
+ "idmap": {"@container": "@id"}
726
+ },
727
+ "idmap": {
728
+ "http://example.org/foo": {"@id": "http://example.org/bar", "label": "Object with @id <foo>"},
729
+ "_:bar": {"@id": "_:foo", "label": "Object with @id _:bar"}
730
+ }
731
+ }),
732
+ output: %([{
733
+ "http://example/idmap": [
734
+ {"@id": "_:foo", "http://example/label": [{"@value": "Object with @id _:bar"}]},
735
+ {"@id": "http://example.org/bar", "http://example/label": [{"@value": "Object with @id <foo>"}]}
736
+ ]
737
+ }])
738
+ },
739
+ "Adds expanded @id to object" => {
740
+ input: %({
741
+ "@context": {
742
+ "@vocab": "http://example/",
743
+ "idmap": {"@container": "@id"}
744
+ },
745
+ "idmap": {
746
+ "foo": {"label": "Object with @id <foo>"}
747
+ }
748
+ }),
749
+ output: %([{
750
+ "http://example/idmap": [
751
+ {"http://example/label": [{"@value": "Object with @id <foo>"}], "@id": "http://example.org/foo"}
752
+ ]
753
+ }]),
754
+ base: "http://example.org/"
755
+ },
756
+ "Raises InvalidContainerMapping if processingMode is not specified" => {
757
+ input: %({
758
+ "@context": {
759
+ "@vocab": "http://example/",
760
+ "idmap": {"@container": "@id"}
761
+ },
762
+ "idmap": {
763
+ "http://example.org/foo": {"label": "Object with @id <foo>"},
764
+ "_:bar": {"label": "Object with @id _:bar"}
765
+ }
766
+ }),
767
+ processingMode: nil,
768
+ exception: JSON::LD::JsonLdError::InvalidContainerMapping
769
+ },
770
+ }.each do |title, params|
771
+ it(title) {run_expand({processingMode: "json-ld-1.1"}.merge(params))}
772
+ end
773
+ end
774
+
775
+ context "@container: @type" do
776
+ {
777
+ "Adds @type to object not having an @type" => {
778
+ input: %({
779
+ "@context": {
780
+ "@vocab": "http://example/",
781
+ "typemap": {"@container": "@type"}
782
+ },
783
+ "typemap": {
784
+ "http://example.org/foo": {"label": "Object with @type <foo>"},
785
+ "_:bar": {"label": "Object with @type _:bar"}
786
+ }
787
+ }),
788
+ output: %([{
789
+ "http://example/typemap": [
790
+ {"http://example/label": [{"@value": "Object with @type _:bar"}], "@type": ["_:bar"]},
791
+ {"http://example/label": [{"@value": "Object with @type <foo>"}], "@type": ["http://example.org/foo"]}
792
+ ]
793
+ }])
794
+ },
795
+ "Prepends @type in object already having an @type" => {
796
+ input: %({
797
+ "@context": {
798
+ "@vocab": "http://example/",
799
+ "typemap": {"@container": "@type"}
800
+ },
801
+ "typemap": {
802
+ "http://example.org/foo": {"@type": "http://example.org/bar", "label": "Object with @type <foo>"},
803
+ "_:bar": {"@type": "_:foo", "label": "Object with @type _:bar"}
804
+ }
805
+ }),
806
+ output: %([{
807
+ "http://example/typemap": [
808
+ {
809
+ "@type": ["_:bar", "_:foo"],
810
+ "http://example/label": [{"@value": "Object with @type _:bar"}]
811
+ },
812
+ {
813
+ "@type": ["http://example.org/foo", "http://example.org/bar"],
814
+ "http://example/label": [{"@value": "Object with @type <foo>"}]
815
+ }
816
+ ]
817
+ }])
818
+ },
819
+ "Adds vocabulary expanded @type to object" => {
820
+ input: %({
821
+ "@context": {
822
+ "@vocab": "http://example/",
823
+ "typemap": {"@container": "@type"}
824
+ },
825
+ "typemap": {
826
+ "Foo": {"label": "Object with @type <foo>"}
827
+ }
828
+ }),
829
+ output: %([{
830
+ "http://example/typemap": [
831
+ {"http://example/label": [{"@value": "Object with @type <foo>"}], "@type": ["http://example/Foo"]}
832
+ ]
833
+ }])
834
+ },
835
+ "Adds document expanded @type to object" => {
836
+ input: %({
837
+ "@context": {
838
+ "typemap": {"@id": "http://example/typemap", "@container": "@type"},
839
+ "label": "http://example/label"
840
+ },
841
+ "typemap": {
842
+ "Foo": {"label": "Object with @type <foo>"}
843
+ }
844
+ }),
845
+ output: %([{
846
+ "http://example/typemap": [
847
+ {"http://example/label": [{"@value": "Object with @type <foo>"}], "@type": ["http://example.org/Foo"]}
848
+ ]
849
+ }]),
850
+ base: "http://example.org/"
851
+ },
852
+ "Raises InvalidContainerMapping if processingMode is not specified" => {
853
+ input: %({
854
+ "@context": {
855
+ "@vocab": "http://example/",
856
+ "typemap": {"@container": "@type"}
857
+ },
858
+ "typemap": {
859
+ "http://example.org/foo": {"label": "Object with @type <foo>"},
860
+ "_:bar": {"label": "Object with @type _:bar"}
861
+ }
862
+ }),
863
+ processingMode: nil,
864
+ exception: JSON::LD::JsonLdError::InvalidContainerMapping
865
+ },
866
+ }.each do |title, params|
867
+ it(title) {run_expand({processingMode: "json-ld-1.1"}.merge(params))}
868
+ end
869
+ end
870
+
871
+ context "@nest" do
872
+ {
873
+ "Expands input using @nest" => {
874
+ input: %({
875
+ "@context": {"@vocab": "http://example.org/"},
876
+ "p1": "v1",
877
+ "@nest": {
878
+ "p2": "v2"
879
+ }
880
+ }),
881
+ output: %([{
882
+ "http://example.org/p1": [{"@value": "v1"}],
883
+ "http://example.org/p2": [{"@value": "v2"}]
884
+ }])
885
+ },
886
+ "Expands input using aliased @nest" => {
887
+ input: %({
888
+ "@context": {
889
+ "@vocab": "http://example.org/",
890
+ "nest": "@nest"
891
+ },
892
+ "p1": "v1",
893
+ "nest": {
894
+ "p2": "v2"
895
+ }
896
+ }),
897
+ output: %([{
898
+ "http://example.org/p1": [{"@value": "v1"}],
899
+ "http://example.org/p2": [{"@value": "v2"}]
900
+ }])
901
+ },
902
+ "Appends nested values when property at base and nested" => {
903
+ input: %({
904
+ "@context": {
905
+ "@vocab": "http://example.org/",
906
+ "nest": "@nest"
907
+ },
908
+ "p1": "v1",
909
+ "nest": {
910
+ "p2": "v3"
911
+ },
912
+ "p2": "v2"
913
+ }),
914
+ output: %([{
915
+ "http://example.org/p1": [{"@value": "v1"}],
916
+ "http://example.org/p2": [
917
+ {"@value": "v2"},
918
+ {"@value": "v3"}
919
+ ]
920
+ }])
921
+ },
922
+ "Appends nested values from all @nest aliases in term order" => {
923
+ input: %({
924
+ "@context": {
925
+ "@vocab": "http://example.org/",
926
+ "nest1": "@nest",
927
+ "nest2": "@nest"
928
+ },
929
+ "p1": "v1",
930
+ "nest2": {
931
+ "p2": "v4"
932
+ },
933
+ "p2": "v2",
934
+ "nest1": {
935
+ "p2": "v3"
936
+ }
937
+ }),
938
+ output: %([{
939
+ "http://example.org/p1": [{"@value": "v1"}],
940
+ "http://example.org/p2": [
941
+ {"@value": "v2"},
942
+ {"@value": "v3"},
943
+ {"@value": "v4"}
944
+ ]
945
+ }])
946
+ },
947
+ "Nested nested containers" => {
948
+ input: %({
949
+ "@context": {
950
+ "@vocab": "http://example.org/"
951
+ },
952
+ "p1": "v1",
953
+ "@nest": {
954
+ "p2": "v3",
955
+ "@nest": {
956
+ "p2": "v4"
957
+ }
958
+ },
959
+ "p2": "v2"
960
+ }),
961
+ output: %([{
962
+ "http://example.org/p1": [{"@value": "v1"}],
963
+ "http://example.org/p2": [
964
+ {"@value": "v2"},
965
+ {"@value": "v3"},
966
+ {"@value": "v4"}
967
+ ]
968
+ }])
969
+ },
970
+ "Arrays of nested values" => {
971
+ input: %({
972
+ "@context": {
973
+ "@vocab": "http://example.org/",
974
+ "nest": "@nest"
975
+ },
976
+ "p1": "v1",
977
+ "nest": {
978
+ "p2": ["v4", "v5"]
979
+ },
980
+ "p2": ["v2", "v3"]
981
+ }),
982
+ output: %([{
983
+ "http://example.org/p1": [{"@value": "v1"}],
984
+ "http://example.org/p2": [
985
+ {"@value": "v2"},
986
+ {"@value": "v3"},
987
+ {"@value": "v4"},
988
+ {"@value": "v5"}
989
+ ]
990
+ }])
991
+ },
992
+ "A nest of arrays" => {
993
+ input: %({
994
+ "@context": {
995
+ "@vocab": "http://example.org/",
996
+ "nest": "@nest"
997
+ },
998
+ "p1": "v1",
999
+ "nest": [{
1000
+ "p2": "v4"
1001
+ }, {
1002
+ "p2": "v5"
1003
+ }],
1004
+ "p2": ["v2", "v3"]
1005
+ }),
1006
+ output: %([{
1007
+ "http://example.org/p1": [{"@value": "v1"}],
1008
+ "http://example.org/p2": [
1009
+ {"@value": "v2"},
1010
+ {"@value": "v3"},
1011
+ {"@value": "v4"},
1012
+ {"@value": "v5"}
1013
+ ]
1014
+ }])
1015
+ },
1016
+ "@nest MUST NOT have a string value" => {
1017
+ input: %({
1018
+ "@context": {"@vocab": "http://example.org/"},
1019
+ "@nest": "This should generate an error"
1020
+ }),
1021
+ exception: JSON::LD::JsonLdError::InvalidNestValue
1022
+ },
1023
+ "@nest MUST NOT have a boolen value" => {
1024
+ input: %({
1025
+ "@context": {"@vocab": "http://example.org/"},
1026
+ "@nest": true
1027
+ }),
1028
+ exception: JSON::LD::JsonLdError::InvalidNestValue
1029
+ },
1030
+ "@nest MUST NOT have a numeric value" => {
1031
+ input: %({
1032
+ "@context": {"@vocab": "http://example.org/"},
1033
+ "@nest": 1
1034
+ }),
1035
+ exception: JSON::LD::JsonLdError::InvalidNestValue
1036
+ },
1037
+ "@nest MUST NOT have a value object value" => {
1038
+ input: %({
1039
+ "@context": {"@vocab": "http://example.org/"},
1040
+ "@nest": {"@value": "This should generate an error"}
1041
+ }),
1042
+ exception: JSON::LD::JsonLdError::InvalidNestValue
1043
+ },
1044
+ "@nest in term definition MUST NOT be a non-@nest keyword" => {
1045
+ input: %({
1046
+ "@context": {
1047
+ "@vocab": "http://example.org/",
1048
+ "nest": {"@nest": "@id"}
1049
+ },
1050
+ "nest": "This should generate an error"
1051
+ }),
1052
+ exception: JSON::LD::JsonLdError::InvalidNestValue
1053
+ },
1054
+ "@nest in term definition MUST NOT have a boolen value" => {
1055
+ input: %({
1056
+ "@context": {
1057
+ "@vocab": "http://example.org/",
1058
+ "nest": {"@nest": true}
1059
+ },
1060
+ "nest": "This should generate an error"
1061
+ }),
1062
+ exception: JSON::LD::JsonLdError::InvalidNestValue
1063
+ },
1064
+ "@nest in term definition MUST NOT have a numeric value" => {
1065
+ input: %({
1066
+ "@context": {
1067
+ "@vocab": "http://example.org/",
1068
+ "nest": {"@nest": 123}
1069
+ },
1070
+ "nest": "This should generate an error"
1071
+ }),
1072
+ exception: JSON::LD::JsonLdError::InvalidNestValue
1073
+ },
1074
+ "Nested @container: @list" => {
1075
+ input: %({
1076
+ "@context": {
1077
+ "@vocab": "http://example.org/",
1078
+ "list": {"@container": "@list", "@nest": "nestedlist"},
1079
+ "nestedlist": "@nest"
1080
+ },
1081
+ "nestedlist": {
1082
+ "list": ["a", "b"]
1083
+ }
1084
+ }),
1085
+ output: %([{
1086
+ "http://example.org/list": [{"@list": [
1087
+ {"@value": "a"},
1088
+ {"@value": "b"}
1089
+ ]}]
1090
+ }])
1091
+ },
1092
+ "Nested @container: @index" => {
1093
+ input: %({
1094
+ "@context": {
1095
+ "@vocab": "http://example.org/",
1096
+ "index": {"@container": "@index", "@nest": "nestedindex"},
1097
+ "nestedindex": "@nest"
1098
+ },
1099
+ "nestedindex": {
1100
+ "index": {
1101
+ "A": "a",
1102
+ "B": "b"
1103
+ }
1104
+ }
1105
+ }),
1106
+ output: %([{
1107
+ "http://example.org/index": [
1108
+ {"@value": "a", "@index": "A"},
1109
+ {"@value": "b", "@index": "B"}
1110
+ ]
1111
+ }])
1112
+ },
1113
+ "Nested @container: @language" => {
1114
+ input: %({
1115
+ "@context": {
1116
+ "@vocab": "http://example.org/",
1117
+ "container": {"@container": "@language", "@nest": "nestedlanguage"},
1118
+ "nestedlanguage": "@nest"
1119
+ },
1120
+ "nestedlanguage": {
1121
+ "container": {
1122
+ "en": "The Queen",
1123
+ "de": "Die Königin"
1124
+ }
1125
+ }
1126
+ }),
1127
+ output: %([{
1128
+ "http://example.org/container": [
1129
+ {"@value": "Die Königin", "@language": "de"},
1130
+ {"@value": "The Queen", "@language": "en"}
1131
+ ]
1132
+ }])
1133
+ },
1134
+ "Nested @container: @type" => {
1135
+ input: %({
1136
+ "@context": {
1137
+ "@vocab": "http://example/",
1138
+ "typemap": {"@container": "@type", "@nest": "nestedtypemap"},
1139
+ "nestedtypemap": "@nest"
1140
+ },
1141
+ "nestedtypemap": {
1142
+ "typemap": {
1143
+ "http://example.org/foo": {"label": "Object with @type <foo>"},
1144
+ "_:bar": {"label": "Object with @type _:bar"}
1145
+ }
1146
+ }
1147
+ }),
1148
+ output: %([{
1149
+ "http://example/typemap": [
1150
+ {"http://example/label": [{"@value": "Object with @type _:bar"}], "@type": ["_:bar"]},
1151
+ {"http://example/label": [{"@value": "Object with @type <foo>"}], "@type": ["http://example.org/foo"]}
1152
+ ]
1153
+ }])
1154
+ },
1155
+ "Nested @container: @id" => {
1156
+ input: %({
1157
+ "@context": {
1158
+ "@vocab": "http://example/",
1159
+ "idmap": {"@container": "@id", "@nest": "nestedidmap"},
1160
+ "nestedidmap": "@nest"
1161
+ },
1162
+ "nestedidmap": {
1163
+ "idmap": {
1164
+ "http://example.org/foo": {"label": "Object with @id <foo>"},
1165
+ "_:bar": {"label": "Object with @id _:bar"}
1166
+ }
1167
+ }
1168
+ }),
1169
+ output: %([{
1170
+ "http://example/idmap": [
1171
+ {"http://example/label": [{"@value": "Object with @id _:bar"}], "@id": "_:bar"},
1172
+ {"http://example/label": [{"@value": "Object with @id <foo>"}], "@id": "http://example.org/foo"}
1173
+ ]
1174
+ }])
1175
+ },
1176
+ "Nest term an invalid keyword" => {
1177
+ input: %({
1178
+ "@context": {
1179
+ "term": {"@id": "http://example/term", "@nest": "@id"}
1180
+ }
1181
+ }),
1182
+ exception: JSON::LD::JsonLdError::InvalidNestValue
1183
+ },
1184
+ "Nest in @reverse" => {
1185
+ input: %({
1186
+ "@context": {
1187
+ "term": {"@reverse": "http://example/term", "@nest": "@nest"}
1188
+ }
1189
+ }),
1190
+ exception: JSON::LD::JsonLdError::InvalidReverseProperty
1191
+ },
1192
+ "Raises InvalidTermDefinition if processingMode is not specified" => {
1193
+ input: %({
1194
+ "@context": {
1195
+ "@vocab": "http://example.org/",
1196
+ "list": {"@container": "@list", "@nest": "nestedlist"},
1197
+ "nestedlist": "@nest"
1198
+ },
1199
+ "nestedlist": {
1200
+ "list": ["a", "b"]
1201
+ }
1202
+ }),
1203
+ processingMode: nil,
1204
+ exception: JSON::LD::JsonLdError::InvalidTermDefinition
1205
+ },
1206
+ }.each do |title, params|
1207
+ it(title) {run_expand({processingMode: "json-ld-1.1"}.merge(params))}
1208
+ end
1209
+ end
1210
+
1211
+ context "scoped context" do
1212
+ {
1213
+ "adding new term" => {
1214
+ input: %({
1215
+ "@context": {
1216
+ "@vocab": "http://example/",
1217
+ "foo": {"@context": {"bar": "http://example.org/bar"}}
1218
+ },
1219
+ "foo": {
1220
+ "bar": "baz"
1221
+ }
1222
+ }),
1223
+ output: %([
1224
+ {
1225
+ "http://example/foo": [{"http://example.org/bar": [{"@value": "baz"}]}]
1226
+ }
1227
+ ])
1228
+ },
1229
+ "overriding a term" => {
1230
+ input: %({
1231
+ "@context": {
1232
+ "@vocab": "http://example/",
1233
+ "foo": {"@context": {"bar": {"@type": "@id"}}},
1234
+ "bar": {"@type": "http://www.w3.org/2001/XMLSchema#string"}
1235
+ },
1236
+ "foo": {
1237
+ "bar": "http://example/baz"
1238
+ }
1239
+ }),
1240
+ output: %([
1241
+ {
1242
+ "http://example/foo": [{"http://example/bar": [{"@id": "http://example/baz"}]}]
1243
+ }
1244
+ ])
1245
+ },
1246
+ "property and value with different terms mapping to the same expanded property" => {
1247
+ input: %({
1248
+ "@context": {
1249
+ "@vocab": "http://example/",
1250
+ "foo": {"@context": {"Bar": {"@id": "bar"}}}
1251
+ },
1252
+ "foo": {
1253
+ "Bar": "baz"
1254
+ }
1255
+ }),
1256
+ output: %([
1257
+ {
1258
+ "http://example/foo": [{
1259
+ "http://example/bar": [
1260
+ {"@value": "baz"}
1261
+ ]}
1262
+ ]
1263
+ }
1264
+ ])
1265
+ },
1266
+ "deep @context affects nested nodes" => {
1267
+ input: %({
1268
+ "@context": {
1269
+ "@vocab": "http://example/",
1270
+ "foo": {"@context": {"baz": {"@type": "@vocab"}}}
1271
+ },
1272
+ "foo": {
1273
+ "bar": {
1274
+ "baz": "buzz"
1275
+ }
1276
+ }
1277
+ }),
1278
+ output: %([
1279
+ {
1280
+ "http://example/foo": [{
1281
+ "http://example/bar": [{
1282
+ "http://example/baz": [{"@id": "http://example/buzz"}]
1283
+ }]
1284
+ }]
1285
+ }
1286
+ ])
1287
+ },
1288
+ "scoped context layers on intemediate contexts" => {
1289
+ input: %({
1290
+ "@context": {
1291
+ "@vocab": "http://example/",
1292
+ "b": {"@context": {"c": "http://example.org/c"}}
1293
+ },
1294
+ "a": {
1295
+ "@context": {"@vocab": "http://example.com/"},
1296
+ "b": {
1297
+ "a": "A in example.com",
1298
+ "c": "C in example.org"
1299
+ },
1300
+ "c": "C in example.com"
1301
+ },
1302
+ "c": "C in example"
1303
+ }),
1304
+ output: %([{
1305
+ "http://example/a": [{
1306
+ "http://example.com/c": [{"@value": "C in example.com"}],
1307
+ "http://example/b": [{
1308
+ "http://example.com/a": [{"@value": "A in example.com"}],
1309
+ "http://example.org/c": [{"@value": "C in example.org"}]
1310
+ }]
1311
+ }],
1312
+ "http://example/c": [{"@value": "C in example"}]
1313
+ }])
1314
+ },
1315
+ "Raises InvalidTermDefinition if processingMode is not specified" => {
1316
+ input: %({
1317
+ "@context": {
1318
+ "@vocab": "http://example/",
1319
+ "foo": {"@context": {"bar": "http://example.org/bar"}}
1320
+ },
1321
+ "foo": {
1322
+ "bar": "baz"
1323
+ }
1324
+ }),
1325
+ processingMode: nil,
1326
+ exception: JSON::LD::JsonLdError::InvalidTermDefinition
1327
+ },
1328
+ }.each do |title, params|
1329
+ it(title) {run_expand({processingMode: "json-ld-1.1"}.merge(params))}
1330
+ end
1331
+ end
1332
+
1333
+ context "scoped context on @type" do
1334
+ {
1335
+ "adding new term" => {
1336
+ input: %({
1337
+ "@context": {
1338
+ "@vocab": "http://example/",
1339
+ "Foo": {"@context": {"bar": "http://example.org/bar"}}
1340
+ },
1341
+ "a": {"@type": "Foo", "bar": "baz"}
1342
+ }),
1343
+ output: %([
1344
+ {
1345
+ "http://example/a": [{
1346
+ "@type": ["http://example/Foo"],
1347
+ "http://example.org/bar": [{"@value": "baz"}]
1348
+ }]
1349
+ }
1350
+ ])
1351
+ },
1352
+ "overriding a term" => {
1353
+ input: %({
1354
+ "@context": {
1355
+ "@vocab": "http://example/",
1356
+ "Foo": {"@context": {"bar": {"@type": "@id"}}},
1357
+ "bar": {"@type": "http://www.w3.org/2001/XMLSchema#string"}
1358
+ },
1359
+ "a": {"@type": "Foo", "bar": "http://example/baz"}
1360
+ }),
1361
+ output: %([
1362
+ {
1363
+ "http://example/a": [{
1364
+ "@type": ["http://example/Foo"],
1365
+ "http://example/bar": [{"@id": "http://example/baz"}]
1366
+ }]
1367
+ }
1368
+ ])
1369
+ },
1370
+ "alias of @type" => {
1371
+ input: %({
1372
+ "@context": {
1373
+ "@vocab": "http://example/",
1374
+ "type": "@type",
1375
+ "Foo": {"@context": {"bar": "http://example.org/bar"}}
1376
+ },
1377
+ "a": {"type": "Foo", "bar": "baz"}
1378
+ }),
1379
+ output: %([
1380
+ {
1381
+ "http://example/a": [{
1382
+ "@type": ["http://example/Foo"],
1383
+ "http://example.org/bar": [{"@value": "baz"}]
1384
+ }]
1385
+ }
1386
+ ])
1387
+ },
1388
+ "deep @context affects nested nodes" => {
1389
+ input: %({
1390
+ "@context": {
1391
+ "@vocab": "http://example/",
1392
+ "Foo": {"@context": {"baz": {"@type": "@vocab"}}}
1393
+ },
1394
+ "@type": "Foo",
1395
+ "bar": {"baz": "buzz"}
1396
+ }),
1397
+ output: %([
1398
+ {
1399
+ "@type": ["http://example/Foo"],
1400
+ "http://example/bar": [{
1401
+ "http://example/baz": [{"@id": "http://example/buzz"}]
1402
+ }]
1403
+ }
1404
+ ])
1405
+ },
1406
+ "scoped context layers on intemediate contexts" => {
1407
+ input: %({
1408
+ "@context": {
1409
+ "@vocab": "http://example/",
1410
+ "B": {"@context": {"c": "http://example.org/c"}}
1411
+ },
1412
+ "a": {
1413
+ "@context": {"@vocab": "http://example.com/"},
1414
+ "@type": "B",
1415
+ "a": "A in example.com",
1416
+ "c": "C in example.org"
1417
+ },
1418
+ "c": "C in example"
1419
+ }),
1420
+ output: %([{
1421
+ "http://example/a": [{
1422
+ "@type": ["http://example/B"],
1423
+ "http://example.com/a": [{"@value": "A in example.com"}],
1424
+ "http://example.org/c": [{"@value": "C in example.org"}]
1425
+ }],
1426
+ "http://example/c": [{"@value": "C in example"}]
1427
+ }])
1428
+ },
1429
+ "with @container: @type" => {
1430
+ input: %({
1431
+ "@context": {
1432
+ "@vocab": "http://example/",
1433
+ "typemap": {"@container": "@type"},
1434
+ "Type": {"@context": {"a": "http://example.org/a"}}
1435
+ },
1436
+ "typemap": {
1437
+ "Type": {"a": "Object with @type <Type>"}
1438
+ }
1439
+ }),
1440
+ output: %([{
1441
+ "http://example/typemap": [
1442
+ {"http://example.org/a": [{"@value": "Object with @type <Type>"}], "@type": ["http://example/Type"]}
1443
+ ]
1444
+ }])
1445
+ },
1446
+ "Raises InvalidTermDefinition if processingMode is not specified" => {
1447
+ input: %({
1448
+ "@context": {
1449
+ "@vocab": "http://example/",
1450
+ "Foo": {"@context": {"bar": "http://example.org/bar"}}
1451
+ },
1452
+ "a": {"@type": "Foo", "bar": "baz"}
1453
+ }),
1454
+ processingMode: nil,
1455
+ exception: JSON::LD::JsonLdError::InvalidTermDefinition
1456
+ },
1457
+ }.each do |title, params|
1458
+ it(title) {run_expand({processingMode: "json-ld-1.1"}.merge(params))}
676
1459
  end
677
1460
  end
678
1461
 
679
1462
  context "@reverse" do
680
1463
  {
1464
+ "@container: @reverse" => {
1465
+ input: %({
1466
+ "@context": {
1467
+ "@vocab": "http://example/",
1468
+ "rev": { "@reverse": "forward", "@type": "@id"}
1469
+ },
1470
+ "@id": "http://example/one",
1471
+ "rev": "http://example/two"
1472
+ }),
1473
+ output: %([{
1474
+ "@id": "http://example/one",
1475
+ "@reverse": {
1476
+ "http://example/forward": [
1477
+ {
1478
+ "@id": "http://example/two"
1479
+ }
1480
+ ]
1481
+ }
1482
+ }])
1483
+ },
681
1484
  "expand-0037" => {
682
- input: ::JSON.parse(%({
1485
+ input: %({
683
1486
  "@context": {
684
1487
  "name": "http://xmlns.com/foaf/0.1/name"
685
1488
  },
@@ -691,8 +1494,8 @@ describe JSON::LD::API do
691
1494
  "name": "Dave Longley"
692
1495
  }
693
1496
  }
694
- })),
695
- output: ::JSON.parse(%([
1497
+ }),
1498
+ output: %([
696
1499
  {
697
1500
  "@id": "http://example.com/people/markus",
698
1501
  "@reverse": {
@@ -713,10 +1516,10 @@ describe JSON::LD::API do
713
1516
  }
714
1517
  ]
715
1518
  }
716
- ]))
1519
+ ])
717
1520
  },
718
1521
  "expand-0043" => {
719
- input: ::JSON.parse(%({
1522
+ input: %({
720
1523
  "@context": {
721
1524
  "name": "http://xmlns.com/foaf/0.1/name",
722
1525
  "isKnownBy": { "@reverse": "http://xmlns.com/foaf/0.1/knows" }
@@ -735,8 +1538,8 @@ describe JSON::LD::API do
735
1538
  }
736
1539
  ]
737
1540
  }
738
- })),
739
- output: ::JSON.parse(%([
1541
+ }),
1542
+ output: %([
740
1543
  {
741
1544
  "@id": "http://example.com/people/markus",
742
1545
  "http://xmlns.com/foaf/0.1/knows": [
@@ -763,48 +1566,19 @@ describe JSON::LD::API do
763
1566
  }
764
1567
  ]
765
1568
  }
766
- ]))
1569
+ ])
767
1570
  },
768
- }.each do |title, params|
769
- it title do
770
- jld = JSON::LD::API.expand(params[:input], logger: logger)
771
- expect(jld).to produce(params[:output], logger)
772
- end
773
- end
774
- end
775
-
776
- context "@index" do
777
- {
778
- "string annotation" => {
779
- input: {
780
- "@context" => {
781
- "container" => {
782
- "@id" => "http://example.com/container",
783
- "@container" => "@index"
784
- }
785
- },
786
- "@id" => "http://example.com/annotationsTest",
787
- "container" => {
788
- "en" => "The Queen",
789
- "de" => [ "Die Königin", "Ihre Majestät" ]
790
- }
791
- },
792
- output: [
793
- {
794
- "@id" => "http://example.com/annotationsTest",
795
- "http://example.com/container" => [
796
- {"@value" => "Die Königin", "@index" => "de"},
797
- {"@value" => "Ihre Majestät", "@index" => "de"},
798
- {"@value" => "The Queen", "@index" => "en"}
799
- ]
1571
+ "@reverse object with an @id property" => {
1572
+ input: %({
1573
+ "@id": "http://example/foo",
1574
+ "@reverse": {
1575
+ "@id": "http://example/bar"
800
1576
  }
801
- ]
1577
+ }),
1578
+ exception: JSON::LD::JsonLdError::InvalidReversePropertyMap,
802
1579
  },
803
1580
  }.each do |title, params|
804
- it title do
805
- jld = JSON::LD::API.expand(params[:input], logger: logger)
806
- expect(jld).to produce(params[:output], logger)
807
- end
1581
+ it(title) {run_expand params}
808
1582
  end
809
1583
  end
810
1584
 
@@ -825,52 +1599,33 @@ describe JSON::LD::API do
825
1599
  },
826
1600
  exception: JSON::LD::JsonLdError::InvalidLanguageTaggedString
827
1601
  },
828
- "@list containing @list" => {
829
- input: {
830
- "http://example.com/foo" => {"@list" => [{"@list" => ["baz"]}]}
831
- },
832
- exception: JSON::LD::JsonLdError::ListOfLists
833
- },
834
- "@list containing @list (with coercion)" => {
835
- input: {
836
- "@context" => {"foo" => {"@id" => "http://example.com/foo", "@container" => "@list"}},
837
- "foo" => [{"@list" => ["baz"]}]
838
- },
839
- exception: JSON::LD::JsonLdError::ListOfLists
840
- },
841
- "coerced @list containing an array" => {
842
- input: {
843
- "@context" => {"foo" => {"@id" => "http://example.com/foo", "@container" => "@list"}},
844
- "foo" => [["baz"]]
845
- },
846
- exception: JSON::LD::JsonLdError::ListOfLists
847
- },
848
- "@reverse object with an @id property" => {
849
- input: JSON.parse(%({
850
- "@id": "http://example/foo",
851
- "@reverse": {
852
- "@id": "http://example/bar"
853
- }
854
- })),
855
- exception: JSON::LD::JsonLdError::InvalidReversePropertyMap,
856
- },
857
1602
  "colliding keywords" => {
858
- input: JSON.parse(%({
1603
+ input: %({
859
1604
  "@context": {
860
1605
  "id": "@id",
861
1606
  "ID": "@id"
862
1607
  },
863
1608
  "id": "http://example/foo",
864
1609
  "ID": "http://example/bar"
865
- })),
1610
+ }),
866
1611
  exception: JSON::LD::JsonLdError::CollidingKeywords,
867
1612
  }
868
1613
  }.each do |title, params|
869
- it title do
870
- #JSON::LD::API.expand(params[:input], logger: logger).should produce([], logger)
871
- expect {JSON::LD::API.expand(params[:input])}.to raise_error(params[:exception])
872
- end
1614
+ it(title) {run_expand params}
873
1615
  end
874
1616
  end
875
1617
  end
1618
+
1619
+ def run_expand(params)
1620
+ input, output, processingMode = params[:input], params[:output], params[:processingMode]
1621
+ input = ::JSON.parse(input) if input.is_a?(String)
1622
+ output = ::JSON.parse(output) if output.is_a?(String)
1623
+ pending params.fetch(:pending, "test implementation") unless input
1624
+ if params[:exception]
1625
+ expect {JSON::LD::API.expand(input, processingMode: processingMode)}.to raise_error(params[:exception])
1626
+ else
1627
+ jld = JSON::LD::API.expand(input, base: params[:base], logger: logger, processingMode: processingMode)
1628
+ expect(jld).to produce(output, logger)
1629
+ end
1630
+ end
876
1631
  end