json-ld 2.2.1 → 3.0.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.
@@ -55,12 +55,14 @@ describe JSON::LD::Context do
55
55
  context "remote" do
56
56
 
57
57
  it "retrieves and parses a remote context document" do
58
+ JSON::LD::Context::PRELOADED.clear
58
59
  expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(remote_doc)
59
60
  ec = subject.parse("http://example.com/context")
60
61
  expect(ec.provided_context).to produce("http://example.com/context", logger)
61
62
  end
62
63
 
63
64
  it "fails given a missing remote @context" do
65
+ JSON::LD::Context::PRELOADED.clear
64
66
  expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/context", anything).and_raise(IOError)
65
67
  expect {subject.parse("http://example.com/context")}.to raise_error(JSON::LD::JsonLdError::LoadingRemoteContextFailed, %r{http://example.com/context})
66
68
  end
@@ -81,6 +83,7 @@ describe JSON::LD::Context do
81
83
  end
82
84
 
83
85
  it "parses a referenced context at a relative URI" do
86
+ JSON::LD::Context::PRELOADED.clear
84
87
  rd1 = JSON::LD::API::RemoteDocument.new("http://example.com/c1", %({"@context": "context"}))
85
88
  expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/c1", anything).and_yield(rd1)
86
89
  expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(remote_doc)
@@ -95,6 +98,7 @@ describe JSON::LD::Context do
95
98
 
96
99
  context "remote with local mappings" do
97
100
  let(:ctx) {["http://example.com/context", {"integer" => "xsd:integer"}]}
101
+ before {JSON::LD::Context::PRELOADED.clear}
98
102
  it "retrieves and parses a remote context document" do
99
103
  expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(remote_doc)
100
104
  subject.parse(ctx)
@@ -375,16 +379,6 @@ describe JSON::LD::Context do
375
379
  end
376
380
 
377
381
  describe "#processingMode" do
378
- it "sets to json-ld-1.0 if not specified" do
379
- [
380
- %({}),
381
- %([{}]),
382
- ].each do |str|
383
- ctx = JSON::LD::Context.parse(::JSON.parse(str))
384
- expect(ctx.processingMode).to eql "json-ld-1.0"
385
- end
386
- end
387
-
388
382
  it "sets to json-ld-1.1 if @version: 1.1" do
389
383
  [
390
384
  %({"@version": 1.1}),
@@ -410,8 +404,8 @@ describe JSON::LD::Context do
410
404
  expect {JSON::LD::Context.parse({"@version" => 1.1}, processingMode: "json-ld-1.0")}.to raise_error(JSON::LD::JsonLdError::ProcessingModeConflict)
411
405
  end
412
406
 
413
- it "raises ProcessingModeConflict nested context is different from starting context" do
414
- expect {JSON::LD::Context.parse([{}, {"@version" => 1.1}])}.to raise_error(JSON::LD::JsonLdError::ProcessingModeConflict)
407
+ it "does not raise ProcessingModeConflict nested context is different from starting context" do
408
+ expect {JSON::LD::Context.parse([{}, {"@version" => 1.1}])}.not_to raise_error
415
409
  end
416
410
  end
417
411
 
@@ -436,6 +430,7 @@ describe JSON::LD::Context do
436
430
  end
437
431
 
438
432
  describe "#serialize" do
433
+ before {JSON::LD::Context::PRELOADED.clear}
439
434
  it "context document" do
440
435
  expect(JSON::LD::API).to receive(:documentLoader).with("http://example.com/context", anything).and_yield(remote_doc)
441
436
  ec = subject.parse("http://example.com/context")
@@ -764,7 +759,7 @@ describe JSON::LD::Context do
764
759
  describe "#expand_iri" do
765
760
  subject {
766
761
  context.parse({
767
- '@base' => 'http://base/',
762
+ '@base' => 'http://base/base',
768
763
  '@vocab' => 'http://vocab/',
769
764
  'ex' => 'http://example.org/',
770
765
  '' => 'http://empty/',
@@ -794,6 +789,8 @@ describe JSON::LD::Context do
794
789
  "keyword" => ["@type", "@type"],
795
790
  "empty" => [":suffix", RDF::URI("http://empty/suffix")],
796
791
  "unmapped" => ["foo", RDF::URI("foo")],
792
+ "relative" => ["foo/bar", RDF::URI("foo/bar")],
793
+ "dotseg" => ["../foo/bar", RDF::URI("../foo/bar")],
797
794
  "empty term" => ["", RDF::URI("")],
798
795
  "another abs IRI"=>["ex://foo", RDF::URI("ex://foo")],
799
796
  "absolute IRI looking like a curie" =>
@@ -815,7 +812,9 @@ describe JSON::LD::Context do
815
812
  "keyword" => ["@type", "@type"],
816
813
  "empty" => [":suffix", RDF::URI("http://empty/suffix")],
817
814
  "unmapped" => ["foo", RDF::URI("http://base/foo")],
818
- "empty term" => ["", RDF::URI("http://base/")],
815
+ "relative" => ["foo/bar", RDF::URI("http://base/foo/bar")],
816
+ "dotseg" => ["../foo/bar", RDF::URI("http://base/foo/bar")],
817
+ "empty term" => ["", RDF::URI("http://base/base")],
819
818
  "another abs IRI"=>["ex://foo", RDF::URI("ex://foo")],
820
819
  "absolute IRI looking like a curie" =>
821
820
  ["foo:bar", RDF::URI("foo:bar")],
@@ -836,6 +835,8 @@ describe JSON::LD::Context do
836
835
  "keyword" => ["@type", "@type"],
837
836
  "empty" => [":suffix", RDF::URI("http://empty/suffix")],
838
837
  "unmapped" => ["foo", RDF::URI("http://vocab/foo")],
838
+ "relative" => ["foo/bar", RDF::URI("http://vocab/foo/bar")],
839
+ "dotseg" => ["../foo/bar", RDF::URI("http://vocab/../foo/bar")],
839
840
  "empty term" => ["", RDF::URI("http://empty/")],
840
841
  "another abs IRI"=>["ex://foo", RDF::URI("ex://foo")],
841
842
  "absolute IRI looking like a curie" =>
@@ -847,6 +848,39 @@ describe JSON::LD::Context do
847
848
  expect(subject.expand_iri(input, vocab: true)).to produce(result, logger)
848
849
  end
849
850
  end
851
+
852
+ context "set to ''" do
853
+ subject {
854
+ context.parse({
855
+ '@base' => 'http://base/base',
856
+ '@vocab' => '',
857
+ 'ex' => 'http://example.org/',
858
+ '' => 'http://empty/',
859
+ '_' => 'http://underscore/'
860
+ })
861
+ }
862
+
863
+ {
864
+ "absolute IRI" => ["http://example.org/", RDF::URI("http://example.org/")],
865
+ "term" => ["ex", RDF::URI("http://example.org/")],
866
+ "prefix:suffix" => ["ex:suffix", RDF::URI("http://example.org/suffix")],
867
+ "keyword" => ["@type", "@type"],
868
+ "empty" => [":suffix", RDF::URI("http://empty/suffix")],
869
+ "unmapped" => ["foo", RDF::URI("http://base/basefoo")],
870
+ "relative" => ["foo/bar", RDF::URI("http://base/basefoo/bar")],
871
+ "dotseg" => ["../foo/bar", RDF::URI("http://base/base../foo/bar")],
872
+ "empty term" => ["", RDF::URI("http://empty/")],
873
+ "another abs IRI"=>["ex://foo", RDF::URI("ex://foo")],
874
+ "absolute IRI looking like a curie" =>
875
+ ["foo:bar", RDF::URI("foo:bar")],
876
+ "bnode" => ["_:t0", RDF::Node("t0")],
877
+ "_" => ["_", RDF::URI("http://underscore/")],
878
+ }.each do |title, (input, result)|
879
+ it title do
880
+ expect(subject.expand_iri(input, vocab: true)).to produce(result, logger)
881
+ end
882
+ end
883
+ end
850
884
  end
851
885
  end
852
886
  end
@@ -926,6 +960,28 @@ describe JSON::LD::Context do
926
960
  expect(subject.compact_iri("http://example.org/name", position: :predicate)).
927
961
  not_to produce("name", logger)
928
962
  end
963
+
964
+ context "with @vocab: relative" do
965
+ before(:each) {
966
+ subject.vocab = ""
967
+ subject.base = 'http://base/base'
968
+ }
969
+
970
+ {
971
+ "absolute IRI" => ["http://example.com/", "http://example.com/"],
972
+ "prefix:suffix" => ["ex:suffix", "http://example.org/suffix"],
973
+ "keyword" => ["@type", "@type"],
974
+ "empty" => [":suffix", "http://empty/suffix"],
975
+ "unmapped" => ["foo", "foo"],
976
+ "bnode" => ["_:a", RDF::Node("a")],
977
+ "relative" => ["foo/bar", "http://base/foo/bar"],
978
+ "odd CURIE" => ["experts", "http://example.org/perts"]
979
+ }.each do |title, (result, input)|
980
+ it title do
981
+ expect(subject.compact_iri(input, vocab: true)).to produce(result, logger)
982
+ end
983
+ end
984
+ end
929
985
  end
930
986
 
931
987
  context "with value" do
@@ -939,47 +995,57 @@ describe JSON::LD::Context do
939
995
  "double" => {"@id" => "http://example.com/double", "@type" => "xsd:double"},
940
996
  "date" => {"@id" => "http://example.com/date", "@type" => "xsd:date"},
941
997
  "id" => {"@id" => "http://example.com/id", "@type" => "@id"},
942
- "listplain" => {"@id" => "http://example.com/plain", "@container" => "@list"},
943
- "listlang" => {"@id" => "http://example.com/lang", "@language" => "en", "@container" => "@list"},
944
- "listbool" => {"@id" => "http://example.com/bool", "@type" => "xsd:boolean", "@container" => "@list"},
945
- "listinteger" => {"@id" => "http://example.com/integer", "@type" => "xsd:integer", "@container" => "@list"},
946
- "listdouble" => {"@id" => "http://example.com/double", "@type" => "xsd:double", "@container" => "@list"},
947
- "listdate" => {"@id" => "http://example.com/date", "@type" => "xsd:date", "@container" => "@list"},
948
- "listid" => {"@id" => "http://example.com/id", "@type" => "@id", "@container" => "@list"},
949
- "setlang" => {"@id" => "http://example.com/lang", "@language" => "en", "@container" => "@set"},
950
- "setbool" => {"@id" => "http://example.com/bool", "@type" => "xsd:boolean", "@container" => "@set"},
951
- "setinteger" => {"@id" => "http://example.com/integer", "@type" => "xsd:integer", "@container" => "@set"},
952
- "setdouble" => {"@id" => "http://example.com/double", "@type" => "xsd:double", "@container" => "@set"},
953
- "setdate" => {"@id" => "http://example.com/date", "@type" => "xsd:date", "@container" => "@set"},
954
- "setid" => {"@id" => "http://example.com/id", "@type" => "@id", "@container" => "@set"},
955
- 'setgraph' => {'@id' => 'http://example.com/graph', '@container' => ['@graph', '@set']},
956
- "langmap" => {"@id" => "http://example.com/langmap", "@container" => "@language"},
998
+ 'graph' => {'@id' => 'http://example.com/graph', '@container' => '@graph'},
999
+
1000
+ "list_plain" => {"@id" => "http://example.com/plain", "@container" => "@list"},
1001
+ "list_lang" => {"@id" => "http://example.com/lang", "@language" => "en", "@container" => "@list"},
1002
+ "list_bool" => {"@id" => "http://example.com/bool", "@type" => "xsd:boolean", "@container" => "@list"},
1003
+ "list_integer" => {"@id" => "http://example.com/integer", "@type" => "xsd:integer", "@container" => "@list"},
1004
+ "list_double" => {"@id" => "http://example.com/double", "@type" => "xsd:double", "@container" => "@list"},
1005
+ "list_date" => {"@id" => "http://example.com/date", "@type" => "xsd:date", "@container" => "@list"},
1006
+ "list_id" => {"@id" => "http://example.com/id", "@type" => "@id", "@container" => "@list"},
1007
+ "list_graph" => {"@id" => "http://example.com/graph", "@type" => "@id", "@container" => "@list"},
1008
+
1009
+ "set_plain" => {"@id" => "http://example.com/plain", "@container" => "@set"},
1010
+ "set_lang" => {"@id" => "http://example.com/lang", "@language" => "en", "@container" => "@set"},
1011
+ "set_bool" => {"@id" => "http://example.com/bool", "@type" => "xsd:boolean", "@container" => "@set"},
1012
+ "set_integer" => {"@id" => "http://example.com/integer", "@type" => "xsd:integer", "@container" => "@set"},
1013
+ "set_double" => {"@id" => "http://example.com/double", "@type" => "xsd:double", "@container" => "@set"},
1014
+ "set_date" => {"@id" => "http://example.com/date", "@type" => "xsd:date", "@container" => "@set"},
1015
+ "set_id" => {"@id" => "http://example.com/id", "@type" => "@id", "@container" => "@set"},
1016
+ 'set_graph' => {'@id' => 'http://example.com/graph', '@container' => ['@graph', '@set']},
1017
+
1018
+ "map_lang" => {"@id" => "http://example.com/lang", "@container" => "@language"},
1019
+
1020
+ "set_map_lang" => {"@id" => "http://example.com/lang", "@container" => ["@language", "@set"]},
957
1021
  })
958
1022
  logger.clear
959
1023
  c
960
1024
  end
961
1025
 
1026
+ # Prefered sets and maps over non sets or maps
962
1027
  {
963
- "plain" => [{"@value" => "foo"}],
964
- "langmap" => [{"@value" => "en", "@language" => "en"}],
965
- "setbool" => [{"@value" => "true", "@type" => "http://www.w3.org/2001/XMLSchema#boolean"}],
966
- "setinteger" => [{"@value" => "1", "@type" => "http://www.w3.org/2001/XMLSchema#integer"}],
967
- "setid" => [{"@id" => "http://example.org/id"}],
968
- "setgraph" => [{"@graph" => [{"@id" => "http://example.org/id"}]}],
1028
+ "set_plain" => [{"@value" => "foo"}],
1029
+ "map_lang" => [{"@value" => "en", "@language" => "en"}],
1030
+ "set_bool" => [{"@value" => "true", "@type" => "http://www.w3.org/2001/XMLSchema#boolean"}],
1031
+ "set_integer" => [{"@value" => "1", "@type" => "http://www.w3.org/2001/XMLSchema#integer"}],
1032
+ "set_id" => [{"@id" => "http://example.org/id"}],
1033
+ "graph" => [{"@graph" => [{"@id" => "http://example.org/id"}]}],
969
1034
  }.each do |prop, values|
970
1035
  context "uses #{prop}" do
971
1036
  values.each do |value|
972
1037
  it "for #{value.inspect}" do
973
- expect(ctx.compact_iri("http://example.com/#{prop.sub('set', '')}", value: value, vocab: true)).
1038
+ expect(ctx.compact_iri("http://example.com/#{prop.sub(/^\w+_/, '')}", value: value, vocab: true)).
974
1039
  to produce(prop, logger)
975
1040
  end
976
1041
  end
977
1042
  end
978
1043
  end
979
1044
 
1045
+ # @language and @type with @list
980
1046
  context "for @list" do
981
1047
  {
982
- "listplain" => [
1048
+ "list_plain" => [
983
1049
  [{"@value" => "foo"}],
984
1050
  [{"@value" => "foo"}, {"@value" => "bar"}, {"@value" => "baz"}],
985
1051
  [{"@value" => "foo"}, {"@value" => "bar"}, {"@value" => 1}],
@@ -990,16 +1056,16 @@ describe JSON::LD::Context do
990
1056
  [{"@value" => true}], [{"@value" => false}],
991
1057
  [{"@value" => 1}], [{"@value" => 1.1}],
992
1058
  ],
993
- "listlang" => [[{"@value" => "en", "@language" => "en"}]],
994
- "listbool" => [[{"@value" => "true", "@type" => RDF::XSD.boolean.to_s}]],
995
- "listinteger" => [[{"@value" => "1", "@type" => RDF::XSD.integer.to_s}]],
996
- "listdouble" => [[{"@value" => "1", "@type" => RDF::XSD.double.to_s}]],
997
- "listdate" => [[{"@value" => "2012-04-17", "@type" => RDF::XSD.date.to_s}]],
1059
+ "list_lang" => [[{"@value" => "en", "@language" => "en"}]],
1060
+ "list_bool" => [[{"@value" => "true", "@type" => RDF::XSD.boolean.to_s}]],
1061
+ "list_integer" => [[{"@value" => "1", "@type" => RDF::XSD.integer.to_s}]],
1062
+ "list_double" => [[{"@value" => "1", "@type" => RDF::XSD.double.to_s}]],
1063
+ "list_date" => [[{"@value" => "2012-04-17", "@type" => RDF::XSD.date.to_s}]],
998
1064
  }.each do |prop, values|
999
1065
  context "uses #{prop}" do
1000
1066
  values.each do |value|
1001
1067
  it "for #{{"@list" => value}.inspect}" do
1002
- expect(ctx.compact_iri("http://example.com/#{prop.sub('list', '')}", value: {"@list" => value}, vocab: true)).
1068
+ expect(ctx.compact_iri("http://example.com/#{prop.sub(/^\w+_/, '')}", value: {"@list" => value}, vocab: true)).
1003
1069
  to produce(prop, logger)
1004
1070
  end
1005
1071
  end
@@ -141,6 +141,141 @@ describe JSON::LD::API do
141
141
  end
142
142
  end
143
143
 
144
+ context "with relative property IRIs" do
145
+ {
146
+ "base": {
147
+ input: %({
148
+ "http://a/b": "foo"
149
+ }),
150
+ output: %([{
151
+ "http://a/b": [{"@value": "foo"}]
152
+ }])
153
+ },
154
+ "relative": {
155
+ input: %({
156
+ "a/b": "foo"
157
+ }),
158
+ output: %([])
159
+ },
160
+ "hash": {
161
+ input: %({
162
+ "#a": "foo"
163
+ }),
164
+ output: %([])
165
+ },
166
+ "dotseg": {
167
+ input: %({
168
+ "../a": "foo"
169
+ }),
170
+ output: %([])
171
+ },
172
+ }.each do |title, params|
173
+ it(title) {run_expand params.merge(base: "http://example.org/")}
174
+ end
175
+
176
+ context "with @vocab" do
177
+ {
178
+ "base": {
179
+ input: %({
180
+ "@context": {"@vocab": "http://vocab/"},
181
+ "http://a/b": "foo"
182
+ }),
183
+ output: %([{
184
+ "http://a/b": [{"@value": "foo"}]
185
+ }])
186
+ },
187
+ "relative": {
188
+ input: %({
189
+ "@context": {"@vocab": "http://vocab/"},
190
+ "a/b": "foo"
191
+ }),
192
+ output: %([{
193
+ "http://vocab/a/b": [{"@value": "foo"}]
194
+ }])
195
+ },
196
+ "hash": {
197
+ input: %({
198
+ "@context": {"@vocab": "http://vocab/"},
199
+ "#a": "foo"
200
+ }),
201
+ output: %([{
202
+ "http://vocab/#a": [{"@value": "foo"}]
203
+ }])
204
+ },
205
+ "dotseg": {
206
+ input: %({
207
+ "@context": {"@vocab": "http://vocab/"},
208
+ "../a": "foo"
209
+ }),
210
+ output: %([{
211
+ "http://vocab/../a": [{"@value": "foo"}]
212
+ }])
213
+ },
214
+ }.each do |title, params|
215
+ it(title) {run_expand params.merge(base: "http://example.org/")}
216
+ end
217
+ end
218
+
219
+ context "with @vocab: ''" do
220
+ {
221
+ "base": {
222
+ input: %({
223
+ "@context": {"@vocab": ""},
224
+ "http://a/b": "foo"
225
+ }),
226
+ output: %([{
227
+ "http://a/b": [{"@value": "foo"}]
228
+ }])
229
+ },
230
+ "relative": {
231
+ input: %({
232
+ "@context": {"@vocab": ""},
233
+ "a/b": "foo"
234
+ }),
235
+ output: %([{
236
+ "http://example.org/a/b": [{"@value": "foo"}]
237
+ }])
238
+ },
239
+ "hash": {
240
+ input: %({
241
+ "@context": {"@vocab": ""},
242
+ "#a": "foo"
243
+ }),
244
+ output: %([{
245
+ "http://example.org/#a": [{"@value": "foo"}]
246
+ }])
247
+ },
248
+ "dotseg": {
249
+ input: %({
250
+ "@context": {"@vocab": ""},
251
+ "../a": "foo"
252
+ }),
253
+ output: %([{
254
+ "http://example.org/../a": [{"@value": "foo"}]
255
+ }])
256
+ },
257
+ "example": {
258
+ input: %({
259
+ "@context": {
260
+ "@base": "http://example/document",
261
+ "@vocab": ""
262
+ },
263
+ "@id": "http://example.org/places#BrewEats",
264
+ "@type": "#Restaurant",
265
+ "#name": "Brew Eats"
266
+ }),
267
+ output: %([{
268
+ "@id": "http://example.org/places#BrewEats",
269
+ "@type": ["http://example/document#Restaurant"],
270
+ "http://example/document#name": [{"@value": "Brew Eats"}]
271
+ }])
272
+ }
273
+ }.each do |title, params|
274
+ it(title) {run_expand params.merge(base: "http://example.org/")}
275
+ end
276
+ end
277
+ end
278
+
144
279
  context "keyword aliasing" do
145
280
  {
146
281
  "@id": {
@@ -671,24 +806,98 @@ describe JSON::LD::API do
671
806
  ])
672
807
  },
673
808
  "@list containing @list" => {
674
- input: {
675
- "http://example.com/foo" => {"@list" => [{"@list" => ["baz"]}]}
676
- },
677
- exception: JSON::LD::JsonLdError::ListOfLists
809
+ input: %({
810
+ "http://example.com/foo": {"@list": [{"@list": ["baz"]}]}
811
+ }),
812
+ output: %([{
813
+ "http://example.com/foo": [{"@list": [{"@list": [{"@value": "baz"}]}]}]
814
+ }])
815
+ },
816
+ "@list containing empty @list" => {
817
+ input: %({
818
+ "http://example.com/foo": {"@list": [{"@list": []}]}
819
+ }),
820
+ output: %([{
821
+ "http://example.com/foo": [{"@list": [{"@list": []}]}]
822
+ }])
678
823
  },
679
824
  "@list containing @list (with coercion)" => {
680
- input: {
681
- "@context" => {"foo" => {"@id" => "http://example.com/foo", "@container" => "@list"}},
682
- "foo" => [{"@list" => ["baz"]}]
683
- },
684
- exception: JSON::LD::JsonLdError::ListOfLists
825
+ input: %({
826
+ "@context": {"foo": {"@id": "http://example.com/foo", "@container": "@list"}},
827
+ "foo": [{"@list": ["baz"]}]
828
+ }),
829
+ output: %([{
830
+ "http://example.com/foo": [{"@list": [{"@list": [{"@value": "baz"}]}]}]
831
+ }])
832
+ },
833
+ "@list containing empty @list (with coercion)" => {
834
+ input: %({
835
+ "@context": {"foo": {"@id": "http://example.com/foo", "@container": "@list"}},
836
+ "foo": [{"@list": []}]
837
+ }),
838
+ output: %([{
839
+ "http://example.com/foo": [{"@list": [{"@list": []}]}]
840
+ }])
685
841
  },
686
842
  "coerced @list containing an array" => {
687
- input: {
688
- "@context" => {"foo" => {"@id" => "http://example.com/foo", "@container" => "@list"}},
689
- "foo" => [["baz"]]
690
- },
691
- exception: JSON::LD::JsonLdError::ListOfLists
843
+ input: %({
844
+ "@context": {"foo": {"@id": "http://example.com/foo", "@container": "@list"}},
845
+ "foo": [["baz"]]
846
+ }),
847
+ output: %([{
848
+ "http://example.com/foo": [{"@list": [{"@list": [{"@value": "baz"}]}]}]
849
+ }])
850
+ },
851
+ "coerced @list containing an empty array" => {
852
+ input: %({
853
+ "@context": {"foo": {"@id": "http://example.com/foo", "@container": "@list"}},
854
+ "foo": [[]]
855
+ }),
856
+ output: %([{
857
+ "http://example.com/foo": [{"@list": [{"@list": []}]}]
858
+ }])
859
+ },
860
+ "coerced @list containing deep arrays" => {
861
+ input: %({
862
+ "@context": {"foo": {"@id": "http://example.com/foo", "@container": "@list"}},
863
+ "foo": [[["baz"]]]
864
+ }),
865
+ output: %([{
866
+ "http://example.com/foo": [{"@list": [{"@list": [{"@list": [{"@value": "baz"}]}]}]}]
867
+ }])
868
+ },
869
+ "coerced @list containing deep empty arrays" => {
870
+ input: %({
871
+ "@context": {"foo": {"@id": "http://example.com/foo", "@container": "@list"}},
872
+ "foo": [[[]]]
873
+ }),
874
+ output: %([{
875
+ "http://example.com/foo": [{"@list": [{"@list": [{"@list": []}]}]}]
876
+ }]),
877
+ },
878
+ "coerced @list containing multiple lists" => {
879
+ input: %({
880
+ "@context": {"foo": {"@id": "http://example.com/foo", "@container": "@list"}},
881
+ "foo": [["a"], ["b"]]
882
+ }),
883
+ output: %([{
884
+ "http://example.com/foo": [{"@list": [
885
+ {"@list": [{"@value": "a"}]},
886
+ {"@list": [{"@value": "b"}]}
887
+ ]}]
888
+ }])
889
+ },
890
+ "coerced @list containing mixed list values" => {
891
+ input: %({
892
+ "@context": {"foo": {"@id": "http://example.com/foo", "@container": "@list"}},
893
+ "foo": [["a"], "b"]
894
+ }),
895
+ output: %([{
896
+ "http://example.com/foo": [{"@list": [
897
+ {"@list": [{"@value": "a"}]},
898
+ {"@value": "b"}
899
+ ]}]
900
+ }])
692
901
  },
693
902
  }.each do |title, params|
694
903
  it(title) {run_expand params}
@@ -796,6 +1005,63 @@ describe JSON::LD::API do
796
1005
  }
797
1006
  ]
798
1007
  },
