Add RDF.Graph builder DSL
This commit is contained in:
parent
8cb72f5ccc
commit
6e1b6213c4
6 changed files with 602 additions and 1 deletions
|
@ -2,7 +2,8 @@ locals_without_parens = [
|
|||
defvocab: 2,
|
||||
def_facet_constraint: 2,
|
||||
def_applicable_facet: 1,
|
||||
bgp: 1
|
||||
bgp: 1,
|
||||
build: 2
|
||||
]
|
||||
|
||||
[
|
||||
|
|
2
.iex.exs
2
.iex.exs
|
@ -1,6 +1,8 @@
|
|||
import RDF.Sigils
|
||||
import RDF.Guards
|
||||
|
||||
require RDF.Graph
|
||||
|
||||
alias RDF.NS
|
||||
alias RDF.NS.{RDFS, OWL, SKOS}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
|
|||
|
||||
### Added
|
||||
|
||||
- a `RDF.Graph` builder DSL available under the `RDF.Graph.build/2` function
|
||||
- `RDF.Graph.new/2` and `RDF.Graph.add/2` support the addition of `RDF.Dataset`s
|
||||
- new guards in `RDF.Guards`: `is_statement/1` and `is_quad/1`
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ defmodule RDF.Graph do
|
|||
@behaviour Access
|
||||
|
||||
alias RDF.{Description, IRI, PrefixMap, PropertyMap}
|
||||
alias RDF.Graph.Builder
|
||||
alias RDF.Star.Statement
|
||||
|
||||
@type graph_description :: %{Statement.subject() => Description.t()}
|
||||
|
@ -136,6 +137,10 @@ defmodule RDF.Graph do
|
|||
defp init(graph, fun, opts) when is_function(fun), do: add(graph, fun.(), opts)
|
||||
defp init(graph, data, opts), do: add(graph, data, opts)
|
||||
|
||||
defmacro build(opts \\ [], do: block) do
|
||||
Builder.build(block, opts)
|
||||
end
|
||||
|
||||
@doc """
|
||||
Removes all triples from `graph`.
|
||||
|
||||
|
|
130
lib/rdf/graph_builder.ex
Normal file
130
lib/rdf/graph_builder.ex
Normal file
|
@ -0,0 +1,130 @@
|
|||
defmodule RDF.Graph.Builder do
|
||||
alias RDF.{Description, Graph, Dataset, PrefixMap}
|
||||
|
||||
import RDF.Guards
|
||||
|
||||
defmodule Error do
|
||||
defexception [:message]
|
||||
end
|
||||
|
||||
defmodule Helper do
|
||||
defdelegate a(), to: RDF.NS.RDF, as: :type
|
||||
defdelegate a(s, o), to: RDF.NS.RDF, as: :type
|
||||
defdelegate a(s, o1, o2), to: RDF.NS.RDF, as: :type
|
||||
defdelegate a(s, o1, o2, o3), to: RDF.NS.RDF, as: :type
|
||||
defdelegate a(s, o1, o2, o3, o4), to: RDF.NS.RDF, as: :type
|
||||
defdelegate a(s, o1, o2, o3, o4, o5), to: RDF.NS.RDF, as: :type
|
||||
end
|
||||
|
||||
def build({:__block__, _, block}, opts) do
|
||||
{declarations, data} = Enum.split_with(block, &declaration?/1)
|
||||
{prefixes, declarations} = extract_prefixes(declarations)
|
||||
{base, declarations} = extract_base(declarations)
|
||||
|
||||
quote do
|
||||
alias RDF.XSD
|
||||
alias RDF.NS.{RDFS, OWL}
|
||||
|
||||
import RDF.Sigils
|
||||
import Helper
|
||||
|
||||
unquote(declarations)
|
||||
|
||||
RDF.Graph.Builder.do_build(unquote(data), unquote(opts), unquote(prefixes), unquote(base))
|
||||
end
|
||||
end
|
||||
|
||||
def build(single, opts) do
|
||||
build({:__block__, [], List.wrap(single)}, opts)
|
||||
end
|
||||
|
||||
@doc false
|
||||
def do_build(data, opts, prefixes, base) do
|
||||
RDF.graph(graph_opts(opts, prefixes, base))
|
||||
|> Graph.add(Enum.filter(data, &rdf?/1))
|
||||
end
|
||||
|
||||
defp graph_opts(opts, prefixes, base) do
|
||||
opts
|
||||
|> set_base_opt(base)
|
||||
|> set_prefix_opt(prefixes)
|
||||
end
|
||||
|
||||
defp set_base_opt(opts, nil), do: opts
|
||||
defp set_base_opt(opts, base), do: Keyword.put(opts, :base_iri, base)
|
||||
|
||||
defp set_prefix_opt(opts, []), do: opts
|
||||
|
||||
defp set_prefix_opt(opts, prefixes) do
|
||||
Keyword.update(opts, :prefixes, RDF.default_prefixes(prefixes), fn opt_prefixes ->
|
||||
PrefixMap.new(prefixes)
|
||||
|> PrefixMap.merge!(opt_prefixes, :ignore)
|
||||
end)
|
||||
end
|
||||
|
||||
defp extract_base(declarations) do
|
||||
{base, declarations} =
|
||||
Enum.reduce(declarations, {nil, []}, fn
|
||||
{:@, line, [{:base, _, [{:__aliases__, _, ns}] = aliases}]}, {_, declarations} ->
|
||||
{Module.concat(ns), [{:alias, line, aliases} | declarations]}
|
||||
|
||||
{:@, _, [{:base, _, [base]}]}, {_, declarations} ->
|
||||
{base, declarations}
|
||||
|
||||
declaration, {base, declarations} ->
|
||||
{base, [declaration | declarations]}
|
||||
end)
|
||||
|
||||
{base, Enum.reverse(declarations)}
|
||||
end
|
||||
|
||||
defp extract_prefixes(declarations) do
|
||||
{prefixes, declarations} =
|
||||
Enum.reduce(declarations, {[], []}, fn
|
||||
{:@, line, [{:prefix, _, [[{prefix, {:__aliases__, _, ns} = aliases}]]}]},
|
||||
{prefixes, declarations} ->
|
||||
{[prefix(prefix, ns) | prefixes], [{:alias, line, [aliases]} | declarations]}
|
||||
|
||||
{:@, line, [{:prefix, _, [{:__aliases__, _, ns}] = aliases}]}, {prefixes, declarations} ->
|
||||
{[prefix(ns) | prefixes], [{:alias, line, aliases} | declarations]}
|
||||
|
||||
declaration, {prefixes, declarations} ->
|
||||
{prefixes, [declaration | declarations]}
|
||||
end)
|
||||
|
||||
{prefixes, Enum.reverse(declarations)}
|
||||
end
|
||||
|
||||
defp prefix(namespace) do
|
||||
namespace
|
||||
|> Enum.reverse()
|
||||
|> hd()
|
||||
|> to_string()
|
||||
|> Macro.underscore()
|
||||
|> String.to_atom()
|
||||
|> prefix(namespace)
|
||||
end
|
||||
|
||||
defp prefix(prefix, namespace), do: {prefix, Module.concat(namespace)}
|
||||
|
||||
defp declaration?({:=, _, _}), do: true
|
||||
defp declaration?({:@, _, [{:prefix, _, _}]}), do: true
|
||||
defp declaration?({:@, _, [{:base, _, _}]}), do: true
|
||||
defp declaration?({:alias, _, _}), do: true
|
||||
defp declaration?({:import, _, _}), do: true
|
||||
defp declaration?({:require, _, _}), do: true
|
||||
defp declaration?({:use, _, _}), do: true
|
||||
defp declaration?(_), do: false
|
||||
|
||||
defp rdf?(nil), do: false
|
||||
defp rdf?(:ok), do: false
|
||||
defp rdf?(%Description{}), do: true
|
||||
defp rdf?(%Graph{}), do: true
|
||||
defp rdf?(%Dataset{}), do: true
|
||||
defp rdf?(statement) when is_statement(statement), do: true
|
||||
defp rdf?(list) when is_list(list), do: true
|
||||
|
||||
defp rdf?(invalid) do
|
||||
raise Error, message: "invalid RDF data: #{inspect(invalid)}"
|
||||
end
|
||||
end
|
462
test/unit/graph_builder_test.exs
Normal file
462
test/unit/graph_builder_test.exs
Normal file
|
@ -0,0 +1,462 @@
|
|||
defmodule RDF.Graph.BuilderTest do
|
||||
use ExUnit.Case
|
||||
|
||||
require RDF.Graph
|
||||
|
||||
doctest RDF.Graph.Builder
|
||||
|
||||
alias RDF.Graph.Builder
|
||||
|
||||
import ExUnit.CaptureLog
|
||||
|
||||
defmodule TestNS do
|
||||
use RDF.Vocabulary.Namespace
|
||||
defvocab EX, base_iri: "http://example.com/", terms: [], strict: false
|
||||
defvocab Custom, base_iri: "http://custom.com/foo#", terms: [], strict: false
|
||||
defvocab ImportTest, base_iri: "http://import.com/bar#", terms: [:foo, :Bar]
|
||||
end
|
||||
|
||||
@compile {:no_warn_undefined, __MODULE__.TestNS.EX}
|
||||
@compile {:no_warn_undefined, __MODULE__.TestNS.Custom}
|
||||
|
||||
alias __MODULE__.TestNS.EX
|
||||
alias RDF.NS
|
||||
|
||||
defmodule UseTest do
|
||||
defmacro __using__(_opts) do
|
||||
quote do
|
||||
{EX.This, EX.ShouldNotAppearIn, EX.Graph}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "single statement" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
EX.S |> EX.p(EX.O)
|
||||
end
|
||||
|
||||
assert graph == RDF.graph(EX.S |> EX.p(EX.O))
|
||||
end
|
||||
|
||||
test "multiple statements" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
EX.S1 |> EX.p1(EX.O1)
|
||||
EX.S2 |> EX.p2(EX.O2)
|
||||
end
|
||||
|
||||
assert graph ==
|
||||
RDF.graph([
|
||||
EX.S1 |> EX.p1(EX.O1),
|
||||
EX.S2 |> EX.p2(EX.O2)
|
||||
])
|
||||
end
|
||||
|
||||
test "different kinds of description forms" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
EX.S1
|
||||
|> EX.p11(EX.O11, EX.O12)
|
||||
|> EX.p12(EX.O11, EX.O12)
|
||||
|
||||
EX.S2
|
||||
|> EX.p2([EX.O21, EX.O22])
|
||||
|
||||
EX.p3(EX.S3, EX.O3)
|
||||
end
|
||||
|
||||
assert graph ==
|
||||
RDF.graph([
|
||||
EX.S1 |> EX.p11(EX.O11, EX.O12),
|
||||
EX.S1 |> EX.p12(EX.O11, EX.O12),
|
||||
EX.S2 |> EX.p2([EX.O21, EX.O22]),
|
||||
EX.p3(EX.S3, EX.O3)
|
||||
])
|
||||
end
|
||||
|
||||
test "triples given as tuples" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
EX.S1 |> EX.p1(EX.O1)
|
||||
|
||||
{EX.S2, EX.p2(), EX.O2}
|
||||
end
|
||||
|
||||
assert graph ==
|
||||
RDF.graph([
|
||||
EX.S1 |> EX.p1(EX.O1),
|
||||
EX.S2 |> EX.p2(EX.O2)
|
||||
])
|
||||
end
|
||||
|
||||
test "nested statements" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
[
|
||||
EX.S1 |> EX.p1([EX.O11, EX.O12]),
|
||||
[
|
||||
{EX.S2, EX.p2(), EX.O2},
|
||||
{EX.S31, EX.p31(), EX.O31}
|
||||
],
|
||||
{EX.S32, EX.p32(), EX.O32}
|
||||
]
|
||||
end
|
||||
|
||||
assert graph ==
|
||||
RDF.graph([
|
||||
EX.S1 |> EX.p1([EX.O11, EX.O12]),
|
||||
EX.S2 |> EX.p2(EX.O2),
|
||||
{EX.S31, EX.p31(), EX.O31},
|
||||
{EX.S32, EX.p32(), EX.O32}
|
||||
])
|
||||
end
|
||||
|
||||
test "a functions as shortcut for rdf:type" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
EX.S1 |> a(EX.Class1)
|
||||
EX.S2 |> a(EX.Class1, EX.Class1)
|
||||
EX.S3 |> a(EX.Class1, EX.Class2, EX.Class3)
|
||||
EX.S4 |> a(EX.Class1, EX.Class2, EX.Class3)
|
||||
EX.S5 |> a(EX.Class1, EX.Class2, EX.Class3, EX.Class4)
|
||||
EX.S5 |> a(EX.Class1, EX.Class2, EX.Class3, EX.Class4, EX.Class5)
|
||||
{EX.S6, a(), EX.O2}
|
||||
end
|
||||
|
||||
assert graph ==
|
||||
RDF.graph([
|
||||
EX.S1 |> RDF.type(EX.Class1),
|
||||
EX.S2 |> RDF.type(EX.Class1, EX.Class1),
|
||||
EX.S3 |> RDF.type(EX.Class1, EX.Class2, EX.Class3),
|
||||
EX.S4 |> RDF.type(EX.Class1, EX.Class2, EX.Class3),
|
||||
EX.S5 |> RDF.type(EX.Class1, EX.Class2, EX.Class3, EX.Class4),
|
||||
EX.S5 |> RDF.type(EX.Class1, EX.Class2, EX.Class3, EX.Class4, EX.Class5),
|
||||
{EX.S6, RDF.type(), EX.O2}
|
||||
])
|
||||
end
|
||||
|
||||
test "non-RDF interpretable data is ignored" do
|
||||
assert_raise Builder.Error, "invalid RDF data: 42", fn ->
|
||||
RDF.Graph.build do
|
||||
EX.S |> EX.p(EX.O)
|
||||
42
|
||||
end
|
||||
end
|
||||
|
||||
assert_raise Builder.Error, "invalid RDF data: \"foo\"", fn ->
|
||||
RDF.Graph.build do
|
||||
EX.S |> EX.p(EX.O)
|
||||
"foo"
|
||||
end
|
||||
end
|
||||
|
||||
assert_raise Builder.Error, "invalid RDF data: {:ok, \"foo\"}", fn ->
|
||||
RDF.Graph.build do
|
||||
EX.S |> EX.p(EX.O)
|
||||
{:ok, "foo"}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
test "variable assignments" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
EX.S1 |> EX.p1(EX.O1)
|
||||
literal = "foo"
|
||||
EX.S2 |> EX.p2(literal)
|
||||
end
|
||||
|
||||
assert graph ==
|
||||
RDF.graph([
|
||||
EX.S1 |> EX.p1(EX.O1),
|
||||
EX.S2 |> EX.p2("foo")
|
||||
])
|
||||
end
|
||||
|
||||
test "function applications" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
Enum.map(1..3, &{EX.S, EX.p(), &1})
|
||||
|
||||
Enum.map(1..2, fn i ->
|
||||
RDF.iri("http://example.com/foo#{i}")
|
||||
|> EX.bar(RDF.bnode("baz#{i}"))
|
||||
end)
|
||||
end
|
||||
|
||||
assert graph ==
|
||||
RDF.graph([
|
||||
{EX.S, EX.p(), 1},
|
||||
{EX.S, EX.p(), 2},
|
||||
{EX.S, EX.p(), 3},
|
||||
{RDF.iri("http://example.com/foo1"), EX.bar(), RDF.bnode("baz1")},
|
||||
{RDF.iri("http://example.com/foo2"), EX.bar(), RDF.bnode("baz2")}
|
||||
])
|
||||
end
|
||||
|
||||
test "conditionals" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
foo = false
|
||||
|
||||
cond do
|
||||
true -> EX.S1 |> EX.p1(EX.O1)
|
||||
end
|
||||
|
||||
if foo do
|
||||
EX.S2 |> EX.p2(EX.O2)
|
||||
end
|
||||
end
|
||||
|
||||
assert graph == RDF.graph([EX.S1 |> EX.p1(EX.O1)])
|
||||
end
|
||||
|
||||
test "comprehensions" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
range = 1..3
|
||||
|
||||
for i <- range do
|
||||
EX.S |> EX.p(i)
|
||||
end
|
||||
end
|
||||
|
||||
assert graph ==
|
||||
RDF.graph([
|
||||
{EX.S, EX.p(), 1},
|
||||
{EX.S, EX.p(), 2},
|
||||
{EX.S, EX.p(), 3}
|
||||
])
|
||||
end
|
||||
|
||||
test "RDF.Sigils is imported" do
|
||||
# we're wrapping this in a function to isolate the import
|
||||
graph =
|
||||
(fn ->
|
||||
RDF.Graph.build do
|
||||
~I"http://test/iri" |> EX.p(~B"foo")
|
||||
end
|
||||
end).()
|
||||
|
||||
assert graph == RDF.graph(RDF.iri("http://test/iri") |> EX.p(RDF.bnode("foo")))
|
||||
end
|
||||
|
||||
test "RDF.XSD is aliased" do
|
||||
# we're wrapping this in a function to isolate the alias
|
||||
graph =
|
||||
(fn ->
|
||||
RDF.Graph.build do
|
||||
EX.S |> EX.p(XSD.byte(42))
|
||||
end
|
||||
end).()
|
||||
|
||||
assert graph == RDF.graph(EX.S |> EX.p(RDF.XSD.byte(42)))
|
||||
end
|
||||
|
||||
test "default aliases" do
|
||||
# we're wrapping this in a function to isolate the alias
|
||||
graph =
|
||||
(fn ->
|
||||
RDF.Graph.build do
|
||||
OWL.Class |> RDFS.subClassOf(RDFS.Class)
|
||||
end
|
||||
end).()
|
||||
|
||||
assert graph == RDF.graph(NS.OWL.Class |> NS.RDFS.subClassOf(NS.RDFS.Class))
|
||||
end
|
||||
|
||||
test "alias" do
|
||||
# we're wrapping this in a function to isolate the alias
|
||||
graph =
|
||||
(fn ->
|
||||
RDF.Graph.build do
|
||||
alias TestNS.Custom
|
||||
# alias RDF.Graph.BuilderTest.TestNS.Custom
|
||||
Custom.S |> Custom.p(Custom.O)
|
||||
end
|
||||
end).()
|
||||
|
||||
assert graph == RDF.graph(TestNS.Custom.S |> TestNS.Custom.p(TestNS.Custom.O))
|
||||
end
|
||||
|
||||
test "import" do
|
||||
# we're wrapping this in a function to isolate the import
|
||||
graph =
|
||||
(fn ->
|
||||
RDF.Graph.build do
|
||||
import RDF.Graph.BuilderTest.TestNS.ImportTest
|
||||
EX.S |> foo(RDF.Graph.BuilderTest.TestNS.ImportTest.Bar)
|
||||
end
|
||||
end).()
|
||||
|
||||
assert graph == RDF.graph(EX.S |> TestNS.ImportTest.foo(TestNS.ImportTest.Bar))
|
||||
end
|
||||
|
||||
test "require" do
|
||||
{graph, log} =
|
||||
with_log(fn ->
|
||||
RDF.Graph.build do
|
||||
require Logger
|
||||
Logger.info("logged successfully")
|
||||
EX.S |> EX.p(EX.O)
|
||||
end
|
||||
end)
|
||||
|
||||
assert graph == RDF.graph(EX.S |> EX.p(EX.O))
|
||||
assert log =~ "logged successfully"
|
||||
end
|
||||
|
||||
test "use" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
use UseTest
|
||||
EX.S |> EX.p(EX.O)
|
||||
end
|
||||
|
||||
assert graph == RDF.graph(EX.S |> EX.p(EX.O))
|
||||
end
|
||||
|
||||
describe "@prefix" do
|
||||
test "for vocabulary namespace with explicit prefix" do
|
||||
# we're wrapping this in a function to isolate the alias
|
||||
graph =
|
||||
(fn ->
|
||||
RDF.Graph.build do
|
||||
# TODO: the following leads to a (RDF.Namespace.UndefinedTermError) Elixir.TestNS is not a RDF.Namespace
|
||||
# @prefix custom: TestNS.Custom
|
||||
@prefix cust: RDF.Graph.BuilderTest.TestNS.Custom
|
||||
|
||||
Custom.S |> Custom.p(Custom.O)
|
||||
end
|
||||
end).()
|
||||
|
||||
assert graph ==
|
||||
RDF.graph(TestNS.Custom.S |> TestNS.Custom.p(TestNS.Custom.O),
|
||||
prefixes: RDF.default_prefixes(cust: TestNS.Custom)
|
||||
)
|
||||
end
|
||||
|
||||
test "for vocabulary namespace with auto-generated prefix" do
|
||||
# we're wrapping this in a function to isolate the alias
|
||||
graph =
|
||||
(fn ->
|
||||
RDF.Graph.build do
|
||||
# TODO: the following leads to a (RDF.Namespace.UndefinedTermError) Elixir.TestNS is not a RDF.Namespace
|
||||
# @prefix custom: TestNS.Custom
|
||||
@prefix RDF.Graph.BuilderTest.TestNS.Custom
|
||||
|
||||
Custom.S |> Custom.p(Custom.O)
|
||||
end
|
||||
end).()
|
||||
|
||||
assert graph ==
|
||||
RDF.graph(TestNS.Custom.S |> TestNS.Custom.p(TestNS.Custom.O),
|
||||
prefixes: RDF.default_prefixes(custom: TestNS.Custom)
|
||||
)
|
||||
end
|
||||
|
||||
test "merge with prefixes opt" do
|
||||
# we're wrapping this in a function to isolate the alias
|
||||
graph =
|
||||
(fn ->
|
||||
RDF.Graph.build prefixes: [custom: EX] do
|
||||
# TODO: the following leads to a (RDF.Namespace.UndefinedTermError) Elixir.TestNS is not a RDF.Namespace
|
||||
# @prefix custom: TestNS.Custom
|
||||
@prefix custom: RDF.Graph.BuilderTest.TestNS.Custom
|
||||
|
||||
Custom.S |> Custom.p(Custom.O)
|
||||
end
|
||||
end).()
|
||||
|
||||
assert graph ==
|
||||
RDF.graph(TestNS.Custom.S |> TestNS.Custom.p(TestNS.Custom.O),
|
||||
prefixes: [custom: TestNS.Custom]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe "@base" do
|
||||
test "with vocabulary namespace" do
|
||||
# we're wrapping this in a function to isolate the alias
|
||||
graph =
|
||||
(fn ->
|
||||
RDF.Graph.build do
|
||||
# TODO: the following leads to a (RDF.Namespace.UndefinedTermError) Elixir.TestNS is not a RDF.Namespace
|
||||
# @prefix custom: TestNS.Custom
|
||||
@base RDF.Graph.BuilderTest.TestNS.Custom
|
||||
|
||||
Custom.S |> Custom.p(Custom.O)
|
||||
end
|
||||
end).()
|
||||
|
||||
assert graph ==
|
||||
RDF.graph(TestNS.Custom.S |> TestNS.Custom.p(TestNS.Custom.O),
|
||||
base_iri: TestNS.Custom
|
||||
)
|
||||
end
|
||||
|
||||
test "with RDF.IRI" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
@base ~I<http://example.com/base>
|
||||
|
||||
EX.S |> EX.p(EX.O)
|
||||
end
|
||||
|
||||
assert graph == RDF.graph(EX.S |> EX.p(EX.O), base_iri: "http://example.com/base")
|
||||
end
|
||||
|
||||
test "with URI as string" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
@base "http://example.com/base"
|
||||
|
||||
EX.S |> EX.p(EX.O)
|
||||
end
|
||||
|
||||
assert graph == RDF.graph(EX.S |> EX.p(EX.O), base_iri: "http://example.com/base")
|
||||
end
|
||||
|
||||
test "with URI from variable" do
|
||||
graph =
|
||||
RDF.Graph.build do
|
||||
foo = "http://example.com/base"
|
||||
@base foo
|
||||
|
||||
EX.S |> EX.p(EX.O)
|
||||
end
|
||||
|
||||
assert graph == RDF.graph(EX.S |> EX.p(EX.O), base_iri: "http://example.com/base")
|
||||
end
|
||||
|
||||
test "conflict with base_iri opt" do
|
||||
graph =
|
||||
RDF.Graph.build base_iri: "http://example.com/old" do
|
||||
@base "http://example.com/base"
|
||||
|
||||
EX.S |> EX.p(EX.O)
|
||||
end
|
||||
|
||||
assert graph == RDF.graph(EX.S |> EX.p(EX.O), base_iri: "http://example.com/base")
|
||||
end
|
||||
end
|
||||
|
||||
test "opts" do
|
||||
initial = {EX.S, EX.p(), "init"}
|
||||
|
||||
opts = [
|
||||
name: EX.Graph,
|
||||
base_iri: "http://base_iri/",
|
||||
prefixes: [ex: EX],
|
||||
init: initial
|
||||
]
|
||||
|
||||
graph =
|
||||
RDF.Graph.build opts do
|
||||
EX.S |> EX.p(EX.O)
|
||||
end
|
||||
|
||||
assert graph == RDF.graph(EX.S |> EX.p(EX.O, "init"), opts)
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue