diff --git a/lib/json/ld/compact.rb b/lib/json/ld/compact.rb index a9f8e4f4..202f0649 100644 --- a/lib/json/ld/compact.rb +++ b/lib/json/ld/compact.rb @@ -145,10 +145,32 @@ def compact(element, property: nil) end end - if %w(@language @index).include?(container) + if %w(@language @index @id @type).include?(container) map_object = result[item_active_property] ||= {} - compacted_item = compacted_item['@value'] if container == '@language' && value?(compacted_item) - map_key = expanded_item[container] + compacted_item = case container + when '@id' + id_prop = context.compact_iri('@id', vocab: true, quiet: true) + map_key = compacted_item[id_prop] + compacted_item.delete(id_prop) + compacted_item + when '@index' + index_prop = context.compact_iri('@index', vocab: true, quiet: true) + map_key = expanded_item[container] + #compacted_item.delete(index_prop) + compacted_item + when '@language' + map_key = expanded_item[container] + value?(expanded_item) ? expanded_item['@value'] : compacted_item + when '@type' + type_prop = context.compact_iri('@type', vocab: true, quiet: true) + map_key, types = Array(compacted_item[type_prop]) + if Array(types).empty? + compacted_item.delete(type_prop) + else + compacted_item[type_prop] = types + end + compacted_item + end merge_compacted_value(map_object, map_key, compacted_item) else compacted_item = [compacted_item] if diff --git a/lib/json/ld/context.rb b/lib/json/ld/context.rb index d83cfa6b..52b276b3 100644 --- a/lib/json/ld/context.rb +++ b/lib/json/ld/context.rb @@ -36,7 +36,7 @@ class TermDefinition # @return [String] Type mapping attr_accessor :type_mapping - # @return [String] Container mapping + # @return ['@index', '@language', '@index', '@set', '@type', '@id'] Container mapping attr_accessor :container_mapping # Language mapping of term, `false` is used if there is explicitly no language mapping for this term. @@ -62,7 +62,7 @@ def simple?; simple; end # @param [String] term # @param [String] id # @param [String] type_mapping Type mapping - # @param [String] container_mapping + # @param ['@index', '@language', '@index', '@set', '@type', '@id'] container_mapping # @param [String] language_mapping # Language mapping of term, `false` is used if there is explicitly no language mapping for this term # @param [Boolean] reverse_property @@ -957,16 +957,10 @@ def compact_iri(iri, value: nil, vocab: nil, reverse: false, quiet: false, **opt containers = [] tl, tl_value = "@language", "@null" - # If the value is a JSON Object, then for the keywords @index, @id, and @type along with the compacted version of all non-keyword properties of the object in order, if the value contains that property, append it to containers. - if value.is_a?(Hash) - %w(@index @id @type).each do |kw| - containers << kw if value.has_key?(kw) - end - containers.concat value.keys. - reject {|k| k.start_with?('@')}. - sort. - map {|k| compact_iri(k, vocab: true, quite: true)} - end + # If the value is a JSON Object, then for the keywords @index, @id, and @type, if the value contains that keyword, append it to containers. + %w(@index @id @type).each do |kw| + containers << kw if value.has_key?(kw) + end if value.is_a?(Hash) if reverse tl, tl_value = "@type", "@reverse" @@ -1503,25 +1497,6 @@ def check_container(container, local_context, defined, term) case container when '@set', '@list', '@language', '@index', '@type', '@id', nil # Okay - when /^@/ - raise JsonLdError::InvalidContainerMapping, - "unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" - when String - expanded = expand_iri(container, - vocab: true, - documentRelative: false, - local_context: local_context, - defined: defined) - case expanded - when RDF::URI - raise JsonLdError::InvalidContainerMapping, - "unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" unless - expanded.absolute? - else - raise JsonLdError::InvalidContainerMapping, - "unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" unless - container.absolute? - end else raise JsonLdError::InvalidContainerMapping, "unknown mapping for '@container' to #{container.inspect} on term #{term.inspect}" diff --git a/lib/json/ld/expand.rb b/lib/json/ld/expand.rb index 43554a66..8e275bdc 100644 --- a/lib/json/ld/expand.rb +++ b/lib/json/ld/expand.rb @@ -273,7 +273,7 @@ def expand(input, active_property, context, ordered: true) end ary - elsif container && !%w(@set @list @language).include?(container) && value.is_a?(Hash) + elsif %w(@index @id @type).include?(container) && value.is_a?(Hash) # 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: # Set ary to an empty array. @@ -289,16 +289,6 @@ def expand(input, active_property, context, ordered: true) when '@id', '@index' then item[container] ||= k # If container is @type add the key-value pair (@type-[index]) to item, appending any existing values in item when '@type' then item[container] = [k].concat(Array(item[container])) - else - #require 'byebug'; byebug - # Otherwise container is an IRI or Blank Node - # Expand index using the Value Expansion algorithm - prop = active_context.expand_iri(container, vocab: true).to_s - item_value = active_context.expand_value(container, k, log_depth: @options[:log_depth]) - # add the key-value pair (container-[{"@id": index}]) to item, appending any existing values in item - values = item[prop] - values = [values].compact unless values.is_a?(Array) - item[prop] = [item_value].concat(values) end # Append item to expanded value. diff --git a/spec/compact_spec.rb b/spec/compact_spec.rb index fd6a0592..6681b562 100644 --- a/spec/compact_spec.rb +++ b/spec/compact_spec.rb @@ -406,7 +406,46 @@ end end - context "language maps" do + context "@container: @index" do + { + "compact-0029" => { + input: %([{ + "@id": "http://example.com/article", + "http://example.com/vocab/author": [{ + "@id": "http://example.org/person/1", + "@index": "regular" + }, { + "@id": "http://example.org/guest/cd24f329aa", + "@index": "guest" + }] + }]), + context: %({ + "author": {"@id": "http://example.com/vocab/author", "@container": "@index" } + }), + output: %({ + "@context": { + "author": { + "@id": "http://example.com/vocab/author", + "@container": "@index" + } + }, + "@id": "http://example.com/article", + "author": { + "regular": { + "@id": "http://example.org/person/1" + }, + "guest": { + "@id": "http://example.org/guest/cd24f329aa" + } + } + }) + }, + }.each_pair do |title, params| + it(title) {run_compact(params)} + end + end + + context "@container: @language" do { "compact-0024" => { input: %([ @@ -440,6 +479,114 @@ end end + context "@container: @id" do + { + "Indexes to object not having an @id" => { + input: %([{ + "http://example/idmap": [ + {"http://example/label": [{"@value": "Object with @id _:bar"}], "@id": "_:bar"}, + {"http://example/label": [{"@value": "Object with @id "}], "@id": "http://example.org/foo"} + ] + }]), + context: %({ + "@vocab": "http://example/", + "idmap": {"@container": "@id"} + }), + output: %({ + "@context": { + "@vocab": "http://example/", + "idmap": {"@container": "@id"} + }, + "idmap": { + "http://example.org/foo": {"label": "Object with @id "}, + "_:bar": {"label": "Object with @id _:bar"} + } + }), + }, + "Indexes to object already having an @id" => { + input: %([{ + "http://example/idmap": [ + {"@id": "_:foo", "http://example/label": [{"@value": "Object with @id _:bar"}]}, + {"@id": "http://example.org/bar", "http://example/label": [{"@value": "Object with @id "}]} + ] + }]), + context: %({ + "@vocab": "http://example/", + "idmap": {"@container": "@id"} + }), + output: %({ + "@context": { + "@vocab": "http://example/", + "idmap": {"@container": "@id"} + }, + "idmap": { + "_:foo": {"label": "Object with @id _:bar"}, + "http://example.org/bar": {"label": "Object with @id "} + } + }), + }, + }.each_pair do |title, params| + it(title) {run_compact(params)} + end + end + + context "@container: @type" do + { + "Indexes to object not having an @type" => { + input: %([{ + "http://example/typemap": [ + {"http://example/label": [{"@value": "Object with @type _:bar"}], "@type": ["_:bar"]}, + {"http://example/label": [{"@value": "Object with @type "}], "@type": ["http://example.org/foo"]} + ] + }]), + context: %({ + "@vocab": "http://example/", + "typemap": {"@container": "@type"} + }), + output: %({ + "@context": { + "@vocab": "http://example/", + "typemap": {"@container": "@type"} + }, + "typemap": { + "http://example.org/foo": {"label": "Object with @type "}, + "_:bar": {"label": "Object with @type _:bar"} + } + }) + }, + "Indexes to object already having an @type" => { + input: %([{ + "http://example/typemap": [ + { + "@type": ["_:bar", "_:foo"], + "http://example/label": [{"@value": "Object with @type _:bar"}] + }, + { + "@type": ["http://example.org/foo", "http://example.org/bar"], + "http://example/label": [{"@value": "Object with @type "}] + } + ] + }]), + context: %({ + "@vocab": "http://example/", + "typemap": {"@container": "@type"} + }), + output: %({ + "@context": { + "@vocab": "http://example/", + "typemap": {"@container": "@type"} + }, + "typemap": { + "http://example.org/foo": {"@type": "http://example.org/bar", "label": "Object with @type "}, + "_:bar": {"@type": "_:foo", "label": "Object with @type _:bar"} + } + }) + }, + }.each_pair do |title, params| + it(title) {run_compact(params)} + end + end + context "@graph" do { "Uses @graph given mutliple inputs" => { diff --git a/spec/context_spec.rb b/spec/context_spec.rb index 94e5734a..1fd6f11f 100644 --- a/spec/context_spec.rb +++ b/spec/context_spec.rb @@ -1320,8 +1320,7 @@ def containers "language" => {"@id" => "ex:language", "@container" => "@language"}, "ndx" => {"@id" => "ex:ndx", "@container" => "@index"}, "id" => {"@id" => "ex:id", "@container" => "@id"}, - "type" => {"@id" => "ex:type", "@container" => "@type"}, - 'uri' => {"@id" => "ex:uri", "@container" => "ex:uri"} + "type" => {"@id" => "ex:type", "@container" => "@type"} }) logger.clear ctx @@ -1335,7 +1334,6 @@ def containers "ndx" => "@index", "id" => "@id", "type" => "@type", - 'uri' => "ex:uri", }.each do |defn, container| expect(subject.container(subject.term_definitions[defn])).to eq container end @@ -1350,7 +1348,6 @@ def containers "ndx" => "@index", "id" => "@id", "type" => "@type", - 'uri' => "ex:uri", }.each do |defn, container| expect(subject.container(defn)).to eq container end diff --git a/spec/expand_spec.rb b/spec/expand_spec.rb index fc1330c0..18f0a101 100644 --- a/spec/expand_spec.rb +++ b/spec/expand_spec.rb @@ -698,7 +698,7 @@ end end - context "@container @id" do + context "@container: @id" do { "Adds @id to object not having an @id" => { input: %({ @@ -741,7 +741,7 @@ end end - context "@container @type" do + context "@container: @type" do { "Adds @type to object not having an @type" => { input: %({ @@ -791,83 +791,6 @@ end end - context "@container IRI" do - { - "Adds property to object not having property" => { - input: %({ - "@context": { - "@vocab": "http://example/", - "irimap": {"@container": "prop"}, - "prop": {"@type": "@id"} - }, - "irimap": { - "http://example.org/foo": {"label": "Object with prop "} - } - }), - output: %([{ - "http://example/irimap": [ - { - "http://example/label": [{"@value": "Object with prop "}], - "http://example/prop": [{"@id": "http://example.org/foo"}] - } - ] - }]) - }, - "Prepends property in object already having an property" => { - input: %({ - "@context": { - "@vocab": "http://example/", - "irimap": {"@container": "prop"}, - "prop": {"@type": "@id"} - }, - "irimap": { - "http://example.org/foo": {"prop": "http://example.org/bar", "label": "Object with prop "}, - "_:bar": {"prop": "_:foo", "label": "Object with prop _:bar"} - } - }), - output: %([{ - "http://example/irimap": [ - { - "http://example/label": [{"@value": "Object with prop _:bar"}], - "http://example/prop": [{"@id": "_:bar"}, {"@id": "_:foo"}] - }, - { - "http://example/label": [{"@value": "Object with prop "}], - "http://example/prop": [{"@id": "http://example.org/foo"}, {"@id": "http://example.org/bar"}] - } - ] - } - ]) - }, - "Adds literal property" => { - input: %({ - "@context": { - "@vocab": "http://example/", - "irimap": {"@container": "prop"} - }, - "irimap": { - "foo": {"label": "Object with prop 'foo'"}, - "bar": {"label": "Object with prop 'bar'"} - } - }), - output: %([{ - "http://example/irimap": [ - { - "http://example/label": [{"@value": "Object with prop 'bar'"}], - "http://example/prop": [{"@value": "bar"}] - }, - { - "http://example/label": [{"@value": "Object with prop 'foo'"}], - "http://example/prop": [{"@value": "foo"}] - } - ] - }]) - }, - }.each do |title, params| - it(title) {run_expand params} - end - end - context "scoped context" do { "adding new term" => {