diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d9c780..b883c32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,11 @@ are specified. of overwriting only statements with the same subject and predicate, which was almost never the expected behaviour. This is fixed now by relying on the new `put/2` behaviour. +- the `values/2` functions of `RDF.Statement`, `RDF.Triple`, `RDF.Quad`, `RDF.Description`, + `RDF.Graph` and `RDF.Dataset` now accept on their second argument an optional + `RDF.PropertyMap`which will be used to map predicates accordingly; the variant of + these `values/2` functions to provide a custom mapping function was extracted into + a new function `map/2` on all of these modules - for consistency reasons the internal `:id` struct field of `RDF.BlankNode` was renamed to `:value` - allow the `base_iri` of `RDF.Vocabulary.Namespace`s to end with a `.` to support diff --git a/lib/rdf/data.ex b/lib/rdf/data.ex index 4684b5b..b023140 100644 --- a/lib/rdf/data.ex +++ b/lib/rdf/data.ex @@ -94,13 +94,16 @@ defprotocol RDF.Data do @doc """ Returns a nested map of the native Elixir values of a RDF data structure. + + When the optional `property_map` argument is given, predicates will be mapped + to the terms defined in the `RDF.PropertyMap` if present. """ - def values(data) + def values(data, property_map \\ nil) @doc """ - Returns a nested map of the native Elixir values of a RDF data structure with values mapped with the given function. + Returns a map representation of a RDF data structure where each element from its statements is mapped with the given function. """ - def values(data, mapping) + def map(data, fun) @doc """ Checks if two RDF data structures are equal. @@ -191,8 +194,11 @@ defimpl RDF.Data, for: RDF.Description do def subject_count(_), do: 1 def statement_count(description), do: RDF.Description.count(description) - def values(description), do: RDF.Description.values(description) - def values(description, mapping), do: RDF.Description.values(description, mapping) + + def values(description, property_map \\ nil), + do: RDF.Description.values(description, property_map) + + def map(description, fun), do: RDF.Description.map(description, fun) def equal?(description, %RDF.Description{} = other_description) do RDF.Description.equal?(description, other_description) @@ -273,8 +279,8 @@ defimpl RDF.Data, for: RDF.Graph do def subject_count(graph), do: RDF.Graph.subject_count(graph) def statement_count(graph), do: RDF.Graph.triple_count(graph) - def values(graph), do: RDF.Graph.values(graph) - def values(graph, mapping), do: RDF.Graph.values(graph, mapping) + def values(graph, property_map \\ nil), do: RDF.Graph.values(graph, property_map) + def map(graph, fun), do: RDF.Graph.map(graph, fun) def equal?(graph, %RDF.Description{} = description), do: RDF.Data.equal?(description, graph) @@ -348,8 +354,8 @@ defimpl RDF.Data, for: RDF.Dataset do def subject_count(dataset), do: dataset |> subjects |> Enum.count() def statement_count(dataset), do: RDF.Dataset.statement_count(dataset) - def values(dataset), do: RDF.Dataset.values(dataset) - def values(dataset, mapping), do: RDF.Dataset.values(dataset, mapping) + def values(dataset, property_map \\ nil), do: RDF.Dataset.values(dataset, property_map) + def map(dataset, fun), do: RDF.Dataset.map(dataset, fun) def equal?(dataset, %RDF.Description{} = description) do with [graph] <- RDF.Dataset.graphs(dataset) do diff --git a/lib/rdf/dataset.ex b/lib/rdf/dataset.ex index a5b65a2..58c336d 100644 --- a/lib/rdf/dataset.ex +++ b/lib/rdf/dataset.ex @@ -17,8 +17,8 @@ defmodule RDF.Dataset do @behaviour Access - alias RDF.{Graph, Description, IRI, Statement} - import RDF.Statement + alias RDF.{Graph, Description, IRI, Statement, PropertyMap} + import RDF.Statement, only: [coerce_subject: 1, coerce_graph_name: 1] import RDF.Utils @type graph_name :: IRI.t() | nil @@ -761,10 +761,8 @@ defmodule RDF.Dataset do @doc """ Returns a nested map of the native Elixir values of a `RDF.Dataset`. - The optional second argument allows to specify a custom mapping with a function - which will receive a tuple `{statement_position, rdf_term}` where - `statement_position` is one of the atoms `:subject`, `:predicate`, `:object`, - or `graph_name` while `rdf_term` is the RDF term to be mapped. + When the optional `property_map` argument is given, predicates will be mapped + to the terms defined in the `RDF.PropertyMap` if present. ## Examples @@ -783,12 +781,35 @@ defmodule RDF.Dataset do } } + """ + @spec values(t, PropertyMap.t() | nil) :: map + def values(dataset, property_map \\ nil) + + def values(%__MODULE__{} = dataset, nil) do + map(dataset, &Statement.default_term_mapping/1) + end + + def values(%__MODULE__{} = dataset, %PropertyMap{} = property_map) do + map(dataset, Statement.default_property_mapping(property_map)) + end + + @doc """ + Returns a nested map of a `RDF.Dataset` where each element from its quads is mapped with the given function. + + The function `fun` will receive a tuple `{statement_position, rdf_term}` where + `statement_position` is one of the atoms `:subject`, `:predicate`, `:object` or + `:graph_name` while `rdf_term` is the RDF term to be mapped. When the given function + returns `nil` this will be interpreted as an error and will become the overhaul + result of the `map/2` call. + + ## Examples + iex> [ ...> {~I, ~I, ~L"Foo", ~I}, ...> {~I, ~I, RDF.XSD.integer(42), } ...> ] ...> |> RDF.Dataset.new() - ...> |> RDF.Dataset.values(fn + ...> |> RDF.Dataset.map(fn ...> {:graph_name, graph_name} -> ...> graph_name ...> {:predicate, predicate} -> @@ -810,12 +831,12 @@ defmodule RDF.Dataset do } """ - @spec values(t, Statement.term_mapping()) :: map - def values(dataset, mapping \\ &Statement.default_term_mapping/1) + @spec map(t, Statement.term_mapping()) :: map + def map(dataset, fun) - def values(%__MODULE__{} = dataset, mapping) do + def map(%__MODULE__{} = dataset, fun) do Map.new(dataset.graphs, fn {graph_name, graph} -> - {mapping.({:graph_name, graph_name}), Graph.values(graph, mapping)} + {fun.({:graph_name, graph_name}), Graph.map(graph, fun)} end) end diff --git a/lib/rdf/description.ex b/lib/rdf/description.ex index 73717f8..deab8e3 100644 --- a/lib/rdf/description.ex +++ b/lib/rdf/description.ex @@ -15,7 +15,9 @@ defmodule RDF.Description do @behaviour Access - import RDF.Statement + import RDF.Statement, + only: [coerce_subject: 1, coerce_predicate: 1, coerce_predicate: 2, coerce_object: 1] + alias RDF.{Statement, Triple, PropertyMap} @type t :: %__MODULE__{ @@ -719,12 +721,11 @@ defmodule RDF.Description do Returns a map of the native Elixir values of a `RDF.Description`. The subject is not part of the result. It can be converted separately with - `RDF.Term.value/1`. + `RDF.Term.value/1`, or, if you want the subject in an outer map, just put the + the description in a graph and use `RDF.Graph.values/2`. - The optional second argument allows to specify a custom mapping with a function - which will receive a tuple `{statement_position, rdf_term}` where - `statement_position` is one of the atoms `:predicate` or `:object`, - while `rdf_term` is the RDF term to be mapped. + When the optional `property_map` argument is given, predicates will be mapped + to the terms defined in the `RDF.PropertyMap` if present. ## Examples @@ -733,7 +734,37 @@ defmodule RDF.Description do %{"http://example.com/p" => ["Foo"]} iex> RDF.Description.new(~I, init: {~I, ~L"Foo"}) - ...> |> RDF.Description.values(fn + ...> |> RDF.Description.values(PropertyMap.new(p: ~I)) + %{p: ["Foo"]} + + """ + @spec values(t, PropertyMap.t() | nil) :: map + def values(description, property_map \\ nil) + + def values(%__MODULE__{} = description, nil) do + map(description, &Statement.default_term_mapping/1) + end + + def values(%__MODULE__{} = description, %PropertyMap{} = property_map) do + map(description, Statement.default_property_mapping(property_map)) + end + + @doc """ + Returns a map of a `RDF.Description` where each element from its triples is mapped with the given function. + + The subject is not part of the result. If you want the subject in an outer map, + just put the the description in a graph and use `RDF.Graph.map/2`. + + The function `fun` will receive a tuple `{statement_position, rdf_term}` where + `statement_position` is one of the atoms `:predicate` or `:object`, while + `rdf_term` is the RDF term to be mapped. When the given function returns + `nil` this will be interpreted as an error and will become the overhaul result + of the `map/2` call. + + ## Examples + + iex> RDF.Description.new(~I, init: {~I, ~L"Foo"}) + ...> |> RDF.Description.map(fn ...> {:predicate, predicate} -> ...> predicate ...> |> to_string() @@ -746,14 +777,14 @@ defmodule RDF.Description do %{p: ["Foo"]} """ - @spec values(t, Statement.term_mapping()) :: map - def values(description, mapping \\ &Statement.default_term_mapping/1) + @spec map(t, Statement.term_mapping()) :: map + def map(description, fun) - def values(%__MODULE__{} = description, mapping) do + def map(%__MODULE__{} = description, fun) do Map.new(description.predications, fn {predicate, objects} -> { - mapping.({:predicate, predicate}), - objects |> Map.keys() |> Enum.map(&mapping.({:object, &1})) + fun.({:predicate, predicate}), + objects |> Map.keys() |> Enum.map(&fun.({:object, &1})) } end) end diff --git a/lib/rdf/graph.ex b/lib/rdf/graph.ex index ed342d9..0590a36 100644 --- a/lib/rdf/graph.ex +++ b/lib/rdf/graph.ex @@ -15,9 +15,9 @@ defmodule RDF.Graph do @behaviour Access - import RDF.Statement + import RDF.Statement, only: [coerce_subject: 1, coerce_graph_name: 1] import RDF.Utils - alias RDF.{Description, IRI, PrefixMap, Statement} + alias RDF.{Description, IRI, PrefixMap, Statement, PropertyMap} @type graph_description :: %{Statement.subject() => Description.t()} @@ -851,10 +851,8 @@ defmodule RDF.Graph do @doc """ Returns a nested map of the native Elixir values of a `RDF.Graph`. - The optional second argument allows to specify a custom mapping with a function - which will receive a tuple `{statement_position, rdf_term}` where - `statement_position` is one of the atoms `:subject`, `:predicate` or `:object`, - while `rdf_term` is the RDF term to be mapped. + When the optional `property_map` argument is given, predicates will be mapped + to the terms defined in the `RDF.PropertyMap` if present. ## Examples @@ -872,7 +870,40 @@ defmodule RDF.Graph do ...> {~I, ~I, ~L"Foo"}, ...> {~I, ~I, RDF.XSD.integer(42)} ...> ]) - ...> |> RDF.Graph.values(fn + ...> |> RDF.Graph.values(PropertyMap.new(p: ~I)) + %{ + "http://example.com/S1" => %{p: ["Foo"]}, + "http://example.com/S2" => %{p: [42]} + } + + """ + @spec values(t, PropertyMap.t() | nil) :: map + def values(graph, property_map \\ nil) + + def values(%__MODULE__{} = graph, nil) do + map(graph, &Statement.default_term_mapping/1) + end + + def values(%__MODULE__{} = graph, %PropertyMap{} = property_map) do + map(graph, Statement.default_property_mapping(property_map)) + end + + @doc """ + Returns a nested map of a `RDF.Graph` where each element from its triples is mapped with the given function. + + The function `fun` will receive a tuple `{statement_position, rdf_term}` where + `statement_position` is one of the atoms `:subject`, `:predicate` or `:object`, + while `rdf_term` is the RDF term to be mapped. When the given function returns + `nil` this will be interpreted as an error and will become the overhaul result + of the `map/2` call. + + ## Examples + + iex> RDF.Graph.new([ + ...> {~I, ~I, ~L"Foo"}, + ...> {~I, ~I, RDF.XSD.integer(42)} + ...> ]) + ...> |> RDF.Graph.map(fn ...> {:predicate, predicate} -> ...> predicate ...> |> to_string() @@ -888,14 +919,14 @@ defmodule RDF.Graph do } """ - @spec values(t, Statement.term_mapping()) :: map - def values(graph, mapping \\ &Statement.default_term_mapping/1) + @spec map(t, Statement.term_mapping()) :: map + def map(description, fun) - def values(%__MODULE__{} = graph, mapping) do + def map(%__MODULE__{} = graph, fun) do Map.new(graph.descriptions, fn {subject, description} -> { - mapping.({:subject, subject}), - Description.values(description, mapping) + fun.({:subject, subject}), + Description.map(description, fun) } end) end diff --git a/lib/rdf/quad.ex b/lib/rdf/quad.ex index 7945059..055db17 100644 --- a/lib/rdf/quad.ex +++ b/lib/rdf/quad.ex @@ -8,8 +8,12 @@ defmodule RDF.Quad do alias RDF.{Statement, PropertyMap} - @type t :: - {Statement.subject(), Statement.predicate(), Statement.object(), Statement.graph_name()} + @type t :: { + Statement.subject(), + Statement.predicate(), + Statement.object(), + Statement.graph_name() + } @type t_values :: {String.t(), String.t(), any, String.t()} @@ -93,14 +97,10 @@ defmodule RDF.Quad do @doc """ Returns a tuple of native Elixir values from a `RDF.Quad` of RDF terms. - Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`. + When the optional `property_map` argument is given, predicates will be mapped + to the terms defined in the `RDF.PropertyMap` if present. - The optional second argument allows to specify a custom mapping with a function - which will receive a tuple `{statement_position, rdf_term}` where - `statement_position` is one of the atoms `:subject`, `:predicate`, `:object` or - `:graph_name`, while `rdf_term` is the RDF term to be mapped. When the given - function returns `nil` this will be interpreted as an error and will become - the overhaul result of the `values/2` call. + Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`. ## Examples @@ -108,7 +108,36 @@ defmodule RDF.Quad do {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"} iex> {~I, ~I, RDF.literal(42), ~I} - ...> |> RDF.Quad.values(fn + ...> |> RDF.Quad.values(PropertyMap.new(p: ~I)) + {"http://example.com/S", :p, 42, "http://example.com/Graph"} + + """ + @spec values(t, PropertyMap.t() | nil) :: t_values | nil + def values(quad, property_map \\ nil) + + def values(quad, nil) do + map(quad, &Statement.default_term_mapping/1) + end + + def values(quad, %PropertyMap{} = property_map) do + map(quad, Statement.default_property_mapping(property_map)) + end + + @doc """ + Returns a tuple where each element from a `RDF.Quad` is mapped with the given function. + + Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`. + + The function `fun` will receive a tuple `{statement_position, rdf_term}` where + `statement_position` is one of the atoms `:subject`, `:predicate`, `:object` or + `:graph_name` while `rdf_term` is the RDF term to be mapped. When the given function + returns `nil` this will be interpreted as an error and will become the overhaul + result of the `map/2` call. + + ## Examples + + iex> {~I, ~I, RDF.literal(42), ~I} + ...> |> RDF.Quad.map(fn ...> {:object, object} -> ...> RDF.Term.value(object) ...> {:graph_name, graph_name} -> @@ -119,22 +148,18 @@ defmodule RDF.Quad do {:S, :p, 42, ~I} """ - @spec values(t | any, Statement.term_mapping()) :: t_values | nil - def values(quad, mapping \\ &Statement.default_term_mapping/1) - - def values({subject, predicate, object, graph_name}, mapping) do - with subject_value when not is_nil(subject_value) <- mapping.({:subject, subject}), - predicate_value when not is_nil(predicate_value) <- mapping.({:predicate, predicate}), - object_value when not is_nil(object_value) <- mapping.({:object, object}), - graph_name_value <- mapping.({:graph_name, graph_name}) do + @spec map(t, Statement.term_mapping()) :: t_values | nil + def map({subject, predicate, object, graph_name}, fun) do + with subject_value when not is_nil(subject_value) <- fun.({:subject, subject}), + predicate_value when not is_nil(predicate_value) <- fun.({:predicate, predicate}), + object_value when not is_nil(object_value) <- fun.({:object, object}), + graph_name_value <- fun.({:graph_name, graph_name}) do {subject_value, predicate_value, object_value, graph_name_value} else _ -> nil end end - def values(_, _), do: nil - @doc """ Checks if the given tuple is a valid RDF quad. diff --git a/lib/rdf/statement.ex b/lib/rdf/statement.ex index daf02f0..86111ae 100644 --- a/lib/rdf/statement.ex +++ b/lib/rdf/statement.ex @@ -18,7 +18,8 @@ defmodule RDF.Statement do @type coercible_object :: object | any @type coercible_graph_name :: graph_name | atom | String.t() - @type qualified_term :: {atom, Term.t() | nil} + @type position :: :subject | :predicate | :object | :graph_name + @type qualified_term :: {position, Term.t() | nil} @type term_mapping :: (qualified_term -> any | nil) @type t :: Triple.t() | Quad.t() @@ -67,8 +68,8 @@ defmodule RDF.Statement do @spec coerce_predicate(coercible_predicate, PropertyMap.t()) :: predicate def coerce_predicate(term, context) - def coerce_predicate(term, %PropertyMap{} = context) when is_atom(term) do - PropertyMap.iri(context, term) || coerce_predicate(term) + def coerce_predicate(term, %PropertyMap{} = property_map) when is_atom(term) do + PropertyMap.iri(property_map, term) || coerce_predicate(term) end def coerce_predicate(term, _), do: coerce_predicate(term) @@ -98,6 +99,32 @@ defmodule RDF.Statement do @doc """ Returns a tuple of native Elixir values from a `RDF.Statement` of RDF terms. + When the optional `property_map` argument is given, predicates will be mapped + to the terms defined in the `RDF.PropertyMap` if present. + + Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`. + + ## Examples + + iex> RDF.Statement.values {~I, ~I, RDF.literal(42)} + {"http://example.com/S", "http://example.com/p", 42} + + iex> RDF.Statement.values {~I, ~I, RDF.literal(42), ~I} + {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"} + + iex> {~I, ~I, RDF.literal(42)} + ...> |> RDF.Statement.values(PropertyMap.new(p: ~I)) + {"http://example.com/S", :p, 42} + + """ + @spec values(t, PropertyMap.t() | nil) :: Triple.t_values() | Quad.t_values() | nil + def values(quad, property_map \\ nil) + def values({_, _, _} = triple, property_map), do: Triple.values(triple, property_map) + def values({_, _, _, _} = quad, property_map), do: Quad.values(quad, property_map) + + @doc """ + Returns a tuple of native Elixir values from a `RDF.Statement` of RDF terms. + Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`. The optional second argument allows to specify a custom mapping with a function @@ -109,13 +136,8 @@ defmodule RDF.Statement do ## Examples - iex> RDF.Statement.values {~I, ~I, RDF.literal(42)} - {"http://example.com/S", "http://example.com/p", 42} - iex> RDF.Statement.values {~I, ~I, RDF.literal(42), ~I} - {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"} - iex> {~I, ~I, RDF.literal(42), ~I} - ...> |> RDF.Statement.values(fn + ...> |> RDF.Statement.map(fn ...> {:subject, subject} -> ...> subject |> to_string() |> String.last() ...> {:predicate, predicate} -> @@ -128,11 +150,10 @@ defmodule RDF.Statement do {"S", :p, 42, ~I} """ - @spec values(t | any, term_mapping) :: Triple.t_values() | Quad.t_values() | nil - def values(statement, mapping \\ &default_term_mapping/1) - def values({_, _, _} = triple, mapping), do: RDF.Triple.values(triple, mapping) - def values({_, _, _, _} = quad, mapping), do: RDF.Quad.values(quad, mapping) - def values(_, _), do: nil + @spec map(t, term_mapping()) :: Triple.t_values() | Quad.t_values() | nil | nil + def map(statement, fun) + def map({_, _, _} = triple, fun), do: RDF.Triple.map(triple, fun) + def map({_, _, _, _} = quad, fun), do: RDF.Quad.map(quad, fun) @doc false @spec default_term_mapping(qualified_term) :: any | nil @@ -140,6 +161,17 @@ defmodule RDF.Statement do def default_term_mapping({:graph_name, nil}), do: nil def default_term_mapping({_, term}), do: RDF.Term.value(term) + @spec default_property_mapping(PropertyMap.t()) :: term_mapping + def default_property_mapping(%PropertyMap{} = property_map) do + fn + {:predicate, predicate} -> + PropertyMap.term(property_map, predicate) || default_term_mapping({:predicate, predicate}) + + other -> + default_term_mapping(other) + end + end + @doc """ Checks if the given tuple is a valid RDF statement, i.e. RDF triple or quad. diff --git a/lib/rdf/triple.ex b/lib/rdf/triple.ex index 4273bfd..b914e2e 100644 --- a/lib/rdf/triple.ex +++ b/lib/rdf/triple.ex @@ -87,14 +87,10 @@ defmodule RDF.Triple do @doc """ Returns a tuple of native Elixir values from a `RDF.Triple` of RDF terms. - Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`. + When the optional `property_map` argument is given, predicates will be mapped + to the terms defined in the `RDF.PropertyMap` if present. - The optional second argument allows to specify a custom mapping with a function - which will receive a tuple `{statement_position, rdf_term}` where - `statement_position` is one of the atoms `:subject`, `:predicate` or `:object`, - while `rdf_term` is the RDF term to be mapped. When the given function returns - `nil` this will be interpreted as an error and will become the overhaul result - of the `values/2` call. + Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`. ## Examples @@ -102,28 +98,54 @@ defmodule RDF.Triple do {"http://example.com/S", "http://example.com/p", 42} iex> {~I, ~I, RDF.literal(42)} - ...> |> RDF.Triple.values(fn + ...> |> RDF.Triple.values(PropertyMap.new(p: ~I)) + {"http://example.com/S", :p, 42} + + + """ + @spec values(t, PropertyMap.t() | nil) :: t_values | nil + def values(triple, property_map \\ nil) + + def values(triple, nil) do + map(triple, &Statement.default_term_mapping/1) + end + + def values(triple, %PropertyMap{} = property_map) do + map(triple, Statement.default_property_mapping(property_map)) + end + + @doc """ + Returns a triple where each element from a `RDF.Triple` is mapped with the given function. + + Returns `nil` if one of the components of the given tuple is not convertible via `RDF.Term.value/1`. + + The function `fun` will receive a tuple `{statement_position, rdf_term}` where + `statement_position` is one of the atoms `:subject`, `:predicate` or `:object`, + while `rdf_term` is the RDF term to be mapped. When the given function returns + `nil` this will be interpreted as an error and will become the overhaul result + of the `map/2` call. + + ## Examples + + iex> {~I, ~I, RDF.literal(42)} + ...> |> RDF.Triple.map(fn ...> {:object, object} -> RDF.Term.value(object) ...> {_, term} -> term |> to_string() |> String.last() ...> end) {"S", "p", 42} """ - @spec values(t | any, Statement.term_mapping()) :: t_values | nil - def values(triple, mapping \\ &Statement.default_term_mapping/1) - - def values({subject, predicate, object}, mapping) do - with subject_value when not is_nil(subject_value) <- mapping.({:subject, subject}), - predicate_value when not is_nil(predicate_value) <- mapping.({:predicate, predicate}), - object_value when not is_nil(object_value) <- mapping.({:object, object}) do + @spec map(t, Statement.term_mapping()) :: t_values | nil + def map({subject, predicate, object}, fun) do + with subject_value when not is_nil(subject_value) <- fun.({:subject, subject}), + predicate_value when not is_nil(predicate_value) <- fun.({:predicate, predicate}), + object_value when not is_nil(object_value) <- fun.({:object, object}) do {subject_value, predicate_value, object_value} else _ -> nil end end - def values(_, _), do: nil - @doc """ Checks if the given tuple is a valid RDF triple. diff --git a/test/unit/data_test.exs b/test/unit/data_test.exs index a5ef266..068c945 100644 --- a/test/unit/data_test.exs +++ b/test/unit/data_test.exs @@ -534,7 +534,7 @@ defmodule RDF.DataTest do } end - test "values/2", %{dataset: dataset} do + test "map/2", %{dataset: dataset} do mapping = fn {:graph_name, graph_name} -> graph_name @@ -546,7 +546,7 @@ defmodule RDF.DataTest do RDF.Term.value(term) end - assert RDF.Data.values(dataset, mapping) == + assert RDF.Data.map(dataset, mapping) == %{ nil => %{ RDF.Term.value(RDF.iri(EX.S)) => %{ diff --git a/test/unit/dataset_test.exs b/test/unit/dataset_test.exs index f146e7d..5600815 100644 --- a/test/unit/dataset_test.exs +++ b/test/unit/dataset_test.exs @@ -1681,6 +1681,19 @@ defmodule RDF.DatasetTest do end test "values/2" do + assert Dataset.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2(), EX.graph()}]) + |> Dataset.values(PropertyMap.new(p: EX.p())) == + %{ + nil => %{ + RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]} + }, + RDF.Term.value(EX.graph()) => %{ + RDF.Term.value(EX.s2()) => %{p: [RDF.Term.value(EX.o2())]} + } + } + end + + test "map/2" do mapping = fn {:graph_name, graph_name} -> graph_name @@ -1692,10 +1705,10 @@ defmodule RDF.DatasetTest do RDF.Term.value(term) end - assert Dataset.new() |> Dataset.values(mapping) == %{} + assert Dataset.new() |> Dataset.map(mapping) == %{} assert Dataset.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2(), EX.graph()}]) - |> Dataset.values(mapping) == + |> Dataset.map(mapping) == %{ nil => %{ RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]} diff --git a/test/unit/description_test.exs b/test/unit/description_test.exs index 2c3c4a4..5a37f19 100644 --- a/test/unit/description_test.exs +++ b/test/unit/description_test.exs @@ -839,6 +839,12 @@ defmodule RDF.DescriptionTest do end test "values/2" do + assert Description.new(EX.s(), init: {EX.s(), EX.p(), ~L"Foo"}) + |> Description.values(PropertyMap.new(p: EX.p())) == + %{p: ["Foo"]} + end + + test "map/2" do mapping = fn {:predicate, predicate} -> predicate |> to_string() |> String.split("/") |> List.last() |> String.to_atom() @@ -847,9 +853,9 @@ defmodule RDF.DescriptionTest do RDF.Term.value(term) end - assert Description.new(EX.s()) |> Description.values(mapping) == %{} + assert Description.new(EX.s()) |> Description.map(mapping) == %{} - assert Description.new(EX.s(), init: {EX.s(), EX.p(), ~L"Foo"}) |> Description.values(mapping) == + assert Description.new(EX.s(), init: {EX.s(), EX.p(), ~L"Foo"}) |> Description.map(mapping) == %{p: ["Foo"]} end diff --git a/test/unit/graph_test.exs b/test/unit/graph_test.exs index d196cce..d6e89e2 100644 --- a/test/unit/graph_test.exs +++ b/test/unit/graph_test.exs @@ -1252,6 +1252,15 @@ defmodule RDF.GraphTest do end test "values/2" do + assert Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}]) + |> Graph.values(PropertyMap.new(p: EX.p())) == + %{ + RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]}, + RDF.Term.value(EX.s2()) => %{p: [RDF.Term.value(EX.o2())]} + } + end + + test "map/2" do mapping = fn {:predicate, predicate} -> predicate |> to_string() |> String.split("/") |> List.last() |> String.to_atom() @@ -1260,10 +1269,10 @@ defmodule RDF.GraphTest do RDF.Term.value(term) end - assert Graph.new() |> Graph.values(mapping) == %{} + assert Graph.new() |> Graph.map(mapping) == %{} assert Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}]) - |> Graph.values(mapping) == + |> Graph.map(mapping) == %{ RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]}, RDF.Term.value(EX.s2()) => %{p: [RDF.Term.value(EX.o2())]} diff --git a/test/unit/quad_test.exs b/test/unit/quad_test.exs index 70acbbb..d62096d 100644 --- a/test/unit/quad_test.exs +++ b/test/unit/quad_test.exs @@ -20,15 +20,36 @@ defmodule RDF.QuadTest do end test "with an invalid RDF.Quad" do - refute Quad.values({~I, ~I}) refute Quad.values({self(), self(), self(), self()}) end end - test "values/2" do + describe "values/2" do + test "with a valid RDF.Quad and RDF.PropertyMap" do + assert Quad.values( + {~I, ~I, XSD.integer(42), + ~I}, + PropertyMap.new(p: ~I) + ) == + {"http://example.com/S", :p, 42, "http://example.com/Graph"} + + assert Quad.values( + {~I, ~I, XSD.integer(42), + ~I}, + PropertyMap.new() + ) == + {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"} + end + + test "with an invalid RDF.Triple" do + refute Quad.values({self(), self(), self(), self()}, PropertyMap.new()) + end + end + + test "map/2" do assert {~I, ~I, XSD.integer(42), ~I} - |> Quad.values(fn + |> Quad.map(fn {:subject, subject} -> subject |> to_string() |> String.last() |> String.to_atom() {:predicate, _} -> :p {:object, object} -> object |> RDF.Term.value() |> Kernel.+(1) diff --git a/test/unit/triple_test.exs b/test/unit/triple_test.exs index cbd4500..c8c8a99 100644 --- a/test/unit/triple_test.exs +++ b/test/unit/triple_test.exs @@ -12,14 +12,33 @@ defmodule RDF.TripleTest do end test "with an invalid RDF.Triple" do - refute Triple.values({~I, ~I}) refute Triple.values({self(), self(), self()}) end end - test "values/2" do + describe "values/2" do + test "with a valid RDF.Triple and RDF.PropertyMap" do + assert Triple.values( + {~I, ~I, XSD.integer(42)}, + PropertyMap.new(p: ~I) + ) == + {"http://example.com/S", :p, 42} + + assert Triple.values( + {~I, ~I, XSD.integer(42)}, + PropertyMap.new() + ) == + {"http://example.com/S", "http://example.com/p", 42} + end + + test "with an invalid RDF.Triple" do + refute Triple.values({self(), self(), self()}, PropertyMap.new()) + end + end + + test "map/2" do assert {~I, ~I, XSD.integer(42)} - |> Triple.values(fn + |> Triple.map(fn {:object, object} -> object |> RDF.Term.value() |> Kernel.+(1) {_, term} -> term |> to_string() |> String.last() end) ==