Skip to content

Commit b4bb3c2

Browse files
committed
Finish 2.2.0
2 parents e6f031a + 356b300 commit b4bb3c2

31 files changed

+1258
-344
lines changed

README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,86 @@ The value of `@container` in a term definition can include `@id` or `@type`, in
298298
}
299299
}
300300

301+
### @graph containers and maps
302+
A term can have `@container` set to include `@graph` optionally including `@id` or `@index` and `@set`. In the first form, with `@container` set to `@graph`, the value of a property is treated as a _simple graph object_, meaning that values treated as if they were contained in an object with `@graph`, creating _named graph_ with an anonymous name.
303+
304+
{
305+
"@context": {
306+
"@vocab": "http://example.org/",
307+
"input": {"@container": "@graph"}
308+
},
309+
"input": {
310+
"value": "x"
311+
}
312+
}
313+
314+
which expands to the following:
315+
316+
[{
317+
"http://example.org/input": [{
318+
"@graph": [{
319+
"http://example.org/value": [{"@value": "x"}]
320+
}]
321+
}]
322+
}]
323+
324+
Compaction reverses this process, optionally ensuring that a single value is contained within an array of `@container` also includes `@set`:
325+
326+
{
327+
"@context": {
328+
"@vocab": "http://example.org/",
329+
"input": {"@container": ["@graph", "@set"]}
330+
}
331+
}
332+
333+
A graph map uses the map form already existing for `@index`, `@language`, `@type`, and `@id` where the index is either an index value or an id.
334+
335+
{
336+
"@context": {
337+
"@vocab": "http://example.org/",
338+
"input": {"@container": ["@graph", "@index"]}
339+
},
340+
"input": {
341+
"g1": {"value": "x"}
342+
}
343+
}
344+
345+
treats "g1" as an index, and expands to the following:
346+
347+
[{
348+
"http://example.org/input": [{
349+
"@index": "g1",
350+
"@graph": [{
351+
"http://example.org/value": [{"@value": "x"}]
352+
}]
353+
}]
354+
}])
355+
356+
This can also include `@set` to ensure that, when compacting, a single value of an index will be in array form.
357+
358+
The _id_ version is similar:
359+
360+
{
361+
"@context": {
362+
"@vocab": "http://example.org/",
363+
"input": {"@container": ["@graph", "@id"]}
364+
},
365+
"input": {
366+
"http://example.com/g1": {"value": "x"}
367+
}
368+
}
369+
370+
which expands to:
371+
372+
[{
373+
"http://example.org/input": [{
374+
"@id": "http://example.com/g1",
375+
"@graph": [{
376+
"http://example.org/value": [{"@value": "x"}]
377+
}]
378+
}]
379+
}])
380+
301381
### Transparent Nesting
302382
Many JSON APIs separate properties from their entities using an intermediate object. For example, a set of possible labels may be grouped under a common property:
303383

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.1.7
1+
2.2.0
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+
}

json-ld.gemspec

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,27 @@ Gem::Specification.new do |gem|
2626

2727
gem.required_ruby_version = '>= 2.2.2'
2828
gem.requirements = []
29-
gem.add_runtime_dependency 'rdf', '~> 2.2', '>= 2.2.8'
29+
#gem.add_runtime_dependency 'rdf', '~> 3.0'
30+
gem.add_runtime_dependency 'rdf', '>= 2.2.8', '< 4.0'
3031
gem.add_runtime_dependency 'multi_json', '~> 1.12'
31-
gem.add_development_dependency 'linkeddata', '~> 2.2'
32+
#gem.add_development_dependency 'linkeddata', '~> 2.2'
33+
gem.add_development_dependency 'linkeddata', '>= 2.2', '< 4.0'
3234
gem.add_development_dependency 'jsonlint', '~> 0.2' unless RUBY_ENGINE == "jruby"
33-
gem.add_development_dependency 'oj', '~> 2.17' unless RUBY_ENGINE == "jruby"
35+
gem.add_development_dependency 'oj', '~> 2.18' unless RUBY_ENGINE == "jruby"
3436
gem.add_development_dependency 'yajl-ruby', '~> 1.2' unless RUBY_ENGINE == "jruby"
35-
gem.add_development_dependency 'rdf-isomorphic', '~> 2.0'
36-
gem.add_development_dependency 'rdf-spec', '~> 2.2'
37-
gem.add_development_dependency 'rdf-trig', '~> 2.0'
38-
gem.add_development_dependency 'rdf-turtle', '~> 2.0'
39-
gem.add_development_dependency 'rdf-vocab', '~> 2.0'
40-
gem.add_development_dependency 'rdf-xsd', '~> 2.0'
41-
gem.add_development_dependency 'rspec', '~> 3.5'
37+
#gem.add_development_dependency 'rdf-isomorphic', '~> 3.0'
38+
#gem.add_development_dependency 'rdf-spec', '~> 3.0'
39+
#gem.add_development_dependency 'rdf-trig', '~> 3.0'
40+
#gem.add_development_dependency 'rdf-turtle', '~> 3.0'
41+
#gem.add_development_dependency 'rdf-vocab', '~> 3.0'
42+
#gem.add_development_dependency 'rdf-xsd', '~> 3.0'
43+
gem.add_development_dependency 'rdf-isomorphic', '>= 2.0', '< 4.0'
44+
gem.add_development_dependency 'rdf-spec', '>= 2.2', '< 4.0'
45+
gem.add_development_dependency 'rdf-trig', '>= 2.2', '< 4.0'
46+
gem.add_development_dependency 'rdf-turtle', '>= 2.2', '< 4.0'
47+
gem.add_development_dependency 'rdf-vocab', '>= 2.2', '< 4.0'
48+
gem.add_development_dependency 'rdf-xsd', '>= 2.2', '< 4.0'
49+
gem.add_development_dependency 'rspec', '~> 3.7'
4250
gem.add_development_dependency 'rspec-its', '~> 1.2'
4351
gem.add_development_dependency 'yard' , '~> 0.8'
4452

