json-ld 2.1.2 → 2.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.
@@ -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