From fe49c0e43145820197add8d446571154b9d304d3 Mon Sep 17 00:00:00 2001 From: Marcel Otto Date: Thu, 8 Aug 2019 22:26:07 +0200 Subject: [PATCH] Move base IRI coercion from PrefixMap into new RDF.IRI.coerce_base/1 - and extend it to also support terms from vocabulary namespaces --- CHANGELOG.md | 4 ++++ lib/rdf/iri.ex | 19 +++++++++++++++++ lib/rdf/prefix_map.ex | 16 ++------------ test/unit/iri_test.exs | 39 ++++++++++++++++++++++++++++++++++- test/unit/prefix_map_test.exs | 2 +- 5 files changed, 64 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 15c6b0f..78f1acd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This project adheres to [Semantic Versioning](http://semver.org/) and option on `RDF.Graph.new` or the the new functions `RDF.Graph.set_base_iri/2` and `RDF.Graph.clear_base_iri/1` - `RDF.Graph.clear_metadata/1` which clears the base IRI and the prefixes +- `RDF.IRI.coerce_base/1` which coerces base IRIs; as opposed to `RDF.IRI.new/1` + it also accepts bare `RDF.Vocabulary.Namespace` modules ### Changed @@ -24,6 +26,8 @@ This project adheres to [Semantic Versioning](http://semver.org/) and - from the `base_iri` field of the given graph - from the `RDF.default_base_iri` returning the one from the application configuration +- `RDF.PrefixMap.new` and `RDF.PrefixMap.add` now also terms from + `RDF.Vocabulary.Namespace`s as namespaces [Compare v0.6.1...HEAD](https://github.com/marcelotto/rdf-ex/compare/v0.6.1...HEAD) diff --git a/lib/rdf/iri.ex b/lib/rdf/iri.ex index a614c7f..bc8bbe8 100644 --- a/lib/rdf/iri.ex +++ b/lib/rdf/iri.ex @@ -65,6 +65,25 @@ defmodule RDF.IRI do def new!(%RDF.IRI{} = iri), do: valid!(iri) + @doc """ + Coerces an IRI serving as a base IRI. + + As opposed to `new/1` this also accepts bare `RDF.Vocabulary.Namespace` modules + and uses the base IRI from their definition. + """ + def coerce_base(base_iri) + + def coerce_base(module) when is_atom(module) do + if RDF.Vocabulary.Namespace.vocabulary_namespace?(module) do + apply(module, :__base_iri__, []) + |> new() + else + new(module) + end + end + def coerce_base(base_iri), do: new(base_iri) + + @doc """ Returns the given value unchanged if it's a valid IRI, otherwise raises an exception. diff --git a/lib/rdf/prefix_map.ex b/lib/rdf/prefix_map.ex index 9ba7b14..cf49412 100644 --- a/lib/rdf/prefix_map.ex +++ b/lib/rdf/prefix_map.ex @@ -33,24 +33,12 @@ defmodule RDF.PrefixMap do map |> Map.new() |> new() end - defp normalize({prefix, %IRI{} = namespace}) when is_atom(prefix), - do: {prefix, namespace} + defp normalize({prefix, namespace}) when is_atom(prefix), + do: {prefix, IRI.coerce_base(namespace)} defp normalize({prefix, namespace}) when is_binary(prefix), do: normalize({String.to_atom(prefix), namespace}) - defp normalize({prefix, namespace}) when is_binary(namespace), - do: normalize({prefix, IRI.new(namespace)}) - - defp normalize({prefix, namespace}) when is_atom(namespace) do - if RDF.Vocabulary.Namespace.vocabulary_namespace?(namespace) do - normalize({prefix, apply(namespace, :__base_iri__, [])}) - else - raise ArgumentError, - "Invalid prefix mapping for #{inspect(prefix)}, #{inspect(namespace)} is not a vocabulary namespace" - end - end - defp normalize({prefix, namespace}), do: raise(ArgumentError, "Invalid prefix mapping: #{inspect(prefix)} => #{inspect(namespace)}") diff --git a/test/unit/iri_test.exs b/test/unit/iri_test.exs index 055834d..b201b5e 100644 --- a/test/unit/iri_test.exs +++ b/test/unit/iri_test.exs @@ -106,6 +106,44 @@ defmodule RDF.IRITest do end + describe "coerce_base/1" do + test "with a string" do + assert IRI.coerce_base("http://example.com/") == IRI.new("http://example.com/") + end + + test "with a RDF.IRI" do + assert IRI.coerce_base(IRI.new("http://example.com/")) == IRI.new("http://example.com/") + end + + test "with a URI" do + assert IRI.coerce_base(URI.parse("http://example.com/")) == + IRI.new(URI.parse("http://example.com/")) + end + + test "with a resolvable atom" do + assert IRI.coerce_base(EX.Foo) == IRI.new(EX.Foo) + end + + test "with a non-resolvable atom" do + assert_raise RDF.Namespace.UndefinedTermError, fn -> IRI.coerce_base(Foo.Bar) end + end + + test "with Elixirs special atoms" do + assert_raise FunctionClauseError, fn -> IRI.coerce_base(true) end + assert_raise FunctionClauseError, fn -> IRI.coerce_base(false) end + assert_raise FunctionClauseError, fn -> IRI.coerce_base(nil) end + end + + test "with a RDF.Vocabulary.Namespace module" do + assert IRI.coerce_base(EX) == IRI.new(EX.__base_iri__) + end + + test "with a RDF.Vocabulary.Namespace module which is not loaded yet" do + assert IRI.coerce_base(RDF.NS.SKOS) == ~I + end + end + + describe "valid!/1" do test "with valid iris" do Enum.each(valid_iris(), fn valid_iri -> @@ -277,7 +315,6 @@ defmodule RDF.IRITest do end end - describe "parse/1" do test "with absolute and relative iris" do Enum.each(absolute_iris() ++ relative_iris(), fn iri -> diff --git a/test/unit/prefix_map_test.exs b/test/unit/prefix_map_test.exs index c8f95fe..66f195b 100644 --- a/test/unit/prefix_map_test.exs +++ b/test/unit/prefix_map_test.exs @@ -80,7 +80,7 @@ defmodule RDF.PrefixMapTest do end test "when the IRI namespace is given as an atom" do - assert_raise ArgumentError, "Invalid prefix mapping for :ex, :foo is not a vocabulary namespace", fn -> + assert_raise RDF.Namespace.UndefinedTermError, "foo is not a term on a RDF.Namespace", fn -> PrefixMap.add(@example1, :ex, :foo) end end