From 733ee44749811e3bb1cffb982d9c816dcdd1b996 Mon Sep 17 00:00:00 2001 From: Marcel Otto Date: Wed, 14 Mar 2018 11:46:11 +0100 Subject: [PATCH] Add RDF.Literal.new!/2 --- CHANGELOG.md | 10 ++++++++-- README.md | 5 +++-- lib/rdf/inspect.ex | 16 +++++++++++----- lib/rdf/literal.ex | 39 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a322c91..17fdcf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,10 +7,16 @@ This project adheres to [Semantic Versioning](http://semver.org/) and ## Unreleased +### Added + +- `RDF.Literal.new!/2` which fails when creating an invalid literal + + ### Changed -- `Literal.new/2` can create `rdf:langString` literals without failing, they are - simply invalid +- `RDF.Literal.new/2` can create `rdf:langString` literals without failing, they + are simply invalid; if you want to fail without a language tag use the new + `RDF.Literal.new!/2` function [Compare v0.4.0...HEAD](https://github.com/marcelotto/rdf-ex/compare/v0.4.0...HEAD) diff --git a/README.md b/README.md index 3d15380..d8ff615 100644 --- a/README.md +++ b/README.md @@ -349,6 +349,8 @@ iex> RDF.Literal.valid? RDF.Integer.new("foo") false ``` +If you want to prohibit the creation of invalid literals, you can use the `new!` constructor function of `RDF.Datatype` or `RDF.Literal`, which will fail in case of invalid values. + A RDF literal is bound to the lexical form of the initially given value. This lexical representation can be retrieved with the `RDF.Literal.lexical/1` function: ```elixir @@ -706,8 +708,7 @@ Note: The later command requires the `json_ld` package to be defined as a depend The file read and write functions are also able to infer the format from the file extension of the given filename. ```elixir -"/path/to/some_file.ttl" -|> RDF.read_file!() +RDF.read_file!("/path/to/some_file.ttl") |> RDF.write_file!("/path/to/some_file.jsonld") ``` diff --git a/lib/rdf/inspect.ex b/lib/rdf/inspect.ex index e36a8f4..cbb5e48 100644 --- a/lib/rdf/inspect.ex +++ b/lib/rdf/inspect.ex @@ -48,6 +48,9 @@ defimpl Inspect, for: RDF.BlankNode do end defimpl Inspect, for: RDF.Literal do + @xsd_string RDF.Datatype.NS.XSD.string + @rdf_lang_string RDF.langString + def inspect(%RDF.Literal{value: value, language: language}, _opts) when not is_nil(language) do ~s[~L"#{value}"#{language}] end @@ -57,11 +60,14 @@ defimpl Inspect, for: RDF.Literal do "%RDF.Literal{value: #{inspect value}, lexical: #{inspect lexical}, datatype: ~I<#{datatype}>}" end - def inspect(%RDF.Literal{value: value, datatype: datatype}, _opts) do - if datatype == RDF.Datatype.NS.XSD.string do - ~s[~L"#{value}"] - else - "%RDF.Literal{value: #{inspect value}, datatype: ~I<#{datatype}>}" + def inspect(%RDF.Literal{value: value, datatype: datatype, language: language}, _opts) do + case datatype do + @xsd_string -> + ~s[~L"#{value}"] + @rdf_lang_string -> + "%RDF.Literal{value: #{inspect value}, datatype: ~I<#{datatype}>, language: #{inspect language}}" + _ -> + "%RDF.Literal{value: #{inspect value}, datatype: ~I<#{datatype}>}" end end end diff --git a/lib/rdf/literal.ex b/lib/rdf/literal.ex index 12f96e2..529dd24 100644 --- a/lib/rdf/literal.ex +++ b/lib/rdf/literal.ex @@ -59,6 +59,11 @@ defmodule RDF.Literal do raise RDF.Literal.InvalidError, "#{inspect value} not convertible to a RDF.Literal" end + @doc """ + Creates a new `RDF.Literal` with the given datatype or language tag. + """ + def new(value, opts) + def new(value, opts) when is_list(opts), do: new(value, Map.new(opts)) @@ -88,6 +93,40 @@ defmodule RDF.Literal do do: new(value) + @doc """ + Creates a new `RDF.Literal`, but fails if it's not valid. + + Note: Validation is only possible if an `RDF.Datatype` with an implementation of + `RDF.Datatype.valid?/1` exists. + + ## Examples + + iex> RDF.Literal.new!("3.14", datatype: XSD.double) == RDF.Literal.new("3.14", datatype: XSD.double) + true + + iex> RDF.Literal.new!("invalid", datatype: "http://example/unkown_datatype") == RDF.Literal.new("invalid", datatype: "http://example/unkown_datatype") + true + + iex> RDF.Literal.new!("foo", datatype: XSD.integer) + ** (RDF.Literal.InvalidError) invalid RDF.Literal: %RDF.Literal{value: nil, lexical: "foo", datatype: ~I} + + iex> RDF.Literal.new!("foo", datatype: RDF.langString) + ** (RDF.Literal.InvalidError) invalid RDF.Literal: %RDF.Literal{value: "foo", datatype: ~I, language: nil} + + """ + def new!(value, opts \\ %{}) do + with %RDF.Literal{} = literal <- new(value, opts) do + if valid?(literal) do + literal + else + raise RDF.Literal.InvalidError, "invalid RDF.Literal: #{inspect literal}" + end + else + invalid -> + raise RDF.Literal.InvalidError, "invalid result of RDF.Literal.new: #{inspect invalid}" + end + end + @doc """ Returns the given literal with the canonical lexical representation according to its datatype. """