core: functions to get the sets of all subjects, predicates, objects and resources of Descriptions and Graphs

This commit is contained in:
Marcel Otto 2016-11-02 03:19:19 +01:00
parent 31331b7388
commit c192b49bfd
6 changed files with 177 additions and 7 deletions

View file

@ -100,6 +100,27 @@ defmodule RDF do
def bnode(id), do: BlankNode.new(id)
@doc """
Checks if the given value is a RDF resource.
## Examples
iex> RDF.resource?(RDF.uri("http://example.com/resource"))
true
iex> RDF.resource?(EX.resource)
true
iex> RDF.resource?(RDF.bnode)
true
iex> RDF.resource?(42)
false
"""
def resource?(value)
def resource?(%URI{}), do: true
def resource?(atom) when is_atom(atom), do: resource?(Vocabulary.__uri__(atom))
def resource?(%BlankNode{}), do: true
def resource?(_), do: false
################################################################################
# temporary manual RDF vocab definitions
# TODO: These should be defined as a vocabulary

View file

@ -53,17 +53,79 @@ defmodule RDF.Description do
end
end
@doc """
Returns the number of statements of the `RDF.Description`.
Returns the number of statements of a `RDF.Description`.
"""
def count(%RDF.Description{predications: predications}) do
Enum.reduce predications, 0,
fn ({_, objects}, count) -> count + Enum.count(objects) end
end
@doc """
Checks if the given statement exists within the `RDF.Description`.
The set of all properties used in the predicates within a `RDF.Description`.
# Examples
iex> RDF.Description.new([
...> {EX.S1, EX.p1, EX.O1},
...> {EX.p2, EX.O2},
...> {EX.p2, EX.O3}]) |>
...> RDF.Description.predicates
MapSet.new([EX.p1, EX.p2])
"""
def predicates(%RDF.Description{predications: predications}),
do: predications |> Map.keys |> MapSet.new
@doc """
The set of all resources used in the objects within a `RDF.Description`.
Note: This function does collect only URIs and BlankNodes, not Literals.
# Examples
iex> RDF.Description.new([
...> {EX.S1, EX.p1, EX.O1},
...> {EX.p2, EX.O2},
...> {EX.p3, EX.O2},
...> {EX.p4, RDF.bnode(:bnode)},
...> {EX.p3, "foo"}
...> ]) |> RDF.Description.objects
MapSet.new([RDF.uri(EX.O1), RDF.uri(EX.O2), RDF.bnode(:bnode)])
"""
def objects(%RDF.Description{predications: predications}) do
Enum.reduce predications, MapSet.new, fn ({_, objects}, acc) ->
objects
|> Map.keys
|> Enum.filter(&RDF.resource?/1)
|> MapSet.new
|> MapSet.union(acc)
end
end
@doc """
The set of all resources used within a `RDF.Description`.
# Examples
iex> RDF.Description.new([
...> {EX.S1, EX.p1, EX.O1},
...> {EX.p2, EX.O2},
...> {EX.p1, EX.O2},
...> {EX.p2, RDF.bnode(:bnode)},
...> {EX.p3, "foo"}
...> ]) |> RDF.Description.resources
MapSet.new([RDF.uri(EX.O1), RDF.uri(EX.O2), RDF.bnode(:bnode), EX.p1, EX.p2, EX.p3])
"""
def resources(description) do
description
|> objects
|> MapSet.union(predicates(description))
end
@doc """
Checks if the given statement exists within a `RDF.Description`.
"""
def include?(description, statement)

View file

