Skip to content

Commit 2308148

Browse files
committed
Context#container always returns an array.
1 parent 82d09d7 commit 2308148

File tree

5 files changed

+190
-101
lines changed

5 files changed

+190
-101
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"@context": {
3+
"@version": 1.1,
4+
"generatedAt": {
5+
"@id": "http://www.w3.org/ns/prov#generatedAtTime",
6+
"@type": "http://www.w3.org/2001/XMLSchema#date"
7+
},
8+
"Person": "http://xmlns.com/foaf/0.1/Person",
9+
"name": "http://xmlns.com/foaf/0.1/name",
10+
"knows": "http://xmlns.com/foaf/0.1/knows",
11+
"claim": {
12+
"@id": "https://w3id.org/credentials#claim",
13+
"@container": "@graph"
14+
}
15+
},
16+
"generatedAt": "2012-04-09",
17+
"claim": [
18+
{
19+
"@id": "http://manu.sporny.org/about#manu",
20+
"@type": "Person",
21+
"name": "Manu Sporny",
22+
"knows": "http://greggkellogg.net/foaf#me"
23+
}, {
24+
"@id": "http://greggkellogg.net/foaf#me",
25+
"@type": "Person",
26+
"name": "Gregg Kellogg",
27+
"knows": "http://manu.sporny.org/about#manu"
28+
}
29+
]
30+
}

lib/json/ld/compact.rb

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ def compact(element, property: nil)
113113
next
114114
end
115115

116-
if expanded_property == '@index' && context.container(property) == '@index'
116+
if expanded_property == '@index' && context.container(property) == %w(@index)
117117
#log_debug("@index") {"drop @index"}
118118
next
119119
end
@@ -176,7 +176,7 @@ def compact(element, property: nil)
176176
# handle @list
177177
if list?(expanded_item)
178178
compacted_item = [compacted_item] unless compacted_item.is_a?(Array)
179-
unless container == '@list'
179+
unless container == %w(@list)
180180
al = context.compact_iri('@list', vocab: true, quiet: true)
181181
compacted_item = {al => compacted_item}
182182
if expanded_item.has_key?('@index')
@@ -191,32 +191,28 @@ def compact(element, property: nil)
191191
end
192192

193193
# handle simple @graph, not the value of a property with @content: @graph
194-
if simple_graph?(expanded_item) && container != '@graph'
194+
if simple_graph?(expanded_item) && !container.include?('@graph')
195195
compacted_item = [compacted_item] unless compacted_item.is_a?(Array)
196196
al = context.compact_iri('@graph', vocab: true, quiet: true)
197197
compacted_item = {al => compacted_item}
198-
if expanded_item.has_key?('@index')
199-
key = context.compact_iri('@index', vocab: true, quiet: true)
200-
compacted_item[key] = expanded_item['@index']
201-
end
202198
end
203199

204-
if container == '@language' || container == '@index' || container == '@id' || container == '@type'
200+
if !(container & %w(@language @index @id @type)).empty?
205201
map_object = nest_result[item_active_property] ||= {}
206202
compacted_item = case container
207-
when '@id'
203+
when %w(@id)
208204
id_prop = context.compact_iri('@id', vocab: true, quiet: true)
209205
map_key = compacted_item[id_prop]
210206
map_key = context.compact_iri(map_key, quiet: true)
211207
compacted_item.delete(id_prop)
212208
compacted_item
213-
when '@index'
214-
map_key = expanded_item[container]
209+
when %w(@index)
210+
map_key = expanded_item['@index']
215211
compacted_item
216-
when '@language'
217-
map_key = expanded_item[container]
212+
when %w(@language)
213+
map_key = expanded_item['@language']
218214
value?(expanded_item) ? expanded_item['@value'] : compacted_item
219-
when '@type'
215+
when %w(@type)
220216
type_prop = context.compact_iri('@type', vocab: true, quiet: true)
221217
map_key, *types = Array(compacted_item[type_prop])
222218
map_key = context.compact_iri(map_key, vocab: true, quiet: true)

lib/json/ld/context.rb

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ class TermDefinition
3838
attr_accessor :type_mapping
3939

4040
# Base container mapping, without @set
41-
# @return ['@index', '@language', '@index', '@type', '@id'] Container mapping
41+
# @return Array<'@index', '@language', '@index', '@set', '@type', '@id', '@graph'> Container mapping
4242
attr_reader :container_mapping
4343