1008
+ "simple map with @none" => {
1009
+ input: {
1010
+ "@context" => {
1011
+ "vocab" => "http://example.com/vocab/",
1012
+ "label" => {
1013
+ "@id" => "vocab:label",
1014
+ "@container" => "@language"
1015
+ }
1016
+ },
1017
+ "@id" => "http://example.com/queen",
1018
+ "label" => {
1019
+ "en" => "The Queen",
1020
+ "de" => [ "Die Königin", "Ihre Majestät" ],
1021
+ "@none" => "The Queen"
1022
+ }
1023
+ },
1024
+ output: [
1025
+ {
1026
+ "@id" => "http://example.com/queen",
1027
+ "http://example.com/vocab/label" => [
1028
+ {"@value" => "The Queen"},
1029
+ {"@value" => "Die Königin", "@language" => "de"},
1030
+ {"@value" => "Ihre Majestät", "@language" => "de"},
1031
+ {"@value" => "The Queen", "@language" => "en"},
1032
+ ]
1033
+ }
1034
+ ]
1035
+ },
1036
+ "simple map with alias of @none" => {
1037
+ input: {
1038
+ "@context" => {
1039
+ "vocab" => "http://example.com/vocab/",
1040
+ "label" => {
1041
+ "@id" => "vocab:label",
1042
+ "@container" => "@language"
1043
+ },
1044
+ "none" => "@none"
1045
+ },
1046
+ "@id" => "http://example.com/queen",
1047
+ "label" => {
1048
+ "en" => "The Queen",
1049
+ "de" => [ "Die Königin", "Ihre Majestät" ],
1050
+ "none" => "The Queen"
1051
+ }
1052
+ },
1053
+ output: [
1054
+ {
1055
+ "@id" => "http://example.com/queen",
1056
+ "http://example.com/vocab/label" => [
1057
+ {"@value" => "Die Königin", "@language" => "de"},
1058
+ {"@value" => "Ihre Majestät", "@language" => "de"},
1059
+ {"@value" => "The Queen", "@language" => "en"},
1060
+ {"@value" => "The Queen"},
1061
+ ]
1062
+ }
1063
+ ]
1064
+ },
799
1065
  "expand-0035" => {
800
1066
  input: {
801
1067
  "@context" => {
@@ -902,6 +1168,25 @@ describe JSON::LD::API do
902
1168
  processingMode: nil,
903
1169
  exception: JSON::LD::JsonLdError::InvalidContainerMapping
904
1170
  },
1171
+ "Does not add @id if it is @none, or expands to @none": {
1172
+ input: %({
1173
+ "@context": {
1174
+ "@vocab": "http://example/",
1175
+ "idmap": {"@container": "@id"},
1176
+ "none": "@none"
1177
+ },
1178
+ "idmap": {
1179
+ "@none": {"label": "Object with no @id"},
1180
+ "none": {"label": "Another object with no @id"}
1181
+ }
1182
+ }),
1183
+ output: %([{
1184
+ "http://example/idmap": [
1185
+ {"http://example/label": [{"@value": "Object with no @id"}]},
1186
+ {"http://example/label": [{"@value": "Another object with no @id"}]}
1187
+ ]
1188
+ }])
1189
+ }
905
1190
  }.each do |title, params|
906
1191
  it(title) {run_expand({processingMode: "json-ld-1.1"}.merge(params))}
907
1192
  end
@@ -970,7 +1255,8 @@ describe JSON::LD::API do
970
1255
  "Adds document expanded @type to object" => {
971
1256
  input: %({
972
1257
  "@context": {
973
- "typemap": {"@id": "http://example/typemap", "@container": "@type"},
1258
+ "@vocab": "http://example/",
1259
+ "typemap": {"@container": "@type"},
974
1260
  "label": "http://example/label"
975
1261
  },
976
1262
  "typemap": {
@@ -979,10 +1265,28 @@ describe JSON::LD::API do
979
1265
  }),
980
1266
  output: %([{
981
1267
  "http://example/typemap": [
982
- {"http://example/label": [{"@value": "Object with @type <foo>"}], "@type": ["http://example.org/Foo"]}
1268
+ {"http://example/label": [{"@value": "Object with @type <foo>"}], "@type": ["http://example/Foo"]}
983
1269
  ]
984
- }]),
985
- base: "http://example.org/"
1270
+ }])
1271
+ },
1272
+ "Does not add @type if it is @none, or expands to @none": {
1273
+ input: %({
1274
+ "@context": {
1275
+ "@vocab": "http://example/",
1276
+ "typemap": {"@container": "@type"},
1277
+ "none": "@none"
1278
+ },
1279
+ "typemap": {
1280
+ "@none": {"label": "Object with no @type"},
1281
+ "none": {"label": "Another object with no @type"}
1282
+ }
1283
+ }),
1284
+ output: %([{
1285
+ "http://example/typemap": [
1286
+ {"http://example/label": [{"@value": "Object with no @type"}]},
1287
+ {"http://example/label": [{"@value": "Another object with no @type"}]}
1288
+ ]
1289
+ }])
986
1290
  },
