json-ld 2.1.7 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -23,7 +23,7 @@ module JSON::LD
23
23
  result = case input
24
24
  when Array
25
25
  # If element is an array,
26
- is_list = context.container(active_property) == '@list'
26
+ is_list = context.container(active_property) == %w(@list)
27
27
  value = input.each_with_object([]) do |v, memo|
28
28
  # Initialize expanded item to the result of using this algorithm recursively, passing active context, active property, and item as element.
29
29
  v = expand(v, active_property, context, ordered: ordered)
@@ -175,7 +175,7 @@ module JSON::LD
175
175
  when Array
176
176
  # Framing allows an array of IRIs, and always puts values in an array
177
177
  raise JsonLdError::InvalidIdValue,
178
- "value of @id must be a string, array of string or hash if framing: #{value.inspect}" unless framing
178
+ "value of @id must be a string unless framing: #{value.inspect}" unless framing
179
179
  context.expand_iri(value, documentRelative: true, quiet: true).to_s
180
180
  value.map do |v|
181
181
  raise JsonLdError::InvalidTypeValue,
@@ -187,7 +187,7 @@ module JSON::LD
187
187
  "value of @id must be a string unless framing: #{value.inspect}" unless framing
188
188
  raise JsonLdError::InvalidTypeValue,
189
189
  "value of @id must be a an empty object for framing: #{value.inspect}" unless
190
- value.empty? && framing
190
+ value.empty?
191
191
  [{}]
192
192
  else
193
193
  raise JsonLdError::InvalidIdValue,
@@ -352,7 +352,7 @@ module JSON::LD
352
352
  term_context = context.term_definitions[key].context if context.term_definitions[key]
353
353
  active_context = term_context ? context.parse(term_context) : context
354
354
  container = active_context.container(key)
355
- expanded_value = if container == '@language' && value.is_a?(Hash)
355
+ expanded_value = if container == %w(@language) && value.is_a?(Hash)
356
356
  # Otherwise, if key's container mapping in active context is @language and value is a JSON object then value is expanded from a language map as follows:
357
357
 
358
358
  # Set multilingual array to an empty array.
@@ -375,17 +375,17 @@ module JSON::LD
375
375
  end
376
376
 
377
377
  ary
378
- elsif CONTAINER_MAPPING_INDEX_ID_TYPE.include?(container) && value.is_a?(Hash)
379
- # Otherwise, if key's container mapping in active context is @index, @id, @type, an IRI or Blank Node and value is a JSON object then value is expanded from an index map as follows:
378
+ elsif !(CONTAINER_MAPPING_INDEX_ID_TYPE & container).empty? && value.is_a?(Hash)
379
+ # Otherwise, if key's container mapping in active context contains @index, @id, @type and value is a JSON object then value is expanded from an index map as follows:
380
380
 
381
381
  # Set ary to an empty array.
382
- container, ary = container.to_s, []
382
+ ary = []
383
383
 
384
384
  # For each key-value in the object:
385
385
  keys = ordered ? value.keys.sort : value.keys
386
386
  keys.each do |k|
387
- # If container mapping in the active context is @type, and k is a term in the active context having a local context, use that context when expanding values
388
- map_context = active_context.term_definitions[k].context if container == '@type' && active_context.term_definitions[k]
387
+ # If container mapping in the active context includes @type, and k is a term in the active context having a local context, use that context when expanding values
388
+ map_context = active_context.term_definitions[k].context if container.include?('@type') && active_context.term_definitions[k]
389
389
  map_context = active_context.parse(map_context) if map_context
390
390
  map_context ||= active_context
391
391
 
@@ -393,15 +393,25 @@ module JSON::LD
393
393
  index_value = expand([value[k]].flatten, key, map_context, ordered: ordered)
394
394
  index_value.each do |item|
395
395
  case container
396
- when '@index' then item[container] ||= k
397
- when '@id'
396
+ when %w(@index) then item['@index'] ||= k
397
+ when %w(@id)
398
398
  # Expand k document relative
399
399
  expanded_k = active_context.expand_iri(k, documentRelative: true, quiet: true).to_s
400
- item[container] ||= expanded_k
401
- when '@type'
400
+ item['@id'] ||= expanded_k
401
+ when %w(@type)
402
402
  # Expand k vocabulary relative
403
403
  expanded_k = active_context.expand_iri(k, vocab: true, documentRelative: true, quiet: true).to_s