lib/json/ld/compact.rb

Lines changed: 56 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ def compact(element, property: nil)
8282
if expanded_property == '@reverse'
8383
compacted_value = compact(expanded_value, property: '@reverse')
8484
#log_debug("@reverse") {"compacted_value: #{compacted_value.inspect}"}
85+
# handle double-reversed properties
8586
compacted_value.each do |prop, value|
8687
if context.reverse?(prop)
8788
value = [value] if !value.is_a?(Array) &&
@@ -112,7 +113,7 @@ def compact(element, property: nil)
112113
next
113114
end
114115

115-
if expanded_property == '@index' && context.container(property) == '@index'
116+
if expanded_property == '@index' && context.container(property) == %w(@index)
116117
#log_debug("@index") {"drop @index"}
117118
next
118119
end
@@ -162,13 +163,20 @@ def compact(element, property: nil)
162163

163164
container = context.container(item_active_property)
164165
as_array = context.as_array?(item_active_property)
165-
value = list?(expanded_item) ? expanded_item['@list'] : expanded_item
166+
167+
value = case
168+
when list?(expanded_item) then expanded_item['@list']
169+
when graph?(expanded_item) then expanded_item['@graph']
170+
else expanded_item
171+
end
172+
166173
compacted_item = compact(value, property: item_active_property)
167174
#log_debug("") {" => compacted key: #{item_active_property.inspect} for #{compacted_item.inspect}"}
168175

176+
# handle @list
169177
if list?(expanded_item)
170178
compacted_item = [compacted_item] unless compacted_item.is_a?(Array)
171-
unless container == '@list'
179+
unless container == %w(@list)
172180
al = context.compact_iri('@list', vocab: true, quiet: true)
173181
compacted_item = {al => compacted_item}
174182
if expanded_item.has_key?('@index')
@@ -178,25 +186,63 @@ def compact(element, property: nil)
178186
else
179187
raise JsonLdError::CompactionToListOfLists,
180188
"key cannot have more than one list value" if nest_result.has_key?(item_active_property)
189+
# Falls through to add list value below
181190
end
182191
end
183192

184-
if container == '@language' || container == '@index' || container == '@id' || container == '@type'
193+
# Graph object compaction cases:
194+
if graph?(expanded_item)
195+
if container.include?('@graph') && container.include?('@id')
196+
# container includes @graph and @id
197+
map_object = nest_result[item_active_property] ||= {}
198+
map_key = expanded_item['@id']
199+
# If there is no @id, create a blank node identifier to use as an index
200+
map_key = map_key ? context.compact_iri(map_key, quiet: true) : namer.get_name
201+
merge_compacted_value(map_object, map_key, compacted_item)
202+
elsif container.include?('@graph') && container.include?('@index') && simple_graph?(expanded_item)
203+
# container includes @graph and @index and value is a simple graph object
204+
map_object = nest_result[item_active_property] ||= {}
205+
# If there is no @index, use @none
206+
map_key = expanded_item['@index'] || '@none'
207+
merge_compacted_value(map_object, map_key, compacted_item)
208+
elsif container.include?('@graph') && simple_graph?(expanded_item)
209+
# container includes @graph but not @id or @index and value is a simple graph object
210+
# Drop through, where compacted_value will be added
211+
compacted_item = [compacted_item] if
212+
!compacted_item.is_a?(Array) && (!@options[:compactArrays] || as_array)
213+
merge_compacted_value(nest_result, item_active_property, compacted_item)
214+
else
215+
# container does not include @graph or otherwise does not match one of the previous cases, redo compacted_item
216+
compacted_item = [compacted_item]
217+
al = context.compact_iri('@graph', vocab: true, quiet: true)
218+
compacted_item = {al => compacted_item}
219+
if expanded_item['@id']
220+
al = context.compact_iri('@id', vocab: true, quiet: true)
221+
compacted_item[al] = context.compact_iri(expanded_item['@id'], vocab: false, quiet: true).to_s
222+
end
223+
if expanded_item.has_key?('@index')
224+
key = context.compact_iri('@index', vocab: true, quiet: true)
225+
compacted_item[key] = expanded_item['@index']
226+
end
227+
compacted_item = [compacted_item] if !@options[:compactArrays] || as_array
228+
merge_compacted_value(nest_result, item_active_property, compacted_item)
229+
end
230+
elsif !(container & %w(@language @index @id @type)).empty? && !container.include?('@graph')
185231
map_object = nest_result[item_active_property] ||= {}
186232
compacted_item = case container
187-
when '@id'
233+
when %w(@id)
188234
id_prop = context.compact_iri('@id', vocab: true, quiet: true)
189235
map_key = compacted_item[id_prop]
190236
map_key = context.compact_iri(map_key, quiet: true)
191237
compacted_item.delete(id_prop)
192238
compacted_item
193-
when '@index'
194-
map_key = expanded_item[container]
239+
when %w(@index)
240+
map_key = expanded_item['@index']
195241
compacted_item
196-
when '@language'
197-
map_key = expanded_item[container]
242+
when %w(@language)
243+
map_key = expanded_item['@language']
198244
value?(expanded_item) ? expanded_item['@value'] : compacted_item
199-
when '@type'
245+
when %w(@type)
200246
type_prop = context.compact_iri('@type', vocab: true, quiet: true)
201247
map_key, *types = Array(compacted_item[type_prop])
202248
map_key = context.compact_iri(map_key, vocab: true, quiet: true)

0 commit comments

Comments
 (0)