987
1291
  "Raises InvalidContainerMapping if processingMode is not specified" => {
988
1292
  input: %({
@@ -1086,6 +1390,43 @@ describe JSON::LD::API do
1086
1390
  }]
1087
1391
  }])
1088
1392
  },
1393
+ "Creates a graph object given an indexed value with index @none" => {
1394
+ input: %({
1395
+ "@context": {
1396
+ "@vocab": "http://example.org/",
1397
+ "input": {"@container": ["@graph", "@index"]}
1398
+ },
1399
+ "input": {
1400
+ "@none": {"value": "x"}
1401
+ }
1402
+ }),
1403
+ output: %([{
1404
+ "http://example.org/input": [{
1405
+ "@graph": [{
1406
+ "http://example.org/value": [{"@value": "x"}]
1407
+ }]
1408
+ }]
1409
+ }])
1410
+ },
1411
+ "Creates a graph object given an indexed value with index alias of @none" => {
1412
+ input: %({
1413
+ "@context": {
1414
+ "@vocab": "http://example.org/",
1415
+ "input": {"@container": ["@graph", "@index"]},
1416
+ "none": "@none"
1417
+ },
1418
+ "input": {
1419
+ "none": {"value": "x"}
1420
+ }
1421
+ }),
1422
+ output: %([{
1423
+ "http://example.org/input": [{
1424
+ "@graph": [{
1425
+ "http://example.org/value": [{"@value": "x"}]
1426
+ }]
1427
+ }]
1428
+ }])
1429
+ },
1089
1430
  "Creates a graph object given an indexed value with @set" => {
1090
1431
  input: %({
1091
1432
  "@context": {
@@ -1154,6 +1495,43 @@ describe JSON::LD::API do
1154
1495
  }]
1155
1496
  }])
