json-ld 3.0.2 → 3.1.0

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/AUTHORS +1 -1
  3. data/README.md +90 -53
  4. data/UNLICENSE +1 -1
  5. data/VERSION +1 -1
  6. data/bin/jsonld +4 -4
  7. data/lib/json/ld.rb +27 -10
  8. data/lib/json/ld/api.rb +325 -96
  9. data/lib/json/ld/compact.rb +75 -27
  10. data/lib/json/ld/conneg.rb +188 -0
  11. data/lib/json/ld/context.rb +677 -292
  12. data/lib/json/ld/expand.rb +240 -75
  13. data/lib/json/ld/flatten.rb +5 -3
  14. data/lib/json/ld/format.rb +19 -19
  15. data/lib/json/ld/frame.rb +135 -85
  16. data/lib/json/ld/from_rdf.rb +44 -17
  17. data/lib/json/ld/html/nokogiri.rb +151 -0
  18. data/lib/json/ld/html/rexml.rb +186 -0
  19. data/lib/json/ld/reader.rb +25 -5
  20. data/lib/json/ld/resource.rb +2 -2
  21. data/lib/json/ld/streaming_writer.rb +3 -1
  22. data/lib/json/ld/to_rdf.rb +47 -17
  23. data/lib/json/ld/utils.rb +4 -2
  24. data/lib/json/ld/writer.rb +75 -14
  25. data/spec/api_spec.rb +13 -34
  26. data/spec/compact_spec.rb +968 -9
  27. data/spec/conneg_spec.rb +373 -0
  28. data/spec/context_spec.rb +447 -53
  29. data/spec/expand_spec.rb +1872 -416
  30. data/spec/flatten_spec.rb +434 -47
  31. data/spec/frame_spec.rb +979 -344
  32. data/spec/from_rdf_spec.rb +305 -5
  33. data/spec/spec_helper.rb +177 -0
  34. data/spec/streaming_writer_spec.rb +4 -4
  35. data/spec/suite_compact_spec.rb +2 -2
  36. data/spec/suite_expand_spec.rb +14 -2
  37. data/spec/suite_flatten_spec.rb +10 -2
  38. data/spec/suite_frame_spec.rb +3 -2
  39. data/spec/suite_from_rdf_spec.rb +2 -2
  40. data/spec/suite_helper.rb +55 -20
  41. data/spec/suite_html_spec.rb +22 -0
  42. data/spec/suite_http_spec.rb +35 -0
  43. data/spec/suite_remote_doc_spec.rb +2 -2
  44. data/spec/suite_to_rdf_spec.rb +14 -3
  45. data/spec/support/extensions.rb +5 -1
  46. data/spec/test-files/test-4-input.json +3 -3
  47. data/spec/test-files/test-5-input.json +2 -2
  48. data/spec/test-files/test-8-framed.json +14 -18
  49. data/spec/to_rdf_spec.rb +606 -16
  50. data/spec/writer_spec.rb +5 -5
  51. metadata +144 -88
@@ -6,7 +6,7 @@ describe JSON::LD::API do
6
6
 
7
7
  describe ".frame" do
8
8
  {
9
- "exact @type match" => {
9
+ "exact @type match": {
10
10
  frame: %({
11
11
  "@context": {"ex": "http://example.org/"},
12
12
  "@type": "ex:Type1"
@@ -30,7 +30,7 @@ describe JSON::LD::API do
30
30
  }]
31
31
  })
32
32
  },
33
- "wildcard @type match" => {
33
+ "wildcard @type match": {
34
34
  frame: %({
35
35
  "@context": {"ex": "http://example.org/"},
36
36
  "@type": {}
@@ -57,7 +57,7 @@ describe JSON::LD::API do
57
57
  }]
58
58
  })
59
59
  },
60
- "match none @type match" => {
60
+ "match none @type match": {
61
61
  frame: %({
62
62
  "@context": {"ex": "http://example.org/"},
63
63
  "@type": []
@@ -82,7 +82,7 @@ describe JSON::LD::API do
82
82
  }]
83
83
  })
84
84
  },
85
- "multiple matches on @type" => {
85
+ "multiple matches on @type": {
86
86
  frame: %({
87
87
  "@context": {"ex": "http://example.org/"},
88
88
  "@type": "ex:Type1"
@@ -114,7 +114,7 @@ describe JSON::LD::API do
114
114
  }]
115
115
  })
116
116
  },
117
- "single @id match" => {
117
+ "single @id match": {
118
118
  frame: %({
119
119
  "@context": {"ex": "http://example.org/"},
120
120
  "@id": "ex:Sub1"
@@ -138,7 +138,7 @@ describe JSON::LD::API do
138
138
  }]
139
139
  })
140
140
  },
141
- "multiple @id match" => {
141
+ "multiple @id match": {
142
142
  frame: %({
143
143
  "@context": {"ex": "http://example.org/"},
144
144
  "@id": ["ex:Sub1", "ex:Sub2"]
@@ -169,7 +169,7 @@ describe JSON::LD::API do
169
169
  }]
170
170
  })
171
171
  },
172
- "wildcard and match none" => {
172
+ "wildcard and match none": {
173
173
  frame: %({
174
174
  "@context": {"ex": "http://example.org/"},
175
175
  "ex:p": [],
@@ -196,7 +196,7 @@ describe JSON::LD::API do
196
196
  }]
197
197
  })
198
198
  },
199
- "match on any property if @requireAll is false" => {
199
+ "match on any property if @requireAll is false": {
200
200
  frame: %({
201
201
  "@context": {"ex": "http://example.org/"},
202
202
  "@requireAll": false,
@@ -227,7 +227,7 @@ describe JSON::LD::API do
227
227
  }]
228
228
  })
229
229
  },
230
- "match on defeaults if @requireAll is true and at least one property matches" => {
230
+ "match on defeaults if @requireAll is true and at least one property matches": {
231
231
  frame: %({
232
232
  "@context": {"ex": "http://example.org/"},
233
233
  "@requireAll": true,
@@ -271,7 +271,7 @@ describe JSON::LD::API do
271
271
  }]
272
272
  })
273
273
  },
274
- "match with @requireAll with one default" => {
274
+ "match with @requireAll with one default": {
275
275
  frame: %({
276
276
  "@context": {"ex": "http://example.org/"},
277
277
  "@requireAll": true,
@@ -307,7 +307,117 @@ describe JSON::LD::API do
307
307
  }]
308
308
  })
309
309
  },
310
- "implicitly includes unframed properties (default @explicit false)" => {
310
+ "don't match with @requireAll, matching @type but no matching property": {
311
+ frame: %({
312
+ "@context": {"ex": "http://example.org/"},
313
+ "@requireAll": true,
314
+ "@type": "ex:Type",
315
+ "ex:p": {}
316
+ }),
317
+ input: %([
318
+ {
319
+ "@context": {"ex": "http://example.org/"},
320
+ "@id": "ex:Sub1",
321
+ "@type": "ex:Type",
322
+ "ex:p": "foo"
323
+ }, {
324
+ "@context": { "ex":"http://example.org/"},
325
+ "@id": "ex:Sub2",
326
+ "@type": "ex:Type"
327
+ }, {
328
+ "@context": { "ex":"http://example.org/"},
329
+ "@id": "ex:Sub3",
330
+ "ex:p": "foo"
331
+ }
332
+ ]),
333
+ output: %({
334
+ "@context": {"ex": "http://example.org/"},
335
+ "@graph": [{
336
+ "@id": "ex:Sub1",
337
+ "@type": "ex:Type",
338
+ "ex:p": "foo"
339
+ }]
340
+ })
341
+ },
342
+ "don't match with @requireAll, matching @id but no matching @type": {
343
+ frame: %({
344
+ "@context": {"ex": "http://example.org/"},
345
+ "@requireAll": true,
346
+ "@id": ["ex:Sub1", "ex:Sub2"],
347
+ "@type": "ex:Type"
348
+ }),
349
+ input: %([
350
+ {
351
+ "@context": {"ex": "http://example.org/"},
352
+ "@id": "ex:Sub1",
353
+ "@type": "ex:Type",
354
+ "ex:p": "foo"
355
+ }, {
356
+ "@context": { "ex":"http://example.org/"},
357
+ "@id": "ex:Sub2",
358
+ "@type": "ex:OtherType"
359
+ }, {
360
+ "@context": { "ex":"http://example.org/"},
361
+ "@id": "ex:Sub3",
362
+ "@type": "ex:Type",
363
+ "ex:p": "foo"
364
+ }
365
+ ]),
366
+ output: %({
367
+ "@context": {"ex": "http://example.org/"},
368
+ "@graph": [{
369
+ "@id": "ex:Sub1",
370
+ "@type": "ex:Type",
371
+ "ex:p": "foo"
372
+ }]
373
+ })
374
+ },
375
+ "issue #40 - example": {
376
+ frame: %({
377
+ "@context": {
378
+ "@version": 1.1,
379
+ "@vocab": "https://schema.org/"
380
+ },
381
+ "@type": "Person",
382
+ "@requireAll": true,
383
+ "givenName": "John",
384
+ "familyName": "Doe"
385
+ }),
386
+ input: %({
387
+ "@context": {
388
+ "@version": 1.1,
389
+ "@vocab": "https://schema.org/"
390
+ },
391
+ "@graph": [
392
+ {
393
+ "@id": "1",
394
+ "@type": "Person",
395
+ "name": "John Doe",
396
+ "givenName": "John",
397
+ "familyName": "Doe"
398
+ },
399
+ {
400
+ "@id": "2",
401
+ "@type": "Person",
402
+ "name": "Jane Doe",
403
+ "givenName": "Jane"
404
+ }
405
+ ]
406
+ }),
407
+ output: %({
408
+ "@context": {
409
+ "@version": 1.1,
410
+ "@vocab": "https://schema.org/"
411
+ },
412
+ "@id": "1",
413
+ "@type": "Person",
414
+ "familyName": "Doe",
415
+ "givenName": "John",
416
+ "name": "John Doe"
417
+ }),
418
+ processingMode: 'json-ld-1.1'
419
+ },
420
+ "implicitly includes unframed properties (default @explicit false)": {
311
421
  frame: %({
312
422
  "@context": {"ex": "http://example.org/"},
313
423
  "@type": "ex:Type1"
@@ -329,7 +439,7 @@ describe JSON::LD::API do
329
439
  }]
330
440
  })