@ -48,6 +48,88 @@ defmodule RDF.Graph do
end
end
@doc """
The set of all properties used in the predicates within a `RDF.Graph`.
# Examples
iex> RDF.Graph.new([
...> {EX.S1, EX.p1, EX.O1},
...> {EX.S2, EX.p2, EX.O2},
...> {EX.S1, EX.p2, EX.O3}]) |>
...> RDF.Graph.subjects
MapSet.new([RDF.uri(EX.S1), RDF.uri(EX.S2)])
"""
def subjects(%RDF.Graph{descriptions: descriptions}),
do: descriptions |> Map.keys |> MapSet.new
@doc """
The set of all properties used in the predicates within a `RDF.Graph`.
# Examples
iex> RDF.Graph.new([
...> {EX.S1, EX.p1, EX.O1},
...> {EX.S2, EX.p2, EX.O2},
...> {EX.S1, EX.p2, EX.O3}]) |>
...> RDF.Graph.predicates
MapSet.new([EX.p1, EX.p2])
"""
def predicates(%RDF.Graph{descriptions: descriptions}) do
Enum.reduce descriptions, MapSet.new, fn ({_, description}, acc) ->
description
|> Description.predicates
|> MapSet.union(acc)
end
end
@doc """
The set of all resources used in the objects within a `RDF.Graph`.
Note: This function does collect only URIs and BlankNodes, not Literals.
# Examples
iex> RDF.Graph.new([
...> {EX.S1, EX.p1, EX.O1},
...> {EX.S2, EX.p2, EX.O2},
...> {EX.S3, EX.p1, EX.O2},
...> {EX.S4, EX.p2, RDF.bnode(:bnode)},
...> {EX.S5, EX.p3, "foo"}
...> ]) |> RDF.Graph.objects
MapSet.new([RDF.uri(EX.O1), RDF.uri(EX.O2), RDF.bnode(:bnode)])
"""
def objects(%RDF.Graph{descriptions: descriptions}) do
Enum.reduce descriptions, MapSet.new, fn ({_, description}, acc) ->
description
|> Description.objects
|> MapSet.union(acc)
end
end
@doc """
The set of all resources used within a `RDF.Graph`.
# Examples
iex> RDF.Graph.new([
...> {EX.S1, EX.p1, EX.O1},
...> {EX.S2, EX.p1, EX.O2},
...> {EX.S2, EX.p2, RDF.bnode(:bnode)},
...> {EX.S3, EX.p1, "foo"}
...> ]) |> RDF.Graph.resources
MapSet.new([RDF.uri(EX.S1), RDF.uri(EX.S2), RDF.uri(EX.S3),
RDF.uri(EX.O1), RDF.uri(EX.O2), RDF.bnode(:bnode), EX.p1, EX.p2])
"""
def resources(graph = %RDF.Graph{descriptions: descriptions}) do
Enum.reduce(descriptions, MapSet.new, fn ({_, description}, acc) ->
description
|> Description.resources
|> MapSet.union(acc)
end) |> MapSet.union(subjects(graph))
end
def include?(%RDF.Graph{descriptions: descriptions},
triple = {subject, _, _}) do
with triple_subject = Triple.convert_subject(subject),

View file

@ -1,13 +1,14 @@
defmodule RDF.DescriptionTest do
use ExUnit.Case
defmodule EX, do:
use RDF.Vocabulary, base_uri: "http://example.com/description/"
doctest RDF.Description
alias RDF.Description
import RDF, only: [uri: 1, literal: 1, bnode: 1]
defmodule EX, do:
use RDF.Vocabulary, base_uri: "http://example.com/description/"
def description, do: Description.new(EX.Subject)
def description_of_subject(%Description{subject: subject}, subject), do: true

View file

@ -1,13 +1,14 @@
defmodule RDF.GraphTest do
use ExUnit.Case
defmodule EX, do:
use RDF.Vocabulary, base_uri: "http://example.com/graph/"
doctest RDF.Graph
alias RDF.Graph
import RDF, only: [uri: 1]
defmodule EX, do:
use RDF.Vocabulary, base_uri: "http://example.com/graph/"
def graph, do: unnamed_graph
def unnamed_graph, do: Graph.new

View file

@ -1,5 +1,8 @@
defmodule RDF.CoreTest do
use ExUnit.Case
defmodule EX, do: use RDF.Vocabulary, base_uri: "http://example.com/"
doctest RDF
# alias RDF.{Triple, Literal, BlankNode}