1156
1497
  },
1498
+ "Creates a graph object given an indexed value of @none" => {
1499
+ input: %({
1500
+ "@context": {
1501
+ "@vocab": "http://example.org/",
1502
+ "input": {"@container": ["@graph", "@id"]}
1503
+ },
1504
+ "input": {
1505
+ "@none": {"value": "x"}
1506
+ }
1507
+ }),
1508
+ output: %([{
1509
+ "http://example.org/input": [{
1510
+ "@graph": [{
1511
+ "http://example.org/value": [{"@value": "x"}]
1512
+ }]
1513
+ }]
1514
+ }])
1515
+ },
1516
+ "Creates a graph object given an indexed value of alias of @none" => {
1517
+ input: %({
1518
+ "@context": {
1519
+ "@vocab": "http://example.org/",
1520
+ "input": {"@container": ["@graph", "@id"]},
1521
+ "none": "@none"
1522
+ },
1523
+ "input": {
1524
+ "none": {"value": "x"}
1525
+ }
1526
+ }),
1527
+ output: %([{
1528
+ "http://example.org/input": [{
1529
+ "@graph": [{
1530
+ "http://example.org/value": [{"@value": "x"}]
1531
+ }]
1532
+ }]
1533
+ }])
1534
+ },
1157
1535
  "Creates a graph object given an indexed value with @set" => {
1158
1536
  input: %({
1159
1537
  "@context": {
@@ -1779,6 +2157,23 @@ describe JSON::LD::API do
1779
2157
  ]
1780
2158
  }])
1781
2159
  },
2160
+ "orders lexicographically" => {
2161
+ input: %({
2162
+ "@context": {
2163
+ "@vocab": "http://example/",
2164
+ "t1": {"@context": {"foo": {"@id": "http://example.com/foo"}}},
2165
+ "t2": {"@context": {"foo": {"@id": "http://example.org/foo", "@type": "@id"}}}
2166
+ },
2167
+ "@type": ["t2", "t1"],
2168
+ "foo": "urn:bar"
2169
+ }),
2170
+ output: %([{
2171
+ "@type": ["http://example/t2", "http://example/t1"],
2172
+ "http://example.org/foo": [
2173
+ {"@id": "urn:bar"}
2174
+ ]
2175
+ }])
2176
+ },
1782
2177
  "Raises InvalidTermDefinition if processingMode is not specified" => {
1783
2178
  input: %({
1784
2179
  "@context": {