4444
# @return [String] Term used for nest properties
@@ -96,7 +96,7 @@ def initialize(term,
9696
@term = term
9797
@id = id.to_s unless id.nil?
9898
@type_mapping = type_mapping.to_s unless type_mapping.nil?
99-
self.container_mapping = container_mapping unless container_mapping.nil?
99+
self.container_mapping = container_mapping
100100
@language_mapping = language_mapping unless language_mapping.nil?
101101
@reverse_property = reverse_property
102102
@nest = nest unless nest.nil?
@@ -112,7 +112,7 @@ def container_mapping=(mapping)
112112
mapping = mapping.dup
113113
mapping.delete('@set')
114114
end
115-
@container_mapping = mapping.first
115+
@container_mapping = mapping.sort
116116
end
117117

118118
##
@@ -143,7 +143,7 @@ def to_context_definition(context)
143143
end
144144
end
145145

146-
cm = [container_mapping, ('@set' if as_set?)].compact
146+
cm = (Array(container_mapping) + (as_set? ? %w(@set) : [])).compact
147147
cm = cm.first if cm.length == 1
148148
defn['@container'] = cm unless cm.empty?
149149
# Language set as false to be output as null
@@ -164,8 +164,9 @@ def to_rb
164164
%w(id type_mapping container_mapping language_mapping reverse_property nest simple prefix context).each do |acc|
165165
v = instance_variable_get("@#{acc}".to_sym)
166166
v = v.to_s if v.is_a?(RDF::Term)
167-
if acc == 'container_mapping' && as_set?
168-
v = v ? [v, '@set'] : '@set'
167+
if acc == 'container_mapping'
168+
v.concat(%w(@set)) if as_set?
169+
v = v.first if v.length <= 1
169170
end
170171
defn << "#{acc}: #{v.inspect}" if v
171172
end
@@ -874,11 +875,11 @@ def find_definition(term)
874875
# Retrieve container mapping, add it if `value` is provided
875876
#
876877
# @param [Term, #to_s] term in unexpanded form
877-
# @return [String]
878+
# @return [Array<'@index', '@language', '@index', '@set', '@type', '@id', '@graph'>]
878879
def container(term)
879-
return term if KEYWORDS.include?(term)
880+
return [term] if KEYWORDS.include?(term)
880881
term = find_definition(term)
881-
term && term.container_mapping
882+
term ? term.container_mapping : []
882883
end
883884

884885
##
@@ -889,7 +890,7 @@ def container(term)
889890
def as_array?(term)
890891
return true if CONTEXT_CONTAINER_ARRAY_TERMS.include?(term)
891892
term = find_definition(term)
892-
term && (term.as_set? || term.container_mapping == '@list')
893+
term && (term.as_set? || term.container_mapping.include?('@list'))
893894
end
894895

895896
##
@@ -1309,7 +1310,7 @@ def compact_value(property, value, options = {})
13091310

13101311
num_members = value.length
13111312

1312-
num_members -= 1 if index?(value) && container(property) == '@index'
1313+
num_members -= 1 if index?(value) && container(property).include?('@index')
13131314
if num_members > 2
13141315
#log_debug("") {"can't compact value with # members > 2"}
13151316
return value
@@ -1447,6 +1448,8 @@ def alias(value)
14471448
private
14481449

14491450
CONTEXT_CONTAINER_ARRAY_TERMS = %w(@set @list @graph).freeze
1451+
CONTEXT_CONTAINER_ID_GRAPH = %w(@id @graph).freeze
1452+
CONTEXT_CONTAINER_INDEX_GRAPH = %w(@index @graph).freeze
14501453

14511454
def uri(value)
14521455
case value.to_s
@@ -1517,7 +1520,8 @@ def inverse_context
15171520
end.each do |term|
15181521
next unless td = term_definitions[term]
15191522

1520-
container = td.container_mapping || (td.as_set? ? '@set' : '@none')
1523+
container = Array(td.container_mapping).sort.first
1524+
container ||= td.as_set? ? %(@set) : %(@none)
15211525
# FIXME: Alternative to consider
15221526
## Creates "@language", "@language@set", "@set", or "@none"
15231527
## for each of "@language", "@index", "@type", "@id", "@list", and "@graph"
@@ -1652,20 +1656,45 @@ def check_container(container, local_context, defined, term)
16521656
val = Array(container).dup
16531657
val.delete('@set') if has_set = val.include?('@set')
16541658

1655-
raise JsonLdError::InvalidContainerMapping,
1656-
"'@container' has more than one value other than @set" if val.length > 1
1657-
1658-
case val.first
1659-
when '@list'
1659+
if val.include?('@list')
16601660
raise JsonLdError::InvalidContainerMapping,
1661-
"'@container' on term #{term.inspect} cannot be both @list and @set" if has_set
1661+
"'@container' on term #{term.inspect} using @list cannot have any other values" unless
1662+
!has_set && val.length == 1
16621663
# Okay
1663-
when '@language', '@index', nil
1664+
elsif val.include?('@language')
1665+
raise JsonLdError::InvalidContainerMapping,
1666+
"unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" if
1667+
has_set && (processingMode || 'json-ld-1.0') < 'json-ld-1.1'
1668+
raise JsonLdError::InvalidContainerMapping,
1669+
"'@container' on term #{term.inspect} using @language cannot have any values other than @set, found #{container.inspect}" unless
1670+
val.length == 1
1671+
# Okay
1672+
elsif val.include?('@index')
1673+
raise JsonLdError::InvalidContainerMapping,
1674+
"unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" if
1675+
has_set && (processingMode || 'json-ld-1.0') < 'json-ld-1.1'
1676+
raise JsonLdError::InvalidContainerMapping,
1677+
"'@container' on term #{term.inspect} using @index cannot have any values other than @set and/or @graph, found #{container.inspect}" unless
1678+
(val - CONTEXT_CONTAINER_INDEX_GRAPH).empty?
16641679
# Okay
1665-
when '@type', '@id', '@graph', nil
1680+
elsif val.include?('@id')
16661681
raise JsonLdError::InvalidContainerMapping,
16671682
"unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" if
16681683
(processingMode || 'json-ld-1.0') < 'json-ld-1.1'
1684+
raise JsonLdError::InvalidContainerMapping,
1685+
"'@container' on term #{term.inspect} using @id cannot have any values other than @set and/or @graph, found #{container.inspect}" unless
1686+
(val - CONTEXT_CONTAINER_ID_GRAPH).empty?
1687+
# Okay
1688+
elsif val.include?('@type') || val.include?('@graph')
1689+
raise JsonLdError::InvalidContainerMapping,
1690+
"unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" if
1691+
(processingMode || 'json-ld-1.0') < 'json-ld-1.1'
1692+
raise JsonLdError::InvalidContainerMapping,
1693+
"'@container' on term #{term.inspect} using @language cannot have any values other than @set, found #{container.inspect}" unless
1694+
val.length == 1
1695+
# Okay
1696+
elsif val.empty?
1697+
# Okay
16691698
else
16701699
raise JsonLdError::InvalidContainerMapping,
16711700
"unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}"

lib/json/ld/expand.rb

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ def expand(input, active_property, context, ordered: true)
2323
result = case input
2424
when Array
2525
# If element is an array,
26-
is_list = context.container(active_property) == '@list'
26+
is_list = context.container(active_property) == %w(@list)
2727
value = input.each_with_object([]) do |v, memo|
2828
# Initialize expanded item to the result of using this algorithm recursively, passing active context, active property, and item as element.
2929
v = expand(v, active_property, context, ordered: ordered)
@@ -352,7 +352,7 @@ def expand_object(input, active_property, context, output_object, ordered: false
352352
term_context = context.term_definitions[key].context if context.term_definitions[key]
353353
active_context = term_context ? context.parse(term_context) : context
354354
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)
356356
# 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:
357357

358358
# Set multilingual array to an empty array.
@@ -375,33 +375,33 @@ def expand_object(input, active_property, context, output_object, ordered: false
375375
end
376376

377377
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:
380380

381381
# Set ary to an empty array.
382-
container, ary = container.to_s, []
382+
ary = []
383383

384384
# For each key-value in the object:
385385
keys = ordered ? value.keys.sort : value.keys
386386
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]
389389
map_context = active_context.parse(map_context) if map_context
390390
map_context ||= active_context
391391

392392
# Initialize index value to the result of using this algorithm recursively, passing active context, key as active property, and index value as element.
393393
index_value = expand([value[k]].flatten, key, map_context, ordered: ordered)
394394
index_value.each do |item|
395395
case container
396-
when '@index' then item[container] ||= k
397-
when '@id'
396+
when %w(@index) then item['@index'] ||= k
397+
when %w(@id)
398398
# Expand k document relative
399399
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)
402402
# Expand k vocabulary relative
403403
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']))
405405
end
406406

407407
# Append item to expanded value.
@@ -422,7 +422,7 @@ def expand_object(input, active_property, context, output_object, ordered: false
422422
#log_debug {" => #{expanded_value.inspect}"}
423423

424424
# 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)
425+
if active_context.container(key) == %w(@list) && !list?(expanded_value)
426426
#log_debug(" => ") { "convert #{expanded_value.inspect} to list"}
427427
expanded_value = [expanded_value] unless expanded_value.is_a?(Array)
428428
expanded_value = {'@list' => expanded_value}
@@ -431,7 +431,7 @@ def expand_object(input, active_property, context, output_object, ordered: false
431431

432432
# convert expanded value to @graph if container specifies it
433433
# FIXME value may be a named graph, as well as a simple graph.
434-
if active_context.container(key) == '@graph' && !graph?(expanded_value)
434+
if active_context.container(key) == %w(@graph) && !graph?(expanded_value)
435435
#log_debug(" => ") { "convert #{expanded_value.inspect} to list"}
436436
expanded_value = [expanded_value] unless expanded_value.is_a?(Array)
437437
expanded_value = {'@graph' => expanded_value}

0 commit comments

Comments
 (0)