404
- item[container] = [expanded_k].concat(Array(item[container]))
404
+ item['@type'] = [expanded_k].concat(Array(item['@type']))
405
+ when %w(@graph @index), %w(@graph @id)
406
+ # Indexed graph by graph name
407
+ if !graph?(item)
408
+ item = [item] unless expanded_value.is_a?(Array)
409
+ item = {'@graph' => item}
410
+ end
411
+ expanded_k = container.include?('@index') ? k :
412
+ active_context.expand_iri(k, documentRelative: true, quiet: true).to_s
413
+ # Expand k document relative
414
+ item[container.include?('@index') ? '@index' : '@id'] ||= k
405
415
  end
406
416
 
407
417
  # Append item to expanded value.
@@ -422,12 +432,21 @@ module JSON::LD
422
432
  #log_debug {" => #{expanded_value.inspect}"}
423
433
 
424
434
  # If the container mapping associated to key in active context is @list and expanded value is not already a list object, convert expanded value to a list object by first setting it to an array containing only expanded value if it is not already an array, and then by setting it to a JSON object containing the key-value pair @list-expanded value.
425
- if active_context.container(key) == '@list' && !list?(expanded_value)
435
+ if active_context.container(key) == %w(@list) && !list?(expanded_value)
426
436
  #log_debug(" => ") { "convert #{expanded_value.inspect} to list"}
427
- expanded_value = {'@list' => [expanded_value].flatten}
437
+ expanded_value = [expanded_value] unless expanded_value.is_a?(Array)
438
+ expanded_value = {'@list' => expanded_value}
428
439
  end
429
440
  #log_debug {" => #{expanded_value.inspect}"}
430
441
 
442
+ # convert expanded value to @graph if container specifies it
443
+ # FIXME value may be a named graph, as well as a simple graph.
444
+ if active_context.container(key) == %w(@graph) && !graph?(expanded_value)
445
+ #log_debug(" => ") { "convert #{expanded_value.inspect} to list"}
446
+ expanded_value = [expanded_value] unless expanded_value.is_a?(Array)
447
+ expanded_value = {'@graph' => expanded_value}
448
+ end
449
+
431
450
  # Otherwise, if the term definition associated to key indicates that it is a reverse property
432
451
  # Spec FIXME: this is not an otherwise.
433
452
  if (td = context.term_definitions[key]) && td.reverse_property
data/lib/json/ld/utils.rb CHANGED
@@ -46,6 +46,27 @@ module JSON::LD
46
46
  end
47
47
  end
48
48
 
49
+ ##
50
+ # Is value an expaned @graph?
51
+ #
52
+ # Note: A value is a simple graph if all of these hold true:
53
+ # 1. It is an object.
54
+ # 2. It has an `@graph` key.
55
+ # 3. It may have '@context', '@id' or '@index'
56
+ #
57
+ # @param [Object] value
58
+ # @return [Boolean]
59
+ def graph?(value)
60
+ value.is_a?(Hash) && (value.keys - UTIL_GRAPH_KEYS) == ['@graph']
61
+ end
62
+ ##
63
+ # Is value a simple @graph (lacking @id)?
64
+ # @param [Object] value
65
+ # @return [Boolean]
66
+ def simple_graph?(value)
67
+ graph?(value) && !value.has_key?('@id')
68
+ end
69
+
49
70
  ##
50
71
  # Is value an expaned @list?
51
72
  #
@@ -184,6 +205,7 @@ module JSON::LD
184
205
  end
185
206
 
186
207
  private
208
+ UTIL_GRAPH_KEYS = %w(@context @id @index).freeze
187
209
 
188
210
  # Merge the last value into an array based for the specified key if hash is not null and value is not already in that array
189
211
  def merge_value(hash, key, value)
data/spec/api_spec.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # coding: utf-8
2
- $:.unshift "."
3
- require 'spec_helper'
2
+ require_relative 'spec_helper'
4
3
 
5
4
  describe JSON::LD::API do
6
5
  let(:logger) {RDF::Spec.logger}
data/spec/compact_spec.rb CHANGED
@@ -1,6 +1,5 @@
1
1
  # coding: utf-8
2
- $:.unshift "."
3
- require 'spec_helper'
2
+ require_relative 'spec_helper'
4
3
 
5
4
  describe JSON::LD::API do
6
5
  let(:logger) {RDF::Spec.logger}
@@ -744,6 +743,301 @@ describe JSON::LD::API do
744
743
  end
745
744
  end
746
745
 
