Add Collectable implementations for all RDF data structures

This commit is contained in:
Marcel Otto 2017-10-30 11:40:44 +01:00
parent dfb42f7eaf
commit b445f2e31c
9 changed files with 137 additions and 3 deletions

View file

@ -5,6 +5,19 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
[Keep a CHANGELOG](http://keepachangelog.com).
## Unreleased
### Added
- `Collectable` implementations for all `RDF.Data` structures so they can be
used as destinations of `Enum.into` and `for` comprehensions
[Compare v0.3.0...HEAD](https://github.com/marcelotto/rdf-ex/compare/v0.3.0...HEAD)
## 0.3.0 - 2017-08-24
### Added

View file

@ -425,7 +425,7 @@ RDF.ex provides various data structures for collections of statements:
- `RDF.Graph`: a named collection of statements
- `RDF.Dataset`: a named collection of graphs, i.e. a collection of statements from different graphs; it may have multiple named graphs and at most one unnamed ("default") graph
All of these structures have similar sets of functions and implement Elixirs `Enumerable` protocol, Elixirs `Access` behaviour and the `RDF.Data` protocol of RDF.ex.
All of these structures have similar sets of functions and implement Elixirs `Enumerable` and `Collectable` protocol, Elixirs `Access` behaviour and the `RDF.Data` protocol of RDF.ex.
The `new` function of these data structures create new instances of the struct and optionally initialize them with initial statements. `RDF.Description.new` requires at least an IRI or blank node for the subject, while `RDF.Graph.new` and `RDF.Dataset.new` take an optional IRI for the name of the graph or dataset.

View file

@ -1 +1 @@
0.3.0
0.3.1-dev

View file

@ -724,6 +724,7 @@ defmodule RDF.Dataset do
end
end
defimpl Enumerable do
def member?(graph, statement), do: {:ok, RDF.Dataset.include?(graph, statement)}
def count(graph), do: {:ok, RDF.Dataset.statement_count(graph)}
@ -741,4 +742,20 @@ defmodule RDF.Dataset do
{:suspended, acc, &reduce(dataset, &1, fun)}
end
end
defimpl Collectable do
def into(original) do
collector_fun = fn
dataset, {:cont, list} when is_list(list)
-> RDF.Dataset.add(dataset, List.to_tuple(list))
dataset, {:cont, elem} -> RDF.Dataset.add(dataset, elem)
dataset, :done -> dataset
_dataset, :halt -> :ok
end
{original, collector_fun}
end
end
end

View file

@ -587,4 +587,19 @@ defmodule RDF.Description do
end
end
defimpl Collectable do
def into(original) do
collector_fun = fn
description, {:cont, list} when is_list(list)
-> RDF.Description.add(description, List.to_tuple(list))
description, {:cont, elem} -> RDF.Description.add(description, elem)
description, :done -> description
_description, :halt -> :ok
end
{original, collector_fun}
end
end
end

View file

@ -617,5 +617,20 @@ defmodule RDF.Graph do
end
end
defimpl Collectable do
def into(original) do
collector_fun = fn
graph, {:cont, list} when is_list(list)
-> RDF.Graph.add(graph, List.to_tuple(list))
graph, {:cont, elem} -> RDF.Graph.add(graph, elem)
graph, :done -> graph
_graph, :halt -> :ok
end
{original, collector_fun}
end
end
end

View file

@ -742,6 +742,27 @@ defmodule RDF.DatasetTest do
end
end
describe "Collectable protocol" do
test "with a list of triples" do
triples = [
{EX.Subject, EX.predicate1, EX.Object1},
{EX.Subject, EX.predicate2, EX.Object2},
{EX.Subject, EX.predicate2, EX.Object2, EX.Graph}
]
assert Enum.into(triples, Dataset.new()) == Dataset.new(triples)
end
test "with a list of lists" do
lists = [
[EX.Subject, EX.predicate1, EX.Object1],
[EX.Subject, EX.predicate2, EX.Object2],
[EX.Subject, EX.predicate2, EX.Object2, EX.Graph]
]
assert Enum.into(lists, Dataset.new()) ==
Dataset.new(Enum.map(lists, &List.to_tuple/1))
end
end
describe "Access behaviour" do
test "access with the [] operator" do
assert Dataset.new[EX.Graph] == nil

View file

@ -370,6 +370,41 @@ defmodule RDF.DescriptionTest do
end
end
describe "Collectable protocol" do
test "with a map" do
map = %{
EX.predicate1 => EX.Object1,
EX.predicate2 => EX.Object2
}
assert Enum.into(map, Description.new(EX.Subject)) == Description.new(EX.Subject, map)
end
test "with a list of triples" do
triples = [
{EX.Subject, EX.predicate1, EX.Object1},
{EX.Subject, EX.predicate2, EX.Object2}
]
assert Enum.into(triples, Description.new(EX.Subject)) == Description.new(triples)
end
test "with a list of predicate-object pairs" do
pairs = [
{EX.predicate1, EX.Object1},
{EX.predicate2, EX.Object2}
]
assert Enum.into(pairs, Description.new(EX.Subject)) == Description.new(EX.Subject, pairs)
end
test "with a list of lists" do
lists = [
[EX.Subject, EX.predicate1, EX.Object1],
[EX.Subject, EX.predicate2, EX.Object2]
]
assert Enum.into(lists, Description.new(EX.Subject)) ==
Description.new(Enum.map(lists, &List.to_tuple/1))
end
end
describe "Access behaviour" do
test "access with the [] operator" do
assert Description.new(EX.Subject)[EX.predicate] == nil
@ -381,7 +416,6 @@ defmodule RDF.DescriptionTest do
{EX.Subject, EX.predicate2, EX.Object3}])[EX.predicate1] ==
[iri(EX.Object1), iri(EX.Object2)]
end
end
end

View file

@ -403,6 +403,25 @@ defmodule RDF.GraphTest do
end
end
describe "Collectable protocol" do
test "with a list of triples" do
triples = [
{EX.Subject, EX.predicate1, EX.Object1},
{EX.Subject, EX.predicate2, EX.Object2}
]
assert Enum.into(triples, Graph.new()) == Graph.new(triples)
end
test "with a list of lists" do
lists = [
[EX.Subject, EX.predicate1, EX.Object1],
[EX.Subject, EX.predicate2, EX.Object2]
]
assert Enum.into(lists, Graph.new()) ==
Graph.new(Enum.map(lists, &List.to_tuple/1))
end
end
describe "Access behaviour" do
test "access with the [] operator" do
assert Graph.new[EX.Subject] == nil