From 0644711a311b01d4cf7d815a5cc94d2c6e474314 Mon Sep 17 00:00:00 2001 From: Marcel Otto Date: Thu, 24 Nov 2016 08:44:07 +0100 Subject: [PATCH] core: Description.new, .add and .put accept a Map with convertible RDF terms --- lib/rdf/description.ex | 19 +++++++++++++++ test/unit/description_test.exs | 43 ++++++++++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/lib/rdf/description.ex b/lib/rdf/description.ex index bb1bd8d..cf1debf 100644 --- a/lib/rdf/description.ex +++ b/lib/rdf/description.ex @@ -31,6 +31,8 @@ defmodule RDF.Description do do: new(subject) |> add(predicate, objects) def new(subject, description = %RDF.Description{}), do: new(subject) |> add(description) + def new(subject, predications = %{}), + do: new(subject) |> add(predications) @doc """ @@ -89,6 +91,13 @@ defmodule RDF.Description do %RDF.Description{subject: subject, predications: merged_predications} end + def add(description = %RDF.Description{}, predications = %{}) do + Enum.reduce predications, description, fn ({predicate, objects}, description) -> + add(description, predicate, objects) + end + end + + @doc """ Puts objects to a predicate of a `RDF.Description`, overwriting all existing objects. @@ -126,6 +135,9 @@ defmodule RDF.Description do iex> RDF.Description.new({EX.S, EX.P, EX.O1}) |> ...> RDF.Description.put(RDF.Description.new(EX.S, EX.P, [EX.O1, EX.O2])) RDF.Description.new([{EX.S, EX.P, EX.O1}, {EX.S, EX.P, EX.O2}]) + iex> RDF.Description.new([{EX.S, EX.P1, EX.O1}, {EX.S, EX.P2, EX.O2}]) |> + ...> RDF.Description.put(%{EX.P2 => [EX.O3, EX.O4]}) + RDF.Description.new([{EX.S, EX.P1, EX.O1}, {EX.S, EX.P2, EX.O3}, {EX.S, EX.P2, EX.O4}]) """ def put(description, statements) @@ -161,6 +173,13 @@ defmodule RDF.Description do %RDF.Description{subject: subject, predications: merged_predications} end + def put(description = %RDF.Description{}, predications = %{}) do + Enum.reduce predications, description, fn ({predicate, objects}, description) -> + put(description, predicate, objects) + end + end + + @doc """ Fetches the objects for the given predicate of a Description. diff --git a/test/unit/description_test.exs b/test/unit/description_test.exs index b4a69c7..16bcd68 100644 --- a/test/unit/description_test.exs +++ b/test/unit/description_test.exs @@ -11,6 +11,7 @@ defmodule RDF.DescriptionTest do def description, do: Description.new(EX.Subject) + def description(content), do: Description.add(description, content) def description_of_subject(%Description{subject: subject}, subject), do: true def description_of_subject(_, _), do: false def empty_description(%Description{predications: predications}) do @@ -73,6 +74,13 @@ defmodule RDF.DescriptionTest do assert description_includes_predication(desc2, {EX.predicate, uri(EX.Object)}) end + test "creating a description from a map with convertible RDF term" do + desc = Description.new(EX.Subject, %{EX.Predicate => EX.Object}) + assert description_of_subject(desc, uri(EX.Subject)) + assert description_includes_predication(desc, {uri(EX.Predicate), uri(EX.Object)}) + end + + describe "add" do test "a predicate-object-pair of proper RDF terms" do assert Description.add(description, EX.predicate, uri(EX.Object)) @@ -146,10 +154,7 @@ defmodule RDF.DescriptionTest do test "another description" do - desc = - description - |> Description.add([{EX.predicate1, EX.Object1}, - {EX.predicate2, EX.Object2}]) + desc = description([{EX.predicate1, EX.Object1}, {EX.predicate2, EX.Object2}]) |> Description.add(Description.new({EX.Other, EX.predicate3, EX.Object3})) assert description_of_subject(desc, uri(EX.Subject)) @@ -164,6 +169,36 @@ defmodule RDF.DescriptionTest do assert description_includes_predication(desc, {EX.predicate1, uri(EX.Object4)}) end + test "a map of predications with convertible RDF terms" do + desc = description([{EX.predicate1, EX.Object1}, {EX.predicate2, EX.Object2}]) + |> Description.add(%{EX.predicate3 => EX.Object3}) + + assert description_of_subject(desc, uri(EX.Subject)) + assert description_includes_predication(desc, {EX.predicate1, uri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate2, uri(EX.Object2)}) + assert description_includes_predication(desc, {EX.predicate3, uri(EX.Object3)}) + + desc = Description.add(desc, %{EX.predicate1 => EX.Object1, + EX.predicate2 => [EX.Object2, 42], + EX.predicate3 => [bnode(:foo)]}) + assert Description.count(desc) == 5 + assert description_includes_predication(desc, {EX.predicate1, uri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate2, uri(EX.Object2)}) + assert description_includes_predication(desc, {EX.predicate2, literal(42)}) + assert description_includes_predication(desc, {EX.predicate3, uri(EX.Object3)}) + assert description_includes_predication(desc, {EX.predicate3, bnode(:foo)}) + end + + test "a map of predications with inconvertible RDF terms" do + assert_raise RDF.InvalidURIError, fn -> + Description.add(description, %{"not a URI" => uri(EX.Object)}) + end + + assert_raise RDF.InvalidLiteralError, fn -> + Description.add(description, %{EX.prop => self}) + end + end + test "duplicates are ignored" do desc = Description.add(description, {EX.predicate, EX.Object}) assert Description.add(desc, {EX.predicate, EX.Object}) == desc