331
441
  },
332
- "explicitly includes unframed properties @explicit false" => {
442
+ "explicitly includes unframed properties @explicit false": {
333
443
  frame: %({
334
444
  "@context": {"ex": "http://example.org/"},
335
445
  "@explicit": false,
@@ -352,7 +462,7 @@ describe JSON::LD::API do
352
462
  }]
353
463
  })
354
464
  },
355
- "explicitly excludes unframed properties (@explicit: true)" => {
465
+ "explicitly excludes unframed properties (@explicit: true)": {
356
466
  frame: %({
357
467
  "@context": {"ex": "http://example.org/"},
358
468
  "@explicit": true,
@@ -373,7 +483,7 @@ describe JSON::LD::API do
373
483
  }]
374
484
  })
375
485
  },
376
- "non-existent framed properties create null property" => {
486
+ "non-existent framed properties create null property": {
377
487
  frame: %({
378
488
  "@context": {"ex": "http://example.org/"},
379
489
  "@type": "ex:Type1",
@@ -401,7 +511,7 @@ describe JSON::LD::API do
401
511
  }]
402
512
  })
403
513
  },
404
- "non-existent framed properties create default property" => {
514
+ "non-existent framed properties create default property": {
405
515
  frame: %({
406
516
  "@context": {
407
517
  "ex": "http://example.org/",
@@ -429,13 +539,32 @@ describe JSON::LD::API do
429
539
  "ex:prop2": {"@id": "ex:Obj1"},
430
540
  "ex:null": ["foo"]
431
541
  }]
432
- }
433
- )
542
+ })
543
+ },
544
+ "default value for @type": {
545
+ frame: %({
546
+ "@context": {"ex": "http://example.org/"},
547
+ "@type": {"@default": "ex:Foo"},
548
+ "ex:foo": "bar"
549
+ }),
550
+ input: %({
551
+ "@context": {"ex": "http://example.org/"},
552
+ "@id": "ex:Sub1",
553
+ "ex:foo": "bar"
554
+ }),
555
+ output: %({
556
+ "@context": {"ex": "http://example.org/"},
557
+ "@graph": [{
558
+ "@id": "ex:Sub1",
559
+ "@type": "ex:Foo",
560
+ "ex:foo": "bar"
561
+ }]
562
+ })
434
563
  },
435
- "mixed content" => {
564
+ "mixed content": {
436
565
  frame: %({
437
566
  "@context": {"ex": "http://example.org/"},
438
- "ex:mixed": {"@embed": false}
567
+ "ex:mixed": {"@embed": "@never"}
439
568
  }),
440
569
  input: %({
441
570
  "@context": {"ex": "http://example.org/"},
@@ -456,10 +585,10 @@ describe JSON::LD::API do
456
585
  }]
457
586
  })
458
587
  },
459
- "no embedding (@embed: false)" => {
588
+ "no embedding (@embed: @never)": {
460
589
  frame: %({
461
590
  "@context": {"ex": "http://example.org/"},
462
- "ex:embed": {"@embed": false}
591
+ "ex:embed": {"@embed": "@never"}
463
592
  }),
464
593
  input: %({
465
594
  "@context": {"ex": "http://example.org/"},
@@ -477,7 +606,58 @@ describe JSON::LD::API do
477
606
  }]
478
607
  })
479
608
  },
480
- "mixed list" => {
609
+ "first embed (@embed: @once)": {
610
+ frame: %({
611
+ "@context": {"ex": "http://www.example.com/#"},
612
+ "@type": "ex:Thing",
613
+ "@embed": "@once"
614
+ }),
615
+ input: %({
616
+ "@context": {"ex": "http://www.example.com/#"},
617
+ "@id": "http://example/outer",
618
+ "@type": "ex:Thing",
619
+ "ex:embed1": {"@id": "http://example/embedded", "ex:name": "Embedded"},
620
+ "ex:embed2": {"@id": "http://example/embedded", "ex:name": "Embedded"}
621
+ }),
622
+ output: %({
623
+ "@context": {"ex": "http://www.example.com/#"},
624
+ "@graph": [
625
+ {
626
+ "@id": "http://example/outer",
627
+ "@type": "ex:Thing",
628
+ "ex:embed1": {"@id": "http://example/embedded", "ex:name": "Embedded"},
629
+ "ex:embed2": {"@id": "http://example/embedded"}
630
+ }
631
+ ]
632
+ }),
633
+ ordered: true
634
+ },
635
+ "always embed (@embed: @always)": {
636
+ frame: %({
637
+ "@context": {"ex": "http://www.example.com/#"},
638
+ "@type": "ex:Thing",
639
+ "@embed": "@always"
640
+ }),
641
+ input: %({
642
+ "@context": {"ex": "http://www.example.com/#"},
643
+ "@id": "http://example/outer",
644
+ "@type": "ex:Thing",
645
+ "ex:embed1": {"@id": "http://example/embedded", "ex:name": "Embedded"},
646
+ "ex:embed2": {"@id": "http://example/embedded", "ex:name": "Embedded"}
647
+ }),
648
+ output: %({
649
+ "@context": {"ex": "http://www.example.com/#"},
650
+ "@graph": [
651
+ {
652
+ "@id": "http://example/outer",
653
+ "@type": "ex:Thing",
654
+ "ex:embed1": {"@id": "http://example/embedded", "ex:name": "Embedded"},
655
+ "ex:embed2": {"@id": "http://example/embedded", "ex:name": "Embedded"}
656
+ }
657
+ ]
658
+ })
659
+ },
660
+ "mixed list": {
481
661
  frame: %({
482
662
  "@context": {"ex": "http://example.org/"},
483
663
  "ex:mixedlist": {}
@@ -507,7 +687,7 @@ describe JSON::LD::API do
507
687
  }]
508
688
  })
509
689
  },
510
- "framed list" => {
690
+ "framed list": {
511
691
  frame: %({
512
692
  "@context": {
513
693
  "ex": "http://example.org/",
@@ -542,7 +722,7 @@ describe JSON::LD::API do
542
722
  }]
543
723
  })
544
724
  },
