json-ld 2.2.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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": {