746
+ context "@container: @graph" do
747
+ {
748
+ "Compacts simple graph" => {
749
+ input: %([{
750
+ "http://example.org/input": [{
751
+ "@graph": [{
752
+ "http://example.org/value": [{"@value": "x"}]
753
+ }]
754
+ }]
755
+ }]),
756
+ context: %({
757
+ "@vocab": "http://example.org/",
758
+ "input": {"@container": "@graph"}
759
+ }),
760
+ output: %({
761
+ "@context": {
762
+ "@vocab": "http://example.org/",
763
+ "input": {"@container": "@graph"}
764
+ },
765
+ "input": {
766
+ "value": "x"
767
+ }
768
+ })
769
+ },
770
+ "Compacts simple graph with @set" => {
771
+ input: %([{
772
+ "http://example.org/input": [{
773
+ "@graph": [{
774
+ "http://example.org/value": [{"@value": "x"}]
775
+ }]
776
+ }]
777
+ }]),
778
+ context: %({
779
+ "@vocab": "http://example.org/",
780
+ "input": {"@container": ["@graph", "@set"]}
781
+ }),
782
+ output: %({
783
+ "@context": {
784
+ "@vocab": "http://example.org/",
785
+ "input": {"@container": ["@graph", "@set"]}
786
+ },
787
+ "input": [{
788
+ "value": "x"
789
+ }]
790
+ })
791
+ },
792
+ "Compacts simple graph with @index" => {
793
+ input: %([{
794
+ "http://example.org/input": [{
795
+ "@graph": [{
796
+ "http://example.org/value": [{"@value": "x"}]
797
+ }],
798
+ "@index": "ndx"
799
+ }]
800
+ }]),
801
+ context: %({
802
+ "@vocab": "http://example.org/",
803
+ "input": {"@container": "@graph"}
804
+ }),
805
+ output: %({
806
+ "@context": {
807
+ "@vocab": "http://example.org/",
808
+ "input": {"@container": "@graph"}
809
+ },
810
+ "input": {
811
+ "value": "x"
812
+ }
813
+ })
814
+ },
815
+ "Does not compact graph with @id" => {
816
+ input: %([{
817
+ "http://example.org/input": [{
818
+ "@graph": [{
819
+ "http://example.org/value": [{"@value": "x"}]
820
+ }],
821
+ "@id": "http://example.org/id"
822
+ }]
823
+ }]),
824
+ context: %({
825
+ "@vocab": "http://example.org/",
826
+ "input": {"@container": "@graph"}
827
+ }),
828
+ output: %({
829
+ "@context": {
830
+ "@vocab": "http://example.org/",
831
+ "input": {"@container": "@graph"}
832
+ },
833
+ "input": {
834
+ "@id": "http://example.org/id",
835
+ "@graph": [{"value": "x"}]
836
+ }
837
+ })
838
+ },
839
+ }.each_pair do |title, params|
840
+ it(title) {run_compact({processingMode: "json-ld-1.1"}.merge(params))}
841
+ end
842
+
843
+ context "+ @index" do
844
+ {
845
+ "Compacts simple graph" => {
846
+ input: %([{
847
+ "http://example.org/input": [{
848
+ "@index": "g1",
849
+ "@graph": [{
850
+ "http://example.org/value": [{"@value": "x"}]
851
+ }]
852
+ }]
853
+ }]),
854
+ context: %({
855
+ "@vocab": "http://example.org/",
856
+ "input": {"@container": ["@graph", "@index"]}
857
+ }),
858
+ output: %({
859
+ "@context": {
860
+ "@vocab": "http://example.org/",
861
+ "input": {"@container": ["@graph", "@index"]}
862
+ },
863
+ "input": {
864
+ "g1": {"value": "x"}
865
+ }
866
+ })
867
+ },
868
+ "Compacts simple graph with @set" => {
869
+ input: %([{
870
+ "http://example.org/input": [{
871
+ "@index": "g1",
872
+ "@graph": [{
873
+ "http://example.org/value": [{"@value": "x"}]
874
+ }]
875
+ }]
876
+ }]),
877
+ context: %({
878
+ "@vocab": "http://example.org/",
879
+ "input": {"@container": ["@graph", "@index", "@set"]}
880
+ }),
881
+ output: %({
882
+ "@context": {
883
+ "@vocab": "http://example.org/",
884
+ "input": {"@container": ["@graph", "@index", "@set"]}
885
+ },
886
+ "input": {
887
+ "g1": [{"value": "x"}]
888
+ }
889
+ })
890
+ },
891
+ "Does not compact graph with @id" => {
892
+ input: %([{
893
+ "http://example.org/input": [{
894
+ "@graph": [{
895
+ "http://example.org/value": [{"@value": "x"}]
896
+ }],
897
+ "@index": "g1",
898
+ "@id": "http://example.org/id"
899
+ }]
900
+ }]),
901
+ context: %({
902
+ "@vocab": "http://example.org/",
903
+ "input": {"@container": ["@graph", "@index"]}
904
+ }),
905
+ output: %({
906
+ "@context": {
907
+ "@vocab": "http://example.org/",
908
+ "input": {"@container": ["@graph", "@index"]}
909
+ },
910
+ "input": {
911
+ "@id": "http://example.org/id",
912
+ "@index": "g1",
913
+ "@graph": [{"value": "x"}]
914
+ }
915
+ })
916
+ },
917
+ }.each_pair do |title, params|
918
+ it(title) {run_compact({processingMode: "json-ld-1.1"}.merge(params))}
919
+ end
920
+ end
921
+
922
+ context "+ @id" do
923
+ {
924
+ "Compacts simple graph" => {
925
+ input: %([{
926
+ "http://example.org/input": [{
927
+ "@graph": [{
928
+ "http://example.org/value": [{"@value": "x"}]
929
+ }]
930
+ }]
931
+ }]),
932
+ context: %({
933
+ "@vocab": "http://example.org/",
934
+ "input": {"@container": ["@graph", "@id"]}
935
+ }),
936
+ output: %({
937
+ "@context": {
938
+ "@vocab": "http://example.org/",
939
+ "input": {"@container": ["@graph", "@id"]}
940
+ },
941
+ "input": {
942
+ "_:b0": {"value": "x"}
943
+ }
944
+ })
945
+ },
946
+ "Compacts simple graph with @set" => {
947
+ input: %([{
948
+ "http://example.org/input": [{
949
+ "@graph": [{
950
+ "http://example.org/value": [{"@value": "x"}]
951
+ }]
952
+ }]
953
+ }]),
954
+ context: %({
955
+ "@vocab": "http://example.org/",
956
+ "input": {"@container": ["@graph", "@id", "@set"]}
957
+ }),
958
+ output: %({
959
+ "@context": {
960
+ "@vocab": "http://example.org/",
961
+ "input": {"@container": ["@graph", "@id", "@set"]}
962
+ },
963
+ "input": {"_:b0": [{"value": "x"}]}
964
+ })
965
+ },
966
+ "Compacts simple graph with @index" => {
967
+ input: %([{
968
+ "http://example.org/input": [{
969
+ "@graph": [{
970
+ "http://example.org/value": [{"@value": "x"}]
971
+ }],
972
+ "@index": "ndx"
973
+ }]
974
+ }]),
975
+ context: %({
976
+ "@vocab": "http://example.org/",
977
+ "input": {"@container": ["@graph", "@id"]}
978
+ }),
979
+ output: %({
980
+ "@context": {
981
+ "@vocab": "http://example.org/",
982
+ "input": {"@container": ["@graph", "@id"]}
983
+ },
984
+ "input": {
985
+ "_:b0": {"value": "x"}
986
+ }
987
+ })
988
+ },
989
+ "Compacts graph with @id" => {
990
+ input: %([{
991
+ "http://example.org/input": [{
992
+ "@graph": [{
993
+ "http://example.org/value": [{"@value": "x"}]
994
+ }],
995
+ "@id": "http://example.org/id"
996
+ }]
997
+ }]),
998
+ context: %({
999
+ "@vocab": "http://example.org/",
1000
+ "input": {"@container": ["@graph", "@id"]}
1001
+ }),
1002
+ output: %({
1003
+ "@context": {
1004
+ "@vocab": "http://example.org/",
1005
+ "input": {"@container": ["@graph", "@id"]}
1006
+ },
1007
+ "input": {
1008
+ "http://example.org/id" : {"value": "x"}
1009
+ }
1010
+ })
1011
+ },
1012
+ "Compacts graph with @id and @set" => {
1013
+ input: %([{
1014
+ "http://example.org/input": [{
1015
+ "@graph": [{
1016
+ "http://example.org/value": [{"@value": "x"}]
1017
+ }],
1018
+ "@id": "http://example.org/id"
1019
+ }]
1020
+ }]),
1021
+ context: %({
1022
+ "@vocab": "http://example.org/",
1023
+ "input": {"@container": ["@graph", "@id", "@set"]}
1024
+ }),
1025
+ output: %({
1026
+ "@context": {
1027
+ "@vocab": "http://example.org/",
1028
+ "input": {"@container": ["@graph", "@id", "@set"]}
1029
+ },
1030
+ "input": {
1031
+ "http://example.org/id" : [{"value": "x"}]
1032
+ }
1033
+ })
1034
+ },
1035
+ }.each_pair do |title, params|
1036
+ it(title) {run_compact({processingMode: "json-ld-1.1"}.merge(params))}
1037
+ end
1038
+ end
1039
+ end
1040
+
747
1041
  context "@nest" do
748
1042
  {
749
1043
  "Indexes to @nest for property with @container: @nest" => {