545
- "presentation example" => {
725
+ "presentation example": {
546
726
  frame: %({
547
727
  "@context": {
548
728
  "primaryTopic": {
@@ -589,7 +769,7 @@ describe JSON::LD::API do
589
769
  }]
590
770
  })
591
771
  },
592
- "microdata manifest" => {
772
+ "microdata manifest": {
593
773
  frame: %({
594
774
  "@context": {
595
775
  "xsd": "http://www.w3.org/2001/XMLSchema#",
@@ -668,7 +848,7 @@ describe JSON::LD::API do
668
848
  }),
669
849
  processingMode: 'json-ld-1.1'
670
850
  },
671
- "library" => {
851
+ "library": {
672
852
  frame: %({
673
853
  "@context": {
674
854
  "dc": "http://purl.org/dc/elements/1.1/",
@@ -737,7 +917,7 @@ describe JSON::LD::API do
737
917
 
738
918
  describe "@reverse" do
739
919
  {
740
- "embed matched frames with @reverse" => {
920
+ "embed matched frames with @reverse": {
741
921
  frame: %({
742
922
  "@context": {"ex": "http://example.org/"},
743
923
  "@type": "ex:Type1",
@@ -770,7 +950,7 @@ describe JSON::LD::API do
770
950
  }]
771
951
  })
772
952
  },
773
- "embed matched frames with reversed property" => {
953
+ "embed matched frames with reversed property": {
774
954
  frame: %({
775
955
  "@context": {
776
956
  "ex": "http://example.org/",
@@ -807,25 +987,212 @@ describe JSON::LD::API do
807
987
  },
808
988
  }.each do |title, params|
809
989
  it title do
810
- begin
811
- input, frame, output = params[:input], params[:frame], params[:output]
812
- input = ::JSON.parse(input) if input.is_a?(String)
813
- frame = ::JSON.parse(frame) if frame.is_a?(String)
814
- output = ::JSON.parse(output) if output.is_a?(String)
815
- jld = JSON::LD::API.frame(input, frame, logger: logger)
816
- expect(jld).to produce_jsonld(output, logger)
817
- rescue JSON::LD::JsonLdError => e
818
- fail("#{e.class}: #{e.message}\n" +
819
- "#{logger}\n" +
820
- "Backtrace:\n#{e.backtrace.join("\n")}")
821
- end
990
+ do_frame(params)
822
991
  end
823
992
  end
824
993
  end
825
994
 
995
+ context "@included" do
996
+ {
997
+ "Basic Included array": {
998
+ input: %([{
999
+ "http://example.org/prop": [{"@value": "value"}],
1000
+ "http://example.org/foo": [{"@value": "bar"}]
1001
+ }, {
1002
+ "http://example.org/prop": [{"@value": "value2"}],
1003
+ "http://example.org/foo": [{"@value": "bar"}]
1004
+ }]),
1005
+ frame: %({
1006
+ "@context": {
1007
+ "@version": 1.1,
1008
+ "@vocab": "http://example.org/",
1009
+ "included": {"@id": "@included", "@container": "@set"}
1010
+ },
1011
+ "@requireAll": true,
1012
+ "foo": "bar",
1013
+ "prop": "value",
1014
+ "@included": [{
1015
+ "@requireAll": true,
1016
+ "foo": "bar",
1017
+ "prop": "value2"
1018
+ }]
1019
+ }),
1020
+ output: %({
1021
+ "@context": {
1022
+ "@version": 1.1,
1023
+ "@vocab": "http://example.org/",
1024
+ "included": {"@id": "@included", "@container": "@set"}
1025
+ },
1026
+ "foo": "bar",
1027
+ "included": [{
1028
+ "foo": "bar",
1029
+ "prop": "value2"
1030
+ }],
1031
+ "prop": "value"
1032
+ })
1033
+ },
1034
+ "Basic Included object": {
1035
+ input: %([{
1036
+ "http://example.org/prop": [{"@value": "value"}],
1037
+ "http://example.org/foo": [{"@value": "bar"}]
1038
+ }, {
1039
+ "http://example.org/prop": [{"@value": "value2"}],
1040
+ "http://example.org/foo": [{"@value": "bar"}]
1041
+ }]),
1042
+ frame: %({
1043
+ "@context": {
1044
+ "@version": 1.1,
1045
+ "@vocab": "http://example.org/"
1046
+ },
1047
+ "@requireAll": true,
1048
+ "foo": "bar",
1049
+ "prop": "value",
1050
+ "@included": [{
1051
+ "@requireAll": true,
1052
+ "foo": "bar",
1053
+ "prop": "value2"
1054
+ }]
1055
+ }),
1056
+ output: %({
1057
+ "@context": {
1058
+ "@version": 1.1,
1059
+ "@vocab": "http://example.org/"
1060
+ },
1061
+ "foo": "bar",
1062
+ "prop": "value",
1063
+ "@included": {
1064
+ "prop": "value2",
1065
+ "foo": "bar"
1066
+ }
1067
+ })
1068
+ },
1069
+ "json.api example": {
1070
+ input: %([{
1071
+ "@id": "http://example.org/base/1",
1072
+ "@type": ["http://example.org/vocab#articles"],
1073
+ "http://example.org/vocab#title": [{"@value": "JSON:API paints my bikeshed!"}],
1074
+ "http://example.org/vocab#self": [{"@id": "http://example.com/articles/1"}],
1075
+ "http://example.org/vocab#author": [{
1076
+ "@id": "http://example.org/base/9",
1077
+ "@type": ["http://example.org/vocab#people"],
1078
+ "http://example.org/vocab#self": [{"@id": "http://example.com/articles/1/relationships/author"}],
1079
+ "http://example.org/vocab#related": [{"@id": "http://example.com/articles/1/author"}]
1080
+ }],
1081
+ "http://example.org/vocab#comments": [{
1082
+ "http://example.org/vocab#self": [{"@id": "http://example.com/articles/1/relationships/comments"}],
1083
+ "http://example.org/vocab#related": [{"@id": "http://example.com/articles/1/comments"}]
1084
+ }],
1085
+ "@included": [{
1086
+ "@id": "http://example.org/base/9",
1087
+ "@type": ["http://example.org/vocab#people"],
1088
+ "http://example.org/vocab#first-name": [{"@value": "Dan"}],
1089
+ "http://example.org/vocab#last-name": [{"@value": "Gebhardt"}],
1090
+ "http://example.org/vocab#twitter": [{"@value": "dgeb"}],
1091
+ "http://example.org/vocab#self": [{"@id": "http://example.com/people/9"}]
1092
+ }, {
1093
+ "@id": "http://example.org/base/5",
1094
+ "@type": ["http://example.org/vocab#comments"],
1095
+ "http://example.org/vocab#body": [{"@value": "First!"}],
1096
+ "http://example.org/vocab#author": [{
1097
+ "@id": "http://example.org/base/2",
1098
+ "@type": ["http://example.org/vocab#people"]
1099
+ }],
1100
+ "http://example.org/vocab#self": [{"@id": "http://example.com/comments/5"}]
1101
+ }, {
1102
+ "@id": "http://example.org/base/12",
1103
+ "@type": ["http://example.org/vocab#comments"],
1104
+ "http://example.org/vocab#body": [{"@value": "I like XML better"}],
1105
+ "http://example.org/vocab#author": [{
1106
+ "@id": "http://example.org/base/9",
1107
+ "@type": ["http://example.org/vocab#people"]
1108
+ }],
1109
+ "http://example.org/vocab#self": [{"@id": "http://example.com/comments/12"}]
1110
+ }]
1111
+ }]),
1112
+ frame: %({
1113
+ "@context": {
1114
+ "@version": 1.1,
1115
+ "@vocab": "http://example.org/vocab#",
1116
+ "@base": "http://example.org/base/",
1117
+ "id": "@id",
1118
+ "type": "@type",
1119
+ "data": "@nest",
1120
+ "attributes": "@nest",
1121
+ "links": "@nest",
1122
+ "relationships": "@nest",
1123
+ "included": "@included",
1124
+ "author": {"@type": "@id"},
1125
+ "self": {"@type": "@id"},
1126
+ "related": {"@type": "@id"},
1127
+ "comments": {"@context": {"data": null}}
1128
+ },
1129
+ "data": {"type": "articles"},
1130
+ "included": {
1131
+ "@requireAll": true,
1132
+ "type": ["comments", "people"],
1133
+ "self": {}
1134
+ }
1135
+ }),
1136
+ output: %({
1137
+ "@context": {
1138
+ "@version": 1.1,
1139
+ "@vocab": "http://example.org/vocab#",
1140
+ "@base": "http://example.org/base/",
1141
+ "id": "@id",
1142
+ "type": "@type",
1143
+ "data": "@nest",
1144
+ "attributes": "@nest",
1145
+ "links": "@nest",
1146
+ "relationships": "@nest",
1147
+ "included": "@included",
1148
+ "author": {"@type": "@id"},
1149
+ "self": {"@type": "@id"},
1150
+ "related": {"@type": "@id"},
1151
+ "comments": {"@context": {"data": null}}
1152
+ },
1153
+ "id": "1",
1154
+ "type": "articles",
1155
+ "title": "JSON:API paints my bikeshed!",
1156
+ "self": "http://example.com/articles/1",
1157
+ "author": "9",
1158
+ "comments": {
1159
+ "self": "http://example.com/articles/1/relationships/comments",
1160
+ "related": "http://example.com/articles/1/comments"
1161
+ },
1162
+ "included": [{
1163
+ "id": "5",
1164
+ "type": "comments",
1165
+ "body": "First!",
1166
+ "author": {"id": "2", "type": "people"},
1167
+ "self": "http://example.com/comments/5"
1168
+ }, {
1169
+ "id": "9",
1170
+ "type": "people",
1171
+ "first-name": "Dan",
1172
+ "last-name": "Gebhardt",
1173
+ "twitter": "dgeb",
1174
+ "self": [
1175
+ "http://example.com/people/9",
1176
+ "http://example.com/articles/1/relationships/author"
1177
+ ],
1178
+ "related": "http://example.com/articles/1/author"
1179
+ }, {
1180
+ "id": "12",
1181
+ "type": "comments",
1182
+ "body": "I like XML better",
1183
+ "author": "9",
1184
+ "self": "http://example.com/comments/12"
1185
+ }]
1186
+ }),
1187
+ },
1188
+ }.each do |title, params|
1189
+ it(title) {do_frame(params.merge(processingMode: 'json-ld-1.1'))}
1190
+ end
1191
+ end
1192
+
826
1193
  describe "node pattern" do
827
1194
  {
828
- "matches a deep node pattern" => {
1195
+ "matches a deep node pattern": {
829
1196
  frame: %({
830
1197
  "@context": {"ex": "http://example.org/"},
831
1198
  "ex:p": {
@@ -874,10 +1241,9 @@ describe JSON::LD::API do
874
1241
 
875
1242
  describe "value pattern" do
876
1243
  {
877
- "matches exact values" => {
1244
+ "matches exact values": {
878
1245
  frame: %({
879
1246
  "@context": {"ex": "http://example.org/"},
880
- "@id": "ex:Sub1",
881
1247
  "ex:p": "P",
882
1248
  "ex:q": {"@value": "Q", "@type": "ex:q"},
883
1249
  "ex:r": {"@value": "R", "@language": "r"}
@@ -899,10 +1265,9 @@ describe JSON::LD::API do
899
1265
  }]
900
1266
  })
901
1267
  },
902
- "matches wildcard @value" => {
1268
+ "matches wildcard @value": {
903
1269
  frame: %({
904
1270
  "@context": {"ex": "http://example.org/"},
905
- "@id": "ex:Sub1",
906
1271
  "ex:p": {"@value": {}},
907
1272
  "ex:q": {"@value": {}, "@type": "ex:q"},
908
1273
  "ex:r": {"@value": {}, "@language": "r"}
@@ -924,10 +1289,9 @@ describe JSON::LD::API do
924
1289
  }]
925
1290
  })
926
1291
  },
927
- "matches wildcard @type" => {
1292
+ "matches wildcard @type": {
928
1293
  frame: %({
929
1294
  "@context": {"ex": "http://example.org/"},
930
- "@id": "ex:Sub1",
931
1295
  "ex:q": {"@value": "Q", "@type": {}}
932
1296
  }),
933
1297
  input: %({
@@ -943,10 +1307,9 @@ describe JSON::LD::API do
943
1307
  }]
944
1308
  })
945
1309
  },
946
- "matches wildcard @language" => {
1310
+ "matches wildcard @language": {
947
1311
  frame: %({
948
1312
  "@context": {"ex": "http://example.org/"},
949
- "@id": "ex:Sub1",
950
1313
  "ex:r": {"@value": "R", "@language": {}}
951
1314
  }),
952
1315
  input: %({
@@ -962,10 +1325,9 @@ describe JSON::LD::API do
962
1325
  }]
963
1326
  })
964
1327
  },
965
- "match none @type" => {
1328
+ "match none @type": {
966
1329
  frame: %({
967
1330
  "@context": {"ex": "http://example.org/"},
968
- "@id": "ex:Sub1",
969
1331
  "ex:p": {"@value": {}, "@type": []},
970
1332
  "ex:q": {"@value": {}, "@type": "ex:q"},
971
1333
  "ex:r": {"@value": {}, "@language": "r"}
@@ -987,10 +1349,9 @@ describe JSON::LD::API do
987
1349
  }]
988
1350
  })
989
1351
  },
990
- "match none @language" => {
1352
+ "match none @language": {
991
1353
  frame: %({
992
1354
  "@context": {"ex": "http://example.org/"},
993
- "@id": "ex:Sub1",
994
1355
  "ex:p": {"@value": {}, "@language": []},
995
1356
  "ex:q": {"@value": {}, "@type": "ex:q"},
996
1357
  "ex:r": {"@value": {}, "@language": "r"}
@@ -1012,10 +1373,9 @@ describe JSON::LD::API do
1012
1373
  }]
1013
1374
  })
1014
1375
  },
1015
- "matches some @value" => {
1376
+ "matches some @value": {
1016
1377
  frame: %({
1017
1378
  "@context": {"ex": "http://example.org/"},
1018
- "@id": "ex:Sub1",
1019
1379
  "ex:p": {"@value": ["P", "Q", "R"]},
1020
1380
  "ex:q": {"@value": ["P", "Q", "R"], "@type": "ex:q"},
1021
1381
  "ex:r": {"@value": ["P", "Q", "R"], "@language": "r"}
@@ -1037,10 +1397,9 @@ describe JSON::LD::API do
1037
1397
  }]
1038
1398
  })
1039
1399
  },
1040
- "matches some @type" => {
1400
+ "matches some @type": {
1041
1401
  frame: %({
1042
1402
  "@context": {"ex": "http://example.org/"},
1043
- "@id": "ex:Sub1",
1044
1403
  "ex:q": {"@value": "Q", "@type": ["ex:q", "ex:Q"]}
1045
1404
  }),
1046
1405
  input: %({
@@ -1056,29 +1415,27 @@ describe JSON::LD::API do
1056
1415
  }]
1057
1416
  })
1058
1417
  },
1059
- "matches some @language" => {
1418
+ "matches some @language": {
1060
1419
  frame: %({
1061
1420
  "@context": {"ex": "http://example.org/"},
1062
- "@id": "ex:Sub1",
1063
1421
  "ex:r": {"@value": "R", "@language": ["p", "q", "r"]}
1064
1422
  }),
1065
1423
  input: %({
1066
1424
  "@context": {"ex": "http://example.org/"},
1067
1425
  "@id": "ex:Sub1",
1068
- "ex:r": {"@value": "R", "@language": "r"}
1426
+ "ex:r": {"@value": "R", "@language": "R"}
1069
1427
  }),
1070
1428
  output: %({
1071
1429
  "@context": {"ex": "http://example.org/"},
1072
1430
  "@graph": [{
1073
1431
  "@id": "ex:Sub1",
1074
- "ex:r": {"@value": "R", "@language": "r"}
1432
+ "ex:r": {"@value": "R", "@language": "R"}
1075
1433
  }]
1076
1434
  })
1077
1435
  },
1078
- "excludes non-matched values" => {
1436
+ "excludes non-matched values": {
1079
1437
  frame: %({
1080
1438
  "@context": {"ex": "http://example.org/"},
1081
- "@id": "ex:Sub1",
1082
1439
  "ex:p": {"@value": {}},
1083
1440
  "ex:q": {"@value": {}, "@type": "ex:q"},
1084
1441
  "ex:r": {"@value": {}, "@language": "R"}
@@ -1096,7 +1453,7 @@ describe JSON::LD::API do
1096
1453
  "@id": "ex:Sub1",
1097
1454
  "ex:p": "P",
1098
1455
  "ex:q": {"@value": "Q", "@type": "ex:q"},
1099
- "ex:r": {"@value": "R", "@language": "r"}
1456
+ "ex:r": {"@value": "R", "@language": "R"}
1100
1457
  }]
1101
1458
  })
1102
1459
  },
@@ -1109,7 +1466,7 @@ describe JSON::LD::API do
1109
1466
 
1110
1467
  describe "named graphs" do
1111
1468
  {
1112
- "Merge graphs if no outer @graph is used" => {
1469
+ "Merge graphs if no outer @graph is used": {
1113
1470
  frame: %({
1114
1471
  "@context": {"@vocab": "urn:"},
1115
1472
  "@type": "Class"
@@ -1133,7 +1490,7 @@ describe JSON::LD::API do
1133
1490
  }),
1134
1491
  processingMode: 'json-ld-1.1'
1135
1492
  },
1136
- "Frame default graph if outer @graph is used" => {
1493
+ "Frame default graph if outer @graph is used": {
1137
1494
  frame: %({
1138
1495
  "@context": {"@vocab": "urn:"},
1139
1496
  "@type": "Class",
@@ -1165,7 +1522,7 @@ describe JSON::LD::API do
1165
1522
  }),
1166
1523
  processingMode: 'json-ld-1.1'
1167
1524
  },
1168
- "Merge one graph and preserve another" => {
1525
+ "Merge one graph and preserve another": {
1169
1526
  frame: %({
1170
1527
  "@context": {"@vocab": "urn:"},
1171
1528
  "@type": "Class",
@@ -1210,7 +1567,7 @@ describe JSON::LD::API do
1210
1567
  }),
1211
1568
  processingMode: 'json-ld-1.1'
1212
1569
  },
1213
- "Merge one graph and deep preserve another" => {
1570
+ "Merge one graph and deep preserve another": {
1214
1571
  frame: %({
1215
1572
  "@context": {"@vocab": "urn:"},
1216
1573
  "@type": "Class",
@@ -1259,7 +1616,7 @@ describe JSON::LD::API do
1259
1616
  }),
1260
1617
  processingMode: 'json-ld-1.1'
1261
1618
  },
1262
- "library" => {
1619
+ "library": {
1263
1620
  frame: %({
1264
1621
  "@context": {"@vocab": "http://example.org/"},
1265
1622
  "@type": "Library",
@@ -1311,7 +1668,65 @@ describe JSON::LD::API do
1311
1668
  }
1312
1669
  }),
1313
1670
  processingMode: 'json-ld-1.1'
1314
- }
1671
+ },
1672
+ "named graph with @embed: @never": {
1673
+ input: %({
1674
+ "@id": "ex:cred",
1675
+ "ex:subject": {
1676
+ "@id": "ex:Subject",
1677
+ "ex:name": "the subject"
1678
+ },
1679
+ "ex:proof": {
1680
+ "@graph": {
1681
+ "@type": "ex:Proof",
1682
+ "ex:name": "the proof",
1683
+ "ex:signer": [{
1684
+ "@id": "ex:Subject",
1685
+ "ex:name": "something different"
1686
+ }]
1687
+ }
1688
+ }
1689
+ }),
1690
+ frame: %({
1691
+ "@context": {
1692
+ "@version": 1.1,
1693
+ "proof": {"@id": "ex:proof", "@container": "@graph"}
1694
+ },
1695
+ "@graph": {
1696
+ "proof": {"@embed": "@never"}
1697
+ }
1698
+ }),
1699
+ output: %({
1700
+ "@context": {
1701
+ "@version": 1.1,
1702
+ "proof": {
1703
+ "@id": "ex:proof",
1704
+ "@container": "@graph"
1705
+ }
1706
+ },
1707
+ "@id": "ex:cred",
1708
+ "ex:subject": {
1709
+ "@id": "ex:Subject",
1710
+ "ex:name": "the subject"
1711
+ },
1712
+ "proof": {
1713
+ "@included": [
1714
+ {
1715
+ "@type": "ex:Proof",
1716
+ "ex:name": "the proof",
1717
+ "ex:signer": {
1718
+ "@id": "ex:Subject"
1719
+ }
1720
+ },
1721
+ {
1722
+ "@id": "ex:Subject",
1723
+ "ex:name": "something different"
1724
+ }
1725
+ ]
1726
+ }
1727
+ }),
1728
+ processingMode: 'json-ld-1.1'
1729
+ },
1315
1730
  }.each do |title, params|
1316
1731
  it title do
1317
1732
  do_frame(params)
@@ -1321,11 +1736,11 @@ describe JSON::LD::API do
1321
1736
  end
1322
1737
 
1323
1738
  describe "prune blank nodes" do
1324
- it "preserves single-use bnode identifiers if @version 1.0" do
1325
- do_frame(
1326
- input: %({
1739
+ {
1740
+ "preserves single-use bnode identifiers if @version 1.0": {
1741
+ frame: %({
1327
1742
  "@context": {
1328
- "dc0": "http://purl.org/dc/terms/",
1743
+ "dc": "http://purl.org/dc/terms/",
1329
1744
  "dc:creator": {
1330
1745
  "@type": "@id"
1331
1746
  },
@@ -1334,11 +1749,9 @@ describe JSON::LD::API do
1334
1749
  },
1335
1750
  "@id": "http://example.com/asset",
1336
1751
  "@type": "ps:Asset",
1337
- "dc:creator": {
1338
- "foaf:name": "John Doe"
1339
- }
1752
+ "dc:creator": {}
1340
1753
  }),
1341
- frame: %({
1754
+ input: %({
1342
1755
  "@context": {
1343
1756
  "dc": "http://purl.org/dc/terms/",
1344
1757
  "dc:creator": {
@@ -1349,7 +1762,9 @@ describe JSON::LD::API do
1349
1762
  },
1350
1763
  "@id": "http://example.com/asset",
1351
1764
  "@type": "ps:Asset",
1352
- "dc:creator": {}
1765
+ "dc:creator": {
1766
+ "foaf:name": "John Doe"
1767
+ }
1353
1768
  }),
1354
1769
  output: %({
1355
1770
  "@context": {
@@ -1370,316 +1785,531 @@ describe JSON::LD::API do
1370
1785
  }
1371
1786
  }
1372
1787
  ]
1373
- })
1374
- )
1375
- end
1376
- end
1377
-
1378
- context "problem cases" do
1379
- it "pr #20" do
1380
- expanded = %([
1381
- {
1382
- "@id": "_:gregg",
1383
- "@type": "http://xmlns.com/foaf/0.1/Person",
1384
- "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg"
1385
- }, {
1386
- "@id": "http://manu.sporny.org/#me",
1387
- "@type": "http://xmlns.com/foaf/0.1/Person",
1388
- "http://xmlns.com/foaf/0.1/knows": {"@id": "_:gregg"},
1389
- "http://xmlns.com/foaf/0.1/name": "Manu Sporny"
1390
- }
1391
- ])
1392
- expected = %({
1393
- "@graph": [
1394
- {
1395
- "@id": "_:b0",
1396
- "@type": "http://xmlns.com/foaf/0.1/Person",
1397
- "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg"
1398
- },
1399
- {
1400
- "@id": "http://manu.sporny.org/#me",
1401
- "@type": "http://xmlns.com/foaf/0.1/Person",
1402
- "http://xmlns.com/foaf/0.1/knows": {
1403
- "@id": "_:b0",
1404
- "@type": "http://xmlns.com/foaf/0.1/Person",
1405
- "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg"
1788
+ }),
1789
+ processingMode: 'json-ld-1.0'
1790
+ },
1791
+ "preserves single-use bnode identifiers if pruneBlankNodeIdentifiers=false": {
1792
+ frame: %({
1793
+ "@context": {
1794
+ "dc": "http://purl.org/dc/terms/",
1795
+ "dc:creator": {
1796
+ "@type": "@id"
1406
1797
  },
1407
- "http://xmlns.com/foaf/0.1/name": "Manu Sporny"
1408
- }
1409
- ]
1410
- })
1411
- do_frame(input: expanded, frame: {}, output: expected)
1412
- end
1413
-
1414
- it "issue #28" do
1415
- input = %({
1416
- "@context": {
1417
- "rdfs": "http://www.w3.org/2000/01/rdf-schema#"
1418
- },
1419
- "@id": "http://www.myresource/uuid",
1420
- "http://www.myresource.com/ontology/1.0#talksAbout": [
1421
- {
1422
- "@id": "http://rdf.freebase.com/ns/m.018w8",
1423
- "rdfs:label": [
1424
- {
1425
- "@value": "Basketball",
1426
- "@language": "en"
1427
- }
1428
- ]
1429
- }
1430
- ]
1431
- })
1432
- frame = %({
1433
- "@context": {
1434
- "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
1435
- "talksAbout": {
1436
- "@id": "http://www.myresource.com/ontology/1.0#talksAbout",
1437
- "@type": "@id"
1798
+ "foaf": "http://xmlns.com/foaf/0.1/",
1799
+ "ps": "http://purl.org/payswarm#"
1438
1800
  },
1439
- "label": {
1440
- "@id": "rdfs:label",
1441
- "@language": "en"
1442
- }
1443
- },
1444
- "@id": "http://www.myresource/uuid"
1445
- })
1446
- expected = %({
1447
- "@context": {
1448
- "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
1449
- "talksAbout": {
1450
- "@id": "http://www.myresource.com/ontology/1.0#talksAbout",
1451
- "@type": "@id"
1801
+ "@id": "http://example.com/asset",
1802
+ "@type": "ps:Asset",
1803
+ "dc:creator": {}
1804
+ }),
1805
+ input: %({
1806
+ "@context": {
1807
+ "dc": "http://purl.org/dc/terms/",
1808
+ "dc:creator": {
1809
+ "@type": "@id"
1810
+ },
1811
+ "foaf": "http://xmlns.com/foaf/0.1/",
1812
+ "ps": "http://purl.org/payswarm#"
1452
1813
  },
1453
- "label": {
1454
- "@id": "rdfs:label",
1455
- "@language": "en"
1814
+ "@id": "http://example.com/asset",
1815
+ "@type": "ps:Asset",
1816
+ "dc:creator": {
1817
+ "foaf:name": "John Doe"
1456
1818
  }
1457
- },
1458
- "@graph": [
1459
- {
1460
- "@id": "http://www.myresource/uuid",
1461
- "talksAbout": {
1462
- "@id": "http://rdf.freebase.com/ns/m.018w8",
1463
- "label": "Basketball"
1819
+ }),
1820
+ output: %({
1821
+ "@context": {
1822
+ "dc": "http://purl.org/dc/terms/",
1823
+ "dc:creator": {
1824
+ "@type": "@id"
1825
+ },
1826
+ "foaf": "http://xmlns.com/foaf/0.1/",
1827
+ "ps": "http://purl.org/payswarm#"
1828
+ },
1829
+ "@graph": [
1830
+ {
1831
+ "@id": "http://example.com/asset",
1832
+ "@type": "ps:Asset",
1833
+ "dc:creator": {
1834
+ "@id": "_:b0",
1835
+ "foaf:name": "John Doe"
1836
+ }
1464
1837
  }
1465
- }
1466
- ]
1467
- })
1468
- do_frame(input: input, frame: frame, output: expected)
1469
- end
1470
-
1471
- it "framing with @version: 1.1 prunes identifiers" do
1472
- input = %({
1473
- "@context": {
1474
- "@version": 1.1,
1475
- "@vocab": "https://example.com#",
1476
- "ex": "http://example.org/",
1477
- "claim": {
1478
- "@id": "ex:claim",
1479
- "@container": "@graph"
1838
+ ]
1839
+ }),
1840
+ pruneBlankNodeIdentiers: false
1841
+ },
1842
+ "framing with @version: 1.1 prunes identifiers": {
1843
+ frame: %({
1844
+ "@context": {
1845
+ "@version": 1.1,
1846
+ "@vocab": "https://example.com#",
1847
+ "ex": "http://example.org/",
1848
+ "claim": {
1849
+ "@id": "ex:claim",
1850
+ "@container": "@graph"
1851
+ },
1852
+ "id": "@id"
1480
1853
  },
1481
- "id": "@id"
1482
- },
1483
- "claim": {
1484
- "id": "ex:1",
1485
- "test": "foo"
1486
- }
1487
- })
1488
- frame = %({
1489
- "@context": {
1490
- "@version": 1.1,
1491
- "@vocab": "https://example.com#",
1492
- "ex": "http://example.org/",
1493
- "claim": {
1494
- "@id": "ex:claim",
1495
- "@container": "@graph"
1854
+ "claim": {}
1855
+ }),
1856
+ input: %({
1857
+ "@context": {
1858
+ "@version": 1.1,
1859
+ "@vocab": "https://example.com#",
1860
+ "ex": "http://example.org/",
1861
+ "claim": {
1862
+ "@id": "ex:claim",
1863
+ "@container": "@graph"
1864
+ },
1865
+ "id": "@id"
1496
1866
  },
1497
- "id": "@id"
1498
- },
1499
- "claim": {}
1500
- })
1501
- expected = %({
1502
- "@context": {
1503
- "@version": 1.1,
1504
- "@vocab": "https://example.com#",
1505
- "ex": "http://example.org/",
1506
1867
  "claim": {
1507
- "@id": "ex:claim",
1508
- "@container": "@graph"
1868
+ "id": "ex:1",
1869
+ "test": "foo"
1870
+ }
1871
+ }),
1872
+ output: %({
1873
+ "@context": {
1874
+ "@version": 1.1,
1875
+ "@vocab": "https://example.com#",
1876
+ "ex": "http://example.org/",
1877
+ "claim": {
1878
+ "@id": "ex:claim",
1879
+ "@container": "@graph"
1880
+ },
1881
+ "id": "@id"
1509
1882
  },
1510
- "id": "@id"
1511
- },
1512
- "claim": {
1513
- "id": "ex:1",
1514
- "test": "foo"
1515
- }
1516
- })
1517
- do_frame(input: input, frame: frame, output: expected, processingMode: 'json-ld-1.1')
1883
+ "claim": {
1884
+ "id": "ex:1",
1885
+ "test": "foo"
1886
+ }
1887
+ }),
1888
+ processingMode: 'json-ld-1.1'
1889
+ }
1890
+ }.each do |title, params|
1891
+ it title do
1892
+ do_frame(params)
1893
+ end
1518
1894
  end
1895
+ end
1519
1896
 
1520
- it "PR #663" do
1521
- input = %({
1522
- "@context": {
1523
- "@vocab": "http://example.com/",
1524
- "loves": {
1525
- "@type": "@id"
1897
+ context "problem cases" do
1898
+ {
1899
+ "pr #20": {
1900
+ frame: %({}),
1901
+ input: %([
1902
+ {
1903
+ "@id": "_:gregg",
1904
+ "@type": "http://xmlns.com/foaf/0.1/Person",
1905
+ "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg"
1906
+ }, {
1907
+ "@id": "http://manu.sporny.org/#me",
1908
+ "@type": "http://xmlns.com/foaf/0.1/Person",
1909
+ "http://xmlns.com/foaf/0.1/knows": {"@id": "_:gregg"},
1910
+ "http://xmlns.com/foaf/0.1/name": "Manu Sporny"
1911
+ }
1912
+ ]),
1913
+ output: %({
1914
+ "@graph": [
1915
+ {
1916
+ "@id": "_:b0",
1917
+ "@type": "http://xmlns.com/foaf/0.1/Person",
1918
+ "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg"
1919
+ },
1920
+ {
1921
+ "@id": "http://manu.sporny.org/#me",
1922
+ "@type": "http://xmlns.com/foaf/0.1/Person",
1923
+ "http://xmlns.com/foaf/0.1/knows": {
1924
+ "@id": "_:b0",
1925
+ "@type": "http://xmlns.com/foaf/0.1/Person",
1926
+ "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg"
1927
+ },
1928
+ "http://xmlns.com/foaf/0.1/name": "Manu Sporny"
1929
+ }
1930
+ ]
1931
+ })
1932
+ },
1933
+ "issue #28": {
1934
+ frame: %({
1935
+ "@context": {
1936
+ "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
1937
+ "talksAbout": {
1938
+ "@id": "http://www.myresource.com/ontology/1.0#talksAbout",
1939
+ "@type": "@id"
1940
+ },
1941
+ "label": {
1942
+ "@id": "rdfs:label",
1943
+ "@language": "en"
1944
+ }
1526
1945
  },
1527
- "unionOf": {
1528
- "@type": "@id",
1529
- "@id": "owl:unionOf",
1530
- "@container": "@list"
1946
+ "@id": "http://www.myresource/uuid"
1947
+ }),
1948
+ input: %({
1949
+ "@context": {
1950
+ "rdfs": "http://www.w3.org/2000/01/rdf-schema#"
1531
1951
  },
1532
- "Class": "owl:Class"
1533
- },
1534
- "@graph": [
1535
- {
1952
+ "@id": "http://www.myresource/uuid",
1953
+ "http://www.myresource.com/ontology/1.0#talksAbout": [
1954
+ {
1955
+ "@id": "http://rdf.freebase.com/ns/m.018w8",
1956
+ "rdfs:label": [
1957
+ {
1958
+ "@value": "Basketball",
1959
+ "@language": "en"
1960
+ }
1961
+ ]
1962
+ }
1963
+ ]
1964
+ }),
1965
+ output: %({
1966
+ "@context": {
1967
+ "rdfs": "http://www.w3.org/2000/01/rdf-schema#",
1968
+ "talksAbout": {
1969
+ "@id": "http://www.myresource.com/ontology/1.0#talksAbout",
1970
+ "@type": "@id"
1971
+ },
1972
+ "label": {
1973
+ "@id": "rdfs:label",
1974
+ "@language": "en"
1975
+ }
1976
+ },
1977
+ "@graph": [
1978
+ {
1979
+ "@id": "http://www.myresource/uuid",
1980
+ "talksAbout": {
1981
+ "@id": "http://rdf.freebase.com/ns/m.018w8",
1982
+ "label": "Basketball"
1983
+ }
1984
+ }
1985
+ ]
1986
+ })
1987
+ },
1988
+ "PR #663 - Multiple named graphs": {
1989
+ frame: %({
1990
+ "@context": {
1991
+ "@vocab": "http://example.com/",
1992
+ "loves": {"@type": "@id"},
1993
+ "unionOf": {
1994
+ "@type": "@id",
1995
+ "@id": "owl:unionOf",
1996
+ "@container": "@list"
1997
+ },
1998
+ "Class": "owl:Class"
1999
+ },
2000
+ "@graph": [
2001
+ {
2002
+ "@explicit": false,
2003
+ "@embed": "@once",
2004
+ "@type": ["Act", "Class"],
2005
+ "@graph": [{
2006
+ "@explicit": true,
2007
+ "@embed": "@always",
2008
+ "@type": "Person",
2009
+ "@id": {},
2010
+ "loves": {"@embed": "@never"}
2011
+ }]
2012
+ }
2013
+ ]
2014
+ }),
2015
+ input: %({
2016
+ "@context": {
2017
+ "@vocab": "http://example.com/",
2018
+ "loves": {"@type": "@id"},
2019
+ "unionOf": {
2020
+ "@type": "@id",
2021
+ "@id": "owl:unionOf",
2022
+ "@container": "@list"
2023
+ },
2024
+ "Class": "owl:Class"
2025
+ },
2026
+ "@graph": [{
1536
2027
  "@type": "Act",
1537
2028
  "@graph": [
1538
- {
1539
- "@id": "Romeo",
1540
- "@type": "Person"
1541
- },
1542
- {
1543
- "@id": "Juliet",
1544
- "@type": "Person"
1545
- }
2029
+ {"@id": "Romeo", "@type": "Person"},
2030
+ {"@id": "Juliet", "@type": "Person"}
1546
2031
  ]
1547
- },
1548
- {
2032
+ }, {
1549
2033
  "@id": "ActTwo",
1550
2034
  "@type": "Act",
1551
2035
  "@graph": [
1552
- {
1553
- "@id": "Romeo",
1554
- "@type": "Person",
1555
- "loves": "Juliet"
1556
- },
1557
- {
1558
- "@id": "Juliet",
1559
- "@type": "Person",
1560
- "loves": "Romeo"
1561
- }
2036
+ {"@id": "Romeo", "@type": "Person", "loves": "Juliet"},
2037
+ {"@id": "Juliet", "@type": "Person", "loves": "Romeo"}
1562
2038
  ]
1563
- },
1564
- {
2039
+ }, {
1565
2040
  "@id": "Person",
1566
2041
  "@type": "Class",
1567
2042
  "unionOf": {
1568
2043
  "@list": [
1569
- {
1570
- "@id": "Montague",
1571
- "@type": "Class"
1572
- },
1573
- {
1574
- "@id": "Capulet",
1575
- "@type": "Class"
1576
- }
2044
+ {"@id": "Montague", "@type": "Class"},
2045
+ {"@id": "Capulet", "@type": "Class"}
1577
2046
  ]
1578
2047
  }
1579
- }
1580
- ]
1581
- })
1582
- frame = %({
1583
- "@context": {
1584
- "@vocab": "http://example.com/",
1585
- "loves": {
1586
- "@type": "@id"
1587
- },
1588
- "unionOf": {
1589
- "@type": "@id",
1590
- "@id": "owl:unionOf",
1591
- "@container": "@list"
1592
- },
1593
- "Class": "owl:Class"
1594
- },
1595
- "@graph": [
1596
- {
1597
- "@explicit": false,
1598
- "@embed": "@last",
1599
- "@type": [
1600
- "Act",
1601
- "Class"
1602
- ],
1603
- "@graph": [{
1604
- "@explicit": true,
1605
- "@embed": "@always",
1606
- "@type": "Person",
1607
- "@id": {},
1608
- "loves": {"@embed": "@never"}
1609
- }]
1610
- }
1611
- ]
1612
- })
1613
- expected = %({
1614
- "@context": {
1615
- "@vocab": "http://example.com/",
1616
- "loves": {
1617
- "@type": "@id"
1618
- },
1619
- "unionOf": {
1620
- "@type": "@id",
1621
- "@id": "owl:unionOf",
1622
- "@container": "@list"
2048
+ }]
2049
+ }),
2050
+ output: %({
2051
+ "@context": {
2052
+ "@vocab": "http://example.com/",
2053
+ "loves": {"@type": "@id"},
2054
+ "unionOf": {
2055
+ "@type": "@id",
2056
+ "@id": "owl:unionOf",
2057
+ "@container": "@list"
2058
+ },
2059
+ "Class": "owl:Class"
1623
2060
  },
1624
- "Class": "owl:Class"
1625
- },
1626
- "@graph": [
1627
- {
1628
- "@graph": [
1629
- {
1630
- "@id": "Juliet",
1631
- "@type": "Person",
1632
- "loves": "Romeo"
1633
- },
1634
- {
1635
- "@id": "Romeo",
1636
- "@type": "Person",
1637
- "loves": "Juliet"
1638
- }
1639
- ],
2061
+ "@graph": [{
1640
2062
  "@id": "ActTwo",
1641
- "@type": "Act"
1642
- },
1643
- {
2063
+ "@type": "Act",
2064
+ "@graph": [
2065
+ {"@id": "Juliet", "@type": "Person", "loves": "Romeo"},
2066
+ {"@id": "Romeo", "@type": "Person", "loves": "Juliet"}
2067
+ ]
2068
+ }, {
1644
2069
  "@id": "Capulet",
1645
2070
  "@type": "Class"
1646
- },
1647
- {
2071
+ }, {
1648
2072
  "@id": "Montague",
1649
2073
  "@type": "Class"
1650
- },
1651
- {
2074
+ }, {
1652
2075
  "@id": "Person",
1653
2076
  "@type": "Class",
1654
2077
  "unionOf": [
1655
- {
1656
- "@id": "Montague",
1657
- "@type": "Class"
1658
- },
1659
- {
1660
- "@id": "Capulet",
1661
- "@type": "Class"
1662
- }
2078
+ {"@id": "Montague", "@type": "Class"},
2079
+ {"@id": "Capulet", "@type": "Class"}
1663
2080
  ]
1664
- },
1665
- {
2081
+ }, {
2082
+ "@type": "Act",
1666
2083
  "@graph": [
1667
2084
  {
1668
2085
  "@id": "Juliet",
1669
2086
  "@type": "Person",
1670
2087
  "loves": null
1671
- },
1672
- {
2088
+ }, {
1673
2089
  "@id": "Romeo",
1674
2090
  "@type": "Person",
1675
2091
  "loves": null
1676
2092
  }
1677
- ],
1678
- "@type": "Act"
2093
+ ]
2094
+ }]
2095
+ }),
2096
+ processingMode: 'json-ld-1.1'
2097
+ },
2098
+ "w3c/json-ld-framing#5": {
2099
+ frame: %({
2100
+ "@context" : {
2101
+ "@vocab" : "http://purl.bdrc.io/ontology/core/",
2102
+ "taxSubclassOf" : {
2103
+ "@id" : "http://purl.bdrc.io/ontology/core/taxSubclassOf",
2104
+ "@type" : "@id"
2105
+ },
2106
+ "bdr" : "http://purl.bdrc.io/resource/",
2107
+ "children": { "@reverse": "http://purl.bdrc.io/ontology/core/taxSubclassOf" }
2108
+ },
2109
+ "@id" : "bdr:O9TAXTBRC201605",
2110
+ "children": {
2111
+ "children": {
2112
+ "children": {}
2113
+ }
2114
+ }
2115
+ }),
2116
+ input: %({
2117
+ "@context": {
2118
+ "@vocab": "http://purl.bdrc.io/ontology/core/",
2119
+ "taxSubclassOf": {
2120
+ "@id": "http://purl.bdrc.io/ontology/core/taxSubclassOf",
2121
+ "@type": "@id"
2122
+ },
2123
+ "bdr": "http://purl.bdrc.io/resource/"
2124
+ },
2125
+ "@graph": [{
2126
+ "@id": "bdr:O9TAXTBRC201605",
2127
+ "@type": "Taxonomy"
2128
+ }, {
2129
+ "@id": "bdr:O9TAXTBRC201605_0001",
2130
+ "@type": "Taxonomy",
2131
+ "taxSubclassOf": "bdr:O9TAXTBRC201605"
2132
+ }, {
2133
+ "@id": "bdr:O9TAXTBRC201605_0002",
2134
+ "@type": "Taxonomy",
2135
+ "taxSubclassOf": "bdr:O9TAXTBRC201605_0001"
2136
+ }, {
2137
+ "@id": "bdr:O9TAXTBRC201605_0010",
2138
+ "@type": "Taxonomy",
2139
+ "taxSubclassOf": "bdr:O9TAXTBRC201605"
2140
+ }]
2141
+ }),
2142
+ output: %({
2143
+ "@context" : {
2144
+ "@vocab" : "http://purl.bdrc.io/ontology/core/",
2145
+ "taxSubclassOf" : {
2146
+ "@id" : "http://purl.bdrc.io/ontology/core/taxSubclassOf",
2147
+ "@type" : "@id"
2148
+ },
2149
+ "bdr" : "http://purl.bdrc.io/resource/",
2150
+ "children": { "@reverse": "http://purl.bdrc.io/ontology/core/taxSubclassOf" }
2151
+ },
2152
+ "@id" : "bdr:O9TAXTBRC201605",
2153
+ "@type": "Taxonomy",
2154
+ "children": [{
2155
+ "@id": "bdr:O9TAXTBRC201605_0001",
2156
+ "@type": "Taxonomy",
2157
+ "taxSubclassOf": "bdr:O9TAXTBRC201605",
2158
+ "children": {
2159
+ "@id": "bdr:O9TAXTBRC201605_0002",
2160
+ "@type": "Taxonomy",
2161
+ "taxSubclassOf": "bdr:O9TAXTBRC201605_0001"
2162
+ }
2163
+ }, {
2164
+ "@id": "bdr:O9TAXTBRC201605_0010",
2165
+ "@type": "Taxonomy",
2166
+ "taxSubclassOf": "bdr:O9TAXTBRC201605"
2167
+ }]
2168
+ }),
2169
+ processingMode: 'json-ld-1.1'
2170
+ },
2171
+ "issue json-ld-framing#30": {
2172
+ input: %({
2173
+ "@context": {"eg": "https://example.org/ns/"},
2174
+ "@id": "https://example.org/what",
2175
+ "eg:sameAs": "https://example.org/what",
2176
+ "eg:age": 42
2177
+ }),
2178
+ frame: %({
2179
+ "@context": {"eg": "https://example.org/ns/"},
2180
+ "@id": "https://example.org/what"
2181
+ }),
2182
+ output: %({
2183
+ "@context": {"eg": "https://example.org/ns/"},
2184
+ "@graph": [{
2185
+ "@id": "https://example.org/what",
2186
+ "eg:age": 42,
2187
+ "eg:sameAs": "https://example.org/what"
2188
+ }]
2189
+ })
2190
+ },
2191
+ "issue json-ld-framing#64": {
2192
+ input: %({
2193
+ "@context": {
2194
+ "@version": 1.1,
2195
+ "@vocab": "http://example.org/vocab#"
2196
+ },
2197
+ "@id": "http://example.org/1",
2198
+ "@type": "HumanMadeObject",
2199
+ "produced_by": {
2200
+ "@type": "Production",
2201
+ "_label": "Top Production",
2202
+ "part": {
2203
+ "@type": "Production",
2204
+ "_label": "Test Part"
2205
+ }
1679
2206
  }
1680
- ]
1681
- })
1682
- do_frame(input: input, frame: frame, output: expected, processingMode: 'json-ld-1.1')
2207
+ }),
2208
+ frame: %({
2209
+ "@context": {
2210
+ "@version": 1.1,
2211
+ "@vocab": "http://example.org/vocab#",
2212
+ "Production": {
2213
+ "@context": {
2214
+ "part": {
2215
+ "@type": "@id",
2216
+ "@container": "@set"
2217
+ }
2218
+ }
2219
+ }
2220
+ },
2221
+ "@id": "http://example.org/1"
2222
+ }),
2223
+ output: %({
2224
+ "@context": {
2225
+ "@version": 1.1,
2226
+ "@vocab": "http://example.org/vocab#",
2227
+ "Production": {
2228
+ "@context": {
2229
+ "part": {
2230
+ "@type": "@id",
2231
+ "@container": "@set"
2232
+ }
2233
+ }
2234
+ }
2235
+ },
2236
+ "@id": "http://example.org/1",
2237
+ "@type": "HumanMadeObject",
2238
+ "produced_by": {
2239
+ "@type": "Production",
2240
+ "part": [{
2241
+ "@type": "Production",
2242
+ "_label": "Test Part"
2243
+ }],
2244
+ "_label": "Top Production"
2245
+ }
2246
+ }),
2247
+ processingMode: "json-ld-1.1"
2248
+ },
2249
+ "issue json-ld-framing#27": {
2250
+ input: %({
2251
+ "@id": "ex:cred",
2252
+ "ex:subject": {
2253
+ "@id": "ex:Subject",
2254
+ "ex:name": "the subject",
2255
+ "ex:knows": {
2256
+ "@id": "ex:issuer",
2257
+ "ex:name": "Someone else"
2258
+ }
2259
+ },
2260
+ "ex:proof": {
2261
+ "@graph": {
2262
+ "@type": "ex:Proof",
2263
+ "ex:name": "the proof",
2264
+ "ex:signer": [{
2265
+ "@id": "ex:Subject",
2266
+ "ex:name": "something different"
2267
+ }]
2268
+ }
2269
+ }
2270
+ }),
2271
+ frame: %({
2272
+ "@context": {
2273
+ "@version": 1.1,
2274
+ "proof": {"@id": "ex:proof", "@container": "@graph"}
2275
+ },
2276
+ "@graph": {
2277
+ "subject": {},
2278
+ "proof": {}
2279
+ }
2280
+ }),
2281
+ output: %({
2282
+ "@context": {
2283
+ "@version": 1.1,
2284
+ "proof": {
2285
+ "@id": "ex:proof",
2286
+ "@container": "@graph"
2287
+ }
2288
+ },
2289
+ "@id": "ex:cred",
2290
+ "ex:subject": {
2291
+ "@id": "ex:Subject",
2292
+ "ex:name": "the subject",
2293
+ "ex:knows": {
2294
+ "@id": "ex:issuer",
2295
+ "ex:name": "Someone else"
2296
+ }
2297
+ },
2298
+ "proof": {
2299
+ "@type": "ex:Proof",
2300
+ "ex:name": "the proof",
2301
+ "ex:signer": {
2302
+ "@id": "ex:Subject",
2303
+ "ex:name": "something different"
2304
+ }
2305
+ }
2306
+ }),
2307
+ processingMode: "json-ld-1.1"
2308
+ }
2309
+ }.each do |title, params|
2310
+ it title do
2311
+ do_frame(params)
2312
+ end
1683
2313
  end
1684
2314
  end
1685
2315
 
@@ -1689,7 +2319,12 @@ describe JSON::LD::API do
1689
2319
  input = ::JSON.parse(input) if input.is_a?(String)
1690
2320
  frame = ::JSON.parse(frame) if frame.is_a?(String)
1691
2321
  output = ::JSON.parse(output) if output.is_a?(String)
1692
- jld = JSON::LD::API.frame(input, frame, logger: logger, processingMode: processingMode)
2322
+ jld = nil
2323
+ if params[:write]
2324
+ expect{jld = JSON::LD::API.frame(input, frame, logger: logger, processingMode: processingMode)}.to write(params[:write]).to(:error)
2325
+ else
2326
+ expect{jld = JSON::LD::API.frame(input, frame, logger: logger, processingMode: processingMode)}.not_to write.to(:error)
2327
+ end
1693
2328
  expect(jld).to produce_jsonld(output, logger)
1694
2329
 
1695
2330
  # Compare expanded jld/output too to make sure list values remain ordered