# coding: utf-8 require_relative 'spec_helper' describe JSON::LD::API do let(:logger) {RDF::Spec.logger} describe ".frame" do { "exact @type match" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@type": "ex:Type1" }), input: %([ { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub2", "@type": "ex:Type2" } ]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1" }] }) }, "wildcard @type match" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@type": {} }), input: %([ { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub2", "@type": "ex:Type2" } ]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@id": "ex:Sub2", "@type": "ex:Type2" }] }) }, "match none @type match" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@type": [] }), input: %([ { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1", "ex:p": "Foo" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub2", "ex:p": "Bar" } ]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub2", "ex:p": "Bar" }] }) }, "multiple matches on @type" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@type": "ex:Type1" }), input: %([{ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub2", "@type": "ex:Type1" }, { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub3", "@type": ["ex:Type1", "ex:Type2"] }]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@id": "ex:Sub2", "@type": "ex:Type1" }, { "@id": "ex:Sub3", "@type": ["ex:Type1", "ex:Type2"] }] }) }, "single @id match" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1" }), input: %([ { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub2", "@type": "ex:Type2" } ]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1" }] }) }, "multiple @id match" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": ["ex:Sub1", "ex:Sub2"] }), input: %([ { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub2", "@type": "ex:Type2" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub3", "@type": "ex:Type3" } ]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@id": "ex:Sub2", "@type": "ex:Type2" }] }) }, "wildcard and match none" => { frame: %({ "@context": {"ex": "http://example.org/"}, "ex:p": [], "ex:q": {} }), input: %([ { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:q": "bar" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub2", "ex:p": "foo", "ex:q": "bar" } ]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": null, "ex:q": "bar" }] }) }, "match on any property if @requireAll is false" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@requireAll": false, "ex:p": {}, "ex:q": {} }), input: %([ { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": "foo" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub2", "ex:q": "bar" } ]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": "foo", "ex:q": null }, { "@id": "ex:Sub2", "ex:p": null, "ex:q": "bar" }] }) }, "match on defeaults if @requireAll is true and at least one property matches" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@requireAll": true, "ex:p": {"@default": "Foo"}, "ex:q": {"@default": "Bar"} }), input: %([ { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": "foo" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub2", "ex:q": "bar" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub3", "ex:p": "foo", "ex:q": "bar" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub4", "ex:r": "baz" } ]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": "foo", "ex:q": "Bar" }, { "@id": "ex:Sub2", "ex:p": "Foo", "ex:q": "bar" }, { "@id": "ex:Sub3", "ex:p": "foo", "ex:q": "bar" }] }) }, "match with @requireAll with one default" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@requireAll": true, "ex:p": {}, "ex:q": {"@default": "Bar"} }), input: %([ { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": "foo" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub2", "ex:q": "bar" }, { "@context": { "ex":"http://example.org/"}, "@id": "ex:Sub3", "ex:p": "foo", "ex:q": "bar" } ]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": "foo", "ex:q": "Bar" }, { "@id": "ex:Sub3", "ex:p": "foo", "ex:q": "bar" }] }) }, "implicitly includes unframed properties (default @explicit false)" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@type": "ex:Type1" }), input: %q({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1", "ex:prop1": "Property 1", "ex:prop2": {"@id": "ex:Obj1"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "ex:prop1": "Property 1", "ex:prop2": {"@id": "ex:Obj1"} }] }) }, "explicitly includes unframed properties @explicit false" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@explicit": false, "@type": "ex:Type1" }), input: %q({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1", "ex:prop1": "Property 1", "ex:prop2": {"@id": "ex:Obj1"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "ex:prop1": "Property 1", "ex:prop2": {"@id": "ex:Obj1"} }] }) }, "explicitly excludes unframed properties (@explicit: true)" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@explicit": true, "@type": "ex:Type1" }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1", "ex:prop1": "Property 1", "ex:prop2": {"@id": "ex:Obj1"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1" }] }) }, "non-existent framed properties create null property" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@type": "ex:Type1", "ex:null": [] }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1", "ex:prop1": "Property 1", "ex:prop2": {"@id": "ex:Obj1"} }), output: %({ "@context": { "ex": "http://example.org/" }, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "ex:prop1": "Property 1", "ex:prop2": { "@id": "ex:Obj1" }, "ex:null": null }] }) }, "non-existent framed properties create default property" => { frame: %({ "@context": { "ex": "http://example.org/", "ex:null": {"@container": "@set"} }, "@type": "ex:Type1", "ex:null": [{"@default": "foo"}] }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1", "ex:prop1": "Property 1", "ex:prop2": {"@id": "ex:Obj1"} }), output: %({ "@context": { "ex": "http://example.org/", "ex:null": {"@container": "@set"} }, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "ex:prop1": "Property 1", "ex:prop2": {"@id": "ex:Obj1"}, "ex:null": ["foo"] }] } ) }, "mixed content" => { frame: %({ "@context": {"ex": "http://example.org/"}, "ex:mixed": {"@embed": false} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:mixed": [ {"@id": "ex:Sub2"}, "literal1" ] }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:mixed": [ {"@id": "ex:Sub2"}, "literal1" ] }] }) }, "no embedding (@embed: false)" => { frame: %({ "@context": {"ex": "http://example.org/"}, "ex:embed": {"@embed": false} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:embed": { "@id": "ex:Sub2", "ex:prop": "property" } }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:embed": {"@id": "ex:Sub2"} }] }) }, "mixed list" => { frame: %({ "@context": {"ex": "http://example.org/"}, "ex:mixedlist": {} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1", "ex:mixedlist": { "@list": [ {"@id": "ex:Sub2", "@type": "ex:Type2"}, "literal1" ] } }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "ex:mixedlist": { "@list": [ {"@id": "ex:Sub2", "@type": "ex:Type2"}, "literal1" ] } }] }) }, "framed list" => { frame: %({ "@context": { "ex": "http://example.org/", "list": {"@id": "ex:list", "@container": "@list"} }, "list": [{"@type": "ex:Element"}] }), input: %({ "@context": { "ex": "http://example.org/", "list": {"@id": "ex:list", "@container": "@list"} }, "@id": "ex:Sub1", "@type": "ex:Type1", "list": [ {"@id": "ex:Sub2", "@type": "ex:Element"}, "literal1" ] }), output: %({ "@context": { "ex": "http://example.org/", "list": {"@id": "ex:list", "@container": "@list"} }, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "list": [ {"@id": "ex:Sub2", "@type": "ex:Element"}, "literal1" ] }] }) }, "presentation example" => { frame: %({ "@context": { "primaryTopic": { "@id": "http://xmlns.com/foaf/0.1/primaryTopic", "@type": "@id" }, "sameAs": { "@id": "http://www.w3.org/2002/07/owl#sameAs", "@type": "@id" } }, "primaryTopic": { "@type": "http://dbpedia.org/class/yago/Buzzwords", "sameAs": {} } }), input: %([{ "@id": "http://en.wikipedia.org/wiki/Linked_Data", "http://xmlns.com/foaf/0.1/primaryTopic": {"@id": "http://dbpedia.org/resource/Linked_Data"} }, { "@id": "http://www4.wiwiss.fu-berlin.de/flickrwrappr/photos/Linked_Data", "http://www.w3.org/2002/07/owl#sameAs": {"@id": "http://dbpedia.org/resource/Linked_Data"} }, { "@id": "http://dbpedia.org/resource/Linked_Data", "@type": "http://dbpedia.org/class/yago/Buzzwords", "http://www.w3.org/2002/07/owl#sameAs": {"@id": "http://rdf.freebase.com/ns/m/02r2kb1"} }, { "@id": "http://mpii.de/yago/resource/Linked_Data", "http://www.w3.org/2002/07/owl#sameAs": {"@id": "http://dbpedia.org/resource/Linked_Data"} } ]), output: %({ "@context": { "primaryTopic": {"@id": "http://xmlns.com/foaf/0.1/primaryTopic", "@type": "@id"}, "sameAs": {"@id": "http://www.w3.org/2002/07/owl#sameAs", "@type": "@id"} }, "@graph": [{ "@id": "http://en.wikipedia.org/wiki/Linked_Data", "primaryTopic": { "@id": "http://dbpedia.org/resource/Linked_Data", "@type": "http://dbpedia.org/class/yago/Buzzwords", "sameAs": "http://rdf.freebase.com/ns/m/02r2kb1" } }] }) }, "microdata manifest" => { frame: %({ "@context": { "xsd": "http://www.w3.org/2001/XMLSchema#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "mf": "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", "mq": "http://www.w3.org/2001/sw/DataAccess/tests/test-query#", "comment": "rdfs:comment", "entries": {"@id": "mf:entries", "@container": "@list"}, "name": "mf:name", "action": "mf:action", "data": {"@id": "mq:data", "@type": "@id"}, "query": {"@id": "mq:query", "@type": "@id"}, "result": {"@id": "mf:result", "@type": "xsd:boolean"} }, "@type": "mf:Manifest", "entries": [{ "@type": "mf:ManifestEntry", "action": { "@type": "mq:QueryTest" } }] }), input: %q({ "@context": { "md": "http://www.w3.org/ns/md#", "mf": "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", "mq": "http://www.w3.org/2001/sw/DataAccess/tests/test-query#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#" }, "@graph": [{ "@id": "_:manifest", "@type": "mf:Manifest", "mf:entries": {"@list": [{"@id": "_:entry"}]}, "rdfs:comment": "Positive processor tests" }, { "@id": "_:entry", "@type": "mf:ManifestEntry", "mf:action": {"@id": "_:query"}, "mf:name": "Test 0001", "mf:result": "true", "rdfs:comment": "Item with no itemtype and literal itemprop" }, { "@id": "_:query", "@type": "mq:QueryTest", "mq:data": {"@id": "http://www.w3.org/TR/microdata-rdf/tests/0001.html"}, "mq:query": {"@id": "http://www.w3.org/TR/microdata-rdf/tests/0001.ttl"} }] }), output: %({ "@context": { "xsd": "http://www.w3.org/2001/XMLSchema#", "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "mf": "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", "mq": "http://www.w3.org/2001/sw/DataAccess/tests/test-query#", "comment": "rdfs:comment", "entries": {"@id": "mf:entries","@container": "@list"}, "name": "mf:name", "action": "mf:action", "data": {"@id": "mq:data", "@type": "@id"}, "query": {"@id": "mq:query", "@type": "@id"}, "result": {"@id": "mf:result", "@type": "xsd:boolean"} }, "@type": "mf:Manifest", "comment": "Positive processor tests", "entries": [{ "@type": "mf:ManifestEntry", "action": { "@type": "mq:QueryTest", "data": "http://www.w3.org/TR/microdata-rdf/tests/0001.html", "query": "http://www.w3.org/TR/microdata-rdf/tests/0001.ttl" }, "comment": "Item with no itemtype and literal itemprop", "mf:result": "true", "name": "Test 0001" }] }), processingMode: 'json-ld-1.1' }, "library" => { frame: %({ "@context": { "dc": "http://purl.org/dc/elements/1.1/", "ex": "http://example.org/vocab#", "xsd": "http://www.w3.org/2001/XMLSchema#", "ex:contains": { "@type": "@id" } }, "@type": "ex:Library", "ex:contains": {} }), input: %({ "@context": { "dc": "http://purl.org/dc/elements/1.1/", "ex": "http://example.org/vocab#", "xsd": "http://www.w3.org/2001/XMLSchema#" }, "@id": "http://example.org/library", "@type": "ex:Library", "dc:name": "Library", "ex:contains": { "@id": "http://example.org/library/the-republic", "@type": "ex:Book", "dc:creator": "Plato", "dc:title": "The Republic", "ex:contains": { "@id": "http://example.org/library/the-republic#introduction", "@type": "ex:Chapter", "dc:description": "An introductory chapter on The Republic.", "dc:title": "The Introduction" } } }), output: %({ "@context": { "dc": "http://purl.org/dc/elements/1.1/", "ex": "http://example.org/vocab#", "xsd": "http://www.w3.org/2001/XMLSchema#", "ex:contains": { "@type": "@id" } }, "@graph": [ { "@id": "http://example.org/library", "@type": "ex:Library", "dc:name": "Library", "ex:contains": { "@id": "http://example.org/library/the-republic", "@type": "ex:Book", "dc:creator": "Plato", "dc:title": "The Republic", "ex:contains": { "@id": "http://example.org/library/the-republic#introduction", "@type": "ex:Chapter", "dc:description": "An introductory chapter on The Republic.", "dc:title": "The Introduction" } } } ] }) } }.each do |title, params| it title do do_frame(params) end end describe "@reverse" do { "embed matched frames with @reverse" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@type": "ex:Type1", "@reverse": {"ex:includes": {}} }), input: %([{ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub2", "@type": "ex:Type2", "ex:includes": {"@id": "ex:Sub1"} }]), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "@reverse": { "ex:includes": { "@id": "ex:Sub2", "@type": "ex:Type2", "ex:includes": { "@id": "ex:Sub1" } } } }] }) }, "embed matched frames with reversed property" => { frame: %({ "@context": { "ex": "http://example.org/", "excludes": {"@reverse": "ex:includes"} }, "@type": "ex:Type1", "excludes": {} }), input: %([{ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "@type": "ex:Type1" }, { "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub2", "@type": "ex:Type2", "ex:includes": {"@id": "ex:Sub1"} }]), output: %({ "@context": { "ex": "http://example.org/", "excludes": {"@reverse": "ex:includes"} }, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "excludes": { "@id": "ex:Sub2", "@type": "ex:Type2", "ex:includes": {"@id": "ex:Sub1"} } }] }) }, }.each do |title, params| it title do begin input, frame, output = params[:input], params[:frame], params[:output] input = ::JSON.parse(input) if input.is_a?(String) frame = ::JSON.parse(frame) if frame.is_a?(String) output = ::JSON.parse(output) if output.is_a?(String) jld = JSON::LD::API.frame(input, frame, logger: logger) expect(jld).to produce_jsonld(output, logger) rescue JSON::LD::JsonLdError => e fail("#{e.class}: #{e.message}\n" + "#{logger}\n" + "Backtrace:\n#{e.backtrace.join("\n")}") end end end end describe "node pattern" do { "matches a deep node pattern" => { frame: %({ "@context": {"ex": "http://example.org/"}, "ex:p": { "ex:q": {} } }), input: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "ex:p": { "@id": "ex:Sub2", "@type": "ex:Type2", "ex:q": "foo" } }, { "@id": "ex:Sub3", "@type": "ex:Type1", "ex:q": { "@id": "ex:Sub4", "@type": "ex:Type2", "ex:r": "bar" } }] }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "@type": "ex:Type1", "ex:p": { "@id": "ex:Sub2", "@type": "ex:Type2", "ex:q": "foo" } }] }) }, }.each do |title, params| it title do do_frame(params) end end end describe "value pattern" do { "matches exact values" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }] }) }, "matches wildcard @value" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": {"@value": {}}, "ex:q": {"@value": {}, "@type": "ex:q"}, "ex:r": {"@value": {}, "@language": "r"} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }] }) }, "matches wildcard @type" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:q": {"@value": "Q", "@type": {}} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:q": {"@value": "Q", "@type": "ex:q"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:q": {"@value": "Q", "@type": "ex:q"} }] }) }, "matches wildcard @language" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:r": {"@value": "R", "@language": {}} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:r": {"@value": "R", "@language": "r"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:r": {"@value": "R", "@language": "r"} }] }) }, "match none @type" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": {"@value": {}, "@type": []}, "ex:q": {"@value": {}, "@type": "ex:q"}, "ex:r": {"@value": {}, "@language": "r"} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }] }) }, "match none @language" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": {"@value": {}, "@language": []}, "ex:q": {"@value": {}, "@type": "ex:q"}, "ex:r": {"@value": {}, "@language": "r"} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }] }) }, "matches some @value" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": {"@value": ["P", "Q", "R"]}, "ex:q": {"@value": ["P", "Q", "R"], "@type": "ex:q"}, "ex:r": {"@value": ["P", "Q", "R"], "@language": "r"} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }] }) }, "matches some @type" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:q": {"@value": "Q", "@type": ["ex:q", "ex:Q"]} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:q": {"@value": "Q", "@type": "ex:q"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:q": {"@value": "Q", "@type": "ex:q"} }] }) }, "matches some @language" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:r": {"@value": "R", "@language": ["p", "q", "r"]} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:r": {"@value": "R", "@language": "r"} }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:r": {"@value": "R", "@language": "r"} }] }) }, "excludes non-matched values" => { frame: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": {"@value": {}}, "ex:q": {"@value": {}, "@type": "ex:q"}, "ex:r": {"@value": {}, "@language": "R"} }), input: %({ "@context": {"ex": "http://example.org/"}, "@id": "ex:Sub1", "ex:p": ["P", {"@value": "P", "@type": "ex:p"}, {"@value": "P", "@language": "P"}], "ex:q": ["Q", {"@value": "Q", "@type": "ex:q"}, {"@value": "Q", "@language": "Q"}], "ex:r": ["R", {"@value": "R", "@type": "ex:r"}, {"@value": "R", "@language": "R"}] }), output: %({ "@context": {"ex": "http://example.org/"}, "@graph": [{ "@id": "ex:Sub1", "ex:p": "P", "ex:q": {"@value": "Q", "@type": "ex:q"}, "ex:r": {"@value": "R", "@language": "r"} }] }) }, }.each do |title, params| it title do do_frame(params) end end end describe "named graphs" do { "Merge graphs if no outer @graph is used" => { frame: %({ "@context": {"@vocab": "urn:"}, "@type": "Class" }), input: %({ "@context": {"@vocab": "urn:"}, "@id": "urn:id-1", "@type": "Class", "preserve": { "@graph": { "@id": "urn:id-2", "term": "data" } } }), output: %({ "@context": {"@vocab": "urn:"}, "@id": "urn:id-1", "@type": "Class", "preserve": {} }), processingMode: 'json-ld-1.1' }, "Frame default graph if outer @graph is used" => { frame: %({ "@context": {"@vocab": "urn:"}, "@type": "Class", "@graph": {} }), input: %({ "@context": {"@vocab": "urn:"}, "@id": "urn:id-1", "@type": "Class", "preserve": { "@id": "urn:gr-1", "@graph": { "@id": "urn:id-2", "term": "data" } } }), output: %({ "@context": {"@vocab": "urn:"}, "@id": "urn:id-1", "@type": "Class", "preserve": { "@id": "urn:gr-1", "@graph": { "@id": "urn:id-2", "term": "data" } } }), processingMode: 'json-ld-1.1' }, "Merge one graph and preserve another" => { frame: %({ "@context": {"@vocab": "urn:"}, "@type": "Class", "preserve": { "@graph": {} } }), input: %({ "@context": {"@vocab": "urn:"}, "@id": "urn:id-1", "@type": "Class", "merge": { "@id": "urn:id-2", "@graph": { "@id": "urn:id-2", "term": "foo" } }, "preserve": { "@id": "urn:graph-1", "@graph": { "@id": "urn:id-3", "term": "bar" } } }), output: %({ "@context": {"@vocab": "urn:"}, "@id": "urn:id-1", "@type": "Class", "merge": { "@id": "urn:id-2", "term": "foo" }, "preserve": { "@id": "urn:graph-1", "@graph": { "@id": "urn:id-3", "term": "bar" } } }), processingMode: 'json-ld-1.1' }, "Merge one graph and deep preserve another" => { frame: %({ "@context": {"@vocab": "urn:"}, "@type": "Class", "preserve": { "deep": { "@graph": {} } } }), input: %({ "@context": {"@vocab": "urn:"}, "@id": "urn:id-1", "@type": "Class", "merge": { "@id": "urn:id-2", "@graph": { "@id": "urn:id-2", "term": "foo" } }, "preserve": { "deep": { "@graph": { "@id": "urn:id-3", "term": "bar" } } } }), output: %({ "@context": {"@vocab": "urn:"}, "@id": "urn:id-1", "@type": "Class", "merge": { "@id": "urn:id-2", "term": "foo" }, "preserve": { "deep": { "@graph": { "@id": "urn:id-3", "term": "bar" } } } }), processingMode: 'json-ld-1.1' }, "library" => { frame: %({ "@context": {"@vocab": "http://example.org/"}, "@type": "Library", "contains": { "@id": "http://example.org/graphs/books", "@graph": {"@type": "Book"} } }), input: %({ "@context": {"@vocab": "http://example.org/"}, "@id": "http://example.org/library", "@type": "Library", "name": "Library", "contains": { "@id": "http://example.org/graphs/books", "@graph": { "@id": "http://example.org/library/the-republic", "@type": "Book", "creator": "Plato", "title": "The Republic", "contains": { "@id": "http://example.org/library/the-republic#introduction", "@type": "Chapter", "description": "An introductory chapter on The Republic.", "title": "The Introduction" } } } }), output: %({ "@context": {"@vocab": "http://example.org/"}, "@id": "http://example.org/library", "@type": "Library", "name": "Library", "contains": { "@id": "http://example.org/graphs/books", "@graph": { "@id": "http://example.org/library/the-republic", "@type": "Book", "creator": "Plato", "title": "The Republic", "contains": { "@id": "http://example.org/library/the-republic#introduction", "@type": "Chapter", "description": "An introductory chapter on The Republic.", "title": "The Introduction" } } } }), processingMode: 'json-ld-1.1' } }.each do |title, params| it title do do_frame(params) end end end end describe "prune blank nodes" do it "preserves single-use bnode identifiers if @version 1.0" do do_frame( input: %({ "@context": { "dc0": "http://purl.org/dc/terms/", "dc:creator": { "@type": "@id" }, "foaf": "http://xmlns.com/foaf/0.1/", "ps": "http://purl.org/payswarm#" }, "@id": "http://example.com/asset", "@type": "ps:Asset", "dc:creator": { "foaf:name": "John Doe" } }), frame: %({ "@context": { "dc": "http://purl.org/dc/terms/", "dc:creator": { "@type": "@id" }, "foaf": "http://xmlns.com/foaf/0.1/", "ps": "http://purl.org/payswarm#" }, "@id": "http://example.com/asset", "@type": "ps:Asset", "dc:creator": {} }), output: %({ "@context": { "dc": "http://purl.org/dc/terms/", "dc:creator": { "@type": "@id" }, "foaf": "http://xmlns.com/foaf/0.1/", "ps": "http://purl.org/payswarm#" }, "@graph": [ { "@id": "http://example.com/asset", "@type": "ps:Asset", "dc:creator": { "@id": "_:b0", "foaf:name": "John Doe" } } ] }) ) end end context "problem cases" do it "pr #20" do expanded = %([ { "@id": "_:gregg", "@type": "http://xmlns.com/foaf/0.1/Person", "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg" }, { "@id": "http://manu.sporny.org/#me", "@type": "http://xmlns.com/foaf/0.1/Person", "http://xmlns.com/foaf/0.1/knows": {"@id": "_:gregg"}, "http://xmlns.com/foaf/0.1/name": "Manu Sporny" } ]) expected = %({ "@graph": [ { "@id": "_:b0", "@type": "http://xmlns.com/foaf/0.1/Person", "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg" }, { "@id": "http://manu.sporny.org/#me", "@type": "http://xmlns.com/foaf/0.1/Person", "http://xmlns.com/foaf/0.1/knows": { "@id": "_:b0", "@type": "http://xmlns.com/foaf/0.1/Person", "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg" }, "http://xmlns.com/foaf/0.1/name": "Manu Sporny" } ] }) do_frame(input: expanded, frame: {}, output: expected) end it "issue #28" do input = %({ "@context": { "rdfs": "http://www.w3.org/2000/01/rdf-schema#" }, "@id": "http://www.myresource/uuid", "http://www.myresource.com/ontology/1.0#talksAbout": [ { "@id": "http://rdf.freebase.com/ns/m.018w8", "rdfs:label": [ { "@value": "Basketball", "@language": "en" } ] } ] }) frame = %({ "@context": { "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "talksAbout": { "@id": "http://www.myresource.com/ontology/1.0#talksAbout", "@type": "@id" }, "label": { "@id": "rdfs:label", "@language": "en" } }, "@id": "http://www.myresource/uuid" }) expected = %({ "@context": { "rdfs": "http://www.w3.org/2000/01/rdf-schema#", "talksAbout": { "@id": "http://www.myresource.com/ontology/1.0#talksAbout", "@type": "@id" }, "label": { "@id": "rdfs:label", "@language": "en" } }, "@graph": [ { "@id": "http://www.myresource/uuid", "talksAbout": { "@id": "http://rdf.freebase.com/ns/m.018w8", "label": "Basketball" } } ] }) do_frame(input: input, frame: frame, output: expected) end it "framing with @version: 1.1 prunes identifiers" do input = %({ "@context": { "@version": 1.1, "@vocab": "https://example.com#", "ex": "http://example.org/", "claim": { "@id": "ex:claim", "@container": "@graph" }, "id": "@id" }, "claim": { "id": "ex:1", "test": "foo" } }) frame = %({ "@context": { "@version": 1.1, "@vocab": "https://example.com#", "ex": "http://example.org/", "claim": { "@id": "ex:claim", "@container": "@graph" }, "id": "@id" }, "claim": {} }) expected = %({ "@context": { "@version": 1.1, "@vocab": "https://example.com#", "ex": "http://example.org/", "claim": { "@id": "ex:claim", "@container": "@graph" }, "id": "@id" }, "claim": { "id": "ex:1", "test": "foo" } }) do_frame(input: input, frame: frame, output: expected, processingMode: 'json-ld-1.1') end it "PR #663" do input = %({ "@context": { "@vocab": "http://example.com/", "loves": { "@type": "@id" }, "unionOf": { "@type": "@id", "@id": "owl:unionOf", "@container": "@list" }, "Class": "owl:Class" }, "@graph": [ { "@type": "Act", "@graph": [ { "@id": "Romeo", "@type": "Person" }, { "@id": "Juliet", "@type": "Person" } ] }, { "@id": "ActTwo", "@type": "Act", "@graph": [ { "@id": "Romeo", "@type": "Person", "loves": "Juliet" }, { "@id": "Juliet", "@type": "Person", "loves": "Romeo" } ] }, { "@id": "Person", "@type": "Class", "unionOf": { "@list": [ { "@id": "Montague", "@type": "Class" }, { "@id": "Capulet", "@type": "Class" } ] } } ] }) frame = %({ "@context": { "@vocab": "http://example.com/", "loves": { "@type": "@id" }, "unionOf": { "@type": "@id", "@id": "owl:unionOf", "@container": "@list" }, "Class": "owl:Class" }, "@graph": [ { "@explicit": false, "@embed": "@last", "@type": [ "Act", "Class" ], "@graph": [{ "@explicit": true, "@embed": "@always", "@type": "Person", "@id": {}, "loves": {"@embed": "@never"} }] } ] }) expected = %({ "@context": { "@vocab": "http://example.com/", "loves": { "@type": "@id" }, "unionOf": { "@type": "@id", "@id": "owl:unionOf", "@container": "@list" }, "Class": "owl:Class" }, "@graph": [ { "@graph": [ { "@id": "Juliet", "@type": "Person", "loves": "Romeo" }, { "@id": "Romeo", "@type": "Person", "loves": "Juliet" } ], "@id": "ActTwo", "@type": "Act" }, { "@id": "Capulet", "@type": "Class" }, { "@id": "Montague", "@type": "Class" }, { "@id": "Person", "@type": "Class", "unionOf": [ { "@id": "Montague", "@type": "Class" }, { "@id": "Capulet", "@type": "Class" } ] }, { "@graph": [ { "@id": "Juliet", "@type": "Person", "loves": null }, { "@id": "Romeo", "@type": "Person", "loves": null } ], "@type": "Act" } ] }) do_frame(input: input, frame: frame, output: expected, processingMode: 'json-ld-1.1') end end def do_frame(params) begin input, frame, output, processingMode = params[:input], params[:frame], params[:output], params.fetch(:processingMode, 'json-ld-1.0') input = ::JSON.parse(input) if input.is_a?(String) frame = ::JSON.parse(frame) if frame.is_a?(String) output = ::JSON.parse(output) if output.is_a?(String) jld = JSON::LD::API.frame(input, frame, logger: logger, processingMode: processingMode) expect(jld).to produce_jsonld(output, logger) # Compare expanded jld/output too to make sure list values remain ordered exp_jld = JSON::LD::API.expand(jld, processingMode: 'json-ld-1.1') exp_output = JSON::LD::API.expand(output, processingMode: 'json-ld-1.1') expect(exp_jld).to produce_jsonld(exp_output, logger) rescue JSON::LD::JsonLdError => e fail("#{e.class}: #{e.message}\n" + "#{logger}\n" + "Backtrace:\n#{e.backtrace.join("\n")}") end end end