diff --git a/.formatter.exs b/.formatter.exs index 00bbc7a..bed7f06 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,5 +1,7 @@ locals_without_parens = [ defvocab: 2, + def_facet_constraint: 2, + def_applicable_facet: 1, bgp: 1 ] diff --git a/bench/bgp.exs b/bench/bgp.exs index 8b8cddc..c36462d 100644 --- a/bench/bgp.exs +++ b/bench/bgp.exs @@ -2,46 +2,63 @@ defmodule NS do use RDF.Vocabulary.Namespace defvocab MF, - base_iri: "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", - terms: [], strict: false + base_iri: "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", + terms: [], + strict: false - defvocab RDFT, - base_iri: "http://www.w3.org/ns/rdftest#", - terms: [], strict: false + defvocab RDFT, base_iri: "http://www.w3.org/ns/rdftest#", terms: [], strict: false end alias NS.{MF, RDFT} alias RDF.NS.RDFS alias RDF.Query.BGP -test_graph = RDF.Turtle.read_file!("test/data/TURTLE-TESTS/manifest.ttl", base: "http://www.w3.org/2013/TurtleTests/") +test_graph = + RDF.Turtle.read_file!("test/data/TURTLE-TESTS/manifest.ttl", + base: "http://www.w3.org/2013/TurtleTests/" + ) all_query = %BGP{triple_patterns: [{:s, :p, :o}]} + Benchee.run(%{ "take 1 from BGP.Simple" => fn -> BGP.Simple.stream(all_query, test_graph) |> Enum.take(1) end, - "take 1 from BGP.Stream" => fn -> BGP.Stream.stream(all_query, test_graph) |> Enum.take(1) end, + "take 1 from BGP.Stream" => fn -> BGP.Stream.stream(all_query, test_graph) |> Enum.take(1) end }) - # rdft:approval rdft:Approved - count: 287 -approved_query = %BGP{triple_patterns: [ - {:test_case, RDFT.approval, RDF.iri(RDFT.Approved)}, - {:test_case, MF.name, :name}, - {:test_case, RDFS.comment, :comment}, -]} +approved_query = %BGP{ + triple_patterns: [ + {:test_case, RDFT.approval(), RDF.iri(RDFT.Approved)}, + {:test_case, MF.name(), :name}, + {:test_case, RDFS.comment(), :comment} + ] +} + # rdft:approval rdft:Proposed - count: 4 -proposed_query = %BGP{triple_patterns: [ - {:test_case, RDFT.approval, RDF.iri(RDFT.Proposed)}, - {:test_case, MF.name, :name}, - {:test_case, RDFS.comment, :comment}, -]} +proposed_query = %BGP{ + triple_patterns: [ + {:test_case, RDFT.approval(), RDF.iri(RDFT.Proposed)}, + {:test_case, MF.name(), :name}, + {:test_case, RDFS.comment(), :comment} + ] +} + Benchee.run(%{ "APPROVED from BGP.Simple" => fn -> BGP.Simple.execute(approved_query, test_graph) end, "PROPOSED from BGP.Simple" => fn -> BGP.Simple.execute(proposed_query, test_graph) end, - - "APPROVED from BGP.Stream (consumed)" => fn -> BGP.Stream.execute(approved_query, test_graph) end, - "PROPOSED from BGP.Stream (consumed)" => fn -> BGP.Stream.execute(proposed_query, test_graph) end, - "APPROVED from BGP.Stream (unconsumed)" => fn -> BGP.Stream.stream(approved_query, test_graph) end, - "PROPOSED from BGP.Stream (unconsumed)" => fn -> BGP.Stream.stream(proposed_query, test_graph) end, - "APPROVED from BGP.Stream (1 consumed)" => fn -> BGP.Stream.stream(approved_query, test_graph) |> Enum.take(1) end + "APPROVED from BGP.Stream (consumed)" => fn -> + BGP.Stream.execute(approved_query, test_graph) + end, + "PROPOSED from BGP.Stream (consumed)" => fn -> + BGP.Stream.execute(proposed_query, test_graph) + end, + "APPROVED from BGP.Stream (unconsumed)" => fn -> + BGP.Stream.stream(approved_query, test_graph) + end, + "PROPOSED from BGP.Stream (unconsumed)" => fn -> + BGP.Stream.stream(proposed_query, test_graph) + end, + "APPROVED from BGP.Stream (1 consumed)" => fn -> + BGP.Stream.stream(approved_query, test_graph) |> Enum.take(1) + end }) diff --git a/lib/rdf.ex b/lib/rdf.ex index 915d61c..65b375c 100644 --- a/lib/rdf.ex +++ b/lib/rdf.ex @@ -40,18 +40,27 @@ defmodule RDF do For a general introduction you may refer to the guides on the [homepage](https://rdf-elixir.dev). """ - alias RDF.{IRI, Namespace, Literal, BlankNode, Triple, Quad, - Description, Graph, Dataset, PrefixMap} + alias RDF.{ + IRI, + Namespace, + Literal, + BlankNode, + Triple, + Quad, + Description, + Graph, + Dataset, + PrefixMap + } import RDF.Guards import RDF.Utils.Bootstrapping defdelegate default_base_iri(), to: RDF.IRI, as: :default_base - @standard_prefixes PrefixMap.new( - xsd: xsd_iri_base(), - rdf: rdf_iri_base(), + xsd: xsd_iri_base(), + rdf: rdf_iri_base(), rdfs: rdfs_iri_base() ) @@ -67,7 +76,6 @@ defmodule RDF do """ def standard_prefixes(), do: @standard_prefixes - @doc """ A user-defined `RDF.PrefixMap` of prefixes to IRI namespaces. @@ -114,16 +122,15 @@ defmodule RDF do default_prefixes() |> PrefixMap.merge!(prefix_mappings) end - defdelegate read_string(content, opts), to: RDF.Serialization - defdelegate read_string!(content, opts), to: RDF.Serialization - defdelegate read_file(filename, opts \\ []), to: RDF.Serialization - defdelegate read_file!(filename, opts \\ []), to: RDF.Serialization - defdelegate write_string(content, opts), to: RDF.Serialization - defdelegate write_string!(content, opts), to: RDF.Serialization - defdelegate write_file(content, filename, opts \\ []), to: RDF.Serialization + defdelegate read_string(content, opts), to: RDF.Serialization + defdelegate read_string!(content, opts), to: RDF.Serialization + defdelegate read_file(filename, opts \\ []), to: RDF.Serialization + defdelegate read_file!(filename, opts \\ []), to: RDF.Serialization + defdelegate write_string(content, opts), to: RDF.Serialization + defdelegate write_string!(content, opts), to: RDF.Serialization + defdelegate write_file(content, filename, opts \\ []), to: RDF.Serialization defdelegate write_file!(content, filename, opts \\ []), to: RDF.Serialization - @doc """ Checks if the given value is a RDF resource. @@ -149,6 +156,7 @@ defmodule RDF do def resource?(value) def resource?(%IRI{}), do: true def resource?(%BlankNode{}), do: true + def resource?(qname) when maybe_ns_term(qname) do case Namespace.resolve_term(qname) do {:ok, iri} -> resource?(iri) @@ -182,12 +190,12 @@ defmodule RDF do """ def term?(value) def term?(%Literal{}), do: true - def term?(value), do: resource?(value) + def term?(value), do: resource?(value) defdelegate uri?(value), to: IRI, as: :valid? defdelegate iri?(value), to: IRI, as: :valid? - defdelegate uri(value), to: IRI, as: :new - defdelegate iri(value), to: IRI, as: :new + defdelegate uri(value), to: IRI, as: :new + defdelegate iri(value), to: IRI, as: :new defdelegate uri!(value), to: IRI, as: :new! defdelegate iri!(value), to: IRI, as: :new! @@ -206,7 +214,7 @@ defmodule RDF do def bnode?(%BlankNode{}), do: true def bnode?(_), do: false - defdelegate bnode(), to: BlankNode, as: :new + defdelegate bnode(), to: BlankNode, as: :new defdelegate bnode(id), to: BlankNode, as: :new @doc """ @@ -215,59 +223,59 @@ defmodule RDF do def literal?(%Literal{}), do: true def literal?(_), do: false - defdelegate literal(value), to: Literal, as: :new + defdelegate literal(value), to: Literal, as: :new defdelegate literal(value, opts), to: Literal, as: :new - defdelegate triple(s, p, o), to: Triple, as: :new - defdelegate triple(tuple), to: Triple, as: :new + defdelegate triple(s, p, o), to: Triple, as: :new + defdelegate triple(tuple), to: Triple, as: :new defdelegate quad(s, p, o, g), to: Quad, as: :new - defdelegate quad(tuple), to: Quad, as: :new + defdelegate quad(tuple), to: Quad, as: :new - defdelegate description(arg), to: Description, as: :new - defdelegate description(arg1, arg2), to: Description, as: :new - defdelegate description(arg1, arg2, arg3), to: Description, as: :new + defdelegate description(arg), to: Description, as: :new + defdelegate description(arg1, arg2), to: Description, as: :new + defdelegate description(arg1, arg2, arg3), to: Description, as: :new - defdelegate graph(), to: Graph, as: :new - defdelegate graph(arg), to: Graph, as: :new - defdelegate graph(arg1, arg2), to: Graph, as: :new - defdelegate graph(arg1, arg2, arg3), to: Graph, as: :new - defdelegate graph(arg1, arg2, arg3, arg4), to: Graph, as: :new + defdelegate graph(), to: Graph, as: :new + defdelegate graph(arg), to: Graph, as: :new + defdelegate graph(arg1, arg2), to: Graph, as: :new + defdelegate graph(arg1, arg2, arg3), to: Graph, as: :new + defdelegate graph(arg1, arg2, arg3, arg4), to: Graph, as: :new - defdelegate dataset(), to: Dataset, as: :new - defdelegate dataset(arg), to: Dataset, as: :new - defdelegate dataset(arg1, arg2), to: Dataset, as: :new + defdelegate dataset(), to: Dataset, as: :new + defdelegate dataset(arg), to: Dataset, as: :new + defdelegate dataset(arg1, arg2), to: Dataset, as: :new defdelegate diff(arg1, arg2), to: RDF.Diff defdelegate list?(resource, graph), to: RDF.List, as: :node? - defdelegate list?(description), to: RDF.List, as: :node? + defdelegate list?(description), to: RDF.List, as: :node? - def list(native_list), do: RDF.List.from(native_list) + def list(native_list), do: RDF.List.from(native_list) def list(head, %Graph{} = graph), do: RDF.List.new(head, graph) - def list(native_list, opts), do: RDF.List.from(native_list, opts) + def list(native_list, opts), do: RDF.List.from(native_list, opts) defdelegate prefix_map(prefixes), to: RDF.PrefixMap, as: :new - defdelegate langString(value, opts), to: RDF.LangString, as: :new + defdelegate langString(value, opts), to: RDF.LangString, as: :new defdelegate lang_string(value, opts), to: RDF.LangString, as: :new for term <- ~w[type subject predicate object first rest value]a do - defdelegate unquote(term)(), to: RDF.NS.RDF + defdelegate unquote(term)(), to: RDF.NS.RDF @doc false - defdelegate unquote(term)(s, o), to: RDF.NS.RDF + defdelegate unquote(term)(s, o), to: RDF.NS.RDF @doc false - defdelegate unquote(term)(s, o1, o2), to: RDF.NS.RDF + defdelegate unquote(term)(s, o1, o2), to: RDF.NS.RDF @doc false - defdelegate unquote(term)(s, o1, o2, o3), to: RDF.NS.RDF + defdelegate unquote(term)(s, o1, o2, o3), to: RDF.NS.RDF @doc false - defdelegate unquote(term)(s, o1, o2, o3, o4), to: RDF.NS.RDF + defdelegate unquote(term)(s, o1, o2, o3, o4), to: RDF.NS.RDF @doc false defdelegate unquote(term)(s, o1, o2, o3, o4, o5), to: RDF.NS.RDF end - defdelegate langString(), to: RDF.NS.RDF - defdelegate lang_string(), to: RDF.NS.RDF, as: :langString + defdelegate langString(), to: RDF.NS.RDF + defdelegate lang_string(), to: RDF.NS.RDF, as: :langString defdelegate unquote(nil)(), to: RDF.NS.RDF defdelegate __base_iri__(), to: RDF.NS.RDF diff --git a/lib/rdf/blank_node.ex b/lib/rdf/blank_node.ex index 6754cb7..0b433bd 100644 --- a/lib/rdf/blank_node.ex +++ b/lib/rdf/blank_node.ex @@ -7,8 +7,8 @@ defmodule RDF.BlankNode do """ @type t :: %__MODULE__{ - id: String.t - } + id: String.t() + } @enforce_keys [:id] defstruct [:id] @@ -28,19 +28,18 @@ defmodule RDF.BlankNode do iex> RDF.bnode(:foo) %RDF.BlankNode{id: "foo"} """ - @spec new(reference | String.t | atom | integer) :: t + @spec new(reference | String.t() | atom | integer) :: t def new(id) def new(id) when is_binary(id), do: %__MODULE__{id: id} def new(id) when is_reference(id), - do: id |> :erlang.ref_to_list |> to_string |> String.replace(~r/\<|\>/, "") |> new + do: id |> :erlang.ref_to_list() |> to_string |> String.replace(~r/\<|\>/, "") |> new def new(id) when is_atom(id) or is_integer(id), do: id |> to_string |> new - @doc """ Tests for value equality of blank nodes. @@ -55,9 +54,7 @@ defmodule RDF.BlankNode do def equal_value?(_, _), do: nil - defimpl String.Chars do def to_string(%RDF.BlankNode{id: id}), do: "_:#{id}" end - end diff --git a/lib/rdf/blank_node/generator.ex b/lib/rdf/blank_node/generator.ex index db54f18..f717127 100644 --- a/lib/rdf/blank_node/generator.ex +++ b/lib/rdf/blank_node/generator.ex @@ -5,7 +5,6 @@ defmodule RDF.BlankNode.Generator do use GenServer - # Client API ############################################################### @doc """ @@ -30,7 +29,6 @@ defmodule RDF.BlankNode.Generator do defp convert_opts(opts) when is_list(opts), do: Map.new(opts) defp convert_opts(opts) when is_map(opts), do: opts - @doc """ Synchronously stops the blank node generator with the given `reason`. @@ -45,7 +43,6 @@ defmodule RDF.BlankNode.Generator do GenServer.stop(pid, reason, timeout) end - @doc """ Generates a new blank node according to the `RDF.BlankNode.Generator.Algorithm` set up. """ @@ -53,7 +50,6 @@ defmodule RDF.BlankNode.Generator do GenServer.call(pid, :generate) end - @doc """ Generates a blank node for a given value according to the `RDF.BlankNode.Generator.Algorithm` set up. """ @@ -61,7 +57,6 @@ defmodule RDF.BlankNode.Generator do GenServer.call(pid, {:generate_for, value}) end - # Server Callbacks ######################################################### @impl GenServer @@ -69,7 +64,6 @@ defmodule RDF.BlankNode.Generator do {:ok, {generation_mod, generation_mod.init(init_opts)}} end - @impl GenServer def handle_call(:generate, _from, {generation_mod, state}) do with {bnode, new_state} = generation_mod.generate(state) do @@ -83,5 +77,4 @@ defmodule RDF.BlankNode.Generator do {:reply, bnode, {generation_mod, new_state}} end end - end diff --git a/lib/rdf/blank_node/generator_algorithm.ex b/lib/rdf/blank_node/generator_algorithm.ex index 3d10724..9f1867b 100644 --- a/lib/rdf/blank_node/generator_algorithm.ex +++ b/lib/rdf/blank_node/generator_algorithm.ex @@ -16,7 +16,7 @@ defmodule RDF.BlankNode.Generator.Algorithm do An implementation should compute a blank node from the given state and return a tuple consisting of the generated blank node and the new state. """ - @callback generate(state :: map) :: {RDF.BlankNode.t, map} + @callback generate(state :: map) :: {RDF.BlankNode.t(), map} @doc """ Generates a blank node for a given string. @@ -27,6 +27,5 @@ defmodule RDF.BlankNode.Generator.Algorithm do given state and return a tuple consisting of the generated blank node and the new state. """ - @callback generate_for(value :: any, state :: map) :: {RDF.BlankNode.t, map} - + @callback generate_for(value :: any, state :: map) :: {RDF.BlankNode.t(), map} end diff --git a/lib/rdf/blank_node/increment.ex b/lib/rdf/blank_node/increment.ex index b252229..196c581 100644 --- a/lib/rdf/blank_node/increment.ex +++ b/lib/rdf/blank_node/increment.ex @@ -40,7 +40,8 @@ defmodule RDF.BlankNode.Increment do case Map.get(map, value) do nil -> {bnode(counter, state), - %{state | map: Map.put(map, value, counter), counter: counter + 1}} + %{state | map: Map.put(map, value, counter), counter: counter + 1}} + previous -> {bnode(previous, state), state} end @@ -53,5 +54,4 @@ defmodule RDF.BlankNode.Increment do defp bnode(counter, _) do BlankNode.new(counter) end - end diff --git a/lib/rdf/data.ex b/lib/rdf/data.ex index 10d39ae..4684b5b 100644 --- a/lib/rdf/data.ex +++ b/lib/rdf/data.ex @@ -137,10 +137,12 @@ defimpl RDF.Data, for: RDF.Description do def merge(description, {_, _, _, _} = quad), do: RDF.Dataset.new(description) |> RDF.Dataset.add(quad) - def merge(%RDF.Description{subject: subject} = description, - %RDF.Description{subject: other_subject} = other_description) - when other_subject == subject, - do: RDF.Description.add(description, other_description) + def merge( + %RDF.Description{subject: subject} = description, + %RDF.Description{subject: other_subject} = other_description + ) + when other_subject == subject, + do: RDF.Description.add(description, other_description) def merge(description, %RDF.Description{} = other_description), do: RDF.Graph.new(description) |> RDF.Graph.add(other_description) @@ -151,14 +153,16 @@ defimpl RDF.Data, for: RDF.Description do def merge(description, %RDF.Dataset{} = dataset), do: RDF.Data.merge(dataset, description) + def delete( + %RDF.Description{subject: subject} = description, + %RDF.Description{subject: other_subject} + ) + when subject != other_subject, + do: description - def delete(%RDF.Description{subject: subject} = description, - %RDF.Description{subject: other_subject}) - when subject != other_subject, do: description def delete(description, statements), do: RDF.Description.delete(description, statements) - - def pop(description), do: RDF.Description.pop(description) + def pop(description), do: RDF.Description.pop(description) def include?(description, statements), do: RDF.Description.include?(description, statements) @@ -180,14 +184,14 @@ defimpl RDF.Data, for: RDF.Description do def subjects(%RDF.Description{subject: subject}), do: MapSet.new([subject]) def predicates(description), do: RDF.Description.predicates(description) - def objects(description), do: RDF.Description.objects(description) + def objects(description), do: RDF.Description.objects(description) def resources(%RDF.Description{subject: subject} = description), do: RDF.Description.resources(description) |> MapSet.put(subject) - def subject_count(_), do: 1 + def subject_count(_), do: 1 def statement_count(description), do: RDF.Description.count(description) - def values(description), do: RDF.Description.values(description) + def values(description), do: RDF.Description.values(description) def values(description, mapping), do: RDF.Description.values(description, mapping) def equal?(description, %RDF.Description{} = other_description) do @@ -209,7 +213,6 @@ defimpl RDF.Data, for: RDF.Description do def equal?(_, _), do: false end - defimpl RDF.Data, for: RDF.Graph do def merge(%RDF.Graph{name: name} = graph, {_, _, _, graph_context} = quad) do with ^name <- RDF.Statement.coerce_graph_name(graph_context) do @@ -230,10 +233,12 @@ defimpl RDF.Data, for: RDF.Graph do def merge(graph, %RDF.Description{} = description), do: RDF.Graph.add(graph, description) - def merge(%RDF.Graph{name: name} = graph, - %RDF.Graph{name: other_name} = other_graph) - when other_name == name, - do: RDF.Graph.add(graph, other_graph) + def merge( + %RDF.Graph{name: name} = graph, + %RDF.Graph{name: other_name} = other_graph + ) + when other_name == name, + do: RDF.Graph.add(graph, other_graph) def merge(graph, %RDF.Graph{} = other_graph), do: RDF.Dataset.new(graph) |> RDF.Dataset.add(other_graph) @@ -241,12 +246,13 @@ defimpl RDF.Data, for: RDF.Graph do def merge(graph, %RDF.Dataset{} = dataset), do: RDF.Data.merge(dataset, graph) - def delete(%RDF.Graph{name: name} = graph, %RDF.Graph{name: other_name}) - when name != other_name, do: graph + when name != other_name, + do: graph + def delete(graph, statements), do: RDF.Graph.delete(graph, statements) - def pop(graph), do: RDF.Graph.pop(graph) + def pop(graph), do: RDF.Graph.pop(graph) def include?(graph, statements), do: RDF.Graph.include?(graph, statements) @@ -260,22 +266,25 @@ defimpl RDF.Data, for: RDF.Graph do def statements(graph), do: RDF.Graph.statements(graph) - def subjects(graph), do: RDF.Graph.subjects(graph) + def subjects(graph), do: RDF.Graph.subjects(graph) def predicates(graph), do: RDF.Graph.predicates(graph) - def objects(graph), do: RDF.Graph.objects(graph) - def resources(graph), do: RDF.Graph.resources(graph) + def objects(graph), do: RDF.Graph.objects(graph) + def resources(graph), do: RDF.Graph.resources(graph) - def subject_count(graph), do: RDF.Graph.subject_count(graph) + def subject_count(graph), do: RDF.Graph.subject_count(graph) def statement_count(graph), do: RDF.Graph.triple_count(graph) - def values(graph), do: RDF.Graph.values(graph) + def values(graph), do: RDF.Graph.values(graph) def values(graph, mapping), do: RDF.Graph.values(graph, mapping) def equal?(graph, %RDF.Description{} = description), do: RDF.Data.equal?(description, graph) def equal?(graph, %RDF.Graph{} = other_graph), - do: RDF.Graph.equal?(%RDF.Graph{graph | name: nil}, - %RDF.Graph{other_graph | name: nil}) + do: + RDF.Graph.equal?( + %RDF.Graph{graph | name: nil}, + %RDF.Graph{other_graph | name: nil} + ) def equal?(graph, %RDF.Dataset{} = dataset), do: RDF.Data.equal?(dataset, graph) @@ -283,25 +292,29 @@ defimpl RDF.Data, for: RDF.Graph do def equal?(_, _), do: false end - defimpl RDF.Data, for: RDF.Dataset do def merge(dataset, {_, _, _} = triple), do: RDF.Dataset.add(dataset, triple) + def merge(dataset, {_, _, _, _} = quad), do: RDF.Dataset.add(dataset, quad) + def merge(dataset, %RDF.Description{} = description), do: RDF.Dataset.add(dataset, description) + def merge(dataset, %RDF.Graph{} = graph), do: RDF.Dataset.add(dataset, graph) + def merge(dataset, %RDF.Dataset{} = other_dataset), do: RDF.Dataset.add(dataset, other_dataset) - def delete(%RDF.Dataset{name: name} = dataset, %RDF.Dataset{name: other_name}) - when name != other_name, do: dataset + when name != other_name, + do: dataset + def delete(dataset, statements), do: RDF.Dataset.delete(dataset, statements) - def pop(dataset), do: RDF.Dataset.pop(dataset) + def pop(dataset), do: RDF.Dataset.pop(dataset) def include?(dataset, statements), do: RDF.Dataset.include?(dataset, statements) @@ -310,31 +323,32 @@ defimpl RDF.Data, for: RDF.Dataset do def description(dataset, subject) do with subject = RDF.Statement.coerce_subject(subject) do - Enum.reduce RDF.Dataset.graphs(dataset), RDF.Description.new(subject), fn + Enum.reduce(RDF.Dataset.graphs(dataset), RDF.Description.new(subject), fn %RDF.Graph{descriptions: %{^subject => graph_description}}, description -> RDF.Description.add(description, graph_description) + _, description -> description - end + end) end end def descriptions(dataset) do dataset |> subjects - |> Enum.map(&(description(dataset, &1))) + |> Enum.map(&description(dataset, &1)) end def statements(dataset), do: RDF.Dataset.statements(dataset) - def subjects(dataset), do: RDF.Dataset.subjects(dataset) + def subjects(dataset), do: RDF.Dataset.subjects(dataset) def predicates(dataset), do: RDF.Dataset.predicates(dataset) - def objects(dataset), do: RDF.Dataset.objects(dataset) - def resources(dataset), do: RDF.Dataset.resources(dataset) + def objects(dataset), do: RDF.Dataset.objects(dataset) + def resources(dataset), do: RDF.Dataset.resources(dataset) - def subject_count(dataset), do: dataset |> subjects |> Enum.count + def subject_count(dataset), do: dataset |> subjects |> Enum.count() def statement_count(dataset), do: RDF.Dataset.statement_count(dataset) - def values(dataset), do: RDF.Dataset.values(dataset) + def values(dataset), do: RDF.Dataset.values(dataset) def values(dataset, mapping), do: RDF.Dataset.values(dataset, mapping) def equal?(dataset, %RDF.Description{} = description) do @@ -354,8 +368,10 @@ defimpl RDF.Data, for: RDF.Dataset do end def equal?(dataset, %RDF.Dataset{} = other_dataset) do - RDF.Dataset.equal?(%RDF.Dataset{dataset | name: nil}, - %RDF.Dataset{other_dataset | name: nil}) + RDF.Dataset.equal?( + %RDF.Dataset{dataset | name: nil}, + %RDF.Dataset{other_dataset | name: nil} + ) end def equal?(_, _), do: false diff --git a/lib/rdf/dataset.ex b/lib/rdf/dataset.ex index d9f3a6b..dd616af 100644 --- a/lib/rdf/dataset.ex +++ b/lib/rdf/dataset.ex @@ -18,20 +18,19 @@ defmodule RDF.Dataset do alias RDF.{Description, Graph, IRI, Statement} import RDF.Statement - @type graph_name :: IRI.t | nil + @type graph_name :: IRI.t() | nil @type t :: %__MODULE__{ name: graph_name, - graphs: %{graph_name => Graph.t} - } + graphs: %{graph_name => Graph.t()} + } - @type input :: Graph.input | t + @type input :: Graph.input() | t - @type update_graph_fun :: (Graph.t -> {Graph.t, input} | :pop) + @type update_graph_fun :: (Graph.t() -> {Graph.t(), input} | :pop) defstruct name: nil, graphs: %{} - @doc """ Creates an empty unnamed `RDF.Dataset`. """ @@ -96,7 +95,6 @@ defmodule RDF.Dataset do |> add(data) end - @doc """ Adds triples and quads to a `RDF.Dataset`. @@ -109,9 +107,9 @@ defmodule RDF.Dataset do def add(dataset, statements, graph_context) when is_list(statements) do with graph_context = graph_context && coerce_graph_name(graph_context) do - Enum.reduce statements, dataset, fn (statement, dataset) -> + Enum.reduce(statements, dataset, fn statement, dataset -> add(dataset, statement, graph_context) - end + end) end end @@ -121,13 +119,20 @@ defmodule RDF.Dataset do def add(dataset, {subject, predicate, objects}, graph_context), do: add(dataset, {subject, predicate, objects, graph_context}) - def add(%__MODULE__{name: name, graphs: graphs}, - {subject, predicate, objects, graph_context}, false) do + def add( + %__MODULE__{name: name, graphs: graphs}, + {subject, predicate, objects, graph_context}, + false + ) do with graph_context = coerce_graph_name(graph_context) do updated_graphs = - Map.update(graphs, graph_context, + Map.update( + graphs, + graph_context, Graph.new({subject, predicate, objects}, name: graph_context), - fn graph -> Graph.add(graph, {subject, predicate, objects}) end) + fn graph -> Graph.add(graph, {subject, predicate, objects}) end + ) + %__MODULE__{name: name, graphs: updated_graphs} end end @@ -138,21 +143,22 @@ defmodule RDF.Dataset do def add(%__MODULE__{} = dataset, %Description{} = description, false), do: add(dataset, description, nil) - def add(%__MODULE__{name: name, graphs: graphs}, - %Description{} = description, graph_context) do + def add(%__MODULE__{name: name, graphs: graphs}, %Description{} = description, graph_context) do with graph_context = coerce_graph_name(graph_context) do updated_graph = Map.get(graphs, graph_context, Graph.new(name: graph_context)) |> Graph.add(description) + %__MODULE__{ - name: name, + name: name, graphs: Map.put(graphs, graph_context, updated_graph) } end end def add(%__MODULE__{name: name, graphs: graphs}, %Graph{} = graph, false) do - %__MODULE__{name: name, + %__MODULE__{ + name: name, graphs: Map.update(graphs, graph.name, graph, fn current -> Graph.add(current, graph) @@ -165,13 +171,12 @@ defmodule RDF.Dataset do def add(%__MODULE__{} = dataset, %__MODULE__{} = other_dataset, graph_context) do with graph_context = graph_context && coerce_graph_name(graph_context) do - Enum.reduce graphs(other_dataset), dataset, fn (graph, dataset) -> + Enum.reduce(graphs(other_dataset), dataset, fn graph, dataset -> add(dataset, graph, graph_context) - end + end) end end - @doc """ Adds statements to a `RDF.Dataset` and overwrites all existing statements with the same subjects and predicates in the specified graph context. @@ -186,7 +191,7 @@ defmodule RDF.Dataset do ...> RDF.Dataset.put([{EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}]) RDF.Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S1, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O3}]) """ - @spec put(t, input | [input], Statement.coercible_graph_name | boolean | nil) :: t + @spec put(t, input | [input], Statement.coercible_graph_name() | boolean | nil) :: t def put(dataset, statements, graph_context \\ false) def put(%__MODULE__{} = dataset, {subject, predicate, objects}, false), @@ -195,18 +200,22 @@ defmodule RDF.Dataset do def put(%__MODULE__{} = dataset, {subject, predicate, objects}, graph_context), do: put(dataset, {subject, predicate, objects, graph_context}) - def put(%__MODULE__{name: name, graphs: graphs}, - {subject, predicate, objects, graph_context}, false) do + def put( + %__MODULE__{name: name, graphs: graphs}, + {subject, predicate, objects, graph_context}, + false + ) do with graph_context = coerce_graph_name(graph_context) do new_graph = case graphs[graph_context] do graph = %Graph{} -> Graph.put(graph, {subject, predicate, objects}) + nil -> Graph.new({subject, predicate, objects}, name: graph_context) end - %__MODULE__{name: name, - graphs: Map.put(graphs, graph_context, new_graph)} + + %__MODULE__{name: name, graphs: Map.put(graphs, graph_context, new_graph)} end end @@ -214,50 +223,61 @@ defmodule RDF.Dataset do do: put(dataset, {subject, predicate, objects, graph_context}, false) def put(%__MODULE__{} = dataset, statements, false) when is_list(statements) do - do_put dataset, Enum.group_by(statements, + do_put( + dataset, + Enum.group_by( + statements, fn - {s, _, _} -> {s, nil} - {s, _, _, nil} -> {s, nil} - {s, _, _, c} -> {s, coerce_graph_name(c)} + {s, _, _} -> {s, nil} + {s, _, _, nil} -> {s, nil} + {s, _, _, c} -> {s, coerce_graph_name(c)} end, fn {_, p, o, _} -> {p, o} - {_, p, o} -> {p, o} - end) + {_, p, o} -> {p, o} + end + ) + ) end def put(%__MODULE__{} = dataset, statements, graph_context) when is_list(statements) do with graph_context = coerce_graph_name(graph_context) do - do_put dataset, Enum.group_by(statements, + do_put( + dataset, + Enum.group_by( + statements, fn {s, _, _, _} -> {s, graph_context} - {s, _, _} -> {s, graph_context} + {s, _, _} -> {s, graph_context} end, fn {_, p, o, _} -> {p, o} - {_, p, o} -> {p, o} - end) + {_, p, o} -> {p, o} + end + ) + ) end end def put(%__MODULE__{} = dataset, %Description{} = description, false), do: put(dataset, description, nil) - def put(%__MODULE__{name: name, graphs: graphs}, - %Description{} = description, graph_context) do + def put(%__MODULE__{name: name, graphs: graphs}, %Description{} = description, graph_context) do with graph_context = coerce_graph_name(graph_context) do updated_graph = Map.get(graphs, graph_context, Graph.new(name: graph_context)) |> Graph.put(description) + %__MODULE__{ - name: name, + name: name, graphs: Map.put(graphs, graph_context, updated_graph) } end end def put(%__MODULE__{name: name, graphs: graphs}, %Graph{} = graph, false) do - %__MODULE__{name: name, + %__MODULE__{ + name: name, graphs: Map.update(graphs, graph.name, graph, fn current -> Graph.put(current, graph) @@ -270,31 +290,31 @@ defmodule RDF.Dataset do def put(%__MODULE__{} = dataset, %__MODULE__{} = other_dataset, graph_context) do with graph_context = graph_context && coerce_graph_name(graph_context) do - Enum.reduce graphs(other_dataset), dataset, fn (graph, dataset) -> + Enum.reduce(graphs(other_dataset), dataset, fn graph, dataset -> put(dataset, graph, graph_context) - end + end) end end defp do_put(%__MODULE__{} = dataset, statements) when is_map(statements) do - Enum.reduce statements, dataset, - fn ({subject_with_context, predications}, dataset) -> - do_put(dataset, subject_with_context, predications) - end + Enum.reduce(statements, dataset, fn {subject_with_context, predications}, dataset -> + do_put(dataset, subject_with_context, predications) + end) end - defp do_put(%__MODULE__{name: name, graphs: graphs}, - {subject, graph_context}, predications) - when is_list(predications) do + defp do_put(%__MODULE__{name: name, graphs: graphs}, {subject, graph_context}, predications) + when is_list(predications) do with graph_context = coerce_graph_name(graph_context) do graph = Map.get(graphs, graph_context, Graph.new(name: graph_context)) - new_graphs = graphs + + new_graphs = + graphs |> Map.put(graph_context, Graph.put(graph, subject, predications)) + %__MODULE__{name: name, graphs: new_graphs} end end - @doc """ Deletes statements from a `RDF.Dataset`. @@ -307,14 +327,14 @@ defmodule RDF.Dataset do are deleted. If you want to delete only datasets with matching names, you can use `RDF.Data.delete/2`. """ - @spec delete(t, input | [input], Statement.coercible_graph_name | boolean | nil) :: t + @spec delete(t, input | [input], Statement.coercible_graph_name() | boolean | nil) :: t def delete(dataset, statements, graph_context \\ false) def delete(%__MODULE__{} = dataset, statements, graph_context) when is_list(statements) do with graph_context = graph_context && coerce_graph_name(graph_context) do - Enum.reduce statements, dataset, fn (statement, dataset) -> + Enum.reduce(statements, dataset, fn statement, dataset -> delete(dataset, statement, graph_context) - end + end) end end @@ -343,18 +363,17 @@ defmodule RDF.Dataset do do: do_delete(dataset, graph_context, graph) def delete(%__MODULE__{} = dataset, %__MODULE__{graphs: graphs}, graph_context) do - Enum.reduce graphs, dataset, fn ({_, graph}, dataset) -> + Enum.reduce(graphs, dataset, fn {_, graph}, dataset -> delete(dataset, graph, graph_context) - end + end) end - defp do_delete(%__MODULE__{name: name, graphs: graphs} = dataset, - graph_context, statements) do + defp do_delete(%__MODULE__{name: name, graphs: graphs} = dataset, graph_context, statements) do with graph_context = coerce_graph_name(graph_context), graph when not is_nil(graph) <- graphs[graph_context], - new_graph = Graph.delete(graph, statements) - do - %__MODULE__{name: name, + new_graph = Graph.delete(graph, statements) do + %__MODULE__{ + name: name, graphs: if Enum.empty?(new_graph) do Map.delete(graphs, graph_context) @@ -367,17 +386,16 @@ defmodule RDF.Dataset do end end - @doc """ Deletes the given graph. """ - @spec delete_graph(t, Statement.graph_name | [Statement.graph_name] | nil) :: t + @spec delete_graph(t, Statement.graph_name() | [Statement.graph_name()] | nil) :: t def delete_graph(graph, graph_names) def delete_graph(%__MODULE__{} = dataset, graph_names) when is_list(graph_names) do - Enum.reduce graph_names, dataset, fn (graph_name, dataset) -> + Enum.reduce(graph_names, dataset, fn graph_name, dataset -> delete_graph(dataset, graph_name) - end + end) end def delete_graph(%__MODULE__{name: name, graphs: graphs}, graph_name) do @@ -393,7 +411,6 @@ defmodule RDF.Dataset do def delete_default_graph(%__MODULE__{} = graph), do: delete_graph(graph, nil) - @doc """ Fetches the `RDF.Graph` with the given name. @@ -410,7 +427,7 @@ defmodule RDF.Dataset do :error """ @impl Access - @spec fetch(t, Statement.graph_name | nil) :: {:ok, Graph.t} | :error + @spec fetch(t, Statement.graph_name() | nil) :: {:ok, Graph.t()} | :error def fetch(%__MODULE__{graphs: graphs}, graph_name) do Access.fetch(graphs, coerce_graph_name(graph_name)) end @@ -433,36 +450,34 @@ defmodule RDF.Dataset do iex> RDF.Dataset.get(dataset, EX.Foo, :bar) :bar """ - @spec get(t, Statement.graph_name | nil, Graph.t | nil) :: Graph.t | nil + @spec get(t, Statement.graph_name() | nil, Graph.t() | nil) :: Graph.t() | nil def get(%__MODULE__{} = dataset, graph_name, default \\ nil) do case fetch(dataset, graph_name) do {:ok, value} -> value - :error -> default + :error -> default end end @doc """ The graph with given name. """ - @spec graph(t, Statement.graph_name | nil) :: Graph.t + @spec graph(t, Statement.graph_name() | nil) :: Graph.t() def graph(%__MODULE__{graphs: graphs}, graph_name), do: Map.get(graphs, coerce_graph_name(graph_name)) @doc """ The default graph of a `RDF.Dataset`. """ - @spec default_graph(t) :: Graph.t + @spec default_graph(t) :: Graph.t() def default_graph(%__MODULE__{graphs: graphs}), - do: Map.get(graphs, nil, Graph.new) - + do: Map.get(graphs, nil, Graph.new()) @doc """ The set of all graphs. """ - @spec graphs(t) :: [Graph.t] + @spec graphs(t) :: [Graph.t()] def graphs(%__MODULE__{graphs: graphs}), do: Map.values(graphs) - @doc """ Gets and updates the graph with the given name, in a single pass. @@ -486,37 +501,43 @@ defmodule RDF.Dataset do {RDF.Graph.new({EX.S, EX.P, EX.O}, name: EX.Graph), RDF.Dataset.new({EX.S, EX.P, EX.NEW, EX.Graph})} """ @impl Access - @spec get_and_update(t, Statement.graph_name | nil, update_graph_fun) :: {Graph.t, input} + @spec get_and_update(t, Statement.graph_name() | nil, update_graph_fun) :: {Graph.t(), input} def get_and_update(%__MODULE__{} = dataset, graph_name, fun) do with graph_context = coerce_graph_name(graph_name) do case fun.(get(dataset, graph_context)) do {old_graph, new_graph} -> {old_graph, put(dataset, new_graph, graph_context)} + :pop -> pop(dataset, graph_context) + other -> - raise "the given function must return a two-element tuple or :pop, got: #{inspect(other)}" + raise "the given function must return a two-element tuple or :pop, got: #{ + inspect(other) + }" end end end - @doc """ Pops an arbitrary statement from a `RDF.Dataset`. """ - @spec pop(t) :: {Statement.t | nil, t} + @spec pop(t) :: {Statement.t() | nil, t} def pop(dataset) def pop(%__MODULE__{graphs: graphs} = dataset) - when graphs == %{}, do: {nil, dataset} + when graphs == %{}, + do: {nil, dataset} def pop(%__MODULE__{name: name, graphs: graphs}) do # TODO: Find a faster way ... [{graph_name, graph}] = Enum.take(graphs, 1) {{s, p, o}, popped_graph} = Graph.pop(graph) - popped = if Enum.empty?(popped_graph), - do: graphs |> Map.delete(graph_name), - else: graphs |> Map.put(graph_name, popped_graph) + + popped = + if Enum.empty?(popped_graph), + do: graphs |> Map.delete(graph_name), + else: graphs |> Map.put(graph_name, popped_graph) {{s, p, o, graph_name}, %__MODULE__{name: name, graphs: popped}} end @@ -538,18 +559,17 @@ defmodule RDF.Dataset do {nil, dataset} """ @impl Access - @spec pop(t, Statement.coercible_graph_name) :: {Statement.t | nil, t} + @spec pop(t, Statement.coercible_graph_name()) :: {Statement.t() | nil, t} def pop(%__MODULE__{name: name, graphs: graphs} = dataset, graph_name) do case Access.pop(graphs, coerce_graph_name(graph_name)) do {nil, _} -> {nil, dataset} + {graph, new_graphs} -> {graph, %__MODULE__{name: name, graphs: new_graphs}} end end - - @doc """ The number of statements within a `RDF.Dataset`. @@ -564,9 +584,9 @@ defmodule RDF.Dataset do """ @spec statement_count(t) :: non_neg_integer def statement_count(%__MODULE__{graphs: graphs}) do - Enum.reduce graphs, 0, fn ({_, graph}, count) -> + Enum.reduce(graphs, 0, fn {_, graph}, count -> count + Graph.triple_count(graph) - end + end) end @doc """ @@ -582,9 +602,9 @@ defmodule RDF.Dataset do MapSet.new([RDF.iri(EX.S1), RDF.iri(EX.S2)]) """ def subjects(%__MODULE__{graphs: graphs}) do - Enum.reduce graphs, MapSet.new, fn ({_, graph}, subjects) -> + Enum.reduce(graphs, MapSet.new(), fn {_, graph}, subjects -> MapSet.union(subjects, Graph.subjects(graph)) - end + end) end @doc """ @@ -600,9 +620,9 @@ defmodule RDF.Dataset do MapSet.new([EX.p1, EX.p2]) """ def predicates(%__MODULE__{graphs: graphs}) do - Enum.reduce graphs, MapSet.new, fn ({_, graph}, predicates) -> + Enum.reduce(graphs, MapSet.new(), fn {_, graph}, predicates -> MapSet.union(predicates, Graph.predicates(graph)) - end + end) end @doc """ @@ -622,9 +642,9 @@ defmodule RDF.Dataset do MapSet.new([RDF.iri(EX.O1), RDF.iri(EX.O2), RDF.bnode(:bnode)]) """ def objects(%__MODULE__{graphs: graphs}) do - Enum.reduce graphs, MapSet.new, fn ({_, graph}, objects) -> + Enum.reduce(graphs, MapSet.new(), fn {_, graph}, objects -> MapSet.union(objects, Graph.objects(graph)) - end + end) end @doc """ @@ -642,9 +662,9 @@ defmodule RDF.Dataset do RDF.iri(EX.O1), RDF.iri(EX.O2), RDF.bnode(:bnode), EX.p1, EX.p2]) """ def resources(%__MODULE__{graphs: graphs}) do - Enum.reduce graphs, MapSet.new, fn ({_, graph}, resources) -> + Enum.reduce(graphs, MapSet.new(), fn {_, graph}, resources -> MapSet.union(resources, Graph.resources(graph)) - end + end) end @doc """ @@ -661,19 +681,19 @@ defmodule RDF.Dataset do {RDF.iri(EX.S1), RDF.iri(EX.p2), RDF.iri(EX.O3)}, {RDF.iri(EX.S2), RDF.iri(EX.p2), RDF.iri(EX.O2)}] """ - @spec statements(t) :: [Statement.t] + @spec statements(t) :: [Statement.t()] def statements(%__MODULE__{graphs: graphs}) do - Enum.reduce graphs, [], fn ({_, graph}, all_statements) -> + Enum.reduce(graphs, [], fn {_, graph}, all_statements -> statements = Graph.triples(graph) + if graph.name do - Enum.map statements, fn {s, p, o} -> {s, p, o, graph.name} end + Enum.map(statements, fn {s, p, o} -> {s, p, o, graph.name} end) else statements end ++ all_statements - end + end) end - @doc """ Returns if a given statement is in a `RDF.Dataset`. @@ -686,7 +706,7 @@ defmodule RDF.Dataset do ...> RDF.Dataset.include?(dataset, {EX.S1, EX.p1, EX.O1, EX.Graph}) true """ - @spec include?(t, Statement.t, Statement.coercible_graph_name | nil) :: boolean + @spec include?(t, Statement.t(), Statement.coercible_graph_name() | nil) :: boolean def include?(dataset, statement, graph_context \\ nil) def include?(%__MODULE__{graphs: graphs}, triple = {_, _, _}, graph_context) do @@ -702,7 +722,6 @@ defmodule RDF.Dataset do def include?(%__MODULE__{} = dataset, {subject, predicate, object, graph_context}, _), do: include?(dataset, {subject, predicate, object}, graph_context) - @doc """ Checks if a graph of a `RDF.Dataset` contains statements about the given resource. @@ -713,7 +732,7 @@ defmodule RDF.Dataset do iex> RDF.Dataset.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Dataset.describes?(EX.S2) false """ - @spec describes?(t, Statement.t, Statement.coercible_graph_name | nil) :: boolean + @spec describes?(t, Statement.t(), Statement.coercible_graph_name() | nil) :: boolean def describes?(%__MODULE__{graphs: graphs}, subject, graph_context \\ nil) do with graph_context = coerce_graph_name(graph_context) do if graph = graphs[graph_context] do @@ -736,17 +755,16 @@ defmodule RDF.Dataset do ...> RDF.Dataset.who_describes(dataset, EX.S1) [nil, RDF.iri(EX.Graph1)] """ - @spec who_describes(t, Statement.coercible_subject) :: [Graph.t] + @spec who_describes(t, Statement.coercible_subject()) :: [Graph.t()] def who_describes(%__MODULE__{graphs: graphs}, subject) do with subject = coerce_subject(subject) do graphs - |> Map.values + |> Map.values() |> Stream.filter(&Graph.describes?(&1, subject)) - |> Enum.map(&(&1.name)) + |> Enum.map(& &1.name) end end - @doc """ Returns a nested map of the native Elixir values of a `RDF.Dataset`. @@ -799,16 +817,15 @@ defmodule RDF.Dataset do } """ - @spec values(t, Statement.term_mapping) :: map + @spec values(t, Statement.term_mapping()) :: map def values(dataset, mapping \\ &RDF.Statement.default_term_mapping/1) def values(%__MODULE__{graphs: graphs}, mapping) do - Map.new graphs, fn {graph_name, graph} -> + Map.new(graphs, fn {graph_name, graph} -> {mapping.({:graph_name, graph_name}), Graph.values(graph, mapping)} - end + end) end - @doc """ Checks if two `RDF.Dataset`s are equal. @@ -825,24 +842,25 @@ defmodule RDF.Dataset do def equal?(_, _), do: false defp clear_metadata(%__MODULE__{graphs: graphs} = dataset) do - %__MODULE__{dataset | - graphs: - Map.new(graphs, fn {name, graph} -> - {name, RDF.Graph.clear_metadata(graph)} - end) + %__MODULE__{ + dataset + | graphs: + Map.new(graphs, fn {name, graph} -> + {name, RDF.Graph.clear_metadata(graph)} + end) } end - defimpl Enumerable do alias RDF.Dataset def member?(dataset, statement), do: {:ok, Dataset.include?(dataset, statement)} - def count(dataset), do: {:ok, Dataset.statement_count(dataset)} - def slice(_dataset), do: {:error, __MODULE__} + def count(dataset), do: {:ok, Dataset.statement_count(dataset)} + def slice(_dataset), do: {:error, __MODULE__} def reduce(%Dataset{graphs: graphs}, {:cont, acc}, _fun) - when map_size(graphs) == 0, do: {:done, acc} + when map_size(graphs) == 0, + do: {:done, acc} def reduce(%Dataset{} = dataset, {:cont, acc}, fun) do {statement, rest} = Dataset.pop(dataset) @@ -850,26 +868,31 @@ defmodule RDF.Dataset do end def reduce(_, {:halt, acc}, _fun), do: {:halted, acc} + def reduce(dataset = %Dataset{}, {:suspend, acc}, fun) do {:suspended, acc, &reduce(dataset, &1, fun)} end end - defimpl Collectable do alias RDF.Dataset def into(original) do collector_fun = fn - dataset, {:cont, list} when is_list(list) - -> Dataset.add(dataset, List.to_tuple(list)) - dataset, {:cont, elem} -> Dataset.add(dataset, elem) - dataset, :done -> dataset - _dataset, :halt -> :ok + dataset, {:cont, list} when is_list(list) -> + Dataset.add(dataset, List.to_tuple(list)) + + dataset, {:cont, elem} -> + Dataset.add(dataset, elem) + + dataset, :done -> + dataset + + _dataset, :halt -> + :ok end {original, collector_fun} end end - end diff --git a/lib/rdf/description.ex b/lib/rdf/description.ex index 0126c6f..ac936de 100644 --- a/lib/rdf/description.ex +++ b/lib/rdf/description.ex @@ -15,51 +15,56 @@ defmodule RDF.Description do import RDF.Statement alias RDF.{Statement, Triple} - @type predications :: %{Statement.predicate => %{Statement.object => nil}} + @type predications :: %{Statement.predicate() => %{Statement.object() => nil}} @type statements :: - {Statement.coercible_predicate, - Statement.coercible_object | [Statement.coercible_predicate]} - | Statement.t + {Statement.coercible_predicate(), + Statement.coercible_object() | [Statement.coercible_predicate()]} + | Statement.t() | predications | t @type t :: %__MODULE__{ - subject: Statement.subject, + subject: Statement.subject(), predications: predications - } + } @enforce_keys [:subject] defstruct subject: nil, predications: %{} - @doc """ Creates a new `RDF.Description` about the given subject with optional initial statements. When given a list of statements, the first one must contain a subject. """ - @spec new(Statement.coercible_subject | statements | [statements]) :: t + @spec new(Statement.coercible_subject() | statements | [statements]) :: t def new(subject) def new({subject, predicate, object}), do: new(subject) |> add(predicate, object) + def new([statement | more_statements]), do: new(statement) |> add(more_statements) + def new(%__MODULE__{} = description), do: description + def new(subject), do: %__MODULE__{subject: coerce_subject(subject)} @doc """ Creates a new `RDF.Description` about the given subject with optional initial statements. """ - @spec new(Statement.coercible_subject, statements | [statements]) :: t + @spec new(Statement.coercible_subject(), statements | [statements]) :: t def new(subject, {predicate, objects}), do: new(subject) |> add(predicate, objects) + def new(subject, statements) when is_list(statements), do: new(subject) |> add(statements) + def new(subject, %__MODULE__{predications: predications}), do: %__MODULE__{new(subject) | predications: predications} + def new(subject, predications = %{}), do: new(subject) |> add(predications) @@ -67,16 +72,16 @@ defmodule RDF.Description do Creates a new `RDF.Description` about the given subject with optional initial statements. """ @spec new( - Statement.coercible_subject | statements | [statements], - Statement.coercible_predicate, - Statement.coercible_object | [Statement.coercible_object] + Statement.coercible_subject() | statements | [statements], + Statement.coercible_predicate(), + Statement.coercible_object() | [Statement.coercible_object()] ) :: t def new(%__MODULE__{} = description, predicate, objects), do: add(description, predicate, objects) + def new(subject, predicate, objects), do: new(subject) |> add(predicate, objects) - @doc """ Add objects to a predicate of a `RDF.Description`. @@ -89,29 +94,28 @@ defmodule RDF.Description do """ @spec add( t, - Statement.coercible_predicate, - Statement.coercible_object | [Statement.coercible_object] + Statement.coercible_predicate(), + Statement.coercible_object() | [Statement.coercible_object()] ) :: t def add(description, predicate, objects) def add(description, predicate, objects) when is_list(objects) do - Enum.reduce objects, description, fn (object, description) -> + Enum.reduce(objects, description, fn object, description -> add(description, predicate, object) - end + end) end def add(%__MODULE__{subject: subject, predications: predications}, predicate, object) do with triple_predicate = coerce_predicate(predicate), triple_object = coerce_object(object), - new_predications = Map.update(predications, - triple_predicate, %{triple_object => nil}, fn objects -> + new_predications = + Map.update(predications, triple_predicate, %{triple_object => nil}, fn objects -> Map.put_new(objects, triple_object, nil) end) do %__MODULE__{subject: subject, predications: new_predications} end end - @doc """ Adds statements to a `RDF.Description`. @@ -128,7 +132,7 @@ defmodule RDF.Description do def add(description = %__MODULE__{}, {subject, predicate, object}) do if coerce_subject(subject) == description.subject, - do: add(description, predicate, object), + do: add(description, predicate, object), else: description end @@ -136,25 +140,29 @@ defmodule RDF.Description do do: add(description, {subject, predicate, object}) def add(description, statements) when is_list(statements) do - Enum.reduce statements, description, fn (statement, description) -> + Enum.reduce(statements, description, fn statement, description -> add(description, statement) - end + end) end - def add(%__MODULE__{subject: subject, predications: predications}, - %__MODULE__{predications: other_predications}) do - merged_predications = Map.merge predications, other_predications, - fn (_, objects, other_objects) -> Map.merge(objects, other_objects) end + def add( + %__MODULE__{subject: subject, predications: predications}, + %__MODULE__{predications: other_predications} + ) do + merged_predications = + Map.merge(predications, other_predications, fn _, objects, other_objects -> + Map.merge(objects, other_objects) + end) + %__MODULE__{subject: subject, predications: merged_predications} end def add(description = %__MODULE__{}, predications = %{}) do - Enum.reduce predications, description, fn ({predicate, objects}, description) -> + Enum.reduce(predications, description, fn {predicate, objects}, description -> add(description, predicate, objects) - end + end) end - @doc """ Puts objects to a predicate of a `RDF.Description`, overwriting all existing objects. @@ -167,18 +175,22 @@ defmodule RDF.Description do """ @spec put( t, - Statement.coercible_predicate, - Statement.coercible_object | [Statement.coercible_object] + Statement.coercible_predicate(), + Statement.coercible_object() | [Statement.coercible_object()] ) :: t def put(description, predicate, objects) - def put(%__MODULE__{subject: subject, predications: predications}, - predicate, objects) when is_list(objects) do + def put(%__MODULE__{subject: subject, predications: predications}, predicate, objects) + when is_list(objects) do with triple_predicate = coerce_predicate(predicate), - triple_objects = Enum.reduce(objects, %{}, fn (object, acc) -> - Map.put_new(acc, coerce_object(object), nil) end), - do: %__MODULE__{subject: subject, - predications: Map.put(predications, triple_predicate, triple_objects)} + triple_objects = + Enum.reduce(objects, %{}, fn object, acc -> + Map.put_new(acc, coerce_object(object), nil) + end), + do: %__MODULE__{ + subject: subject, + predications: Map.put(predications, triple_predicate, triple_objects) + } end def put(%__MODULE__{} = description, predicate, object), @@ -209,7 +221,7 @@ defmodule RDF.Description do def put(%__MODULE__{} = description, {subject, predicate, object}) do if coerce_subject(subject) == description.subject, - do: put(description, predicate, object), + do: put(description, predicate, object), else: description end @@ -219,53 +231,62 @@ defmodule RDF.Description do def put(%__MODULE__{subject: subject} = description, statements) when is_list(statements) do statements |> Stream.map(fn - {p, o} -> {coerce_predicate(p), o} - {^subject, p, o} -> {coerce_predicate(p), o} - {s, p, o} -> - if coerce_subject(s) == subject, - do: {coerce_predicate(p), o} - bad -> raise ArgumentError, "#{inspect bad} is not a valid statement" - end) - |> Stream.filter(&(&1)) # filter nil values - |> Enum.group_by(&(elem(&1, 0)), &(elem(&1, 1))) - |> Enum.reduce(description, fn ({predicate, objects}, description) -> - put(description, predicate, objects) - end) + {p, o} -> + {coerce_predicate(p), o} + + {^subject, p, o} -> + {coerce_predicate(p), o} + + {s, p, o} -> + if coerce_subject(s) == subject, + do: {coerce_predicate(p), o} + + bad -> + raise ArgumentError, "#{inspect(bad)} is not a valid statement" + end) + # filter nil values + |> Stream.filter(& &1) + |> Enum.group_by(&elem(&1, 0), &elem(&1, 1)) + |> Enum.reduce(description, fn {predicate, objects}, description -> + put(description, predicate, objects) + end) end - def put(%__MODULE__{subject: subject, predications: predications}, - %__MODULE__{predications: other_predications}) do - merged_predications = Map.merge predications, other_predications, - fn (_, _, other_objects) -> other_objects end + def put( + %__MODULE__{subject: subject, predications: predications}, + %__MODULE__{predications: other_predications} + ) do + merged_predications = + Map.merge(predications, other_predications, fn _, _, other_objects -> other_objects end) + %__MODULE__{subject: subject, predications: merged_predications} end def put(description = %__MODULE__{}, predications = %{}) do - Enum.reduce predications, description, fn ({predicate, objects}, description) -> + Enum.reduce(predications, description, fn {predicate, objects}, description -> put(description, predicate, objects) - end + end) end - @doc """ Deletes statements from a `RDF.Description`. """ @spec delete( t, - Statement.coercible_predicate, - Statement.coercible_object | [Statement.coercible_object] + Statement.coercible_predicate(), + Statement.coercible_object() | [Statement.coercible_object()] ) :: t def delete(description, predicate, objects) def delete(description, predicate, objects) when is_list(objects) do - Enum.reduce objects, description, fn (object, description) -> + Enum.reduce(objects, description, fn object, description -> delete(description, predicate, object) - end + end) end def delete(%__MODULE__{subject: subject, predications: predications} = descr, predicate, object) do with triple_predicate = coerce_predicate(predicate), - triple_object = coerce_object(object) do + triple_object = coerce_object(object) do if (objects = predications[triple_predicate]) && Map.has_key?(objects, triple_object) do %__MODULE__{ subject: subject, @@ -274,10 +295,10 @@ defmodule RDF.Description do Map.delete(predications, triple_predicate) else Map.update!(predications, triple_predicate, fn objects -> - Map.delete(objects, triple_object) - end) + Map.delete(objects, triple_object) + end) end - } + } else descr end @@ -300,7 +321,7 @@ defmodule RDF.Description do def delete(description = %__MODULE__{}, {subject, predicate, object}) do if coerce_subject(subject) == description.subject, - do: delete(description, predicate, object), + do: delete(description, predicate, object), else: description end @@ -308,34 +329,34 @@ defmodule RDF.Description do do: delete(description, {subject, predicate, object}) def delete(description, statements) when is_list(statements) do - Enum.reduce statements, description, fn (statement, description) -> + Enum.reduce(statements, description, fn statement, description -> delete(description, statement) - end + end) end def delete(description = %__MODULE__{}, other_description = %__MODULE__{}) do - Enum.reduce other_description, description, fn ({_, predicate, object}, description) -> + Enum.reduce(other_description, description, fn {_, predicate, object}, description -> delete(description, predicate, object) - end + end) end def delete(description = %__MODULE__{}, predications = %{}) do - Enum.reduce predications, description, fn ({predicate, objects}, description) -> + Enum.reduce(predications, description, fn {predicate, objects}, description -> delete(description, predicate, objects) - end + end) end - @doc """ Deletes all statements with the given properties. """ - @spec delete_predicates(t, Statement.coercible_predicate | [Statement.coercible_predicate]) :: t + @spec delete_predicates(t, Statement.coercible_predicate() | [Statement.coercible_predicate()]) :: + t def delete_predicates(description, properties) def delete_predicates(%__MODULE__{} = description, properties) when is_list(properties) do - Enum.reduce properties, description, fn (property, description) -> + Enum.reduce(properties, description, fn property, description -> delete_predicates(description, property) - end + end) end def delete_predicates(%__MODULE__{subject: subject, predications: predications}, property) do @@ -344,7 +365,6 @@ defmodule RDF.Description do end end - @doc """ Fetches the objects for the given predicate of a Description. @@ -361,7 +381,7 @@ defmodule RDF.Description do :error """ @impl Access - @spec fetch(t, Statement.coercible_predicate) :: {:ok, [Statement.object]} | :error + @spec fetch(t, Statement.coercible_predicate()) :: {:ok, [Statement.object()]} | :error def fetch(%__MODULE__{predications: predications}, predicate) do with {:ok, objects} <- Access.fetch(predications, coerce_predicate(predicate)) do {:ok, Map.keys(objects)} @@ -382,11 +402,11 @@ defmodule RDF.Description do iex> RDF.Description.get(RDF.Description.new(EX.S), EX.foo, :bar) :bar """ - @spec get(t, Statement.coercible_predicate, any) :: [Statement.object] | any + @spec get(t, Statement.coercible_predicate(), any) :: [Statement.object()] | any def get(description = %__MODULE__{}, predicate, default \\ nil) do case fetch(description, predicate) do {:ok, value} -> value - :error -> default + :error -> default end end @@ -402,11 +422,11 @@ defmodule RDF.Description do iex> RDF.Description.first(RDF.Description.new(EX.S), EX.foo) nil """ - @spec first(t, Statement.coercible_predicate) :: Statement.object | nil + @spec first(t, Statement.coercible_predicate()) :: Statement.object() | nil def first(description = %__MODULE__{}, predicate) do description |> get(predicate, []) - |> List.first + |> List.first() end @doc """ @@ -433,8 +453,8 @@ defmodule RDF.Description do """ @spec update( t, - Statement.coercible_predicate, - Statement.coercible_object | nil, + Statement.coercible_predicate(), + Statement.coercible_object() | nil, ([Statement.Object] -> [Statement.Object]) ) :: t def update(description = %__MODULE__{}, predicate, initial \\ nil, fun) do @@ -453,13 +473,12 @@ defmodule RDF.Description do |> fun.() |> List.wrap() |> case do - [] -> delete_predicates(description, predicate) - objects -> put(description, predicate, objects) - end + [] -> delete_predicates(description, predicate) + objects -> put(description, predicate, objects) + end end end - @doc """ Gets and updates the objects of the given predicate of a Description, in a single pass. @@ -488,7 +507,7 @@ defmodule RDF.Description do @impl Access @spec get_and_update( t, - Statement.coercible_predicate, + Statement.coercible_predicate(), ([Statement.Object] -> {[Statement.Object], t} | :pop) ) :: {[Statement.Object], t} def get_and_update(description = %__MODULE__{}, predicate, fun) do @@ -496,32 +515,34 @@ defmodule RDF.Description do case fun.(get(description, triple_predicate)) do {objects_to_return, new_objects} -> {objects_to_return, put(description, triple_predicate, new_objects)} - :pop -> pop(description, triple_predicate) + + :pop -> + pop(description, triple_predicate) end end end - @doc """ Pops an arbitrary triple from a `RDF.Description`. """ - @spec pop(t) :: {Triple.t | [Statement.Object] | nil, t} + @spec pop(t) :: {Triple.t() | [Statement.Object] | nil, t} def pop(description) def pop(description = %__MODULE__{predications: predications}) - when predications == %{}, do: {nil, description} + when predications == %{}, + do: {nil, description} def pop(%__MODULE__{subject: subject, predications: predications}) do # TODO: Find a faster way ... predicate = List.first(Map.keys(predications)) [{object, _}] = Enum.take(objects = predications[predicate], 1) - popped = if Enum.count(objects) == 1, - do: elem(Map.pop(predications, predicate), 1), - else: elem(pop_in(predications, [predicate, object]), 1) + popped = + if Enum.count(objects) == 1, + do: elem(Map.pop(predications, predicate), 1), + else: elem(pop_in(predications, [predicate, object]), 1) - {{subject, predicate, object}, - %__MODULE__{subject: subject, predications: popped}} + {{subject, predicate, object}, %__MODULE__{subject: subject, predications: popped}} end @doc """ @@ -541,12 +562,12 @@ defmodule RDF.Description do case Access.pop(predications, coerce_predicate(predicate)) do {nil, _} -> {nil, description} + {objects, new_predications} -> {Map.keys(objects), %__MODULE__{subject: subject, predications: new_predications}} end end - @doc """ The set of all properties used in the predicates within a `RDF.Description`. @@ -559,9 +580,9 @@ defmodule RDF.Description do ...> RDF.Description.predicates MapSet.new([EX.p1, EX.p2]) """ - @spec predicates(t) :: MapSet.t + @spec predicates(t) :: MapSet.t() def predicates(%__MODULE__{predications: predications}), - do: predications |> Map.keys |> MapSet.new + do: predications |> Map.keys() |> MapSet.new() @doc """ The set of all resources used in the objects within a `RDF.Description`. @@ -579,22 +600,22 @@ defmodule RDF.Description do ...> ]) |> RDF.Description.objects MapSet.new([RDF.iri(EX.O1), RDF.iri(EX.O2), RDF.bnode(:bnode)]) """ - @spec objects(t) :: MapSet.t + @spec objects(t) :: MapSet.t() def objects(%__MODULE__{} = description), do: objects(description, &RDF.resource?/1) @doc """ The set of all resources used in the objects within a `RDF.Description` satisfying the given filter criterion. """ - @spec objects(t, (Statement.object -> boolean)) :: MapSet.t + @spec objects(t, (Statement.object() -> boolean)) :: MapSet.t() def objects(%__MODULE__{predications: predications}, filter_fn) do - Enum.reduce predications, MapSet.new, fn ({_, objects}, acc) -> + Enum.reduce(predications, MapSet.new(), fn {_, objects}, acc -> objects - |> Map.keys + |> Map.keys() |> Enum.filter(filter_fn) - |> MapSet.new + |> MapSet.new() |> MapSet.union(acc) - end + end) end @doc """ @@ -611,7 +632,7 @@ defmodule RDF.Description do ...> ]) |> RDF.Description.resources MapSet.new([RDF.iri(EX.O1), RDF.iri(EX.O2), RDF.bnode(:bnode), EX.p1, EX.p2, EX.p3]) """ - @spec resources(t) :: MapSet.t + @spec resources(t) :: MapSet.t() def resources(description) do description |> objects @@ -626,42 +647,42 @@ defmodule RDF.Description do defdelegate statements(description), to: __MODULE__, as: :triples - @doc """ Returns the number of statements of a `RDF.Description`. """ @spec count(t) :: non_neg_integer def count(%__MODULE__{predications: predications}) do - Enum.reduce predications, 0, - fn ({_, objects}, count) -> count + Enum.count(objects) end + Enum.reduce(predications, 0, fn {_, objects}, count -> count + Enum.count(objects) end) end - @doc """ Checks if the given statement exists within a `RDF.Description`. """ @spec include?(t, statements) :: boolean def include?(description, statement) - def include?(%__MODULE__{predications: predications}, - {predicate, object}) do + def include?( + %__MODULE__{predications: predications}, + {predicate, object} + ) do with triple_predicate = coerce_predicate(predicate), - triple_object = coerce_object(object) do + triple_object = coerce_object(object) do predications |> Map.get(triple_predicate, %{}) |> Map.has_key?(triple_object) end end - def include?(desc = %__MODULE__{subject: desc_subject}, - {subject, predicate, object}) do + def include?( + desc = %__MODULE__{subject: desc_subject}, + {subject, predicate, object} + ) do coerce_subject(subject) == desc_subject && include?(desc, {predicate, object}) end def include?(%__MODULE__{}, _), do: false - @doc """ Checks if a `RDF.Description` has the given resource as subject. @@ -672,7 +693,7 @@ defmodule RDF.Description do iex> RDF.Description.new(EX.S1, EX.p1, EX.O1) |> RDF.Description.describes?(EX.S2) false """ - @spec describes?(t, Statement.subject) :: boolean + @spec describes?(t, Statement.subject()) :: boolean def describes?(%__MODULE__{subject: subject}, other_subject) do with other_subject = coerce_subject(other_subject) do subject == other_subject @@ -712,16 +733,16 @@ defmodule RDF.Description do %{p: ["Foo"]} """ - @spec values(t, Statement.term_mapping) :: map + @spec values(t, Statement.term_mapping()) :: map def values(description, mapping \\ &RDF.Statement.default_term_mapping/1) def values(%__MODULE__{predications: predications}, mapping) do - Map.new predications, fn {predicate, objects} -> + Map.new(predications, fn {predicate, objects} -> { mapping.({:predicate, predicate}), - objects |> Map.keys() |> Enum.map(&(mapping.({:object, &1}))) + objects |> Map.keys() |> Enum.map(&mapping.({:object, &1})) } - end + end) end @doc """ @@ -731,13 +752,13 @@ defmodule RDF.Description do If `nil` is passed, the description is left untouched. """ - @spec take(t, [Statement.coercible_predicate] | Enum.t | nil) :: t + @spec take(t, [Statement.coercible_predicate()] | Enum.t() | nil) :: t def take(description, predicates) def take(%__MODULE__{} = description, nil), do: description def take(%__MODULE__{predications: predications} = description, predicates) do - predicates = Enum.map(predicates, &(coerce_predicate/1)) + predicates = Enum.map(predicates, &coerce_predicate/1) %__MODULE__{description | predications: Map.take(predications, predicates)} end @@ -755,43 +776,48 @@ defmodule RDF.Description do def equal?(_, _), do: false - defimpl Enumerable do alias RDF.Description def member?(desc, triple), do: {:ok, Description.include?(desc, triple)} - def count(desc), do: {:ok, Description.count(desc)} - def slice(_desc), do: {:error, __MODULE__} + def count(desc), do: {:ok, Description.count(desc)} + def slice(_desc), do: {:error, __MODULE__} def reduce(%Description{predications: predications}, {:cont, acc}, _fun) - when map_size(predications) == 0, do: {:done, acc} + when map_size(predications) == 0, + do: {:done, acc} def reduce(description = %Description{}, {:cont, acc}, fun) do {triple, rest} = Description.pop(description) reduce(rest, fun.(triple, acc), fun) end - def reduce(_, {:halt, acc}, _fun), do: {:halted, acc} + def reduce(_, {:halt, acc}, _fun), do: {:halted, acc} + def reduce(description = %Description{}, {:suspend, acc}, fun) do {:suspended, acc, &reduce(description, &1, fun)} end end - defimpl Collectable do alias RDF.Description def into(original) do collector_fun = fn - description, {:cont, list} when is_list(list) - -> Description.add(description, List.to_tuple(list)) - description, {:cont, elem} -> Description.add(description, elem) - description, :done -> description - _description, :halt -> :ok + description, {:cont, list} when is_list(list) -> + Description.add(description, List.to_tuple(list)) + + description, {:cont, elem} -> + Description.add(description, elem) + + description, :done -> + description + + _description, :halt -> + :ok end {original, collector_fun} end end - end diff --git a/lib/rdf/diff.ex b/lib/rdf/diff.ex index bc808fe..670eedc 100644 --- a/lib/rdf/diff.ex +++ b/lib/rdf/diff.ex @@ -9,13 +9,12 @@ defmodule RDF.Diff do alias RDF.{Description, Graph} @type t :: %__MODULE__{ - additions: Graph.t, - deletions: Graph.t - } + additions: Graph.t(), + deletions: Graph.t() + } defstruct [:additions, :deletions] - @doc """ Creates a `RDF.Diff` struct. @@ -32,8 +31,10 @@ defmodule RDF.Diff do end defp coerce_graph(nil), do: Graph.new() + defp coerce_graph(%Description{} = description), - do: if Enum.empty?(description), do: Graph.new(), else: Graph.new(description) + do: if(Enum.empty?(description), do: Graph.new(), else: Graph.new(description)) + defp coerce_graph(data), do: Graph.new(data) @doc """ @@ -59,43 +60,49 @@ defmodule RDF.Diff do deletions: RDF.graph({EX.S1, EX.p1, EX.O1}) } """ - @spec diff(Description.t | Graph.t, Description.t | Graph.t) :: t + @spec diff(Description.t() | Graph.t(), Description.t() | Graph.t()) :: t def diff(original_rdf_data, new_rdf_data) def diff(%Description{} = description, description), do: new() - def diff(%Description{subject: subject} = original_description, - %Description{subject: subject} = new_description) do + def diff( + %Description{subject: subject} = original_description, + %Description{subject: subject} = new_description + ) do {additions, deletions} = original_description |> Description.predicates() - |> Enum.reduce({new_description, Description.new(subject)}, - fn property, {additions, deletions} -> - original_objects = Description.get(original_description, property) - case Description.get(new_description, property) do - nil -> - { - additions, - Description.add(deletions, property, original_objects) - } + |> Enum.reduce( + {new_description, Description.new(subject)}, + fn property, {additions, deletions} -> + original_objects = Description.get(original_description, property) - new_objects -> - {unchanged_objects, deleted_objects} = - Enum.reduce(original_objects, {[], []}, fn - original_object, {unchanged_objects, deleted_objects} -> - if original_object in new_objects do - {[original_object | unchanged_objects], deleted_objects} - else - {unchanged_objects, [original_object | deleted_objects]} - end - end) + case Description.get(new_description, property) do + nil -> + { + additions, + Description.add(deletions, property, original_objects) + } + + new_objects -> + {unchanged_objects, deleted_objects} = + Enum.reduce(original_objects, {[], []}, fn + original_object, {unchanged_objects, deleted_objects} -> + if original_object in new_objects do + {[original_object | unchanged_objects], deleted_objects} + else + {unchanged_objects, [original_object | deleted_objects]} + end + end) + + { + Description.delete(additions, property, unchanged_objects), + Description.add(deletions, property, deleted_objects) + } + end + end + ) - { - Description.delete(additions, property, unchanged_objects), - Description.add(deletions, property, deleted_objects), - } - end - end) new(additions: additions, deletions: deletions) end @@ -111,16 +118,20 @@ defmodule RDF.Diff do graph1_subjects |> MapSet.intersection(graph2_subjects) |> Enum.reduce( - new( - additions: Graph.take(graph2, added_subjects), - deletions: Graph.take(graph1, deleted_subjects) - ), - fn subject, diff -> - merge(diff, diff( - Graph.description(graph1, subject), - Graph.description(graph2, subject) - )) - end) + new( + additions: Graph.take(graph2, added_subjects), + deletions: Graph.take(graph1, deleted_subjects) + ), + fn subject, diff -> + merge( + diff, + diff( + Graph.description(graph1, subject), + Graph.description(graph2, subject) + ) + ) + end + ) end def diff(%Description{} = description, %Graph{} = graph) do @@ -139,10 +150,7 @@ defmodule RDF.Diff do def diff(%Graph{} = graph, %Description{} = description) do diff = diff(description, graph) - %__MODULE__{ diff | - additions: diff.deletions, - deletions: diff.additions - } + %__MODULE__{diff | additions: diff.deletions, deletions: diff.additions} end @doc """ @@ -178,7 +186,7 @@ defmodule RDF.Diff do The result of an application is always a `RDF.Graph`, even if a `RDF.Description` is given and the additions from the diff are all about the subject of this description. """ - @spec apply(t, Description.t | Graph.t) :: Graph.t + @spec apply(t, Description.t() | Graph.t()) :: Graph.t() def apply(diff, rdf_data) def apply(%__MODULE__{} = diff, %Graph{} = graph) do diff --git a/lib/rdf/exceptions.ex b/lib/rdf/exceptions.ex index 1f756d7..73b33cc 100644 --- a/lib/rdf/exceptions.ex +++ b/lib/rdf/exceptions.ex @@ -38,7 +38,6 @@ defmodule RDF.Quad.InvalidGraphContextError do end end - defmodule RDF.Namespace.InvalidVocabBaseIRIError do defexception [:message] end @@ -55,7 +54,6 @@ defmodule RDF.Namespace.UndefinedTermError do defexception [:message] end - defmodule RDF.Query.InvalidError do defexception [:message] end diff --git a/lib/rdf/graph.ex b/lib/rdf/graph.ex index 07d4ce3..c9039fc 100644 --- a/lib/rdf/graph.ex +++ b/lib/rdf/graph.ex @@ -16,24 +16,23 @@ defmodule RDF.Graph do import RDF.Statement alias RDF.{Description, IRI, PrefixMap, Statement} - @type graph_description :: %{Statement.subject => Description.t} + @type graph_description :: %{Statement.subject() => Description.t()} @type t :: %__MODULE__{ - name: IRI.t | nil, + name: IRI.t() | nil, descriptions: graph_description, - prefixes: PrefixMap.t | nil, - base_iri: IRI.t | nil - } + prefixes: PrefixMap.t() | nil, + base_iri: IRI.t() | nil + } - @type input :: Statement.t | Description.t | t + @type input :: Statement.t() | Description.t() | t - @type update_description_fun :: (Description.t -> Description.t) + @type update_description_fun :: (Description.t() -> Description.t()) - @type get_and_update_description_fun :: (Description.t -> {Description.t, input} | :pop) + @type get_and_update_description_fun :: (Description.t() -> {Description.t(), input} | :pop) defstruct name: nil, descriptions: %{}, prefixes: nil, base_iri: nil - @doc """ Creates an empty unnamed `RDF.Graph`. """ @@ -119,15 +118,14 @@ defmodule RDF.Graph do See `new/2` for available arguments. """ @spec new( - Statement.coercible_subject, - Statement.coercible_predicate, - Statement.coercible_object | [Statement.coercible_object], + Statement.coercible_subject(), + Statement.coercible_predicate(), + Statement.coercible_object() | [Statement.coercible_object()], keyword ) :: t def new(subject, predicate, objects, options \\ []), do: new([], options) |> add(subject, predicate, objects) - @doc """ Removes all triples from `graph`. @@ -140,15 +138,14 @@ defmodule RDF.Graph do %__MODULE__{graph | descriptions: %{}} end - @doc """ Adds triples to a `RDF.Graph`. """ @spec add( t, - Statement.coercible_subject, - Statement.coercible_predicate, - Statement.coercible_object | [Statement.coercible_object] + Statement.coercible_subject(), + Statement.coercible_predicate(), + Statement.coercible_object() | [Statement.coercible_object()] ) :: t def add(%__MODULE__{} = graph, subject, predicate, objects), do: add(graph, {subject, predicate, objects}) @@ -175,9 +172,9 @@ defmodule RDF.Graph do do: add(graph, {subject, predicate, object}) def add(graph, triples) when is_list(triples) do - Enum.reduce triples, graph, fn (triple, graph) -> + Enum.reduce(triples, graph, fn triple, graph -> add(graph, triple) - end + end) end def add(%__MODULE__{} = graph, %Description{subject: subject} = description), @@ -185,9 +182,9 @@ defmodule RDF.Graph do def add(graph, %__MODULE__{descriptions: descriptions, prefixes: prefixes}) do graph = - Enum.reduce descriptions, graph, fn ({_, description}, graph) -> + Enum.reduce(descriptions, graph, fn {_, description}, graph -> add(graph, description) - end + end) if prefixes do add_prefixes(graph, prefixes, fn _, ns, _ -> ns end) @@ -197,16 +194,15 @@ defmodule RDF.Graph do end defp do_add(%__MODULE__{descriptions: descriptions} = graph, subject, statements) do - %__MODULE__{graph | - descriptions: - Map.update(descriptions, subject, Description.new(statements), - fn description -> + %__MODULE__{ + graph + | descriptions: + Map.update(descriptions, subject, Description.new(statements), fn description -> Description.add(description, statements) end) } end - @doc """ Adds statements to a `RDF.Graph` and overwrites all existing statements with the same subjects and predicates. @@ -235,9 +231,9 @@ defmodule RDF.Graph do def put(graph, %__MODULE__{descriptions: descriptions, prefixes: prefixes}) do graph = - Enum.reduce descriptions, graph, fn ({_, description}, graph) -> + Enum.reduce(descriptions, graph, fn {_, description}, graph -> put(graph, description) - end + end) if prefixes do add_prefixes(graph, prefixes, fn _, ns, _ -> ns end) @@ -247,31 +243,40 @@ defmodule RDF.Graph do end def put(%__MODULE__{} = graph, statements) when is_map(statements) do - Enum.reduce statements, graph, fn ({subject, predications}, graph) -> + Enum.reduce(statements, graph, fn {subject, predications}, graph -> put(graph, subject, predications) - end + end) end def put(%__MODULE__{} = graph, statements) when is_list(statements) do - put(graph, Enum.group_by(statements, &(elem(&1, 0)), fn {_, p, o} -> {p, o} end)) + put(graph, Enum.group_by(statements, &elem(&1, 0), fn {_, p, o} -> {p, o} end)) end @doc """ Add statements to a `RDF.Graph`, overwriting all statements with the same subject and predicate. """ - @spec put(t, Statement.coercible_subject, Description.statements | [Description.statements]) :: t + @spec put( + t, + Statement.coercible_subject(), + Description.statements() | [Description.statements()] + ) :: t def put(graph, subject, predications) def put(%__MODULE__{descriptions: descriptions} = graph, subject, predications) - when is_list(predications) do + when is_list(predications) do with subject = coerce_subject(subject) do # TODO: Can we reduce this case also to do_put somehow? Only the initializer of Map.update differs ... - %__MODULE__{graph | - descriptions: - Map.update(descriptions, subject, Description.new(subject, predications), - fn current -> - Description.put(current, predications) - end) + %__MODULE__{ + graph + | descriptions: + Map.update( + descriptions, + subject, + Description.new(subject, predications), + fn current -> + Description.put(current, predications) + end + ) } end end @@ -280,10 +285,10 @@ defmodule RDF.Graph do do: put(graph, subject, [predications]) defp do_put(%__MODULE__{descriptions: descriptions} = graph, subject, statements) do - %__MODULE__{graph | - descriptions: - Map.update(descriptions, subject, Description.new(statements), - fn current -> + %__MODULE__{ + graph + | descriptions: + Map.update(descriptions, subject, Description.new(statements), fn current -> Description.put(current, statements) end) } @@ -302,22 +307,21 @@ defmodule RDF.Graph do """ @spec put( t, - Statement.coercible_subject, - Statement.coercible_predicate, - Statement.coercible_object | [Statement.coercible_object] + Statement.coercible_subject(), + Statement.coercible_predicate(), + Statement.coercible_object() | [Statement.coercible_object()] ) :: t def put(%__MODULE__{} = graph, subject, predicate, objects), do: put(graph, {subject, predicate, objects}) - @doc """ Deletes statements from a `RDF.Graph`. """ @spec delete( t, - Statement.coercible_subject, - Statement.coercible_predicate, - Statement.coercible_object | [Statement.coercible_object] + Statement.coercible_subject(), + Statement.coercible_predicate(), + Statement.coercible_object() | [Statement.coercible_object()] ) :: t def delete(graph, subject, predicate, object), do: delete(graph, {subject, predicate, object}) @@ -341,52 +345,50 @@ defmodule RDF.Graph do do: delete(graph, {subject, predicate, object}) def delete(%__MODULE__{} = graph, triples) when is_list(triples) do - Enum.reduce triples, graph, fn (triple, graph) -> + Enum.reduce(triples, graph, fn triple, graph -> delete(graph, triple) - end + end) end def delete(%__MODULE__{} = graph, %Description{subject: subject} = description), do: do_delete(graph, subject, description) def delete(%__MODULE__{} = graph, %__MODULE__{descriptions: descriptions}) do - Enum.reduce descriptions, graph, fn ({_, description}, graph) -> + Enum.reduce(descriptions, graph, fn {_, description}, graph -> delete(graph, description) - end + end) end - defp do_delete(%__MODULE__{descriptions: descriptions} = graph, - subject, statements) do + defp do_delete(%__MODULE__{descriptions: descriptions} = graph, subject, statements) do with description when not is_nil(description) <- descriptions[subject], - new_description = Description.delete(description, statements) - do - %__MODULE__{graph | - descriptions: - if Enum.empty?(new_description) do - Map.delete(descriptions, subject) - else - Map.put(descriptions, subject, new_description) - end + new_description = Description.delete(description, statements) do + %__MODULE__{ + graph + | descriptions: + if Enum.empty?(new_description) do + Map.delete(descriptions, subject) + else + Map.put(descriptions, subject, new_description) + end } else nil -> graph end end - @doc """ Deletes all statements with the given subjects. """ @spec delete_subjects( - t, - Statement.coercible_subject | [Statement.coercible_subject] - ) :: t + t, + Statement.coercible_subject() | [Statement.coercible_subject()] + ) :: t def delete_subjects(graph, subjects) def delete_subjects(%__MODULE__{} = graph, subjects) when is_list(subjects) do - Enum.reduce subjects, graph, fn (subject, graph) -> + Enum.reduce(subjects, graph, fn subject, graph -> delete_subjects(graph, subject) - end + end) end def delete_subjects(%__MODULE__{descriptions: descriptions} = graph, subject) do @@ -395,7 +397,6 @@ defmodule RDF.Graph do end end - @doc """ Updates the description of the `subject` in `graph` with the given function. @@ -428,8 +429,8 @@ defmodule RDF.Graph do """ @spec update( t, - Statement.coercible_subject, - Description.statements | [Description.statements] | nil, + Statement.coercible_subject(), + Description.statements() | [Description.statements()] | nil, update_description_fun ) :: t def update(graph = %__MODULE__{}, subject, initial \\ nil, fun) do @@ -447,18 +448,17 @@ defmodule RDF.Graph do description |> fun.() |> case do - nil -> - delete_subjects(graph, subject) + nil -> + delete_subjects(graph, subject) - new_description -> - graph - |> delete_subjects(subject) - |> add(Description.new(subject, new_description)) - end + new_description -> + graph + |> delete_subjects(subject) + |> add(Description.new(subject, new_description)) + end end end - @doc """ Fetches the description of the given subject. @@ -474,7 +474,7 @@ defmodule RDF.Graph do """ @impl Access - @spec fetch(t, Statement.coercible_subject) :: {:ok, Description.t} | :error + @spec fetch(t, Statement.coercible_subject()) :: {:ok, Description.t()} | :error def fetch(%__MODULE__{descriptions: descriptions}, subject) do Access.fetch(descriptions, coerce_subject(subject)) end @@ -519,29 +519,28 @@ defmodule RDF.Graph do :bar """ - @spec get(t, Statement.coercible_subject, Description.t | nil) :: Description.t | nil + @spec get(t, Statement.coercible_subject(), Description.t() | nil) :: Description.t() | nil def get(%__MODULE__{} = graph, subject, default \\ nil) do case fetch(graph, subject) do {:ok, value} -> value - :error -> default + :error -> default end end @doc """ The `RDF.Description` of the given subject. """ - @spec description(t, Statement.coercible_subject) :: Description.t | nil + @spec description(t, Statement.coercible_subject()) :: Description.t() | nil def description(%__MODULE__{descriptions: descriptions}, subject), do: Map.get(descriptions, coerce_subject(subject)) @doc """ All `RDF.Description`s within a `RDF.Graph`. """ - @spec descriptions(t) :: [Description.t] + @spec descriptions(t) :: [Description.t()] def descriptions(%__MODULE__{descriptions: descriptions}), do: Map.values(descriptions) - @doc """ Gets and updates the description of the given subject, in a single pass. @@ -566,38 +565,44 @@ defmodule RDF.Graph do """ @impl Access - @spec get_and_update(t, Statement.coercible_subject, get_and_update_description_fun) :: - {Description.t, input} + @spec get_and_update(t, Statement.coercible_subject(), get_and_update_description_fun) :: + {Description.t(), input} def get_and_update(%__MODULE__{} = graph, subject, fun) do with subject = coerce_subject(subject) do case fun.(get(graph, subject)) do {old_description, new_description} -> {old_description, put(graph, subject, new_description)} + :pop -> pop(graph, subject) + other -> - raise "the given function must return a two-element tuple or :pop, got: #{inspect(other)}" + raise "the given function must return a two-element tuple or :pop, got: #{ + inspect(other) + }" end end end - @doc """ Pops an arbitrary triple from a `RDF.Graph`. """ - @spec pop(t) :: {Statement.t | nil, t} + @spec pop(t) :: {Statement.t() | nil, t} def pop(graph) def pop(%__MODULE__{descriptions: descriptions} = graph) - when descriptions == %{}, do: {nil, graph} + when descriptions == %{}, + do: {nil, graph} def pop(%__MODULE__{descriptions: descriptions} = graph) do # TODO: Find a faster way ... [{subject, description}] = Enum.take(descriptions, 1) {triple, popped_description} = Description.pop(description) - popped = if Enum.empty?(popped_description), - do: descriptions |> Map.delete(subject), - else: descriptions |> Map.put(subject, popped_description) + + popped = + if Enum.empty?(popped_description), + do: descriptions |> Map.delete(subject), + else: descriptions |> Map.put(subject, popped_description) {triple, %__MODULE__{graph | descriptions: popped}} end @@ -617,17 +622,17 @@ defmodule RDF.Graph do """ @impl Access - @spec pop(t, Statement.coercible_subject) :: {Description.t | nil, t} + @spec pop(t, Statement.coercible_subject()) :: {Description.t() | nil, t} def pop(%__MODULE__{descriptions: descriptions} = graph, subject) do case Access.pop(descriptions, coerce_subject(subject)) do {nil, _} -> {nil, graph} + {description, new_descriptions} -> {description, %__MODULE__{graph | descriptions: new_descriptions}} end end - @doc """ The number of subjects within a `RDF.Graph`. @@ -660,9 +665,9 @@ defmodule RDF.Graph do """ @spec triple_count(t) :: non_neg_integer def triple_count(%__MODULE__{descriptions: descriptions}) do - Enum.reduce descriptions, 0, fn ({_subject, description}, count) -> + Enum.reduce(descriptions, 0, fn {_subject, description}, count -> count + Description.count(description) - end + end) end @doc """ @@ -678,7 +683,7 @@ defmodule RDF.Graph do MapSet.new([RDF.iri(EX.S1), RDF.iri(EX.S2)]) """ def subjects(%__MODULE__{descriptions: descriptions}), - do: descriptions |> Map.keys |> MapSet.new + do: descriptions |> Map.keys() |> MapSet.new() @doc """ The set of all properties used in the predicates of the statements within a `RDF.Graph`. @@ -693,11 +698,11 @@ defmodule RDF.Graph do MapSet.new([EX.p1, EX.p2]) """ def predicates(%__MODULE__{descriptions: descriptions}) do - Enum.reduce descriptions, MapSet.new, fn ({_, description}, acc) -> + Enum.reduce(descriptions, MapSet.new(), fn {_, description}, acc -> description - |> Description.predicates + |> Description.predicates() |> MapSet.union(acc) - end + end) end @doc """ @@ -717,11 +722,11 @@ defmodule RDF.Graph do MapSet.new([RDF.iri(EX.O1), RDF.iri(EX.O2), RDF.bnode(:bnode)]) """ def objects(%__MODULE__{descriptions: descriptions}) do - Enum.reduce descriptions, MapSet.new, fn ({_, description}, acc) -> + Enum.reduce(descriptions, MapSet.new(), fn {_, description}, acc -> description - |> Description.objects + |> Description.objects() |> MapSet.union(acc) - end + end) end @doc """ @@ -739,11 +744,12 @@ defmodule RDF.Graph do RDF.iri(EX.O1), RDF.iri(EX.O2), RDF.bnode(:bnode), EX.p1, EX.p2]) """ def resources(graph = %__MODULE__{descriptions: descriptions}) do - Enum.reduce(descriptions, MapSet.new, fn ({_, description}, acc) -> + Enum.reduce(descriptions, MapSet.new(), fn {_, description}, acc -> description - |> Description.resources + |> Description.resources() |> MapSet.union(acc) - end) |> MapSet.union(subjects(graph)) + end) + |> MapSet.union(subjects(graph)) end @doc """ @@ -760,18 +766,19 @@ defmodule RDF.Graph do {RDF.iri(EX.S1), RDF.iri(EX.p2), RDF.iri(EX.O3)}, {RDF.iri(EX.S2), RDF.iri(EX.p2), RDF.iri(EX.O2)}] """ - @spec triples(t) :: [Statement.t] + @spec triples(t) :: [Statement.t()] def triples(%__MODULE__{} = graph), do: Enum.to_list(graph) defdelegate statements(graph), to: RDF.Graph, as: :triples - @doc """ Checks if the given statement exists within a `RDF.Graph`. """ - @spec include?(t, Statement.t) :: boolean - def include?(%__MODULE__{descriptions: descriptions}, - triple = {subject, _, _}) do + @spec include?(t, Statement.t()) :: boolean + def include?( + %__MODULE__{descriptions: descriptions}, + triple = {subject, _, _} + ) do with subject = coerce_subject(subject), %Description{} <- description = descriptions[subject] do Description.include?(description, triple) @@ -790,14 +797,13 @@ defmodule RDF.Graph do iex> RDF.Graph.new([{EX.S1, EX.p1, EX.O1}]) |> RDF.Graph.describes?(EX.S2) false """ - @spec describes?(t, Statement.coercible_subject) :: boolean + @spec describes?(t, Statement.coercible_subject()) :: boolean def describes?(%__MODULE__{descriptions: descriptions}, subject) do with subject = coerce_subject(subject) do Map.has_key?(descriptions, subject) end end - @doc """ Returns a nested map of the native Elixir values of a `RDF.Graph`. @@ -840,13 +846,13 @@ defmodule RDF.Graph do } """ - @spec values(t, Statement.term_mapping) :: map + @spec values(t, Statement.term_mapping()) :: map def values(graph, mapping \\ &RDF.Statement.default_term_mapping/1) def values(%__MODULE__{descriptions: descriptions}, mapping) do - Map.new descriptions, fn {subject, description} -> + Map.new(descriptions, fn {subject, description} -> {mapping.({:subject, subject}), Description.values(description, mapping)} - end + end) end @doc """ @@ -858,26 +864,32 @@ defmodule RDF.Graph do If `nil` is passed as the `subjects`, the subjects will not be limited. """ - @spec take(t, [Statement.coercible_subject] | Enum.t | nil, [Statement.coercible_predicate] | Enum.t | nil) :: t + @spec take( + t, + [Statement.coercible_subject()] | Enum.t() | nil, + [Statement.coercible_predicate()] | Enum.t() | nil + ) :: t def take(graph, subjects, properties \\ nil) def take(%__MODULE__{} = graph, nil, nil), do: graph def take(%__MODULE__{descriptions: descriptions} = graph, subjects, nil) do - subjects = Enum.map(subjects, &(coerce_subject/1)) + subjects = Enum.map(subjects, &coerce_subject/1) %__MODULE__{graph | descriptions: Map.take(descriptions, subjects)} end def take(%__MODULE__{} = graph, subjects, properties) do graph = take(graph, subjects, nil) - %__MODULE__{graph | - descriptions: Map.new(graph.descriptions, fn {subject, description} -> - {subject, Description.take(description, properties)} - end) + + %__MODULE__{ + graph + | descriptions: + Map.new(graph.descriptions, fn {subject, description} -> + {subject, Description.take(description, properties)} + end) } end - @doc """ Checks if two `RDF.Graph`s are equal. @@ -893,7 +905,6 @@ defmodule RDF.Graph do def equal?(_, _), do: false - @doc """ Adds `prefixes` to the given `graph`. @@ -906,8 +917,8 @@ defmodule RDF.Graph do """ @spec add_prefixes( t, - PrefixMap.t | map | keyword | nil, - PrefixMap.conflict_resolver | nil + PrefixMap.t() | map | keyword | nil, + PrefixMap.conflict_resolver() | nil ) :: t def add_prefixes(graph, prefixes, conflict_resolver \\ nil) @@ -922,9 +933,7 @@ defmodule RDF.Graph do end def add_prefixes(%__MODULE__{prefixes: prefixes} = graph, additions, conflict_resolver) do - %__MODULE__{graph | - prefixes: RDF.PrefixMap.merge!(prefixes, additions, conflict_resolver) - } + %__MODULE__{graph | prefixes: RDF.PrefixMap.merge!(prefixes, additions, conflict_resolver)} end @doc """ @@ -933,7 +942,7 @@ defmodule RDF.Graph do The `prefixes` can be a single prefix or a list of prefixes. Prefixes not in prefixes of the graph are simply ignored. """ - @spec delete_prefixes(t, PrefixMap.t) :: t + @spec delete_prefixes(t, PrefixMap.t()) :: t def delete_prefixes(graph, prefixes) def delete_prefixes(%__MODULE__{prefixes: nil} = graph, _), do: graph @@ -955,7 +964,7 @@ defmodule RDF.Graph do The `base_iri` can be given as anything accepted by `RDF.IRI.coerce_base/1`. """ - @spec set_base_iri(t, IRI.t | nil) :: t + @spec set_base_iri(t, IRI.t() | nil) :: t def set_base_iri(graph, base_iri) def set_base_iri(%__MODULE__{} = graph, nil) do @@ -984,16 +993,16 @@ defmodule RDF.Graph do |> clear_prefixes() end - defimpl Enumerable do alias RDF.Graph - def member?(graph, triple), do: {:ok, Graph.include?(graph, triple)} - def count(graph), do: {:ok, Graph.triple_count(graph)} - def slice(_graph), do: {:error, __MODULE__} + def member?(graph, triple), do: {:ok, Graph.include?(graph, triple)} + def count(graph), do: {:ok, Graph.triple_count(graph)} + def slice(_graph), do: {:error, __MODULE__} def reduce(%Graph{descriptions: descriptions}, {:cont, acc}, _fun) - when map_size(descriptions) == 0, do: {:done, acc} + when map_size(descriptions) == 0, + do: {:done, acc} def reduce(%Graph{} = graph, {:cont, acc}, fun) do {triple, rest} = Graph.pop(graph) @@ -1001,6 +1010,7 @@ defmodule RDF.Graph do end def reduce(_, {:halt, acc}, _fun), do: {:halted, acc} + def reduce(%Graph{} = graph, {:suspend, acc}, fun) do {:suspended, acc, &reduce(graph, &1, fun)} end @@ -1011,11 +1021,17 @@ defmodule RDF.Graph do def into(original) do collector_fun = fn - graph, {:cont, list} when is_list(list) - -> Graph.add(graph, List.to_tuple(list)) - graph, {:cont, elem} -> Graph.add(graph, elem) - graph, :done -> graph - _graph, :halt -> :ok + graph, {:cont, list} when is_list(list) -> + Graph.add(graph, List.to_tuple(list)) + + graph, {:cont, elem} -> + Graph.add(graph, elem) + + graph, :done -> + graph + + _graph, :halt -> + :ok end {original, collector_fun} diff --git a/lib/rdf/inspect.ex b/lib/rdf/inspect.ex index 98a3879..627a098 100644 --- a/lib/rdf/inspect.ex +++ b/lib/rdf/inspect.ex @@ -3,35 +3,34 @@ defmodule RDF.InspectHelper do import Inspect.Algebra - def objects_doc(objects, opts) do objects - |> Enum.map(fn {object, _} -> to_doc(object, opts) end) - |> fold_doc(fn(object, acc) -> line(object, acc) end) + |> Enum.map(fn {object, _} -> to_doc(object, opts) end) + |> fold_doc(fn object, acc -> line(object, acc) end) end def predications_doc(predications, opts) do predications |> Enum.map(fn {predicate, objects} -> - to_doc(predicate, opts) - |> line(objects_doc(objects, opts)) - |> nest(4) - end) - |> fold_doc(fn(predication, acc) -> - line(predication, acc) - end) + to_doc(predicate, opts) + |> line(objects_doc(objects, opts)) + |> nest(4) + end) + |> fold_doc(fn predication, acc -> + line(predication, acc) + end) end def descriptions_doc(descriptions, opts) do descriptions |> Enum.map(fn {subject, description} -> - to_doc(subject, opts) - |> line(predications_doc(description.predications, opts)) - |> nest(4) - end) - |> fold_doc(fn(predication, acc) -> - line(predication, acc) - end) + to_doc(subject, opts) + |> line(predications_doc(description.predications, opts)) + |> nest(4) + end) + |> fold_doc(fn predication, acc -> + line(predication, acc) + end) end def surround_doc(left, doc, right) do @@ -53,7 +52,7 @@ end defimpl Inspect, for: RDF.Literal do def inspect(literal, _opts) do - "%RDF.Literal{literal: #{inspect literal.literal}, valid: #{RDF.Literal.valid?(literal)}}" + "%RDF.Literal{literal: #{inspect(literal.literal)}, valid: #{RDF.Literal.valid?(literal)}}" end end @@ -66,6 +65,7 @@ defimpl Inspect, for: RDF.Description do space("subject:", to_doc(subject, opts)) |> line(predications_doc(predications, opts)) |> nest(4) + surround_doc("#RDF.Description{", doc, "}") end end @@ -79,6 +79,7 @@ defimpl Inspect, for: RDF.Graph do space("name:", to_doc(name, opts)) |> line(descriptions_doc(descriptions, opts)) |> nest(4) + surround_doc("#RDF.Graph{", doc, "}") end end @@ -92,12 +93,13 @@ defimpl Inspect, for: RDF.Dataset do space("name:", to_doc(name, opts)) |> line(graphs_doc(RDF.Dataset.graphs(dataset), opts)) |> nest(4) + surround_doc("#RDF.Dataset{", doc, "}") end defp graphs_doc(graphs, opts) do graphs - |> Enum.map(fn graph -> to_doc(graph, opts) end) - |> fold_doc(fn(graph, acc) -> line(graph, acc) end) + |> Enum.map(fn graph -> to_doc(graph, opts) end) + |> fold_doc(fn graph, acc -> line(graph, acc) end) end end diff --git a/lib/rdf/iri.ex b/lib/rdf/iri.ex index 0cad31b..8aa5447 100644 --- a/lib/rdf/iri.ex +++ b/lib/rdf/iri.ex @@ -20,10 +20,10 @@ defmodule RDF.IRI do import RDF.Guards @type t :: %__MODULE__{ - value: String.t - } + value: String.t() + } - @type coercible :: String.t | URI.t | module | t + @type coercible :: String.t() | URI.t() | module | t @enforce_keys [:value] defstruct [:value] @@ -44,16 +44,15 @@ defmodule RDF.IRI do @default_base Application.get_env(:rdf, :default_base_iri) def default_base, do: @default_base - @doc """ Creates a `RDF.IRI`. """ @spec new(coercible) :: t def new(iri) - def new(iri) when is_binary(iri), do: %__MODULE__{value: iri} + def new(iri) when is_binary(iri), do: %__MODULE__{value: iri} def new(qname) when maybe_ns_term(qname), do: Namespace.resolve_term!(qname) - def new(%URI{} = uri), do: uri |> URI.to_string |> new - def new(%__MODULE__{} = iri), do: iri + def new(%URI{} = uri), do: uri |> URI.to_string() |> new + def new(%__MODULE__{} = iri), do: iri @doc """ Creates a `RDF.IRI`, but checks if the given IRI is valid. @@ -64,11 +63,11 @@ defmodule RDF.IRI do """ @spec new!(coercible) :: t def new!(iri) - def new!(iri) when is_binary(iri), do: iri |> valid!() |> new() - def new!(qname) when maybe_ns_term(qname), do: new(qname) # since terms of a namespace are already validated - def new!(%URI{} = uri), do: uri |> valid!() |> new() - def new!(%__MODULE__{} = iri), do: valid!(iri) - + def new!(iri) when is_binary(iri), do: iri |> valid!() |> new() + # since terms of a namespace are already validated + def new!(qname) when maybe_ns_term(qname), do: new(qname) + def new!(%URI{} = uri), do: uri |> valid!() |> new() + def new!(%__MODULE__{} = iri), do: valid!(iri) @doc """ Coerces an IRI serving as a base IRI. @@ -87,8 +86,8 @@ defmodule RDF.IRI do new(module) end end - def coerce_base(base_iri), do: new(base_iri) + 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. @@ -104,11 +103,10 @@ defmodule RDF.IRI do """ @spec valid!(coercible) :: coercible def valid!(iri) do - if not valid?(iri), do: raise RDF.IRI.InvalidError, "Invalid IRI: #{inspect iri}" + if not valid?(iri), do: raise(RDF.IRI.InvalidError, "Invalid IRI: #{inspect(iri)}") iri end - @doc """ Checks if the given IRI is valid. @@ -122,8 +120,8 @@ defmodule RDF.IRI do false """ @spec valid?(coercible) :: boolean - def valid?(iri), do: absolute?(iri) # TODO: Provide a more elaborate validation - + # TODO: Provide a more elaborate validation + def valid?(iri), do: absolute?(iri) @doc """ Checks if the given value is an absolute IRI. @@ -135,17 +133,18 @@ defmodule RDF.IRI do def absolute?(iri) def absolute?(value) when is_binary(value), do: not is_nil(scheme(value)) - def absolute?(%__MODULE__{value: value}), do: absolute?(value) - def absolute?(%URI{scheme: nil}), do: false - def absolute?(%URI{scheme: _}), do: true + def absolute?(%__MODULE__{value: value}), do: absolute?(value) + def absolute?(%URI{scheme: nil}), do: false + def absolute?(%URI{scheme: _}), do: true + def absolute?(qname) when maybe_ns_term(qname) do case Namespace.resolve_term(qname) do {:ok, iri} -> absolute?(iri) _ -> false end end - def absolute?(_), do: false + def absolute?(_), do: false @doc """ Resolves a relative IRI against a base IRI. @@ -162,13 +161,12 @@ defmodule RDF.IRI do @spec absolute(coercible, coercible) :: t | nil def absolute(iri, base) do cond do - absolute?(iri) -> new(iri) + absolute?(iri) -> new(iri) not absolute?(base) -> nil - true -> merge(base, iri) + true -> merge(base, iri) end end - @doc """ Merges two IRIs. @@ -183,7 +181,6 @@ defmodule RDF.IRI do |> new() end - @doc """ Returns the scheme of the given IRI @@ -196,28 +193,27 @@ defmodule RDF.IRI do iex> RDF.IRI.scheme("not an iri") nil """ - @spec scheme(coercible) :: String.t | nil + @spec scheme(coercible) :: String.t() | nil def scheme(iri) - def scheme(%__MODULE__{value: value}), do: scheme(value) - def scheme(%URI{scheme: scheme}), do: scheme + def scheme(%__MODULE__{value: value}), do: scheme(value) + def scheme(%URI{scheme: scheme}), do: scheme def scheme(qname) when maybe_ns_term(qname), do: Namespace.resolve_term!(qname) |> scheme() + def scheme(iri) when is_binary(iri) do with [_, scheme] <- Regex.run(@scheme_regex, iri) do scheme end end - @doc """ Parses an IRI into its components and returns them as an `URI` struct. """ - @spec parse(coercible) :: URI.t + @spec parse(coercible) :: URI.t() def parse(iri) - def parse(iri) when is_binary(iri), do: URI.parse(iri) + def parse(iri) when is_binary(iri), do: URI.parse(iri) def parse(qname) when maybe_ns_term(qname), do: Namespace.resolve_term!(qname) |> parse() - def parse(%__MODULE__{value: value}), do: URI.parse(value) - def parse(%URI{} = uri), do: uri - + def parse(%__MODULE__{value: value}), do: URI.parse(value) + def parse(%URI{} = uri), do: uri @doc """ Tests for value equality of IRIs. @@ -226,7 +222,8 @@ defmodule RDF.IRI do see """ - @spec equal_value?(t | RDF.Literal.t | atom, t | RDF.Literal.t | URI.t | atom) :: boolean | nil + @spec equal_value?(t | RDF.Literal.t() | atom, t | RDF.Literal.t() | URI.t() | atom) :: + boolean | nil def equal_value?(left, right) def equal_value?(%__MODULE__{value: left}, %__MODULE__{value: right}), @@ -251,7 +248,6 @@ defmodule RDF.IRI do def equal_value?(_, _), do: nil - @doc """ Returns the given IRI as a string. @@ -267,7 +263,7 @@ defmodule RDF.IRI do "http://example.com/#Foo" """ - @spec to_string(t | module) :: String.t + @spec to_string(t | module) :: String.t() def to_string(iri) def to_string(%__MODULE__{value: value}), diff --git a/lib/rdf/list.ex b/lib/rdf/list.ex index 10c07c9..4d370da 100644 --- a/lib/rdf/list.ex +++ b/lib/rdf/list.ex @@ -12,16 +12,15 @@ defmodule RDF.List do import RDF.Guards @type t :: %__MODULE__{ - head: IRI.t, - graph: Graph.t - } + head: IRI.t(), + graph: Graph.t() + } @enforce_keys [:head] defstruct [:head, :graph] @rdf_nil RDF.Utils.Bootstrapping.rdf_iri("nil") - @doc """ Creates a `RDF.List` for a given RDF list node of a given `RDF.Graph`. @@ -33,7 +32,7 @@ defmodule RDF.List do - does not contain cycles, i.e. `rdf:rest` statements don't refer to preceding list nodes """ - @spec new(IRI.coercible, Graph.t) :: t + @spec new(IRI.coercible(), Graph.t()) :: t def new(head, graph) def new(head, graph) when maybe_ns_term(head), @@ -48,7 +47,7 @@ defmodule RDF.List do end defp well_formed?(list) do - Enum.reduce_while(list, MapSet.new, fn node_description, preceding_nodes -> + Enum.reduce_while(list, MapSet.new(), fn node_description, preceding_nodes -> with head = node_description.subject do if MapSet.member?(preceding_nodes, head) do {:halt, false} @@ -59,7 +58,6 @@ defmodule RDF.List do end) && true end - @doc """ Creates a `RDF.List` from a native Elixir list or any other `Enumerable` with coercible RDF values. @@ -73,18 +71,17 @@ defmodule RDF.List do the head node of the empty list is always `RDF.nil`. """ - @spec from(Enumerable.t, keyword) :: t + @spec from(Enumerable.t(), keyword) :: t def from(list, opts \\ []) do - with head = Keyword.get(opts, :head, RDF.bnode), - graph = Keyword.get(opts, :graph, RDF.graph), - {head, graph} = do_from(list, head, graph, opts) - do + with head = Keyword.get(opts, :head, RDF.bnode()), + graph = Keyword.get(opts, :graph, RDF.graph()), + {head, graph} = do_from(list, head, graph, opts) do %__MODULE__{head: head, graph: graph} end end defp do_from([], _, graph, _) do - {RDF.nil, graph} + {RDF.nil(), graph} end defp do_from(list, head, graph, opts) when maybe_ns_term(head) do @@ -92,16 +89,17 @@ defmodule RDF.List do end defp do_from([list | rest], head, graph, opts) when is_list(list) do - with {nested_list_node, graph} = do_from(list, RDF.bnode, graph, opts) do + with {nested_list_node, graph} = do_from(list, RDF.bnode(), graph, opts) do do_from([nested_list_node | rest], head, graph, opts) end end defp do_from([first | rest], head, graph, opts) do - with {next, graph} = do_from(rest, RDF.bnode, graph, opts) do + with {next, graph} = do_from(rest, RDF.bnode(), graph, opts) do { head, - Graph.add(graph, + Graph.add( + graph, head |> RDF.first(first) |> RDF.rest(next) @@ -116,16 +114,16 @@ defmodule RDF.List do |> do_from(head, graph, opts) end - @doc """ The values of a `RDF.List` as an Elixir list. Nested lists are converted recursively. """ - @spec values(t) :: Enumerable.t + @spec values(t) :: Enumerable.t() def values(%__MODULE__{graph: graph} = list) do - Enum.map list, fn node_description -> - value = Description.first(node_description, RDF.first) + Enum.map(list, fn node_description -> + value = Description.first(node_description, RDF.first()) + if node?(value, graph) do value |> new(graph) @@ -133,26 +131,23 @@ defmodule RDF.List do else value end - end + end) end - @doc """ The RDF nodes constituting a `RDF.List` as an Elixir list. """ - @spec nodes(t) :: [BlankNode.t] + @spec nodes(t) :: [BlankNode.t()] def nodes(%__MODULE__{} = list) do - Enum.map list, fn node_description -> node_description.subject end + Enum.map(list, fn node_description -> node_description.subject end) end - @doc """ Checks if a list is the empty list. """ @spec empty?(t) :: boolean def empty?(%__MODULE__{head: @rdf_nil}), do: true - def empty?(%__MODULE__{}), do: false - + def empty?(%__MODULE__{}), do: false @doc """ Checks if the given list consists of list nodes which are all blank nodes. @@ -161,12 +156,11 @@ defmodule RDF.List do def valid?(%__MODULE__{head: @rdf_nil}), do: true def valid?(%__MODULE__{} = list) do - Enum.all? list, fn node_description -> + Enum.all?(list, fn node_description -> RDF.bnode?(node_description.subject) - end + end) end - @doc """ Checks if a given resource is a RDF list node in a given `RDF.Graph`. @@ -176,7 +170,7 @@ defmodule RDF.List do Note: This function doesn't indicate if the list is valid. See `new/2` and `valid?/2` for validations. """ - @spec node?(any, Graph.t) :: boolean + @spec node?(any, Graph.t()) :: boolean def node?(list_node, graph) def node?(@rdf_nil, _), @@ -204,15 +198,14 @@ defmodule RDF.List do def node?(nil), do: false def node?(%Description{predications: predications}) do - Map.has_key?(predications, RDF.first) and - Map.has_key?(predications, RDF.rest) + Map.has_key?(predications, RDF.first()) and + Map.has_key?(predications, RDF.rest()) end - defimpl Enumerable do @rdf_nil RDF.Utils.Bootstrapping.rdf_iri("nil") - def reduce(_, {:halt, acc}, _fun), do: {:halted, acc} + def reduce(_, {:halt, acc}, _fun), do: {:halted, acc} def reduce(list, {:suspend, acc}, fun), do: {:suspended, acc, &reduce(list, &1, fun)} def reduce(%RDF.List{head: @rdf_nil}, {:cont, acc}, _fun), @@ -226,19 +219,17 @@ defmodule RDF.List do def reduce(_, _, _), do: {:halted, nil} - defp do_reduce(%RDF.List{head: head, graph: graph}, - {:cont, acc}, fun) do + defp do_reduce(%RDF.List{head: head, graph: graph}, {:cont, acc}, fun) do with description when not is_nil(description) <- - Graph.description(graph, head), - [_] <- Description.get(description, RDF.first), - [rest] <- Description.get(description, RDF.rest), - acc = fun.(description, acc) - do + Graph.description(graph, head), + [_] <- Description.get(description, RDF.first()), + [rest] <- Description.get(description, RDF.rest()), + acc = fun.(description, acc) do if rest == @rdf_nil do case acc do {:cont, acc} -> {:done, acc} # TODO: Is the :suspend case handled properly - _ -> reduce(%RDF.List{head: rest, graph: graph}, acc, fun) + _ -> reduce(%RDF.List{head: rest, graph: graph}, acc, fun) end else reduce(%RDF.List{head: rest, graph: graph}, acc, fun) @@ -246,13 +237,14 @@ defmodule RDF.List do else nil -> {:halted, nil} + values when is_list(values) -> {:halted, nil} end end - def member?(_, _), do: {:error, __MODULE__} - def count(_), do: {:error, __MODULE__} - def slice(_), do: {:error, __MODULE__} + def member?(_, _), do: {:error, __MODULE__} + def count(_), do: {:error, __MODULE__} + def slice(_), do: {:error, __MODULE__} end end diff --git a/lib/rdf/literal.ex b/lib/rdf/literal.ex index 612581f..b0f9849 100644 --- a/lib/rdf/literal.ex +++ b/lib/rdf/literal.ex @@ -35,8 +35,10 @@ defmodule RDF.Literal do def new(value) do case coerce(value) do nil -> - raise RDF.Literal.InvalidError, "#{inspect value} not convertible to a RDF.Literal" - literal -> literal + raise RDF.Literal.InvalidError, "#{inspect(value)} not convertible to a RDF.Literal" + + literal -> + literal end end @@ -58,7 +60,7 @@ defmodule RDF.Literal do datatype = Keyword.get(opts, :datatype) -> case Datatype.get(datatype) do - nil -> Generic.new(value, opts) + nil -> Generic.new(value, opts) datatype -> datatype.new(value, opts) end @@ -98,16 +100,16 @@ defmodule RDF.Literal do def coerce(%__MODULE__{} = literal), do: literal - def coerce(value) when is_binary(value), do: RDF.XSD.String.new(value) + def coerce(value) when is_binary(value), do: RDF.XSD.String.new(value) def coerce(value) when is_boolean(value), do: RDF.XSD.Boolean.new(value) def coerce(value) when is_integer(value), do: RDF.XSD.Integer.new(value) - def coerce(value) when is_float(value), do: RDF.XSD.Double.new(value) - def coerce(%Decimal{} = value), do: RDF.XSD.Decimal.new(value) - def coerce(%Date{} = value), do: RDF.XSD.Date.new(value) - def coerce(%Time{} = value), do: RDF.XSD.Time.new(value) - def coerce(%DateTime{} = value), do: RDF.XSD.DateTime.new(value) - def coerce(%NaiveDateTime{} = value), do: RDF.XSD.DateTime.new(value) - def coerce(%URI{} = value), do: RDF.XSD.AnyURI.new(value) + def coerce(value) when is_float(value), do: RDF.XSD.Double.new(value) + def coerce(%Decimal{} = value), do: RDF.XSD.Decimal.new(value) + def coerce(%Date{} = value), do: RDF.XSD.Date.new(value) + def coerce(%Time{} = value), do: RDF.XSD.Time.new(value) + def coerce(%DateTime{} = value), do: RDF.XSD.DateTime.new(value) + def coerce(%NaiveDateTime{} = value), do: RDF.XSD.DateTime.new(value) + def coerce(%URI{} = value), do: RDF.XSD.AnyURI.new(value) def coerce(value) when maybe_ns_term(value) do case RDF.Namespace.resolve_term(value) do @@ -132,7 +134,6 @@ defmodule RDF.Literal do def coerce(_), do: nil - @doc """ Creates a new `RDF.Literal`, but fails if it's not valid. @@ -154,10 +155,11 @@ defmodule RDF.Literal do @spec new!(t | any, keyword) :: t def new!(value, opts \\ []) do literal = new(value, opts) + if valid?(literal) do literal else - raise RDF.Literal.InvalidError, "invalid RDF.Literal: #{inspect literal}" + raise RDF.Literal.InvalidError, "invalid RDF.Literal: #{inspect(literal)}" end end @@ -223,8 +225,7 @@ defmodule RDF.Literal do """ @spec simple?(t) :: boolean def simple?(%__MODULE__{literal: %RDF.XSD.String{}}), do: true - def simple?(%__MODULE__{}), do: false - + def simple?(%__MODULE__{}), do: false @doc """ Returns if a literal is a plain literal. @@ -263,7 +264,7 @@ defmodule RDF.Literal do @doc """ Returns the lexical form of the given `literal`. """ - @spec lexical(t) :: String.t + @spec lexical(t) :: String.t() def lexical(%__MODULE__{literal: %datatype{} = literal}), do: datatype.lexical(literal) @doc """ @@ -275,8 +276,9 @@ defmodule RDF.Literal do @doc """ Returns the canonical lexical of the given `literal`. """ - @spec canonical_lexical(t) :: String.t | nil - def canonical_lexical(%__MODULE__{literal: %datatype{} = literal}), do: datatype.canonical_lexical(literal) + @spec canonical_lexical(t) :: String.t() | nil + def canonical_lexical(%__MODULE__{literal: %datatype{} = literal}), + do: datatype.canonical_lexical(literal) @doc """ Returns if the lexical of the given `literal` has the canonical form. @@ -311,7 +313,7 @@ defmodule RDF.Literal do def equal_value?(_, _), do: nil - @spec compare(t, t) :: Datatype.comparison_result | :indeterminate | nil + @spec compare(t, t) :: Datatype.comparison_result() | :indeterminate | nil def compare(%__MODULE__{literal: %datatype{} = left}, right) do datatype.compare(left, right) end @@ -339,16 +341,21 @@ defmodule RDF.Literal do see """ - @spec matches?(t | String.t, pattern :: t | String.t, flags :: t | String.t) :: boolean + @spec matches?(t | String.t(), pattern :: t | String.t(), flags :: t | String.t()) :: boolean def matches?(value, pattern, flags \\ "") + def matches?(%__MODULE__{} = literal, pattern, flags), do: matches?(lexical(literal), pattern, flags) + def matches?(value, %__MODULE__{literal: %RDF.XSD.String{}} = pattern, flags), do: matches?(value, lexical(pattern), flags) + def matches?(value, pattern, %__MODULE__{literal: %RDF.XSD.String{}} = flags), do: matches?(value, pattern, lexical(flags)) - def matches?(value, pattern, flags) when is_binary(value) and is_binary(pattern) and is_binary(flags), - do: RDF.XSD.Utils.Regex.matches?(value, pattern, flags) + + def matches?(value, pattern, flags) + when is_binary(value) and is_binary(pattern) and is_binary(flags), + do: RDF.XSD.Utils.Regex.matches?(value, pattern, flags) @doc """ Updates the value of a `RDF.Literal` without changing everything else. diff --git a/lib/rdf/literal/datatype.ex b/lib/rdf/literal/datatype.ex index 91fd1b7..8842bd4 100644 --- a/lib/rdf/literal/datatype.ex +++ b/lib/rdf/literal/datatype.ex @@ -53,7 +53,7 @@ defmodule RDF.Literal.Datatype do A final catch-all clause should delegate to `super`. For example `RDF.XSD.Datatype`s will handle casting from derived datatypes in the default implementation. """ - @callback do_cast(literal | RDF.IRI.t | RDF.BlankNode.t) :: Literal.t() | nil + @callback do_cast(literal | RDF.IRI.t() | RDF.BlankNode.t()) :: Literal.t() | nil @doc """ Checks if the given `RDF.Literal` has the datatype for which the `RDF.Literal.Datatype` is implemented or is derived from it. @@ -64,24 +64,24 @@ defmodule RDF.Literal.Datatype do true """ - @callback datatype?(Literal.t | t | literal) :: boolean + @callback datatype?(Literal.t() | t | literal) :: boolean @doc """ The datatype IRI of the given `RDF.Literal`. """ - @callback datatype_id(Literal.t | literal) :: IRI.t() + @callback datatype_id(Literal.t() | literal) :: IRI.t() @doc """ The language of the given `RDF.Literal` if present. """ - @callback language(Literal.t | literal) :: String.t() | nil + @callback language(Literal.t() | literal) :: String.t() | nil @doc """ Returns the value of a `RDF.Literal`. This function also accepts literals of derived datatypes. """ - @callback value(Literal.t | literal) :: any + @callback value(Literal.t() | literal) :: any @doc """ Returns the lexical form of a `RDF.Literal`. @@ -178,7 +178,7 @@ defmodule RDF.Literal.Datatype do iex> RDF.literal("foo", datatype: "http://example.com/dt") |> RDF.Literal.Generic.update(fn _ -> "bar" end) RDF.literal("bar", datatype: "http://example.com/dt") """ - @callback update(Literal.t() | literal, fun()) :: Literal.t + @callback update(Literal.t() | literal, fun()) :: Literal.t() @doc """ Updates the value of a `RDF.Literal` without changing anything else. @@ -192,7 +192,7 @@ defmodule RDF.Literal.Datatype do ...> fn value -> value <> "1" end, as: :lexical) RDF.XSD.integer(421) """ - @callback update(Literal.t() | literal, fun(), keyword) :: Literal.t + @callback update(Literal.t() | literal, fun(), keyword) :: Literal.t() @doc """ Returns the `RDF.Literal.Datatype` for a datatype IRI. @@ -200,14 +200,13 @@ defmodule RDF.Literal.Datatype do defdelegate get(id), to: Literal.Datatype.Registry, as: :datatype @doc !""" - As opposed to RDF.Literal.valid?/1 this function operates on the datatype structs ... + As opposed to RDF.Literal.valid?/1 this function operates on the datatype structs ... - It's meant for internal use only and doesn't perform checks if the struct - passed is actually a `RDF.Literal.Datatype` struct. - """ + It's meant for internal use only and doesn't perform checks if the struct + passed is actually a `RDF.Literal.Datatype` struct. + """ def valid?(%datatype{} = datatype_literal), do: datatype.valid?(datatype_literal) - defmacro __using__(opts) do name = Keyword.fetch!(opts, :name) id = Keyword.fetch!(opts, :id) @@ -227,10 +226,10 @@ defmodule RDF.Literal.Datatype do @behaviour unquote(__MODULE__) @doc !""" - This function is just used to check if a module is a RDF.Literal.Datatype. + This function is just used to check if a module is a RDF.Literal.Datatype. - See `RDF.Literal.Datatype.Registry.is_rdf_literal_datatype?/1`. - """ + See `RDF.Literal.Datatype.Registry.is_rdf_literal_datatype?/1`. + """ def __rdf_literal_datatype_indicator__, do: true @name unquote(name) @@ -274,6 +273,7 @@ defmodule RDF.Literal.Datatype do literal |> canonical() |> lexical() end end + def canonical_lexical(_), do: nil @doc """ @@ -284,15 +284,17 @@ defmodule RDF.Literal.Datatype do Implementations define the casting for a given value with the `c:RDF.Literal.Datatype.do_cast/1` callback. """ - @spec cast(Literal.Datatype.literal | RDF.Term.t) :: Literal.t() | nil + @spec cast(Literal.Datatype.literal() | RDF.Term.t()) :: Literal.t() | nil @dialyzer {:nowarn_function, cast: 1} def cast(literal_or_value) def cast(%Literal{literal: literal}), do: cast(literal) + def cast(%__MODULE__{} = datatype_literal), - do: if(valid?(datatype_literal), do: literal(datatype_literal)) + do: if(valid?(datatype_literal), do: literal(datatype_literal)) + def cast(%struct{} = datatype_literal) do if (Literal.datatype?(struct) and Literal.Datatype.valid?(datatype_literal)) or - struct in [RDF.IRI, RDF.BlankNode] do + struct in [RDF.IRI, RDF.BlankNode] do case do_cast(datatype_literal) do %__MODULE__{} = literal -> if valid?(literal), do: literal(literal) %Literal{literal: %__MODULE__{}} = literal -> if valid?(literal), do: literal @@ -325,10 +327,15 @@ defmodule RDF.Literal.Datatype do def equal_value?(%Literal{literal: left}, right), do: equal_value?(left, right) def equal_value?(nil, _), do: nil def equal_value?(_, nil), do: nil + def equal_value?(left, right) do cond do - not Literal.datatype?(right) and not resource?(right) -> equal_value?(left, Literal.coerce(right)) - not Literal.datatype?(left) and not resource?(left) -> equal_value?(Literal.coerce(left), right) + not Literal.datatype?(right) and not resource?(right) -> + equal_value?(left, Literal.coerce(right)) + + not Literal.datatype?(left) and not resource?(left) -> + equal_value?(Literal.coerce(left), right) + true -> left_datatype = left.__struct__ right_datatype = right.__struct__ @@ -343,6 +350,7 @@ defmodule RDF.Literal.Datatype do case equality_path(left_datatype, right_datatype) do {:same_or_derived, datatype} -> datatype.do_equal_value_same_or_derived_datatypes?(left, right) + {:different, datatype} -> datatype.do_equal_value_different_datatypes?(left, right) end @@ -381,14 +389,15 @@ defmodule RDF.Literal.Datatype do # RDF.XSD.Datatypes offers another default implementation, but since it is # still in a macro implementation defoverridable doesn't work unless RDF.XSD.Datatype in @behaviour do - @spec compare(RDF.Literal.t() | any, RDF.Literal.t() | any) :: RDF.Literal.Datatype.comparison_result | :indeterminate | nil + @spec compare(RDF.Literal.t() | any, RDF.Literal.t() | any) :: + RDF.Literal.Datatype.comparison_result() | :indeterminate | nil def compare(left, right) def compare(left, %RDF.Literal{literal: right}), do: compare(left, right) def compare(%RDF.Literal{literal: left}, right), do: compare(left, right) def compare(left, right) do if RDF.Literal.datatype?(left) and RDF.Literal.datatype?(right) and - RDF.Literal.Datatype.valid?(left) and RDF.Literal.Datatype.valid?(right) do + RDF.Literal.Datatype.valid?(left) and RDF.Literal.Datatype.valid?(right) do do_compare(left, right) end end @@ -396,8 +405,12 @@ defmodule RDF.Literal.Datatype do @impl RDF.Literal.Datatype def do_compare(%datatype{} = left, %datatype{} = right) do case {datatype.value(left), datatype.value(right)} do - {left_value, right_value} when left_value < right_value -> :lt - {left_value, right_value} when left_value > right_value -> :gt + {left_value, right_value} when left_value < right_value -> + :lt + + {left_value, right_value} when left_value > right_value -> + :gt + _ -> if datatype.equal_value?(left, right), do: :eq end @@ -415,6 +428,7 @@ defmodule RDF.Literal.Datatype do @impl unquote(__MODULE__) def update(literal, fun, opts \\ []) def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts) + def update(%__MODULE__{} = literal, fun, opts) do case Keyword.get(opts, :as) do :lexical -> lexical(literal) @@ -449,7 +463,7 @@ defmodule RDF.Literal.Datatype do import ProtocolEx defimpl_ex Registration, unquote(unquoted_id), - for: RDF.Literal.Datatype.Registry.Registration do + for: RDF.Literal.Datatype.Registry.Registration do @moduledoc false def datatype(id), do: unquote(datatype) diff --git a/lib/rdf/literal/datatype/registry.ex b/lib/rdf/literal/datatype/registry.ex index 570a037..762e558 100644 --- a/lib/rdf/literal/datatype/registry.ex +++ b/lib/rdf/literal/datatype/registry.ex @@ -13,37 +13,38 @@ defmodule RDF.Literal.Datatype.Registry do RDF.XSD.Double ] - @builtin_numeric_datatypes @primitive_numeric_datatypes ++ [ - RDF.XSD.Long, - RDF.XSD.Int, - RDF.XSD.Short, - RDF.XSD.Byte, - RDF.XSD.NonNegativeInteger, - RDF.XSD.PositiveInteger, - RDF.XSD.UnsignedLong, - RDF.XSD.UnsignedInt, - RDF.XSD.UnsignedShort, - RDF.XSD.UnsignedByte, - RDF.XSD.NonPositiveInteger, - RDF.XSD.NegativeInteger, - RDF.XSD.Float - ] + @builtin_numeric_datatypes @primitive_numeric_datatypes ++ + [ + RDF.XSD.Long, + RDF.XSD.Int, + RDF.XSD.Short, + RDF.XSD.Byte, + RDF.XSD.NonNegativeInteger, + RDF.XSD.PositiveInteger, + RDF.XSD.UnsignedLong, + RDF.XSD.UnsignedInt, + RDF.XSD.UnsignedShort, + RDF.XSD.UnsignedByte, + RDF.XSD.NonPositiveInteger, + RDF.XSD.NegativeInteger, + RDF.XSD.Float + ] @builtin_xsd_datatypes [ - XSD.Boolean, - XSD.String, - XSD.Date, - XSD.Time, - XSD.DateTime, - XSD.AnyURI - ] ++ @builtin_numeric_datatypes + XSD.Boolean, + XSD.String, + XSD.Date, + XSD.Time, + XSD.DateTime, + XSD.AnyURI + ] ++ @builtin_numeric_datatypes @builtin_datatypes [RDF.LangString | @builtin_xsd_datatypes] @doc """ Returns a list of all builtin `RDF.Literal.Datatype` modules. """ - @spec builtin_datatypes :: [RDF.Literal.Datatype.t] + @spec builtin_datatypes :: [RDF.Literal.Datatype.t()] def builtin_datatypes, do: @builtin_datatypes @doc """ @@ -63,7 +64,7 @@ defmodule RDF.Literal.Datatype.Registry do @doc """ Checks if the given module is a builtin datatype or a registered custom datatype implementing the `RDF.Literal.Datatype` behaviour. """ - @spec datatype?(Literal.t | Literal.Datatype.literal | module) :: boolean + @spec datatype?(Literal.t() | Literal.Datatype.literal() | module) :: boolean def datatype?(value) # We assume literals were created properly which means they have a proper RDF.Literal.Datatype @@ -71,7 +72,7 @@ defmodule RDF.Literal.Datatype.Registry do def datatype?(value), do: datatype_struct?(value) @doc false - @spec datatype_struct?(Literal.Datatype.literal | module) :: boolean + @spec datatype_struct?(Literal.Datatype.literal() | module) :: boolean def datatype_struct?(value) def datatype_struct?(%datatype{}), do: datatype_struct?(datatype) @@ -87,7 +88,7 @@ defmodule RDF.Literal.Datatype.Registry do @doc """ Returns a list of all builtin `RDF.XSD.Datatype` modules. """ - @spec builtin_xsd_datatypes :: [RDF.Literal.Datatype.t] + @spec builtin_xsd_datatypes :: [RDF.Literal.Datatype.t()] def builtin_xsd_datatypes, do: @builtin_xsd_datatypes @doc false @@ -103,13 +104,13 @@ defmodule RDF.Literal.Datatype.Registry do @doc """ Checks if the given module is a builtin XSD datatype or a registered custom datatype implementing the `RDF.XSD.Datatype` behaviour. """ - @spec xsd_datatype?(Literal.t | XSD.Datatype.literal | module) :: boolean + @spec xsd_datatype?(Literal.t() | XSD.Datatype.literal() | module) :: boolean def xsd_datatype?(value) def xsd_datatype?(%Literal{literal: datatype_struct}), do: xsd_datatype?(datatype_struct) def xsd_datatype?(value), do: xsd_datatype_struct?(value) @doc false - @spec xsd_datatype_struct?(RDF.Literal.t() | XSD.Datatype.literal | module) :: boolean + @spec xsd_datatype_struct?(RDF.Literal.t() | XSD.Datatype.literal() | module) :: boolean def xsd_datatype_struct?(value) def xsd_datatype_struct?(%datatype{}), do: xsd_datatype_struct?(datatype) @@ -123,13 +124,13 @@ defmodule RDF.Literal.Datatype.Registry do @doc """ Returns a list of all numeric datatype modules. """ - @spec builtin_numeric_datatypes() :: [RDF.Literal.Datatype.t] + @spec builtin_numeric_datatypes() :: [RDF.Literal.Datatype.t()] def builtin_numeric_datatypes(), do: @builtin_numeric_datatypes @doc """ The set of all primitive numeric datatypes. """ - @spec primitive_numeric_datatypes() :: [RDF.Literal.Datatype.t] + @spec primitive_numeric_datatypes() :: [RDF.Literal.Datatype.t()] def primitive_numeric_datatypes(), do: @primitive_numeric_datatypes @doc false @@ -142,7 +143,6 @@ defmodule RDF.Literal.Datatype.Registry do def builtin_numeric_datatype?(_), do: false - @doc """ Returns if a given literal or datatype has or is a numeric datatype. """ @@ -152,12 +152,11 @@ defmodule RDF.Literal.Datatype.Registry do def numeric_datatype?(%datatype{}), do: numeric_datatype?(datatype) def numeric_datatype?(datatype) when maybe_module(datatype) do - builtin_numeric_datatype?(datatype) or ( - xsd_datatype?(datatype) and - Enum.any?(@primitive_numeric_datatypes, fn numeric_primitive -> - datatype.derived_from?(numeric_primitive) - end) - ) + builtin_numeric_datatype?(datatype) or + (xsd_datatype?(datatype) and + Enum.any?(@primitive_numeric_datatypes, fn numeric_primitive -> + datatype.derived_from?(numeric_primitive) + end)) end def numeric_datatype?(_), do: false @@ -165,7 +164,7 @@ defmodule RDF.Literal.Datatype.Registry do @doc """ Returns the `RDF.Literal.Datatype` for a datatype IRI. """ - @spec datatype(Literal.t | IRI.t | String.t) :: Literal.Datatype.t + @spec datatype(Literal.t() | IRI.t() | String.t()) :: Literal.Datatype.t() def datatype(%Literal{} = literal), do: literal.literal.__struct__ def datatype(%IRI{} = id), do: id |> to_string() |> datatype() def datatype(id) when maybe_ns_term(id), do: id |> Namespace.resolve_term!() |> datatype() @@ -174,7 +173,7 @@ defmodule RDF.Literal.Datatype.Registry do @doc """ Returns the `RDF.XSD.Datatype` for a datatype IRI. """ - @spec xsd_datatype(Literal.t | IRI.t | String.t) :: XSD.Datatype.t + @spec xsd_datatype(Literal.t() | IRI.t() | String.t()) :: XSD.Datatype.t() def xsd_datatype(id) do datatype = datatype(id) diff --git a/lib/rdf/literal/datatypes/generic.ex b/lib/rdf/literal/datatypes/generic.ex index 40df786..501a726 100644 --- a/lib/rdf/literal/datatypes/generic.ex +++ b/lib/rdf/literal/datatypes/generic.ex @@ -14,16 +14,18 @@ defmodule RDF.Literal.Generic do import RDF.Guards @type t :: %__MODULE__{ - value: String.t, - datatype: String.t - } + value: String.t(), + datatype: String.t() + } @impl Datatype - @spec new(any, String.t | IRI.t | keyword) :: Literal.t + @spec new(any, String.t() | IRI.t() | keyword) :: Literal.t() def new(value, datatype_or_opts \\ []) def new(value, %IRI{} = datatype), do: new(value, datatype: datatype) + def new(value, datatype) when is_binary(datatype) or maybe_ns_term(datatype), do: new(value, datatype: datatype) + def new(value, opts) do %Literal{ literal: %__MODULE__{ @@ -36,18 +38,24 @@ defmodule RDF.Literal.Generic do defp normalize_datatype(nil), do: nil defp normalize_datatype(""), do: nil defp normalize_datatype(%IRI{} = datatype), do: to_string(datatype) - defp normalize_datatype(datatype) when maybe_ns_term(datatype), do: datatype |> RDF.iri() |> to_string() + + defp normalize_datatype(datatype) when maybe_ns_term(datatype), + do: datatype |> RDF.iri() |> to_string() + defp normalize_datatype(datatype), do: datatype @impl Datatype - @spec new!(any, String.t | IRI.t | keyword) :: Literal.t + @spec new!(any, String.t() | IRI.t() | keyword) :: Literal.t() def new!(value, datatype_or_opts \\ []) do literal = new(value, datatype_or_opts) if valid?(literal) do literal else - raise ArgumentError, "#{inspect(value)} with datatype #{inspect literal.literal.datatype} is not a valid #{inspect(__MODULE__)}" + raise ArgumentError, + "#{inspect(value)} with datatype #{inspect(literal.literal.datatype)} is not a valid #{ + inspect(__MODULE__) + }" end end @@ -88,15 +96,23 @@ defmodule RDF.Literal.Generic do def do_equal_value_same_or_derived_datatypes?( %{datatype: datatype} = left, %{datatype: datatype} = right - ), do: left == right + ), + do: left == right + def do_equal_value_same_or_derived_datatypes?(_, _), do: nil @impl Datatype - def do_compare(%__MODULE__{datatype: datatype} = left_literal, - %__MODULE__{datatype: datatype} = right_literal) do + def do_compare( + %__MODULE__{datatype: datatype} = left_literal, + %__MODULE__{datatype: datatype} = right_literal + ) do case {left_literal.value, right_literal.value} do - {left_value, right_value} when left_value < right_value -> :lt - {left_value, right_value} when left_value > right_value -> :gt + {left_value, right_value} when left_value < right_value -> + :lt + + {left_value, right_value} when left_value > right_value -> + :gt + _ -> if equal_value?(left_literal, right_literal), do: :eq end @@ -107,6 +123,7 @@ defmodule RDF.Literal.Generic do @impl Datatype def update(literal, fun, opts \\ []) def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts) + def update(%__MODULE__{} = literal, fun, _opts) do literal |> value() diff --git a/lib/rdf/literal/datatypes/lang_string.ex b/lib/rdf/literal/datatypes/lang_string.ex index 8a4a6fd..73c8899 100644 --- a/lib/rdf/literal/datatypes/lang_string.ex +++ b/lib/rdf/literal/datatypes/lang_string.ex @@ -6,8 +6,8 @@ defmodule RDF.LangString do defstruct [:value, :language] use RDF.Literal.Datatype, - name: "langString", - id: RDF.Utils.Bootstrapping.rdf_iri("langString") + name: "langString", + id: RDF.Utils.Bootstrapping.rdf_iri("langString") import RDF.Utils.Guards @@ -15,18 +15,19 @@ defmodule RDF.LangString do alias RDF.Literal @type t :: %__MODULE__{ - value: String.t, - language: String.t - } + value: String.t(), + language: String.t() + } @doc """ Creates a new `RDF.Literal` with this datatype and the given `value` and `language`. """ @impl RDF.Literal.Datatype - @spec new(any, String.t | atom | keyword) :: Literal.t + @spec new(any, String.t() | atom | keyword) :: Literal.t() def new(value, language_or_opts \\ []) def new(value, language) when is_binary(language), do: new(value, language: language) def new(value, language) when is_ordinary_atom(language), do: new(value, language: language) + def new(value, opts) do %Literal{ literal: %__MODULE__{ @@ -38,18 +39,24 @@ defmodule RDF.LangString do defp normalize_language(nil), do: nil defp normalize_language(""), do: nil - defp normalize_language(language) when is_ordinary_atom(language), do: language |> to_string() |> normalize_language() + + defp normalize_language(language) when is_ordinary_atom(language), + do: language |> to_string() |> normalize_language() + defp normalize_language(language), do: String.downcase(language) @impl RDF.Literal.Datatype - @spec new!(any, String.t | atom | keyword) :: Literal.t + @spec new!(any, String.t() | atom | keyword) :: Literal.t() def new!(value, language_or_opts \\ []) do literal = new(value, language_or_opts) if valid?(literal) do literal else - raise ArgumentError, "#{inspect(value)} with language #{inspect literal.literal.language} is not a valid #{inspect(__MODULE__)}" + raise ArgumentError, + "#{inspect(value)} with language #{inspect(literal.literal.language)} is not a valid #{ + inspect(__MODULE__) + }" end end @@ -84,6 +91,7 @@ defmodule RDF.LangString do @impl Datatype def update(literal, fun, opts \\ []) def update(%Literal{literal: literal}, fun, opts), do: update(literal, fun, opts) + def update(%__MODULE__{} = literal, fun, _opts) do literal |> value() @@ -102,12 +110,14 @@ defmodule RDF.LangString do see """ - @spec match_language?(Literal.t | t() | String.t, String.t) :: boolean + @spec match_language?(Literal.t() | t() | String.t(), String.t()) :: boolean def match_language?(language_tag, language_range) def match_language?(%Literal{literal: literal}, language_range), do: match_language?(literal, language_range) + def match_language?(%__MODULE__{language: nil}, _), do: false + def match_language?(%__MODULE__{language: language_tag}, language_range), do: match_language?(language_tag, language_range) @@ -121,7 +131,7 @@ defmodule RDF.LangString do case String.split(language_tag, language_range, parts: 2) do [_, rest] -> rest == "" or String.starts_with?(rest, "-") - _ -> false + _ -> false end end diff --git a/lib/rdf/namespace.ex b/lib/rdf/namespace.ex index 24084fe..88dc71e 100644 --- a/lib/rdf/namespace.ex +++ b/lib/rdf/namespace.ex @@ -14,14 +14,13 @@ defmodule RDF.Namespace do @doc """ Resolves a term to a `RDF.IRI`. """ - @callback __resolve_term__(atom) :: {:ok, IRI.t} | {:error, Exception.t} + @callback __resolve_term__(atom) :: {:ok, IRI.t()} | {:error, Exception.t()} @doc """ All terms of a `RDF.Namespace`. """ @callback __terms__() :: [atom] - @doc """ Resolves a qualified term to a `RDF.IRI`. @@ -29,7 +28,7 @@ defmodule RDF.Namespace do delegates to remaining part of the term to `__resolve_term__/1` of this determined namespace. """ - @spec resolve_term(IRI.t | module) :: {:ok, IRI.t} | {:error, Exception.t} + @spec resolve_term(IRI.t() | module) :: {:ok, IRI.t()} | {:error, Exception.t()} def resolve_term(expr) def resolve_term(%IRI{} = iri), do: {:ok, iri} @@ -45,7 +44,7 @@ defmodule RDF.Namespace do See `resolve_term/1` for more. """ - @spec resolve_term!(IRI.t | module) :: IRI.t + @spec resolve_term!(IRI.t() | module) :: IRI.t() def resolve_term!(expr) do with {:ok, iri} <- resolve_term(expr) do iri @@ -57,7 +56,7 @@ defmodule RDF.Namespace do defp do_resolve_term("Elixir." <> _ = namespaced_term) do {term, namespace} = namespaced_term - |> Module.split + |> Module.split() |> List.pop_at(-1) do_resolve_term(Module.concat(namespace), String.to_atom(term)) @@ -65,20 +64,18 @@ defmodule RDF.Namespace do defp do_resolve_term(namespaced_term) do {:error, - %RDF.Namespace.UndefinedTermError{ - message: "#{namespaced_term} is not a term on a RDF.Namespace" - } - } + %RDF.Namespace.UndefinedTermError{ + message: "#{namespaced_term} is not a term on a RDF.Namespace" + }} end defp do_resolve_term(RDF, term), do: do_resolve_term(RDF.NS.RDF, term) defp do_resolve_term(Elixir, term) do {:error, - %RDF.Namespace.UndefinedTermError{message: - "#{term} is not a RDF.Namespace; top-level modules can't be RDF.Namespaces" - } - } + %RDF.Namespace.UndefinedTermError{ + message: "#{term} is not a RDF.Namespace; top-level modules can't be RDF.Namespaces" + }} end defp do_resolve_term(namespace, term) do @@ -91,9 +88,7 @@ defmodule RDF.Namespace do if is_module and Keyword.has_key?(namespace.__info__(:functions), :__resolve_term__) do namespace.__resolve_term__(term) else - {:error, - %RDF.Namespace.UndefinedTermError{message: "#{namespace} is not a RDF.Namespace"} - } + {:error, %RDF.Namespace.UndefinedTermError{message: "#{namespace} is not a RDF.Namespace"}} end end end diff --git a/lib/rdf/ns.ex b/lib/rdf/ns.ex index 4e45211..6c099b4 100644 --- a/lib/rdf/ns.ex +++ b/lib/rdf/ns.ex @@ -26,7 +26,7 @@ defmodule RDF.NS do base_iri: "http://www.w3.org/1999/02/22-rdf-syntax-ns#", file: "rdf.ttl", alias: [ - Nil: "nil", + Nil: "nil", LangString: "langString" ] diff --git a/lib/rdf/prefix_map.ex b/lib/rdf/prefix_map.ex index 8709d9d..460d6e8 100644 --- a/lib/rdf/prefix_map.ex +++ b/lib/rdf/prefix_map.ex @@ -7,11 +7,11 @@ defmodule RDF.PrefixMap do alias RDF.IRI - @type prefix :: atom - @type namespace :: IRI.t + @type prefix :: atom + @type namespace :: IRI.t() - @type coercible_prefix :: atom | String.t - @type coercible_namespace :: atom | String.t | IRI.t + @type coercible_prefix :: atom | String.t() + @type coercible_namespace :: atom | String.t() | IRI.t() @type prefix_map :: %{prefix => namespace} @@ -20,11 +20,10 @@ defmodule RDF.PrefixMap do @type t :: %__MODULE__{ map: prefix_map - } + } defstruct map: %{} - @doc """ Creates an empty `RDF.PrefixMap`. """ @@ -67,7 +66,7 @@ defmodule RDF.PrefixMap do Unless a mapping of the given prefix to a different namespace already exists, an ok tuple is returned, other an error tuple. """ - @spec add(t, coercible_prefix, coercible_namespace) :: {:ok, t} | {:error, String.t} + @spec add(t, coercible_prefix, coercible_namespace) :: {:ok, t} | {:error, String.t()} def add(prefix_map, prefix, namespace) def add(%__MODULE__{map: map}, prefix, %IRI{} = namespace) when is_atom(prefix) do @@ -109,7 +108,7 @@ defmodule RDF.PrefixMap do See also `merge/3` which allows you to resolve conflicts with a function. """ - @spec merge(t, t | map | keyword) :: {:ok, t} | {:error, [atom | String.t]} + @spec merge(t, t | map | keyword) :: {:ok, t} | {:error, [atom | String.t()]} def merge(prefix_map1, prefix_map2) def merge(%__MODULE__{map: map1}, %__MODULE__{map: map2}) do @@ -149,7 +148,8 @@ defmodule RDF.PrefixMap do If everything could be merged, an `:ok` tuple is returned. """ - @spec merge(t, t | map | keyword, conflict_resolver | nil) :: {:ok, t} | {:error, [atom | String.t]} + @spec merge(t, t | map | keyword, conflict_resolver | nil) :: + {:ok, t} | {:error, [atom | String.t()]} def merge(prefix_map1, prefix_map2, conflict_resolver) def merge(%__MODULE__{map: map1}, %__MODULE__{map: map2}, conflict_resolver) diff --git a/lib/rdf/quad.ex b/lib/rdf/quad.ex index 015bcfa..35af2d0 100644 --- a/lib/rdf/quad.ex +++ b/lib/rdf/quad.ex @@ -8,14 +8,14 @@ defmodule RDF.Quad do alias RDF.Statement - @type t :: {Statement.subject, Statement.predicate, Statement.object, Statement.graph_name} + @type t :: + {Statement.subject(), Statement.predicate(), Statement.object(), Statement.graph_name()} @type coercible_t :: - {Statement.coercible_subject, Statement.coercible_predicate, - Statement.coercible_object, Statement.coercible_graph_name} - - @type t_values :: {String.t, String.t, any, String.t} + {Statement.coercible_subject(), Statement.coercible_predicate(), + Statement.coercible_object(), Statement.coercible_graph_name()} + @type t_values :: {String.t(), String.t(), any, String.t()} @doc """ Creates a `RDF.Quad` with proper RDF values. @@ -32,10 +32,10 @@ defmodule RDF.Quad do {RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42), RDF.iri("http://example.com/Graph")} """ @spec new( - Statement.coercible_subject, - Statement.coercible_predicate, - Statement.coercible_object, - Statement.coercible_graph_name + Statement.coercible_subject(), + Statement.coercible_predicate(), + Statement.coercible_object(), + Statement.coercible_graph_name() ) :: t def new(subject, predicate, object, graph_context) do { @@ -64,7 +64,6 @@ defmodule RDF.Quad do def new({subject, predicate, object, graph_context}), do: new(subject, predicate, object, graph_context) - @doc """ Returns a tuple of native Elixir values from a `RDF.Quad` of RDF terms. @@ -94,15 +93,14 @@ defmodule RDF.Quad do {:S, :p, 42, ~I} """ - @spec values(t | any, Statement.term_mapping) :: t_values | nil + @spec values(t | any, Statement.term_mapping()) :: t_values | nil def values(quad, mapping \\ &Statement.default_term_mapping/1) def values({subject, predicate, object, graph_context}, mapping) do - with subject_value when not is_nil(subject_value) <- mapping.({:subject, subject}), + with subject_value when not is_nil(subject_value) <- mapping.({:subject, subject}), predicate_value when not is_nil(predicate_value) <- mapping.({:predicate, predicate}), - object_value when not is_nil(object_value) <- mapping.({:object, object}), - graph_context_value <- mapping.({:graph_name, graph_context}) - do + object_value when not is_nil(object_value) <- mapping.({:object, object}), + graph_context_value <- mapping.({:graph_name, graph_context}) do {subject_value, predicate_value, object_value, graph_context_value} else _ -> nil @@ -111,7 +109,6 @@ defmodule RDF.Quad do def values(_, _), do: nil - @doc """ Checks if the given tuple is a valid RDF quad. @@ -123,5 +120,4 @@ defmodule RDF.Quad do def valid?(tuple) def valid?({_, _, _, _} = quad), do: Statement.valid?(quad) def valid?(_), do: false - end diff --git a/lib/rdf/query.ex b/lib/rdf/query.ex index 270c79a..5b879f1 100644 --- a/lib/rdf/query.ex +++ b/lib/rdf/query.ex @@ -84,7 +84,7 @@ defmodule RDF.Query do As opposed to `execute/3` this returns the results directly or fails with an exception. """ - def execute!(query, graph, opts \\ []) do + def execute!(query, graph, opts \\ []) do case execute(query, graph, opts) do {:ok, results} -> results {:error, error} -> raise error @@ -152,7 +152,7 @@ defmodule RDF.Query do As opposed to `stream/3` this returns the stream directly or fails with an exception. """ - def stream!(query, graph, opts \\ []) do + def stream!(query, graph, opts \\ []) do case stream(query, graph, opts) do {:ok, results} -> results {:error, error} -> raise error diff --git a/lib/rdf/query/bgp.ex b/lib/rdf/query/bgp.ex index 1104d13..3a7a9ef 100644 --- a/lib/rdf/query/bgp.ex +++ b/lib/rdf/query/bgp.ex @@ -9,13 +9,12 @@ defmodule RDF.Query.BGP do @enforce_keys [:triple_patterns] defstruct [:triple_patterns] - - @type variable :: String.t + @type variable :: String.t() @type triple_pattern :: { - subject :: variable | RDF.Term.t, - predicate :: variable | RDF.Term.t, - object :: variable | RDF.Term.t - } + subject :: variable | RDF.Term.t(), + predicate :: variable | RDF.Term.t(), + object :: variable | RDF.Term.t() + } @type triple_patterns :: list(triple_pattern) @type t :: %__MODULE__{triple_patterns: triple_patterns} diff --git a/lib/rdf/query/bgp/blank_node_handler.ex b/lib/rdf/query/bgp/blank_node_handler.ex index a976463..2307dcb 100644 --- a/lib/rdf/query/bgp/blank_node_handler.ex +++ b/lib/rdf/query/bgp/blank_node_handler.ex @@ -4,7 +4,11 @@ defmodule RDF.Query.BGP.BlankNodeHandler do alias RDF.Query.BGP alias RDF.BlankNode - @default_remove_bnode_query_variables Application.get_env(:rdf, :default_remove_bnode_query_variables, true) + @default_remove_bnode_query_variables Application.get_env( + :rdf, + :default_remove_bnode_query_variables, + true + ) def preprocess(triple_patterns) do Enum.reduce(triple_patterns, {false, []}, fn @@ -14,22 +18,30 @@ defmodule RDF.Query.BGP.BlankNodeHandler do end) end - defp convert_blank_nodes({%BlankNode{} = s, %BlankNode{} = p, %BlankNode{} = o}), do: {true, {bnode_var(s), bnode_var(p), bnode_var(o)}} - defp convert_blank_nodes({s, %BlankNode{} = p, %BlankNode{} = o}), do: {true, {s, bnode_var(p), bnode_var(o)}} - defp convert_blank_nodes({%BlankNode{} = s, p, %BlankNode{} = o}), do: {true, {bnode_var(s), p, bnode_var(o)}} - defp convert_blank_nodes({%BlankNode{} = s, %BlankNode{} = p, o}), do: {true, {bnode_var(s), bnode_var(p), o}} + defp convert_blank_nodes({%BlankNode{} = s, %BlankNode{} = p, %BlankNode{} = o}), + do: {true, {bnode_var(s), bnode_var(p), bnode_var(o)}} + + defp convert_blank_nodes({s, %BlankNode{} = p, %BlankNode{} = o}), + do: {true, {s, bnode_var(p), bnode_var(o)}} + + defp convert_blank_nodes({%BlankNode{} = s, p, %BlankNode{} = o}), + do: {true, {bnode_var(s), p, bnode_var(o)}} + + defp convert_blank_nodes({%BlankNode{} = s, %BlankNode{} = p, o}), + do: {true, {bnode_var(s), bnode_var(p), o}} + defp convert_blank_nodes({%BlankNode{} = s, p, o}), do: {true, {bnode_var(s), p, o}} defp convert_blank_nodes({s, %BlankNode{} = p, o}), do: {true, {s, bnode_var(p), o}} defp convert_blank_nodes({s, p, %BlankNode{} = o}), do: {true, {s, p, bnode_var(o)}} - defp convert_blank_nodes(triple_pattern), do: {false, triple_pattern} + defp convert_blank_nodes(triple_pattern), do: {false, triple_pattern} defp bnode_var(bnode), do: bnode |> to_string() |> String.to_atom() def postprocess(solutions, bgp, has_blank_nodes, opts) do if has_blank_nodes and - Keyword.get(opts, :remove_bnode_query_variables, @default_remove_bnode_query_variables) do + Keyword.get(opts, :remove_bnode_query_variables, @default_remove_bnode_query_variables) do bnode_vars = bgp |> bnodes() |> Enum.map(&bnode_var/1) - Enum.map(solutions, &(Map.drop(&1, bnode_vars))) + Enum.map(solutions, &Map.drop(&1, bnode_vars)) else solutions end @@ -45,7 +57,7 @@ defmodule RDF.Query.BGP.BlankNodeHandler do defp bnodes({%BlankNode{} = s, %BlankNode{} = p, %BlankNode{} = o}), do: [s, p, o] defp bnodes({%BlankNode{} = s, %BlankNode{} = p, _}), do: [s, p] - defp bnodes({%BlankNode{} = s, _, %BlankNode{} = o}) , do: [s, o] + defp bnodes({%BlankNode{} = s, _, %BlankNode{} = o}), do: [s, o] defp bnodes({_, %BlankNode{} = p, %BlankNode{} = o}), do: [p, o] defp bnodes({%BlankNode{} = s, _, _}), do: [s] defp bnodes({_, %BlankNode{} = p, _}), do: [p] diff --git a/lib/rdf/query/bgp/matcher.ex b/lib/rdf/query/bgp/matcher.ex index 63040d3..90802bf 100644 --- a/lib/rdf/query/bgp/matcher.ex +++ b/lib/rdf/query/bgp/matcher.ex @@ -1,7 +1,7 @@ defmodule RDF.Query.BGP.Matcher do @moduledoc !""" - An interface for various BGP matching algorithm implementations. - """ + An interface for various BGP matching algorithm implementations. + """ alias RDF.Query.BGP alias RDF.Graph @@ -9,8 +9,7 @@ defmodule RDF.Query.BGP.Matcher do @type solution :: map @type solutions :: [solution] - @callback execute(BGP.t, Graph.t, opts :: Keyword.t) :: solutions - - @callback stream(BGP.t, Graph.t, opts :: Keyword.t) :: Enumerable.t() + @callback execute(BGP.t(), Graph.t(), opts :: Keyword.t()) :: solutions + @callback stream(BGP.t(), Graph.t(), opts :: Keyword.t()) :: Enumerable.t() end diff --git a/lib/rdf/query/bgp/query_planner.ex b/lib/rdf/query/bgp/query_planner.ex index 2f96ca4..058d21a 100644 --- a/lib/rdf/query/bgp/query_planner.ex +++ b/lib/rdf/query/bgp/query_planner.ex @@ -14,28 +14,30 @@ defmodule RDF.Query.BGP.QueryPlanner do query_plan( mark_solved_variables(rest, new_solved), new_solved, - [next_best | plan]) + [next_best | plan] + ) end defp triple_priority({v, v, v}), do: triple_priority({v, "p", "o"}) defp triple_priority({v, v, o}), do: triple_priority({v, "p", o}) defp triple_priority({v, p, v}), do: triple_priority({v, p, "o"}) defp triple_priority({s, v, v}), do: triple_priority({s, v, "o"}) + defp triple_priority({s, p, o}) do {sp, pp, op} = {value_priority(s), value_priority(p), value_priority(o)} - <<(sp + pp + op) :: size(2), sp :: size(1), pp :: size(1), op :: size(1)>> + <> end defp value_priority(value) when is_atom(value), do: 1 - defp value_priority(_), do: 0 + defp value_priority(_), do: 0 defp mark_solved_variables(triple_patterns, solved) do - Enum.map triple_patterns, fn {s, p, o} -> + Enum.map(triple_patterns, fn {s, p, o} -> { - (if is_atom(s) and s in solved, do: {s}, else: s), - (if is_atom(p) and p in solved, do: {p}, else: p), - (if is_atom(o) and o in solved, do: {o}, else: o) + if(is_atom(s) and s in solved, do: {s}, else: s), + if(is_atom(p) and p in solved, do: {p}, else: p), + if(is_atom(o) and o in solved, do: {o}, else: o) } - end + end) end end diff --git a/lib/rdf/query/bgp/simple.ex b/lib/rdf/query/bgp/simple.ex index 0cf9fad..8eb0166 100644 --- a/lib/rdf/query/bgp/simple.ex +++ b/lib/rdf/query/bgp/simple.ex @@ -10,11 +10,11 @@ defmodule RDF.Query.BGP.Simple do @impl RDF.Query.BGP.Matcher def execute(bgp, graph, opts \\ []) - def execute(%BGP{triple_patterns: []}, _, _), do: [%{}] # https://www.w3.org/TR/sparql11-query/#emptyGroupPattern + # https://www.w3.org/TR/sparql11-query/#emptyGroupPattern + def execute(%BGP{triple_patterns: []}, _, _), do: [%{}] def execute(%BGP{triple_patterns: triple_patterns}, %Graph{} = graph, opts) do - {bnode_state, preprocessed_triple_patterns} = - BlankNodeHandler.preprocess(triple_patterns) + {bnode_state, preprocessed_triple_patterns} = BlankNodeHandler.preprocess(triple_patterns) preprocessed_triple_patterns |> QueryPlanner.query_plan() @@ -28,7 +28,6 @@ defmodule RDF.Query.BGP.Simple do |> Stream.into([]) end - defp do_execute([triple_pattern | remaining], graph) do do_execute(remaining, graph, match(graph, triple_pattern)) end @@ -43,19 +42,18 @@ defmodule RDF.Query.BGP.Simple do do_execute(remaining, graph, match_with_solutions(graph, triple_pattern, solutions)) end - defp match_with_solutions(graph, {s, p, o} = triple_pattern, existing_solutions) when is_tuple(s) or is_tuple(p) or is_tuple(o) do triple_pattern |> apply_solutions(existing_solutions) - |> Enum.flat_map(&(merging_match(&1, graph))) + |> Enum.flat_map(&merging_match(&1, graph)) end defp match_with_solutions(graph, triple_pattern, existing_solutions) do graph |> match(triple_pattern) |> Enum.flat_map(fn solution -> - Enum.map(existing_solutions, &(Map.merge(solution, &1))) + Enum.map(existing_solutions, &Map.merge(solution, &1)) end) end @@ -63,14 +61,15 @@ defmodule RDF.Query.BGP.Simple do apply_solution = case triple_pattern do {{s}, {p}, {o}} -> fn solution -> {solution, {solution[s], solution[p], solution[o]}} end - {{s}, {p}, o } -> fn solution -> {solution, {solution[s], solution[p], o}} end - {{s}, p , {o}} -> fn solution -> {solution, {solution[s], p , solution[o]}} end - {{s}, p , o } -> fn solution -> {solution, {solution[s], p , o}} end - { s , {p}, {o}} -> fn solution -> {solution, {s , solution[p], solution[o]}} end - { s , {p} , o } -> fn solution -> {solution, {s , solution[p], o}} end - { s , p , {o}} -> fn solution -> {solution, {s , p , solution[o]}} end + {{s}, {p}, o} -> fn solution -> {solution, {solution[s], solution[p], o}} end + {{s}, p, {o}} -> fn solution -> {solution, {solution[s], p, solution[o]}} end + {{s}, p, o} -> fn solution -> {solution, {solution[s], p, o}} end + {s, {p}, {o}} -> fn solution -> {solution, {s, solution[p], solution[o]}} end + {s, {p}, o} -> fn solution -> {solution, {s, solution[p], o}} end + {s, p, {o}} -> fn solution -> {solution, {s, p, solution[o]}} end _ -> nil end + if apply_solution do Stream.map(solutions, apply_solution) else @@ -80,7 +79,9 @@ defmodule RDF.Query.BGP.Simple do defp merging_match({dependent_solution, triple_pattern}, graph) do case match(graph, triple_pattern) do - nil -> [] + nil -> + [] + solutions -> Enum.map(solutions, fn solution -> Map.merge(dependent_solution, solution) @@ -88,12 +89,13 @@ defmodule RDF.Query.BGP.Simple do end end - defp match(%Graph{descriptions: descriptions}, {subject_variable, _, _} = triple_pattern) when is_atom(subject_variable) do - Enum.reduce(descriptions, [], fn ({subject, description}, acc) -> + Enum.reduce(descriptions, [], fn {subject, description}, acc -> case match(description, solve_variables(subject_variable, subject, triple_pattern)) do - nil -> acc + nil -> + acc + solutions -> Enum.map(solutions, fn solution -> Map.put(solution, subject_variable, subject) @@ -104,14 +106,14 @@ defmodule RDF.Query.BGP.Simple do defp match(%Graph{} = graph, {subject, _, _} = triple_pattern) do case graph[subject] do - nil -> [] + nil -> [] description -> match(description, triple_pattern) end end defp match(%Description{predications: predications}, {_, variable, variable}) when is_atom(variable) do - Enum.reduce(predications, [], fn ({predicate, objects}, solutions) -> + Enum.reduce(predications, [], fn {predicate, objects}, solutions -> if Map.has_key?(objects, predicate) do [%{variable => predicate} | solutions] else @@ -122,17 +124,20 @@ defmodule RDF.Query.BGP.Simple do defp match(%Description{predications: predications}, {_, predicate_variable, object_variable}) when is_atom(predicate_variable) and is_atom(object_variable) do - Enum.reduce(predications, [], fn ({predicate, objects}, solutions) -> + Enum.reduce(predications, [], fn {predicate, objects}, solutions -> solutions ++ - Enum.map(objects, fn {object, _} -> - %{predicate_variable => predicate, object_variable => object} - end) + Enum.map(objects, fn {object, _} -> + %{predicate_variable => predicate, object_variable => object} + end) end) end - defp match(%Description{predications: predications}, - {_, predicate_variable, object}) when is_atom(predicate_variable) do - Enum.reduce(predications, [], fn ({predicate, objects}, solutions) -> + defp match( + %Description{predications: predications}, + {_, predicate_variable, object} + ) + when is_atom(predicate_variable) do + Enum.reduce(predications, [], fn {predicate, objects}, solutions -> if Map.has_key?(objects, object) do [%{predicate_variable => predicate} | solutions] else @@ -141,10 +146,14 @@ defmodule RDF.Query.BGP.Simple do end) end - defp match(%Description{predications: predications}, - {_, predicate, object_or_variable}) do + defp match( + %Description{predications: predications}, + {_, predicate, object_or_variable} + ) do case predications[predicate] do - nil -> [] + nil -> + [] + objects -> cond do # object_or_variable is a variable @@ -165,11 +174,11 @@ defmodule RDF.Query.BGP.Simple do end defp solve_variables(var, val, {var, var, var}), do: {val, val, val} - defp solve_variables(var, val, {s, var, var}), do: {s, val, val} - defp solve_variables(var, val, {var, p, var}), do: {val, p, val} - defp solve_variables(var, val, {var, var, o}), do: {val, val, o} - defp solve_variables(var, val, {var, p, o}), do: {val, p, o} - defp solve_variables(var, val, {s, var, o}), do: {s, val, o} - defp solve_variables(var, val, {s, p, var}), do: {s, p, val} - defp solve_variables(_, _, pattern), do: pattern + defp solve_variables(var, val, {s, var, var}), do: {s, val, val} + defp solve_variables(var, val, {var, p, var}), do: {val, p, val} + defp solve_variables(var, val, {var, var, o}), do: {val, val, o} + defp solve_variables(var, val, {var, p, o}), do: {val, p, o} + defp solve_variables(var, val, {s, var, o}), do: {s, val, o} + defp solve_variables(var, val, {s, p, var}), do: {s, p, val} + defp solve_variables(_, _, pattern), do: pattern end diff --git a/lib/rdf/query/bgp/stream.ex b/lib/rdf/query/bgp/stream.ex index 6b2c807..9eb0dca 100644 --- a/lib/rdf/query/bgp/stream.ex +++ b/lib/rdf/query/bgp/stream.ex @@ -7,15 +7,14 @@ defmodule RDF.Query.BGP.Stream do alias RDF.Query.BGP.{QueryPlanner, BlankNodeHandler} alias RDF.{Graph, Description} - @impl RDF.Query.BGP.Matcher def stream(bgp, graph, opts \\ []) - def stream(%BGP{triple_patterns: []}, _, _), do: to_stream([%{}]) # https://www.w3.org/TR/sparql11-query/#emptyGroupPattern + # https://www.w3.org/TR/sparql11-query/#emptyGroupPattern + def stream(%BGP{triple_patterns: []}, _, _), do: to_stream([%{}]) def stream(%BGP{triple_patterns: triple_patterns}, %Graph{} = graph, opts) do - {bnode_state, preprocessed_triple_patterns} = - BlankNodeHandler.preprocess(triple_patterns) + {bnode_state, preprocessed_triple_patterns} = BlankNodeHandler.preprocess(triple_patterns) preprocessed_triple_patterns |> QueryPlanner.query_plan() @@ -47,18 +46,17 @@ defmodule RDF.Query.BGP.Stream do do_execute(remaining, graph, match_with_solutions(graph, triple_pattern, solutions)) end - defp match_with_solutions(graph, {s, p, o} = triple_pattern, existing_solutions) when is_tuple(s) or is_tuple(p) or is_tuple(o) do triple_pattern |> apply_solutions(existing_solutions) - |> Stream.flat_map(&(merging_match(&1, graph))) + |> Stream.flat_map(&merging_match(&1, graph)) end defp match_with_solutions(graph, triple_pattern, existing_solutions) do if solutions = match(graph, triple_pattern) do Stream.flat_map(solutions, fn solution -> - Stream.map(existing_solutions, &(Map.merge(solution, &1))) + Stream.map(existing_solutions, &Map.merge(solution, &1)) end) end end @@ -67,14 +65,15 @@ defmodule RDF.Query.BGP.Stream do apply_solution = case triple_pattern do {{s}, {p}, {o}} -> fn solution -> {solution, {solution[s], solution[p], solution[o]}} end - {{s}, {p}, o } -> fn solution -> {solution, {solution[s], solution[p], o}} end - {{s}, p , {o}} -> fn solution -> {solution, {solution[s], p , solution[o]}} end - {{s}, p , o } -> fn solution -> {solution, {solution[s], p , o}} end - { s , {p}, {o}} -> fn solution -> {solution, {s , solution[p], solution[o]}} end - { s , {p} , o } -> fn solution -> {solution, {s , solution[p], o}} end - { s , p , {o}} -> fn solution -> {solution, {s , p , solution[o]}} end + {{s}, {p}, o} -> fn solution -> {solution, {solution[s], solution[p], o}} end + {{s}, p, {o}} -> fn solution -> {solution, {solution[s], p, solution[o]}} end + {{s}, p, o} -> fn solution -> {solution, {solution[s], p, o}} end + {s, {p}, {o}} -> fn solution -> {solution, {s, solution[p], solution[o]}} end + {s, {p}, o} -> fn solution -> {solution, {s, solution[p], o}} end + {s, p, {o}} -> fn solution -> {solution, {s, p, solution[o]}} end _ -> nil end + if apply_solution do Stream.map(solutions, apply_solution) else @@ -84,20 +83,23 @@ defmodule RDF.Query.BGP.Stream do defp merging_match({dependent_solution, triple_pattern}, graph) do case match(graph, triple_pattern) do - nil -> [] + nil -> + [] + solutions -> - Stream.map solutions, fn solution -> + Stream.map(solutions, fn solution -> Map.merge(dependent_solution, solution) - end + end) end end - defp match(%Graph{descriptions: descriptions}, {subject_variable, _, _} = triple_pattern) when is_atom(subject_variable) do Stream.flat_map(descriptions, fn {subject, description} -> case match(description, solve_variables(subject_variable, subject, triple_pattern)) do - nil -> [] + nil -> + [] + solutions -> Stream.map(solutions, fn solution -> Map.put(solution, subject_variable, subject) @@ -108,7 +110,7 @@ defmodule RDF.Query.BGP.Stream do defp match(%Graph{} = graph, {subject, _, _} = triple_pattern) do case graph[subject] do - nil -> nil + nil -> nil description -> match(description, triple_pattern) end end @@ -132,20 +134,26 @@ defmodule RDF.Query.BGP.Stream do end) end - defp match(%Description{predications: predications}, - {_, predicate_variable, object}) when is_atom(predicate_variable) do - matches = - Stream.filter(predications, fn {_, objects} -> Map.has_key?(objects, object) end) + defp match( + %Description{predications: predications}, + {_, predicate_variable, object} + ) + when is_atom(predicate_variable) do + matches = Stream.filter(predications, fn {_, objects} -> Map.has_key?(objects, object) end) unless Enum.empty?(matches) do Stream.map(matches, fn {predicate, _} -> %{predicate_variable => predicate} end) end end - defp match(%Description{predications: predications}, - {_, predicate, object_or_variable}) do + defp match( + %Description{predications: predications}, + {_, predicate, object_or_variable} + ) do case predications[predicate] do - nil -> nil + nil -> + nil + objects -> cond do # object_or_variable is a variable @@ -162,17 +170,17 @@ defmodule RDF.Query.BGP.Stream do true -> nil end - end + end end defp solve_variables(var, val, {var, var, var}), do: {val, val, val} - defp solve_variables(var, val, {s, var, var}), do: {s, val, val} - defp solve_variables(var, val, {var, p, var}), do: {val, p, val} - defp solve_variables(var, val, {var, var, o}), do: {val, val, o} - defp solve_variables(var, val, {var, p, o}), do: {val, p, o} - defp solve_variables(var, val, {s, var, o}), do: {s, val, o} - defp solve_variables(var, val, {s, p, var}), do: {s, p, val} - defp solve_variables(_, _, pattern), do: pattern + defp solve_variables(var, val, {s, var, var}), do: {s, val, val} + defp solve_variables(var, val, {var, p, var}), do: {val, p, val} + defp solve_variables(var, val, {var, var, o}), do: {val, val, o} + defp solve_variables(var, val, {var, p, o}), do: {val, p, o} + defp solve_variables(var, val, {s, var, o}), do: {s, val, o} + defp solve_variables(var, val, {s, p, var}), do: {s, p, val} + defp solve_variables(_, _, pattern), do: pattern defp to_stream(enum), do: Stream.into(enum, []) end diff --git a/lib/rdf/query/builder.ex b/lib/rdf/query/builder.ex index ee6c584..fba87b3 100644 --- a/lib/rdf/query/builder.ex +++ b/lib/rdf/query/builder.ex @@ -32,7 +32,7 @@ defmodule RDF.Query.Builder do end defp triple_patterns(triple_pattern) when is_tuple(triple_pattern), - do: triple_patterns([triple_pattern]) + do: triple_patterns([triple_pattern]) defp triple_pattern({subject, predicate, object}) when not is_list(predicate) and not is_list(object) do @@ -43,7 +43,8 @@ defmodule RDF.Query.Builder do end end - defp triple_pattern(combined_objects_triple_pattern) when is_tuple(combined_objects_triple_pattern) do + defp triple_pattern(combined_objects_triple_pattern) + when is_tuple(combined_objects_triple_pattern) do [subject | rest] = Tuple.to_list(combined_objects_triple_pattern) case rest do @@ -53,9 +54,10 @@ defmodule RDF.Query.Builder do |> Enum.map(fn object -> {subject, predicate, object} end) |> triple_patterns() else - {:error, %RDF.Query.InvalidError{ - message: "Invalid use of predicate-object pair brackets"} - } + {:error, + %RDF.Query.InvalidError{ + message: "Invalid use of predicate-object pair brackets" + }} end predicate_object_pairs -> @@ -66,9 +68,10 @@ defmodule RDF.Query.Builder do end) |> triple_patterns() else - {:error, %RDF.Query.InvalidError{ - message: "Invalid use of predicate-object pair brackets"} - } + {:error, + %RDF.Query.InvalidError{ + message: "Invalid use of predicate-object pair brackets" + }} end end end @@ -79,9 +82,10 @@ defmodule RDF.Query.Builder do if value do {:ok, value} else - {:error, %RDF.Query.InvalidError{ - message: "Invalid subject term in BGP triple pattern: #{inspect subject}"} - } + {:error, + %RDF.Query.InvalidError{ + message: "Invalid subject term in BGP triple pattern: #{inspect(subject)}" + }} end end @@ -91,9 +95,10 @@ defmodule RDF.Query.Builder do if value do {:ok, value} else - {:error, %RDF.Query.InvalidError{ - message: "Invalid predicate term in BGP triple pattern: #{inspect predicate}"} - } + {:error, + %RDF.Query.InvalidError{ + message: "Invalid predicate term in BGP triple pattern: #{inspect(predicate)}" + }} end end @@ -103,9 +108,10 @@ defmodule RDF.Query.Builder do if value do {:ok, value} else - {:error, %RDF.Query.InvalidError{ - message: "Invalid object term in BGP triple pattern: #{inspect object}"} - } + {:error, + %RDF.Query.InvalidError{ + message: "Invalid object term in BGP triple pattern: #{inspect(object)}" + }} end end @@ -146,13 +152,13 @@ defmodule RDF.Query.Builder do defp literal(%Literal{} = literal), do: literal defp literal(value), do: Literal.coerce(value) - def path(query, opts \\ []) def path(query, _) when is_list(query) and length(query) < 3 do - {:error, %RDF.Query.InvalidError{ - message: "Invalid path expression: must have at least three elements"} - } + {:error, + %RDF.Query.InvalidError{ + message: "Invalid path expression: must have at least three elements" + }} end def path([subject | rest], opts) do @@ -175,6 +181,12 @@ defmodule RDF.Query.Builder do defp path_pattern(subject, [predicate | rest], triple_patterns, count, with_elements) do object = if with_elements, do: :"el#{count}?", else: RDF.bnode(count) - path_pattern(object, rest, [{subject, predicate, object} | triple_patterns], count + 1, with_elements) + path_pattern( + object, + rest, + [{subject, predicate, object} | triple_patterns], + count + 1, + with_elements + ) end end diff --git a/lib/rdf/serialization/decoder.ex b/lib/rdf/serialization/decoder.ex index 8bacd8b..6fbb8fb 100644 --- a/lib/rdf/serialization/decoder.ex +++ b/lib/rdf/serialization/decoder.ex @@ -11,7 +11,7 @@ defmodule RDF.Serialization.Decoder do It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or dataset, or `{:error, reason}` if an error occurs. """ - @callback decode(String.t, keyword | map) :: {:ok, Graph.t | Dataset.t} | {:error, any} + @callback decode(String.t(), keyword | map) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} @doc """ Decodes a serialized `RDF.Graph` or `RDF.Dataset` from the given string. @@ -21,24 +21,22 @@ defmodule RDF.Serialization.Decoder do Note: The `__using__` macro automatically provides an overridable default implementation based on the non-bang `decode` function. """ - @callback decode!(String.t, keyword | map) :: RDF.Graph.t | RDF.Dataset.t - + @callback decode!(String.t(), keyword | map) :: RDF.Graph.t() | RDF.Dataset.t() defmacro __using__(_) do quote bind_quoted: [], unquote: true do @behaviour unquote(__MODULE__) @impl unquote(__MODULE__) - @spec decode!(String.t, keyword | map) :: RDF.Graph.t | RDF.Dataset.t + @spec decode!(String.t(), keyword | map) :: RDF.Graph.t() | RDF.Dataset.t() def decode!(content, opts \\ []) do case decode(content, opts) do - {:ok, data} -> data + {:ok, data} -> data {:error, reason} -> raise reason end end - defoverridable [decode!: 2] + defoverridable decode!: 2 end end - end diff --git a/lib/rdf/serialization/encoder.ex b/lib/rdf/serialization/encoder.ex index cff59df..27f60df 100644 --- a/lib/rdf/serialization/encoder.ex +++ b/lib/rdf/serialization/encoder.ex @@ -12,7 +12,7 @@ defmodule RDF.Serialization.Encoder do It returns an `{:ok, string}` tuple, with `string` being the serialized `RDF.Graph` or `RDF.Dataset`, or `{:error, reason}` if an error occurs. """ - @callback encode(Graph.t | Dataset.t, keyword | map) :: {:ok, String.t} | {:error, any} + @callback encode(Graph.t() | Dataset.t(), keyword | map) :: {:ok, String.t()} | {:error, any} @doc """ Encodes a `RDF.Graph` or `RDF.Dataset`. @@ -22,8 +22,7 @@ defmodule RDF.Serialization.Encoder do Note: The `__using__` macro automatically provides an overridable default implementation based on the non-bang `encode` function. """ - @callback encode!(Graph.t | Dataset.t, keyword | map) :: String.t - + @callback encode!(Graph.t() | Dataset.t(), keyword | map) :: String.t() defmacro __using__(_) do quote bind_quoted: [], unquote: true do @@ -31,17 +30,16 @@ defmodule RDF.Serialization.Encoder do @impl unquote(__MODULE__) @dialyzer {:nowarn_function, encode!: 2} - @spec encode!(Graph.t | Dataset.t, keyword) :: String.t + @spec encode!(Graph.t() | Dataset.t(), keyword) :: String.t() def encode!(data, opts \\ []) do case encode(data, opts) do - {:ok, data} -> data + {:ok, data} -> data {:error, reason} -> raise reason end end - defoverridable [encode!: 1] - defoverridable [encode!: 2] + defoverridable encode!: 1 + defoverridable encode!: 2 end end - end diff --git a/lib/rdf/serialization/format.ex b/lib/rdf/serialization/format.ex index 938e9b4..d02e6f5 100644 --- a/lib/rdf/serialization/format.ex +++ b/lib/rdf/serialization/format.ex @@ -33,7 +33,7 @@ defmodule RDF.Serialization.Format do @doc """ An IRI of the serialization format. """ - @callback id :: RDF.IRI.t + @callback id :: RDF.IRI.t() @doc """ An name atom of the serialization format. @@ -43,12 +43,12 @@ defmodule RDF.Serialization.Format do @doc """ The usual file extension for the serialization format. """ - @callback extension :: String.t + @callback extension :: String.t() @doc """ The MIME type of the serialization format. """ - @callback media_type :: String.t + @callback media_type :: String.t() @doc """ A map with the supported options of the `Encoder` and `Decoder` for the serialization format. @@ -65,7 +65,6 @@ defmodule RDF.Serialization.Format do """ @callback encoder :: module - defmacro __using__(_) do quote bind_quoted: [], unquote: true do @behaviour unquote(__MODULE__) @@ -82,31 +81,37 @@ defmodule RDF.Serialization.Format do @impl unquote(__MODULE__) def options, do: %{} - defoverridable [decoder: 0, encoder: 0, options: 0] + defoverridable decoder: 0, encoder: 0, options: 0 - @spec read_string(String.t, keyword) :: {:ok, Graph.t | Dataset.t} | {:error, any} + @spec read_string(String.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} def read_string(content, opts \\ []), do: RDF.Serialization.Reader.read_string(decoder(), content, opts) - @spec read_string!(String.t, keyword) :: Graph.t | Dataset.t + + @spec read_string!(String.t(), keyword) :: Graph.t() | Dataset.t() def read_string!(content, opts \\ []), do: RDF.Serialization.Reader.read_string!(decoder(), content, opts) - @spec read_file(Path.t, keyword) :: {:ok, Graph.t | Dataset.t} | {:error, any} + + @spec read_file(Path.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} def read_file(file, opts \\ []), do: RDF.Serialization.Reader.read_file(decoder(), file, opts) - @spec read_file!(Path.t, keyword) :: Graph.t | Dataset.t + + @spec read_file!(Path.t(), keyword) :: Graph.t() | Dataset.t() def read_file!(file, opts \\ []), do: RDF.Serialization.Reader.read_file!(decoder(), file, opts) - @spec write_string(Graph.t | Dataset.t, keyword) :: {:ok, String.t} | {:error, any} + @spec write_string(Graph.t() | Dataset.t(), keyword) :: {:ok, String.t()} | {:error, any} def write_string(data, opts \\ []), do: RDF.Serialization.Writer.write_string(encoder(), data, opts) - @spec write_string!(Graph.t | Dataset.t, keyword) :: String.t + + @spec write_string!(Graph.t() | Dataset.t(), keyword) :: String.t() def write_string!(data, opts \\ []), do: RDF.Serialization.Writer.write_string!(encoder(), data, opts) - @spec write_file(Graph.t | Dataset.t, Path.t, keyword) :: :ok | {:error, any} + + @spec write_file(Graph.t() | Dataset.t(), Path.t(), keyword) :: :ok | {:error, any} def write_file(data, path, opts \\ []), do: RDF.Serialization.Writer.write_file(encoder(), data, path, opts) - @spec write_file!(Graph.t | Dataset.t, Path.t, keyword) :: :ok + + @spec write_file!(Graph.t() | Dataset.t(), Path.t(), keyword) :: :ok def write_file!(data, path, opts \\ []), do: RDF.Serialization.Writer.write_file!(encoder(), data, path, opts) @@ -117,26 +122,28 @@ defmodule RDF.Serialization.Format do defmacro __before_compile__(_env) do quote do if !Module.defines?(__MODULE__, {:id, 0}) && - Module.get_attribute(__MODULE__, :id) do + Module.get_attribute(__MODULE__, :id) do @impl unquote(__MODULE__) def id, do: @id end + if !Module.defines?(__MODULE__, {:name, 0}) && - Module.get_attribute(__MODULE__, :name) do + Module.get_attribute(__MODULE__, :name) do @impl unquote(__MODULE__) def name, do: @name end + if !Module.defines?(__MODULE__, {:extension, 0}) && - Module.get_attribute(__MODULE__, :extension) do + Module.get_attribute(__MODULE__, :extension) do @impl unquote(__MODULE__) def extension, do: @extension end + if !Module.defines?(__MODULE__, {:media_type, 0}) && - Module.get_attribute(__MODULE__, :media_type) do + Module.get_attribute(__MODULE__, :media_type) do @impl unquote(__MODULE__) def media_type, do: @media_type end end end - end diff --git a/lib/rdf/serialization/parse_helper.ex b/lib/rdf/serialization/parse_helper.ex index 665b386..e878fbf 100644 --- a/lib/rdf/serialization/parse_helper.ex +++ b/lib/rdf/serialization/parse_helper.ex @@ -6,7 +6,6 @@ defmodule RDF.Serialization.ParseHelper do @rdf_type RDF.Utils.Bootstrapping.rdf_iri("type") def rdf_type, do: @rdf_type - def to_iri_string({:iriref, _line, value}), do: value |> iri_unescape def to_iri({:iriref, line, value}) do @@ -29,65 +28,69 @@ defmodule RDF.Serialization.ParseHelper do end end - def to_bnode({:blank_node_label, _line, value}), do: RDF.bnode(value) - def to_bnode({:anon, _line}), do: RDF.bnode + def to_bnode({:anon, _line}), do: RDF.bnode() def to_literal({:string_literal_quote, _line, value}), - do: value |> string_unescape |> RDF.literal + do: value |> string_unescape |> RDF.literal() + def to_literal({:integer, _line, value}), do: RDF.literal(value) def to_literal({:decimal, _line, value}), do: RDF.literal(value) - def to_literal({:double, _line, value}), do: RDF.literal(value) - def to_literal({:boolean, _line, value}), do: RDF.literal(value) + def to_literal({:double, _line, value}), do: RDF.literal(value) + def to_literal({:boolean, _line, value}), do: RDF.literal(value) + def to_literal({:string_literal_quote, _line, value}, {:language, language}), do: value |> string_unescape |> RDF.literal(language: language) + def to_literal({:string_literal_quote, _line, value}, {:datatype, %IRI{} = type}), do: value |> string_unescape |> RDF.literal(datatype: type) + def to_literal(string_literal_quote_ast, type), do: {string_literal_quote_ast, type} - def integer(value), do: RDF.XSD.Integer.new(List.to_string(value)) - def decimal(value), do: RDF.XSD.Decimal.new(List.to_string(value)) - def double(value), do: RDF.XSD.Double.new(List.to_string(value)) - def boolean('true'), do: true + def integer(value), do: RDF.XSD.Integer.new(List.to_string(value)) + def decimal(value), do: RDF.XSD.Decimal.new(List.to_string(value)) + def double(value), do: RDF.XSD.Double.new(List.to_string(value)) + def boolean('true'), do: true def boolean('false'), do: false def to_langtag({:langtag, _line, value}), do: value def to_langtag({:"@prefix", 1}), do: "prefix" - def to_langtag({:"@base", 1}), do: "base" + def to_langtag({:"@base", 1}), do: "base" - def bnode_str('_:' ++ value), do: List.to_string(value) - def langtag_str('@' ++ value), do: List.to_string(value) - def quoted_content_str(value), do: value |> List.to_string |> String.slice(1..-2) - def long_quoted_content_str(value), do: value |> List.to_string |> String.slice(3..-4) + def bnode_str('_:' ++ value), do: List.to_string(value) + def langtag_str('@' ++ value), do: List.to_string(value) + def quoted_content_str(value), do: value |> List.to_string() |> String.slice(1..-2) + def long_quoted_content_str(value), do: value |> List.to_string() |> String.slice(3..-4) - def prefix_ns(value), do: value |> List.to_string |> String.slice(0..-2) - def prefix_ln(value), do: value |> List.to_string |> String.split(":", parts: 2) |> List.to_tuple + def prefix_ns(value), do: value |> List.to_string() |> String.slice(0..-2) + def prefix_ln(value), + do: value |> List.to_string() |> String.split(":", parts: 2) |> List.to_tuple() def string_unescape(string), do: string |> unescape_8digit_unicode_seq |> Macro.unescape_string(&string_unescape_map(&1)) + def iri_unescape(string), do: string |> unescape_8digit_unicode_seq |> Macro.unescape_string(&iri_unescape_map(&1)) - defp string_unescape_map(?b), do: ?\b - defp string_unescape_map(?f), do: ?\f - defp string_unescape_map(?n), do: ?\n - defp string_unescape_map(?r), do: ?\r - defp string_unescape_map(?t), do: ?\t - defp string_unescape_map(?u), do: true - defp string_unescape_map(:unicode), do: true - defp string_unescape_map(e), do: e + defp string_unescape_map(?b), do: ?\b + defp string_unescape_map(?f), do: ?\f + defp string_unescape_map(?n), do: ?\n + defp string_unescape_map(?r), do: ?\r + defp string_unescape_map(?t), do: ?\t + defp string_unescape_map(?u), do: true + defp string_unescape_map(:unicode), do: true + defp string_unescape_map(e), do: e - defp iri_unescape_map(?u), do: true - defp iri_unescape_map(:unicode), do: true - defp iri_unescape_map(e), do: e + defp iri_unescape_map(?u), do: true + defp iri_unescape_map(:unicode), do: true + defp iri_unescape_map(e), do: e def unescape_8digit_unicode_seq(string) do String.replace(string, ~r/\\U([0-9]|[A-F]|[a-f]){2}(([0-9]|[A-F]|[a-f]){6})/, "\\u{\\2}") end - def error_description(error_descriptor) when is_list(error_descriptor) do error_descriptor |> Stream.map(&to_string/1) diff --git a/lib/rdf/serialization/reader.ex b/lib/rdf/serialization/reader.ex index acc550f..dfee9ef 100644 --- a/lib/rdf/serialization/reader.ex +++ b/lib/rdf/serialization/reader.ex @@ -15,7 +15,7 @@ defmodule RDF.Serialization.Reader do It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or dataset, or `{:error, reason}` if an error occurs. """ - @spec read_string(module, String.t, keyword) :: {:ok, Graph.t | Dataset.t} | {:error, any} + @spec read_string(module, String.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} def read_string(decoder, content, opts \\ []) do decoder.decode(content, opts) end @@ -25,7 +25,7 @@ defmodule RDF.Serialization.Reader do As opposed to `read_string`, it raises an exception if an error occurs. """ - @spec read_string!(module, String.t, keyword) :: Graph.t | Dataset.t + @spec read_string!(module, String.t(), keyword) :: Graph.t() | Dataset.t() def read_string!(decoder, content, opts \\ []) do decoder.decode!(content, opts) end @@ -36,10 +36,10 @@ defmodule RDF.Serialization.Reader do It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or dataset, or `{:error, reason}` if an error occurs. """ - @spec read_file(module, Path.t, keyword) :: {:ok, Graph.t | Dataset.t} | {:error, any} + @spec read_file(module, Path.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} def read_file(decoder, file, opts \\ []) do case File.read(file) do - {:ok, content} -> read_string(decoder, content, opts) + {:ok, content} -> read_string(decoder, content, opts) {:error, reason} -> {:error, reason} end end @@ -49,7 +49,7 @@ defmodule RDF.Serialization.Reader do As opposed to `read_file`, it raises an exception if an error occurs. """ - @spec read_file!(module, Path.t, keyword) :: Graph.t | Dataset.t + @spec read_file!(module, Path.t(), keyword) :: Graph.t() | Dataset.t() def read_file!(decoder, file, opts \\ []) do with content = File.read!(file) do read_string!(decoder, content, opts) diff --git a/lib/rdf/serialization/serialization.ex b/lib/rdf/serialization/serialization.ex index e8d289a..c79436d 100644 --- a/lib/rdf/serialization/serialization.ex +++ b/lib/rdf/serialization/serialization.ex @@ -11,7 +11,7 @@ defmodule RDF.Serialization do RDF.Turtle, JSON.LD, RDF.NTriples, - RDF.NQuads, + RDF.NQuads ] @doc """ @@ -43,7 +43,7 @@ defmodule RDF.Serialization do """ @spec available_formats :: [format] def available_formats do - Enum.filter @formats, &Code.ensure_loaded?/1 + Enum.filter(@formats, &Code.ensure_loaded?/1) end @doc """ @@ -58,12 +58,12 @@ defmodule RDF.Serialization do iex> RDF.Serialization.format(:jsonld) nil # unless json_ld is defined as a dependency of the application """ - @spec format(String.t | atom) :: format | nil + @spec format(String.t() | atom) :: format | nil def format(name) def format(name) when is_binary(name) do name - |> String.to_existing_atom + |> String.to_existing_atom() |> format() rescue ArgumentError -> nil @@ -73,7 +73,6 @@ defmodule RDF.Serialization do format_where(fn format -> format.name == name end) end - @doc """ Returns the `RDF.Serialization.Format` with the given media type, if available. @@ -84,7 +83,7 @@ defmodule RDF.Serialization do iex> RDF.Serialization.format_by_media_type("application/ld+json") nil # unless json_ld is defined as a dependency of the application """ - @spec format_by_media_type(String.t) :: format | nil + @spec format_by_media_type(String.t()) :: format | nil def format_by_media_type(media_type) do format_where(fn format -> format.media_type == media_type end) end @@ -101,7 +100,7 @@ defmodule RDF.Serialization do iex> RDF.Serialization.format_by_extension("jsonld") nil # unless json_ld is defined as a dependency of the application """ - @spec format_by_extension(String.t) :: format | nil + @spec format_by_extension(String.t()) :: format | nil def format_by_extension(extension) def format_by_extension("." <> extension), do: format_by_extension(extension) @@ -116,7 +115,6 @@ defmodule RDF.Serialization do |> Enum.find(fun) end - @doc """ Reads and decodes a serialized graph or dataset from a string. @@ -126,7 +124,7 @@ defmodule RDF.Serialization do It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or dataset, or `{:error, reason}` if an error occurs. """ - @spec read_string(String.t, keyword) :: {:ok, Graph.t | Dataset.t} | {:error, any} + @spec read_string(String.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} def read_string(content, opts) do with {:ok, format} <- string_format(opts) do format.read_string(content, opts) @@ -141,7 +139,7 @@ defmodule RDF.Serialization do As opposed to `read_string`, it raises an exception if an error occurs. """ - @spec read_string!(String.t, keyword) :: Graph.t | Dataset.t + @spec read_string!(String.t(), keyword) :: Graph.t() | Dataset.t() def read_string!(content, opts) do with {:ok, format} <- string_format(opts) do format.read_string!(content, opts) @@ -160,7 +158,7 @@ defmodule RDF.Serialization do It returns an `{:ok, data}` tuple, with `data` being the deserialized graph or dataset, or `{:error, reason}` if an error occurs. """ - @spec read_file(Path.t, keyword) :: {:ok, Graph.t | Dataset.t} | {:error, any} + @spec read_file(Path.t(), keyword) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} def read_file(file, opts \\ []) do with {:ok, format} <- file_format(file, opts) do format.read_file(file, opts) @@ -176,7 +174,7 @@ defmodule RDF.Serialization do As opposed to `read_file`, it raises an exception if an error occurs. """ - @spec read_file!(Path.t, keyword) :: Graph.t | Dataset.t + @spec read_file!(Path.t(), keyword) :: Graph.t() | Dataset.t() def read_file!(file, opts \\ []) do with {:ok, format} <- file_format(file, opts) do format.read_file!(file, opts) @@ -194,7 +192,7 @@ defmodule RDF.Serialization do It returns an `{:ok, string}` tuple, with `string` being the serialized graph or dataset, or `{:error, reason}` if an error occurs. """ - @spec write_string(Graph.t | Dataset.t, keyword) :: {:ok, String.t} | {:error, any} + @spec write_string(Graph.t() | Dataset.t(), keyword) :: {:ok, String.t()} | {:error, any} def write_string(data, opts) do with {:ok, format} <- string_format(opts) do format.write_string(data, opts) @@ -209,7 +207,7 @@ defmodule RDF.Serialization do As opposed to `write_string`, it raises an exception if an error occurs. """ - @spec write_string!(Graph.t | Dataset.t, keyword) :: String.t + @spec write_string!(Graph.t() | Dataset.t(), keyword) :: String.t() def write_string!(data, opts) do with {:ok, format} <- string_format(opts) do format.write_string!(data, opts) @@ -234,7 +232,7 @@ defmodule RDF.Serialization do It returns `:ok` if successful or `{:error, reason}` if an error occurs. """ - @spec write_file(Graph.t | Dataset.t, Path.t, keyword) :: :ok | {:error, any} + @spec write_file(Graph.t() | Dataset.t(), Path.t(), keyword) :: :ok | {:error, any} def write_file(data, path, opts \\ []) do with {:ok, format} <- file_format(path, opts) do format.write_file(data, path, opts) @@ -252,7 +250,7 @@ defmodule RDF.Serialization do As opposed to `write_file`, it raises an exception if an error occurs. """ - @spec write_file!(Graph.t | Dataset.t, Path.t, keyword) :: :ok + @spec write_file!(Graph.t() | Dataset.t(), Path.t(), keyword) :: :ok def write_file!(data, path, opts \\ []) do with {:ok, format} <- file_format(path, opts) do format.write_file!(data, path, opts) @@ -261,12 +259,10 @@ defmodule RDF.Serialization do end end - defp string_format(opts) do if format = - (opts |> Keyword.get(:format) |> format()) || - (opts |> Keyword.get(:media_type) |> format_by_media_type()) - do + opts |> Keyword.get(:format) |> format() || + opts |> Keyword.get(:media_type) |> format_by_media_type() do {:ok, format} else {:error, "unable to detect serialization format"} @@ -276,7 +272,7 @@ defmodule RDF.Serialization do defp file_format(filename, opts) do case string_format(opts) do {:ok, format} -> {:ok, format} - _ -> format_by_file_name(filename) + _ -> format_by_file_name(filename) end end @@ -287,5 +283,4 @@ defmodule RDF.Serialization do {:error, "unable to detect serialization format"} end end - end diff --git a/lib/rdf/serialization/writer.ex b/lib/rdf/serialization/writer.ex index 52153c9..d19fc24 100644 --- a/lib/rdf/serialization/writer.ex +++ b/lib/rdf/serialization/writer.ex @@ -15,7 +15,8 @@ defmodule RDF.Serialization.Writer do It returns an `{:ok, string}` tuple, with `string` being the serialized graph or dataset, or `{:error, reason}` if an error occurs. """ - @spec write_string(module, Graph.t | Dataset.t, keyword) :: {:ok, String.t} | {:error, any} + @spec write_string(module, Graph.t() | Dataset.t(), keyword) :: + {:ok, String.t()} | {:error, any} def write_string(encoder, data, opts \\ []) do encoder.encode(data, opts) end @@ -25,7 +26,7 @@ defmodule RDF.Serialization.Writer do As opposed to `write_string`, it raises an exception if an error occurs. """ - @spec write_string!(module, Graph.t | Dataset.t, keyword) :: String.t + @spec write_string!(module, Graph.t() | Dataset.t(), keyword) :: String.t() def write_string!(encoder, data, opts \\ []) do encoder.encode!(data, opts) end @@ -42,7 +43,7 @@ defmodule RDF.Serialization.Writer do It returns `:ok` if successful or `{:error, reason}` if an error occurs. """ - @spec write_file(module, Graph.t | Dataset.t, Path.t, keyword) :: :ok | {:error, any} + @spec write_file(module, Graph.t() | Dataset.t(), Path.t(), keyword) :: :ok | {:error, any} def write_file(encoder, data, path, opts \\ []) do with {:ok, encoded_string} <- write_string(encoder, data, opts) do File.write(path, encoded_string, file_mode(encoder, opts)) @@ -56,7 +57,7 @@ defmodule RDF.Serialization.Writer do As opposed to `write_file`, it raises an exception if an error occurs. """ - @spec write_file!(module, Graph.t | Dataset.t, Path.t, keyword) :: :ok + @spec write_file!(module, Graph.t() | Dataset.t(), Path.t(), keyword) :: :ok def write_file!(encoder, data, path, opts \\ []) do with encoded_string = write_string!(encoder, data, opts) do File.write!(path, encoded_string, file_mode(encoder, opts)) diff --git a/lib/rdf/serializations/nquads.ex b/lib/rdf/serializations/nquads.ex index d76e702..2fae8d8 100644 --- a/lib/rdf/serializations/nquads.ex +++ b/lib/rdf/serializations/nquads.ex @@ -17,9 +17,8 @@ defmodule RDF.NQuads do import RDF.Sigils - @id ~I - @name :nquads - @extension "nq" + @id ~I + @name :nquads + @extension "nq" @media_type "application/n-quads" - end diff --git a/lib/rdf/serializations/nquads_decoder.ex b/lib/rdf/serializations/nquads_decoder.ex index 3dc707d..b63013f 100644 --- a/lib/rdf/serializations/nquads_decoder.ex +++ b/lib/rdf/serializations/nquads_decoder.ex @@ -8,26 +8,29 @@ defmodule RDF.NQuads.Decoder do alias RDF.{Dataset, Graph} @impl RDF.Serialization.Decoder - @spec decode(String.t, keyword | map) :: {:ok, Graph.t | Dataset.t} | {:error, any} + @spec decode(String.t(), keyword | map) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} def decode(content, _opts \\ []) do with {:ok, tokens, _} <- tokenize(content), - {:ok, ast} <- parse(tokens) do + {:ok, ast} <- parse(tokens) do {:ok, build_dataset(ast)} else {:error, {error_line, :ntriples_lexer, error_descriptor}, _error_line_again} -> - {:error, "N-Quad scanner error on line #{error_line}: #{error_description error_descriptor}"} + {:error, + "N-Quad scanner error on line #{error_line}: #{error_description(error_descriptor)}"} + {:error, {error_line, :nquads_parser, error_descriptor}} -> - {:error, "N-Quad parser error on line #{error_line}: #{error_description error_descriptor}"} + {:error, + "N-Quad parser error on line #{error_line}: #{error_description(error_descriptor)}"} end end - defp tokenize(content), do: content |> to_charlist |> :ntriples_lexer.string + defp tokenize(content), do: content |> to_charlist |> :ntriples_lexer.string() - defp parse(tokens), do: tokens |> :nquads_parser.parse + defp parse(tokens), do: tokens |> :nquads_parser.parse() defp build_dataset(ast) do - Enum.reduce ast, RDF.Dataset.new, fn(quad, dataset) -> + Enum.reduce(ast, RDF.Dataset.new(), fn quad, dataset -> RDF.Dataset.add(dataset, quad) - end + end) end end diff --git a/lib/rdf/serializations/nquads_encoder.ex b/lib/rdf/serializations/nquads_encoder.ex index 20600e0..4d51c5a 100644 --- a/lib/rdf/serializations/nquads_encoder.ex +++ b/lib/rdf/serializations/nquads_encoder.ex @@ -6,31 +6,32 @@ defmodule RDF.NQuads.Encoder do alias RDF.{Dataset, Graph, Quad, Statement, Triple} @impl RDF.Serialization.Encoder - @callback encode(Graph.t | Dataset.t, keyword | map) :: {:ok, String.t} | {:error, any} + @callback encode(Graph.t() | Dataset.t(), keyword | map) :: {:ok, String.t()} | {:error, any} def encode(data, _opts \\ []) do result = data - |> Enum.reduce([], fn (statement, result) -> [statement(statement) | result] end) - |> Enum.reverse + |> Enum.reduce([], fn statement, result -> [statement(statement) | result] end) + |> Enum.reverse() |> Enum.join("\n") - {:ok, (if result == "", do: result, else: "#{result}\n")} + + {:ok, if(result == "", do: result, else: "#{result}\n")} end - @spec statement({Statement.subject, Statement.predicate, Statement.object, nil}) :: String.t + @spec statement({Statement.subject(), Statement.predicate(), Statement.object(), nil}) :: + String.t() def statement({subject, predicate, object, nil}) do statement({subject, predicate, object}) end - @spec statement(Quad.t) :: String.t + @spec statement(Quad.t()) :: String.t() def statement({subject, predicate, object, graph}) do "#{term(subject)} #{term(predicate)} #{term(object)} #{term(graph)} ." end - @spec statement(Triple.t) :: String.t + @spec statement(Triple.t()) :: String.t() def statement({subject, predicate, object}) do "#{term(subject)} #{term(predicate)} #{term(object)} ." end defdelegate term(value), to: RDF.NTriples.Encoder - end diff --git a/lib/rdf/serializations/ntriples.ex b/lib/rdf/serializations/ntriples.ex index 947d9d2..7605d05 100644 --- a/lib/rdf/serializations/ntriples.ex +++ b/lib/rdf/serializations/ntriples.ex @@ -19,9 +19,8 @@ defmodule RDF.NTriples do import RDF.Sigils - @id ~I - @name :ntriples - @extension "nt" + @id ~I + @name :ntriples + @extension "nt" @media_type "application/n-triples" - end diff --git a/lib/rdf/serializations/ntriples_decoder.ex b/lib/rdf/serializations/ntriples_decoder.ex index 95ccfc7..f8bb497 100644 --- a/lib/rdf/serializations/ntriples_decoder.ex +++ b/lib/rdf/serializations/ntriples_decoder.ex @@ -8,26 +8,29 @@ defmodule RDF.NTriples.Decoder do alias RDF.{Dataset, Graph} @impl RDF.Serialization.Decoder - @spec decode(String.t, keyword | map) :: {:ok, Graph.t | Dataset.t} | {:error, any} + @spec decode(String.t(), keyword | map) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} def decode(content, _opts \\ []) do with {:ok, tokens, _} <- tokenize(content), - {:ok, ast} <- parse(tokens) do + {:ok, ast} <- parse(tokens) do {:ok, build_graph(ast)} else {:error, {error_line, :ntriples_lexer, error_descriptor}, _error_line_again} -> - {:error, "N-Triple scanner error on line #{error_line}: #{error_description error_descriptor}"} + {:error, + "N-Triple scanner error on line #{error_line}: #{error_description(error_descriptor)}"} + {:error, {error_line, :ntriples_parser, error_descriptor}} -> - {:error, "N-Triple parser error on line #{error_line}: #{error_description error_descriptor}"} + {:error, + "N-Triple parser error on line #{error_line}: #{error_description(error_descriptor)}"} end end - defp tokenize(content), do: content |> to_charlist |> :ntriples_lexer.string + defp tokenize(content), do: content |> to_charlist |> :ntriples_lexer.string() - defp parse(tokens), do: tokens |> :ntriples_parser.parse + defp parse(tokens), do: tokens |> :ntriples_parser.parse() defp build_graph(ast) do - Enum.reduce ast, RDF.Graph.new, fn(triple, graph) -> + Enum.reduce(ast, RDF.Graph.new(), fn triple, graph -> RDF.Graph.add(graph, triple) - end + end) end end diff --git a/lib/rdf/serializations/ntriples_encoder.ex b/lib/rdf/serializations/ntriples_encoder.ex index 7c73cf2..16662d4 100644 --- a/lib/rdf/serializations/ntriples_encoder.ex +++ b/lib/rdf/serializations/ntriples_encoder.ex @@ -6,24 +6,25 @@ defmodule RDF.NTriples.Encoder do alias RDF.{BlankNode, Dataset, Graph, IRI, XSD, Literal, Statement, Triple, LangString} @impl RDF.Serialization.Encoder - @callback encode(Graph.t | Dataset.t, keyword | map) :: {:ok, String.t} | {:error, any} + @callback encode(Graph.t() | Dataset.t(), keyword | map) :: {:ok, String.t()} | {:error, any} def encode(data, _opts \\ []) do result = data - |> Enum.reduce([], fn (statement, result) -> - [statement(statement) | result] - end) - |> Enum.reverse + |> Enum.reduce([], fn statement, result -> + [statement(statement) | result] + end) + |> Enum.reverse() |> Enum.join("\n") - {:ok, (if result == "", do: result, else: result <> "\n")} + + {:ok, if(result == "", do: result, else: result <> "\n")} end - @spec statement(Triple.t) :: String.t + @spec statement(Triple.t()) :: String.t() def statement({subject, predicate, object}) do "#{term(subject)} #{term(predicate)} #{term(object)} ." end - @spec term(Statement.subject | Statement.predicate | Statement.object) :: String.t + @spec term(Statement.subject() | Statement.predicate() | Statement.object()) :: String.t() def term(%IRI{} = iri) do "<#{to_string(iri)}>" end @@ -43,5 +44,4 @@ defmodule RDF.NTriples.Encoder do def term(%BlankNode{} = bnode) do to_string(bnode) end - end diff --git a/lib/rdf/serializations/turtle.ex b/lib/rdf/serializations/turtle.ex index 53a9e44..95d4943 100644 --- a/lib/rdf/serializations/turtle.ex +++ b/lib/rdf/serializations/turtle.ex @@ -10,9 +10,8 @@ defmodule RDF.Turtle do import RDF.Sigils - @id ~I - @name :turtle - @extension "ttl" + @id ~I + @name :turtle + @extension "ttl" @media_type "text/turtle" - end diff --git a/lib/rdf/serializations/turtle_decoder.ex b/lib/rdf/serializations/turtle_decoder.ex index 9e8d347..dc03439 100644 --- a/lib/rdf/serializations/turtle_decoder.ex +++ b/lib/rdf/serializations/turtle_decoder.ex @@ -19,13 +19,12 @@ defmodule RDF.Turtle.Decoder do end def next_bnode(%State{bnode_counter: bnode_counter} = state) do - {RDF.bnode("b#{bnode_counter}"), - %State{state | bnode_counter: bnode_counter + 1}} + {RDF.bnode("b#{bnode_counter}"), %State{state | bnode_counter: bnode_counter + 1}} end end @impl RDF.Serialization.Decoder - @spec decode(String.t, keyword | map) :: {:ok, Graph.t | Dataset.t} | {:error, any} + @spec decode(String.t(), keyword | map) :: {:ok, Graph.t() | Dataset.t()} | {:error, any} def decode(content, opts \\ %{}) def decode(content, opts) when is_list(opts), @@ -33,25 +32,28 @@ defmodule RDF.Turtle.Decoder do def decode(content, opts) do with {:ok, tokens, _} <- tokenize(content), - {:ok, ast} <- parse(tokens), + {:ok, ast} <- parse(tokens), base_iri = Map.get(opts, :base, Map.get(opts, :base_iri, RDF.default_base_iri())) do build_graph(ast, base_iri && RDF.iri(base_iri)) else {:error, {error_line, :turtle_lexer, error_descriptor}, _error_line_again} -> - {:error, "Turtle scanner error on line #{error_line}: #{error_description error_descriptor}"} + {:error, + "Turtle scanner error on line #{error_line}: #{error_description(error_descriptor)}"} + {:error, {error_line, :turtle_parser, error_descriptor}} -> - {:error, "Turtle parser error on line #{error_line}: #{error_description error_descriptor}"} + {:error, + "Turtle parser error on line #{error_line}: #{error_description(error_descriptor)}"} end end - def tokenize(content), do: content |> to_charlist |> :turtle_lexer.string + def tokenize(content), do: content |> to_charlist |> :turtle_lexer.string() - def parse([]), do: {:ok, []} - def parse(tokens), do: tokens |> :turtle_parser.parse + def parse([]), do: {:ok, []} + def parse(tokens), do: tokens |> :turtle_parser.parse() defp build_graph(ast, base_iri) do {graph, %State{namespaces: namespaces, base_iri: base_iri}} = - Enum.reduce ast, {RDF.Graph.new, %State{base_iri: base_iri}}, fn + Enum.reduce(ast, {RDF.Graph.new(), %State{base_iri: base_iri}}, fn {:triples, triples_ast}, {graph, state} -> with {statements, state} = triples(triples_ast, state) do {RDF.Graph.add(graph, statements), state} @@ -59,16 +61,15 @@ defmodule RDF.Turtle.Decoder do {:directive, directive_ast}, {graph, state} -> {graph, directive(directive_ast, state)} - end + end) {:ok, - if Enum.empty?(namespaces) do - graph - else - RDF.Graph.add_prefixes(graph, namespaces) - end - |> RDF.Graph.set_base_iri(base_iri) - } + if Enum.empty?(namespaces) do + graph + else + RDF.Graph.add_prefixes(graph, namespaces) + end + |> RDF.Graph.set_base_iri(base_iri)} rescue error -> {:error, Exception.message(error)} end @@ -87,16 +88,17 @@ defmodule RDF.Turtle.Decoder do cond do IRI.absolute?(iri) -> %State{state | base_iri: RDF.iri(iri)} + base_iri != nil -> with absolute_iri = IRI.absolute(iri, base_iri) do %State{state | base_iri: absolute_iri} end + true -> raise "Could not resolve relative IRI '#{iri}', no base iri provided" end end - defp triples({:blankNodePropertyList, _} = ast, state) do with {_, statements, state} = resolve_node(ast, [], state) do {statements, state} @@ -105,15 +107,16 @@ defmodule RDF.Turtle.Decoder do defp triples({subject, predications}, state) do with {subject, statements, state} = resolve_node(subject, [], state) do - Enum.reduce predications, {statements, state}, fn {predicate, objects}, {statements, state} -> + Enum.reduce(predications, {statements, state}, fn {predicate, objects}, + {statements, state} -> with {predicate, statements, state} = resolve_node(predicate, statements, state) do - Enum.reduce objects, {statements, state}, fn object, {statements, state} -> + Enum.reduce(objects, {statements, state}, fn object, {statements, state} -> with {object, statements, state} = resolve_node(object, statements, state) do {[{subject, predicate, object} | statements], state} end - end + end) end - end + end) end end @@ -121,7 +124,7 @@ defmodule RDF.Turtle.Decoder do if ns = State.ns(state, prefix) do {RDF.iri(ns <> local_name_unescape(name)), statements, state} else - raise "line #{line_number}: undefined prefix #{inspect prefix}" + raise "line #{line_number}: undefined prefix #{inspect(prefix)}" end end @@ -129,7 +132,7 @@ defmodule RDF.Turtle.Decoder do if ns = State.ns(state, prefix) do {RDF.iri(ns), statements, state} else - raise "line #{line_number}: undefined prefix #{inspect prefix}" + raise "line #{line_number}: undefined prefix #{inspect(prefix)}" end end @@ -154,35 +157,43 @@ defmodule RDF.Turtle.Decoder do end end - defp resolve_node({{:string_literal_quote, _line, value}, {:datatype, datatype}}, statements, state) do + defp resolve_node( + {{:string_literal_quote, _line, value}, {:datatype, datatype}}, + statements, + state + ) do with {datatype, statements, state} = resolve_node(datatype, statements, state) do {RDF.literal(value, datatype: datatype), statements, state} end end defp resolve_node({:collection, []}, statements, state) do - {RDF.nil, statements, state} + {RDF.nil(), statements, state} end defp resolve_node({:collection, elements}, statements, state) do with {first_list_node, state} = State.next_bnode(state), [first_element | rest_elements] = elements, - {first_element_node, statements, state} = - resolve_node(first_element, statements, state), - first_statement = [{first_list_node, RDF.first, first_element_node}] do + {first_element_node, statements, state} = resolve_node(first_element, statements, state), + first_statement = [{first_list_node, RDF.first(), first_element_node}] do {last_list_node, statements, state} = - Enum.reduce rest_elements, {first_list_node, statements ++ first_statement, state}, + Enum.reduce( + rest_elements, + {first_list_node, statements ++ first_statement, state}, fn element, {list_node, statements, state} -> - with {element_node, statements, state} = - resolve_node(element, statements, state), + with {element_node, statements, state} = resolve_node(element, statements, state), {next_list_node, state} = State.next_bnode(state) do - {next_list_node, statements ++ [ - {list_node, RDF.rest, next_list_node}, - {next_list_node, RDF.first, element_node}, - ], state} + {next_list_node, + statements ++ + [ + {list_node, RDF.rest(), next_list_node}, + {next_list_node, RDF.first(), element_node} + ], state} end end - {first_list_node, statements ++ [{last_list_node, RDF.rest, RDF.nil}], state} + ) + + {first_list_node, statements ++ [{last_list_node, RDF.rest(), RDF.nil()}], state} end end @@ -195,5 +206,4 @@ defmodule RDF.Turtle.Decoder do defp local_name_unescape_map(e) when e in @reserved_characters, do: e defp local_name_unescape_map(_), do: false - end diff --git a/lib/rdf/serializations/turtle_encoder.ex b/lib/rdf/serializations/turtle_encoder.ex index c38c256..93e3e7a 100644 --- a/lib/rdf/serializations/turtle_encoder.ex +++ b/lib/rdf/serializations/turtle_encoder.ex @@ -29,23 +29,22 @@ defmodule RDF.Turtle.Encoder do ] @ordered_properties MapSet.new(@predicate_order) - @impl RDF.Serialization.Encoder - @callback encode(Graph.t | Dataset.t, keyword | map) :: {:ok, String.t} | {:error, any} + @callback encode(Graph.t() | Dataset.t(), keyword | map) :: {:ok, String.t()} | {:error, any} def encode(data, opts \\ []) do - with base = Keyword.get(opts, :base, Keyword.get(opts, :base_iri)) - |> base_iri(data) |> init_base_iri(), - prefixes = Keyword.get(opts, :prefixes) - |> prefixes(data) |> init_prefixes(), + with base = + Keyword.get(opts, :base, Keyword.get(opts, :base_iri)) + |> base_iri(data) + |> init_base_iri(), + prefixes = Keyword.get(opts, :prefixes) |> prefixes(data) |> init_prefixes(), {:ok, state} = State.start_link(data, base, prefixes) do try do State.preprocess(state) {:ok, - base_directive(base) <> - prefix_directives(prefixes) <> - graph_statements(state) - } + base_directive(base) <> + prefix_directives(prefixes) <> + graph_statements(state)} after State.stop(state) end @@ -60,6 +59,7 @@ defmodule RDF.Turtle.Encoder do defp init_base_iri(base_iri) do base_iri = to_string(base_iri) + if String.ends_with?(base_iri, ~w[/ #]) do {:ok, base_iri} else @@ -73,28 +73,26 @@ defmodule RDF.Turtle.Encoder do defp prefixes(prefixes, _), do: RDF.PrefixMap.new(prefixes) defp init_prefixes(prefixes) do - Enum.reduce prefixes, %{}, fn {prefix, iri}, reverse -> + Enum.reduce(prefixes, %{}, fn {prefix, iri}, reverse -> Map.put(reverse, iri, to_string(prefix)) - end + end) end - - defp base_directive(nil), do: "" - defp base_directive({_, base}), do: "@base <#{base}> .\n" + defp base_directive(nil), do: "" + defp base_directive({_, base}), do: "@base <#{base}> .\n" defp prefix_directive({ns, prefix}), do: "@prefix #{prefix}: <#{to_string(ns)}> .\n" defp prefix_directives(prefixes) do case Enum.map(prefixes, &prefix_directive/1) do - [] -> "" + [] -> "" prefixes -> Enum.join(prefixes, "") <> "\n" end end - defp graph_statements(state) do State.data(state) - |> RDF.Data.descriptions + |> RDF.Data.descriptions() |> order_descriptions(state) |> Enum.map(&description_statements(&1, state)) |> Enum.reject(&is_nil/1) @@ -103,49 +101,54 @@ defmodule RDF.Turtle.Encoder do defp order_descriptions(descriptions, state) do base_iri = State.base_iri(state) + group = - Enum.group_by descriptions, fn + Enum.group_by(descriptions, fn %Description{subject: ^base_iri} -> :base + description -> with types when not is_nil(types) <- description.predications[@rdf_type] do - Enum.find @top_classes, :other, fn top_class -> + Enum.find(@top_classes, :other, fn top_class -> Map.has_key?(types, top_class) - end + end) else _ -> :other end - end - ordered_descriptions = ( - @top_classes - |> Stream.map(fn top_class -> group[top_class] end) - |> Stream.reject(&is_nil/1) - |> Stream.map(&sort_description_group/1) - |> Enum.reduce([], fn class_group, ordered_descriptions -> - ordered_descriptions ++ class_group - end) - ) ++ (group |> Map.get(:other, []) |> sort_description_group()) + end) + + ordered_descriptions = + (@top_classes + |> Stream.map(fn top_class -> group[top_class] end) + |> Stream.reject(&is_nil/1) + |> Stream.map(&sort_description_group/1) + |> Enum.reduce([], fn class_group, ordered_descriptions -> + ordered_descriptions ++ class_group + end)) ++ (group |> Map.get(:other, []) |> sort_description_group()) case group[:base] do [base] -> [base | ordered_descriptions] - _ -> ordered_descriptions + _ -> ordered_descriptions end end defp sort_description_group(descriptions) do - Enum.sort descriptions, fn - %Description{subject: %IRI{}}, %Description{subject: %BlankNode{}} -> true - %Description{subject: %BlankNode{}}, %Description{subject: %IRI{}} -> false + Enum.sort(descriptions, fn + %Description{subject: %IRI{}}, %Description{subject: %BlankNode{}} -> + true + + %Description{subject: %BlankNode{}}, %Description{subject: %IRI{}} -> + false + %Description{subject: s1}, %Description{subject: s2} -> to_string(s1) < to_string(s2) - end + end) end defp description_statements(description, state, nesting \\ 0) do with %BlankNode{} <- description.subject, ref_count when ref_count < 2 <- - State.bnode_ref_counter(state, description.subject) - do + State.bnode_ref_counter(state, description.subject) do unrefed_bnode_subject_term(description, ref_count, state, nesting) else _ -> full_description_statements(description, state, nesting) @@ -154,9 +157,7 @@ defmodule RDF.Turtle.Encoder do defp full_description_statements(subject, description, state, nesting) do with nesting = nesting + @indentation do - subject <> newline_indent(nesting) <> ( - predications(description, state, nesting) - ) <> " .\n" + subject <> newline_indent(nesting) <> predications(description, state, nesting) <> " .\n" end end @@ -167,7 +168,8 @@ defmodule RDF.Turtle.Encoder do defp blank_node_property_list(description, state, nesting) do with indented = nesting + @indentation do - "[" <> newline_indent(indented) <> + "[" <> + newline_indent(indented) <> predications(description, state, indented) <> newline_indent(nesting) <> "]" end @@ -196,14 +198,14 @@ defmodule RDF.Turtle.Encoder do end defp predication({predicate, objects}, state, nesting) do - term(predicate, state, :predicate, nesting) <> " " <> ( - objects + term(predicate, state, :predicate, nesting) <> + " " <> + (objects |> Enum.map(fn {object, _} -> term(object, state, :object, nesting) end) - |> Enum.join(", ") # TODO: split if the line gets too long - ) + # TODO: split if the line gets too long + |> Enum.join(", ")) end - defp unrefed_bnode_subject_term(bnode_description, ref_count, state, nesting) do if valid_list_node?(bnode_description.subject, state) do case ref_count do @@ -211,9 +213,14 @@ defmodule RDF.Turtle.Encoder do bnode_description.subject |> list_term(state, nesting) |> full_description_statements( - list_subject_description(bnode_description), state, nesting) + list_subject_description(bnode_description), + state, + nesting + ) + 1 -> nil + _ -> raise "Internal error: This shouldn't happen. Please raise an issue in the RDF.ex project with the input document causing this error." end @@ -221,8 +228,10 @@ defmodule RDF.Turtle.Encoder do case ref_count do 0 -> blank_node_property_list(bnode_description, state, nesting) <> " .\n" + 1 -> nil + _ -> raise "Internal error: This shouldn't happen. Please raise an issue in the RDF.ex project with the input document causing this error." end @@ -231,7 +240,7 @@ defmodule RDF.Turtle.Encoder do @dialyzer {:nowarn_function, list_subject_description: 1} defp list_subject_description(description) do - with description = Description.delete_predicates(description, [RDF.first, RDF.rest]) do + with description = Description.delete_predicates(description, [RDF.first(), RDF.rest()]) do if Enum.count(description.predications) == 0 do # since the Turtle grammar doesn't allow bare lists, we add a statement description |> RDF.type(RDF.List) @@ -256,7 +265,7 @@ defmodule RDF.Turtle.Encoder do end defp valid_list_node?(bnode, state) do - MapSet.member?(State.list_nodes(state), bnode) + MapSet.member?(State.list_nodes(state), bnode) end defp list_term(head, state, nesting) do @@ -265,9 +274,8 @@ defmodule RDF.Turtle.Encoder do |> term(state, :list, nesting) end - defp term(@rdf_type, _, :predicate, _), do: "a" - defp term(@rdf_nil, _, _, _), do: "()" + defp term(@rdf_nil, _, _, _), do: "()" defp term(%IRI{} = iri, state, _, _) do based_name(iri, State.base(state)) || @@ -276,7 +284,7 @@ defmodule RDF.Turtle.Encoder do end defp term(%BlankNode{} = bnode, state, position, nesting) - when position in ~w[object list]a do + when position in ~w[object list]a do if (ref_count = State.bnode_ref_counter(state, bnode)) <= 1 do unrefed_bnode_object_term(bnode, ref_count, state, nesting) else @@ -296,7 +304,7 @@ defmodule RDF.Turtle.Encoder do end defp term(%Literal{literal: %datatype{}} = literal, state, _, nesting) - when datatype in @native_supported_datatypes do + when datatype in @native_supported_datatypes do if Literal.valid?(literal) do Literal.canonical_lexical(literal) else @@ -309,15 +317,14 @@ defmodule RDF.Turtle.Encoder do defp term(list, state, _, nesting) when is_list(list) do "(" <> - ( - list - |> Enum.map(&term(&1, state, :list, nesting)) - |> Enum.join(" ") - ) <> + (list + |> Enum.map(&term(&1, state, :list, nesting)) + |> Enum.join(" ")) <> ")" end defp based_name(%IRI{} = iri, base), do: based_name(to_string(iri), base) + defp based_name(iri, {:ok, base}) do if String.starts_with?(iri, base) do "<#{String.slice(iri, String.length(base)..-1)}>" @@ -326,22 +333,23 @@ defmodule RDF.Turtle.Encoder do defp based_name(_, _), do: nil - defp typed_literal_term(%Literal{} = literal, state, nesting), - do: ~s["#{Literal.lexical(literal)}"^^#{literal |> Literal.datatype_id() |> term(state, :datatype, nesting)}] - + do: + ~s["#{Literal.lexical(literal)}"^^#{ + literal |> Literal.datatype_id() |> term(state, :datatype, nesting) + }] def prefixed_name(iri, prefixes) do with {ns, name} <- split_iri(iri) do case prefixes[ns] do - nil -> nil + nil -> nil prefix -> prefix <> ":" <> name end end end defp split_iri(%IRI{} = iri), - do: iri |> IRI.parse |> split_iri() + do: iri |> IRI.parse() |> split_iri() defp split_iri(%URI{fragment: fragment} = uri) when not is_nil(fragment), do: {RDF.iri(%URI{uri | fragment: ""}), fragment} @@ -375,7 +383,6 @@ defmodule RDF.Turtle.Encoder do |> String.replace("\"", ~S[\"]) end - defp newline_indent(nesting), do: "\n" <> String.duplicate(@indentation_char, nesting) end diff --git a/lib/rdf/serializations/turtle_encoder_state.ex b/lib/rdf/serializations/turtle_encoder_state.ex index 060eb4c..f604be4 100644 --- a/lib/rdf/serializations/turtle_encoder_state.ex +++ b/lib/rdf/serializations/turtle_encoder_state.ex @@ -3,7 +3,6 @@ defmodule RDF.Turtle.Encoder.State do alias RDF.{BlankNode, Description} - def start_link(data, base, prefixes) do Agent.start_link(fn -> %{data: data, base: base, prefixes: prefixes} end) end @@ -12,11 +11,11 @@ defmodule RDF.Turtle.Encoder.State do Agent.stop(state) end - def data(state), do: Agent.get(state, &(&1.data)) - def base(state), do: Agent.get(state, &(&1.base)) - def prefixes(state), do: Agent.get(state, &(&1.prefixes)) - def list_nodes(state), do: Agent.get(state, &(&1.list_nodes)) - def bnode_ref_counter(state), do: Agent.get(state, &(&1.bnode_ref_counter)) + def data(state), do: Agent.get(state, & &1.data) + def base(state), do: Agent.get(state, & &1.base) + def prefixes(state), do: Agent.get(state, & &1.prefixes) + def list_nodes(state), do: Agent.get(state, & &1.list_nodes) + def bnode_ref_counter(state), do: Agent.get(state, & &1.bnode_ref_counter) def bnode_ref_counter(state, bnode) do bnode_ref_counter(state) |> Map.get(bnode, 0) @@ -30,13 +29,12 @@ defmodule RDF.Turtle.Encoder.State do end end - def list_values(head, state), do: Agent.get(state, &(&1.list_values[head])) + def list_values(head, state), do: Agent.get(state, & &1.list_values[head]) def preprocess(state) do with data = data(state), {bnode_ref_counter, list_parents} = bnode_info(data), - {list_nodes, list_values} = valid_lists(list_parents, bnode_ref_counter, data) - do + {list_nodes, list_values} = valid_lists(list_parents, bnode_ref_counter, data) do Agent.update(state, &Map.put(&1, :bnode_ref_counter, bnode_ref_counter)) Agent.update(state, &Map.put(&1, :list_nodes, list_nodes)) Agent.update(state, &Map.put(&1, :list_values, list_values)) @@ -45,45 +43,50 @@ defmodule RDF.Turtle.Encoder.State do defp bnode_info(data) do data - |> RDF.Data.descriptions - |> Enum.reduce({%{}, %{}}, - fn %Description{subject: subject} = description, - {bnode_ref_counter, list_parents} -> + |> RDF.Data.descriptions() + |> Enum.reduce( + {%{}, %{}}, + fn %Description{subject: subject} = description, {bnode_ref_counter, list_parents} -> + list_parents = + if match?(%BlankNode{}, subject) and + to_list?(description, Map.get(bnode_ref_counter, subject, 0)), + do: Map.put_new(list_parents, subject, nil), + else: list_parents - list_parents = - if match?(%BlankNode{}, subject) and - to_list?(description, Map.get(bnode_ref_counter, subject, 0)), - do: Map.put_new(list_parents, subject, nil), - else: list_parents + Enum.reduce(description.predications, {bnode_ref_counter, list_parents}, fn + {predicate, objects}, {bnode_ref_counter, list_parents} -> + Enum.reduce(Map.keys(objects), {bnode_ref_counter, list_parents}, fn + %BlankNode{} = object, {bnode_ref_counter, list_parents} -> + { + # Note: The following conditional produces imprecise results + # (sometimes the occurrence in the subject counts, sometimes it doesn't), + # but is sufficient for the current purpose of handling the + # case of a statement with the same subject and object bnode. + Map.update( + bnode_ref_counter, + object, + if(subject == object, do: 2, else: 1), + &(&1 + 1) + ), + if predicate == RDF.rest() do + Map.put_new(list_parents, object, subject) + else + list_parents + end + } - Enum.reduce(description.predications, {bnode_ref_counter, list_parents}, fn - ({predicate, objects}, {bnode_ref_counter, list_parents}) -> - Enum.reduce(Map.keys(objects), {bnode_ref_counter, list_parents}, fn - (%BlankNode{} = object, {bnode_ref_counter, list_parents}) -> - { - # Note: The following conditional produces imprecise results - # (sometimes the occurrence in the subject counts, sometimes it doesn't), - # but is sufficient for the current purpose of handling the - # case of a statement with the same subject and object bnode. - Map.update(bnode_ref_counter, object, - (if subject == object, do: 2, else: 1), &(&1 + 1)), - if predicate == RDF.rest do - Map.put_new(list_parents, object, subject) - else - list_parents - end - } - (_, {bnode_ref_counter, list_parents}) -> - {bnode_ref_counter, list_parents} - end) - end) - end) + _, {bnode_ref_counter, list_parents} -> + {bnode_ref_counter, list_parents} + end) + end) + end + ) end @list_properties MapSet.new([ - RDF.Utils.Bootstrapping.rdf_iri("first"), - RDF.Utils.Bootstrapping.rdf_iri("rest") - ]) + RDF.Utils.Bootstrapping.rdf_iri("first"), + RDF.Utils.Bootstrapping.rdf_iri("rest") + ]) @dialyzer {:nowarn_function, to_list?: 2} defp to_list?(%Description{} = description, 1) do @@ -97,39 +100,37 @@ defmodule RDF.Turtle.Encoder.State do defp to_list?(_, _), do: false - defp valid_lists(list_parents, bnode_ref_counter, data) do head_nodes = for {list_node, nil} <- list_parents, do: list_node - all_list_nodes = MapSet.new( - for {list_node, _} <- list_parents, Map.get(bnode_ref_counter, list_node, 0) < 2 do - list_node - end) - - Enum.reduce head_nodes, {MapSet.new, %{}}, - fn head_node, {valid_list_nodes, list_values} -> - with list when not is_nil(list) <- - RDF.List.new(head_node, data), - list_nodes = - RDF.List.nodes(list), - true <- - Enum.all?(list_nodes, fn - %BlankNode{} = list_node -> - MapSet.member?(all_list_nodes, list_node) - _ -> - false - end) - do - { - Enum.reduce(list_nodes, valid_list_nodes, fn list_node, valid_list_nodes -> - MapSet.put(valid_list_nodes, list_node) - end), - Map.put(list_values, head_node, RDF.List.values(list)), - } - else - _ -> {valid_list_nodes, list_values} + all_list_nodes = + MapSet.new( + for {list_node, _} <- list_parents, Map.get(bnode_ref_counter, list_node, 0) < 2 do + list_node end - end - end + ) + Enum.reduce(head_nodes, {MapSet.new(), %{}}, fn head_node, {valid_list_nodes, list_values} -> + with list when not is_nil(list) <- + RDF.List.new(head_node, data), + list_nodes = RDF.List.nodes(list), + true <- + Enum.all?(list_nodes, fn + %BlankNode{} = list_node -> + MapSet.member?(all_list_nodes, list_node) + + _ -> + false + end) do + { + Enum.reduce(list_nodes, valid_list_nodes, fn list_node, valid_list_nodes -> + MapSet.put(valid_list_nodes, list_node) + end), + Map.put(list_values, head_node, RDF.List.values(list)) + } + else + _ -> {valid_list_nodes, list_values} + end + end) + end end diff --git a/lib/rdf/sigils.ex b/lib/rdf/sigils.ex index 004d409..427b08e 100644 --- a/lib/rdf/sigils.ex +++ b/lib/rdf/sigils.ex @@ -3,7 +3,6 @@ defmodule RDF.Sigils do Sigils for the most common types of RDF nodes. """ - @doc ~S""" Handles the sigil `~I` for IRIs. @@ -34,7 +33,6 @@ defmodule RDF.Sigils do Macro.escape(RDF.BlankNode.new(bnode)) end - @doc ~S""" Handles the sigil `~L` for plain Literals. diff --git a/lib/rdf/statement.ex b/lib/rdf/statement.ex index 34bfa7d..01e6e9a 100644 --- a/lib/rdf/statement.ex +++ b/lib/rdf/statement.ex @@ -8,21 +8,20 @@ defmodule RDF.Statement do alias RDF.{BlankNode, IRI, Literal, Quad, Term, Triple} import RDF.Guards - @type subject :: IRI.t | BlankNode.t - @type predicate :: IRI.t | BlankNode.t - @type object :: IRI.t | BlankNode.t | Literal.t - @type graph_name :: IRI.t | BlankNode.t + @type subject :: IRI.t() | BlankNode.t() + @type predicate :: IRI.t() | BlankNode.t() + @type object :: IRI.t() | BlankNode.t() | Literal.t() + @type graph_name :: IRI.t() | BlankNode.t() - @type coercible_subject :: subject | atom | String.t - @type coercible_predicate :: predicate | atom | String.t - @type coercible_object :: object | any - @type coercible_graph_name :: graph_name | atom | String.t + @type coercible_subject :: subject | atom | String.t() + @type coercible_predicate :: predicate | atom | String.t() + @type coercible_object :: object | any + @type coercible_graph_name :: graph_name | atom | String.t() - @type qualified_term :: {atom, Term.t | nil} - @type term_mapping :: (qualified_term -> any | nil) - - @type t :: Triple.t | Quad.t + @type qualified_term :: {atom, Term.t() | nil} + @type term_mapping :: (qualified_term -> any | nil) + @type t :: Triple.t() | Quad.t() @doc """ Creates a `RDF.Statement` tuple with proper RDF values. @@ -36,10 +35,10 @@ defmodule RDF.Statement do iex> RDF.Statement.coerce {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"} {~I, ~I, RDF.literal(42), ~I} """ - @spec coerce(Triple.coercible_t) :: Triple.t - @spec coerce(Quad.coercible_t) :: Quad.t + @spec coerce(Triple.coercible_t()) :: Triple.t() + @spec coerce(Quad.coercible_t()) :: Quad.t() def coerce(statement) - def coerce({_, _, _} = triple), do: Triple.new(triple) + def coerce({_, _, _} = triple), do: Triple.new(triple) def coerce({_, _, _, _} = quad), do: Quad.new(quad) @doc false @@ -49,7 +48,7 @@ defmodule RDF.Statement do def coerce_subject(bnode = %BlankNode{}), do: bnode def coerce_subject("_:" <> identifier), do: RDF.bnode(identifier) def coerce_subject(iri) when maybe_ns_term(iri) or is_binary(iri), do: RDF.iri!(iri) - def coerce_subject(arg), do: raise RDF.Triple.InvalidSubjectError, subject: arg + def coerce_subject(arg), do: raise(RDF.Triple.InvalidSubjectError, subject: arg) @doc false @spec coerce_predicate(coercible_predicate) :: predicate @@ -60,7 +59,7 @@ defmodule RDF.Statement do # TODO: Support an option `:strict_rdf` to explicitly disallow them or produce warnings or ... def coerce_predicate(bnode = %BlankNode{}), do: bnode def coerce_predicate(iri) when maybe_ns_term(iri) or is_binary(iri), do: RDF.iri!(iri) - def coerce_predicate(arg), do: raise RDF.Triple.InvalidPredicateError, predicate: arg + def coerce_predicate(arg), do: raise(RDF.Triple.InvalidPredicateError, predicate: arg) @doc false @spec coerce_object(coercible_object) :: object @@ -80,9 +79,9 @@ defmodule RDF.Statement do def coerce_graph_name(bnode = %BlankNode{}), do: bnode def coerce_graph_name("_:" <> identifier), do: RDF.bnode(identifier) def coerce_graph_name(iri) when maybe_ns_term(iri) or is_binary(iri), do: RDF.iri!(iri) - def coerce_graph_name(arg), - do: raise RDF.Quad.InvalidGraphContextError, graph_context: arg + def coerce_graph_name(arg), + do: raise(RDF.Quad.InvalidGraphContextError, graph_context: arg) @doc """ Returns a tuple of native Elixir values from a `RDF.Statement` of RDF terms. @@ -117,9 +116,9 @@ defmodule RDF.Statement do {"S", :p, 42, ~I} """ - @spec values(t | any, term_mapping) :: Triple.t_values | Quad.t_values | nil + @spec values(t | any, term_mapping) :: Triple.t_values() | Quad.t_values() | nil def values(statement, mapping \\ &default_term_mapping/1) - def values({_, _, _} = triple, mapping), do: RDF.Triple.values(triple, mapping) + def values({_, _, _} = triple, mapping), do: RDF.Triple.values(triple, mapping) def values({_, _, _, _} = quad, mapping), do: RDF.Quad.values(quad, mapping) def values(_, _), do: nil @@ -129,7 +128,6 @@ defmodule RDF.Statement do def default_term_mapping({:graph_name, nil}), do: nil def default_term_mapping({_, term}), do: RDF.Term.value(term) - @doc """ Checks if the given tuple is a valid RDF statement, i.e. RDF triple or quad. @@ -137,7 +135,7 @@ defmodule RDF.Statement do position only IRIs and blank nodes allowed, while on the predicate and graph context position only IRIs allowed. The object position can be any RDF term. """ - @spec valid?(Triple.t | Quad.t | any) :: boolean + @spec valid?(Triple.t() | Quad.t() | any) :: boolean def valid?(tuple) def valid?({subject, predicate, object}) do @@ -152,22 +150,21 @@ defmodule RDF.Statement do def valid?(_), do: false @spec valid_subject?(subject | any) :: boolean - def valid_subject?(%IRI{}), do: true + def valid_subject?(%IRI{}), do: true def valid_subject?(%BlankNode{}), do: true - def valid_subject?(_), do: false + def valid_subject?(_), do: false @spec valid_predicate?(predicate | any) :: boolean - def valid_predicate?(%IRI{}), do: true - def valid_predicate?(_), do: false + def valid_predicate?(%IRI{}), do: true + def valid_predicate?(_), do: false @spec valid_object?(object | any) :: boolean - def valid_object?(%IRI{}), do: true - def valid_object?(%BlankNode{}), do: true - def valid_object?(%Literal{}), do: true - def valid_object?(_), do: false + def valid_object?(%IRI{}), do: true + def valid_object?(%BlankNode{}), do: true + def valid_object?(%Literal{}), do: true + def valid_object?(_), do: false @spec valid_graph_name?(graph_name | any) :: boolean - def valid_graph_name?(%IRI{}), do: true - def valid_graph_name?(_), do: false - + def valid_graph_name?(%IRI{}), do: true + def valid_graph_name?(_), do: false end diff --git a/lib/rdf/term.ex b/lib/rdf/term.ex index 01a27c4..2caf14c 100644 --- a/lib/rdf/term.ex +++ b/lib/rdf/term.ex @@ -11,8 +11,7 @@ defprotocol RDF.Term do see """ - @type t :: RDF.IRI.t | RDF.BlankNode.t | RDF.Literal.t - + @type t :: RDF.IRI.t() | RDF.BlankNode.t() | RDF.Literal.t() @doc """ Checks if the given value is a RDF term. @@ -43,7 +42,6 @@ defprotocol RDF.Term do @fallback_to_any true def equal?(term1, term2) - @doc """ Tests for equality of values. @@ -89,52 +87,52 @@ defprotocol RDF.Term do """ def value(term) - end defimpl RDF.Term, for: RDF.IRI do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.IRI.equal_value?(term1, term2) - def coerce(term), do: term - def value(term), do: term.value - def term?(_), do: true + def coerce(term), do: term + def value(term), do: term.value + def term?(_), do: true end defimpl RDF.Term, for: RDF.BlankNode do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.BlankNode.equal_value?(term1, term2) - def coerce(term), do: term - def value(term), do: to_string(term) - def term?(_), do: true + def coerce(term), do: term + def value(term), do: to_string(term) + def term?(_), do: true end defimpl RDF.Term, for: Reference do @dialyzer {:nowarn_function, equal_value?: 2} @dialyzer {:nowarn_function, coerce: 1} - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.BlankNode.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.BlankNode.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: RDF.Literal do - def equal?(term1, term2), do: RDF.Literal.equal?(term1, term2) + def equal?(term1, term2), do: RDF.Literal.equal?(term1, term2) def equal_value?(term1, term2), do: RDF.Literal.equal_value?(term1, term2) - def coerce(term), do: term - def value(term), do: RDF.Literal.value(term) || RDF.Literal.lexical(term) - def term?(_), do: true + def coerce(term), do: term + def value(term), do: RDF.Literal.value(term) || RDF.Literal.lexical(term) + def term?(_), do: true end defimpl RDF.Term, for: Atom do def equal?(term1, term2), do: term1 == term2 - def equal_value?(nil, _), do: nil + def equal_value?(nil, _), do: nil def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(true), do: RDF.XSD.true - def coerce(false), do: RDF.XSD.false - def coerce(nil), do: nil + def coerce(true), do: RDF.XSD.true() + def coerce(false), do: RDF.XSD.false() + def coerce(nil), do: nil + def coerce(term) do case RDF.Namespace.resolve_term(term) do {:ok, iri} -> iri @@ -142,90 +140,90 @@ defimpl RDF.Term, for: Atom do end end - def value(true), do: true + def value(true), do: true def value(false), do: false - def value(nil), do: nil - def value(term), do: RDF.Term.value(coerce(term)) + def value(nil), do: nil + def value(term), do: RDF.Term.value(coerce(term)) def term?(_), do: false end defimpl RDF.Term, for: BitString do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.XSD.String.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.XSD.String.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: Integer do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.XSD.Integer.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.XSD.Integer.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: Float do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.XSD.Double.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.XSD.Double.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: Decimal do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.XSD.Decimal.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.XSD.Decimal.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: DateTime do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.XSD.DateTime.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.XSD.DateTime.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: NaiveDateTime do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.XSD.DateTime.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.XSD.DateTime.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: Date do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.XSD.Date.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.XSD.Date.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: Time do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.XSD.Time.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.XSD.Time.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: URI do - def equal?(term1, term2), do: term1 == term2 + def equal?(term1, term2), do: term1 == term2 def equal_value?(term1, term2), do: RDF.Term.equal_value?(coerce(term1), term2) - def coerce(term), do: RDF.XSD.AnyURI.new(term) - def value(term), do: term - def term?(_), do: false + def coerce(term), do: RDF.XSD.AnyURI.new(term) + def value(term), do: term + def term?(_), do: false end defimpl RDF.Term, for: Any do def equal?(term1, term2), do: term1 == term2 - def equal_value?(_, _), do: nil - def coerce(_), do: nil - def value(_), do: nil - def term?(_), do: false + def equal_value?(_, _), do: nil + def coerce(_), do: nil + def value(_), do: nil + def term?(_), do: false end diff --git a/lib/rdf/triple.ex b/lib/rdf/triple.ex index 055d6ab..8095548 100644 --- a/lib/rdf/triple.ex +++ b/lib/rdf/triple.ex @@ -8,14 +8,13 @@ defmodule RDF.Triple do alias RDF.Statement - @type t :: {Statement.subject, Statement.predicate, Statement.object} + @type t :: {Statement.subject(), Statement.predicate(), Statement.object()} @type coercible_t :: - {Statement.coercible_subject, Statement.coercible_predicate, - Statement.coercible_object} - - @type t_values :: {String.t, String.t, any} + {Statement.coercible_subject(), Statement.coercible_predicate(), + Statement.coercible_object()} + @type t_values :: {String.t(), String.t(), any} @doc """ Creates a `RDF.Triple` with proper RDF values. @@ -32,9 +31,9 @@ defmodule RDF.Triple do {RDF.iri("http://example.com/S"), RDF.iri("http://example.com/p"), RDF.literal(42)} """ @spec new( - Statement.coercible_subject, - Statement.coercible_predicate, - Statement.coercible_object + Statement.coercible_subject(), + Statement.coercible_predicate(), + Statement.coercible_object() ) :: t def new(subject, predicate, object) do { @@ -61,7 +60,6 @@ defmodule RDF.Triple do @spec new(coercible_t) :: t def new({subject, predicate, object}), do: new(subject, predicate, object) - @doc """ Returns a tuple of native Elixir values from a `RDF.Triple` of RDF terms. @@ -87,14 +85,13 @@ defmodule RDF.Triple do {"S", "p", 42} """ - @spec values(t | any, Statement.term_mapping) :: t_values | nil + @spec values(t | any, Statement.term_mapping()) :: t_values | nil def values(triple, mapping \\ &Statement.default_term_mapping/1) def values({subject, predicate, object}, mapping) do - with subject_value when not is_nil(subject_value) <- mapping.({:subject, subject}), + with subject_value when not is_nil(subject_value) <- mapping.({:subject, subject}), predicate_value when not is_nil(predicate_value) <- mapping.({:predicate, predicate}), - object_value when not is_nil(object_value) <- mapping.({:object, object}) - do + object_value when not is_nil(object_value) <- mapping.({:object, object}) do {subject_value, predicate_value, object_value} else _ -> nil @@ -103,7 +100,6 @@ defmodule RDF.Triple do def values(_, _), do: nil - @doc """ Checks if the given tuple is a valid RDF triple. @@ -115,5 +111,4 @@ defmodule RDF.Triple do def valid?(tuple) def valid?({_, _, _} = triple), do: Statement.valid?(triple) def valid?(_), do: false - end diff --git a/lib/rdf/utils/bootstrapping.ex b/lib/rdf/utils/bootstrapping.ex index 6600f1f..30bca53 100644 --- a/lib/rdf/utils/bootstrapping.ex +++ b/lib/rdf/utils/bootstrapping.ex @@ -1,7 +1,7 @@ defmodule RDF.Utils.Bootstrapping do @moduledoc !""" - This module holds functions to circumvent circular dependency problems. - """ + This module holds functions to circumvent circular dependency problems. + """ @xsd_base_iri "http://www.w3.org/2001/XMLSchema#" @rdf_base_iri "http://www.w3.org/1999/02/22-rdf-syntax-ns#" diff --git a/lib/rdf/utils/guards.ex b/lib/rdf/utils/guards.ex index cb50010..1822211 100644 --- a/lib/rdf/utils/guards.ex +++ b/lib/rdf/utils/guards.ex @@ -1,6 +1,6 @@ defmodule RDF.Utils.Guards do defguard is_ordinary_atom(term) - when is_atom(term) and term not in [nil, true, false] + when is_atom(term) and term not in [nil, true, false] defguard maybe_module(term) when is_ordinary_atom(term) end diff --git a/lib/rdf/utils/resource_classifier.ex b/lib/rdf/utils/resource_classifier.ex index 7bcc219..3af7337 100644 --- a/lib/rdf/utils/resource_classifier.ex +++ b/lib/rdf/utils/resource_classifier.ex @@ -13,35 +13,41 @@ defmodule RDF.Utils.ResourceClassifier do def property?(resource, data) do with %Description{} = description <- RDF.Data.description(data, resource) do property_by_domain?(description) or - property_by_rdf_type?(Description.get(description, @rdf_type)) + property_by_rdf_type?(Description.get(description, @rdf_type)) end -# || property_by_predicate_usage?(resource, data) + + # || property_by_predicate_usage?(resource, data) end - - @property_properties Enum.map(~w[ + @property_properties (Enum.map( + ~w[ domain range subPropertyOf - ], &rdfs_iri/1) ++ - Enum.map(~w[ + ], + &rdfs_iri/1 + ) ++ + Enum.map( + ~w[ equivalentProperty inverseOf propertyDisjointWith - ], &owl_iri/1) - |> MapSet.new + ], + &owl_iri/1 + )) + |> MapSet.new() defp property_by_domain?(description) do - Enum.any? @property_properties, fn property -> + Enum.any?(@property_properties, fn property -> description[property] - end + end) end @property_classes [ rdf_iri("Property"), rdfs_iri("ContainerMembershipProperty") - | - Enum.map(~w[ + | Enum.map( + ~w[ ObjectProperty DatatypeProperty AnnotationProperty @@ -53,23 +59,22 @@ defmodule RDF.Utils.ResourceClassifier do IrreflexiveProperty TransitiveProperty DeprecatedProperty - ], &owl_iri/1) + ], + &owl_iri/1 + ) ] - |> MapSet.new + |> MapSet.new() @dialyzer {:nowarn_function, property_by_rdf_type?: 1} defp property_by_rdf_type?(nil), do: nil + defp property_by_rdf_type?(types) do - not ( - types - |> MapSet.new - |> MapSet.disjoint?(@property_classes) - ) + not (types + |> MapSet.new() + |> MapSet.disjoint?(@property_classes)) end - -# defp property_by_predicate_usage?(resource, data) do -# resource in Graph.predicates(data) || nil -# end - + # defp property_by_predicate_usage?(resource, data) do + # resource in Graph.predicates(data) || nil + # end end diff --git a/lib/rdf/vocabulary_namespace.ex b/lib/rdf/vocabulary_namespace.ex index f5f34c1..9db7c53 100644 --- a/lib/rdf/vocabulary_namespace.ex +++ b/lib/rdf/vocabulary_namespace.ex @@ -23,13 +23,14 @@ defmodule RDF.Vocabulary.Namespace do Defines a `RDF.Namespace` module for a RDF vocabulary. """ defmacro defvocab(name, opts) do - strict = strict?(opts) + strict = strict?(opts) base_iri = base_iri!(opts) - file = filename!(opts) + file = filename!(opts) + {terms, data} = case source!(opts) do {:terms, terms} -> {terms, nil} - {:data, data} -> {rdf_data_vocab_terms(data, base_iri), data} + {:data, data} -> {rdf_data_vocab_terms(data, base_iri), data} end unless Mix.env() == :test do @@ -37,6 +38,7 @@ defmodule RDF.Vocabulary.Namespace do end ignored_terms = ignored_terms!(opts) + terms = terms |> term_mapping!(opts) @@ -44,8 +46,9 @@ defmodule RDF.Vocabulary.Namespace do |> validate_terms! |> validate_characters!(opts) |> validate_case!(data, base_iri, opts) + case_separated_terms = group_terms_by_case(terms) - lowercased_terms = Map.get(case_separated_terms, :lowercased, %{}) + lowercased_terms = Map.get(case_separated_terms, :lowercased, %{}) quote do vocabdoc = Module.delete_attribute(__MODULE__, :vocabdoc) @@ -60,7 +63,7 @@ defmodule RDF.Vocabulary.Namespace do end @base_iri unquote(base_iri) - @spec __base_iri__ :: String.t + @spec __base_iri__ :: String.t() def __base_iri__, do: @base_iri @strict unquote(strict) @@ -69,24 +72,24 @@ defmodule RDF.Vocabulary.Namespace do @terms unquote(Macro.escape(terms)) @impl Elixir.RDF.Namespace - def __terms__, do: @terms |> Map.keys + def __terms__, do: @terms |> Map.keys() @ignored_terms unquote(Macro.escape(ignored_terms)) @doc """ Returns all known IRIs of the vocabulary. """ - @spec __iris__ :: [Elixir.RDF.IRI.t] + @spec __iris__ :: [Elixir.RDF.IRI.t()] def __iris__ do @terms |> Enum.map(fn - {term, true} -> term_to_iri(@base_iri, term) - {_alias, term} -> term_to_iri(@base_iri, term) - end) - |> Enum.uniq + {term, true} -> term_to_iri(@base_iri, term) + {_alias, term} -> term_to_iri(@base_iri, term) + end) + |> Enum.uniq() end - define_vocab_terms unquote(lowercased_terms), unquote(base_iri) + define_vocab_terms(unquote(lowercased_terms), unquote(base_iri)) @impl Elixir.RDF.Namespace @dialyzer {:nowarn_function, __resolve_term__: 1} @@ -95,15 +98,16 @@ defmodule RDF.Vocabulary.Namespace do nil -> if @strict or MapSet.member?(@ignored_terms, term) do {:error, - %Elixir.RDF.Namespace.UndefinedTermError{ - message: "undefined term #{term} in strict vocabulary #{__MODULE__}" - } - } + %Elixir.RDF.Namespace.UndefinedTermError{ + message: "undefined term #{term} in strict vocabulary #{__MODULE__}" + }} else {:ok, term_to_iri(@base_iri, term)} end + true -> {:ok, term_to_iri(@base_iri, term)} + original_term -> {:ok, term_to_iri(@base_iri, original_term)} end @@ -134,39 +138,43 @@ defmodule RDF.Vocabulary.Namespace do defmacro define_vocab_terms(terms, base_iri) do terms |> Stream.filter(fn - {term, true} -> valid_term?(term) - {_, _} -> true - end) + {term, true} -> valid_term?(term) + {_, _} -> true + end) |> Stream.map(fn - {term, true} -> {term, term} - {term, original_term} -> {term, original_term} - end) + {term, true} -> {term, term} + {term, original_term} -> {term, original_term} + end) |> Enum.map(fn {term, iri_suffix} -> - iri = term_to_iri(base_iri, iri_suffix) - quote do - @doc "<#{unquote(to_string(iri))}>" - def unquote(term)(), do: unquote(Macro.escape(iri)) + iri = term_to_iri(base_iri, iri_suffix) - @doc "`RDF.Description` builder for `#{unquote(term)}/0`" - def unquote(term)(subject, object) do - RDF.Description.new(subject, unquote(Macro.escape(iri)), object) - end + quote do + @doc "<#{unquote(to_string(iri))}>" + def unquote(term)(), do: unquote(Macro.escape(iri)) - # Is there a better way to support multiple objects via arguments? - @doc false - def unquote(term)(subject, o1, o2), - do: unquote(term)(subject, [o1, o2]) - @doc false - def unquote(term)(subject, o1, o2, o3), - do: unquote(term)(subject, [o1, o2, o3]) - @doc false - def unquote(term)(subject, o1, o2, o3, o4), - do: unquote(term)(subject, [o1, o2, o3, o4]) - @doc false - def unquote(term)(subject, o1, o2, o3, o4, o5), - do: unquote(term)(subject, [o1, o2, o3, o4, o5]) + @doc "`RDF.Description` builder for `#{unquote(term)}/0`" + def unquote(term)(subject, object) do + RDF.Description.new(subject, unquote(Macro.escape(iri)), object) end - end) + + # Is there a better way to support multiple objects via arguments? + @doc false + def unquote(term)(subject, o1, o2), + do: unquote(term)(subject, [o1, o2]) + + @doc false + def unquote(term)(subject, o1, o2, o3), + do: unquote(term)(subject, [o1, o2, o3]) + + @doc false + def unquote(term)(subject, o1, o2, o3, o4), + do: unquote(term)(subject, [o1, o2, o3, o4]) + + @doc false + def unquote(term)(subject, o1, o2, o3, o4, o5), + do: unquote(term)(subject, [o1, o2, o3, o4, o5]) + end + end) end defp strict?(opts), @@ -174,9 +182,10 @@ defmodule RDF.Vocabulary.Namespace do defp base_iri!(opts) do base_iri = Keyword.fetch!(opts, :base_iri) + unless is_binary(base_iri) and String.ends_with?(base_iri, ["/", "#"]) do raise RDF.Namespace.InvalidVocabBaseIRIError, - "a base_iri without a trailing '/' or '#' is invalid" + "a base_iri without a trailing '/' or '#' is invalid" else base_iri end @@ -184,9 +193,15 @@ defmodule RDF.Vocabulary.Namespace do defp source!(opts) do cond do - Keyword.has_key?(opts, :file) -> {:data, filename!(opts) |> RDF.read_file!()} - rdf_data = Keyword.get(opts, :data) -> {:data, raw_rdf_data(rdf_data)} - terms = Keyword.get(opts, :terms) -> {:terms, terms_from_user_input!(terms)} + Keyword.has_key?(opts, :file) -> + {:data, filename!(opts) |> RDF.read_file!()} + + rdf_data = Keyword.get(opts, :data) -> + {:data, raw_rdf_data(rdf_data)} + + terms = Keyword.get(opts, :terms) -> + {:terms, terms_from_user_input!(terms)} + true -> raise KeyError, key: ~w[terms data file], term: opts end @@ -194,81 +209,89 @@ defmodule RDF.Vocabulary.Namespace do defp terms_from_user_input!(terms) do # TODO: find an alternative to Code.eval_quoted - We want to support that the terms can be given as sigils ... - {terms, _ } = Code.eval_quoted(terms, [], rdf_data_env()) - Enum.map terms, fn - term when is_atom(term) -> term - term when is_binary(term) -> String.to_atom(term) + {terms, _} = Code.eval_quoted(terms, [], rdf_data_env()) + + Enum.map(terms, fn + term when is_atom(term) -> + term + + term when is_binary(term) -> + String.to_atom(term) + term -> raise RDF.Namespace.InvalidTermError, - "'#{term}' is not a valid vocabulary term" - end + "'#{term}' is not a valid vocabulary term" + end) end defp raw_rdf_data(%RDF.Description{} = rdf_data), do: rdf_data defp raw_rdf_data(%RDF.Graph{} = rdf_data), do: rdf_data defp raw_rdf_data(%RDF.Dataset{} = rdf_data), do: rdf_data + defp raw_rdf_data(rdf_data) do # TODO: find an alternative to Code.eval_quoted {rdf_data, _} = Code.eval_quoted(rdf_data, [], rdf_data_env()) rdf_data end - defp ignored_terms!(opts) do # TODO: find an alternative to Code.eval_quoted - We want to support that the terms can be given as sigils ... with terms = Keyword.get(opts, :ignore, []) do - {terms, _ } = Code.eval_quoted(terms, [], rdf_data_env()) + {terms, _} = Code.eval_quoted(terms, [], rdf_data_env()) + terms |> Enum.map(fn - term when is_atom(term) -> term - term when is_binary(term) -> String.to_atom(term) - term -> raise RDF.Namespace.InvalidTermError, inspect(term) - end) - |> MapSet.new + term when is_atom(term) -> term + term when is_binary(term) -> String.to_atom(term) + term -> raise RDF.Namespace.InvalidTermError, inspect(term) + end) + |> MapSet.new() end end - defp term_mapping!(terms, opts) do - terms = Map.new terms, fn - term when is_atom(term) -> {term, true} - term -> {String.to_atom(term), true} - end + terms = + Map.new(terms, fn + term when is_atom(term) -> {term, true} + term -> {String.to_atom(term), true} + end) + Keyword.get(opts, :alias, []) |> Enum.reduce(terms, fn {alias, original_term}, terms -> - term = String.to_atom(original_term) - cond do - not valid_characters?(alias) -> - raise RDF.Namespace.InvalidAliasError, - "alias '#{alias}' contains invalid characters" + term = String.to_atom(original_term) - Map.get(terms, alias) == true -> - raise RDF.Namespace.InvalidAliasError, - "alias '#{alias}' already defined" + cond do + not valid_characters?(alias) -> + raise RDF.Namespace.InvalidAliasError, + "alias '#{alias}' contains invalid characters" - strict?(opts) and not Map.has_key?(terms, term) -> - raise RDF.Namespace.InvalidAliasError, + Map.get(terms, alias) == true -> + raise RDF.Namespace.InvalidAliasError, + "alias '#{alias}' already defined" + + strict?(opts) and not Map.has_key?(terms, term) -> + raise RDF.Namespace.InvalidAliasError, "term '#{original_term}' is not a term in this vocabulary" - Map.get(terms, term, true) != true -> - raise RDF.Namespace.InvalidAliasError, + Map.get(terms, term, true) != true -> + raise RDF.Namespace.InvalidAliasError, "'#{original_term}' is already an alias" - true -> - Map.put(terms, alias, to_string(original_term)) - end - end) + true -> + Map.put(terms, alias, to_string(original_term)) + end + end) end defp aliased_terms(terms) do terms - |> Map.values - |> MapSet.new + |> Map.values() + |> MapSet.new() |> MapSet.delete(true) |> Enum.map(&String.to_atom/1) end - @invalid_terms MapSet.new ~w[ + @invalid_terms MapSet.new(~w[ and or xor @@ -288,7 +311,7 @@ defmodule RDF.Vocabulary.Namespace do require super __aliases__ - ]a + ]a) def invalid_terms, do: @invalid_terms @@ -309,18 +332,17 @@ defmodule RDF.Vocabulary.Namespace do defp handle_invalid_terms!(invalid_terms) do raise RDF.Namespace.InvalidTermError, """ - The following terms can not be used, because they conflict with the Elixir semantics: + The following terms can not be used, because they conflict with the Elixir semantics: - - #{Enum.join(invalid_terms, "\n- ")} + - #{Enum.join(invalid_terms, "\n- ")} - You have the following options: + You have the following options: - - define an alias with the :alias option on defvocab - - ignore the resource with the :ignore option on defvocab - """ + - define an alias with the :alias option on defvocab + - ignore the resource with the :ignore option on defvocab + """ end - defp validate_characters!(terms, opts) do if (handling = Keyword.get(opts, :invalid_characters, :fail)) == :ignore do terms @@ -333,8 +355,7 @@ defmodule RDF.Vocabulary.Namespace do defp detect_invalid_characters(terms) do with aliased_terms = aliased_terms(terms) do - for {term, _} <- terms, term not in aliased_terms and not valid_characters?(term), - do: term + for {term, _} <- terms, term not in aliased_terms and not valid_characters?(term), do: term end end @@ -342,32 +363,35 @@ defmodule RDF.Vocabulary.Namespace do defp handle_invalid_characters(invalid_terms, :fail, _) do raise RDF.Namespace.InvalidTermError, """ - The following terms contain invalid characters: + The following terms contain invalid characters: - - #{Enum.join(invalid_terms, "\n- ")} + - #{Enum.join(invalid_terms, "\n- ")} - You have the following options: + You have the following options: - - if you are in control of the vocabulary, consider renaming the resource - - define an alias with the :alias option on defvocab - - change the handling of invalid characters with the :invalid_characters option on defvocab - - ignore the resource with the :ignore option on defvocab - """ + - if you are in control of the vocabulary, consider renaming the resource + - define an alias with the :alias option on defvocab + - change the handling of invalid characters with the :invalid_characters option on defvocab + - ignore the resource with the :ignore option on defvocab + """ end defp handle_invalid_characters(invalid_terms, :warn, terms) do - Enum.each invalid_terms, fn term -> - IO.warn "'#{term}' is not valid term, since it contains invalid characters" - end + Enum.each(invalid_terms, fn term -> + IO.warn("'#{term}' is not valid term, since it contains invalid characters") + end) + terms end defp valid_characters?(term) when is_atom(term), do: valid_characters?(Atom.to_string(term)) + defp valid_characters?(term), do: Regex.match?(~r/^[a-zA-Z_]\w*$/, term) defp validate_case!(terms, nil, _, _), do: terms + defp validate_case!(terms, data, base_iri, opts) do if (handling = Keyword.get(opts, :case_violations, :warn)) == :ignore do terms @@ -381,40 +405,43 @@ defmodule RDF.Vocabulary.Namespace do defp detect_case_violations(terms, data, base_iri) do aliased_terms = aliased_terms(terms) + terms |> Enum.filter(fn {term, _} -> - not(Atom.to_string(term) |> String.starts_with?("_")) - end) + not (Atom.to_string(term) |> String.starts_with?("_")) + end) |> Enum.filter(fn - {term, true} -> - if term not in aliased_terms do - proper_case?(term, base_iri, Atom.to_string(term), data) - end - {term, original_term} -> - proper_case?(term, base_iri, original_term, data) - end) + {term, true} -> + if term not in aliased_terms do + proper_case?(term, base_iri, Atom.to_string(term), data) + end + + {term, original_term} -> + proper_case?(term, base_iri, original_term, data) + end) end defp proper_case?(term, base_iri, iri_suffix, data) do case ResourceClassifier.property?(term_to_iri(base_iri, iri_suffix), data) do - true -> not lowercase?(term) + true -> not lowercase?(term) false -> lowercase?(term) - nil -> lowercase?(term) + nil -> lowercase?(term) end end defp group_case_violations(violations) do violations |> Enum.group_by(fn - {term, true} -> - if lowercase?(term), - do: :lowercased_term, - else: :capitalized_term - {term, _original} -> - if lowercase?(term), - do: :lowercased_alias, - else: :capitalized_alias - end) + {term, true} -> + if lowercase?(term), + do: :lowercased_term, + else: :capitalized_term + + {term, _original} -> + if lowercase?(term), + do: :lowercased_alias, + else: :capitalized_alias + end) end defp handle_case_violations(%{} = violations, _, terms, _, _) when map_size(violations) == 0, @@ -427,101 +454,106 @@ defmodule RDF.Vocabulary.Namespace do |> Enum.map(&to_string/1) |> Enum.join("\n- ") end + alias_violations = fn violations -> violations |> Enum.map(fn {term, original} -> - "alias #{term} for #{term_to_iri(base_iri, original)}" - end) + "alias #{term} for #{term_to_iri(base_iri, original)}" + end) |> Enum.join("\n- ") end violation_error_lines = violations |> Enum.map(fn - {:capitalized_term, violations} -> - """ - Terms for properties should be lowercased, but the following properties are - capitalized: + {:capitalized_term, violations} -> + """ + Terms for properties should be lowercased, but the following properties are + capitalized: - - #{resource_name_violations.(violations)} + - #{resource_name_violations.(violations)} - """ - {:lowercased_term, violations} -> - """ - Terms for non-property resource should be capitalized, but the following - non-properties are lowercased: + """ - - #{resource_name_violations.(violations)} + {:lowercased_term, violations} -> + """ + Terms for non-property resource should be capitalized, but the following + non-properties are lowercased: - """ - {:capitalized_alias, violations} -> - """ - Terms for properties should be lowercased, but the following aliases for - properties are capitalized: + - #{resource_name_violations.(violations)} - - #{alias_violations.(violations)} + """ - """ - {:lowercased_alias, violations} -> - """ - Terms for non-property resource should be capitalized, but the following - aliases for non-properties are lowercased: + {:capitalized_alias, violations} -> + """ + Terms for properties should be lowercased, but the following aliases for + properties are capitalized: - - #{alias_violations.(violations)} + - #{alias_violations.(violations)} - """ - end) - |> Enum.join + """ + + {:lowercased_alias, violations} -> + """ + Terms for non-property resource should be capitalized, but the following + aliases for non-properties are lowercased: + + - #{alias_violations.(violations)} + + """ + end) + |> Enum.join() raise RDF.Namespace.InvalidTermError, """ - Case violations detected + Case violations detected - #{violation_error_lines} - You have the following options: + #{violation_error_lines} + You have the following options: - - if you are in control of the vocabulary, consider renaming the resource - - define a properly cased alias with the :alias option on defvocab - - change the handling of case violations with the :case_violations option on defvocab - - ignore the resource with the :ignore option on defvocab - """ + - if you are in control of the vocabulary, consider renaming the resource + - define a properly cased alias with the :alias option on defvocab + - change the handling of case violations with the :case_violations option on defvocab + - ignore the resource with the :ignore option on defvocab + """ end - defp handle_case_violations(violations, :warn, terms, base_iri, _) do for {type, violations} <- violations, - {term, original} <- violations do + {term, original} <- violations do case_violation_warning(type, term, original, base_iri) end + terms end defp case_violation_warning(:capitalized_term, term, _, base_iri) do - IO.warn "'#{term_to_iri(base_iri, term)}' is a capitalized property" + IO.warn("'#{term_to_iri(base_iri, term)}' is a capitalized property") end defp case_violation_warning(:lowercased_term, term, _, base_iri) do - IO.warn "'#{term_to_iri(base_iri, term)}' is a lowercased non-property resource" + IO.warn("'#{term_to_iri(base_iri, term)}' is a lowercased non-property resource") end defp case_violation_warning(:capitalized_alias, term, _, _) do - IO.warn "capitalized alias '#{term}' for a property" + IO.warn("capitalized alias '#{term}' for a property") end defp case_violation_warning(:lowercased_alias, term, _, _) do - IO.warn "lowercased alias '#{term}' for a non-property resource" + IO.warn("lowercased alias '#{term}' for a non-property resource") end - defp filename!(opts) do if filename = Keyword.get(opts, :file) do cond do File.exists?(filename) -> filename + File.exists?(expanded_filename = Path.expand(filename, @vocabs_dir)) -> expanded_filename + true -> raise File.Error, path: filename, action: "find", reason: :enoent - end + end end end @@ -532,13 +564,13 @@ defmodule RDF.Vocabulary.Namespace do defp rdf_data_vocab_terms(data, base_iri) do data - |> RDF.Data.resources + |> RDF.Data.resources() |> Stream.filter(fn - %RDF.IRI{} -> true - _ -> false - end) + %RDF.IRI{} -> true + _ -> false + end) |> Stream.map(&to_string/1) - |> Stream.map(&(strip_base_iri(&1, base_iri))) + |> Stream.map(&strip_base_iri(&1, base_iri)) |> Stream.filter(&vocab_term?/1) |> Enum.map(&String.to_atom/1) end @@ -546,17 +578,18 @@ defmodule RDF.Vocabulary.Namespace do defp group_terms_by_case(terms) do terms |> Enum.group_by(fn {term, _} -> - if lowercase?(term), - do: :lowercased, - else: :capitalized - end) + if lowercase?(term), + do: :lowercased, + else: :capitalized + end) |> Map.new(fn {group, term_mapping} -> - {group, Map.new(term_mapping)} - end) + {group, Map.new(term_mapping)} + end) end defp lowercase?(term) when is_atom(term), do: Atom.to_string(term) |> lowercase? + defp lowercase?(term), do: term =~ ~r/^(_|\p{Ll})/u @@ -567,15 +600,18 @@ defmodule RDF.Vocabulary.Namespace do end defp vocab_term?(""), do: false + defp vocab_term?(term) when is_binary(term) do not String.contains?(term, "/") end + defp vocab_term?(_), do: false @doc false - @spec term_to_iri(String.t, String.t | atom) :: RDF.IRI.t + @spec term_to_iri(String.t(), String.t() | atom) :: RDF.IRI.t() def term_to_iri(base_iri, term) when is_atom(term), do: term_to_iri(base_iri, Atom.to_string(term)) + def term_to_iri(base_iri, term), do: RDF.iri(base_iri <> term) @@ -587,5 +623,4 @@ defmodule RDF.Vocabulary.Namespace do _ -> false end end - end diff --git a/lib/rdf/xsd.ex b/lib/rdf/xsd.ex index 150065a..8cb467a 100644 --- a/lib/rdf/xsd.ex +++ b/lib/rdf/xsd.ex @@ -49,6 +49,7 @@ defmodule RDF.XSD do defdelegate unquote(String.to_atom(datatype.name))(value, opts), to: datatype, as: :new elixir_name = Macro.underscore(datatype.name) + unless datatype.name == elixir_name do defdelegate unquote(String.to_atom(elixir_name))(value), to: datatype, as: :new defdelegate unquote(String.to_atom(elixir_name))(value, opts), to: datatype, as: :new @@ -58,6 +59,6 @@ defmodule RDF.XSD do defdelegate datetime(value), to: XSD.DateTime, as: :new defdelegate datetime(value, opts), to: XSD.DateTime, as: :new - defdelegate unquote(true)(), to: XSD.Boolean.Value + defdelegate unquote(true)(), to: XSD.Boolean.Value defdelegate unquote(false)(), to: XSD.Boolean.Value end diff --git a/lib/rdf/xsd/datatype.ex b/lib/rdf/xsd/datatype.ex index 8074fab..845fc38 100644 --- a/lib/rdf/xsd/datatype.ex +++ b/lib/rdf/xsd/datatype.ex @@ -174,6 +174,7 @@ defmodule RDF.XSD.Datatype do @doc false def most_specific(left, right) def most_specific(datatype, datatype), do: datatype + def most_specific(left, right) do cond do left.datatype?(right) -> right @@ -182,7 +183,6 @@ defmodule RDF.XSD.Datatype do end end - defmacro __using__(opts) do quote do defstruct [:value, :uncanonical_lexical] @@ -201,10 +201,10 @@ defmodule RDF.XSD.Datatype do } @doc !""" - This function is just used to check if a module is a RDF.XSD.Datatype. + This function is just used to check if a module is a RDF.XSD.Datatype. - See `RDF.Literal.Datatype.Registry.is_xsd_datatype?/1`. - """ + See `RDF.Literal.Datatype.Registry.is_xsd_datatype?/1`. + """ def __xsd_datatype_indicator__, do: true @doc """ @@ -214,19 +214,23 @@ defmodule RDF.XSD.Datatype do def datatype?(%RDF.Literal{literal: literal}), do: datatype?(literal) def datatype?(%datatype{}), do: datatype?(datatype) def datatype?(__MODULE__), do: true + def datatype?(datatype) when maybe_module(datatype) do RDF.XSD.datatype?(datatype) and datatype.derived_from?(__MODULE__) end + def datatype?(_), do: false @doc false def datatype!(%__MODULE__{}), do: true - def datatype!((%datatype{} = literal)) do + + def datatype!(%datatype{} = literal) do datatype?(datatype) || raise RDF.XSD.Datatype.Mismatch, value: literal, expected_type: __MODULE__ end + def datatype!(value), - do: raise RDF.XSD.Datatype.Mismatch, value: value, expected_type: __MODULE__ + do: raise(RDF.XSD.Datatype.Mismatch, value: value, expected_type: __MODULE__) @doc """ Creates a new `RDF.Literal` with this datatype and the given `value`. @@ -288,7 +292,8 @@ defmodule RDF.XSD.Datatype do end @doc false - @spec build_valid(any, RDF.XSD.Datatype.uncanonical_lexical(), Keyword.t()) :: RDF.Literal.t() + @spec build_valid(any, RDF.XSD.Datatype.uncanonical_lexical(), Keyword.t()) :: + RDF.Literal.t() def build_valid(value, lexical, opts) do if Keyword.get(opts, :canonicalize) do literal(%__MODULE__{value: value}) @@ -310,7 +315,6 @@ defmodule RDF.XSD.Datatype do literal(%__MODULE__{uncanonical_lexical: init_invalid_lexical(lexical, opts)}) end - @doc """ Returns the value of a `RDF.Literal` of this or a derived datatype. """ @@ -342,7 +346,10 @@ defmodule RDF.XSD.Datatype do """ @impl RDF.Literal.Datatype def canonical_lexical(%RDF.Literal{literal: literal}), do: canonical_lexical(literal) - def canonical_lexical(%__MODULE__{value: value}) when not is_nil(value), do: canonical_mapping(value) + + def canonical_lexical(%__MODULE__{value: value}) when not is_nil(value), + do: canonical_mapping(value) + def canonical_lexical(_), do: nil @doc """ @@ -380,13 +387,16 @@ defmodule RDF.XSD.Datatype do def valid?(%RDF.Literal{literal: literal}), do: valid?(literal) def valid?(%__MODULE__{value: @invalid_value}), do: false def valid?(%__MODULE__{}), do: true - def valid?((%datatype{} = literal)), + + def valid?(%datatype{} = literal), do: datatype?(datatype) and datatype.valid?(literal) + def valid?(_), do: false @doc false defp equality_path(left_datatype, right_datatype) defp equality_path(datatype, datatype), do: {:same_or_derived, datatype} + defp equality_path(left_datatype, right_datatype) do if RDF.XSD.datatype?(left_datatype) and RDF.XSD.datatype?(right_datatype) do if datatype = RDF.XSD.Datatype.most_specific(left_datatype, right_datatype) do @@ -399,7 +409,6 @@ defmodule RDF.XSD.Datatype do end end - @doc """ Compares two `RDF.Literal`s. @@ -409,14 +418,15 @@ defmodule RDF.XSD.Datatype do due to their datatype, or `:indeterminate` is returned, when the order of the given values is not defined on only partially ordered datatypes. """ - @spec compare(RDF.Literal.t() | any, RDF.Literal.t() | any) :: RDF.Literal.Datatype.comparison_result | :indeterminate | nil + @spec compare(RDF.Literal.t() | any, RDF.Literal.t() | any) :: + RDF.Literal.Datatype.comparison_result() | :indeterminate | nil def compare(left, right) def compare(left, %RDF.Literal{literal: right}), do: compare(left, right) def compare(%RDF.Literal{literal: left}, right), do: compare(left, right) def compare(left, right) do if RDF.XSD.datatype?(left) and RDF.XSD.datatype?(right) and - RDF.Literal.Datatype.valid?(left) and RDF.Literal.Datatype.valid?(right) do + RDF.Literal.Datatype.valid?(left) and RDF.Literal.Datatype.valid?(right) do do_compare(left, right) end end diff --git a/lib/rdf/xsd/datatype/primitive.ex b/lib/rdf/xsd/datatype/primitive.ex index ce78b0c..5e615ee 100644 --- a/lib/rdf/xsd/datatype/primitive.ex +++ b/lib/rdf/xsd/datatype/primitive.ex @@ -58,25 +58,33 @@ defmodule RDF.XSD.Datatype.Primitive do @impl RDF.Literal.Datatype def do_cast(value) do - if datatype?(value) do # i.e. derived datatype + # i.e. derived datatype + if datatype?(value) do build_valid(value.value, value.uncanonical_lexical, []) end end @impl RDF.Literal.Datatype - def do_equal_value_same_or_derived_datatypes?(%left_datatype{} = left, %right_datatype{} = right) do + def do_equal_value_same_or_derived_datatypes?( + %left_datatype{} = left, + %right_datatype{} = right + ) do left_datatype.value(left) == right_datatype.value(right) end @impl RDF.Literal.Datatype def do_equal_value_different_datatypes?(left, right), do: nil - @impl RDF.Literal.Datatype + @impl RDF.Literal.Datatype def do_compare(%left_datatype{} = left, %right_datatype{} = right) do if left_datatype.datatype?(right_datatype) or right_datatype.datatype?(left_datatype) do case {left_datatype.value(left), right_datatype.value(right)} do - {left_value, right_value} when left_value < right_value -> :lt - {left_value, right_value} when left_value > right_value -> :gt + {left_value, right_value} when left_value < right_value -> + :lt + + {left_value, right_value} when left_value > right_value -> + :gt + _ -> if left_datatype.equal_value?(left, right), do: :eq end diff --git a/lib/rdf/xsd/datatypes/any_uri.ex b/lib/rdf/xsd/datatypes/any_uri.ex index 5abae44..7fcbccd 100644 --- a/lib/rdf/xsd/datatypes/any_uri.ex +++ b/lib/rdf/xsd/datatypes/any_uri.ex @@ -15,7 +15,6 @@ defmodule RDF.XSD.AnyURI do import RDF.Guards - def_applicable_facet XSD.Facets.MinLength def_applicable_facet XSD.Facets.MaxLength def_applicable_facet XSD.Facets.Length @@ -41,7 +40,6 @@ defmodule RDF.XSD.AnyURI do XSD.Facets.Pattern.conform?(pattern, lexical) end - @impl XSD.Datatype @spec lexical_mapping(String.t(), Keyword.t()) :: valid_value def lexical_mapping(lexical, _), do: URI.parse(lexical) diff --git a/lib/rdf/xsd/datatypes/boolean.ex b/lib/rdf/xsd/datatypes/boolean.ex index 33e3c15..c0bcafd 100644 --- a/lib/rdf/xsd/datatypes/boolean.ex +++ b/lib/rdf/xsd/datatypes/boolean.ex @@ -12,7 +12,6 @@ defmodule RDF.XSD.Boolean do alias RDF.XSD - def_applicable_facet XSD.Facets.Pattern @doc false @@ -20,7 +19,6 @@ defmodule RDF.XSD.Boolean do XSD.Facets.Pattern.conform?(pattern, lexical) end - @impl XSD.Datatype def lexical_mapping(lexical, _) do with lexical do @@ -142,6 +140,7 @@ defmodule RDF.XSD.Boolean do @spec fn_not(input_value) :: t() | nil def fn_not(value) def fn_not(%RDF.Literal{literal: literal}), do: fn_not(literal) + def fn_not(value) do case ebv(value) do %RDF.Literal{literal: %__MODULE__{value: true}} -> XSD.Boolean.Value.false() @@ -177,6 +176,7 @@ defmodule RDF.XSD.Boolean do def logical_and(left, right) def logical_and(%RDF.Literal{literal: left}, right), do: logical_and(left, right) def logical_and(left, %RDF.Literal{literal: right}), do: logical_and(left, right) + def logical_and(left, right) do case ebv(left) do %RDF.Literal{literal: %__MODULE__{value: false}} -> @@ -223,6 +223,7 @@ defmodule RDF.XSD.Boolean do def logical_or(left, right) def logical_or(%RDF.Literal{literal: left}, right), do: logical_or(left, right) def logical_or(left, %RDF.Literal{literal: right}), do: logical_or(left, right) + def logical_or(left, right) do case ebv(left) do %RDF.Literal{literal: %__MODULE__{value: true}} -> diff --git a/lib/rdf/xsd/datatypes/boolean_values.ex b/lib/rdf/xsd/datatypes/boolean_values.ex index 3997cc1..6b89277 100644 --- a/lib/rdf/xsd/datatypes/boolean_values.ex +++ b/lib/rdf/xsd/datatypes/boolean_values.ex @@ -1,14 +1,14 @@ defmodule RDF.XSD.Boolean.Value do @moduledoc !""" - This module holds the two boolean value literals, so they can be accessed - directly without needing to construct them every time. - They can't be defined in the RDF.XSD.Boolean module, because we can not use - the `RDF.XSD.Boolean.new` function without having it compiled first. - """ + This module holds the two boolean value literals, so they can be accessed + directly without needing to construct them every time. + They can't be defined in the RDF.XSD.Boolean module, because we can not use + the `RDF.XSD.Boolean.new` function without having it compiled first. + """ - @xsd_true RDF.XSD.Boolean.new(true) + @xsd_true RDF.XSD.Boolean.new(true) @xsd_false RDF.XSD.Boolean.new(false) - def unquote(:true)(), do: @xsd_true - def unquote(:false)(), do: @xsd_false + def unquote(true)(), do: @xsd_true + def unquote(false)(), do: @xsd_false end diff --git a/lib/rdf/xsd/datatypes/date.ex b/lib/rdf/xsd/datatypes/date.ex index 89cb407..dc1a358 100644 --- a/lib/rdf/xsd/datatypes/date.ex +++ b/lib/rdf/xsd/datatypes/date.ex @@ -16,7 +16,6 @@ defmodule RDF.XSD.Date do alias RDF.XSD - def_applicable_facet XSD.Facets.ExplicitTimezone def_applicable_facet XSD.Facets.Pattern @@ -32,7 +31,6 @@ defmodule RDF.XSD.Date do XSD.Facets.Pattern.conform?(pattern, lexical) end - # TODO: Are GMT/UTC actually allowed? Maybe because it is supported by Elixir's Datetime ... @grammar ~r/\A(-?\d{4}-\d{2}-\d{2})((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z/ @tz_grammar ~r/\A((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)\Z/ @@ -165,7 +163,6 @@ defmodule RDF.XSD.Date do end end - @impl RDF.Literal.Datatype def do_equal_value_same_or_derived_datatypes?(left, right) do XSD.DateTime.equal_value?( diff --git a/lib/rdf/xsd/datatypes/date_time.ex b/lib/rdf/xsd/datatypes/date_time.ex index a7ff417..eef1928 100644 --- a/lib/rdf/xsd/datatypes/date_time.ex +++ b/lib/rdf/xsd/datatypes/date_time.ex @@ -11,7 +11,6 @@ defmodule RDF.XSD.DateTime do alias RDF.XSD - def_applicable_facet XSD.Facets.ExplicitTimezone def_applicable_facet XSD.Facets.Pattern @@ -27,7 +26,6 @@ defmodule RDF.XSD.DateTime do XSD.Facets.Pattern.conform?(pattern, lexical) end - @impl XSD.Datatype def lexical_mapping(lexical, opts) do case DateTime.from_iso8601(lexical) do @@ -120,6 +118,7 @@ defmodule RDF.XSD.DateTime do def tz(xsd_datetime) def tz(%RDF.Literal{literal: xsd_datetime}), do: tz(xsd_datetime) def tz(%__MODULE__{value: %NaiveDateTime{}}), do: "" + def tz(date_time_literal) do if valid?(date_time_literal) do date_time_literal @@ -134,6 +133,7 @@ defmodule RDF.XSD.DateTime do @spec canonical_lexical_with_zone(RDF.Literal.t() | t()) :: String.t() | nil def canonical_lexical_with_zone(%RDF.Literal{literal: xsd_datetime}), do: canonical_lexical_with_zone(xsd_datetime) + def canonical_lexical_with_zone(%__MODULE__{} = xsd_datetime) do case tz(xsd_datetime) do nil -> diff --git a/lib/rdf/xsd/datatypes/decimal.ex b/lib/rdf/xsd/datatypes/decimal.ex index 85bcd50..2385c24 100644 --- a/lib/rdf/xsd/datatypes/decimal.ex +++ b/lib/rdf/xsd/datatypes/decimal.ex @@ -12,7 +12,6 @@ defmodule RDF.XSD.Decimal do alias RDF.XSD alias Elixir.Decimal, as: D - def_applicable_facet XSD.Facets.MinInclusive def_applicable_facet XSD.Facets.MaxInclusive def_applicable_facet XSD.Facets.MinExclusive @@ -56,7 +55,6 @@ defmodule RDF.XSD.Decimal do XSD.Facets.Pattern.conform?(pattern, lexical) end - @impl XSD.Datatype def lexical_mapping(lexical, opts) do if String.contains?(lexical, ~w[e E]) do @@ -136,7 +134,7 @@ defmodule RDF.XSD.Decimal do XSD.Boolean.datatype?(literal) -> case literal.value do false -> new(0.0) - true -> new(1.0) + true -> new(1.0) end XSD.Integer.datatype?(literal) -> @@ -151,13 +149,13 @@ defmodule RDF.XSD.Decimal do end end + @impl RDF.Literal.Datatype + def do_equal_value_same_or_derived_datatypes?(left, right), + do: XSD.Numeric.do_equal_value?(left, right) @impl RDF.Literal.Datatype - def do_equal_value_same_or_derived_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right) - - @impl RDF.Literal.Datatype - def do_equal_value_different_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right) - + def do_equal_value_different_datatypes?(left, right), + do: XSD.Numeric.do_equal_value?(left, right) @impl RDF.Literal.Datatype def do_compare(left, right), do: XSD.Numeric.do_compare(left, right) @@ -179,7 +177,8 @@ defmodule RDF.XSD.Decimal do |> datatype.canonical_lexical() |> do_digit_count() - true -> nil + true -> + nil end end @@ -195,17 +194,21 @@ defmodule RDF.XSD.Decimal do The number of digits to the right of the decimal point in the XML Schema canonical form of the literal value. """ @spec fraction_digit_count(RDF.Literal.t()) :: non_neg_integer | nil - def fraction_digit_count(%RDF.Literal{literal: datatype_literal}), do: fraction_digit_count(datatype_literal) + def fraction_digit_count(%RDF.Literal{literal: datatype_literal}), + do: fraction_digit_count(datatype_literal) def fraction_digit_count(%datatype{} = literal) do cond do - XSD.Integer.datatype?(literal) -> 0 + XSD.Integer.datatype?(literal) -> + 0 + datatype?(literal) and datatype.valid?(literal) -> literal |> datatype.canonical_lexical() |> do_fraction_digit_count() - true -> nil + true -> + nil end end diff --git a/lib/rdf/xsd/datatypes/double.ex b/lib/rdf/xsd/datatypes/double.ex index 08a7425..96d5b2e 100644 --- a/lib/rdf/xsd/datatypes/double.ex +++ b/lib/rdf/xsd/datatypes/double.ex @@ -14,7 +14,6 @@ defmodule RDF.XSD.Double do alias RDF.XSD - def_applicable_facet XSD.Facets.MinInclusive def_applicable_facet XSD.Facets.MaxInclusive def_applicable_facet XSD.Facets.MinExclusive @@ -46,7 +45,6 @@ defmodule RDF.XSD.Double do XSD.Facets.Pattern.conform?(pattern, lexical) end - @impl XSD.Datatype def lexical_mapping(lexical, opts) do case Float.parse(lexical) do @@ -143,7 +141,7 @@ defmodule RDF.XSD.Double do XSD.Boolean.datatype?(literal) -> case literal.value do false -> new(0.0) - true -> new(1.0) + true -> new(1.0) end XSD.Integer.datatype?(literal) -> @@ -159,13 +157,13 @@ defmodule RDF.XSD.Double do end end + @impl RDF.Literal.Datatype + def do_equal_value_same_or_derived_datatypes?(left, right), + do: XSD.Numeric.do_equal_value?(left, right) @impl RDF.Literal.Datatype - def do_equal_value_same_or_derived_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right) - - @impl RDF.Literal.Datatype - def do_equal_value_different_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right) - + def do_equal_value_different_datatypes?(left, right), + do: XSD.Numeric.do_equal_value?(left, right) @impl RDF.Literal.Datatype def do_compare(left, right), do: XSD.Numeric.do_compare(left, right) diff --git a/lib/rdf/xsd/datatypes/integer.ex b/lib/rdf/xsd/datatypes/integer.ex index e0137f6..f858b5a 100644 --- a/lib/rdf/xsd/datatypes/integer.ex +++ b/lib/rdf/xsd/datatypes/integer.ex @@ -14,7 +14,6 @@ defmodule RDF.XSD.Integer do alias RDF.XSD - def_applicable_facet XSD.Facets.MinInclusive def_applicable_facet XSD.Facets.MaxInclusive def_applicable_facet XSD.Facets.MinExclusive @@ -52,7 +51,6 @@ defmodule RDF.XSD.Integer do XSD.Facets.Pattern.conform?(pattern, lexical) end - @impl XSD.Datatype def lexical_mapping(lexical, _) do case Integer.parse(lexical) do @@ -80,7 +78,7 @@ defmodule RDF.XSD.Integer do XSD.Boolean.datatype?(literal) -> case literal.value do false -> new(0) - true -> new(1) + true -> new(1) end XSD.Decimal.datatype?(literal) -> @@ -89,7 +87,8 @@ defmodule RDF.XSD.Integer do |> Decimal.to_integer() |> new() - is_float(literal.value) and XSD.Double.datatype?(literal) -> # we're catching the XSD.Floats with this too + # we're catching the XSD.Floats with this too + is_float(literal.value) and XSD.Double.datatype?(literal) -> literal.value |> trunc() |> new() @@ -100,10 +99,12 @@ defmodule RDF.XSD.Integer do end @impl RDF.Literal.Datatype - def do_equal_value_same_or_derived_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right) + def do_equal_value_same_or_derived_datatypes?(left, right), + do: XSD.Numeric.do_equal_value?(left, right) @impl RDF.Literal.Datatype - def do_equal_value_different_datatypes?(left, right), do: XSD.Numeric.do_equal_value?(left, right) + def do_equal_value_different_datatypes?(left, right), + do: XSD.Numeric.do_equal_value?(left, right) @impl RDF.Literal.Datatype def do_compare(left, right), do: XSD.Numeric.do_compare(left, right) diff --git a/lib/rdf/xsd/datatypes/numeric.ex b/lib/rdf/xsd/datatypes/numeric.ex index e92895d..16c9a9b 100644 --- a/lib/rdf/xsd/datatypes/numeric.ex +++ b/lib/rdf/xsd/datatypes/numeric.ex @@ -13,13 +13,13 @@ defmodule RDF.XSD.Numeric do defdelegate datatype?(value), to: Literal.Datatype.Registry, as: :numeric_datatype? @doc !""" - Tests for numeric value equality of two numeric XSD datatyped literals. + Tests for numeric value equality of two numeric XSD datatyped literals. - see: + see: - - - - - """ + - + - + """ @spec do_equal_value?(t() | any, t() | any) :: boolean def do_equal_value?(left, right) @@ -52,14 +52,14 @@ defmodule RDF.XSD.Numeric do defp new_decimal(value), do: D.new(value) @doc !""" - Compares two numeric XSD literals. + Compares two numeric XSD literals. - Returns `:gt` if first literal is greater than the second and `:lt` for vice - versa. If the two literals are equal `:eq` is returned. + Returns `:gt` if first literal is greater than the second and `:lt` for vice + versa. If the two literals are equal `:eq` is returned. - Returns `nil` when the given arguments are not comparable datatypes. + Returns `nil` when the given arguments are not comparable datatypes. - """ + """ @spec do_compare(t, t) :: Literal.Datatype.comparison_result() | nil def do_compare(left, right) @@ -68,9 +68,15 @@ defmodule RDF.XSD.Numeric do cond do XSD.Decimal.datatype?(left_datatype) or XSD.Decimal.datatype?(right_datatype) -> compare_decimal_value(left, right) - left < right -> :lt - left > right -> :gt - true -> :eq + + left < right -> + :lt + + left > right -> + :gt + + true -> + :eq end end end @@ -273,8 +279,9 @@ defmodule RDF.XSD.Numeric do |> datatype.base_primitive().new() value -> - target_datatype = if XSD.Float.datatype?(datatype), - do: XSD.Float, else: datatype.base_primitive() + target_datatype = + if XSD.Float.datatype?(datatype), do: XSD.Float, else: datatype.base_primitive() + value |> Kernel.abs() |> target_datatype.new() @@ -337,7 +344,7 @@ defmodule RDF.XSD.Numeric do |> XSD.Decimal.new() (float_datatype = XSD.Float.datatype?(datatype)) or - XSD.Double.datatype?(datatype) -> + XSD.Double.datatype?(datatype) -> if literal_value in ~w[nan positive_infinity negative_infinity]a do literal(value) else @@ -400,7 +407,7 @@ defmodule RDF.XSD.Numeric do |> XSD.Decimal.new() (float_datatype = XSD.Float.datatype?(datatype)) or - XSD.Double.datatype?(datatype) -> + XSD.Double.datatype?(datatype) -> if literal_value in ~w[nan positive_infinity negative_infinity]a do literal(value) else @@ -457,7 +464,7 @@ defmodule RDF.XSD.Numeric do |> XSD.Decimal.new() (float_datatype = XSD.Float.datatype?(datatype)) or - XSD.Double.datatype?(datatype) -> + XSD.Double.datatype?(datatype) -> if literal_value in ~w[nan positive_infinity negative_infinity]a do literal(value) else @@ -483,11 +490,15 @@ defmodule RDF.XSD.Numeric do end end - defp arithmetic_operation(op, %Literal{literal: literal1}, literal2, fun), do: arithmetic_operation(op, literal1, literal2, fun) - defp arithmetic_operation(op, literal1, %Literal{literal: literal2}, fun), do: arithmetic_operation(op, literal1, literal2, fun) + defp arithmetic_operation(op, %Literal{literal: literal1}, literal2, fun), + do: arithmetic_operation(op, literal1, literal2, fun) + + defp arithmetic_operation(op, literal1, %Literal{literal: literal2}, fun), + do: arithmetic_operation(op, literal1, literal2, fun) + defp arithmetic_operation(op, %datatype1{} = literal1, %datatype2{} = literal2, fun) do if datatype?(datatype1) and datatype?(datatype2) and - Literal.Datatype.valid?(literal1) and Literal.Datatype.valid?(literal2) do + Literal.Datatype.valid?(literal1) and Literal.Datatype.valid?(literal2) do result_type = result_type(op, datatype1, datatype2) {arg1, arg2} = type_conversion(literal1, literal2, result_type) result = fun.(arg1.value, arg2.value, result_type) @@ -538,7 +549,8 @@ defmodule RDF.XSD.Numeric do defp type_conversion(left, right, _), do: {left, right} @doc false - def result_type(op, left, right), do: do_result_type(op, base_primitive(left), base_primitive(right)) + def result_type(op, left, right), + do: do_result_type(op, base_primitive(left), base_primitive(right)) defp do_result_type(_, XSD.Double, _), do: XSD.Double defp do_result_type(_, _, XSD.Double), do: XSD.Double @@ -551,9 +563,10 @@ defmodule RDF.XSD.Numeric do defp base_primitive(datatype) do primitive = datatype.base_primitive() + if primitive == XSD.Double and XSD.Float.datatype?(datatype), - do: XSD.Float, - else: primitive + do: XSD.Float, + else: primitive end defp literal(value), do: %Literal{literal: value} diff --git a/lib/rdf/xsd/datatypes/string.ex b/lib/rdf/xsd/datatypes/string.ex index 414366d..5cc0613 100644 --- a/lib/rdf/xsd/datatypes/string.ex +++ b/lib/rdf/xsd/datatypes/string.ex @@ -11,7 +11,6 @@ defmodule RDF.XSD.String do alias RDF.XSD - def_applicable_facet XSD.Facets.MinLength def_applicable_facet XSD.Facets.MaxLength def_applicable_facet XSD.Facets.Length @@ -37,7 +36,6 @@ defmodule RDF.XSD.String do XSD.Facets.Pattern.conform?(pattern, value) end - @impl XSD.Datatype @spec lexical_mapping(String.t(), Keyword.t()) :: valid_value def lexical_mapping(lexical, _), do: to_string(lexical) diff --git a/lib/rdf/xsd/datatypes/time.ex b/lib/rdf/xsd/datatypes/time.ex index 5f128d5..f5f61ef 100644 --- a/lib/rdf/xsd/datatypes/time.ex +++ b/lib/rdf/xsd/datatypes/time.ex @@ -20,7 +20,6 @@ defmodule RDF.XSD.Time do @grammar ~r/\A(\d{2}:\d{2}:\d{2}(?:\.\d+)?)((?:[\+\-]\d{2}:\d{2})|UTC|GMT|Z)?\Z/ @tz_number_grammar ~r/\A(?:([\+\-])(\d{2}):(\d{2}))\Z/ - def_applicable_facet XSD.Facets.ExplicitTimezone def_applicable_facet XSD.Facets.Pattern @@ -36,7 +35,6 @@ defmodule RDF.XSD.Time do XSD.Facets.Pattern.conform?(pattern, lexical) end - @impl XSD.Datatype def lexical_mapping(lexical, opts) do case Regex.run(@grammar, lexical) do @@ -196,8 +194,15 @@ defmodule RDF.XSD.Time do @impl RDF.Literal.Datatype def do_equal_value_same_or_derived_datatypes?(left, right) - def do_equal_value_same_or_derived_datatypes?(%{value: %{}}, %{value: tz_tuple}) when is_tuple(tz_tuple), do: nil - def do_equal_value_same_or_derived_datatypes?(%{value: tz_tuple}, %{value: %{}}) when is_tuple(tz_tuple), do: nil + + def do_equal_value_same_or_derived_datatypes?(%{value: %{}}, %{value: tz_tuple}) + when is_tuple(tz_tuple), + do: nil + + def do_equal_value_same_or_derived_datatypes?(%{value: tz_tuple}, %{value: %{}}) + when is_tuple(tz_tuple), + do: nil + def do_equal_value_same_or_derived_datatypes?(left, right), do: super(left, right) @doc """ @@ -216,7 +221,8 @@ defmodule RDF.XSD.Time do """ @spec canonical_lexical_with_zone(RDF.Literal.t() | t()) :: String.t() | nil def canonical_lexical_with_zone(%RDF.Literal{literal: xsd_time}), - do: canonical_lexical_with_zone(xsd_time) + do: canonical_lexical_with_zone(xsd_time) + def canonical_lexical_with_zone(%__MODULE__{} = xsd_time) do case tz(xsd_time) do nil -> diff --git a/lib/rdf/xsd/facets/pattern.ex b/lib/rdf/xsd/facets/pattern.ex index 9a3b178..f1f2cfa 100644 --- a/lib/rdf/xsd/facets/pattern.ex +++ b/lib/rdf/xsd/facets/pattern.ex @@ -1,13 +1,13 @@ defmodule RDF.XSD.Facets.Pattern do - use RDF.XSD.Facet, name: :pattern, type: String.t | [String.t] + use RDF.XSD.Facet, name: :pattern, type: String.t() | [String.t()] @doc !""" - A generic implementation for the `pattern_conform?/3` on the datatypes. - """ + A generic implementation for the `pattern_conform?/3` on the datatypes. + """ def conform?(pattern, lexical) def conform?(patterns, lexical) when is_list(patterns) do - Enum.any?(patterns, &(conform?(&1, lexical))) + Enum.any?(patterns, &conform?(&1, lexical)) end def conform?(pattern, lexical) do diff --git a/lib/rdf/xsd/utils/regex.ex b/lib/rdf/xsd/utils/regex.ex index 48ae28c..337d263 100644 --- a/lib/rdf/xsd/utils/regex.ex +++ b/lib/rdf/xsd/utils/regex.ex @@ -1,11 +1,11 @@ defmodule RDF.XSD.Utils.Regex do @moduledoc !""" - XSD-flavoured regex matching. + XSD-flavoured regex matching. - This is not intended to be used directly. - Use `c:RDF.XSD.Datatype.matches?/3` implementations on the datatypes or - `RDF.Literal.matches?/3` instead. - """ + This is not intended to be used directly. + Use `c:RDF.XSD.Datatype.matches?/3` implementations on the datatypes or + `RDF.Literal.matches?/3` instead. + """ @doc """ Matches the string representation of the given value against a XPath and XQuery regular expression pattern. diff --git a/mix.exs b/mix.exs index 723e355..e8ec15d 100644 --- a/mix.exs +++ b/mix.exs @@ -3,18 +3,18 @@ defmodule RDF.Mixfile do @repo_url "https://github.com/rdf-elixir/rdf-ex" - @version File.read!("VERSION") |> String.trim + @version File.read!("VERSION") |> String.trim() def project do [ app: :rdf, version: @version, elixir: "~> 1.8", - build_embedded: Mix.env == :prod, - start_permanent: Mix.env == :prod, + build_embedded: Mix.env() == :prod, + start_permanent: Mix.env() == :prod, deps: deps(), elixirc_paths: elixirc_paths(Mix.env()), - compilers: Mix.compilers ++ [:protocol_ex], + compilers: Mix.compilers() ++ [:protocol_ex], # Dialyzer dialyzer: dialyzer(), @@ -29,7 +29,7 @@ defmodule RDF.Mixfile do main: "RDF", source_url: @repo_url, source_ref: "v#{@version}", - extras: ["CHANGELOG.md"], + extras: ["CHANGELOG.md"] ], # ExCoveralls @@ -39,7 +39,7 @@ defmodule RDF.Mixfile do "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test - ], + ] ] end @@ -56,7 +56,7 @@ defmodule RDF.Mixfile do links: %{ "Homepage" => "https://rdf-elixir.dev", "GitHub" => @repo_url, - "Changelog" => @repo_url <> "/blob/master/CHANGELOG.md", + "Changelog" => @repo_url <> "/blob/master/CHANGELOG.md" }, files: ~w[lib src/*.xrl src/*.yrl priv mix.exs .formatter.exs VERSION *.md] ] @@ -70,13 +70,11 @@ defmodule RDF.Mixfile do [ {:decimal, "~> 1.5"}, {:protocol_ex, "~> 0.4"}, - - {:credo, "~> 1.4", only: [:dev, :test], runtime: false}, - {:dialyxir, "~> 1.0", only: :dev, runtime: false}, - {:ex_doc, "~> 0.22", only: :dev, runtime: false}, - {:excoveralls, "~> 0.13", only: :test}, - - {:benchee, "~> 1.0", only: :bench}, + {:credo, "~> 1.4", only: [:dev, :test], runtime: false}, + {:dialyxir, "~> 1.0", only: :dev, runtime: false}, + {:ex_doc, "~> 0.22", only: :dev, runtime: false}, + {:excoveralls, "~> 0.13", only: :test}, + {:benchee, "~> 1.0", only: :bench} ] end @@ -89,5 +87,5 @@ defmodule RDF.Mixfile do end defp elixirc_paths(:test), do: ["lib", "test/support"] - defp elixirc_paths(_), do: ["lib"] + defp elixirc_paths(_), do: ["lib"] end diff --git a/test/acceptance/nquads_w3c_test.exs b/test/acceptance/nquads_w3c_test.exs index fb87f49..3315447 100644 --- a/test/acceptance/nquads_w3c_test.exs +++ b/test/acceptance/nquads_w3c_test.exs @@ -7,15 +7,14 @@ defmodule RDF.NQuads.W3C.TestSuite do use ExUnit.Case, async: false - @w3c_nquads_test_suite Path.join(RDF.TestData.dir, "N-QUADS-TESTS") + @w3c_nquads_test_suite Path.join(RDF.TestData.dir(), "N-QUADS-TESTS") - - ExUnit.Case.register_attribute __ENV__, :nq_test + ExUnit.Case.register_attribute(__ENV__, :nq_test) @w3c_nquads_test_suite - |> File.ls! - |> Enum.filter(fn (file) -> Path.extname(file) == ".nq" end) - |> Enum.each(fn (file) -> + |> File.ls!() + |> Enum.filter(fn file -> Path.extname(file) == ".nq" end) + |> Enum.each(fn file -> @nq_test file: Path.join(@w3c_nquads_test_suite, file) if file |> String.contains?("-bad-") do test "Negative syntax test: #{file}", context do @@ -27,5 +26,4 @@ defmodule RDF.NQuads.W3C.TestSuite do end end end) - end diff --git a/test/acceptance/ntriples_w3c_test.exs b/test/acceptance/ntriples_w3c_test.exs index 497f224..7f006a8 100644 --- a/test/acceptance/ntriples_w3c_test.exs +++ b/test/acceptance/ntriples_w3c_test.exs @@ -7,14 +7,14 @@ defmodule RDF.NTriples.W3C.TestSuite do use ExUnit.Case, async: false - @w3c_ntriples_test_suite Path.join(RDF.TestData.dir, "N-TRIPLES-TESTS") + @w3c_ntriples_test_suite Path.join(RDF.TestData.dir(), "N-TRIPLES-TESTS") - ExUnit.Case.register_attribute __ENV__, :nt_test + ExUnit.Case.register_attribute(__ENV__, :nt_test) @w3c_ntriples_test_suite - |> File.ls! - |> Enum.filter(fn (file) -> Path.extname(file) == ".nt" end) - |> Enum.each(fn (file) -> + |> File.ls!() + |> Enum.filter(fn file -> Path.extname(file) == ".nt" end) + |> Enum.each(fn file -> @nt_test file: Path.join(@w3c_ntriples_test_suite, file) if file |> String.contains?("-bad-") do test "Negative syntax test: #{file}", context do @@ -26,5 +26,4 @@ defmodule RDF.NTriples.W3C.TestSuite do end end end) - end diff --git a/test/acceptance/turtle_w3c_test.exs b/test/acceptance/turtle_w3c_test.exs index 4cf0636..43456cd 100644 --- a/test/acceptance/turtle_w3c_test.exs +++ b/test/acceptance/turtle_w3c_test.exs @@ -8,7 +8,7 @@ defmodule RDF.Turtle.W3C.Test do """ use ExUnit.Case, async: false - ExUnit.Case.register_attribute __ENV__, :test_case + ExUnit.Case.register_attribute(__ENV__, :test_case) alias RDF.{Turtle, TestSuite, NTriples} alias TestSuite.NS.RDFT @@ -17,8 +17,8 @@ defmodule RDF.Turtle.W3C.Test do TestSuite.test_cases("Turtle", RDFT.TestTurtleEval, base: @base) |> Enum.each(fn test_case -> - @tag test_case: test_case - if TestSuite.test_name(test_case) in ~w[ + @tag test_case: test_case + if TestSuite.test_name(test_case) in ~w[ anonymous_blank_node_subject anonymous_blank_node_object labeled_blank_node_subject @@ -45,58 +45,61 @@ defmodule RDF.Turtle.W3C.Test do turtle-subm-10 turtle-subm-14 ] do - @tag skip: """ - The produced graphs are correct, but have different blank node labels than the result graph. - TODO: Implement a graph isomorphism algorithm. - """ - end + @tag skip: """ + The produced graphs are correct, but have different blank node labels than the result graph. + TODO: Implement a graph isomorphism algorithm. + """ + end - test TestSuite.test_title(test_case), %{test_case: test_case} do - with base = to_string(TestSuite.test_input_file(test_case)) do - assert RDF.Graph.equal?( - (TestSuite.test_input_file_path(test_case, "Turtle") - |> Turtle.read_file!(base: base)), - (TestSuite.test_result_file_path(test_case, "Turtle") - |> NTriples.read_file!) - ) - end - end - end) + test TestSuite.test_title(test_case), %{test_case: test_case} do + with base = to_string(TestSuite.test_input_file(test_case)) do + assert RDF.Graph.equal?( + TestSuite.test_input_file_path(test_case, "Turtle") + |> Turtle.read_file!(base: base), + TestSuite.test_result_file_path(test_case, "Turtle") + |> NTriples.read_file!() + ) + end + end + end) TestSuite.test_cases("Turtle", RDFT.TestTurtlePositiveSyntax, base: @base) |> Enum.each(fn test_case -> - @tag test_case: test_case - test TestSuite.test_title(test_case), %{test_case: test_case} do - with base = to_string(TestSuite.test_input_file(test_case)) do - assert {:ok, _} = - TestSuite.test_input_file_path(test_case, "Turtle") |> Turtle.read_file(base: base) - end - end - end) + @tag test_case: test_case + test TestSuite.test_title(test_case), %{test_case: test_case} do + with base = to_string(TestSuite.test_input_file(test_case)) do + assert {:ok, _} = + TestSuite.test_input_file_path(test_case, "Turtle") + |> Turtle.read_file(base: base) + end + end + end) TestSuite.test_cases("Turtle", RDFT.TestTurtleNegativeSyntax, base: @base) |> Enum.each(fn test_case -> - @tag test_case: test_case - test TestSuite.test_title(test_case), %{test_case: test_case} do - with base = to_string(TestSuite.test_input_file(test_case)) do - assert {:error, _} = - TestSuite.test_input_file_path(test_case, "Turtle") |> Turtle.read_file(base: base) - end - end - end) + @tag test_case: test_case + test TestSuite.test_title(test_case), %{test_case: test_case} do + with base = to_string(TestSuite.test_input_file(test_case)) do + assert {:error, _} = + TestSuite.test_input_file_path(test_case, "Turtle") + |> Turtle.read_file(base: base) + end + end + end) TestSuite.test_cases("Turtle", RDFT.TestTurtleNegativeEval, base: @base) |> Enum.each(fn test_case -> - if TestSuite.test_name(test_case) in ~w[turtle-eval-bad-01 turtle-eval-bad-02 turtle-eval-bad-03] do - @tag skip: "TODO: IRI validation" - end - @tag test_case: test_case - test TestSuite.test_title(test_case), %{test_case: test_case} do - with base = to_string(TestSuite.test_input_file(test_case)) do - assert {:error, _} = - TestSuite.test_input_file_path(test_case, "Turtle") |> Turtle.read_file(base: base) - end - end - end) + if TestSuite.test_name(test_case) in ~w[turtle-eval-bad-01 turtle-eval-bad-02 turtle-eval-bad-03] do + @tag skip: "TODO: IRI validation" + end + @tag test_case: test_case + test TestSuite.test_title(test_case), %{test_case: test_case} do + with base = to_string(TestSuite.test_input_file(test_case)) do + assert {:error, _} = + TestSuite.test_input_file_path(test_case, "Turtle") + |> Turtle.read_file(base: base) + end + end + end) end diff --git a/test/support/rdf_case.ex b/test/support/rdf_case.ex index 3612ceb..7f3bee2 100644 --- a/test/support/rdf_case.ex +++ b/test/support/rdf_case.ex @@ -2,13 +2,9 @@ defmodule RDF.Test.Case do use ExUnit.CaseTemplate use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.com/", - terms: [], strict: false + defvocab EX, base_iri: "http://example.com/", terms: [], strict: false - defvocab FOAF, - base_iri: "http://xmlns.com/foaf/0.1/", - terms: [], strict: false + defvocab FOAF, base_iri: "http://xmlns.com/foaf/0.1/", terms: [], strict: false alias RDF.{Dataset, Graph, Description, IRI} import RDF, only: [iri: 1] @@ -31,11 +27,12 @@ defmodule RDF.Test.Case do ############################### # RDF.Description - def description, do: Description.new(EX.Subject) + def description, do: Description.new(EX.Subject) def description(content), do: Description.add(description(), content) def description_of_subject(%Description{subject: subject}, subject), do: true + def description_of_subject(_, _), do: false @@ -53,17 +50,17 @@ defmodule RDF.Test.Case do def graph, do: unnamed_graph() - def unnamed_graph, do: Graph.new + def unnamed_graph, do: Graph.new() def named_graph(name \\ EX.GraphName), do: Graph.new(name: name) def unnamed_graph?(%Graph{name: nil}), do: true - def unnamed_graph?(_), do: false + def unnamed_graph?(_), do: false - def named_graph?(%Graph{name: %IRI{}}), do: true - def named_graph?(_), do: false + def named_graph?(%Graph{name: %IRI{}}), do: true + def named_graph?(_), do: false def named_graph?(%Graph{name: name}, name), do: true - def named_graph?(_, _), do: false + def named_graph?(_, _), do: false def empty_graph?(%Graph{descriptions: descriptions}), do: descriptions == %{} @@ -74,40 +71,40 @@ defmodule RDF.Test.Case do |> Enum.member?(statement) end - ############################### # RDF.Dataset def dataset, do: unnamed_dataset() - def unnamed_dataset, do: Dataset.new + def unnamed_dataset, do: Dataset.new() def named_dataset(name \\ EX.DatasetName), do: Dataset.new(name: name) def unnamed_dataset?(%Dataset{name: nil}), do: true - def unnamed_dataset?(_), do: false + def unnamed_dataset?(_), do: false - def named_dataset?(%Dataset{name: %IRI{}}), do: true - def named_dataset?(_), do: false + def named_dataset?(%Dataset{name: %IRI{}}), do: true + def named_dataset?(_), do: false def named_dataset?(%Dataset{name: name}, name), do: true - def named_dataset?(_, _), do: false + def named_dataset?(_, _), do: false def empty_dataset?(%Dataset{graphs: graphs}), do: graphs == %{} def dataset_includes_statement?(dataset, {_, _, _} = statement) do dataset - |> Dataset.default_graph + |> Dataset.default_graph() |> graph_includes_statement?(statement) end def dataset_includes_statement?(dataset, {subject, predicate, objects, nil}), do: dataset_includes_statement?(dataset, {subject, predicate, objects}) - def dataset_includes_statement?(dataset, - {subject, predicate, objects, graph_context}) do + def dataset_includes_statement?( + dataset, + {subject, predicate, objects, graph_context} + ) do dataset.graphs |> Map.get(iri(graph_context), named_graph(graph_context)) |> graph_includes_statement?({subject, predicate, objects}) end - end diff --git a/test/support/rdf_query_test_case.ex b/test/support/rdf_query_test_case.ex index a6340ba..9548c82 100644 --- a/test/support/rdf_query_test_case.ex +++ b/test/support/rdf_query_test_case.ex @@ -8,18 +8,18 @@ defmodule RDF.Query.Test.Case do alias RDF.Query.BGP import unquote(__MODULE__) - end end alias RDF.Query.BGP def bgp_struct(), do: %BGP{triple_patterns: []} + def bgp_struct(triple_patterns) when is_list(triple_patterns), do: %BGP{triple_patterns: triple_patterns} + def bgp_struct({_, _, _} = triple_pattern), do: %BGP{triple_patterns: [triple_pattern]} def ok_bgp_struct(triple_patterns), do: {:ok, bgp_struct(triple_patterns)} - end diff --git a/test/support/test_data.ex b/test/support/test_data.ex index 026507e..f4d4320 100644 --- a/test/support/test_data.ex +++ b/test/support/test_data.ex @@ -1,14 +1,12 @@ defmodule RDF.TestData do - - @dir Path.join(File.cwd!, "test/data/") + @dir Path.join(File.cwd!(), "test/data/") def dir, do: @dir def file(name) do - if (path = Path.join(@dir, name)) |> File.exists? do + if (path = Path.join(@dir, name)) |> File.exists?() do path else raise "Test data file '#{name}' not found" end end - end diff --git a/test/support/test_datatypes.ex b/test/support/test_datatypes.ex index 21e57e4..97e7336 100644 --- a/test/support/test_datatypes.ex +++ b/test/support/test_datatypes.ex @@ -1,39 +1,39 @@ defmodule RDF.TestDatatypes do defmodule Initials do use RDF.XSD.Datatype.Restriction, - name: "initials", - id: "http://example.com/initials", - base: RDF.XSD.String + name: "initials", + id: "http://example.com/initials", + base: RDF.XSD.String def_facet_constraint RDF.XSD.Facets.Length, 2 end defmodule UsZipcode do use RDF.XSD.Datatype.Restriction, - name: "us_zipcode", - id: "http://example.com/us-zipcode", - base: RDF.XSD.String + name: "us_zipcode", + id: "http://example.com/us-zipcode", + base: RDF.XSD.String def_facet_constraint RDF.XSD.Facets.Pattern, "[0-9]{5}(-[0-9]{4})?" end defmodule AltUsZipcode do use RDF.XSD.Datatype.Restriction, - name: "alt_us_zipcode", - id: "http://example.com/alt-us-zipcode", - base: RDF.XSD.String + name: "alt_us_zipcode", + id: "http://example.com/alt-us-zipcode", + base: RDF.XSD.String def_facet_constraint RDF.XSD.Facets.Pattern, [ "[0-9]{5}", - "[0-9]{5}-[0-9]{4}", + "[0-9]{5}-[0-9]{4}" ] end defmodule Age do use RDF.XSD.Datatype.Restriction, - name: "age", - id: "http://example.com/Age", - base: RDF.XSD.PositiveInteger + name: "age", + id: "http://example.com/Age", + base: RDF.XSD.PositiveInteger def_facet_constraint RDF.XSD.Facets.MaxInclusive, 150 @@ -43,9 +43,9 @@ defmodule RDF.TestDatatypes do defmodule DecimalUnitInterval do use RDF.XSD.Datatype.Restriction, - name: "decimal_unit_interval", - id: "http://example.com/decimalUnitInterval", - base: RDF.XSD.Decimal + name: "decimal_unit_interval", + id: "http://example.com/decimalUnitInterval", + base: RDF.XSD.Decimal def_facet_constraint RDF.XSD.Facets.MinInclusive, 0 def_facet_constraint RDF.XSD.Facets.MaxInclusive, 1 @@ -53,9 +53,9 @@ defmodule RDF.TestDatatypes do defmodule DoubleUnitInterval do use RDF.XSD.Datatype.Restriction, - name: "double_unit_interval", - id: "http://example.com/doubleUnitInterval", - base: RDF.XSD.Double + name: "double_unit_interval", + id: "http://example.com/doubleUnitInterval", + base: RDF.XSD.Double def_facet_constraint RDF.XSD.Facets.MinInclusive, 0 def_facet_constraint RDF.XSD.Facets.MaxInclusive, 1 @@ -63,9 +63,9 @@ defmodule RDF.TestDatatypes do defmodule FloatUnitInterval do use RDF.XSD.Datatype.Restriction, - name: "float_unit_interval", - id: "http://example.com/floatUnitInterval", - base: RDF.XSD.Float + name: "float_unit_interval", + id: "http://example.com/floatUnitInterval", + base: RDF.XSD.Float def_facet_constraint RDF.XSD.Facets.MinInclusive, 0 def_facet_constraint RDF.XSD.Facets.MaxInclusive, 1 @@ -73,27 +73,27 @@ defmodule RDF.TestDatatypes do defmodule DateTimeWithTz do use RDF.XSD.Datatype.Restriction, - name: "datetime_with_tz", - id: "http://example.com/datetime-with-tz", - base: RDF.XSD.DateTime + name: "datetime_with_tz", + id: "http://example.com/datetime-with-tz", + base: RDF.XSD.DateTime def_facet_constraint RDF.XSD.Facets.ExplicitTimezone, :required end defmodule DateWithoutTz do use RDF.XSD.Datatype.Restriction, - name: "date_with_tz", - id: "http://example.com/date-with-tz", - base: RDF.XSD.Date + name: "date_with_tz", + id: "http://example.com/date-with-tz", + base: RDF.XSD.Date def_facet_constraint RDF.XSD.Facets.ExplicitTimezone, :prohibited end defmodule CustomTime do use RDF.XSD.Datatype.Restriction, - name: "time_with_tz", - id: "http://example.com/time-with-tz", - base: RDF.XSD.Time + name: "time_with_tz", + id: "http://example.com/time-with-tz", + base: RDF.XSD.Time def_facet_constraint RDF.XSD.Facets.ExplicitTimezone, :optional end diff --git a/test/support/test_literals.ex b/test/support/test_literals.ex index 531492d..44be6e6 100644 --- a/test/support/test_literals.ex +++ b/test/support/test_literals.ex @@ -1,49 +1,53 @@ defmodule RDF.TestLiterals do - alias RDF.Literal alias RDF.NS.XSD - def value(:empty), do: [""] - def value(:plain), do: ["Hello"] - def value(:empty_lang), do: ["", [language: "en"]] - def value(:plain_lang), do: ["Hello", [language: "en"]] - def value(:typed_string), do: ["String", [datatype: XSD.string]] - def value(:uri), do: [URI.parse("http://example.com")] - def value(:true), do: [true] - def value(:false), do: [false] - def value(:int), do: [123] - def value(:neg_int), do: [-123] - def value(:decimal), do: [Decimal.from_float(3.14)] - def value(:long), do: [9223372036854775807] - def value(:double), do: [3.1415] - def value(:date), do: [~D[2017-04-13]] + def value(:empty), do: [""] + def value(:plain), do: ["Hello"] + def value(:empty_lang), do: ["", [language: "en"]] + def value(:plain_lang), do: ["Hello", [language: "en"]] + def value(:typed_string), do: ["String", [datatype: XSD.string()]] + def value(:uri), do: [URI.parse("http://example.com")] + def value(true), do: [true] + def value(false), do: [false] + def value(:int), do: [123] + def value(:neg_int), do: [-123] + def value(:decimal), do: [Decimal.from_float(3.14)] + def value(:long), do: [9_223_372_036_854_775_807] + def value(:double), do: [3.1415] + def value(:date), do: [~D[2017-04-13]] def value(:naive_datetime), do: [~N[2017-04-14 15:32:07]] - def value(:datetime), do: ["2017-04-14 15:32:07Z" |> DateTime.from_iso8601 |> elem(1)] - def value(:time), do: [~T[01:02:03]] + def value(:datetime), do: ["2017-04-14 15:32:07Z" |> DateTime.from_iso8601() |> elem(1)] + def value(:time), do: [~T[01:02:03]] + def value(selector) do raise "unexpected literal: :#{selector}" end def values(:all_simple), do: Enum.map(~W(empty plain typed_string)a, &value/1) + def values(:all_plain_lang), do: Enum.map(~W[empty_lang plain_lang]a, &value/1) + def values(:all_native), do: Enum.map(~W[false true int long double time date datetime naive_datetime]a, &value/1) + def values(:all_plain), do: values(~W[all_simple all_plain_lang]a) + def values(:all), do: values(~W[all_native all_plain]a) + def values(selectors) when is_list(selectors) do - Enum.reduce selectors, [], fn(selector, values) -> + Enum.reduce(selectors, [], fn selector, values -> values ++ values(selector) - end + end) end def literal(selector), do: apply(Literal, :new, value(selector)) def literals(selectors), - do: Enum.map values(selectors), fn value -> apply(Literal, :new, value) end - + do: Enum.map(values(selectors), fn value -> apply(Literal, :new, value) end) end diff --git a/test/support/test_suite.ex b/test/support/test_suite.ex index 0362b2b..d163e7c 100644 --- a/test/support/test_suite.ex +++ b/test/support/test_suite.ex @@ -1,11 +1,11 @@ defmodule RDF.TestSuite do - defmodule NS do use RDF.Vocabulary.Namespace defvocab MF, base_iri: "http://www.w3.org/2001/sw/DataAccess/tests/test-manifest#", - terms: [], strict: false + terms: [], + strict: false defvocab RDFT, base_iri: "http://www.w3.org/ns/rdftest#", @@ -25,10 +25,9 @@ defmodule RDF.TestSuite do alias RDF.{Turtle, Graph, Description, IRI} - - def dir(format), do: Path.join(RDF.TestData.dir, String.upcase(format) <> "-TESTS") + def dir(format), do: Path.join(RDF.TestData.dir(), String.upcase(format) <> "-TESTS") def file(filename, format), do: format |> dir |> Path.join(filename) - def manifest_path(format), do: file("manifest.ttl", format) + def manifest_path(format), do: file("manifest.ttl", format) def manifest_graph(format, opts \\ []) do format @@ -39,34 +38,32 @@ defmodule RDF.TestSuite do def test_cases(format, test_type, opts) do format |> manifest_graph(opts) - |> Graph.descriptions + |> Graph.descriptions() |> Enum.filter(fn description -> - RDF.iri(test_type) in Description.get(description, RDF.type, []) - end) + RDF.iri(test_type) in Description.get(description, RDF.type(), []) + end) end - def test_name(test_case), do: value(test_case, MF.name) + def test_name(test_case), do: value(test_case, MF.name()) def test_title(test_case), -# Unfortunately OTP < 20 doesn't support unicode characters in atoms, -# so we can't put the description in the test name -# do: test_name(test_case) <> ": " <> value(test_case, RDFS.comment) + # Unfortunately OTP < 20 doesn't support unicode characters in atoms, + # so we can't put the description in the test name + # do: test_name(test_case) <> ": " <> value(test_case, RDFS.comment) do: test_name(test_case) def test_input_file(test_case), - do: test_case |> Description.first(MF.action) |> IRI.parse + do: test_case |> Description.first(MF.action()) |> IRI.parse() def test_output_file(test_case), - do: test_case |> Description.first(MF.result) |> IRI.parse + do: test_case |> Description.first(MF.result()) |> IRI.parse() def test_input_file_path(test_case, format), - do: test_input_file(test_case).path |> Path.basename |> file(format) + do: test_input_file(test_case).path |> Path.basename() |> file(format) def test_result_file_path(test_case, format), - do: test_output_file(test_case).path |> Path.basename |> file(format) - + do: test_output_file(test_case).path |> Path.basename() |> file(format) defp value(description, property), do: Description.first(description, property) |> to_string - end diff --git a/test/support/xsd_datatype_case.ex b/test/support/xsd_datatype_case.ex index e6f96b4..b84e98c 100644 --- a/test/support/xsd_datatype_case.ex +++ b/test/support/xsd_datatype_case.ex @@ -7,8 +7,7 @@ defmodule RDF.XSD.Datatype.Test.Case do datatype = Keyword.fetch!(opts, :datatype) datatype_name = Keyword.fetch!(opts, :name) - datatype_iri = - Keyword.get(opts, :iri, RDF.NS.XSD.__base_iri__ <> datatype_name) + datatype_iri = Keyword.get(opts, :iri, RDF.NS.XSD.__base_iri__() <> datatype_name) valid = Keyword.get(opts, :valid) invalid = Keyword.get(opts, :invalid) @@ -116,45 +115,48 @@ defmodule RDF.XSD.Datatype.Test.Case do describe "general datatype?/1" do test "on the exact same datatype" do - assert (unquote(datatype).datatype?(unquote(datatype))) == true + assert unquote(datatype).datatype?(unquote(datatype)) == true + Enum.each(@valid, fn {input, _} -> literal = unquote(datatype).new(input) - assert (unquote(datatype).datatype?(literal)) == true - assert (unquote(datatype).datatype?(literal.literal)) == true + assert unquote(datatype).datatype?(literal) == true + assert unquote(datatype).datatype?(literal.literal) == true end) end unless unquote(primitive) do test "on the base datatype" do - assert (unquote(base).datatype?(unquote(datatype))) == true + assert unquote(base).datatype?(unquote(datatype)) == true + Enum.each(@valid, fn {input, _} -> literal = unquote(datatype).new(input) - assert (unquote(base).datatype?(literal)) == true - assert (unquote(base).datatype?(literal.literal)) == true + assert unquote(base).datatype?(literal) == true + assert unquote(base).datatype?(literal.literal) == true end) end test "on the base primitive datatype" do - assert (unquote(base_primitive).datatype?(unquote(datatype))) == true + assert unquote(base_primitive).datatype?(unquote(datatype)) == true + Enum.each(@valid, fn {input, _} -> literal = unquote(datatype).new(input) - assert (unquote(base_primitive).datatype?(literal)) == true - assert (unquote(base_primitive).datatype?(literal.literal)) == true + assert unquote(base_primitive).datatype?(literal) == true + assert unquote(base_primitive).datatype?(literal.literal) == true end) end - end end test "datatype_id/1" do Enum.each(@valid, fn {input, _} -> - assert (unquote(datatype).new(input) |> unquote(datatype).datatype_id()) == RDF.iri(unquote(datatype_iri)) + assert unquote(datatype).new(input) |> unquote(datatype).datatype_id() == + RDF.iri(unquote(datatype_iri)) end) end test "language/1" do Enum.each(@valid, fn {input, _} -> - assert (unquote(datatype).new(input) |> unquote(datatype).language()) == nil + assert unquote(datatype).new(input) |> unquote(datatype).language() == nil end) end @@ -288,9 +290,9 @@ defmodule RDF.XSD.Datatype.Test.Case do @tag example: %{input: input, canonicalized: canonicalized} test "canonical? for #{unquote(datatype)} #{inspect(input)}", %{example: example} do literal = unquote(datatype).new(example.input) - assert unquote(datatype).canonical?(literal) == ( - unquote(datatype).lexical(literal) ==example.canonicalized - ) + + assert unquote(datatype).canonical?(literal) == + (unquote(datatype).lexical(literal) == example.canonicalized) end end) diff --git a/test/unit/blank_node/increment_test.exs b/test/unit/blank_node/increment_test.exs index cf71c66..29ecbb2 100644 --- a/test/unit/blank_node/increment_test.exs +++ b/test/unit/blank_node/increment_test.exs @@ -5,40 +5,38 @@ defmodule RDF.BlankNode.IncrementTest do alias RDF.BlankNode.{Generator, Increment} - describe "generate/1" do test "without prefix" do assert Increment.generate(%{counter: 0, map: %{}}) == - {bnode(0), (%{counter: 1, map: %{}})} + {bnode(0), %{counter: 1, map: %{}}} end test "with prefix" do assert Increment.generate(%{counter: 0, map: %{}, prefix: "b"}) == - {bnode("b0"), (%{counter: 1, map: %{}, prefix: "b"})} + {bnode("b0"), %{counter: 1, map: %{}, prefix: "b"}} end end - describe "generate_for/2" do test "when the given string not exists in the map" do assert Increment.generate_for("bar", %{counter: 1, map: %{"foo" => 0}}) == - {bnode(1), (%{counter: 2, map: %{"foo" => 0, "bar" => 1}})} + {bnode(1), %{counter: 2, map: %{"foo" => 0, "bar" => 1}}} end test "when the given string exists in the map" do assert Increment.generate_for("foo", %{counter: 1, map: %{"foo" => 0}}) == - {bnode(0), (%{counter: 1, map: %{"foo" => 0}})} + {bnode(0), %{counter: 1, map: %{"foo" => 0}}} end test "with prefix" do assert Increment.generate_for("bar", %{counter: 1, map: %{"foo" => 0}, prefix: "b"}) == - {bnode("b1"), (%{counter: 2, map: %{"foo" => 0, "bar" => 1}, prefix: "b"})} + {bnode("b1"), %{counter: 2, map: %{"foo" => 0, "bar" => 1}, prefix: "b"}} + assert Increment.generate_for("foo", %{counter: 1, map: %{"foo" => 0}, prefix: "b"}) == - {bnode("b0"), (%{counter: 1, map: %{"foo" => 0}, prefix: "b"})} + {bnode("b0"), %{counter: 1, map: %{"foo" => 0}, prefix: "b"}} end end - test "generator without prefix" do {:ok, generator} = Generator.start_link(Increment) @@ -77,5 +75,4 @@ defmodule RDF.BlankNode.IncrementTest do assert Generator.generate_for(generator, {:foo, 42}) == bnode("b2") assert Generator.generate(generator) == bnode("b6") end - end diff --git a/test/unit/data_test.exs b/test/unit/data_test.exs index 85ff63a..503eba2 100644 --- a/test/unit/data_test.exs +++ b/test/unit/data_test.exs @@ -7,88 +7,92 @@ defmodule RDF.DataTest do |> EX.p1(EX.O1, EX.O2) |> EX.p2(EX.O3) |> EX.p3(~B, ~L"bar") + graph = - Graph.new + Graph.new() |> Graph.add(description) |> Graph.add( - EX.S2 - |> EX.p2(EX.O3, EX.O4) + EX.S2 + |> EX.p2(EX.O3, EX.O4) ) + named_graph = %Graph{graph | name: iri(EX.NamedGraph)} + dataset = - Dataset.new + Dataset.new() |> Dataset.add(graph) |> Dataset.add( - Graph.new(name: EX.NamedGraph) - |> Graph.add(description) - |> Graph.add({EX.S3, EX.p3, EX.O5}) - |> Graph.add({EX.S, EX.p3, EX.O5})) - {:ok, - description: description, - graph: graph, named_graph: named_graph, - dataset: dataset, - } - end + Graph.new(name: EX.NamedGraph) + |> Graph.add(description) + |> Graph.add({EX.S3, EX.p3(), EX.O5}) + |> Graph.add({EX.S, EX.p3(), EX.O5}) + ) + {:ok, description: description, graph: graph, named_graph: named_graph, dataset: dataset} + end describe "RDF.Data protocol implementation of RDF.Description" do test "merge of a single triple with different subject", %{description: description} do - assert RDF.Data.merge(description, {EX.Other, EX.p1, EX.O3}) == - Graph.new(description) |> Graph.add({EX.Other, EX.p1, EX.O3}) + assert RDF.Data.merge(description, {EX.Other, EX.p1(), EX.O3}) == + Graph.new(description) |> Graph.add({EX.Other, EX.p1(), EX.O3}) end test "merge of a single triple with same subject", %{description: description} do - assert RDF.Data.merge(description, {EX.S, EX.p1, EX.O3}) == - Description.add(description, {EX.S, EX.p1, EX.O3}) + assert RDF.Data.merge(description, {EX.S, EX.p1(), EX.O3}) == + Description.add(description, {EX.S, EX.p1(), EX.O3}) end test "merge of a single quad", %{description: description} do - assert RDF.Data.merge(description, {EX.Other, EX.p1, EX.O3, EX.Graph}) == - Dataset.new(description) |> Dataset.add({EX.Other, EX.p1, EX.O3, EX.Graph}) - assert RDF.Data.merge(description, {EX.S, EX.p1, EX.O3, EX.Graph}) == - Dataset.new(description) |> Dataset.add({EX.S, EX.p1, EX.O3, EX.Graph}) + assert RDF.Data.merge(description, {EX.Other, EX.p1(), EX.O3, EX.Graph}) == + Dataset.new(description) |> Dataset.add({EX.Other, EX.p1(), EX.O3, EX.Graph}) + + assert RDF.Data.merge(description, {EX.S, EX.p1(), EX.O3, EX.Graph}) == + Dataset.new(description) |> Dataset.add({EX.S, EX.p1(), EX.O3, EX.Graph}) end test "merge of a description with different subject", %{description: description} do - assert RDF.Data.merge(description, Description.new({EX.Other, EX.p1, EX.O3})) == - Graph.new(description) |> Graph.add({EX.Other, EX.p1, EX.O3}) + assert RDF.Data.merge(description, Description.new({EX.Other, EX.p1(), EX.O3})) == + Graph.new(description) |> Graph.add({EX.Other, EX.p1(), EX.O3}) end test "merge of a description with same subject", %{description: description} do - assert RDF.Data.merge(description, Description.new({EX.S, EX.p1, EX.O3})) == - Description.add(description, {EX.S, EX.p1, EX.O3}) + assert RDF.Data.merge(description, Description.new({EX.S, EX.p1(), EX.O3})) == + Description.add(description, {EX.S, EX.p1(), EX.O3}) end test "merge of a graph", %{graph: graph} do - assert RDF.Data.merge(Description.new({EX.Other, EX.p1, EX.O3}), graph) == - Graph.add(graph, {EX.Other, EX.p1, EX.O3}) + assert RDF.Data.merge(Description.new({EX.Other, EX.p1(), EX.O3}), graph) == + Graph.add(graph, {EX.Other, EX.p1(), EX.O3}) end test "merge of a dataset", %{dataset: dataset} do - assert RDF.Data.merge(Description.new({EX.Other, EX.p1, EX.O3}), dataset) == - Dataset.add(dataset, {EX.Other, EX.p1, EX.O3}) + assert RDF.Data.merge(Description.new({EX.Other, EX.p1(), EX.O3}), dataset) == + Dataset.add(dataset, {EX.Other, EX.p1(), EX.O3}) end - test "delete", %{description: description} do - assert RDF.Data.delete(description, {EX.S, EX.p1, EX.O2}) == - Description.delete(description, {EX.S, EX.p1, EX.O2}) - assert RDF.Data.delete(description, {EX.Other, EX.p1, EX.O2}) == description + assert RDF.Data.delete(description, {EX.S, EX.p1(), EX.O2}) == + Description.delete(description, {EX.S, EX.p1(), EX.O2}) + + assert RDF.Data.delete(description, {EX.Other, EX.p1(), EX.O2}) == description end - test "deleting a Description with a different subject does nothing", %{description: description} do - assert RDF.Data.delete(description, - %Description{description | subject: EX.Other}) == description + test "deleting a Description with a different subject does nothing", %{ + description: description + } do + assert RDF.Data.delete( + description, + %Description{description | subject: EX.Other} + ) == description end - test "pop", %{description: description} do assert RDF.Data.pop(description) == Description.pop(description) end test "include?", %{description: description} do - assert RDF.Data.include?(description, {EX.S, EX.p1, EX.O2}) - refute RDF.Data.include?(description, {EX.Other, EX.p1, EX.O2}) + assert RDF.Data.include?(description, {EX.S, EX.p1(), EX.O2}) + refute RDF.Data.include?(description, {EX.Other, EX.p1(), EX.O2}) end test "describes?", %{description: description} do @@ -97,14 +101,14 @@ defmodule RDF.DataTest do end test "description when the requested subject matches the Description.subject", - %{description: description} do + %{description: description} do assert RDF.Data.description(description, description.subject) == description assert RDF.Data.description(description, to_string(description.subject)) == description assert RDF.Data.description(description, EX.S) == description end test "description when the requested subject does not match the Description.subject", - %{description: description} do + %{description: description} do assert RDF.Data.description(description, iri(EX.Other)) == Description.new(EX.Other) end @@ -121,17 +125,26 @@ defmodule RDF.DataTest do end test "predicates", %{description: description} do - assert RDF.Data.predicates(description) == MapSet.new([EX.p1, EX.p2, EX.p3]) + assert RDF.Data.predicates(description) == MapSet.new([EX.p1(), EX.p2(), EX.p3()]) end test "objects", %{description: description} do assert RDF.Data.objects(description) == - MapSet.new([iri(EX.O1), iri(EX.O2), iri(EX.O3), ~B]) + MapSet.new([iri(EX.O1), iri(EX.O2), iri(EX.O3), ~B]) end test "resources", %{description: description} do assert RDF.Data.resources(description) == - MapSet.new([iri(EX.S), EX.p1, EX.p2, EX.p3, iri(EX.O1), iri(EX.O2), iri(EX.O3), ~B]) + MapSet.new([ + iri(EX.S), + EX.p1(), + EX.p2(), + EX.p3(), + iri(EX.O1), + iri(EX.O2), + iri(EX.O3), + ~B + ]) end test "subject_count", %{description: description} do @@ -145,12 +158,12 @@ defmodule RDF.DataTest do test "values", %{description: description} do assert RDF.Data.values(description) == %{ - RDF.Term.value(EX.p1) => [ + RDF.Term.value(EX.p1()) => [ RDF.Term.value(RDF.iri(EX.O1)), RDF.Term.value(RDF.iri(EX.O2)) ], - RDF.Term.value(EX.p2) => [RDF.Term.value(RDF.iri(EX.O3))], - RDF.Term.value(EX.p3) => ["_:foo", "bar"], + RDF.Term.value(EX.p2()) => [RDF.Term.value(RDF.iri(EX.O3))], + RDF.Term.value(EX.p3()) => ["_:foo", "bar"] } end @@ -166,71 +179,79 @@ defmodule RDF.DataTest do end end - describe "RDF.Data protocol implementation of RDF.Graph" do test "merge of a single triple", %{graph: graph, named_graph: named_graph} do - assert RDF.Data.merge(graph, {EX.Other, EX.p, EX.O}) == - Graph.add(graph, {EX.Other, EX.p, EX.O}) - assert RDF.Data.merge(named_graph, {EX.Other, EX.p, EX.O}) == - Graph.add(named_graph, {EX.Other, EX.p, EX.O}) + assert RDF.Data.merge(graph, {EX.Other, EX.p(), EX.O}) == + Graph.add(graph, {EX.Other, EX.p(), EX.O}) + + assert RDF.Data.merge(named_graph, {EX.Other, EX.p(), EX.O}) == + Graph.add(named_graph, {EX.Other, EX.p(), EX.O}) end test "merge of a single quad with the same graph context", - %{graph: graph, named_graph: named_graph} do - assert RDF.Data.merge(graph, {EX.Other, EX.p, EX.O, nil}) == - Graph.add(graph, {EX.Other, EX.p, EX.O}) - assert RDF.Data.merge(named_graph, {EX.Other, EX.p, EX.O, EX.NamedGraph}) == - Graph.add(named_graph, {EX.Other, EX.p, EX.O}) + %{graph: graph, named_graph: named_graph} do + assert RDF.Data.merge(graph, {EX.Other, EX.p(), EX.O, nil}) == + Graph.add(graph, {EX.Other, EX.p(), EX.O}) + + assert RDF.Data.merge(named_graph, {EX.Other, EX.p(), EX.O, EX.NamedGraph}) == + Graph.add(named_graph, {EX.Other, EX.p(), EX.O}) end test "merge of a single quad with a different graph context", - %{graph: graph, named_graph: named_graph} do - assert RDF.Data.merge(graph, {EX.S, EX.p1, EX.O3, EX.NamedGraph}) == - Dataset.new(graph) |> Dataset.add({EX.S, EX.p1, EX.O3, EX.NamedGraph}) - assert RDF.Data.merge(named_graph, {EX.S, EX.p1, EX.O3, nil}) == - Dataset.new(named_graph) |> Dataset.add({EX.S, EX.p1, EX.O3, nil}) + %{graph: graph, named_graph: named_graph} do + assert RDF.Data.merge(graph, {EX.S, EX.p1(), EX.O3, EX.NamedGraph}) == + Dataset.new(graph) |> Dataset.add({EX.S, EX.p1(), EX.O3, EX.NamedGraph}) + + assert RDF.Data.merge(named_graph, {EX.S, EX.p1(), EX.O3, nil}) == + Dataset.new(named_graph) |> Dataset.add({EX.S, EX.p1(), EX.O3, nil}) end test "merge of a description", %{graph: graph} do - assert RDF.Data.merge(graph, Description.new({EX.Other, EX.p1, EX.O3})) == - Graph.add(graph, {EX.Other, EX.p1, EX.O3}) - assert RDF.Data.merge(graph, Description.new({EX.S, EX.p1, EX.O3})) == - Graph.add(graph, {EX.S, EX.p1, EX.O3}) + assert RDF.Data.merge(graph, Description.new({EX.Other, EX.p1(), EX.O3})) == + Graph.add(graph, {EX.Other, EX.p1(), EX.O3}) + + assert RDF.Data.merge(graph, Description.new({EX.S, EX.p1(), EX.O3})) == + Graph.add(graph, {EX.S, EX.p1(), EX.O3}) end test "merge of a graph with the same name", - %{graph: graph, named_graph: named_graph} do - assert RDF.Data.merge(graph, Graph.add(graph, {EX.Other, EX.p1, EX.O3})) == - Graph.add(graph, {EX.Other, EX.p1, EX.O3}) - assert RDF.Data.merge(named_graph, Graph.add(named_graph, {EX.Other, EX.p1, EX.O3})) == - Graph.add(named_graph, {EX.Other, EX.p1, EX.O3}) + %{graph: graph, named_graph: named_graph} do + assert RDF.Data.merge(graph, Graph.add(graph, {EX.Other, EX.p1(), EX.O3})) == + Graph.add(graph, {EX.Other, EX.p1(), EX.O3}) + + assert RDF.Data.merge(named_graph, Graph.add(named_graph, {EX.Other, EX.p1(), EX.O3})) == + Graph.add(named_graph, {EX.Other, EX.p1(), EX.O3}) end test "merge of a graph with a different name", - %{graph: graph, named_graph: named_graph} do + %{graph: graph, named_graph: named_graph} do assert RDF.Data.merge(graph, named_graph) == - Dataset.new(graph) |> Dataset.add(named_graph) + Dataset.new(graph) |> Dataset.add(named_graph) + assert RDF.Data.merge(named_graph, graph) == - Dataset.new(named_graph) |> Dataset.add(graph) + Dataset.new(named_graph) |> Dataset.add(graph) end test "merge of a dataset", %{dataset: dataset} do - assert RDF.Data.merge(Graph.new({EX.Other, EX.p1, EX.O3}), dataset) == - Dataset.add(dataset, {EX.Other, EX.p1, EX.O3}) - assert RDF.Data.merge(Graph.new({EX.Other, EX.p1, EX.O3}, name: EX.NamedGraph), dataset) == - Dataset.add(dataset, {EX.Other, EX.p1, EX.O3, EX.NamedGraph}) + assert RDF.Data.merge(Graph.new({EX.Other, EX.p1(), EX.O3}), dataset) == + Dataset.add(dataset, {EX.Other, EX.p1(), EX.O3}) + + assert RDF.Data.merge(Graph.new({EX.Other, EX.p1(), EX.O3}, name: EX.NamedGraph), dataset) == + Dataset.add(dataset, {EX.Other, EX.p1(), EX.O3, EX.NamedGraph}) end - test "delete", %{graph: graph} do - assert RDF.Data.delete(graph, {EX.S, EX.p1, EX.O2}) == - Graph.delete(graph, {EX.S, EX.p1, EX.O2}) - assert RDF.Data.delete(graph, {EX.Other, EX.p1, EX.O2}) == graph + assert RDF.Data.delete(graph, {EX.S, EX.p1(), EX.O2}) == + Graph.delete(graph, {EX.S, EX.p1(), EX.O2}) + + assert RDF.Data.delete(graph, {EX.Other, EX.p1(), EX.O2}) == graph end test "deleting a Graph with a different name does nothing", %{graph: graph} do - assert RDF.Data.delete(graph, - %Graph{graph | name: EX.OtherGraph}) == graph + assert RDF.Data.delete( + graph, + %Graph{graph | name: EX.OtherGraph} + ) == graph end test "pop", %{graph: graph} do @@ -238,9 +259,9 @@ defmodule RDF.DataTest do end test "include?", %{graph: graph} do - assert RDF.Data.include?(graph, {EX.S, EX.p1, EX.O2}) - assert RDF.Data.include?(graph, {EX.S2, EX.p2, EX.O3}) - refute RDF.Data.include?(graph, {EX.Other, EX.p1, EX.O2}) + assert RDF.Data.include?(graph, {EX.S, EX.p1(), EX.O2}) + assert RDF.Data.include?(graph, {EX.S2, EX.p2(), EX.O3}) + refute RDF.Data.include?(graph, {EX.Other, EX.p1(), EX.O2}) end test "describes?", %{graph: graph} do @@ -250,7 +271,7 @@ defmodule RDF.DataTest do end test "description when a description is present", - %{graph: graph, description: description} do + %{graph: graph, description: description} do assert RDF.Data.description(graph, iri(EX.S)) == description assert RDF.Data.description(graph, EX.S) == description end @@ -261,7 +282,7 @@ defmodule RDF.DataTest do test "descriptions", %{graph: graph, description: description} do assert RDF.Data.descriptions(graph) == - [description, EX.S2 |> EX.p2(EX.O3, EX.O4)] + [description, EX.S2 |> EX.p2(EX.O3, EX.O4)] end test "statements", %{graph: graph} do @@ -273,19 +294,28 @@ defmodule RDF.DataTest do end test "predicates", %{graph: graph} do - assert RDF.Data.predicates(graph) == MapSet.new([EX.p1, EX.p2, EX.p3]) + assert RDF.Data.predicates(graph) == MapSet.new([EX.p1(), EX.p2(), EX.p3()]) end test "objects", %{graph: graph} do assert RDF.Data.objects(graph) == - MapSet.new([iri(EX.O1), iri(EX.O2), iri(EX.O3), iri(EX.O4), ~B]) + MapSet.new([iri(EX.O1), iri(EX.O2), iri(EX.O3), iri(EX.O4), ~B]) end test "resources", %{graph: graph} do - assert RDF.Data.resources(graph) == MapSet.new([ - iri(EX.S), iri(EX.S2), EX.p1, EX.p2, EX.p3, - iri(EX.O1), iri(EX.O2), iri(EX.O3), iri(EX.O4), ~B - ]) + assert RDF.Data.resources(graph) == + MapSet.new([ + iri(EX.S), + iri(EX.S2), + EX.p1(), + EX.p2(), + EX.p3(), + iri(EX.O1), + iri(EX.O2), + iri(EX.O3), + iri(EX.O4), + ~B + ]) end test "subject_count", %{graph: graph} do @@ -300,19 +330,19 @@ defmodule RDF.DataTest do assert RDF.Data.values(graph) == %{ RDF.Term.value(RDF.iri(EX.S)) => %{ - RDF.Term.value(EX.p1) => [ + RDF.Term.value(EX.p1()) => [ RDF.Term.value(RDF.iri(EX.O1)), RDF.Term.value(RDF.iri(EX.O2)) ], - RDF.Term.value(EX.p2) => [RDF.Term.value(RDF.iri(EX.O3))], - RDF.Term.value(EX.p3) => ["_:foo", "bar"], + RDF.Term.value(EX.p2()) => [RDF.Term.value(RDF.iri(EX.O3))], + RDF.Term.value(EX.p3()) => ["_:foo", "bar"] }, RDF.Term.value(RDF.iri(EX.S2)) => %{ - RDF.Term.value(EX.p2) => [ + RDF.Term.value(EX.p2()) => [ RDF.Term.value(RDF.iri(EX.O3)), RDF.Term.value(RDF.iri(EX.O4)) - ], - }, + ] + } } end @@ -330,51 +360,59 @@ defmodule RDF.DataTest do end end - describe "RDF.Data protocol implementation of RDF.Dataset" do test "merge of a single triple", %{dataset: dataset} do - assert RDF.Data.merge(dataset, {EX.Other, EX.p, EX.O}) == - Dataset.add(dataset, {EX.Other, EX.p, EX.O}) + assert RDF.Data.merge(dataset, {EX.Other, EX.p(), EX.O}) == + Dataset.add(dataset, {EX.Other, EX.p(), EX.O}) end test "merge of a single quad", %{dataset: dataset} do - assert RDF.Data.merge(dataset, {EX.Other, EX.p, EX.O, nil}) == - Dataset.add(dataset, {EX.Other, EX.p, EX.O}) - assert RDF.Data.merge(dataset, {EX.Other, EX.p, EX.O, EX.NamedGraph}) == - Dataset.add(dataset, {EX.Other, EX.p, EX.O, EX.NamedGraph}) + assert RDF.Data.merge(dataset, {EX.Other, EX.p(), EX.O, nil}) == + Dataset.add(dataset, {EX.Other, EX.p(), EX.O}) + + assert RDF.Data.merge(dataset, {EX.Other, EX.p(), EX.O, EX.NamedGraph}) == + Dataset.add(dataset, {EX.Other, EX.p(), EX.O, EX.NamedGraph}) end test "merge of a description", %{dataset: dataset} do - assert RDF.Data.merge(dataset, Description.new({EX.Other, EX.p1, EX.O3})) == - Dataset.add(dataset, {EX.Other, EX.p1, EX.O3}) + assert RDF.Data.merge(dataset, Description.new({EX.Other, EX.p1(), EX.O3})) == + Dataset.add(dataset, {EX.Other, EX.p1(), EX.O3}) end test "merge of a graph", %{dataset: dataset} do - assert RDF.Data.merge(dataset, Graph.new({EX.Other, EX.p1, EX.O3})) == - Dataset.add(dataset, {EX.Other, EX.p1, EX.O3}) - assert RDF.Data.merge(dataset, Graph.new({EX.Other, EX.p1, EX.O3}, name: EX.NamedGraph)) == - Dataset.add(dataset, {EX.Other, EX.p1, EX.O3, EX.NamedGraph}) + assert RDF.Data.merge(dataset, Graph.new({EX.Other, EX.p1(), EX.O3})) == + Dataset.add(dataset, {EX.Other, EX.p1(), EX.O3}) + + assert RDF.Data.merge(dataset, Graph.new({EX.Other, EX.p1(), EX.O3}, name: EX.NamedGraph)) == + Dataset.add(dataset, {EX.Other, EX.p1(), EX.O3, EX.NamedGraph}) end test "merge of a dataset", %{dataset: dataset} do - assert RDF.Data.merge(dataset, Dataset.new({EX.Other, EX.p1, EX.O3})) == - Dataset.add(dataset, {EX.Other, EX.p1, EX.O3}) - assert RDF.Data.merge(dataset, Dataset.new({EX.Other, EX.p1, EX.O3}, name: EX.NamedDataset)) == - Dataset.add(dataset, {EX.Other, EX.p1, EX.O3}) + assert RDF.Data.merge(dataset, Dataset.new({EX.Other, EX.p1(), EX.O3})) == + Dataset.add(dataset, {EX.Other, EX.p1(), EX.O3}) + + assert RDF.Data.merge( + dataset, + Dataset.new({EX.Other, EX.p1(), EX.O3}, name: EX.NamedDataset) + ) == + Dataset.add(dataset, {EX.Other, EX.p1(), EX.O3}) end - test "delete", %{dataset: dataset} do - assert RDF.Data.delete(dataset, {EX.S, EX.p1, EX.O2}) == - Dataset.delete(dataset, {EX.S, EX.p1, EX.O2}) - assert RDF.Data.delete(dataset, {EX.S3, EX.p3, EX.O5, EX.NamedGraph}) == - Dataset.delete(dataset, {EX.S3, EX.p3, EX.O5, EX.NamedGraph}) - assert RDF.Data.delete(dataset, {EX.Other, EX.p1, EX.O2}) == dataset + assert RDF.Data.delete(dataset, {EX.S, EX.p1(), EX.O2}) == + Dataset.delete(dataset, {EX.S, EX.p1(), EX.O2}) + + assert RDF.Data.delete(dataset, {EX.S3, EX.p3(), EX.O5, EX.NamedGraph}) == + Dataset.delete(dataset, {EX.S3, EX.p3(), EX.O5, EX.NamedGraph}) + + assert RDF.Data.delete(dataset, {EX.Other, EX.p1(), EX.O2}) == dataset end test "deleting a Dataset with a different name does nothing", %{dataset: dataset} do - assert RDF.Data.delete(dataset, - %Dataset{dataset | name: EX.OtherDataset}) == dataset + assert RDF.Data.delete( + dataset, + %Dataset{dataset | name: EX.OtherDataset} + ) == dataset end test "pop", %{dataset: dataset} do @@ -382,10 +420,10 @@ defmodule RDF.DataTest do end test "include?", %{dataset: dataset} do - assert RDF.Data.include?(dataset, {EX.S, EX.p1, EX.O2}) - assert RDF.Data.include?(dataset, {EX.S2, EX.p2, EX.O3}) - assert RDF.Data.include?(dataset, {EX.S3, EX.p3, EX.O5, EX.NamedGraph}) - refute RDF.Data.include?(dataset, {EX.Other, EX.p1, EX.O2}) + assert RDF.Data.include?(dataset, {EX.S, EX.p1(), EX.O2}) + assert RDF.Data.include?(dataset, {EX.S2, EX.p2(), EX.O3}) + assert RDF.Data.include?(dataset, {EX.S3, EX.p3(), EX.O5, EX.NamedGraph}) + refute RDF.Data.include?(dataset, {EX.Other, EX.p1(), EX.O2}) end test "describes?", %{dataset: dataset} do @@ -396,8 +434,8 @@ defmodule RDF.DataTest do end test "description when a description is present", - %{dataset: dataset, description: description} do - description_aggregate = Description.add(description, {EX.S, EX.p3, EX.O5}) + %{dataset: dataset, description: description} do + description_aggregate = Description.add(description, {EX.S, EX.p3(), EX.O5}) assert RDF.Data.description(dataset, iri(EX.S)) == description_aggregate assert RDF.Data.description(dataset, EX.S) == description_aggregate end @@ -407,12 +445,13 @@ defmodule RDF.DataTest do end test "descriptions", %{dataset: dataset, description: description} do - description_aggregate = Description.add(description, {EX.S, EX.p3, EX.O5}) + description_aggregate = Description.add(description, {EX.S, EX.p3(), EX.O5}) + assert RDF.Data.descriptions(dataset) == [ - description_aggregate, - (EX.S2 |> EX.p2(EX.O3, EX.O4)), - (EX.S3 |> EX.p3(EX.O5)) - ] + description_aggregate, + EX.S2 |> EX.p2(EX.O3, EX.O4), + EX.S3 |> EX.p3(EX.O5) + ] end test "statements", %{dataset: dataset} do @@ -424,19 +463,30 @@ defmodule RDF.DataTest do end test "predicates", %{dataset: dataset} do - assert RDF.Data.predicates(dataset) == MapSet.new([EX.p1, EX.p2, EX.p3]) + assert RDF.Data.predicates(dataset) == MapSet.new([EX.p1(), EX.p2(), EX.p3()]) end test "objects", %{dataset: dataset} do assert RDF.Data.objects(dataset) == - MapSet.new([iri(EX.O1), iri(EX.O2), iri(EX.O3), iri(EX.O4), iri(EX.O5), ~B]) + MapSet.new([iri(EX.O1), iri(EX.O2), iri(EX.O3), iri(EX.O4), iri(EX.O5), ~B]) end test "resources", %{dataset: dataset} do - assert RDF.Data.resources(dataset) == MapSet.new([ - iri(EX.S), iri(EX.S2), iri(EX.S3), EX.p1, EX.p2, EX.p3, - iri(EX.O1), iri(EX.O2), iri(EX.O3), iri(EX.O4), iri(EX.O5), ~B - ]) + assert RDF.Data.resources(dataset) == + MapSet.new([ + iri(EX.S), + iri(EX.S2), + iri(EX.S3), + EX.p1(), + EX.p2(), + EX.p3(), + iri(EX.O1), + iri(EX.O2), + iri(EX.O3), + iri(EX.O4), + iri(EX.O5), + ~B + ]) end test "subject_count", %{dataset: dataset} do @@ -452,34 +502,34 @@ defmodule RDF.DataTest do %{ nil => %{ RDF.Term.value(RDF.iri(EX.S)) => %{ - RDF.Term.value(EX.p1) => [ + RDF.Term.value(EX.p1()) => [ RDF.Term.value(RDF.iri(EX.O1)), RDF.Term.value(RDF.iri(EX.O2)) ], - RDF.Term.value(EX.p2) => [RDF.Term.value(RDF.iri(EX.O3))], - RDF.Term.value(EX.p3) => ["_:foo", "bar"], + RDF.Term.value(EX.p2()) => [RDF.Term.value(RDF.iri(EX.O3))], + RDF.Term.value(EX.p3()) => ["_:foo", "bar"] }, RDF.Term.value(RDF.iri(EX.S2)) => %{ - RDF.Term.value(EX.p2) => [ + RDF.Term.value(EX.p2()) => [ RDF.Term.value(RDF.iri(EX.O3)), RDF.Term.value(RDF.iri(EX.O4)) - ], - }, + ] + } }, RDF.Term.value(RDF.iri(EX.NamedGraph)) => %{ RDF.Term.value(RDF.iri(EX.S)) => %{ - RDF.Term.value(EX.p1) => [ + RDF.Term.value(EX.p1()) => [ RDF.Term.value(RDF.iri(EX.O1)), RDF.Term.value(RDF.iri(EX.O2)) ], - RDF.Term.value(EX.p2) => [RDF.Term.value(RDF.iri(EX.O3))], - RDF.Term.value(EX.p3) => ["_:foo", "bar", RDF.Term.value(RDF.iri(EX.O5))], + RDF.Term.value(EX.p2()) => [RDF.Term.value(RDF.iri(EX.O3))], + RDF.Term.value(EX.p3()) => ["_:foo", "bar", RDF.Term.value(RDF.iri(EX.O5))] }, RDF.Term.value(RDF.iri(EX.S3)) => %{ - RDF.Term.value(EX.p3) => [ + RDF.Term.value(EX.p3()) => [ RDF.Term.value(RDF.iri(EX.O5)) - ], - }, + ] + } } } end @@ -488,8 +538,10 @@ defmodule RDF.DataTest do mapping = fn {:graph_name, graph_name} -> graph_name + {:predicate, predicate} -> predicate |> to_string() |> String.split("/") |> List.last() |> String.to_atom() + {_, term} -> RDF.Term.value(term) end @@ -503,14 +555,14 @@ defmodule RDF.DataTest do RDF.Term.value(RDF.iri(EX.O2)) ], p2: [RDF.Term.value(RDF.iri(EX.O3))], - p3: ["_:foo", "bar"], + p3: ["_:foo", "bar"] }, RDF.Term.value(RDF.iri(EX.S2)) => %{ p2: [ RDF.Term.value(RDF.iri(EX.O3)), RDF.Term.value(RDF.iri(EX.O4)) - ], - }, + ] + } }, RDF.iri(EX.NamedGraph) => %{ RDF.Term.value(RDF.iri(EX.S)) => %{ @@ -519,13 +571,13 @@ defmodule RDF.DataTest do RDF.Term.value(RDF.iri(EX.O2)) ], p2: [RDF.Term.value(RDF.iri(EX.O3))], - p3: ["_:foo", "bar", RDF.Term.value(RDF.iri(EX.O5))], + p3: ["_:foo", "bar", RDF.Term.value(RDF.iri(EX.O5))] }, RDF.Term.value(RDF.iri(EX.S3)) => %{ p3: [ RDF.Term.value(RDF.iri(EX.O5)) - ], - }, + ] + } } } end @@ -536,20 +588,26 @@ defmodule RDF.DataTest do assert RDF.Data.equal?(Dataset.new(description), description) assert RDF.Data.equal?(Dataset.new(graph), graph) assert RDF.Data.equal?(Dataset.new(graph), RDF.Graph.add_prefixes(graph, %{ex: EX})) - assert RDF.Data.equal?((Dataset.new(graph) - |> Dataset.add(Graph.new(description, name: EX.Graph1, prefixes: %{ex: EX}))), - (Dataset.new(graph) - |> Dataset.add(Graph.new(description, name: EX.Graph1, prefixes: %{ex: RDF})))) + + assert RDF.Data.equal?( + Dataset.new(graph) + |> Dataset.add(Graph.new(description, name: EX.Graph1, prefixes: %{ex: EX})), + Dataset.new(graph) + |> Dataset.add(Graph.new(description, name: EX.Graph1, prefixes: %{ex: RDF})) + ) refute RDF.Data.equal?(dataset, dataset |> Dataset.delete_graph(EX.NamedGraph)) refute RDF.Data.equal?(dataset |> Dataset.delete_graph(EX.NamedGraph), dataset) - refute RDF.Data.equal?((Dataset.new(graph) - |> Dataset.add(Graph.new(description, name: EX.Graph1))), - (Dataset.new(graph) - |> Dataset.add(Graph.new(description, name: EX.Graph2)))) + + refute RDF.Data.equal?( + Dataset.new(graph) + |> Dataset.add(Graph.new(description, name: EX.Graph1)), + Dataset.new(graph) + |> Dataset.add(Graph.new(description, name: EX.Graph2)) + ) + refute RDF.Data.equal?(dataset, description) refute RDF.Data.equal?(dataset, graph) end end - end diff --git a/test/unit/dataset_test.exs b/test/unit/dataset_test.exs index 79c6577..fd67e4c 100644 --- a/test/unit/dataset_test.exs +++ b/test/unit/dataset_test.exs @@ -3,7 +3,6 @@ defmodule RDF.DatasetTest do doctest RDF.Dataset - describe "new" do test "creating an empty unnamed dataset" do assert unnamed_dataset?(unnamed_dataset()) @@ -17,437 +16,643 @@ defmodule RDF.DatasetTest do test "creating an empty dataset with a coercible dataset name" do assert named_dataset("http://example.com/DatasetName") |> named_dataset?(iri("http://example.com/DatasetName")) + assert named_dataset(EX.Foo) |> named_dataset?(iri(EX.Foo)) end test "creating an unnamed dataset with an initial triple" do - ds = Dataset.new({EX.Subject, EX.predicate, EX.Object}) + ds = Dataset.new({EX.Subject, EX.predicate(), EX.Object}) assert unnamed_dataset?(ds) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate(), EX.Object}) end test "creating an unnamed dataset with an initial quad" do - ds = Dataset.new({EX.Subject, EX.predicate, EX.Object, EX.GraphName}) + ds = Dataset.new({EX.Subject, EX.predicate(), EX.Object, EX.GraphName}) assert unnamed_dataset?(ds) - assert dataset_includes_statement?(ds, - {EX.Subject, EX.predicate, EX.Object, EX.GraphName}) + + assert dataset_includes_statement?( + ds, + {EX.Subject, EX.predicate(), EX.Object, EX.GraphName} + ) end test "creating a named dataset with an initial triple" do - ds = Dataset.new({EX.Subject, EX.predicate, EX.Object}, name: EX.DatasetName) + ds = Dataset.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.DatasetName) assert named_dataset?(ds, iri(EX.DatasetName)) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate(), EX.Object}) end test "creating a named dataset with an initial quad" do - ds = Dataset.new({EX.Subject, EX.predicate, EX.Object, EX.GraphName}, name: EX.DatasetName) + ds = + Dataset.new({EX.Subject, EX.predicate(), EX.Object, EX.GraphName}, name: EX.DatasetName) + assert named_dataset?(ds, iri(EX.DatasetName)) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object, EX.GraphName}) + + assert dataset_includes_statement?( + ds, + {EX.Subject, EX.predicate(), EX.Object, EX.GraphName} + ) end test "creating an unnamed dataset with a list of initial statements" do - ds = Dataset.new([ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject2, EX.predicate2, EX.Object2, EX.GraphName}, - {EX.Subject3, EX.predicate3, EX.Object3, nil} - ]) + ds = + Dataset.new([ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject2, EX.predicate2(), EX.Object2, EX.GraphName}, + {EX.Subject3, EX.predicate3(), EX.Object3, nil} + ]) + assert unnamed_dataset?(ds) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1, nil}) - assert dataset_includes_statement?(ds, {EX.Subject2, EX.predicate2, EX.Object2, EX.GraphName}) - assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3, EX.Object3, nil}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1, nil}) + + assert dataset_includes_statement?( + ds, + {EX.Subject2, EX.predicate2(), EX.Object2, EX.GraphName} + ) + + assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3(), EX.Object3, nil}) end test "creating a named dataset with a list of initial statements" do - ds = Dataset.new([ - {EX.Subject, EX.predicate1, EX.Object1}, - {EX.Subject, EX.predicate2, EX.Object2, EX.GraphName}, - {EX.Subject, EX.predicate3, EX.Object3, nil} - ], name: EX.DatasetName) + ds = + Dataset.new( + [ + {EX.Subject, EX.predicate1(), EX.Object1}, + {EX.Subject, EX.predicate2(), EX.Object2, EX.GraphName}, + {EX.Subject, EX.predicate3(), EX.Object3, nil} + ], + name: EX.DatasetName + ) + assert named_dataset?(ds, iri(EX.DatasetName)) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1, EX.Object1, nil}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate2, EX.Object2, EX.GraphName}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate3, EX.Object3, nil}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1(), EX.Object1, nil}) + + assert dataset_includes_statement?( + ds, + {EX.Subject, EX.predicate2(), EX.Object2, EX.GraphName} + ) + + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate3(), EX.Object3, nil}) end test "creating a named dataset with an initial description" do - ds = Dataset.new(Description.new({EX.Subject, EX.predicate, EX.Object}), name: EX.DatasetName) + ds = + Dataset.new(Description.new({EX.Subject, EX.predicate(), EX.Object}), name: EX.DatasetName) + assert named_dataset?(ds, iri(EX.DatasetName)) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate(), EX.Object}) end test "creating an unnamed dataset with an initial description" do - ds = Dataset.new(Description.new({EX.Subject, EX.predicate, EX.Object})) + ds = Dataset.new(Description.new({EX.Subject, EX.predicate(), EX.Object})) assert unnamed_dataset?(ds) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate(), EX.Object}) end test "creating a named dataset with an initial graph" do - ds = Dataset.new(Graph.new({EX.Subject, EX.predicate, EX.Object}), name: EX.DatasetName) + ds = Dataset.new(Graph.new({EX.Subject, EX.predicate(), EX.Object}), name: EX.DatasetName) assert named_dataset?(ds, iri(EX.DatasetName)) assert unnamed_graph?(Dataset.default_graph(ds)) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate(), EX.Object}) + + ds = + Dataset.new(Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.GraphName), + name: EX.DatasetName + ) - ds = Dataset.new(Graph.new({EX.Subject, EX.predicate, EX.Object}, name: EX.GraphName), name: EX.DatasetName) assert named_dataset?(ds, iri(EX.DatasetName)) assert unnamed_graph?(Dataset.default_graph(ds)) assert named_graph?(Dataset.graph(ds, EX.GraphName), iri(EX.GraphName)) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object, EX.GraphName}) + + assert dataset_includes_statement?( + ds, + {EX.Subject, EX.predicate(), EX.Object, EX.GraphName} + ) end test "creating an unnamed dataset with an inital graph" do - ds = Dataset.new(Graph.new({EX.Subject, EX.predicate, EX.Object})) + ds = Dataset.new(Graph.new({EX.Subject, EX.predicate(), EX.Object})) assert unnamed_dataset?(ds) assert unnamed_graph?(Dataset.default_graph(ds)) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate(), EX.Object}) - ds = Dataset.new(Graph.new({EX.Subject, EX.predicate, EX.Object}, name: EX.GraphName)) + ds = Dataset.new(Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.GraphName)) assert unnamed_dataset?(ds) assert unnamed_graph?(Dataset.default_graph(ds)) assert named_graph?(Dataset.graph(ds, EX.GraphName), iri(EX.GraphName)) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object, EX.GraphName}) + + assert dataset_includes_statement?( + ds, + {EX.Subject, EX.predicate(), EX.Object, EX.GraphName} + ) end end describe "add" do test "a proper triple is added to the default graph" do - assert Dataset.add(dataset(), {iri(EX.Subject), EX.predicate, iri(EX.Object)}) - |> dataset_includes_statement?({EX.Subject, EX.predicate, EX.Object}) + assert Dataset.add(dataset(), {iri(EX.Subject), EX.predicate(), iri(EX.Object)}) + |> dataset_includes_statement?({EX.Subject, EX.predicate(), EX.Object}) end test "a proper quad is added to the specified graph" do - ds = Dataset.add(dataset(), {iri(EX.Subject), EX.predicate, iri(EX.Object), iri(EX.Graph)}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object, iri(EX.Graph)}) + ds = + Dataset.add(dataset(), {iri(EX.Subject), EX.predicate(), iri(EX.Object), iri(EX.Graph)}) + + assert dataset_includes_statement?( + ds, + {EX.Subject, EX.predicate(), EX.Object, iri(EX.Graph)} + ) end test "a proper quad with nil context is added to the default graph" do - ds = Dataset.add(dataset(), {iri(EX.Subject), EX.predicate, iri(EX.Object), nil}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate, EX.Object}) + ds = Dataset.add(dataset(), {iri(EX.Subject), EX.predicate(), iri(EX.Object), nil}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate(), EX.Object}) end test "a coercible triple" do - assert Dataset.add(dataset(), - {"http://example.com/Subject", EX.predicate, EX.Object}) - |> dataset_includes_statement?({EX.Subject, EX.predicate, EX.Object}) + assert Dataset.add( + dataset(), + {"http://example.com/Subject", EX.predicate(), EX.Object} + ) + |> dataset_includes_statement?({EX.Subject, EX.predicate(), EX.Object}) end test "a coercible quad" do - assert Dataset.add(dataset(), - {"http://example.com/Subject", EX.predicate, EX.Object, "http://example.com/GraphName"}) - |> dataset_includes_statement?({EX.Subject, EX.predicate, EX.Object, EX.GraphName}) + assert Dataset.add( + dataset(), + {"http://example.com/Subject", EX.predicate(), EX.Object, + "http://example.com/GraphName"} + ) + |> dataset_includes_statement?({EX.Subject, EX.predicate(), EX.Object, EX.GraphName}) end test "a quad and an overwriting graph context " do - assert Dataset.add(dataset(), {EX.Subject, EX.predicate, EX.Object, EX.Graph}, EX.Other) - |> dataset_includes_statement?({EX.Subject, EX.predicate, EX.Object, EX.Other}) - assert Dataset.add(dataset(), {EX.Subject, EX.predicate, EX.Object, EX.Graph}, nil) - |> dataset_includes_statement?({EX.Subject, EX.predicate, EX.Object}) + assert Dataset.add(dataset(), {EX.Subject, EX.predicate(), EX.Object, EX.Graph}, EX.Other) + |> dataset_includes_statement?({EX.Subject, EX.predicate(), EX.Object, EX.Other}) + + assert Dataset.add(dataset(), {EX.Subject, EX.predicate(), EX.Object, EX.Graph}, nil) + |> dataset_includes_statement?({EX.Subject, EX.predicate(), EX.Object}) end test "statements with multiple objects" do - ds = Dataset.add(dataset(), {EX.Subject1, EX.predicate1, [EX.Object1, EX.Object2]}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object2}) + ds = Dataset.add(dataset(), {EX.Subject1, EX.predicate1(), [EX.Object1, EX.Object2]}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object2}) - ds = Dataset.add(dataset(), {EX.Subject1, EX.predicate1, [EX.Object1, EX.Object2], EX.GraphName}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1, EX.GraphName}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object2, EX.GraphName}) + ds = + Dataset.add( + dataset(), + {EX.Subject1, EX.predicate1(), [EX.Object1, EX.Object2], EX.GraphName} + ) + + assert dataset_includes_statement?( + ds, + {EX.Subject1, EX.predicate1(), EX.Object1, EX.GraphName} + ) + + assert dataset_includes_statement?( + ds, + {EX.Subject1, EX.predicate1(), EX.Object2, EX.GraphName} + ) end test "a list of triples without specification of the default context" do - ds = Dataset.add(dataset(), [ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - {EX.Subject3, EX.predicate3, EX.Object3} - ]) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3, EX.Object3}) + ds = + Dataset.add(dataset(), [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ]) + + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3(), EX.Object3}) end test "a list of triples with specification of the default context" do - ds = Dataset.add(dataset(), [ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - {EX.Subject3, EX.predicate3, EX.Object3} - ], EX.Graph) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3, EX.Object3, EX.Graph}) + ds = + Dataset.add( + dataset(), + [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ], + EX.Graph + ) - ds = Dataset.add(dataset(), [ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - {EX.Subject3, EX.predicate3, EX.Object3} - ], nil) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1, nil}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2, nil}) - assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3, EX.Object3, nil}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3(), EX.Object3, EX.Graph}) + + ds = + Dataset.add( + dataset(), + [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ], + nil + ) + + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1, nil}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2, nil}) + assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3(), EX.Object3, nil}) end test "a list of quads without specification of the default context" do - ds = Dataset.add(dataset(), [ - {EX.Subject, EX.predicate1, EX.Object1, EX.Graph1}, - {EX.Subject, EX.predicate2, EX.Object2, nil}, - {EX.Subject, EX.predicate1, EX.Object1, EX.Graph2} - ]) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1, EX.Object1, EX.Graph1}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate2, EX.Object2, nil}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1, EX.Object1, EX.Graph2}) + ds = + Dataset.add(dataset(), [ + {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph1}, + {EX.Subject, EX.predicate2(), EX.Object2, nil}, + {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph2} + ]) + + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph1}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate2(), EX.Object2, nil}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph2}) end test "a list of quads with specification of the default context" do - ds = Dataset.add(dataset(), [ - {EX.Subject, EX.predicate1, EX.Object1, EX.Graph1}, - {EX.Subject, EX.predicate2, EX.Object2, nil}, - {EX.Subject, EX.predicate1, EX.Object1, EX.Graph2} - ], EX.Graph) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1, EX.Object1, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate2, EX.Object2, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1, EX.Object1, EX.Graph}) + ds = + Dataset.add( + dataset(), + [ + {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph1}, + {EX.Subject, EX.predicate2(), EX.Object2, nil}, + {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph2} + ], + EX.Graph + ) - ds = Dataset.add(dataset(), [ - {EX.Subject, EX.predicate1, EX.Object1, EX.Graph1}, - {EX.Subject, EX.predicate2, EX.Object2, nil}, - {EX.Subject, EX.predicate1, EX.Object1, EX.Graph2} - ], nil) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1, EX.Object1, nil}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate2, EX.Object2, nil}) - assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1, EX.Object1, nil}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate2(), EX.Object2, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph}) + + ds = + Dataset.add( + dataset(), + [ + {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph1}, + {EX.Subject, EX.predicate2(), EX.Object2, nil}, + {EX.Subject, EX.predicate1(), EX.Object1, EX.Graph2} + ], + nil + ) + + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1(), EX.Object1, nil}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate2(), EX.Object2, nil}) + assert dataset_includes_statement?(ds, {EX.Subject, EX.predicate1(), EX.Object1, nil}) end test "a list of mixed triples and quads" do - ds = Dataset.add(dataset(), [ - {EX.Subject1, EX.predicate1, EX.Object1, EX.GraphName}, - {EX.Subject3, EX.predicate3, EX.Object3} - ]) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1, EX.GraphName}) - assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3, EX.Object3, nil}) + ds = + Dataset.add(dataset(), [ + {EX.Subject1, EX.predicate1(), EX.Object1, EX.GraphName}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ]) + + assert dataset_includes_statement?( + ds, + {EX.Subject1, EX.predicate1(), EX.Object1, EX.GraphName} + ) + + assert dataset_includes_statement?(ds, {EX.Subject3, EX.predicate3(), EX.Object3, nil}) end test "a Description without specification of the default context" do - ds = Dataset.add(dataset(), Description.new(EX.Subject1, [ - {EX.predicate1, EX.Object1}, - {EX.predicate2, EX.Object2}, - ])) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) + ds = + Dataset.add( + dataset(), + Description.new(EX.Subject1, [ + {EX.predicate1(), EX.Object1}, + {EX.predicate2(), EX.Object2} + ]) + ) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) end test "a Description with specification of the default context" do - ds = Dataset.add(dataset(), Description.new(EX.Subject1, [ - {EX.predicate1, EX.Object1}, - {EX.predicate2, EX.Object2}, - ]), nil) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) + ds = + Dataset.add( + dataset(), + Description.new(EX.Subject1, [ + {EX.predicate1(), EX.Object1}, + {EX.predicate2(), EX.Object2} + ]), + nil + ) - ds = Dataset.add(ds, Description.new({EX.Subject1, EX.predicate3, EX.Object3}), EX.Graph) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + + ds = Dataset.add(ds, Description.new({EX.Subject1, EX.predicate3(), EX.Object3}), EX.Graph) assert Enum.count(ds) == 3 - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate3, EX.Object3, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate3(), EX.Object3, EX.Graph}) end test "an unnamed Graph without specification of the default context" do - ds = Dataset.add(dataset(), Graph.new([ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - ])) - assert unnamed_graph?(Dataset.default_graph(ds)) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) + ds = + Dataset.add( + dataset(), + Graph.new([ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2} + ]) + ) - ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2, EX.Object3})) + assert unnamed_graph?(Dataset.default_graph(ds)) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + + ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2(), EX.Object3})) assert unnamed_graph?(Dataset.default_graph(ds)) assert Enum.count(ds) == 3 - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3}) end test "an unnamed Graph with specification of the default context" do - ds = Dataset.add(dataset(), Graph.new([ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - ]), nil) - assert unnamed_graph?(Dataset.default_graph(ds)) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) + ds = + Dataset.add( + dataset(), + Graph.new([ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2} + ]), + nil + ) - ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2, EX.Object3}), nil) + assert unnamed_graph?(Dataset.default_graph(ds)) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + + ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2(), EX.Object3}), nil) assert unnamed_graph?(Dataset.default_graph(ds)) assert Enum.count(ds) == 3 - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3}) - ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2, EX.Object3}), EX.Graph) + ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2(), EX.Object3}), EX.Graph) assert unnamed_graph?(Dataset.default_graph(ds)) assert named_graph?(Dataset.graph(ds, EX.Graph), iri(EX.Graph)) assert Enum.count(ds) == 4 - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3, EX.Graph}) end test "a named Graph without specification of the default context" do - ds = Dataset.add(dataset(), Graph.new([ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - ], name: EX.Graph1)) + ds = + Dataset.add( + dataset(), + Graph.new( + [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2} + ], + name: EX.Graph1 + ) + ) + assert Dataset.graph(ds, EX.Graph1) assert named_graph?(Dataset.graph(ds, EX.Graph1), iri(EX.Graph1)) assert unnamed_graph?(Dataset.default_graph(ds)) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1, EX.Graph1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2, EX.Graph1}) - ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2, EX.Object3}, name: EX.Graph2)) + assert dataset_includes_statement?( + ds, + {EX.Subject1, EX.predicate1(), EX.Object1, EX.Graph1} + ) + + assert dataset_includes_statement?( + ds, + {EX.Subject1, EX.predicate2(), EX.Object2, EX.Graph1} + ) + + ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2(), EX.Object3}, name: EX.Graph2)) assert Dataset.graph(ds, EX.Graph2) assert named_graph?(Dataset.graph(ds, EX.Graph2), iri(EX.Graph2)) assert unnamed_graph?(Dataset.default_graph(ds)) assert Enum.count(ds) == 3 - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1, EX.Graph1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2, EX.Graph1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3, EX.Graph2}) + + assert dataset_includes_statement?( + ds, + {EX.Subject1, EX.predicate1(), EX.Object1, EX.Graph1} + ) + + assert dataset_includes_statement?( + ds, + {EX.Subject1, EX.predicate2(), EX.Object2, EX.Graph1} + ) + + assert dataset_includes_statement?( + ds, + {EX.Subject1, EX.predicate2(), EX.Object3, EX.Graph2} + ) end test "a named Graph with specification of the default context" do - ds = Dataset.add(dataset(), Graph.new([ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - ], name: EX.Graph1), nil) + ds = + Dataset.add( + dataset(), + Graph.new( + [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2} + ], + name: EX.Graph1 + ), + nil + ) + refute Dataset.graph(ds, EX.Graph1) assert unnamed_graph?(Dataset.default_graph(ds)) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + + ds = + Dataset.add( + ds, + Graph.new({EX.Subject1, EX.predicate2(), EX.Object3}, name: EX.Graph2), + nil + ) - ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2, EX.Object3}, name: EX.Graph2), nil) refute Dataset.graph(ds, EX.Graph2) assert unnamed_graph?(Dataset.default_graph(ds)) assert Enum.count(ds) == 3 - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3}) + + ds = + Dataset.add( + ds, + Graph.new({EX.Subject1, EX.predicate2(), EX.Object3}, name: EX.Graph3), + EX.Graph + ) - ds = Dataset.add(ds, Graph.new({EX.Subject1, EX.predicate2, EX.Object3}, name: EX.Graph3), EX.Graph) assert named_graph?(Dataset.graph(ds, EX.Graph), iri(EX.Graph)) assert Enum.count(ds) == 4 - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3, EX.Graph}) end test "an unnamed Dataset" do - ds = Dataset.add(dataset(), Dataset.new([ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - ])) - assert ds.name == nil - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) + ds = + Dataset.add( + dataset(), + Dataset.new([ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2} + ]) + ) - ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2, EX.Object3})) - ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2, EX.Object3, EX.Graph})) - ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2, EX.Object4}), EX.Graph) + assert ds.name == nil + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + + ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2(), EX.Object3})) + ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2(), EX.Object3, EX.Graph})) + ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2(), EX.Object4}), EX.Graph) assert ds.name == nil assert Enum.count(ds) == 5 - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object4, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object4, EX.Graph}) end test "a named Dataset" do - ds = Dataset.add(named_dataset(), Dataset.new([ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - ], name: EX.DS1)) - assert ds.name == iri(EX.DatasetName) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) + ds = + Dataset.add( + named_dataset(), + Dataset.new( + [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2} + ], + name: EX.DS1 + ) + ) + + assert ds.name == iri(EX.DatasetName) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + + ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2(), EX.Object3}, name: EX.DS2)) + + ds = + Dataset.add( + ds, + Dataset.new({EX.Subject1, EX.predicate2(), EX.Object3, EX.Graph}, name: EX.DS2) + ) + + ds = + Dataset.add( + ds, + Dataset.new({EX.Subject1, EX.predicate2(), EX.Object4}, name: EX.DS2), + EX.Graph + ) - ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2, EX.Object3}, name: EX.DS2)) - ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2, EX.Object3, EX.Graph}, name: EX.DS2)) - ds = Dataset.add(ds, Dataset.new({EX.Subject1, EX.predicate2, EX.Object4}, name: EX.DS2), EX.Graph) assert ds.name == iri(EX.DatasetName) assert Enum.count(ds) == 5 - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object3, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2, EX.Object4, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object3, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate2(), EX.Object4, EX.Graph}) end test "a list of Descriptions" do - ds = Dataset.add(dataset(), [ - Description.new({EX.Subject1, EX.predicate1, EX.Object1}), - Description.new({EX.Subject2, EX.predicate2, EX.Object2}), - Description.new({EX.Subject1, EX.predicate3, EX.Object3}) - ]) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject2, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate3, EX.Object3}) + ds = + Dataset.add(dataset(), [ + Description.new({EX.Subject1, EX.predicate1(), EX.Object1}), + Description.new({EX.Subject2, EX.predicate2(), EX.Object2}), + Description.new({EX.Subject1, EX.predicate3(), EX.Object3}) + ]) - ds = Dataset.add(ds, [ - Description.new({EX.Subject1, EX.predicate1, EX.Object1}), - Description.new({EX.Subject2, EX.predicate2, EX.Object2}), - Description.new({EX.Subject1, EX.predicate3, EX.Object3}) - ], EX.Graph) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.Subject2, EX.predicate2, EX.Object2, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate3, EX.Object3, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1, EX.Object1}) - assert dataset_includes_statement?(ds, {EX.Subject2, EX.predicate2, EX.Object2}) - assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate3, EX.Object3}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject2, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate3(), EX.Object3}) + + ds = + Dataset.add( + ds, + [ + Description.new({EX.Subject1, EX.predicate1(), EX.Object1}), + Description.new({EX.Subject2, EX.predicate2(), EX.Object2}), + Description.new({EX.Subject1, EX.predicate3(), EX.Object3}) + ], + EX.Graph + ) + + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject2, EX.predicate2(), EX.Object2, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate3(), EX.Object3, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert dataset_includes_statement?(ds, {EX.Subject2, EX.predicate2(), EX.Object2}) + assert dataset_includes_statement?(ds, {EX.Subject1, EX.predicate3(), EX.Object3}) end test "a list of Graphs" do - ds = Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}]) + ds = + Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}]) |> RDF.Dataset.add([ - Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S1, EX.P2, bnode(:foo)}]), - Graph.new({EX.S1, EX.P2, EX.O3}), - Graph.new([{EX.S1, EX.P2, EX.O2}, {EX.S2, EX.P2, EX.O2}], name: EX.Graph) - ]) + Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S1, EX.P2, bnode(:foo)}]), + Graph.new({EX.S1, EX.P2, EX.O3}), + Graph.new([{EX.S1, EX.P2, EX.O2}, {EX.S2, EX.P2, EX.O2}], name: EX.Graph) + ]) - assert Enum.count(ds) == 6 - assert dataset_includes_statement?(ds, {EX.S1, EX.P1, EX.O1}) - assert dataset_includes_statement?(ds, {EX.S1, EX.P2, bnode(:foo)}) - assert dataset_includes_statement?(ds, {EX.S1, EX.P2, EX.O3}) - assert dataset_includes_statement?(ds, {EX.S2, EX.P2, EX.O2}) - assert dataset_includes_statement?(ds, {EX.S1, EX.P2, EX.O2, EX.Graph}) - assert dataset_includes_statement?(ds, {EX.S2, EX.P2, EX.O2, EX.Graph}) + assert Enum.count(ds) == 6 + assert dataset_includes_statement?(ds, {EX.S1, EX.P1, EX.O1}) + assert dataset_includes_statement?(ds, {EX.S1, EX.P2, bnode(:foo)}) + assert dataset_includes_statement?(ds, {EX.S1, EX.P2, EX.O3}) + assert dataset_includes_statement?(ds, {EX.S2, EX.P2, EX.O2}) + assert dataset_includes_statement?(ds, {EX.S1, EX.P2, EX.O2, EX.Graph}) + assert dataset_includes_statement?(ds, {EX.S2, EX.P2, EX.O2, EX.Graph}) end test "duplicates are ignored" do - ds = Dataset.add(dataset(), {EX.Subject, EX.predicate, EX.Object, EX.GraphName}) - assert Dataset.add(ds, {EX.Subject, EX.predicate, EX.Object, EX.GraphName}) == ds + ds = Dataset.add(dataset(), {EX.Subject, EX.predicate(), EX.Object, EX.GraphName}) + assert Dataset.add(ds, {EX.Subject, EX.predicate(), EX.Object, EX.GraphName}) == ds end test "non-coercible statements elements are causing an error" do assert_raise RDF.IRI.InvalidError, fn -> - Dataset.add(dataset(), {"not a IRI", EX.predicate, iri(EX.Object), iri(EX.GraphName)}) + Dataset.add(dataset(), {"not a IRI", EX.predicate(), iri(EX.Object), iri(EX.GraphName)}) end + assert_raise RDF.Literal.InvalidError, fn -> - Dataset.add(dataset(), {EX.Subject, EX.prop, self(), nil}) + Dataset.add(dataset(), {EX.Subject, EX.prop(), self(), nil}) end + assert_raise RDF.IRI.InvalidError, fn -> - Dataset.add(dataset(), {iri(EX.Subject), EX.predicate, iri(EX.Object), "not a IRI"}) + Dataset.add(dataset(), {iri(EX.Subject), EX.predicate(), iri(EX.Object), "not a IRI"}) end end end describe "put" do test "a list of statements without specification of the default context" do - ds = Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2, EX.Graph}]) + ds = + Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2, EX.Graph}]) |> RDF.Dataset.put([ - {EX.S1, EX.P2, EX.O3, EX.Graph}, - {EX.S1, EX.P2, bnode(:foo), nil}, - {EX.S2, EX.P2, EX.O3, EX.Graph}, - {EX.S2, EX.P2, EX.O4, EX.Graph}]) + {EX.S1, EX.P2, EX.O3, EX.Graph}, + {EX.S1, EX.P2, bnode(:foo), nil}, + {EX.S2, EX.P2, EX.O3, EX.Graph}, + {EX.S2, EX.P2, EX.O4, EX.Graph} + ]) assert Dataset.statement_count(ds) == 5 assert dataset_includes_statement?(ds, {EX.S1, EX.P1, EX.O1}) @@ -458,12 +663,17 @@ defmodule RDF.DatasetTest do end test "a list of statements with specification of the default context" do - ds = Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2, EX.Graph}]) - |> RDF.Dataset.put([ - {EX.S1, EX.P1, EX.O3, EX.Graph}, - {EX.S1, EX.P2, bnode(:foo), nil}, - {EX.S2, EX.P2, EX.O3, EX.Graph}, - {EX.S2, EX.P2, EX.O4}], nil) + ds = + Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2, EX.Graph}]) + |> RDF.Dataset.put( + [ + {EX.S1, EX.P1, EX.O3, EX.Graph}, + {EX.S1, EX.P2, bnode(:foo), nil}, + {EX.S2, EX.P2, EX.O3, EX.Graph}, + {EX.S2, EX.P2, EX.O4} + ], + nil + ) assert Dataset.statement_count(ds) == 5 assert dataset_includes_statement?(ds, {EX.S1, EX.P1, EX.O3}) @@ -472,13 +682,18 @@ defmodule RDF.DatasetTest do assert dataset_includes_statement?(ds, {EX.S2, EX.P2, EX.O4}) assert dataset_includes_statement?(ds, {EX.S2, EX.P2, EX.O2, EX.Graph}) - ds = Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2, EX.Graph}]) - |> RDF.Dataset.put([ - {EX.S1, EX.P1, EX.O3}, - {EX.S1, EX.P1, EX.O4, EX.Graph}, - {EX.S1, EX.P2, bnode(:foo), nil}, - {EX.S2, EX.P2, EX.O3, EX.Graph}, - {EX.S2, EX.P2, EX.O4}], EX.Graph) + ds = + Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2, EX.Graph}]) + |> RDF.Dataset.put( + [ + {EX.S1, EX.P1, EX.O3}, + {EX.S1, EX.P1, EX.O4, EX.Graph}, + {EX.S1, EX.P2, bnode(:foo), nil}, + {EX.S2, EX.P2, EX.O3, EX.Graph}, + {EX.S2, EX.P2, EX.O4} + ], + EX.Graph + ) assert Dataset.statement_count(ds) == 6 assert dataset_includes_statement?(ds, {EX.S1, EX.P1, EX.O1}) @@ -490,7 +705,8 @@ defmodule RDF.DatasetTest do end test "a Description" do - ds = Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}, {EX.S1, EX.P3, EX.O3}]) + ds = + Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}, {EX.S1, EX.P3, EX.O3}]) |> RDF.Dataset.put(Description.new(EX.S1, [{EX.P3, EX.O4}, {EX.P2, bnode(:foo)}])) assert Dataset.statement_count(ds) == 4 @@ -501,7 +717,8 @@ defmodule RDF.DatasetTest do end test "an unnamed Graph" do - ds = Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}, {EX.S1, EX.P3, EX.O3}]) + ds = + Dataset.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}, {EX.S1, EX.P3, EX.O3}]) |> RDF.Dataset.put(Graph.new([{EX.S1, EX.P3, EX.O4}, {EX.S1, EX.P2, bnode(:foo)}])) assert Dataset.statement_count(ds) == 4 @@ -512,10 +729,16 @@ defmodule RDF.DatasetTest do end test "a named Graph" do - ds = Dataset.new( - Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}, {EX.S1, EX.P3, EX.O3}], name: EX.GraphName)) + ds = + Dataset.new( + Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}, {EX.S1, EX.P3, EX.O3}], + name: EX.GraphName + ) + ) |> RDF.Dataset.put( - Graph.new([{EX.S1, EX.P3, EX.O4}, {EX.S1, EX.P2, bnode(:foo)}]), EX.GraphName) + Graph.new([{EX.S1, EX.P3, EX.O4}, {EX.S1, EX.P2, bnode(:foo)}]), + EX.GraphName + ) assert Dataset.statement_count(ds) == 4 assert dataset_includes_statement?(ds, {EX.S1, EX.P1, EX.O1, EX.GraphName}) @@ -525,145 +748,182 @@ defmodule RDF.DatasetTest do end test "simultaneous use of the different forms to address the default context" do - ds = RDF.Dataset.put(dataset(), [ - {EX.S, EX.P, EX.O1}, - {EX.S, EX.P, EX.O2, nil}]) + ds = + RDF.Dataset.put(dataset(), [ + {EX.S, EX.P, EX.O1}, + {EX.S, EX.P, EX.O2, nil} + ]) + assert Dataset.statement_count(ds) == 2 assert dataset_includes_statement?(ds, {EX.S, EX.P, EX.O1}) assert dataset_includes_statement?(ds, {EX.S, EX.P, EX.O2}) end end - describe "delete" do setup do {:ok, - dataset1: Dataset.new({EX.S1, EX.p1, EX.O1}), - dataset2: Dataset.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S2, EX.p2, EX.O2, EX.Graph}, - ]), - dataset3: Dataset.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S2, EX.p2, [EX.O1, EX.O2], EX.Graph1}, - {EX.S3, EX.p3, [~B, ~L"bar"], EX.Graph2}, - ]), - } + dataset1: Dataset.new({EX.S1, EX.p1(), EX.O1}), + dataset2: + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S2, EX.p2(), EX.O2, EX.Graph} + ]), + dataset3: + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S2, EX.p2(), [EX.O1, EX.O2], EX.Graph1}, + {EX.S3, EX.p3(), [~B, ~L"bar"], EX.Graph2} + ])} end test "a single statement", - %{dataset1: dataset1, dataset2: dataset2, dataset3: dataset3} do - assert Dataset.delete(Dataset.new, {EX.S, EX.p, EX.O}) == Dataset.new - assert Dataset.delete(dataset1, {EX.S1, EX.p1, EX.O1}) == Dataset.new - assert Dataset.delete(dataset2, {EX.S2, EX.p2, EX.O2, EX.Graph}) == dataset1 - assert Dataset.delete(dataset2, {EX.S1, EX.p1, EX.O1}) == - Dataset.new({EX.S2, EX.p2, EX.O2, EX.Graph}) - assert Dataset.delete(dataset3, {EX.S2, EX.p2, EX.O1, EX.Graph1}) == - Dataset.new [ - {EX.S1, EX.p1, EX.O1}, - {EX.S2, EX.p2, EX.O2, EX.Graph1}, - {EX.S3, EX.p3, [~B, ~L"bar"], EX.Graph2}, - ] - assert Dataset.delete(dataset3, {EX.S2, EX.p2, [EX.O1, EX.O2], EX.Graph1}) == - Dataset.new [ - {EX.S1, EX.p1, EX.O1}, - {EX.S3, EX.p3, [~B, ~L"bar"], EX.Graph2}, - ] - assert Dataset.delete(dataset3, {EX.S2, EX.p2, [EX.O1, EX.O2]}, EX.Graph1) == - Dataset.new [ - {EX.S1, EX.p1, EX.O1}, - {EX.S3, EX.p3, [~B, ~L"bar"], EX.Graph2}, - ] + %{dataset1: dataset1, dataset2: dataset2, dataset3: dataset3} do + assert Dataset.delete(Dataset.new(), {EX.S, EX.p(), EX.O}) == Dataset.new() + assert Dataset.delete(dataset1, {EX.S1, EX.p1(), EX.O1}) == Dataset.new() + assert Dataset.delete(dataset2, {EX.S2, EX.p2(), EX.O2, EX.Graph}) == dataset1 + + assert Dataset.delete(dataset2, {EX.S1, EX.p1(), EX.O1}) == + Dataset.new({EX.S2, EX.p2(), EX.O2, EX.Graph}) + + assert Dataset.delete(dataset3, {EX.S2, EX.p2(), EX.O1, EX.Graph1}) == + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S2, EX.p2(), EX.O2, EX.Graph1}, + {EX.S3, EX.p3(), [~B, ~L"bar"], EX.Graph2} + ]) + + assert Dataset.delete(dataset3, {EX.S2, EX.p2(), [EX.O1, EX.O2], EX.Graph1}) == + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S3, EX.p3(), [~B, ~L"bar"], EX.Graph2} + ]) + + assert Dataset.delete(dataset3, {EX.S2, EX.p2(), [EX.O1, EX.O2]}, EX.Graph1) == + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S3, EX.p3(), [~B, ~L"bar"], EX.Graph2} + ]) end test "multiple statements with a list of triples", - %{dataset1: dataset1, dataset2: dataset2, dataset3: dataset3} do - assert Dataset.delete(dataset1, [{EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p1, EX.O2}]) == Dataset.new - assert Dataset.delete(dataset2, [{EX.S1, EX.p1, EX.O1}, - {EX.S2, EX.p2, EX.O2, EX.Graph}]) == Dataset.new + %{dataset1: dataset1, dataset2: dataset2, dataset3: dataset3} do + assert Dataset.delete(dataset1, [{EX.S1, EX.p1(), EX.O1}, {EX.S1, EX.p1(), EX.O2}]) == + Dataset.new() + + assert Dataset.delete(dataset2, [{EX.S1, EX.p1(), EX.O1}, {EX.S2, EX.p2(), EX.O2, EX.Graph}]) == + Dataset.new() + assert Dataset.delete(dataset3, [ - {EX.S1, EX.p1, EX.O1}, - {EX.S2, EX.p2, [EX.O1, EX.O2, EX.O3], EX.Graph1}, - {EX.S3, EX.p3, ~B, EX.Graph2}]) == Dataset.new({EX.S3, EX.p3, ~L"bar", EX.Graph2}) + {EX.S1, EX.p1(), EX.O1}, + {EX.S2, EX.p2(), [EX.O1, EX.O2, EX.O3], EX.Graph1}, + {EX.S3, EX.p3(), ~B, EX.Graph2} + ]) == Dataset.new({EX.S3, EX.p3(), ~L"bar", EX.Graph2}) end test "multiple statements with a Description", - %{dataset1: dataset1, dataset2: dataset2} do - assert Dataset.delete(dataset1, Description.new(EX.S1, EX.p1, EX.O1)) == Dataset.new - assert Dataset.delete(dataset1, Description.new(EX.S1, EX.p1, EX.O1), EX.Graph) == dataset1 - assert Dataset.delete(dataset2, Description.new(EX.S2, EX.p2, EX.O2), EX.Graph) == dataset1 - assert Dataset.delete(dataset2, Description.new(EX.S1, EX.p1, EX.O1)) == - Dataset.new({EX.S2, EX.p2, EX.O2, EX.Graph}) + %{dataset1: dataset1, dataset2: dataset2} do + assert Dataset.delete(dataset1, Description.new(EX.S1, EX.p1(), EX.O1)) == Dataset.new() + + assert Dataset.delete(dataset1, Description.new(EX.S1, EX.p1(), EX.O1), EX.Graph) == + dataset1 + + assert Dataset.delete(dataset2, Description.new(EX.S2, EX.p2(), EX.O2), EX.Graph) == + dataset1 + + assert Dataset.delete(dataset2, Description.new(EX.S1, EX.p1(), EX.O1)) == + Dataset.new({EX.S2, EX.p2(), EX.O2, EX.Graph}) end test "multiple statements with a Graph", - %{dataset1: dataset1, dataset2: dataset2, dataset3: dataset3} do - assert Dataset.delete(dataset1, Graph.new({EX.S1, EX.p1, EX.O1})) == Dataset.new - assert Dataset.delete(dataset2, Graph.new({EX.S1, EX.p1, EX.O1})) == - Dataset.new({EX.S2, EX.p2, EX.O2, EX.Graph}) - assert Dataset.delete(dataset2, Graph.new({EX.S2, EX.p2, EX.O2}, name: EX.Graph)) == dataset1 - assert Dataset.delete(dataset2, Graph.new({EX.S2, EX.p2, EX.O2}, name: EX.Graph)) == dataset1 - assert Dataset.delete(dataset2, Graph.new({EX.S2, EX.p2, EX.O2}), EX.Graph) == dataset1 - assert Dataset.delete(dataset2, Graph.new({EX.S2, EX.p2, EX.O2}), EX.Graph) == dataset1 - assert Dataset.delete(dataset3, Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - {EX.S2, EX.p2, EX.O3}, - {EX.S3, EX.p3, ~B}, - ])) == Dataset.new([ - {EX.S2, EX.p2, [EX.O1, EX.O2], EX.Graph1}, - {EX.S3, EX.p3, [~B, ~L"bar"], EX.Graph2}, - ]) - assert Dataset.delete(dataset3, Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - {EX.S2, EX.p2, EX.O3}, - {EX.S3, EX.p3, ~B}, - ], name: EX.Graph2)) == Dataset.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S2, EX.p2, [EX.O1, EX.O2], EX.Graph1}, - {EX.S3, EX.p3, [~L"bar"], EX.Graph2}, - ]) - assert Dataset.delete(dataset3, Graph.new({EX.S3, EX.p3, ~B}), EX.Graph2) == - Dataset.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S2, EX.p2, [EX.O1, EX.O2], EX.Graph1}, - {EX.S3, EX.p3, ~L"bar", EX.Graph2}, - ]) + %{dataset1: dataset1, dataset2: dataset2, dataset3: dataset3} do + assert Dataset.delete(dataset1, Graph.new({EX.S1, EX.p1(), EX.O1})) == Dataset.new() + + assert Dataset.delete(dataset2, Graph.new({EX.S1, EX.p1(), EX.O1})) == + Dataset.new({EX.S2, EX.p2(), EX.O2, EX.Graph}) + + assert Dataset.delete(dataset2, Graph.new({EX.S2, EX.p2(), EX.O2}, name: EX.Graph)) == + dataset1 + + assert Dataset.delete(dataset2, Graph.new({EX.S2, EX.p2(), EX.O2}, name: EX.Graph)) == + dataset1 + + assert Dataset.delete(dataset2, Graph.new({EX.S2, EX.p2(), EX.O2}), EX.Graph) == dataset1 + assert Dataset.delete(dataset2, Graph.new({EX.S2, EX.p2(), EX.O2}), EX.Graph) == dataset1 + + assert Dataset.delete( + dataset3, + Graph.new([ + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + {EX.S2, EX.p2(), EX.O3}, + {EX.S3, EX.p3(), ~B} + ]) + ) == + Dataset.new([ + {EX.S2, EX.p2(), [EX.O1, EX.O2], EX.Graph1}, + {EX.S3, EX.p3(), [~B, ~L"bar"], EX.Graph2} + ]) + + assert Dataset.delete( + dataset3, + Graph.new( + [ + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + {EX.S2, EX.p2(), EX.O3}, + {EX.S3, EX.p3(), ~B} + ], + name: EX.Graph2 + ) + ) == + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S2, EX.p2(), [EX.O1, EX.O2], EX.Graph1}, + {EX.S3, EX.p3(), [~L"bar"], EX.Graph2} + ]) + + assert Dataset.delete(dataset3, Graph.new({EX.S3, EX.p3(), ~B}), EX.Graph2) == + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S2, EX.p2(), [EX.O1, EX.O2], EX.Graph1}, + {EX.S3, EX.p3(), ~L"bar", EX.Graph2} + ]) end test "multiple statements with a Dataset", - %{dataset1: dataset1, dataset2: dataset2} do - assert Dataset.delete(dataset1, dataset1) == Dataset.new - assert Dataset.delete(dataset1, dataset2) == Dataset.new - assert Dataset.delete(dataset2, dataset1) == Dataset.new({EX.S2, EX.p2, EX.O2, EX.Graph}) + %{dataset1: dataset1, dataset2: dataset2} do + assert Dataset.delete(dataset1, dataset1) == Dataset.new() + assert Dataset.delete(dataset1, dataset2) == Dataset.new() + assert Dataset.delete(dataset2, dataset1) == Dataset.new({EX.S2, EX.p2(), EX.O2, EX.Graph}) end end - describe "delete_graph" do setup do {:ok, - dataset1: Dataset.new({EX.S1, EX.p1, EX.O1}), - dataset2: Dataset.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S2, EX.p2, EX.O2, EX.Graph}, - ]), - dataset3: Dataset.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S2, EX.p2, EX.O2, EX.Graph1}, - {EX.S3, EX.p3, EX.O3, EX.Graph2}, - ]), - } + dataset1: Dataset.new({EX.S1, EX.p1(), EX.O1}), + dataset2: + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S2, EX.p2(), EX.O2, EX.Graph} + ]), + dataset3: + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S2, EX.p2(), EX.O2, EX.Graph1}, + {EX.S3, EX.p3(), EX.O3, EX.Graph2} + ])} end test "the default graph", %{dataset1: dataset1, dataset2: dataset2} do - assert Dataset.delete_graph(dataset1, nil) == Dataset.new - assert Dataset.delete_graph(dataset2, nil) == Dataset.new({EX.S2, EX.p2, EX.O2, EX.Graph}) + assert Dataset.delete_graph(dataset1, nil) == Dataset.new() + assert Dataset.delete_graph(dataset2, nil) == Dataset.new({EX.S2, EX.p2(), EX.O2, EX.Graph}) end test "delete_default_graph", %{dataset1: dataset1, dataset2: dataset2} do - assert Dataset.delete_default_graph(dataset1) == Dataset.new - assert Dataset.delete_default_graph(dataset2) == Dataset.new({EX.S2, EX.p2, EX.O2, EX.Graph}) + assert Dataset.delete_default_graph(dataset1) == Dataset.new() + + assert Dataset.delete_default_graph(dataset2) == + Dataset.new({EX.S2, EX.p2(), EX.O2, EX.Graph}) end test "a single graph", %{dataset1: dataset1, dataset2: dataset2} do @@ -671,46 +931,47 @@ defmodule RDF.DatasetTest do assert Dataset.delete_graph(dataset2, EX.Graph) == dataset1 end - test "a list of graphs", %{dataset1: dataset1, dataset3: dataset3} do + test "a list of graphs", %{dataset1: dataset1, dataset3: dataset3} do assert Dataset.delete_graph(dataset3, [EX.Graph1, EX.Graph2]) == dataset1 assert Dataset.delete_graph(dataset3, [EX.Graph1, EX.Graph2, EX.Graph3]) == dataset1 - assert Dataset.delete_graph(dataset3, [EX.Graph1, EX.Graph2, nil]) == Dataset.new + assert Dataset.delete_graph(dataset3, [EX.Graph1, EX.Graph2, nil]) == Dataset.new() end end - test "pop" do - assert Dataset.pop(Dataset.new) == {nil, Dataset.new} + assert Dataset.pop(Dataset.new()) == {nil, Dataset.new()} - {quad, dataset} = Dataset.new({EX.S, EX.p, EX.O, EX.Graph}) |> Dataset.pop - assert quad == {iri(EX.S), iri(EX.p), iri(EX.O), iri(EX.Graph)} + {quad, dataset} = Dataset.new({EX.S, EX.p(), EX.O, EX.Graph}) |> Dataset.pop() + assert quad == {iri(EX.S), iri(EX.p()), iri(EX.O), iri(EX.Graph)} assert Enum.count(dataset.graphs) == 0 {{subject, predicate, object, _}, dataset} = - Dataset.new([{EX.S, EX.p, EX.O, EX.Graph}, {EX.S, EX.p, EX.O}]) - |> Dataset.pop - assert {subject, predicate, object} == {iri(EX.S), iri(EX.p), iri(EX.O)} + Dataset.new([{EX.S, EX.p(), EX.O, EX.Graph}, {EX.S, EX.p(), EX.O}]) + |> Dataset.pop() + + assert {subject, predicate, object} == {iri(EX.S), iri(EX.p()), iri(EX.O)} assert Enum.count(dataset.graphs) == 1 {{subject, _, _, graph_context}, dataset} = - Dataset.new([{EX.S, EX.p, EX.O1, EX.Graph}, {EX.S, EX.p, EX.O2, EX.Graph}]) - |> Dataset.pop + Dataset.new([{EX.S, EX.p(), EX.O1, EX.Graph}, {EX.S, EX.p(), EX.O2, EX.Graph}]) + |> Dataset.pop() + assert subject == iri(EX.S) assert graph_context == iri(EX.Graph) assert Enum.count(dataset.graphs) == 1 end - test "values/1" do assert Dataset.new() |> Dataset.values() == %{} - assert Dataset.new([{EX.s1, EX.p, EX.o1}, {EX.s2, EX.p, EX.o2, EX.graph}]) + + assert Dataset.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2(), EX.graph()}]) |> Dataset.values() == %{ nil => %{ - RDF.Term.value(EX.s1) => %{RDF.Term.value(EX.p) => [RDF.Term.value(EX.o1)]} + RDF.Term.value(EX.s1()) => %{RDF.Term.value(EX.p()) => [RDF.Term.value(EX.o1())]} }, - RDF.Term.value(EX.graph) => %{ - RDF.Term.value(EX.s2) => %{RDF.Term.value(EX.p) => [RDF.Term.value(EX.o2)]}, + RDF.Term.value(EX.graph()) => %{ + RDF.Term.value(EX.s2()) => %{RDF.Term.value(EX.p()) => [RDF.Term.value(EX.o2())]} } } end @@ -719,117 +980,140 @@ defmodule RDF.DatasetTest do mapping = fn {:graph_name, graph_name} -> graph_name + {:predicate, predicate} -> predicate |> to_string() |> String.split("/") |> List.last() |> String.to_atom() + {_, term} -> RDF.Term.value(term) end assert Dataset.new() |> Dataset.values(mapping) == %{} - assert Dataset.new([{EX.s1, EX.p, EX.o1}, {EX.s2, EX.p, EX.o2, EX.graph}]) + + assert Dataset.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2(), EX.graph()}]) |> Dataset.values(mapping) == %{ nil => %{ - RDF.Term.value(EX.s1) => %{p: [RDF.Term.value(EX.o1)]} + RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]} }, - EX.graph => %{ - RDF.Term.value(EX.s2) => %{p: [RDF.Term.value(EX.o2)]}, + EX.graph() => %{ + RDF.Term.value(EX.s2()) => %{p: [RDF.Term.value(EX.o2())]} } } end - test "equal/2" do - triple = {EX.S, EX.p, EX.O} + triple = {EX.S, EX.p(), EX.O} assert Dataset.equal?(Dataset.new(triple), Dataset.new(triple)) - assert Dataset.equal?(Dataset.new(triple, name: EX.Dataset1), - Dataset.new(triple, name: EX.Dataset1)) + + assert Dataset.equal?( + Dataset.new(triple, name: EX.Dataset1), + Dataset.new(triple, name: EX.Dataset1) + ) + assert Dataset.equal?( Dataset.new(Graph.new(triple, name: EX.Graph1, prefixes: %{ex: EX})), Dataset.new(Graph.new(triple, name: EX.Graph1, prefixes: %{ex: RDF})) ) + assert Dataset.equal?( - Dataset.new(Graph.new(triple, name: EX.Graph1, base_iri: EX.base)), - Dataset.new(Graph.new(triple, name: EX.Graph1, base_iri: EX.other_base)) + Dataset.new(Graph.new(triple, name: EX.Graph1, base_iri: EX.base())), + Dataset.new(Graph.new(triple, name: EX.Graph1, base_iri: EX.other_base())) ) - refute Dataset.equal?(Dataset.new(triple), Dataset.new({EX.S, EX.p, EX.O2})) - refute Dataset.equal?(Dataset.new(triple, name: EX.Dataset1), - Dataset.new(triple, name: EX.Dataset2)) + + refute Dataset.equal?(Dataset.new(triple), Dataset.new({EX.S, EX.p(), EX.O2})) + + refute Dataset.equal?( + Dataset.new(triple, name: EX.Dataset1), + Dataset.new(triple, name: EX.Dataset2) + ) + refute Dataset.equal?( Dataset.new(Graph.new(triple, name: EX.Graph1)), Dataset.new(Graph.new(triple, name: EX.Graph2)) ) end - describe "Enumerable protocol" do test "Enum.count" do - assert Enum.count(Dataset.new(name: EX.foo)) == 0 - assert Enum.count(Dataset.new {EX.S, EX.p, EX.O, EX.Graph}) == 1 - assert Enum.count(Dataset.new [{EX.S, EX.p, EX.O1, EX.Graph}, {EX.S, EX.p, EX.O2}]) == 2 + assert Enum.count(Dataset.new(name: EX.foo())) == 0 + assert Enum.count(Dataset.new({EX.S, EX.p(), EX.O, EX.Graph})) == 1 + + assert Enum.count(Dataset.new([{EX.S, EX.p(), EX.O1, EX.Graph}, {EX.S, EX.p(), EX.O2}])) == + 2 + + ds = + Dataset.add(dataset(), [ + {EX.Subject1, EX.predicate1(), EX.Object1, EX.Graph}, + {EX.Subject1, EX.predicate2(), EX.Object2, EX.Graph}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ]) - ds = Dataset.add(dataset(), [ - {EX.Subject1, EX.predicate1, EX.Object1, EX.Graph}, - {EX.Subject1, EX.predicate2, EX.Object2, EX.Graph}, - {EX.Subject3, EX.predicate3, EX.Object3} - ]) assert Enum.count(ds) == 3 end test "Enum.member?" do - refute Enum.member?(Dataset.new, {iri(EX.S), EX.p, iri(EX.O), iri(EX.Graph)}) - assert Enum.member?(Dataset.new({EX.S, EX.p, EX.O, EX.Graph}), - {EX.S, EX.p, EX.O, EX.Graph}) + refute Enum.member?(Dataset.new(), {iri(EX.S), EX.p(), iri(EX.O), iri(EX.Graph)}) - ds = Dataset.add(dataset(), [ - {EX.Subject1, EX.predicate1, EX.Object1, EX.Graph}, - {EX.Subject1, EX.predicate2, EX.Object2, EX.Graph}, - {EX.Subject3, EX.predicate3, EX.Object3} - ]) - assert Enum.member?(ds, {EX.Subject1, EX.predicate1, EX.Object1, EX.Graph}) - assert Enum.member?(ds, {EX.Subject1, EX.predicate2, EX.Object2, EX.Graph}) - assert Enum.member?(ds, {EX.Subject3, EX.predicate3, EX.Object3}) + assert Enum.member?( + Dataset.new({EX.S, EX.p(), EX.O, EX.Graph}), + {EX.S, EX.p(), EX.O, EX.Graph} + ) + + ds = + Dataset.add(dataset(), [ + {EX.Subject1, EX.predicate1(), EX.Object1, EX.Graph}, + {EX.Subject1, EX.predicate2(), EX.Object2, EX.Graph}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ]) + + assert Enum.member?(ds, {EX.Subject1, EX.predicate1(), EX.Object1, EX.Graph}) + assert Enum.member?(ds, {EX.Subject1, EX.predicate2(), EX.Object2, EX.Graph}) + assert Enum.member?(ds, {EX.Subject3, EX.predicate3(), EX.Object3}) end test "Enum.reduce" do - ds = Dataset.add(dataset(), [ - {EX.Subject1, EX.predicate1, EX.Object1, EX.Graph}, - {EX.Subject1, EX.predicate2, EX.Object2}, - {EX.Subject3, EX.predicate3, EX.Object3, EX.Graph} - ]) + ds = + Dataset.add(dataset(), [ + {EX.Subject1, EX.predicate1(), EX.Object1, EX.Graph}, + {EX.Subject1, EX.predicate2(), EX.Object2}, + {EX.Subject3, EX.predicate3(), EX.Object3, EX.Graph} + ]) - assert ds == Enum.reduce(ds, dataset(), - fn(statement, acc) -> acc |> Dataset.add(statement) end) + assert ds == + Enum.reduce(ds, dataset(), fn statement, acc -> acc |> Dataset.add(statement) end) 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} - ] + {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] - ] + [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)) + 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 - assert Dataset.new({EX.S, EX.p, EX.O, EX.Graph})[EX.Graph] == - Graph.new({EX.S, EX.p, EX.O}, name: EX.Graph) + assert Dataset.new()[EX.Graph] == nil + + assert Dataset.new({EX.S, EX.p(), EX.O, EX.Graph})[EX.Graph] == + Graph.new({EX.S, EX.p(), EX.O}, name: EX.Graph) end end - end diff --git a/test/unit/datatypes/generic_test.exs b/test/unit/datatypes/generic_test.exs index 03a6ca8..46c67f0 100644 --- a/test/unit/datatypes/generic_test.exs +++ b/test/unit/datatypes/generic_test.exs @@ -6,192 +6,211 @@ defmodule RDF.Literal.GenericTest do @valid %{ # input => { value , datatype } - "foo" => { "foo" , "http://example.com/datatype" }, + "foo" => {"foo", "http://example.com/datatype"} } describe "new" do test "with value and datatype" do - Enum.each @valid, fn {input, {value, datatype}} -> + Enum.each(@valid, fn {input, {value, datatype}} -> assert %Literal{literal: %Generic{value: ^value, datatype: ^datatype}} = Generic.new(input, datatype: datatype) + assert %Literal{literal: %Generic{value: ^value, datatype: ^datatype}} = Generic.new(input, datatype: RDF.iri(datatype)) - end + end) end test "with datatype directly" do - Enum.each @valid, fn {input, {_, datatype}} -> + Enum.each(@valid, fn {input, {_, datatype}} -> datatype_iri = RDF.iri(datatype) assert Generic.new(input, datatype) == Generic.new(input, datatype: datatype) assert Generic.new(input, datatype_iri) == Generic.new(input, datatype: datatype_iri) - end + end) end test "with datatype as a vocabulary term" do datatype = EX.Datatype |> RDF.iri() |> to_string() + assert %Literal{literal: %Generic{value: "foo", datatype: ^datatype}} = Generic.new("foo", datatype: EX.Datatype) + assert Generic.new("foo", EX.Datatype) == Generic.new("foo", datatype: EX.Datatype) end test "with canonicalize opts" do - Enum.each @valid, fn {input, {value, datatype}} -> + Enum.each(@valid, fn {input, {value, datatype}} -> assert %Literal{literal: %Generic{value: ^value, datatype: ^datatype}} = Generic.new(input, datatype: datatype, canonicalize: true) - end + end) end test "without a datatype it produces an invalid literal" do - Enum.each @valid, fn {input, {value, _}} -> + Enum.each(@valid, fn {input, {value, _}} -> assert %Literal{literal: %Generic{value: ^value, datatype: nil}} = literal = Generic.new(input, []) + assert Generic.valid?(literal) == false - end + end) end test "with nil as a datatype it produces an invalid literal" do - Enum.each @valid, fn {input, {value, _}} -> + Enum.each(@valid, fn {input, {value, _}} -> assert %Literal{literal: %Generic{value: ^value, datatype: nil}} = literal = Generic.new(input, datatype: nil) + assert Generic.valid?(literal) == false - end + end) end test "with the empty string as a datatype it produces an invalid literal" do - Enum.each @valid, fn {input, {value, _}} -> + Enum.each(@valid, fn {input, {value, _}} -> assert %Literal{literal: %Generic{value: ^value, datatype: nil}} = literal = Generic.new(input, datatype: "") + assert Generic.valid?(literal) == false - end + end) end end describe "new!" do test "with valid values, it behaves the same as new" do - Enum.each @valid, fn {input, {_, datatype}} -> + Enum.each(@valid, fn {input, {_, datatype}} -> assert Generic.new!(input, datatype: datatype) == Generic.new(input, datatype: datatype) + assert Generic.new!(input, datatype: datatype, canonicalize: true) == Generic.new(input, datatype: datatype, canonicalize: true) - end + end) end test "without a datatype it raises an error" do - Enum.each @valid, fn {input, _} -> + Enum.each(@valid, fn {input, _} -> assert_raise ArgumentError, fn -> Generic.new!(input, []) end - end + end) end test "with nil as a datatype it raises an error" do - Enum.each @valid, fn {input, _} -> + Enum.each(@valid, fn {input, _} -> assert_raise ArgumentError, fn -> Generic.new!(input, datatype: nil) end - end + end) end test "with the empty string as a datatype it raises an error" do - Enum.each @valid, fn {input, _} -> + Enum.each(@valid, fn {input, _} -> assert_raise ArgumentError, fn -> Generic.new!(input, datatype: "") end - end + end) end end test "datatype?/1" do assert Generic.datatype?(Generic) == true - Enum.each @valid, fn {input, {_, datatype}} -> + + Enum.each(@valid, fn {input, {_, datatype}} -> literal = Generic.new(input, datatype: datatype) assert Generic.datatype?(literal) == true assert Generic.datatype?(literal.literal) == true - end + end) end test "datatype_id/1" do - Enum.each @valid, fn {input, {_, datatype}} -> - assert (Generic.new(input, datatype: datatype) |> Generic.datatype_id()) == RDF.iri(datatype) - end + Enum.each(@valid, fn {input, {_, datatype}} -> + assert Generic.new(input, datatype: datatype) |> Generic.datatype_id() == RDF.iri(datatype) + end) end test "language/1" do - Enum.each @valid, fn {input, {_, datatype}} -> - assert (Generic.new(input, datatype: datatype) |> Generic.language()) == nil - end + Enum.each(@valid, fn {input, {_, datatype}} -> + assert Generic.new(input, datatype: datatype) |> Generic.language() == nil + end) end test "value/1" do - Enum.each @valid, fn {input, {value, datatype}} -> - assert (Generic.new(input, datatype: datatype) |> Generic.value()) == value - end + Enum.each(@valid, fn {input, {value, datatype}} -> + assert Generic.new(input, datatype: datatype) |> Generic.value() == value + end) end test "lexical/1" do - Enum.each @valid, fn {input, {value, datatype}} -> - assert (Generic.new(input, datatype: datatype) |> Generic.lexical()) == value - end + Enum.each(@valid, fn {input, {value, datatype}} -> + assert Generic.new(input, datatype: datatype) |> Generic.lexical() == value + end) end test "canonical/1" do - Enum.each @valid, fn {input, {_, datatype}} -> - assert (Generic.new(input, datatype: datatype) |> Generic.canonical()) == + Enum.each(@valid, fn {input, {_, datatype}} -> + assert Generic.new(input, datatype: datatype) |> Generic.canonical() == Generic.new(input, datatype: datatype) - end + end) end test "canonical?/1" do - Enum.each @valid, fn {input, {_, datatype}} -> - assert (Generic.new(input, datatype: datatype) |> Generic.canonical?()) == true - end + Enum.each(@valid, fn {input, {_, datatype}} -> + assert Generic.new(input, datatype: datatype) |> Generic.canonical?() == true + end) end describe "valid?/1" do test "with a datatype" do - Enum.each @valid, fn {input, {_, datatype}} -> - assert (Generic.new(input, datatype: datatype) |> Generic.valid?()) == true - end + Enum.each(@valid, fn {input, {_, datatype}} -> + assert Generic.new(input, datatype: datatype) |> Generic.valid?() == true + end) end test "without a datatype" do - Enum.each @valid, fn {input, _} -> - assert (Generic.new(input, datatype: nil) |> Generic.valid?()) == false - assert (Generic.new(input, datatype: "") |> Generic.valid?()) == false - end + Enum.each(@valid, fn {input, _} -> + assert Generic.new(input, datatype: nil) |> Generic.valid?() == false + assert Generic.new(input, datatype: "") |> Generic.valid?() == false + end) end end describe "cast/1" do test "always return nil (RDF.Literal.Generic does not support cast)" do - Enum.each @valid, fn {input, {_, datatype}} -> - assert (Generic.new(input, datatype: datatype) |> Generic.cast()) == nil - end + Enum.each(@valid, fn {input, {_, datatype}} -> + assert Generic.new(input, datatype: datatype) |> Generic.cast() == nil + end) end end test "equal_value?/2" do - Enum.each @valid, fn {input, {_, datatype}} -> + Enum.each(@valid, fn {input, {_, datatype}} -> assert Generic.equal_value?( Generic.new(input, datatype: datatype), - Generic.new(input, datatype: datatype)) == true - end + Generic.new(input, datatype: datatype) + ) == true + end) assert Generic.equal_value?( Generic.new("foo", datatype: "http://example.com/foo"), - Generic.new("foo", datatype: "http://example.com/bar")) == nil + Generic.new("foo", datatype: "http://example.com/bar") + ) == nil + assert Generic.equal_value?(Generic.new("foo", []), Generic.new("foo", [])) == true assert Generic.equal_value?(Generic.new("foo", []), Generic.new("bar", [])) == false - assert Generic.equal_value?(Generic.new("foo", datatype: "foo"), RDF.XSD.String.new("foo")) == nil + + assert Generic.equal_value?(Generic.new("foo", datatype: "foo"), RDF.XSD.String.new("foo")) == + nil end test "compare/2" do - Enum.each @valid, fn {input, {_, datatype}} -> + Enum.each(@valid, fn {input, {_, datatype}} -> assert Generic.compare( Generic.new(input, datatype: datatype), - Generic.new(input, datatype: datatype)) == :eq - end + Generic.new(input, datatype: datatype) + ) == :eq + end) - assert Generic.compare(Generic.new("foo", datatype: "en"), Generic.new("bar", datatype: "en")) == :gt - assert Generic.compare(Generic.new("bar", datatype: "en"), Generic.new("baz", datatype: "en")) == :lt + assert Generic.compare(Generic.new("foo", datatype: "en"), Generic.new("bar", datatype: "en")) == + :gt + + assert Generic.compare(Generic.new("bar", datatype: "en"), Generic.new("baz", datatype: "en")) == + :lt assert Generic.compare( Generic.new("foo", datatype: "en"), - Generic.new("foo", datatype: "de")) == nil + Generic.new("foo", datatype: "de") + ) == nil + assert Generic.compare(Generic.new("foo", []), Generic.new("foo", [])) == nil assert Generic.compare(Generic.new("foo", []), RDF.XSD.String.new("foo")) == nil end diff --git a/test/unit/datatypes/lang_string_test.exs b/test/unit/datatypes/lang_string_test.exs index ae142b3..2233167 100644 --- a/test/unit/datatypes/lang_string_test.exs +++ b/test/unit/datatypes/lang_string_test.exs @@ -5,171 +5,179 @@ defmodule RDF.LangStringTest do alias RDF.XSD @valid %{ - # input => { value , language } - "foo" => { "foo" , "en" }, - 0 => { "0" , "en" }, - 42 => { "42" , "en" }, - 3.14 => { "3.14" , "en" }, - true => { "true" , "en" }, - false => { "false" , "en" }, + # input => { value, language } + "foo" => {"foo", "en"}, + 0 => {"0", "en"}, + 42 => {"42", "en"}, + 3.14 => {"3.14", "en"}, + true => {"true", "en"}, + false => {"false", "en"} } describe "new" do test "with value and language" do - Enum.each @valid, fn {input, {value, language}} -> + Enum.each(@valid, fn {input, {value, language}} -> assert %Literal{literal: %LangString{value: ^value, language: ^language}} = LangString.new(input, language: language) + assert %Literal{literal: %LangString{value: ^value, language: ^language}} = LangString.new(input, language: String.to_atom(language)) - end + end) end test "with language directly" do - Enum.each @valid, fn {input, {_, language}} -> + Enum.each(@valid, fn {input, {_, language}} -> assert LangString.new(input, language) == LangString.new(input, language: language) + assert LangString.new(input, String.to_atom(language)) == LangString.new(input, language: String.to_atom(language)) - end + end) end test "language get normalized to downcase" do - Enum.each @valid, fn {input, {value, _}} -> + Enum.each(@valid, fn {input, {value, _}} -> assert %Literal{literal: %LangString{value: ^value, language: "de"}} = LangString.new(input, language: "DE") - end + end) end test "with canonicalize opts" do - Enum.each @valid, fn {input, {value, language}} -> + Enum.each(@valid, fn {input, {value, language}} -> assert %Literal{literal: %LangString{value: ^value, language: ^language}} = LangString.new(input, language: language, canonicalize: true) - end + end) end test "without a language it produces an invalid literal" do - Enum.each @valid, fn {input, {value, _}} -> + Enum.each(@valid, fn {input, {value, _}} -> assert %Literal{literal: %LangString{value: ^value, language: nil}} = literal = LangString.new(input, []) + assert LangString.valid?(literal) == false - end + end) end test "with nil as a language it produces an invalid literal" do - Enum.each @valid, fn {input, {value, _}} -> + Enum.each(@valid, fn {input, {value, _}} -> assert %Literal{literal: %LangString{value: ^value, language: nil}} = literal = LangString.new(input, language: nil) + assert LangString.valid?(literal) == false - end + end) end test "with the empty string as a language it produces an invalid literal" do - Enum.each @valid, fn {input, {value, _}} -> + Enum.each(@valid, fn {input, {value, _}} -> assert %Literal{literal: %LangString{value: ^value, language: nil}} = literal = LangString.new(input, language: "") + assert LangString.valid?(literal) == false - end + end) end end describe "new!" do test "with valid values, it behaves the same as new" do - Enum.each @valid, fn {input, {_, language}} -> + Enum.each(@valid, fn {input, {_, language}} -> assert LangString.new!(input, language: language) == - LangString.new(input, language: language) + LangString.new(input, language: language) + assert LangString.new!(input, language: language, canonicalize: true) == - LangString.new(input, language: language, canonicalize: true) - end + LangString.new(input, language: language, canonicalize: true) + end) end test "without a language it raises an error" do - Enum.each @valid, fn {input, _} -> + Enum.each(@valid, fn {input, _} -> assert_raise ArgumentError, fn -> LangString.new!(input, []) end - end + end) end test "with nil as a language it raises an error" do - Enum.each @valid, fn {input, _} -> + Enum.each(@valid, fn {input, _} -> assert_raise ArgumentError, fn -> LangString.new!(input, language: nil) end - end + end) end test "with the empty string as a language it raises an error" do - Enum.each @valid, fn {input, _} -> + Enum.each(@valid, fn {input, _} -> assert_raise ArgumentError, fn -> LangString.new!(input, language: "") end - end + end) end end test "datatype?/1" do assert LangString.datatype?(LangString) == true - Enum.each @valid, fn {input, {_, language}} -> + + Enum.each(@valid, fn {input, {_, language}} -> literal = LangString.new(input, language: language) assert LangString.datatype?(literal) == true assert LangString.datatype?(literal.literal) == true - end + end) end test "datatype_id/1" do - Enum.each @valid, fn {input, {_, language}} -> - assert (LangString.new(input, language: language) |> LangString.datatype_id()) == RDF.iri(LangString.id()) - end + Enum.each(@valid, fn {input, {_, language}} -> + assert LangString.new(input, language: language) |> LangString.datatype_id() == + RDF.iri(LangString.id()) + end) end test "language/1" do - Enum.each @valid, fn {input, {_, language}} -> - assert (LangString.new(input, language: language) |> LangString.language()) == language - end + Enum.each(@valid, fn {input, {_, language}} -> + assert LangString.new(input, language: language) |> LangString.language() == language + end) - assert (LangString.new("foo", language: nil) |> LangString.language()) == nil - assert (LangString.new("foo", language: "") |> LangString.language()) == nil + assert LangString.new("foo", language: nil) |> LangString.language() == nil + assert LangString.new("foo", language: "") |> LangString.language() == nil end test "value/1" do - Enum.each @valid, fn {input, {value, language}} -> - assert (LangString.new(input, language: language) |> LangString.value()) == value - end + Enum.each(@valid, fn {input, {value, language}} -> + assert LangString.new(input, language: language) |> LangString.value() == value + end) end test "lexical/1" do - Enum.each @valid, fn {input, {value, language}} -> - assert (LangString.new(input, language: language) |> LangString.lexical()) == value - end + Enum.each(@valid, fn {input, {value, language}} -> + assert LangString.new(input, language: language) |> LangString.lexical() == value + end) end test "canonical/1" do - Enum.each @valid, fn {input, {_, language}} -> - assert (LangString.new(input, language: language) |> LangString.canonical()) == + Enum.each(@valid, fn {input, {_, language}} -> + assert LangString.new(input, language: language) |> LangString.canonical() == LangString.new(input, language: language) - end + end) end test "canonical?/1" do - Enum.each @valid, fn {input, {_, language}} -> - assert (LangString.new(input, language: language) |> LangString.canonical?()) == true - end + Enum.each(@valid, fn {input, {_, language}} -> + assert LangString.new(input, language: language) |> LangString.canonical?() == true + end) end describe "valid?/1" do test "with a language" do - Enum.each @valid, fn {input, {_, language}} -> - assert (LangString.new(input, language: language) |> LangString.valid?()) == true - end + Enum.each(@valid, fn {input, {_, language}} -> + assert LangString.new(input, language: language) |> LangString.valid?() == true + end) end test "without a language" do - Enum.each @valid, fn {input, _} -> - assert (LangString.new(input, language: nil) |> LangString.valid?()) == false - assert (LangString.new(input, language: "") |> LangString.valid?()) == false - end + Enum.each(@valid, fn {input, _} -> + assert LangString.new(input, language: nil) |> LangString.valid?() == false + assert LangString.new(input, language: "") |> LangString.valid?() == false + end) end end describe "cast/1" do test "when given a valid RDF.LangString literal" do - Enum.each @valid, fn {input, {_, language}} -> + Enum.each(@valid, fn {input, {_, language}} -> assert LangString.new(input, language: language) |> LangString.cast() == LangString.new(input, language: language) - end + end) end test "when given an valid RDF.LangString literal" do @@ -192,15 +200,18 @@ defmodule RDF.LangStringTest do end test "equal_value?/2" do - Enum.each @valid, fn {input, {_, language}} -> + Enum.each(@valid, fn {input, {_, language}} -> assert LangString.equal_value?( LangString.new(input, language: language), - LangString.new(input, language: language)) == true - end + LangString.new(input, language: language) + ) == true + end) assert LangString.equal_value?( LangString.new("foo", language: "en"), - LangString.new("foo", language: "de")) == false + LangString.new("foo", language: "de") + ) == false + assert LangString.equal_value?(LangString.new("foo", []), LangString.new("foo", [])) == true assert LangString.equal_value?(LangString.new("foo", []), LangString.new("bar", [])) == false assert LangString.equal_value?(LangString.new("foo", []), RDF.XSD.String.new("foo")) == nil @@ -208,18 +219,28 @@ defmodule RDF.LangStringTest do end test "compare/2" do - Enum.each @valid, fn {input, {_, language}} -> + Enum.each(@valid, fn {input, {_, language}} -> assert LangString.compare( LangString.new(input, language: language), - LangString.new(input, language: language)) == :eq - end - - assert LangString.compare(LangString.new("foo", language: "en"), LangString.new("bar", language: "en")) == :gt - assert LangString.compare(LangString.new("bar", language: "en"), LangString.new("baz", language: "en")) == :lt + LangString.new(input, language: language) + ) == :eq + end) assert LangString.compare( LangString.new("foo", language: "en"), - LangString.new("foo", language: "de")) == nil + LangString.new("bar", language: "en") + ) == :gt + + assert LangString.compare( + LangString.new("bar", language: "en"), + LangString.new("baz", language: "en") + ) == :lt + + assert LangString.compare( + LangString.new("foo", language: "en"), + LangString.new("foo", language: "de") + ) == nil + assert LangString.compare(LangString.new("foo", []), LangString.new("foo", [])) == nil assert LangString.compare(LangString.new("foo", []), RDF.XSD.String.new("foo")) == nil end @@ -231,35 +252,39 @@ defmodule RDF.LangStringTest do {"de-DE", "de"}, {"de-CH", "de"}, {"de-CH", "de-ch"}, - {"de-DE-1996", "de-de"}, + {"de-DE-1996", "de-de"} ] @negative_examples [ {"en", "de"}, {"de", "de-CH"}, {"de-Deva", "de-de"}, - {"de-Latn-DE", "de-de"}, + {"de-Latn-DE", "de-de"} ] test "with a language tag and a matching non-'*' language range" do - Enum.each @positive_examples, fn {language_tag, language_range} -> + Enum.each(@positive_examples, fn {language_tag, language_range} -> assert LangString.match_language?(language_tag, language_range), - "expected language range #{inspect language_range} to match language tag #{inspect language_tag}, but it didn't" - end + "expected language range #{inspect(language_range)} to match language tag #{ + inspect(language_tag) + }, but it didn't" + end) end test "with a language tag and a non-matching non-'*' language range" do - Enum.each @negative_examples, fn {language_tag, language_range} -> + Enum.each(@negative_examples, fn {language_tag, language_range} -> refute LangString.match_language?(language_tag, language_range), - "expected language range #{inspect language_range} to not match language tag #{inspect language_tag}, but it did" - end + "expected language range #{inspect(language_range)} to not match language tag #{ + inspect(language_tag) + }, but it did" + end) end test "with a language tag and '*' language range" do - Enum.each @positive_examples ++ @negative_examples, fn {language_tag, _} -> + Enum.each(@positive_examples ++ @negative_examples, fn {language_tag, _} -> assert LangString.match_language?(language_tag, "*"), - ~s[expected language range "*" to match language tag #{inspect language_tag}, but it didn't] - end + ~s[expected language range "*" to match language tag #{inspect(language_tag)}, but it didn't] + end) end test "with the empty string as language tag" do @@ -272,16 +297,22 @@ defmodule RDF.LangStringTest do end test "with a RDF.LangString literal and a language range" do - Enum.each @positive_examples, fn {language_tag, language_range} -> + Enum.each(@positive_examples, fn {language_tag, language_range} -> literal = LangString.new("foo", language: language_tag) + assert LangString.match_language?(literal, language_range), - "expected language range #{inspect language_range} to match #{inspect literal}, but it didn't" - end - Enum.each @negative_examples, fn {language_tag, language_range} -> + "expected language range #{inspect(language_range)} to match #{inspect(literal)}, but it didn't" + end) + + Enum.each(@negative_examples, fn {language_tag, language_range} -> literal = LangString.new("foo", language: language_tag) + refute LangString.match_language?(literal, language_range), - "expected language range #{inspect language_range} to not match #{inspect literal}, but it did" - end + "expected language range #{inspect(language_range)} to not match #{ + inspect(literal) + }, but it did" + end) + refute LangString.match_language?(LangString.new("foo", language: ""), "de") refute LangString.match_language?(LangString.new("foo", language: ""), "*") refute LangString.match_language?(LangString.new("foo", language: nil), "de") diff --git a/test/unit/description_test.exs b/test/unit/description_test.exs index 4fc7f28..742cfcf 100644 --- a/test/unit/description_test.exs +++ b/test/unit/description_test.exs @@ -3,16 +3,19 @@ defmodule RDF.DescriptionTest do doctest RDF.Description - describe "new" do test "with a subject IRI" do - assert description_of_subject(Description.new(~I), - ~I) + assert description_of_subject( + Description.new(~I), + ~I + ) end test "with a raw subject IRI string" do - assert description_of_subject(Description.new("http://example.com/description/subject"), - ~I) + assert description_of_subject( + Description.new("http://example.com/description/subject"), + ~I + ) end test "with an unresolved subject IRI term atom" do @@ -24,34 +27,38 @@ defmodule RDF.DescriptionTest do end test "with a single initial triple" do - desc = Description.new({EX.Subject, EX.predicate, EX.Object}) + desc = Description.new({EX.Subject, EX.predicate(), EX.Object}) assert description_of_subject(desc, iri(EX.Subject)) - assert description_includes_predication(desc, {EX.predicate, iri(EX.Object)}) + assert description_includes_predication(desc, {EX.predicate(), iri(EX.Object)}) - desc = Description.new(EX.Subject, EX.predicate, 42) + desc = Description.new(EX.Subject, EX.predicate(), 42) assert description_of_subject(desc, iri(EX.Subject)) - assert description_includes_predication(desc, {EX.predicate, literal(42)}) + assert description_includes_predication(desc, {EX.predicate(), literal(42)}) end test "with a list of initial triples" do - desc = Description.new([{EX.Subject, EX.predicate1, EX.Object1}, - {EX.Subject, EX.predicate2, EX.Object2}]) - assert description_of_subject(desc, iri(EX.Subject)) - assert description_includes_predication(desc, {EX.predicate1, iri(EX.Object1)}) - assert description_includes_predication(desc, {EX.predicate2, iri(EX.Object2)}) + desc = + Description.new([ + {EX.Subject, EX.predicate1(), EX.Object1}, + {EX.Subject, EX.predicate2(), EX.Object2} + ]) - desc = Description.new(EX.Subject, EX.predicate, [EX.Object, bnode(:foo), "bar"]) assert description_of_subject(desc, iri(EX.Subject)) - assert description_includes_predication(desc, {EX.predicate, iri(EX.Object)}) - assert description_includes_predication(desc, {EX.predicate, bnode(:foo)}) - assert description_includes_predication(desc, {EX.predicate, literal("bar")}) + assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate2(), iri(EX.Object2)}) + + desc = Description.new(EX.Subject, EX.predicate(), [EX.Object, bnode(:foo), "bar"]) + assert description_of_subject(desc, iri(EX.Subject)) + assert description_includes_predication(desc, {EX.predicate(), iri(EX.Object)}) + assert description_includes_predication(desc, {EX.predicate(), bnode(:foo)}) + assert description_includes_predication(desc, {EX.predicate(), literal("bar")}) end test "from another description" do - desc1 = Description.new({EX.Other, EX.predicate, EX.Object}) + desc1 = Description.new({EX.Other, EX.predicate(), EX.Object}) desc2 = Description.new(EX.Subject, desc1) assert description_of_subject(desc2, iri(EX.Subject)) - assert description_includes_predication(desc2, {EX.predicate, iri(EX.Object)}) + assert description_includes_predication(desc2, {EX.predicate(), iri(EX.Object)}) end test "from a map with coercible RDF term" do @@ -61,123 +68,150 @@ defmodule RDF.DescriptionTest do end test "with another description as subject, it performs and add " do - desc = Description.new({EX.S, EX.p, EX.O}) + desc = Description.new({EX.S, EX.p(), EX.O}) - assert Description.new(desc, EX.p2, EX.O2) == - Description.add(desc, EX.p2, EX.O2) - assert Description.new(desc, EX.p, [EX.O1, EX.O2]) == - Description.add(desc, EX.p, [EX.O1, EX.O2]) + assert Description.new(desc, EX.p2(), EX.O2) == + Description.add(desc, EX.p2(), EX.O2) + + assert Description.new(desc, EX.p(), [EX.O1, EX.O2]) == + Description.add(desc, EX.p(), [EX.O1, EX.O2]) end end - describe "add" do test "a predicate-object-pair of proper RDF terms" do - assert Description.add(description(), EX.predicate, iri(EX.Object)) - |> description_includes_predication({EX.predicate, iri(EX.Object)}) - assert Description.add(description(), {EX.predicate, iri(EX.Object)}) - |> description_includes_predication({EX.predicate, iri(EX.Object)}) + assert Description.add(description(), EX.predicate(), iri(EX.Object)) + |> description_includes_predication({EX.predicate(), iri(EX.Object)}) + + assert Description.add(description(), {EX.predicate(), iri(EX.Object)}) + |> description_includes_predication({EX.predicate(), iri(EX.Object)}) end test "a predicate-object-pair of coercible RDF terms" do - assert Description.add(description(), - "http://example.com/predicate", iri(EX.Object)) - |> description_includes_predication({EX.predicate, iri(EX.Object)}) + assert Description.add(description(), "http://example.com/predicate", iri(EX.Object)) + |> description_includes_predication({EX.predicate(), iri(EX.Object)}) - assert Description.add(description(), - {"http://example.com/predicate", 42}) - |> description_includes_predication({EX.predicate, literal(42)}) + assert Description.add( + description(), + {"http://example.com/predicate", 42} + ) + |> description_includes_predication({EX.predicate(), literal(42)}) - assert Description.add(description(), - {"http://example.com/predicate", true}) - |> description_includes_predication({EX.predicate, literal(true)}) + assert Description.add( + description(), + {"http://example.com/predicate", true} + ) + |> description_includes_predication({EX.predicate(), literal(true)}) - assert Description.add(description(), - {"http://example.com/predicate", bnode(:foo)}) - |> description_includes_predication({EX.predicate, bnode(:foo)}) + assert Description.add( + description(), + {"http://example.com/predicate", bnode(:foo)} + ) + |> description_includes_predication({EX.predicate(), bnode(:foo)}) end test "a proper triple" do - assert Description.add(description(), - {iri(EX.Subject), EX.predicate, iri(EX.Object)}) - |> description_includes_predication({EX.predicate, iri(EX.Object)}) + assert Description.add( + description(), + {iri(EX.Subject), EX.predicate(), iri(EX.Object)} + ) + |> description_includes_predication({EX.predicate(), iri(EX.Object)}) - assert Description.add(description(), - {iri(EX.Subject), EX.predicate, literal(42)}) - |> description_includes_predication({EX.predicate, literal(42)}) + assert Description.add( + description(), + {iri(EX.Subject), EX.predicate(), literal(42)} + ) + |> description_includes_predication({EX.predicate(), literal(42)}) - assert Description.add(description(), - {iri(EX.Subject), EX.predicate, bnode(:foo)}) - |> description_includes_predication({EX.predicate, bnode(:foo)}) + assert Description.add( + description(), + {iri(EX.Subject), EX.predicate(), bnode(:foo)} + ) + |> description_includes_predication({EX.predicate(), bnode(:foo)}) end test "add ignores triples not about the subject of the Description struct" do assert empty_description( - Description.add(description(), {EX.Other, EX.predicate, iri(EX.Object)})) + Description.add(description(), {EX.Other, EX.predicate(), iri(EX.Object)}) + ) end test "a list of predicate-object-pairs" do - desc = Description.add(description(), - [{EX.predicate, EX.Object1}, {EX.predicate, EX.Object2}]) - assert description_includes_predication(desc, {EX.predicate, iri(EX.Object1)}) - assert description_includes_predication(desc, {EX.predicate, iri(EX.Object2)}) + desc = + Description.add( + description(), + [{EX.predicate(), EX.Object1}, {EX.predicate(), EX.Object2}] + ) + + assert description_includes_predication(desc, {EX.predicate(), iri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate(), iri(EX.Object2)}) end test "a list of triples" do - desc = Description.add(description(), [ - {EX.Subject, EX.predicate1, EX.Object1}, - {EX.Subject, EX.predicate2, EX.Object2} - ]) - assert description_includes_predication(desc, {EX.predicate1, iri(EX.Object1)}) - assert description_includes_predication(desc, {EX.predicate2, iri(EX.Object2)}) + desc = + Description.add(description(), [ + {EX.Subject, EX.predicate1(), EX.Object1}, + {EX.Subject, EX.predicate2(), EX.Object2} + ]) + + assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate2(), iri(EX.Object2)}) end test "a list of mixed triples and predicate-object-pairs" do - desc = Description.add(description(), [ - {EX.predicate, EX.Object1}, - {EX.Subject, EX.predicate, EX.Object2}, - {EX.Other, EX.predicate, EX.Object3} - ]) + desc = + Description.add(description(), [ + {EX.predicate(), EX.Object1}, + {EX.Subject, EX.predicate(), EX.Object2}, + {EX.Other, EX.predicate(), EX.Object3} + ]) + assert description_of_subject(desc, iri(EX.Subject)) - assert description_includes_predication(desc, {EX.predicate, iri(EX.Object1)}) - assert description_includes_predication(desc, {EX.predicate, iri(EX.Object2)}) - refute description_includes_predication(desc, {EX.predicate, iri(EX.Object3)}) + assert description_includes_predication(desc, {EX.predicate(), iri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate(), iri(EX.Object2)}) + refute description_includes_predication(desc, {EX.predicate(), iri(EX.Object3)}) end test "another description" do - desc = description([{EX.predicate1, EX.Object1}, {EX.predicate2, EX.Object2}]) - |> Description.add(Description.new({EX.Other, EX.predicate3, EX.Object3})) + desc = + description([{EX.predicate1(), EX.Object1}, {EX.predicate2(), EX.Object2}]) + |> Description.add(Description.new({EX.Other, EX.predicate3(), EX.Object3})) assert description_of_subject(desc, iri(EX.Subject)) - assert description_includes_predication(desc, {EX.predicate1, iri(EX.Object1)}) - assert description_includes_predication(desc, {EX.predicate2, iri(EX.Object2)}) - assert description_includes_predication(desc, {EX.predicate3, iri(EX.Object3)}) + assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate2(), iri(EX.Object2)}) + assert description_includes_predication(desc, {EX.predicate3(), iri(EX.Object3)}) - desc = Description.add(desc, Description.new({EX.Other, EX.predicate1, EX.Object4})) - assert description_includes_predication(desc, {EX.predicate1, iri(EX.Object1)}) - assert description_includes_predication(desc, {EX.predicate2, iri(EX.Object2)}) - assert description_includes_predication(desc, {EX.predicate3, iri(EX.Object3)}) - assert description_includes_predication(desc, {EX.predicate1, iri(EX.Object4)}) + desc = Description.add(desc, Description.new({EX.Other, EX.predicate1(), EX.Object4})) + assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate2(), iri(EX.Object2)}) + assert description_includes_predication(desc, {EX.predicate3(), iri(EX.Object3)}) + assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object4)}) end test "a map of predications with coercible RDF terms" do - desc = description([{EX.predicate1, EX.Object1}, {EX.predicate2, EX.Object2}]) - |> Description.add(%{EX.predicate3 => EX.Object3}) + desc = + description([{EX.predicate1(), EX.Object1}, {EX.predicate2(), EX.Object2}]) + |> Description.add(%{EX.predicate3() => EX.Object3}) assert description_of_subject(desc, iri(EX.Subject)) - assert description_includes_predication(desc, {EX.predicate1, iri(EX.Object1)}) - assert description_includes_predication(desc, {EX.predicate2, iri(EX.Object2)}) - assert description_includes_predication(desc, {EX.predicate3, iri(EX.Object3)}) + assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate2(), iri(EX.Object2)}) + assert description_includes_predication(desc, {EX.predicate3(), iri(EX.Object3)}) + + desc = + Description.add(desc, %{ + EX.predicate1() => EX.Object1, + EX.predicate2() => [EX.Object2, 42], + EX.predicate3() => [bnode(:foo)] + }) - desc = Description.add(desc, %{EX.predicate1 => EX.Object1, - EX.predicate2 => [EX.Object2, 42], - EX.predicate3 => [bnode(:foo)]}) assert Description.count(desc) == 5 - assert description_includes_predication(desc, {EX.predicate1, iri(EX.Object1)}) - assert description_includes_predication(desc, {EX.predicate2, iri(EX.Object2)}) - assert description_includes_predication(desc, {EX.predicate2, literal(42)}) - assert description_includes_predication(desc, {EX.predicate3, iri(EX.Object3)}) - assert description_includes_predication(desc, {EX.predicate3, bnode(:foo)}) + assert description_includes_predication(desc, {EX.predicate1(), iri(EX.Object1)}) + assert description_includes_predication(desc, {EX.predicate2(), iri(EX.Object2)}) + assert description_includes_predication(desc, {EX.predicate2(), literal(42)}) + assert description_includes_predication(desc, {EX.predicate3(), iri(EX.Object3)}) + assert description_includes_predication(desc, {EX.predicate3(), bnode(:foo)}) end test "a map of predications with non-coercible RDF terms" do @@ -186,17 +220,17 @@ defmodule RDF.DescriptionTest do end assert_raise RDF.Literal.InvalidError, fn -> - Description.add(description(), %{EX.prop => self()}) + Description.add(description(), %{EX.prop() => self()}) end end test "duplicates are ignored" do - desc = Description.add(description(), {EX.predicate, EX.Object}) - assert Description.add(desc, {EX.predicate, EX.Object}) == desc - assert Description.add(desc, {EX.Subject, EX.predicate, EX.Object}) == desc + desc = Description.add(description(), {EX.predicate(), EX.Object}) + assert Description.add(desc, {EX.predicate(), EX.Object}) == desc + assert Description.add(desc, {EX.Subject, EX.predicate(), EX.Object}) == desc - desc = Description.add(description(), {EX.predicate, 42}) - assert Description.add(desc, {EX.predicate, literal(42)}) == desc + desc = Description.add(description(), {EX.predicate(), 42}) + assert Description.add(desc, {EX.predicate(), literal(42)}) == desc end test "non-coercible Triple elements are causing an error" do @@ -205,7 +239,7 @@ defmodule RDF.DescriptionTest do end assert_raise RDF.Literal.InvalidError, fn -> - Description.add(description(), {EX.prop, self()}) + Description.add(description(), {EX.prop(), self()}) end end end @@ -213,115 +247,164 @@ defmodule RDF.DescriptionTest do describe "delete" do setup do {:ok, - empty_description: Description.new(EX.S), - description1: Description.new(EX.S, EX.p, EX.O), - description2: Description.new(EX.S, EX.p, [EX.O1, EX.O2]), - description3: Description.new(EX.S, [ - {EX.p1, [EX.O1, EX.O2]}, - {EX.p2, EX.O3}, - {EX.p3, [~B, ~L"bar"]}, - ]) - } + empty_description: Description.new(EX.S), + description1: Description.new(EX.S, EX.p(), EX.O), + description2: Description.new(EX.S, EX.p(), [EX.O1, EX.O2]), + description3: + Description.new(EX.S, [ + {EX.p1(), [EX.O1, EX.O2]}, + {EX.p2(), EX.O3}, + {EX.p3(), [~B, ~L"bar"]} + ])} end test "a single statement as a predicate object", - %{empty_description: empty_description, description1: description1, description2: description2} do - assert Description.delete(empty_description, EX.p, EX.O) == empty_description - assert Description.delete(description1, EX.p, EX.O) == empty_description - assert Description.delete(description2, EX.p, EX.O1) == Description.new(EX.S, EX.p, EX.O2) + %{ + empty_description: empty_description, + description1: description1, + description2: description2 + } do + assert Description.delete(empty_description, EX.p(), EX.O) == empty_description + assert Description.delete(description1, EX.p(), EX.O) == empty_description + + assert Description.delete(description2, EX.p(), EX.O1) == + Description.new(EX.S, EX.p(), EX.O2) end test "a single statement as a predicate-object tuple", - %{empty_description: empty_description, description1: description1, description2: description2} do - assert Description.delete(empty_description, {EX.p, EX.O}) == empty_description - assert Description.delete(description1, {EX.p, EX.O}) == empty_description - assert Description.delete(description2, {EX.p, EX.O2}) == Description.new(EX.S, EX.p, EX.O1) + %{ + empty_description: empty_description, + description1: description1, + description2: description2 + } do + assert Description.delete(empty_description, {EX.p(), EX.O}) == empty_description + assert Description.delete(description1, {EX.p(), EX.O}) == empty_description + + assert Description.delete(description2, {EX.p(), EX.O2}) == + Description.new(EX.S, EX.p(), EX.O1) end test "a single statement as a subject-predicate-object tuple and the proper description subject", - %{empty_description: empty_description, description1: description1, description2: description2} do - assert Description.delete(empty_description, {EX.S, EX.p, EX.O}) == empty_description - assert Description.delete(description1, {EX.S, EX.p, EX.O}) == empty_description - assert Description.delete(description2, {EX.S, EX.p, EX.O2}) == Description.new(EX.S, EX.p, EX.O1) + %{ + empty_description: empty_description, + description1: description1, + description2: description2 + } do + assert Description.delete(empty_description, {EX.S, EX.p(), EX.O}) == empty_description + assert Description.delete(description1, {EX.S, EX.p(), EX.O}) == empty_description + + assert Description.delete(description2, {EX.S, EX.p(), EX.O2}) == + Description.new(EX.S, EX.p(), EX.O1) end test "a single statement as a subject-predicate-object tuple and another description subject", - %{empty_description: empty_description, description1: description1, description2: description2} do - assert Description.delete(empty_description, {EX.Other, EX.p, EX.O}) == empty_description - assert Description.delete(description1, {EX.Other, EX.p, EX.O}) == description1 - assert Description.delete(description2, {EX.Other, EX.p, EX.O2}) == description2 + %{ + empty_description: empty_description, + description1: description1, + description2: description2 + } do + assert Description.delete(empty_description, {EX.Other, EX.p(), EX.O}) == empty_description + assert Description.delete(description1, {EX.Other, EX.p(), EX.O}) == description1 + assert Description.delete(description2, {EX.Other, EX.p(), EX.O2}) == description2 end test "multiple statements via predicate-objects tuple", - %{empty_description: empty_description, description1: description1, description2: description2} do - assert Description.delete(empty_description, {EX.p, [EX.O1, EX.O2]}) == empty_description - assert Description.delete(description1, {EX.p, [EX.O, EX.O2]}) == empty_description - assert Description.delete(description2, {EX.p, [EX.O1, EX.O2]}) == empty_description + %{ + empty_description: empty_description, + description1: description1, + description2: description2 + } do + assert Description.delete(empty_description, {EX.p(), [EX.O1, EX.O2]}) == empty_description + assert Description.delete(description1, {EX.p(), [EX.O, EX.O2]}) == empty_description + assert Description.delete(description2, {EX.p(), [EX.O1, EX.O2]}) == empty_description end test "multiple statements with a list", - %{empty_description: empty_description, description3: description3} do - assert Description.delete(empty_description, [{EX.p, [EX.O1, EX.O2]}]) == empty_description + %{empty_description: empty_description, description3: description3} do + assert Description.delete(empty_description, [{EX.p(), [EX.O1, EX.O2]}]) == + empty_description + assert Description.delete(description3, [ - {EX.p1, EX.O1}, - {EX.p2, [EX.O2, EX.O3]}, - {EX.S, EX.p3, [~B, ~L"bar"]}, - ]) == Description.new(EX.S, EX.p1, EX.O2) + {EX.p1(), EX.O1}, + {EX.p2(), [EX.O2, EX.O3]}, + {EX.S, EX.p3(), [~B, ~L"bar"]} + ]) == Description.new(EX.S, EX.p1(), EX.O2) end test "multiple statements with a map of predications", - %{empty_description: empty_description, description3: description3} do - assert Description.delete(empty_description, %{EX.p => EX.O1}) == empty_description + %{empty_description: empty_description, description3: description3} do + assert Description.delete(empty_description, %{EX.p() => EX.O1}) == empty_description + assert Description.delete(description3, %{ - EX.p1 => EX.O1, - EX.p2 => [EX.O2, EX.O3], - EX.p3 => [~B, ~L"bar"], - }) == Description.new(EX.S, EX.p1, EX.O2) + EX.p1() => EX.O1, + EX.p2() => [EX.O2, EX.O3], + EX.p3() => [~B, ~L"bar"] + }) == Description.new(EX.S, EX.p1(), EX.O2) end test "multiple statements with another description", - %{empty_description: empty_description, description1: description1, description3: description3} do + %{ + empty_description: empty_description, + description1: description1, + description3: description3 + } do assert Description.delete(empty_description, description1) == empty_description - assert Description.delete(description3, Description.new(EX.S, %{ - EX.p1 => EX.O1, - EX.p2 => [EX.O2, EX.O3], - EX.p3 => [~B, ~L"bar"], - })) == Description.new(EX.S, EX.p1, EX.O2) + + assert Description.delete( + description3, + Description.new(EX.S, %{ + EX.p1() => EX.O1, + EX.p2() => [EX.O2, EX.O3], + EX.p3() => [~B, ~L"bar"] + }) + ) == Description.new(EX.S, EX.p1(), EX.O2) end end - describe "delete_predicates" do setup do {:ok, - empty_description: Description.new(EX.S), - description1: Description.new(EX.S, EX.p, [EX.O1, EX.O2]), - description2: Description.new(EX.S, [ - {EX.P1, [EX.O1, EX.O2]}, - {EX.p2, [~B, ~L"bar"]}, - ]) - } + empty_description: Description.new(EX.S), + description1: Description.new(EX.S, EX.p(), [EX.O1, EX.O2]), + description2: + Description.new(EX.S, [ + {EX.P1, [EX.O1, EX.O2]}, + {EX.p2(), [~B, ~L"bar"]} + ])} end test "a single property", - %{empty_description: empty_description, description1: description1, description2: description2} do - assert Description.delete_predicates(description1, EX.p) == empty_description + %{ + empty_description: empty_description, + description1: description1, + description2: description2 + } do + assert Description.delete_predicates(description1, EX.p()) == empty_description + assert Description.delete_predicates(description2, EX.P1) == - Description.new(EX.S, EX.p2, [~B, ~L"bar"]) + Description.new(EX.S, EX.p2(), [~B, ~L"bar"]) end test "a list of properties", - %{empty_description: empty_description, description1: description1, description2: description2} do - assert Description.delete_predicates(description1, [EX.p]) == empty_description - assert Description.delete_predicates(description2, [EX.P1, EX.p2, EX.p3]) == empty_description + %{ + empty_description: empty_description, + description1: description1, + description2: description2 + } do + assert Description.delete_predicates(description1, [EX.p()]) == empty_description + + assert Description.delete_predicates(description2, [EX.P1, EX.p2(), EX.p3()]) == + empty_description end end describe "update/4" do test "list values returned from the update function become new coerced objects of the predicate" do assert Description.new(EX.S, EX.P, [EX.O1, EX.O2]) - |> Description.update(EX.P, - fn [_object | other] -> [EX.O3 | other] end) == + |> Description.update( + EX.P, + fn [_object | other] -> [EX.O3 | other] end + ) == Description.new(EX.S, EX.P, [EX.O3, EX.O2]) end @@ -332,18 +415,22 @@ defmodule RDF.DescriptionTest do end test "returning an empty list or nil from the update function causes a removal of the predications" do - description = EX.S - |> EX.p(EX.O1, EX.O2) + description = + EX.S + |> EX.p(EX.O1, EX.O2) + assert description - |> Description.update(EX.p, fn _ -> [] end) == - Description.new(EX.S, {EX.p, []}) + |> Description.update(EX.p(), fn _ -> [] end) == + Description.new(EX.S, {EX.p(), []}) + assert description - |> Description.update(EX.p, fn _ -> nil end) == - Description.new(EX.S, {EX.p, []}) + |> Description.update(EX.p(), fn _ -> nil end) == + Description.new(EX.S, {EX.p(), []}) end test "when the property is not present the initial object value is added for the predicate and the update function not called" do fun = fn _ -> raise "should not be called" end + assert Description.new(EX.S) |> Description.update(EX.P, EX.O, fun) == Description.new(EX.S, EX.P, EX.O) @@ -357,143 +444,174 @@ defmodule RDF.DescriptionTest do test "pop" do assert Description.pop(Description.new(EX.S)) == {nil, Description.new(EX.S)} - {triple, desc} = Description.new({EX.S, EX.p, EX.O}) |> Description.pop - assert {iri(EX.S), iri(EX.p), iri(EX.O)} == triple + {triple, desc} = Description.new({EX.S, EX.p(), EX.O}) |> Description.pop() + assert {iri(EX.S), iri(EX.p()), iri(EX.O)} == triple assert Enum.count(desc.predications) == 0 {{subject, predicate, _}, desc} = - Description.new([{EX.S, EX.p, EX.O1}, {EX.S, EX.p, EX.O2}]) - |> Description.pop - assert {subject, predicate} == {iri(EX.S), iri(EX.p)} + Description.new([{EX.S, EX.p(), EX.O1}, {EX.S, EX.p(), EX.O2}]) + |> Description.pop() + + assert {subject, predicate} == {iri(EX.S), iri(EX.p())} assert Enum.count(desc.predications) == 1 {{subject, _, _}, desc} = - Description.new([{EX.S, EX.p1, EX.O1}, {EX.S, EX.p2, EX.O2}]) - |> Description.pop + Description.new([{EX.S, EX.p1(), EX.O1}, {EX.S, EX.p2(), EX.O2}]) + |> Description.pop() + assert subject == iri(EX.S) assert Enum.count(desc.predications) == 1 end test "values/1" do - assert Description.new(EX.s) |> Description.values() == %{} - assert Description.new({EX.s, EX.p, ~L"Foo"}) |> Description.values() == - %{RDF.Term.value(EX.p) => ["Foo"]} + assert Description.new(EX.s()) |> Description.values() == %{} + + assert Description.new({EX.s(), EX.p(), ~L"Foo"}) |> Description.values() == + %{RDF.Term.value(EX.p()) => ["Foo"]} end test "values/2" do mapping = fn {:predicate, predicate} -> predicate |> to_string() |> String.split("/") |> List.last() |> String.to_atom() + {_, term} -> RDF.Term.value(term) end - assert Description.new(EX.s) |> Description.values(mapping) == %{} - assert Description.new({EX.s, EX.p, ~L"Foo"}) |> Description.values(mapping) == + assert Description.new(EX.s()) |> Description.values(mapping) == %{} + + assert Description.new({EX.s(), EX.p(), ~L"Foo"}) |> Description.values(mapping) == %{p: ["Foo"]} end describe "take/2" do test "with a non-empty property list" do - assert Description.new([{EX.S, EX.p1, EX.O1}, {EX.S, EX.p2, EX.O2}]) - |> Description.take([EX.p2, EX.p3]) == - Description.new({EX.S, EX.p2, EX.O2}) + assert Description.new([{EX.S, EX.p1(), EX.O1}, {EX.S, EX.p2(), EX.O2}]) + |> Description.take([EX.p2(), EX.p3()]) == + Description.new({EX.S, EX.p2(), EX.O2}) end test "with an empty property list" do - assert Description.new([{EX.S, EX.p1, EX.O1}, {EX.S, EX.p2, EX.O2}]) + assert Description.new([{EX.S, EX.p1(), EX.O1}, {EX.S, EX.p2(), EX.O2}]) |> Description.take([]) == Description.new(EX.S) end test "with nil" do - assert Description.new([{EX.S, EX.p1, EX.O1}, {EX.S, EX.p2, EX.O2}]) + assert Description.new([{EX.S, EX.p1(), EX.O1}, {EX.S, EX.p2(), EX.O2}]) |> Description.take(nil) == - Description.new([{EX.S, EX.p1, EX.O1}, {EX.S, EX.p2, EX.O2}]) + Description.new([{EX.S, EX.p1(), EX.O1}, {EX.S, EX.p2(), EX.O2}]) end end test "equal/2" do - assert Description.new({EX.S, EX.p, EX.O}) |> Description.equal?(Description.new({EX.S, EX.p, EX.O})) - refute Description.new({EX.S, EX.p, EX.O}) |> Description.equal?(Description.new({EX.S, EX.p, EX.O2})) + assert Description.new({EX.S, EX.p(), EX.O}) + |> Description.equal?(Description.new({EX.S, EX.p(), EX.O})) + + refute Description.new({EX.S, EX.p(), EX.O}) + |> Description.equal?(Description.new({EX.S, EX.p(), EX.O2})) end describe "Enumerable protocol" do test "Enum.count" do - assert Enum.count(Description.new EX.foo) == 0 - assert Enum.count(Description.new {EX.S, EX.p, EX.O}) == 1 - assert Enum.count(Description.new [{EX.S, EX.p, EX.O1}, {EX.S, EX.p, EX.O2}]) == 2 + assert Enum.count(Description.new(EX.foo())) == 0 + assert Enum.count(Description.new({EX.S, EX.p(), EX.O})) == 1 + assert Enum.count(Description.new([{EX.S, EX.p(), EX.O1}, {EX.S, EX.p(), EX.O2}])) == 2 end test "Enum.member?" do - refute Enum.member?(Description.new(EX.S), {iri(EX.S), EX.p, iri(EX.O)}) - assert Enum.member?(Description.new({EX.S, EX.p, EX.O}), {EX.S, EX.p, EX.O}) + refute Enum.member?(Description.new(EX.S), {iri(EX.S), EX.p(), iri(EX.O)}) + assert Enum.member?(Description.new({EX.S, EX.p(), EX.O}), {EX.S, EX.p(), EX.O}) - desc = Description.new([ - {EX.Subject, EX.predicate1, EX.Object1}, - {EX.Subject, EX.predicate2, EX.Object2}, - {EX.predicate2, EX.Object3}]) - assert Enum.member?(desc, {EX.Subject, EX.predicate1, EX.Object1}) - assert Enum.member?(desc, {EX.Subject, EX.predicate2, EX.Object2}) - assert Enum.member?(desc, {EX.Subject, EX.predicate2, EX.Object3}) - refute Enum.member?(desc, {EX.Subject, EX.predicate1, EX.Object2}) + desc = + Description.new([ + {EX.Subject, EX.predicate1(), EX.Object1}, + {EX.Subject, EX.predicate2(), EX.Object2}, + {EX.predicate2(), EX.Object3} + ]) + + assert Enum.member?(desc, {EX.Subject, EX.predicate1(), EX.Object1}) + assert Enum.member?(desc, {EX.Subject, EX.predicate2(), EX.Object2}) + assert Enum.member?(desc, {EX.Subject, EX.predicate2(), EX.Object3}) + refute Enum.member?(desc, {EX.Subject, EX.predicate1(), EX.Object2}) end test "Enum.reduce" do - desc = Description.new([ - {EX.Subject, EX.predicate1, EX.Object1}, - {EX.Subject, EX.predicate2, EX.Object2}, - {EX.predicate2, EX.Object3}]) - assert desc == Enum.reduce(desc, description(), - fn(triple, acc) -> acc |> Description.add(triple) end) + desc = + Description.new([ + {EX.Subject, EX.predicate1(), EX.Object1}, + {EX.Subject, EX.predicate2(), EX.Object2}, + {EX.predicate2(), EX.Object3} + ]) + + assert desc == + Enum.reduce(desc, description(), fn triple, acc -> + acc |> Description.add(triple) + end) end end describe "Collectable protocol" do test "with a map" do map = %{ - EX.predicate1 => EX.Object1, - EX.predicate2 => EX.Object2 - } + 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} - ] + {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} - ] + {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] - ] + [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)) + 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 - assert Description.new(EX.Subject, EX.predicate, EX.Object)[EX.predicate] == [iri(EX.Object)] - assert Description.new(EX.Subject, EX.Predicate, EX.Object)[EX.Predicate] == [iri(EX.Object)] - assert Description.new(EX.Subject, EX.predicate, EX.Object)["http://example.com/predicate"] == [iri(EX.Object)] - assert Description.new([{EX.Subject, EX.predicate1, EX.Object1}, - {EX.Subject, EX.predicate1, EX.Object2}, - {EX.Subject, EX.predicate2, EX.Object3}])[EX.predicate1] == - [iri(EX.Object1), iri(EX.Object2)] + assert Description.new(EX.Subject)[EX.predicate()] == nil + + assert Description.new(EX.Subject, EX.predicate(), EX.Object)[EX.predicate()] == [ + iri(EX.Object) + ] + + assert Description.new(EX.Subject, EX.Predicate, EX.Object)[EX.Predicate] == [ + iri(EX.Object) + ] + + assert Description.new(EX.Subject, EX.predicate(), EX.Object)[ + "http://example.com/predicate" + ] == [iri(EX.Object)] + + assert Description.new([ + {EX.Subject, EX.predicate1(), EX.Object1}, + {EX.Subject, EX.predicate1(), EX.Object2}, + {EX.Subject, EX.predicate2(), EX.Object3} + ])[EX.predicate1()] == + [iri(EX.Object1), iri(EX.Object2)] end end - end diff --git a/test/unit/diff_test.exs b/test/unit/diff_test.exs index e22c8cd..13f8820 100644 --- a/test/unit/diff_test.exs +++ b/test/unit/diff_test.exs @@ -8,12 +8,16 @@ defmodule RDF.DiffTest do test "new" do assert Diff.new() == %Diff{additions: Graph.new(), deletions: Graph.new()} + assert Diff.new(additions: [], deletions: []) == %Diff{additions: Graph.new(), deletions: Graph.new()} - assert Diff.new(additions: Graph.new(), deletions: Graph.new) == + + assert Diff.new(additions: Graph.new(), deletions: Graph.new()) == %Diff{additions: Graph.new(), deletions: Graph.new()} - description = Description.new({EX.S, EX.p, EX.O1}) - graph = Graph.new({EX.S, EX.p, EX.O2}) + + description = Description.new({EX.S, EX.p(), EX.O1}) + graph = Graph.new({EX.S, EX.p(), EX.O2}) + assert Diff.new(additions: description, deletions: graph) == %Diff{additions: Graph.new(description), deletions: graph} end @@ -26,43 +30,54 @@ defmodule RDF.DiffTest do end test "with two descriptions with different subjects" do - description1 = Description.new({EX.S1, EX.p, EX.O}) - description2 = Description.new({EX.S2, EX.p, EX.O}) + description1 = Description.new({EX.S1, EX.p(), EX.O}) + description2 = Description.new({EX.S2, EX.p(), EX.O}) + assert Diff.diff(description1, description2) == - Diff.new(additions: Graph.new(description2), - deletions: Graph.new(description1)) + Diff.new( + additions: Graph.new(description2), + deletions: Graph.new(description1) + ) end test "with two descriptions when the second description has additional statements" do - description1 = Description.new({EX.S, EX.p, EX.O}) + description1 = Description.new({EX.S, EX.p(), EX.O}) + description2 = description1 |> EX.p(EX.O2) |> EX.p2(EX.O) assert Diff.diff(description1, description2) == - Diff.new(additions: Graph.new( - EX.S - |> EX.p(EX.O2) - |> EX.p2(EX.O) - ), - deletions: Graph.new()) + Diff.new( + additions: + Graph.new( + EX.S + |> EX.p(EX.O2) + |> EX.p2(EX.O) + ), + deletions: Graph.new() + ) end test "with two descriptions when the first description has additional statements" do - description1 = Description.new({EX.S, EX.p, EX.O}) + description1 = Description.new({EX.S, EX.p(), EX.O}) + description2 = description1 |> EX.p(EX.O2) |> EX.p2(EX.O) assert Diff.diff(description2, description1) == - Diff.new(additions: Graph.new, - deletions: Graph.new( - EX.S - |> EX.p(EX.O2) - |> EX.p2(EX.O) - )) + Diff.new( + additions: Graph.new(), + deletions: + Graph.new( + EX.S + |> EX.p(EX.O2) + |> EX.p2(EX.O) + ) + ) end end @@ -71,6 +86,7 @@ defmodule RDF.DiffTest do EX.S |> EX.p(EX.O1, EX.O2) |> EX.p2(EX.O) + description2 = EX.S |> EX.p(EX.O1, EX.O3) @@ -78,17 +94,19 @@ defmodule RDF.DiffTest do assert Diff.diff(description1, description2) == Diff.new( - additions: Graph.new( - EX.S - |> EX.p(EX.O3) - |> EX.p3(EX.O) - - ), - deletions: Graph.new( - EX.S - |> EX.p(EX.O2) - |> EX.p2(EX.O) - )) + additions: + Graph.new( + EX.S + |> EX.p(EX.O3) + |> EX.p3(EX.O) + ), + deletions: + Graph.new( + EX.S + |> EX.p(EX.O2) + |> EX.p2(EX.O) + ) + ) end test "with one description and a graph" do @@ -96,112 +114,141 @@ defmodule RDF.DiffTest do EX.S1 |> EX.p(EX.O1, EX.O2) |> EX.p2(EX.O) - graph = Graph.new([ - EX.S1 - |> EX.p(EX.O2, EX.O3) - |> EX.p3(EX.O), - EX.S3 - |> EX.p(EX.O) - ]) + + graph = + Graph.new([ + EX.S1 + |> EX.p(EX.O2, EX.O3) + |> EX.p3(EX.O), + EX.S3 + |> EX.p(EX.O) + ]) + assert Diff.diff(description, graph) == Diff.new( - additions: Graph.new([ - EX.S1 - |> EX.p(EX.O3) - |> EX.p3(EX.O), - EX.S3 - |> EX.p(EX.O) - ]), - deletions: Graph.new([ - EX.S1 - |> EX.p(EX.O1) - |> EX.p2(EX.O), - ])) + additions: + Graph.new([ + EX.S1 + |> EX.p(EX.O3) + |> EX.p3(EX.O), + EX.S3 + |> EX.p(EX.O) + ]), + deletions: + Graph.new([ + EX.S1 + |> EX.p(EX.O1) + |> EX.p2(EX.O) + ]) + ) assert Diff.diff(graph, description) == Diff.new( - additions: Graph.new([ - EX.S1 - |> EX.p(EX.O1) - |> EX.p2(EX.O), - ]), - deletions: Graph.new([ - EX.S1 - |> EX.p(EX.O3) - |> EX.p3(EX.O), - EX.S3 - |> EX.p(EX.O) - ]) + additions: + Graph.new([ + EX.S1 + |> EX.p(EX.O1) + |> EX.p2(EX.O) + ]), + deletions: + Graph.new([ + EX.S1 + |> EX.p(EX.O3) + |> EX.p3(EX.O), + EX.S3 + |> EX.p(EX.O) + ]) ) disjoint_description = EX.S |> EX.p(EX.O1, EX.O2) |> EX.p2(EX.O) + assert Diff.diff(disjoint_description, graph) == Diff.new( additions: graph, - deletions: Graph.new(disjoint_description)) + deletions: Graph.new(disjoint_description) + ) + assert Diff.diff(graph, disjoint_description) == Diff.new( additions: Graph.new(disjoint_description), - deletions: graph) + deletions: graph + ) end test "with two graphs with additions and deletions" do - graph1 = Graph.new([ - EX.S1 - |> EX.p(EX.O1, EX.O2) - |> EX.p2(EX.O), - EX.S2 - |> EX.p(EX.O) - ]) - graph2 = Graph.new([ - EX.S1 - |> EX.p(EX.O2, EX.O3) - |> EX.p3(EX.O), - EX.S3 - |> EX.p(EX.O) - ]) + graph1 = + Graph.new([ + EX.S1 + |> EX.p(EX.O1, EX.O2) + |> EX.p2(EX.O), + EX.S2 + |> EX.p(EX.O) + ]) + + graph2 = + Graph.new([ + EX.S1 + |> EX.p(EX.O2, EX.O3) + |> EX.p3(EX.O), + EX.S3 + |> EX.p(EX.O) + ]) assert Diff.diff(graph1, graph2) == Diff.new( - additions: Graph.new([ - EX.S1 - |> EX.p(EX.O3) - |> EX.p3(EX.O), - EX.S3 - |> EX.p(EX.O) - ]), - deletions: Graph.new([ - EX.S1 - |> EX.p(EX.O1) - |> EX.p2(EX.O), - EX.S2 - |> EX.p(EX.O) - ])) + additions: + Graph.new([ + EX.S1 + |> EX.p(EX.O3) + |> EX.p3(EX.O), + EX.S3 + |> EX.p(EX.O) + ]), + deletions: + Graph.new([ + EX.S1 + |> EX.p(EX.O1) + |> EX.p2(EX.O), + EX.S2 + |> EX.p(EX.O) + ]) + ) end test "merge/2" do assert Diff.merge( - Diff.new(additions: Graph.new({EX.S, EX.p, EX.O1}), - deletions: Graph.new({EX.S1, EX.p, EX.O})), - Diff.new(additions: Graph.new({EX.S, EX.p, EX.O2}), - deletions: Graph.new({EX.S2, EX.p, EX.O})) + Diff.new( + additions: Graph.new({EX.S, EX.p(), EX.O1}), + deletions: Graph.new({EX.S1, EX.p(), EX.O}) + ), + Diff.new( + additions: Graph.new({EX.S, EX.p(), EX.O2}), + deletions: Graph.new({EX.S2, EX.p(), EX.O}) + ) ) == Diff.new( - additions: Graph.new({EX.S, EX.p, [EX.O1, EX.O2]}), - deletions: Graph.new([ - {EX.S1, EX.p, EX.O}, - {EX.S2, EX.p, EX.O} - ]) + additions: Graph.new({EX.S, EX.p(), [EX.O1, EX.O2]}), + deletions: + Graph.new([ + {EX.S1, EX.p(), EX.O}, + {EX.S2, EX.p(), EX.O} + ]) ) end test "empty?/1" do assert Diff.empty?(Diff.new()) == true - assert Diff.empty?(Diff.new(additions: EX.p(EX.S, EX.O), - deletions: EX.p(EX.S, EX.O))) == false + + assert Diff.empty?( + Diff.new( + additions: EX.p(EX.S, EX.O), + deletions: EX.p(EX.S, EX.O) + ) + ) == false + assert Diff.empty?(Diff.new(additions: EX.p(EX.S, EX.O))) == false assert Diff.empty?(Diff.new(deletions: EX.p(EX.S, EX.O))) == false end @@ -209,27 +256,32 @@ defmodule RDF.DiffTest do describe "apply/2" do test "on a graph" do assert Diff.new( - additions: Graph.new([ + additions: + Graph.new([ EX.S1 |> EX.p(EX.O3) |> EX.p3(EX.O), EX.S3 |> EX.p(EX.O) ]), - deletions: Graph.new([ + deletions: + Graph.new([ EX.S1 |> EX.p(EX.O1) |> EX.p2(EX.O), EX.S2 |> EX.p(EX.O) - ])) - |> Diff.apply(Graph.new([ - EX.S1 - |> EX.p(EX.O1, EX.O2) - |> EX.p2(EX.O), - EX.S2 - |> EX.p(EX.O) - ])) == + ]) + ) + |> Diff.apply( + Graph.new([ + EX.S1 + |> EX.p(EX.O1, EX.O2) + |> EX.p2(EX.O), + EX.S2 + |> EX.p(EX.O) + ]) + ) == Graph.new([ EX.S1 |> EX.p(EX.O2, EX.O3) @@ -241,23 +293,26 @@ defmodule RDF.DiffTest do test "on a description" do assert Diff.new( - additions: Graph.new([ - EX.S1 - |> EX.p(EX.O3) - |> EX.p3(EX.O), - EX.S3 - |> EX.p(EX.O) - ]), - deletions: Graph.new([ - EX.S1 - |> EX.p(EX.O1) - |> EX.p2(EX.O), - ])) + additions: + Graph.new([ + EX.S1 + |> EX.p(EX.O3) + |> EX.p3(EX.O), + EX.S3 + |> EX.p(EX.O) + ]), + deletions: + Graph.new([ + EX.S1 + |> EX.p(EX.O1) + |> EX.p2(EX.O) + ]) + ) |> Diff.apply( - EX.S1 - |> EX.p(EX.O1, EX.O2) - |> EX.p2(EX.O) - ) == + EX.S1 + |> EX.p(EX.O1, EX.O2) + |> EX.p2(EX.O) + ) == Graph.new([ EX.S1 |> EX.p(EX.O2, EX.O3) @@ -269,21 +324,26 @@ defmodule RDF.DiffTest do test "when the statements to be deleted are not present" do assert Diff.new( - additions: Graph.new( + additions: + Graph.new( + EX.S1 + |> EX.p(EX.O4) + ), + deletions: + Graph.new([ + EX.S1 + |> EX.p(EX.O2, EX.O3) + |> EX.p2(EX.O), + EX.S2 + |> EX.p(EX.O) + ]) + ) + |> Diff.apply( + Graph.new( EX.S1 - |> EX.p(EX.O4) - ), - deletions: Graph.new([ - EX.S1 - |> EX.p(EX.O2, EX.O3) - |> EX.p2(EX.O), - EX.S2 - |> EX.p(EX.O) - ])) - |> Diff.apply(Graph.new( - EX.S1 - |> EX.p(EX.O1, EX.O2) - )) == + |> EX.p(EX.O1, EX.O2) + ) + ) == Graph.new( EX.S1 |> EX.p(EX.O1, EX.O4) diff --git a/test/unit/equality_test.exs b/test/unit/equality_test.exs index e253c45..b23f75d 100644 --- a/test/unit/equality_test.exs +++ b/test/unit/equality_test.exs @@ -1,36 +1,44 @@ defmodule RDF.EqualityTest do use RDF.Test.Case - alias RDF.TestDatatypes.{Initials, CustomTime, DateWithoutTz, DateTimeWithTz, Age, - DecimalUnitInterval, DoubleUnitInterval, FloatUnitInterval} + alias RDF.TestDatatypes.{ + Initials, + CustomTime, + DateWithoutTz, + DateTimeWithTz, + Age, + DecimalUnitInterval, + DoubleUnitInterval, + FloatUnitInterval + } describe "RDF.IRI and XSD.AnyURI" do @term_equal_iris [ {RDF.iri("http://example.com/"), RDF.iri("http://example.com/")}, - {XSD.anyURI("http://example.com/"), XSD.anyURI("http://example.com/")}, + {XSD.anyURI("http://example.com/"), XSD.anyURI("http://example.com/")} ] @value_equal_iris [ - {RDF.iri("http://example.com/"), XSD.anyURI("http://example.com/")}, + {RDF.iri("http://example.com/"), XSD.anyURI("http://example.com/")} ] @unequal_iris [ {RDF.iri("http://example.com/foo"), RDF.iri("http://example.com/bar")}, - {RDF.iri("http://example.com/foo"), XSD.anyURI("http://example.com/bar")}, + {RDF.iri("http://example.com/foo"), XSD.anyURI("http://example.com/bar")} ] @equal_iris_by_coercion [ {RDF.iri("http://example.com/"), URI.parse("http://example.com/")}, {XSD.anyURI("http://example.com/"), URI.parse("http://example.com/")}, {RDF.iri("http://example.com/Foo"), EX.Foo}, - {XSD.anyURI("http://example.com/Foo"), EX.Foo}, + {XSD.anyURI("http://example.com/Foo"), EX.Foo} ] @unequal_iris_by_coercion [ {RDF.iri("http://example.com/foo"), URI.parse("http://example.com/bar")}, {XSD.anyURI("http://example.com/foo"), URI.parse("http://example.com/bar")}, {RDF.iri("http://example.com/Bar"), EX.Foo}, - {XSD.anyURI("http://example.com/Bar"), EX.Foo}, + {XSD.anyURI("http://example.com/Bar"), EX.Foo} ] @incomparable_iris [ {RDF.iri("http://example.com/"), XSD.string("http://example.com/")}, - {XSD.anyURI("http://example.com/"), XSD.string("http://example.com/")}, + {XSD.anyURI("http://example.com/"), XSD.string("http://example.com/")} ] test "term equality", do: assert_term_equal(@term_equal_iris) @@ -43,26 +51,25 @@ defmodule RDF.EqualityTest do describe "RDF.BlankNode" do @term_equal_bnodes [ - {RDF.bnode("foo"), RDF.bnode("foo")}, - ] - @value_equal_bnodes [ + {RDF.bnode("foo"), RDF.bnode("foo")} ] + @value_equal_bnodes [] @unequal_bnodes [ - {RDF.bnode("foo"), RDF.bnode("bar")}, + {RDF.bnode("foo"), RDF.bnode("bar")} ] @equal_bnodes_by_coercion [] @unequal_bnodes_by_coercion [] @incomparable_bnodes [ - {RDF.bnode("foo"), XSD.string("foo")}, - {XSD.string("foo"), RDF.bnode("foo")}, + {RDF.bnode("foo"), XSD.string("foo")}, + {XSD.string("foo"), RDF.bnode("foo")} ] - test "term equality", do: assert_term_equal @term_equal_bnodes - test "value equality", do: assert_value_equal @value_equal_bnodes - test "inequality", do: assert_unequal @unequal_bnodes + test "term equality", do: assert_term_equal(@term_equal_bnodes) + test "value equality", do: assert_value_equal(@value_equal_bnodes) + test "inequality", do: assert_unequal(@unequal_bnodes) test "coerced value equality", do: assert_coerced_equal(@equal_bnodes_by_coercion) test "coerced value inequality", do: assert_coerced_unequal(@unequal_bnodes_by_coercion) - test "incomparability", do: assert_incomparable @incomparable_bnodes + test "incomparability", do: assert_incomparable(@incomparable_bnodes) end describe "XSD.String and RDF.LangString" do @@ -88,7 +95,7 @@ defmodule RDF.EqualityTest do {RDF.lang_string("foo", language: "de"), "foo"}, {XSD.string("foo"), RDF.lang_string("foo", language: "de")}, {RDF.lang_string("foo", language: "de"), XSD.string("foo")}, - {XSD.string("foo"), RDF.bnode("foo")}, + {XSD.string("foo"), RDF.bnode("foo")} ] test "term equality", do: assert_term_equal(@term_equal_strings) @@ -159,7 +166,7 @@ defmodule RDF.EqualityTest do {XSD.decimal("-42.0"), XSD.decimal(-42.0)}, {XSD.decimal("1.0"), XSD.decimal(1.0)}, {Age.new("42"), Age.new("42")}, - {DecimalUnitInterval.new("0.1"), DecimalUnitInterval.new("0.1")}, + {DecimalUnitInterval.new("0.1"), DecimalUnitInterval.new("0.1")} ] @value_equal_numerics [ {XSD.integer("42"), XSD.non_negative_integer("42")}, @@ -200,7 +207,7 @@ defmodule RDF.EqualityTest do {XSD.integer(1), XSD.integer(2)}, {XSD.integer("1"), XSD.double("1.1")}, {XSD.integer("1"), XSD.decimal("1.1")}, - {DecimalUnitInterval.new(0.1), DoubleUnitInterval.new(0.2)}, + {DecimalUnitInterval.new(0.1), DoubleUnitInterval.new(0.2)} ] @equal_numerics_by_coercion [ {XSD.integer(42), 42}, @@ -228,7 +235,7 @@ defmodule RDF.EqualityTest do {XSD.float("foo"), XSD.float("foo")}, {XSD.non_negative_integer("foo"), XSD.non_negative_integer("foo")}, {XSD.positive_integer("foo"), XSD.positive_integer("foo")}, - {DecimalUnitInterval.new(1.1), DecimalUnitInterval.new(1.1)}, + {DecimalUnitInterval.new(1.1), DecimalUnitInterval.new(1.1)} ] @unequal_invalid_numerics [ {XSD.integer("foo"), XSD.integer("bar")}, @@ -239,7 +246,7 @@ defmodule RDF.EqualityTest do {XSD.float("foo"), XSD.float("bar")}, {XSD.non_negative_integer("foo"), XSD.non_negative_integer("bar")}, {XSD.positive_integer("foo"), XSD.positive_integer("bar")}, - {DecimalUnitInterval.new(1.1), DoubleUnitInterval.new(1.2)}, + {DecimalUnitInterval.new(1.1), DoubleUnitInterval.new(1.2)} ] @incomparable_numerics [ {XSD.integer("42"), nil}, @@ -266,7 +273,7 @@ defmodule RDF.EqualityTest do @term_equal_datetimes [ {XSD.datetime("2002-04-02T12:00:00-01:00"), XSD.datetime("2002-04-02T12:00:00-01:00")}, {XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002-04-02T12:00:00")}, - {DateTimeWithTz.new("2002-04-02T12:00:00Z"), DateTimeWithTz.new("2002-04-02T12:00:00Z")}, + {DateTimeWithTz.new("2002-04-02T12:00:00Z"), DateTimeWithTz.new("2002-04-02T12:00:00Z")} ] @value_equal_datetimes [ {XSD.datetime("2002-04-02T12:00:00-01:00"), XSD.datetime("2002-04-02T17:00:00+04:00")}, @@ -278,10 +285,10 @@ defmodule RDF.EqualityTest do {XSD.datetime("2002-04-02T23:00:00+00:00"), XSD.datetime("2002-04-02T23:00:00-00:00")}, {XSD.datetime("2010-01-01T00:00:00.0000Z"), XSD.datetime("2010-01-01T00:00:00Z")}, {XSD.datetime("2005-04-04T24:00:00"), XSD.datetime("2005-04-05T00:00:00")}, - - {DateTimeWithTz.new("2002-04-02T12:00:00-01:00"), DateTimeWithTz.new("2002-04-02T17:00:00+04:00")}, + {DateTimeWithTz.new("2002-04-02T12:00:00-01:00"), + DateTimeWithTz.new("2002-04-02T17:00:00+04:00")}, {DateTimeWithTz.new("2002-04-02T23:00:00Z"), XSD.datetime("2002-04-02T23:00:00+00:00")}, - {XSD.datetime("2002-04-02T23:00:00+00:00"), DateTimeWithTz.new("2002-04-02T23:00:00-00:00")}, + {XSD.datetime("2002-04-02T23:00:00+00:00"), DateTimeWithTz.new("2002-04-02T23:00:00-00:00")} ] @unequal_datetimes [ {XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002-04-02T17:00:00")}, @@ -290,20 +297,20 @@ defmodule RDF.EqualityTest do ] @equal_datetimes_by_coercion [ {XSD.datetime("2002-04-02T12:00:00-01:00"), - elem(DateTime.from_iso8601("2002-04-02T12:00:00-01:00"), 1)}, + elem(DateTime.from_iso8601("2002-04-02T12:00:00-01:00"), 1)}, {XSD.datetime("2002-04-02T12:00:00"), ~N"2002-04-02T12:00:00"}, {XSD.datetime("2002-04-02T23:00:00Z"), - elem(DateTime.from_iso8601("2002-04-02T23:00:00+00:00"), 1)}, + elem(DateTime.from_iso8601("2002-04-02T23:00:00+00:00"), 1)}, {XSD.datetime("2002-04-02T23:00:00+00:00"), - elem(DateTime.from_iso8601("2002-04-02T23:00:00Z"), 1)}, + elem(DateTime.from_iso8601("2002-04-02T23:00:00Z"), 1)}, {XSD.datetime("2002-04-02T23:00:00-00:00"), - elem(DateTime.from_iso8601("2002-04-02T23:00:00Z"), 1)}, + elem(DateTime.from_iso8601("2002-04-02T23:00:00Z"), 1)}, {XSD.datetime("2002-04-02T23:00:00-00:00"), - elem(DateTime.from_iso8601("2002-04-02T23:00:00+00:00"), 1)} + elem(DateTime.from_iso8601("2002-04-02T23:00:00+00:00"), 1)} ] @unequal_datetimes_by_coercion [ {XSD.datetime("2002-04-02T12:00:00-01:00"), - elem(DateTime.from_iso8601("2002-04-02T12:00:00+00:00"), 1)} + elem(DateTime.from_iso8601("2002-04-02T12:00:00+00:00"), 1)} ] @equal_invalid_datetimes [ {XSD.datetime("foo"), XSD.datetime("foo")}, @@ -320,7 +327,7 @@ defmodule RDF.EqualityTest do {XSD.string("2002-04-02T12:00:00-01:00"), XSD.datetime("2002-04-02T12:00:00-01:00")}, # These are incomparable because of indeterminacy due to missing timezone {XSD.datetime("2002-04-02T12:00:00"), XSD.datetime("2002-04-02T23:00:00+00:00")}, - {XSD.datetime("2002-04-02T12:00:00"), DateTimeWithTz.new("2002-04-02T12:00:00Z")}, + {XSD.datetime("2002-04-02T12:00:00"), DateTimeWithTz.new("2002-04-02T12:00:00Z")} ] test "term equality", do: assert_term_equal(@term_equal_datetimes) @@ -337,17 +344,17 @@ defmodule RDF.EqualityTest do @term_equal_dates [ {XSD.date("2002-04-02-01:00"), XSD.date("2002-04-02-01:00")}, {XSD.date("2002-04-02"), XSD.date("2002-04-02")}, - {DateWithoutTz.new("2002-04-02"), DateWithoutTz.new("2002-04-02")}, + {DateWithoutTz.new("2002-04-02"), DateWithoutTz.new("2002-04-02")} ] @value_equal_dates [ {XSD.date("2002-04-02-00:00"), XSD.date("2002-04-02+00:00")}, {XSD.date("2002-04-02Z"), XSD.date("2002-04-02+00:00")}, {XSD.date("2002-04-02Z"), XSD.date("2002-04-02-00:00")}, - {XSD.date("2002-04-02"), DateWithoutTz.new("2002-04-02")}, + {XSD.date("2002-04-02"), DateWithoutTz.new("2002-04-02")} ] @unequal_dates [ {XSD.date("2002-04-01"), XSD.date("2002-04-02")}, - {DateWithoutTz.new("2002-04-02"), DateWithoutTz.new("2002-04-01")}, + {DateWithoutTz.new("2002-04-02"), DateWithoutTz.new("2002-04-01")} ] @equal_dates_by_coercion [ {XSD.date("2002-04-02"), Date.from_iso8601!("2002-04-02")} @@ -357,13 +364,13 @@ defmodule RDF.EqualityTest do ] @equal_invalid_dates [ {XSD.date("foo"), XSD.date("foo")}, - {DateWithoutTz.new("foo"), DateWithoutTz.new("foo")}, + {DateWithoutTz.new("foo"), DateWithoutTz.new("foo")} ] @unequal_invalid_dates [ {XSD.date("2002.04.02"), XSD.date("2002-04-02")}, {XSD.date("foo"), XSD.date("bar")}, {DateWithoutTz.new("foo"), DateWithoutTz.new("bar")}, - {XSD.date("foo"), DateWithoutTz.new("bar")}, + {XSD.date("foo"), DateWithoutTz.new("bar")} ] @incomparable_dates [ {XSD.date("2002-04-02"), XSD.string("2002-04-02")}, @@ -434,17 +441,17 @@ defmodule RDF.EqualityTest do @term_equal_times [ {XSD.time("12:00:00+01:00"), XSD.time("12:00:00+01:00")}, {XSD.time("12:00:00"), XSD.time("12:00:00")}, - {CustomTime.new("00:00:00Z"), CustomTime.new("00:00:00Z")}, + {CustomTime.new("00:00:00Z"), CustomTime.new("00:00:00Z")} ] @value_equal_times [ {XSD.time("00:00:00+00:00"), XSD.time("00:00:00Z")}, {XSD.time("00:00:00+00:00"), CustomTime.new("00:00:00Z")}, - {CustomTime.new("00:00:00+00:00"), CustomTime.new("00:00:00Z")}, + {CustomTime.new("00:00:00+00:00"), CustomTime.new("00:00:00Z")} ] @unequal_times [ {XSD.time("12:00:00"), XSD.time("13:00:00")}, {XSD.time("00:00:00.0000Z"), XSD.time("00:00:00Z")}, - {XSD.time("00:00:00.0000Z"), CustomTime.new("00:00:00Z")}, + {XSD.time("00:00:00.0000Z"), CustomTime.new("00:00:00Z")} ] @equal_times_by_coercion [ {XSD.time("12:00:00"), Time.from_iso8601!("12:00:00")} @@ -454,11 +461,11 @@ defmodule RDF.EqualityTest do ] @equal_invalid_times [ {XSD.time("foo"), XSD.time("foo")}, - {CustomTime.new("foo"), CustomTime.new("foo")}, + {CustomTime.new("foo"), CustomTime.new("foo")} ] @unequal_invalid_times [ {XSD.time("foo"), XSD.time("bar")}, - {XSD.time("foo"), CustomTime.new("bar")}, + {XSD.time("foo"), CustomTime.new("bar")} ] @incomparable_times [ {XSD.time("12:00:00"), XSD.string("12:00:00")}, @@ -508,20 +515,20 @@ defmodule RDF.EqualityTest do describe "RDF.Literal.Generics" do @equal_literals [ {RDF.literal("foo", datatype: "http://example.com/datatype"), - RDF.literal("foo", datatype: "http://example.com/datatype")}, + RDF.literal("foo", datatype: "http://example.com/datatype")} ] @unequal_literals [ {RDF.literal("foo", datatype: "http://example.com/datatype"), - RDF.literal("bar", datatype: "http://example.com/datatype")}, + RDF.literal("bar", datatype: "http://example.com/datatype")} ] @incomparable_literals [ {RDF.literal("foo", datatype: "http://example.com/datatype1"), - RDF.literal("foo", datatype: "http://example.com/datatype2")}, + RDF.literal("foo", datatype: "http://example.com/datatype2")} ] - test "equality", do: assert_term_equal @equal_literals - test "inequality", do: assert_unequal @unequal_literals - test "incomparability", do: assert_incomparable @incomparable_literals + test "equality", do: assert_term_equal(@equal_literals) + test "inequality", do: assert_unequal(@unequal_literals) + test "incomparability", do: assert_incomparable(@incomparable_literals) end defp assert_term_equal(examples) do diff --git a/test/unit/graph_test.exs b/test/unit/graph_test.exs index 6620f25..b947b02 100644 --- a/test/unit/graph_test.exs +++ b/test/unit/graph_test.exs @@ -24,110 +24,131 @@ defmodule RDF.GraphTest do test "creating an empty graph with a coercible graph name" do assert named_graph("http://example.com/graph/GraphName") |> named_graph?(iri("http://example.com/graph/GraphName")) + assert named_graph(EX.Foo) |> named_graph?(iri(EX.Foo)) end test "creating an unnamed graph with an initial triple" do - g = Graph.new({EX.Subject, EX.predicate, EX.Object}) + g = Graph.new({EX.Subject, EX.predicate(), EX.Object}) assert unnamed_graph?(g) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) - g = Graph.new(EX.Subject, EX.predicate, EX.Object) + g = Graph.new(EX.Subject, EX.predicate(), EX.Object) assert unnamed_graph?(g) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) end test "creating a named graph with an initial triple" do - g = Graph.new({EX.Subject, EX.predicate, EX.Object}, name: EX.GraphName) + g = Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.GraphName) assert named_graph?(g, iri(EX.GraphName)) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) - g = Graph.new(EX.Subject, EX.predicate, EX.Object, name: EX.GraphName) + g = Graph.new(EX.Subject, EX.predicate(), EX.Object, name: EX.GraphName) assert named_graph?(g, iri(EX.GraphName)) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) end test "creating an unnamed graph with a list of initial triples" do - g = Graph.new([{EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject2, EX.predicate2, EX.Object2}]) - assert unnamed_graph?(g) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2, EX.Object2}) + g = + Graph.new([ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject2, EX.predicate2(), EX.Object2} + ]) - g = Graph.new(EX.Subject, EX.predicate, [EX.Object1, EX.Object2]) assert unnamed_graph?(g) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object2}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2(), EX.Object2}) + + g = Graph.new(EX.Subject, EX.predicate(), [EX.Object1, EX.Object2]) + assert unnamed_graph?(g) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object2}) end test "creating a named graph with a list of initial triples" do - g = Graph.new([{EX.Subject, EX.predicate1, EX.Object1}, - {EX.Subject, EX.predicate2, EX.Object2}], - name: EX.GraphName) - assert named_graph?(g, iri(EX.GraphName)) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate1, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate2, EX.Object2}) + g = + Graph.new( + [{EX.Subject, EX.predicate1(), EX.Object1}, {EX.Subject, EX.predicate2(), EX.Object2}], + name: EX.GraphName + ) - g = Graph.new(EX.Subject, EX.predicate, [EX.Object1, EX.Object2], - name: EX.GraphName) assert named_graph?(g, iri(EX.GraphName)) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object2}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate1(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate2(), EX.Object2}) + + g = Graph.new(EX.Subject, EX.predicate(), [EX.Object1, EX.Object2], name: EX.GraphName) + assert named_graph?(g, iri(EX.GraphName)) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object2}) end test "creating a named graph with an initial description" do - g = Graph.new(Description.new({EX.Subject, EX.predicate, EX.Object}), - name: EX.GraphName) + g = + Graph.new(Description.new({EX.Subject, EX.predicate(), EX.Object}), + name: EX.GraphName + ) + assert named_graph?(g, iri(EX.GraphName)) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) end test "creating an unnamed graph with an initial description" do - g = Graph.new(Description.new({EX.Subject, EX.predicate, EX.Object})) + g = Graph.new(Description.new({EX.Subject, EX.predicate(), EX.Object})) assert unnamed_graph?(g) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) end test "creating a named graph from another graph" do - g = Graph.new(Graph.new({EX.Subject, EX.predicate, EX.Object}), - name: EX.GraphName) - assert named_graph?(g, iri(EX.GraphName)) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + g = + Graph.new(Graph.new({EX.Subject, EX.predicate(), EX.Object}), + name: EX.GraphName + ) - g = Graph.new(Graph.new({EX.Subject, EX.predicate, EX.Object}, name: EX.OtherGraphName), - name: EX.GraphName) assert named_graph?(g, iri(EX.GraphName)) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) + + g = + Graph.new(Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.OtherGraphName), + name: EX.GraphName + ) + + assert named_graph?(g, iri(EX.GraphName)) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) end test "creating an unnamed graph from another graph" do - g = Graph.new(Graph.new({EX.Subject, EX.predicate, EX.Object})) + g = Graph.new(Graph.new({EX.Subject, EX.predicate(), EX.Object})) assert unnamed_graph?(g) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) - g = Graph.new(Graph.new({EX.Subject, EX.predicate, EX.Object}, name: EX.OtherGraphName)) + g = Graph.new(Graph.new({EX.Subject, EX.predicate(), EX.Object}, name: EX.OtherGraphName)) assert unnamed_graph?(g) - assert graph_includes_statement?(g, {EX.Subject, EX.predicate, EX.Object}) + assert graph_includes_statement?(g, {EX.Subject, EX.predicate(), EX.Object}) end test "with prefixes" do assert Graph.new(prefixes: %{ex: EX}) == %Graph{prefixes: PrefixMap.new(ex: EX)} - assert Graph.new(prefixes: %{ex: EX}, name: EX.graph_name) == - %Graph{prefixes: PrefixMap.new(ex: EX), name: EX.graph_name} - assert Graph.new({EX.Subject, EX.predicate, EX.Object}, prefixes: %{ex: EX}) == - %Graph{Graph.new({EX.Subject, EX.predicate, EX.Object}) | prefixes: PrefixMap.new(ex: EX)} + assert Graph.new(prefixes: %{ex: EX}, name: EX.graph_name()) == + %Graph{prefixes: PrefixMap.new(ex: EX), name: EX.graph_name()} + + assert Graph.new({EX.Subject, EX.predicate(), EX.Object}, prefixes: %{ex: EX}) == + %Graph{ + Graph.new({EX.Subject, EX.predicate(), EX.Object}) + | prefixes: PrefixMap.new(ex: EX) + } end test "with base_iri" do - assert Graph.new(base_iri: EX.base) == - %Graph{base_iri: EX.base} - assert Graph.new(prefixes: %{ex: EX}, base_iri: EX.base) == - %Graph{prefixes: PrefixMap.new(ex: EX), base_iri: EX.base} + assert Graph.new(base_iri: EX.base()) == + %Graph{base_iri: EX.base()} - assert Graph.new({EX.Subject, EX.predicate, EX.Object}, base_iri: EX.base) == - %Graph{Graph.new({EX.Subject, EX.predicate, EX.Object}) | base_iri: EX.base} + assert Graph.new(prefixes: %{ex: EX}, base_iri: EX.base()) == + %Graph{prefixes: PrefixMap.new(ex: EX), base_iri: EX.base()} + + assert Graph.new({EX.Subject, EX.predicate(), EX.Object}, base_iri: EX.base()) == + %Graph{Graph.new({EX.Subject, EX.predicate(), EX.Object}) | base_iri: EX.base()} end test "creating a graph from another graph takes the prefixes from the other graph, but overwrites if necessary" do @@ -141,148 +162,185 @@ defmodule RDF.GraphTest do end test "clear/1" do - opts = [name: EX.Graph, base_iri: EX.base, prefixes: %{ex: EX.prefix}] - assert Graph.new({EX.S, EX.p, EX.O}, opts) + opts = [name: EX.Graph, base_iri: EX.base(), prefixes: %{ex: EX.prefix()}] + + assert Graph.new({EX.S, EX.p(), EX.O}, opts) |> Graph.clear() == Graph.new(opts) end describe "add" do test "a proper triple" do - assert Graph.add(graph(), iri(EX.Subject), EX.predicate, iri(EX.Object)) - |> graph_includes_statement?({EX.Subject, EX.predicate, EX.Object}) - assert Graph.add(graph(), {iri(EX.Subject), EX.predicate, iri(EX.Object)}) - |> graph_includes_statement?({EX.Subject, EX.predicate, EX.Object}) + assert Graph.add(graph(), iri(EX.Subject), EX.predicate(), iri(EX.Object)) + |> graph_includes_statement?({EX.Subject, EX.predicate(), EX.Object}) + + assert Graph.add(graph(), {iri(EX.Subject), EX.predicate(), iri(EX.Object)}) + |> graph_includes_statement?({EX.Subject, EX.predicate(), EX.Object}) end test "a coercible triple" do - assert Graph.add(graph(), - "http://example.com/Subject", EX.predicate, EX.Object) - |> graph_includes_statement?({EX.Subject, EX.predicate, EX.Object}) - assert Graph.add(graph(), - {"http://example.com/Subject", EX.predicate, EX.Object}) - |> graph_includes_statement?({EX.Subject, EX.predicate, EX.Object}) + assert Graph.add(graph(), "http://example.com/Subject", EX.predicate(), EX.Object) + |> graph_includes_statement?({EX.Subject, EX.predicate(), EX.Object}) + + assert Graph.add( + graph(), + {"http://example.com/Subject", EX.predicate(), EX.Object} + ) + |> graph_includes_statement?({EX.Subject, EX.predicate(), EX.Object}) end test "a triple with multiple objects" do - g = Graph.add(graph(), EX.Subject1, EX.predicate1, [EX.Object1, EX.Object2]) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object2}) + g = Graph.add(graph(), EX.Subject1, EX.predicate1(), [EX.Object1, EX.Object2]) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object2}) end test "a list of triples" do - g = Graph.add(graph(), [ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - {EX.Subject3, EX.predicate3, EX.Object3} - ]) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2, EX.Object2}) - assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3, EX.Object3}) + g = + Graph.add(graph(), [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ]) + + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3(), EX.Object3}) end test "a Description" do - g = Graph.add(graph(), Description.new(EX.Subject1, [ - {EX.predicate1, EX.Object1}, - {EX.predicate2, EX.Object2}, - ])) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2, EX.Object2}) + g = + Graph.add( + graph(), + Description.new(EX.Subject1, [ + {EX.predicate1(), EX.Object1}, + {EX.predicate2(), EX.Object2} + ]) + ) - g = Graph.add(g, Description.new({EX.Subject1, EX.predicate3, EX.Object3})) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2, EX.Object2}) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate3, EX.Object3}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2(), EX.Object2}) + + g = Graph.add(g, Description.new({EX.Subject1, EX.predicate3(), EX.Object3})) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate3(), EX.Object3}) end test "a list of Descriptions" do - g = Graph.add(graph(), [ - Description.new({EX.Subject1, EX.predicate1, EX.Object1}), - Description.new({EX.Subject2, EX.predicate2, EX.Object2}), - Description.new({EX.Subject1, EX.predicate3, EX.Object3}) - ]) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2, EX.Object2}) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate3, EX.Object3}) + g = + Graph.add(graph(), [ + Description.new({EX.Subject1, EX.predicate1(), EX.Object1}), + Description.new({EX.Subject2, EX.predicate2(), EX.Object2}), + Description.new({EX.Subject1, EX.predicate3(), EX.Object3}) + ]) + + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2(), EX.Object2}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate3(), EX.Object3}) end test "duplicates are ignored" do - g = Graph.add(graph(), {EX.Subject, EX.predicate, EX.Object}) - assert Graph.add(g, {EX.Subject, EX.predicate, EX.Object}) == g + g = Graph.add(graph(), {EX.Subject, EX.predicate(), EX.Object}) + assert Graph.add(g, {EX.Subject, EX.predicate(), EX.Object}) == g end test "a Graph" do - g = Graph.add(graph(), Graph.new([ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject2, EX.predicate2, EX.Object2}, - {EX.Subject3, EX.predicate3, EX.Object3} - ])) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2, EX.Object2}) - assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3, EX.Object3}) + g = + Graph.add( + graph(), + Graph.new([ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject2, EX.predicate2(), EX.Object2}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ]) + ) - g = Graph.add(g, Graph.new([ - {EX.Subject1, EX.predicate1, EX.Object2}, - {EX.Subject2, EX.predicate4, EX.Object4}, - ])) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object1}) - assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1, EX.Object2}) - assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2, EX.Object2}) - assert graph_includes_statement?(g, {EX.Subject2, EX.predicate4, EX.Object4}) - assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3, EX.Object3}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2(), EX.Object2}) + assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3(), EX.Object3}) + + g = + Graph.add( + g, + Graph.new([ + {EX.Subject1, EX.predicate1(), EX.Object2}, + {EX.Subject2, EX.predicate4(), EX.Object4} + ]) + ) + + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert graph_includes_statement?(g, {EX.Subject1, EX.predicate1(), EX.Object2}) + assert graph_includes_statement?(g, {EX.Subject2, EX.predicate2(), EX.Object2}) + assert graph_includes_statement?(g, {EX.Subject2, EX.predicate4(), EX.Object4}) + assert graph_includes_statement?(g, {EX.Subject3, EX.predicate3(), EX.Object3}) end test "merges the prefixes of another graph" do - graph = Graph.new(prefixes: %{xsd: XSD}) - |> Graph.add(Graph.new(prefixes: %{rdfs: RDFS})) + graph = + Graph.new(prefixes: %{xsd: XSD}) + |> Graph.add(Graph.new(prefixes: %{rdfs: RDFS})) + assert graph.prefixes == PrefixMap.new(xsd: XSD, rdfs: RDFS) end test "merges the prefixes of another graph and keeps the original mapping in case of conflicts" do - graph = Graph.new(prefixes: %{ex: EX}) - |> Graph.add(Graph.new(prefixes: %{ex: XSD})) + graph = + Graph.new(prefixes: %{ex: EX}) + |> Graph.add(Graph.new(prefixes: %{ex: XSD})) + assert graph.prefixes == PrefixMap.new(ex: EX) end test "preserves the base_iri" do - graph = Graph.new() - |> Graph.add(Graph.new({EX.Subject, EX.predicate, EX.Object}, base_iri: EX.base)) - assert graph.base_iri == Graph.new.base_iri + graph = + Graph.new() + |> Graph.add(Graph.new({EX.Subject, EX.predicate(), EX.Object}, base_iri: EX.base())) + + assert graph.base_iri == Graph.new().base_iri end test "preserves the name and prefixes when the data provided is not a graph" do - graph = Graph.new(name: EX.GraphName, prefixes: %{ex: EX}) - |> Graph.add(EX.Subject, EX.predicate, EX.Object) + graph = + Graph.new(name: EX.GraphName, prefixes: %{ex: EX}) + |> Graph.add(EX.Subject, EX.predicate(), EX.Object) + assert graph.name == RDF.iri(EX.GraphName) assert graph.prefixes == PrefixMap.new(ex: EX) end test "non-coercible Triple elements are causing an error" do assert_raise RDF.IRI.InvalidError, fn -> - Graph.add(graph(), {"not a IRI", EX.predicate, iri(EX.Object)}) + Graph.add(graph(), {"not a IRI", EX.predicate(), iri(EX.Object)}) end + assert_raise RDF.Literal.InvalidError, fn -> - Graph.add(graph(), {EX.Subject, EX.prop, self()}) + Graph.add(graph(), {EX.Subject, EX.prop(), self()}) end end end - describe "put" do test "a list of triples" do - g = Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}]) - |> RDF.Graph.put([{EX.S1, EX.P2, EX.O3}, {EX.S1, EX.P2, bnode(:foo)}, - {EX.S2, EX.P2, EX.O3}, {EX.S2, EX.P2, EX.O4}]) + g = + Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}]) + |> RDF.Graph.put([ + {EX.S1, EX.P2, EX.O3}, + {EX.S1, EX.P2, bnode(:foo)}, + {EX.S2, EX.P2, EX.O3}, + {EX.S2, EX.P2, EX.O4} + ]) - assert Graph.triple_count(g) == 5 - assert graph_includes_statement?(g, {EX.S1, EX.P1, EX.O1}) - assert graph_includes_statement?(g, {EX.S1, EX.P2, EX.O3}) - assert graph_includes_statement?(g, {EX.S1, EX.P2, bnode(:foo)}) - assert graph_includes_statement?(g, {EX.S2, EX.P2, EX.O3}) - assert graph_includes_statement?(g, {EX.S2, EX.P2, EX.O4}) + assert Graph.triple_count(g) == 5 + assert graph_includes_statement?(g, {EX.S1, EX.P1, EX.O1}) + assert graph_includes_statement?(g, {EX.S1, EX.P2, EX.O3}) + assert graph_includes_statement?(g, {EX.S1, EX.P2, bnode(:foo)}) + assert graph_includes_statement?(g, {EX.S2, EX.P2, EX.O3}) + assert graph_includes_statement?(g, {EX.S2, EX.P2, EX.O4}) end test "a Description" do - g = Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}, {EX.S1, EX.P3, EX.O3}]) + g = + Graph.new([{EX.S1, EX.P1, EX.O1}, {EX.S2, EX.P2, EX.O2}, {EX.S1, EX.P3, EX.O3}]) |> RDF.Graph.put(Description.new(EX.S1, [{EX.P3, EX.O4}, {EX.P2, bnode(:foo)}])) assert Graph.triple_count(g) == 4 @@ -297,13 +355,15 @@ defmodule RDF.GraphTest do Graph.new([ {EX.S1, EX.P1, EX.O1}, {EX.S1, EX.P3, EX.O3}, - {EX.S2, EX.P2, EX.O2}, + {EX.S2, EX.P2, EX.O2} ]) - |> RDF.Graph.put(Graph.new([ - {EX.S1, EX.P3, EX.O4}, - {EX.S2, EX.P2, bnode(:foo)}, - {EX.S3, EX.P3, EX.O3} - ])) + |> RDF.Graph.put( + Graph.new([ + {EX.S1, EX.P3, EX.O4}, + {EX.S2, EX.P2, bnode(:foo)}, + {EX.S3, EX.P3, EX.O3} + ]) + ) assert Graph.triple_count(g) == 4 assert graph_includes_statement?(g, {EX.S1, EX.P1, EX.O1}) @@ -313,116 +373,142 @@ defmodule RDF.GraphTest do end test "merges the prefixes of another graph" do - graph = Graph.new(prefixes: %{xsd: XSD}) - |> Graph.put(Graph.new(prefixes: %{rdfs: RDFS})) + graph = + Graph.new(prefixes: %{xsd: XSD}) + |> Graph.put(Graph.new(prefixes: %{rdfs: RDFS})) + assert graph.prefixes == PrefixMap.new(xsd: XSD, rdfs: RDFS) end test "merges the prefixes of another graph and keeps the original mapping in case of conflicts" do - graph = Graph.new(prefixes: %{ex: EX}) - |> Graph.put(Graph.new(prefixes: %{ex: XSD})) + graph = + Graph.new(prefixes: %{ex: EX}) + |> Graph.put(Graph.new(prefixes: %{ex: XSD})) + assert graph.prefixes == PrefixMap.new(ex: EX) end test "preserves the name, base_iri and prefixes" do - graph = Graph.new(name: EX.GraphName, prefixes: %{ex: EX}, base_iri: EX.base) - |> Graph.put(EX.Subject, EX.predicate, EX.Object) + graph = + Graph.new(name: EX.GraphName, prefixes: %{ex: EX}, base_iri: EX.base()) + |> Graph.put(EX.Subject, EX.predicate(), EX.Object) + assert graph.name == RDF.iri(EX.GraphName) assert graph.prefixes == PrefixMap.new(ex: EX) - assert graph.base_iri == EX.base + assert graph.base_iri == EX.base() end end - describe "delete" do setup do {:ok, - graph1: Graph.new({EX.S, EX.p, EX.O}), - graph2: Graph.new({EX.S, EX.p, [EX.O1, EX.O2]}, name: EX.Graph), - graph3: Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - {EX.S2, EX.p2, EX.O3}, - {EX.S3, EX.p3, [~B, ~L"bar"]}, - ]) - } + graph1: Graph.new({EX.S, EX.p(), EX.O}), + graph2: Graph.new({EX.S, EX.p(), [EX.O1, EX.O2]}, name: EX.Graph), + graph3: + Graph.new([ + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + {EX.S2, EX.p2(), EX.O3}, + {EX.S3, EX.p3(), [~B, ~L"bar"]} + ])} end test "a single statement as a triple", - %{graph1: graph1, graph2: graph2} do - assert Graph.delete(Graph.new, {EX.S, EX.p, EX.O}) == Graph.new - assert Graph.delete(graph1, {EX.S, EX.p, EX.O}) == Graph.new - assert Graph.delete(graph2, {EX.S, EX.p, EX.O1}) == - Graph.new({EX.S, EX.p, EX.O2}, name: EX.Graph) - assert Graph.delete(graph2, {EX.S, EX.p, EX.O1}) == - Graph.new({EX.S, EX.p, EX.O2}, name: EX.Graph) + %{graph1: graph1, graph2: graph2} do + assert Graph.delete(Graph.new(), {EX.S, EX.p(), EX.O}) == Graph.new() + assert Graph.delete(graph1, {EX.S, EX.p(), EX.O}) == Graph.new() + + assert Graph.delete(graph2, {EX.S, EX.p(), EX.O1}) == + Graph.new({EX.S, EX.p(), EX.O2}, name: EX.Graph) + + assert Graph.delete(graph2, {EX.S, EX.p(), EX.O1}) == + Graph.new({EX.S, EX.p(), EX.O2}, name: EX.Graph) end test "multiple statements with a triple with multiple objects", - %{graph1: graph1, graph2: graph2} do - assert Graph.delete(Graph.new, {EX.S, EX.p, [EX.O1, EX.O2]}) == Graph.new - assert Graph.delete(graph1, {EX.S, EX.p, [EX.O, EX.O2]}) == Graph.new - assert Graph.delete(graph2, {EX.S, EX.p, [EX.O1, EX.O2]}) == Graph.new(name: EX.Graph) + %{graph1: graph1, graph2: graph2} do + assert Graph.delete(Graph.new(), {EX.S, EX.p(), [EX.O1, EX.O2]}) == Graph.new() + assert Graph.delete(graph1, {EX.S, EX.p(), [EX.O, EX.O2]}) == Graph.new() + assert Graph.delete(graph2, {EX.S, EX.p(), [EX.O1, EX.O2]}) == Graph.new(name: EX.Graph) end test "multiple statements with a list of triples", - %{graph1: graph1, graph2: graph2, graph3: graph3} do - assert Graph.delete(graph1, [{EX.S, EX.p, EX.O}, - {EX.S, EX.p, EX.O2}]) == Graph.new - assert Graph.delete(graph2, [{EX.S, EX.p, EX.O1}, - {EX.S, EX.p, EX.O2}]) == Graph.new(name: EX.Graph) + %{graph1: graph1, graph2: graph2, graph3: graph3} do + assert Graph.delete(graph1, [{EX.S, EX.p(), EX.O}, {EX.S, EX.p(), EX.O2}]) == Graph.new() + + assert Graph.delete(graph2, [{EX.S, EX.p(), EX.O1}, {EX.S, EX.p(), EX.O2}]) == + Graph.new(name: EX.Graph) + assert Graph.delete(graph3, [ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - {EX.S2, EX.p2, EX.O3}, - {EX.S3, EX.p3, ~B}]) == Graph.new({EX.S3, EX.p3, ~L"bar"}) + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + {EX.S2, EX.p2(), EX.O3}, + {EX.S3, EX.p3(), ~B} + ]) == Graph.new({EX.S3, EX.p3(), ~L"bar"}) end test "multiple statements with a Description", - %{graph1: graph1, graph2: graph2, graph3: graph3} do - assert Graph.delete(graph1, Description.new(EX.S, - [{EX.p, EX.O}, {EX.p2, EX.O2}])) == Graph.new - assert Graph.delete(graph2, Description.new(EX.S, EX.p, [EX.O1, EX.O2])) == - Graph.new(name: EX.Graph) - assert Graph.delete(graph3, Description.new(EX.S3, EX.p3, ~B)) == + %{graph1: graph1, graph2: graph2, graph3: graph3} do + assert Graph.delete( + graph1, + Description.new( + EX.S, + [{EX.p(), EX.O}, {EX.p2(), EX.O2}] + ) + ) == Graph.new() + + assert Graph.delete(graph2, Description.new(EX.S, EX.p(), [EX.O1, EX.O2])) == + Graph.new(name: EX.Graph) + + assert Graph.delete(graph3, Description.new(EX.S3, EX.p3(), ~B)) == Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - {EX.S2, EX.p2, EX.O3}, - {EX.S3, EX.p3, [~L"bar"]}, - ]) + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + {EX.S2, EX.p2(), EX.O3}, + {EX.S3, EX.p3(), [~L"bar"]} + ]) end test "multiple statements with a Graph", - %{graph1: graph1, graph2: graph2, graph3: graph3} do + %{graph1: graph1, graph2: graph2, graph3: graph3} do assert Graph.delete(graph1, graph2) == graph1 - assert Graph.delete(graph1, graph1) == Graph.new - assert Graph.delete(graph2, Graph.new({EX.S, EX.p, [EX.O1, EX.O3]}, - name: EX.Graph)) == - Graph.new({EX.S, EX.p, EX.O2}, name: EX.Graph) - assert Graph.delete(graph3, Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - {EX.S2, EX.p2, EX.O3}, - {EX.S3, EX.p3, ~B}, - ])) == Graph.new({EX.S3, EX.p3, ~L"bar"}) + assert Graph.delete(graph1, graph1) == Graph.new() + + assert Graph.delete( + graph2, + Graph.new({EX.S, EX.p(), [EX.O1, EX.O3]}, + name: EX.Graph + ) + ) == + Graph.new({EX.S, EX.p(), EX.O2}, name: EX.Graph) + + assert Graph.delete( + graph3, + Graph.new([ + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + {EX.S2, EX.p2(), EX.O3}, + {EX.S3, EX.p3(), ~B} + ]) + ) == Graph.new({EX.S3, EX.p3(), ~L"bar"}) end test "preserves the name and prefixes" do - graph = Graph.new(EX.Subject, EX.predicate, EX.Object, name: EX.GraphName, prefixes: %{ex: EX}) - |> Graph.delete(EX.Subject, EX.predicate, EX.Object) + graph = + Graph.new(EX.Subject, EX.predicate(), EX.Object, name: EX.GraphName, prefixes: %{ex: EX}) + |> Graph.delete(EX.Subject, EX.predicate(), EX.Object) + assert graph.name == RDF.iri(EX.GraphName) assert graph.prefixes == PrefixMap.new(ex: EX) end end - describe "delete_subjects" do setup do {:ok, - graph1: Graph.new({EX.S, EX.p, [EX.O1, EX.O2]}, name: EX.Graph), - graph2: Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - {EX.S2, EX.p2, EX.O3}, - {EX.S3, EX.p3, [~B, ~L"bar"]}, - ]) - } + graph1: Graph.new({EX.S, EX.p(), [EX.O1, EX.O2]}, name: EX.Graph), + graph2: + Graph.new([ + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + {EX.S2, EX.p2(), EX.O3}, + {EX.S3, EX.p3(), [~B, ~L"bar"]} + ])} end test "a single subject", %{graph1: graph1} do @@ -430,66 +516,73 @@ defmodule RDF.GraphTest do assert Graph.delete_subjects(graph1, EX.S) == Graph.new(name: EX.Graph) end - test "a list of subjects", %{graph1: graph1, graph2: graph2} do + test "a list of subjects", %{graph1: graph1, graph2: graph2} do assert Graph.delete_subjects(graph1, [EX.S, EX.Other]) == Graph.new(name: EX.Graph) - assert Graph.delete_subjects(graph2, [EX.S1, EX.S2, EX.S3]) == Graph.new + assert Graph.delete_subjects(graph2, [EX.S1, EX.S2, EX.S3]) == Graph.new() end end - describe "update/4" do test "a description returned from the update function becomes new description of the subject" do - old_description = Description.new({EX.S2, EX.p2, EX.O3}) - new_description = Description.new({EX.S2, EX.p, EX.O}) + old_description = Description.new({EX.S2, EX.p2(), EX.O3}) + new_description = Description.new({EX.S2, EX.p(), EX.O}) + assert Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - old_description, + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + old_description ]) |> Graph.update(EX.S2, fn ^old_description -> new_description end) == Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - new_description, + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + new_description ]) end test "a description with another subject returned from the update function becomes new description of the subject" do - old_description = Description.new({EX.S2, EX.p2, EX.O3}) - new_description = Description.new({EX.S2, EX.p, EX.O}) + old_description = Description.new({EX.S2, EX.p2(), EX.O3}) + new_description = Description.new({EX.S2, EX.p(), EX.O}) + assert Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - old_description, + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + old_description ]) - |> Graph.update(EX.S2, - fn ^old_description -> Description.new(EX.S3, new_description) end) == + |> Graph.update( + EX.S2, + fn ^old_description -> Description.new(EX.S3, new_description) end + ) == Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - new_description, + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + new_description ]) end test "a value returned from the update function becomes new coerced description of the subject" do - old_description = Description.new({EX.S2, EX.p2, EX.O3}) - new_description = {EX.p, [EX.O1, EX.O2]} + old_description = Description.new({EX.S2, EX.p2(), EX.O3}) + new_description = {EX.p(), [EX.O1, EX.O2]} + assert Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - old_description, + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + old_description ]) - |> Graph.update(EX.S2, - fn ^old_description -> new_description end) == + |> Graph.update( + EX.S2, + fn ^old_description -> new_description end + ) == Graph.new([ - {EX.S1, EX.p1, [EX.O1, EX.O2]}, - Description.new(EX.S2, new_description), + {EX.S1, EX.p1(), [EX.O1, EX.O2]}, + Description.new(EX.S2, new_description) ]) end test "returning nil from the update function causes a removal of the description" do - assert Graph.new({EX.S, EX.p, EX.O}) + assert Graph.new({EX.S, EX.p(), EX.O}) |> Graph.update(EX.S, fn _ -> nil end) == Graph.new() end test "when the property is not present the initial object value is added for the predicate and the update function not called" do fun = fn _ -> raise "should not be called" end + assert Graph.new() |> Graph.update(EX.S, {EX.P, EX.O}, fun) == Graph.new(EX.S, EX.P, EX.O) @@ -501,33 +594,35 @@ defmodule RDF.GraphTest do end test "pop" do - assert Graph.pop(Graph.new) == {nil, Graph.new} + assert Graph.pop(Graph.new()) == {nil, Graph.new()} - {triple, graph} = Graph.new({EX.S, EX.p, EX.O}) |> Graph.pop - assert {iri(EX.S), iri(EX.p), iri(EX.O)} == triple + {triple, graph} = Graph.new({EX.S, EX.p(), EX.O}) |> Graph.pop() + assert {iri(EX.S), iri(EX.p()), iri(EX.O)} == triple assert Enum.count(graph.descriptions) == 0 {{subject, predicate, _}, graph} = - Graph.new([{EX.S, EX.p, EX.O1}, {EX.S, EX.p, EX.O2}]) - |> Graph.pop - assert {subject, predicate} == {iri(EX.S), iri(EX.p)} + Graph.new([{EX.S, EX.p(), EX.O1}, {EX.S, EX.p(), EX.O2}]) + |> Graph.pop() + + assert {subject, predicate} == {iri(EX.S), iri(EX.p())} assert Enum.count(graph.descriptions) == 1 {{subject, _, _}, graph} = - Graph.new([{EX.S, EX.p1, EX.O1}, {EX.S, EX.p2, EX.O2}]) - |> Graph.pop + Graph.new([{EX.S, EX.p1(), EX.O1}, {EX.S, EX.p2(), EX.O2}]) + |> Graph.pop() + assert subject == iri(EX.S) assert Enum.count(graph.descriptions) == 1 end - test "values/1" do assert Graph.new() |> Graph.values() == %{} - assert Graph.new([{EX.s1, EX.p, EX.o1}, {EX.s2, EX.p, EX.o2}]) + + assert Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}]) |> Graph.values() == %{ - RDF.Term.value(EX.s1) => %{RDF.Term.value(EX.p) => [RDF.Term.value(EX.o1)]}, - RDF.Term.value(EX.s2) => %{RDF.Term.value(EX.p) => [RDF.Term.value(EX.o2)]}, + RDF.Term.value(EX.s1()) => %{RDF.Term.value(EX.p()) => [RDF.Term.value(EX.o1())]}, + RDF.Term.value(EX.s2()) => %{RDF.Term.value(EX.p()) => [RDF.Term.value(EX.o2())]} } end @@ -535,77 +630,92 @@ defmodule RDF.GraphTest do mapping = fn {:predicate, predicate} -> predicate |> to_string() |> String.split("/") |> List.last() |> String.to_atom() + {_, term} -> RDF.Term.value(term) end assert Graph.new() |> Graph.values(mapping) == %{} - assert Graph.new([{EX.s1, EX.p, EX.o1}, {EX.s2, EX.p, EX.o2}]) + + assert Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}]) |> Graph.values(mapping) == %{ - RDF.Term.value(EX.s1) => %{p: [RDF.Term.value(EX.o1)]}, - RDF.Term.value(EX.s2) => %{p: [RDF.Term.value(EX.o2)]}, + RDF.Term.value(EX.s1()) => %{p: [RDF.Term.value(EX.o1())]}, + RDF.Term.value(EX.s2()) => %{p: [RDF.Term.value(EX.o2())]} } end describe "take/2" do test "with a non-empty subject list" do - assert Graph.new([{EX.s1, EX.p, EX.o1}, {EX.s2, EX.p, EX.o2}]) - |> Graph.take([EX.s2, EX.s3]) == - Graph.new([{EX.s2, EX.p, EX.o2}]) + assert Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}]) + |> Graph.take([EX.s2(), EX.s3()]) == + Graph.new([{EX.s2(), EX.p(), EX.o2()}]) end test "with an empty subject list" do - assert Graph.new([{EX.s1, EX.p, EX.o1}, {EX.s2, EX.p, EX.o2}]) + assert Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}]) |> Graph.take([]) == Graph.new() end test "with nil" do - assert Graph.new([{EX.s1, EX.p, EX.o1}, {EX.s2, EX.p, EX.o2}]) + assert Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}]) |> Graph.take(nil) == - Graph.new([{EX.s1, EX.p, EX.o1}, {EX.s2, EX.p, EX.o2}]) + Graph.new([{EX.s1(), EX.p(), EX.o1()}, {EX.s2(), EX.p(), EX.o2()}]) end end describe "take/3" do test "with non-empty subject and property lists" do - assert Graph.new([{EX.s1, EX.p1, EX.o1}, {EX.s1, EX.p2, EX.o1}, {EX.s2, EX.p1, EX.o2}]) - |> Graph.take([EX.s1, EX.s3], [EX.p2]) == - Graph.new([{EX.s1, EX.p2, EX.o1}]) + assert Graph.new([ + {EX.s1(), EX.p1(), EX.o1()}, + {EX.s1(), EX.p2(), EX.o1()}, + {EX.s2(), EX.p1(), EX.o2()} + ]) + |> Graph.take([EX.s1(), EX.s3()], [EX.p2()]) == + Graph.new([{EX.s1(), EX.p2(), EX.o1()}]) end test "with an empty subject list" do assert Graph.new( [ - {EX.s1, EX.p1, EX.o1}, - {EX.s1, EX.p2, EX.o1}, - {EX.s2, EX.p1, EX.o2} - ], name: EX.Graph) - |> Graph.take([], [EX.p1]) == Graph.new(name: EX.Graph) + {EX.s1(), EX.p1(), EX.o1()}, + {EX.s1(), EX.p2(), EX.o1()}, + {EX.s2(), EX.p1(), EX.o2()} + ], + name: EX.Graph + ) + |> Graph.take([], [EX.p1()]) == Graph.new(name: EX.Graph) end test "with nil" do - assert Graph.new([{EX.s1, EX.p1, EX.o1}, {EX.s1, EX.p2, EX.o1}, {EX.s2, EX.p1, EX.o2}]) - |> Graph.take(nil, [EX.p1]) == - Graph.new([{EX.s1, EX.p1, EX.o1}, {EX.s2, EX.p1, EX.o2}]) + assert Graph.new([ + {EX.s1(), EX.p1(), EX.o1()}, + {EX.s1(), EX.p2(), EX.o1()}, + {EX.s2(), EX.p1(), EX.o2()} + ]) + |> Graph.take(nil, [EX.p1()]) == + Graph.new([{EX.s1(), EX.p1(), EX.o1()}, {EX.s2(), EX.p1(), EX.o2()}]) end end test "equal/2" do - assert Graph.new({EX.S, EX.p, EX.O}) |> Graph.equal?(Graph.new({EX.S, EX.p, EX.O})) - assert Graph.new({EX.S, EX.p, EX.O}, name: EX.Graph1) - |> Graph.equal?(Graph.new({EX.S, EX.p, EX.O}, name: EX.Graph1)) - assert Graph.new({EX.S, EX.p, EX.O}, prefixes: %{ex: EX}) - |> Graph.equal?(Graph.new({EX.S, EX.p, EX.O}, prefixes: %{xsd: XSD})) - assert Graph.new({EX.S, EX.p, EX.O}, base_iri: EX.base) - |> Graph.equal?(Graph.new({EX.S, EX.p, EX.O}, base_iri: EX.other_base)) + assert Graph.new({EX.S, EX.p(), EX.O}) |> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O})) - refute Graph.new({EX.S, EX.p, EX.O}) |> Graph.equal?(Graph.new({EX.S, EX.p, EX.O2})) - refute Graph.new({EX.S, EX.p, EX.O}, name: EX.Graph1) - |> Graph.equal?(Graph.new({EX.S, EX.p, EX.O}, name: EX.Graph2)) + assert Graph.new({EX.S, EX.p(), EX.O}, name: EX.Graph1) + |> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O}, name: EX.Graph1)) + + assert Graph.new({EX.S, EX.p(), EX.O}, prefixes: %{ex: EX}) + |> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O}, prefixes: %{xsd: XSD})) + + assert Graph.new({EX.S, EX.p(), EX.O}, base_iri: EX.base()) + |> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O}, base_iri: EX.other_base())) + + refute Graph.new({EX.S, EX.p(), EX.O}) |> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O2})) + + refute Graph.new({EX.S, EX.p(), EX.O}, name: EX.Graph1) + |> Graph.equal?(Graph.new({EX.S, EX.p(), EX.O}, name: EX.Graph2)) end - describe "add_prefixes/2" do test "when prefixes already exist" do graph = Graph.new(prefixes: %{xsd: XSD}) |> Graph.add_prefixes(ex: EX) @@ -623,7 +733,9 @@ defmodule RDF.GraphTest do end test "when prefixes have conflicting mappings and a conflict resolver function is provided" do - graph = Graph.new(prefixes: %{ex: EX}) |> Graph.add_prefixes([ex: XSD], fn _, ns, _ -> ns end) + graph = + Graph.new(prefixes: %{ex: EX}) |> Graph.add_prefixes([ex: XSD], fn _, ns, _ -> ns end) + assert graph.prefixes == PrefixMap.new(ex: EX) end end @@ -635,7 +747,9 @@ defmodule RDF.GraphTest do end test "when given a list of prefixes" do - graph = Graph.new(prefixes: %{ex1: EX, ex2: EX}) |> Graph.delete_prefixes([:ex1, :ex2, :ex3]) + graph = + Graph.new(prefixes: %{ex1: EX, ex2: EX}) |> Graph.delete_prefixes([:ex1, :ex2, :ex3]) + assert graph.prefixes == PrefixMap.new() end @@ -646,7 +760,7 @@ defmodule RDF.GraphTest do end test "clear_prefixes/1" do - assert Graph.clear_prefixes(Graph.new(prefixes: %{ex: EX})) == Graph.new + assert Graph.clear_prefixes(Graph.new(prefixes: %{ex: EX})) == Graph.new() end describe "set_base_iri/1" do @@ -662,7 +776,7 @@ defmodule RDF.GraphTest do test "when given a vocabulary namespace module" do graph = Graph.new() |> Graph.set_base_iri(EX) - assert graph.base_iri == RDF.iri(EX.__base_iri__) + assert graph.base_iri == RDF.iri(EX.__base_iri__()) end test "when given nil" do @@ -672,79 +786,85 @@ defmodule RDF.GraphTest do end test "clear_base_iri/1" do - assert Graph.clear_base_iri(Graph.new(base_iri: EX.base)) == Graph.new + assert Graph.clear_base_iri(Graph.new(base_iri: EX.base())) == Graph.new() end test "clear_metadata/1" do - assert Graph.clear_metadata(Graph.new(base_iri: EX.base, prefixes: %{ex: EX})) == - Graph.new + assert Graph.clear_metadata(Graph.new(base_iri: EX.base(), prefixes: %{ex: EX})) == + Graph.new() end describe "Enumerable protocol" do test "Enum.count" do - assert Enum.count(Graph.new(name: EX.foo)) == 0 - assert Enum.count(Graph.new {EX.S, EX.p, EX.O}) == 1 - assert Enum.count(Graph.new [{EX.S, EX.p, EX.O1}, {EX.S, EX.p, EX.O2}]) == 2 + assert Enum.count(Graph.new(name: EX.foo())) == 0 + assert Enum.count(Graph.new({EX.S, EX.p(), EX.O})) == 1 + assert Enum.count(Graph.new([{EX.S, EX.p(), EX.O1}, {EX.S, EX.p(), EX.O2}])) == 2 + + g = + Graph.add(graph(), [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ]) - g = Graph.add(graph(), [ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - {EX.Subject3, EX.predicate3, EX.Object3} - ]) assert Enum.count(g) == 3 end test "Enum.member?" do - refute Enum.member?(Graph.new, {iri(EX.S), EX.p, iri(EX.O)}) - assert Enum.member?(Graph.new({EX.S, EX.p, EX.O}), {EX.S, EX.p, EX.O}) + refute Enum.member?(Graph.new(), {iri(EX.S), EX.p(), iri(EX.O)}) + assert Enum.member?(Graph.new({EX.S, EX.p(), EX.O}), {EX.S, EX.p(), EX.O}) - g = Graph.add(graph(), [ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - {EX.Subject3, EX.predicate3, EX.Object3} - ]) - assert Enum.member?(g, {EX.Subject1, EX.predicate1, EX.Object1}) - assert Enum.member?(g, {EX.Subject1, EX.predicate2, EX.Object2}) - assert Enum.member?(g, {EX.Subject3, EX.predicate3, EX.Object3}) + g = + Graph.add(graph(), [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ]) + + assert Enum.member?(g, {EX.Subject1, EX.predicate1(), EX.Object1}) + assert Enum.member?(g, {EX.Subject1, EX.predicate2(), EX.Object2}) + assert Enum.member?(g, {EX.Subject3, EX.predicate3(), EX.Object3}) end test "Enum.reduce" do - g = Graph.add(graph(), [ - {EX.Subject1, EX.predicate1, EX.Object1}, - {EX.Subject1, EX.predicate2, EX.Object2}, - {EX.Subject3, EX.predicate3, EX.Object3} - ]) + g = + Graph.add(graph(), [ + {EX.Subject1, EX.predicate1(), EX.Object1}, + {EX.Subject1, EX.predicate2(), EX.Object2}, + {EX.Subject3, EX.predicate3(), EX.Object3} + ]) - assert g == Enum.reduce(g, graph(), - fn(triple, acc) -> acc |> Graph.add(triple) end) + assert g == Enum.reduce(g, graph(), fn triple, acc -> acc |> Graph.add(triple) end) 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.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] - ] + [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)) + 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 - assert Graph.new({EX.S, EX.p, EX.O})[EX.S] == - Description.new({EX.S, EX.p, EX.O}) + assert Graph.new()[EX.Subject] == nil + + assert Graph.new({EX.S, EX.p(), EX.O})[EX.S] == + Description.new({EX.S, EX.p(), EX.O}) end end - end diff --git a/test/unit/iri_test.exs b/test/unit/iri_test.exs index af6aa91..703260f 100644 --- a/test/unit/iri_test.exs +++ b/test/unit/iri_test.exs @@ -3,39 +3,37 @@ defmodule RDF.IRITest do use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.com/#", - terms: [], strict: false + defvocab EX, base_iri: "http://example.com/#", terms: [], strict: false doctest RDF.IRI alias RDF.IRI @absolute_iris [ - "http://www.example.com/foo/", - %IRI{value: "http://www.example.com/foo/"}, - URI.parse("http://www.example.com/foo/"), - "http://www.example.com/foo#", - %IRI{value: "http://www.example.com/foo#"}, - URI.parse("http://www.example.com/foo#"), - "https://en.wiktionary.org/wiki/Ῥόδος", - %IRI{value: "https://en.wiktionary.org/wiki/Ῥόδος"}, - URI.parse("https://en.wiktionary.org/wiki/Ῥόδος"), - ] + "http://www.example.com/foo/", + %IRI{value: "http://www.example.com/foo/"}, + URI.parse("http://www.example.com/foo/"), + "http://www.example.com/foo#", + %IRI{value: "http://www.example.com/foo#"}, + URI.parse("http://www.example.com/foo#"), + "https://en.wiktionary.org/wiki/Ῥόδος", + %IRI{value: "https://en.wiktionary.org/wiki/Ῥόδος"}, + URI.parse("https://en.wiktionary.org/wiki/Ῥόδος") + ] @relative_iris [ - "/relative/", - %IRI{value: "/relative/"}, - URI.parse("/relative/"), - "/Ῥόδος/", - %IRI{value: "/Ῥόδος/"}, - URI.parse("/Ῥόδος/"), - ] + "/relative/", + %IRI{value: "/relative/"}, + URI.parse("/relative/"), + "/Ῥόδος/", + %IRI{value: "/Ῥόδος/"}, + URI.parse("/Ῥόδος/") + ] def absolute_iris, do: @absolute_iris def relative_iris, do: @relative_iris - def valid_iris, do: @absolute_iris - def invalid_iris, do: nil # TODO: - + def valid_iris, do: @absolute_iris + # TODO: + def invalid_iris, do: nil describe "new/1" do test "with a string" do @@ -65,7 +63,6 @@ defmodule RDF.IRITest do end end - describe "new!/1" do test "with valid iris" do Enum.each(valid_iris(), fn valid_iri -> @@ -105,7 +102,6 @@ defmodule RDF.IRITest do end end - describe "coerce_base/1" do test "with a string" do assert IRI.coerce_base("http://example.com/") == IRI.new("http://example.com/") @@ -135,7 +131,7 @@ defmodule RDF.IRITest do end test "with a RDF.Vocabulary.Namespace module" do - assert IRI.coerce_base(EX) == IRI.new(EX.__base_iri__) + assert IRI.coerce_base(EX) == IRI.new(EX.__base_iri__()) end test "with a RDF.Vocabulary.Namespace module which is not loaded yet" do @@ -143,7 +139,6 @@ defmodule RDF.IRITest do end end - describe "valid!/1" do test "with valid iris" do Enum.each(valid_iris(), fn valid_iri -> @@ -180,7 +175,6 @@ defmodule RDF.IRITest do end end - describe "valid?/1" do test "with valid iris" do Enum.each(valid_iris(), fn valid_iri -> @@ -213,7 +207,6 @@ defmodule RDF.IRITest do end end - describe "absolute?/1" do test "with absolute iris" do Enum.each(absolute_iris(), fn absolute_iri -> @@ -246,7 +239,6 @@ defmodule RDF.IRITest do end end - describe "absolute/2" do test "with an already absolute iri" do for absolute_iri <- absolute_iris(), @@ -258,7 +250,7 @@ defmodule RDF.IRITest do test "with a relative iri" do for relative_iri <- relative_iris(), base_iri <- absolute_iris() do assert IRI.absolute(relative_iri, base_iri) == - IRI.merge(base_iri, relative_iri) + IRI.merge(base_iri, relative_iri) end end @@ -269,28 +261,25 @@ defmodule RDF.IRITest do end end - describe "merge/2" do test "with a valid absolute base iri and a valid relative iri" do for base_iri <- absolute_iris(), relative_iri <- relative_iris() do - assert IRI.merge(base_iri, relative_iri) == ( - base_iri - |> to_string - |> URI.merge(to_string(relative_iri)) - |> IRI.new - ) - end + assert IRI.merge(base_iri, relative_iri) == + base_iri + |> to_string + |> URI.merge(to_string(relative_iri)) + |> IRI.new() + end end test "with a valid absolute base iri and a valid absolute iri" do for base_iri <- absolute_iris(), absolute_iri <- absolute_iris() do - assert IRI.merge(base_iri, absolute_iri) == ( - base_iri - |> to_string - |> URI.merge(to_string(absolute_iri)) - |> IRI.new - ) - end + assert IRI.merge(base_iri, absolute_iri) == + base_iri + |> to_string + |> URI.merge(to_string(absolute_iri)) + |> IRI.new() + end end test "with a relative base iri" do @@ -302,7 +291,7 @@ defmodule RDF.IRITest do end test "with empty fragments" do - assert IRI.merge("http://example.com/","foo#") == IRI.new("http://example.com/foo#") + assert IRI.merge("http://example.com/", "foo#") == IRI.new("http://example.com/foo#") end @tag skip: "TODO: proper validation" @@ -316,17 +305,16 @@ defmodule RDF.IRITest do describe "parse/1" do test "with absolute and relative iris" do Enum.each(absolute_iris() ++ relative_iris(), fn iri -> - assert IRI.parse(iri) == ( - iri - |> IRI.new - |> to_string() - |> URI.parse - ) + assert IRI.parse(iri) == + iri + |> IRI.new() + |> to_string() + |> URI.parse() end) end test "with a resolvable atom" do - assert IRI.parse(EX.Foo) == (EX.Foo |> IRI.new |> IRI.parse) + assert IRI.parse(EX.Foo) == EX.Foo |> IRI.new() |> IRI.parse() end test "with empty fragments" do @@ -354,7 +342,7 @@ defmodule RDF.IRITest do test "with IRI resolvable namespace terms" do assert IRI.to_string(EX.Foo) == "http://example.com/#Foo" - assert IRI.to_string(EX.foo) == "http://example.com/#foo" + assert IRI.to_string(EX.foo()) == "http://example.com/#foo" end test "with non-resolvable atoms" do @@ -369,5 +357,4 @@ defmodule RDF.IRITest do test "Inspect protocol implementation" do assert inspect(IRI.new("http://example.com/")) == "~I" end - end diff --git a/test/unit/list_test.exs b/test/unit/list_test.exs index 5c9a97a..272aa3f 100644 --- a/test/unit/list_test.exs +++ b/test/unit/list_test.exs @@ -9,152 +9,172 @@ defmodule RDF.ListTest do use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.org/#", - terms: [], strict: false + defvocab EX, base_iri: "http://example.org/#", terms: [], strict: false setup do {:ok, - empty: RDF.List.new(RDF.nil, Graph.new), - one: RDF.List.from([EX.element], head: ~B), - abc: RDF.List.from(~w[a b c], head: ~B), - ten: RDF.List.from(Enum.to_list(1..10), head: ~B), - nested: RDF.List.from(["foo", [1, 2], "bar"], head: ~B), - } + empty: RDF.List.new(RDF.nil(), Graph.new()), + one: RDF.List.from([EX.element()], head: ~B), + abc: RDF.List.from(~w[a b c], head: ~B), + ten: RDF.List.from(Enum.to_list(1..10), head: ~B), + nested: RDF.List.from(["foo", [1, 2], "bar"], head: ~B)} end - describe "new/2" do - ####################################################################### # success cases test "valid head list node" do - graph = Graph.new( - ~B - |> RDF.first(1) - |> RDF.rest(~B)) - |> Graph.add( - ~B - |> RDF.first(2) - |> RDF.rest(RDF.nil)) + graph = + Graph.new( + ~B + |> RDF.first(1) + |> RDF.rest(~B) + ) + |> Graph.add( + ~B + |> RDF.first(2) + |> RDF.rest(RDF.nil()) + ) + assert %RDF.List{} = list = RDF.List.new(~B, graph) assert list.head == ~B assert list.graph == graph end test "with non-blank list nodes" do - graph = Graph.new( - EX.Foo - |> RDF.first(1) - |> RDF.rest(RDF.nil)) + graph = + Graph.new( + EX.Foo + |> RDF.first(1) + |> RDF.rest(RDF.nil()) + ) + assert %RDF.List{} = list = RDF.List.new(EX.Foo, graph) assert list.head == iri(EX.Foo) end test "with other properties on its nodes" do - assert RDF.List.new(~B, + assert RDF.List.new( + ~B, Graph.new( - ~B - |> EX.other(EX.Property) - |> RDF.first(1) - |> RDF.rest(~B)) + ~B + |> EX.other(EX.Property) + |> RDF.first(1) + |> RDF.rest(~B) + ) |> Graph.add( - ~B - |> EX.other(EX.Property2) - |> RDF.first(2) - |> RDF.rest(RDF.nil)) + ~B + |> EX.other(EX.Property2) + |> RDF.first(2) + |> RDF.rest(RDF.nil()) + ) ) - |> RDF.List.valid? == true + |> RDF.List.valid?() == true end ####################################################################### # failure cases test "when given list node doesn't exist in the given graph" do - assert RDF.List.new(RDF.bnode, RDF.Graph.new) == nil + assert RDF.List.new(RDF.bnode(), RDF.Graph.new()) == nil end test "When the given head node is not a list" do - assert RDF.List.new(42, RDF.Graph.new) == nil - assert RDF.List.new(EX.Foo, RDF.Graph.new({EX.Foo, EX.bar, EX.Baz})) == nil - assert RDF.List.new(EX.Foo, RDF.Graph.new({EX.Foo, RDF.first, EX.Baz})) == nil + assert RDF.List.new(42, RDF.Graph.new()) == nil + assert RDF.List.new(EX.Foo, RDF.Graph.new({EX.Foo, EX.bar(), EX.Baz})) == nil + assert RDF.List.new(EX.Foo, RDF.Graph.new({EX.Foo, RDF.first(), EX.Baz})) == nil end - test "when list nodes are incomplete" do - assert RDF.List.new(EX.Foo, RDF.Graph.new({EX.Foo, RDF.first, EX.Baz})) == nil - assert RDF.List.new(EX.Foo, RDF.Graph.new({EX.Foo, RDF.rest, RDF.nil})) == nil + assert RDF.List.new(EX.Foo, RDF.Graph.new({EX.Foo, RDF.first(), EX.Baz})) == nil + assert RDF.List.new(EX.Foo, RDF.Graph.new({EX.Foo, RDF.rest(), RDF.nil()})) == nil end test "when head node has multiple rdf:first objects" do - assert RDF.List.new(~B, + assert RDF.List.new( + ~B, Graph.new( - ~B - |> RDF.first(1, 2) - |> RDF.rest(RDF.nil)) + ~B + |> RDF.first(1, 2) + |> RDF.rest(RDF.nil()) + ) ) == nil end test "when later list nodes have multiple rdf:first objects" do - assert RDF.List.new(~B, + assert RDF.List.new( + ~B, Graph.new( - ~B - |> RDF.first(1) - |> RDF.rest(~B)) + ~B + |> RDF.first(1) + |> RDF.rest(~B) + ) |> Graph.add( - ~B - |> RDF.first(2, 3) - |> RDF.rest(RDF.nil)) + ~B + |> RDF.first(2, 3) + |> RDF.rest(RDF.nil()) + ) ) == nil end test "when list nodes have multiple rdf:rest objects" do - assert RDF.List.new(~B, + assert RDF.List.new( + ~B, Graph.new( - ~B - |> RDF.first(1) - |> RDF.rest(~B, ~B)) + ~B + |> RDF.first(1) + |> RDF.rest(~B, ~B) + ) |> Graph.add( - ~B - |> RDF.first(2) - |> RDF.rest(RDF.nil)) + ~B + |> RDF.first(2) + |> RDF.rest(RDF.nil()) + ) |> Graph.add( - ~B - |> RDF.first(3) - |> RDF.rest(RDF.nil)) + ~B + |> RDF.first(3) + |> RDF.rest(RDF.nil()) + ) ) == nil - assert RDF.List.new(~B, + + assert RDF.List.new( + ~B, Graph.new( - ~B - |> RDF.first(1) - |> RDF.rest(~B)) + ~B + |> RDF.first(1) + |> RDF.rest(~B) + ) |> Graph.add( - ~B - |> RDF.first(2) - |> RDF.rest(RDF.nil, ~B)) + ~B + |> RDF.first(2) + |> RDF.rest(RDF.nil(), ~B) + ) |> Graph.add( - ~B - |> RDF.first(3) - |> RDF.rest(RDF.nil)) + ~B + |> RDF.first(3) + |> RDF.rest(RDF.nil()) + ) ) == nil end test "when the list is cyclic" do - assert RDF.List.new(~B, + assert RDF.List.new( + ~B, Graph.new( - ~B - |> RDF.first(1) - |> RDF.rest(~B)) + ~B + |> RDF.first(1) + |> RDF.rest(~B) + ) |> Graph.add( - ~B - |> RDF.first(2) - |> RDF.rest(~B)) + ~B + |> RDF.first(2) + |> RDF.rest(~B) + ) ) == nil end end - describe "from/1" do test "an empty list", %{empty: empty} do assert RDF.List.from([]) == empty @@ -165,85 +185,99 @@ defmodule RDF.ListTest do end %{ - "IRI" => iri(EX.Foo), + "IRI" => iri(EX.Foo), "blank node" => ~B, - "literal" => ~L, - "string" => "Foo", - "integer" => 42, - "float" => 3.14, - "true" => true, - "false" => false, - "unresolved namespace-qualified name" => EX.Foo, + "literal" => ~L, + "string" => "Foo", + "integer" => 42, + "float" => 3.14, + "true" => true, + "false" => false, + "unresolved namespace-qualified name" => EX.Foo } |> Enum.each(fn {type, element} -> - @tag element: element - test "list with #{type} element", %{element: element} do - with {bnode, graph_with_list} = one_element_list(element) do - assert RDF.List.from([element], head: bnode) == - RDF.List.new(bnode, graph_with_list) - end + @tag element: element + test "list with #{type} element", %{element: element} do + with {bnode, graph_with_list} = one_element_list(element) do + assert RDF.List.from([element], head: bnode) == + RDF.List.new(bnode, graph_with_list) end - end) + end + end) test "nested list" do - assert %RDF.List{head: bnode, graph: graph_with_list} = - RDF.List.from([[1]]) - assert [nested] = get_in(graph_with_list, [bnode, RDF.first]) - assert get_in(graph_with_list, [bnode, RDF.rest]) == [RDF.nil] - assert get_in(graph_with_list, [nested, RDF.first]) == [XSD.integer(1)] - assert get_in(graph_with_list, [nested, RDF.rest]) == [RDF.nil] + assert %RDF.List{head: bnode, graph: graph_with_list} = RDF.List.from([[1]]) + assert [nested] = get_in(graph_with_list, [bnode, RDF.first()]) + assert get_in(graph_with_list, [bnode, RDF.rest()]) == [RDF.nil()] + assert get_in(graph_with_list, [nested, RDF.first()]) == [XSD.integer(1)] + assert get_in(graph_with_list, [nested, RDF.rest()]) == [RDF.nil()] assert %RDF.List{head: bnode, graph: graph_with_list} = - RDF.List.from(["foo", [1, 2], "bar"]) - assert get_in(graph_with_list, [bnode, RDF.first]) == [~L"foo"] - assert [second] = get_in(graph_with_list, [bnode, RDF.rest]) - assert [nested] = get_in(graph_with_list, [second, RDF.first]) - assert get_in(graph_with_list, [nested, RDF.first]) == [XSD.integer(1)] - assert [nested_second] = get_in(graph_with_list, [nested, RDF.rest]) - assert get_in(graph_with_list, [nested_second, RDF.first]) == [XSD.integer(2)] - assert get_in(graph_with_list, [nested_second, RDF.rest]) == [RDF.nil] - assert [third] = get_in(graph_with_list, [second, RDF.rest]) - assert get_in(graph_with_list, [third, RDF.first]) == [~L"bar"] - assert get_in(graph_with_list, [third, RDF.rest]) == [RDF.nil] + RDF.List.from(["foo", [1, 2], "bar"]) + + assert get_in(graph_with_list, [bnode, RDF.first()]) == [~L"foo"] + assert [second] = get_in(graph_with_list, [bnode, RDF.rest()]) + assert [nested] = get_in(graph_with_list, [second, RDF.first()]) + assert get_in(graph_with_list, [nested, RDF.first()]) == [XSD.integer(1)] + assert [nested_second] = get_in(graph_with_list, [nested, RDF.rest()]) + assert get_in(graph_with_list, [nested_second, RDF.first()]) == [XSD.integer(2)] + assert get_in(graph_with_list, [nested_second, RDF.rest()]) == [RDF.nil()] + assert [third] = get_in(graph_with_list, [second, RDF.rest()]) + assert get_in(graph_with_list, [third, RDF.first()]) == [~L"bar"] + assert get_in(graph_with_list, [third, RDF.rest()]) == [RDF.nil()] end %{ - "preserve order" => [3, 2, 1], - "different types" => [1, "foo", true, false, 3.14, EX.foo, EX.Foo, ~B], + "preserve order" => [3, 2, 1], + "different types" => [1, "foo", true, false, 3.14, EX.foo(), EX.Foo, ~B] } |> Enum.each(fn {desc, list} -> - @tag list: list - test "list with multiple elements: #{desc}", %{list: list} do - assert %RDF.List{head: bnode, graph: graph_with_list} = - RDF.List.from(list) - assert RDF.nil == - Enum.reduce list, bnode, fn element, list_node -> - case element do - %IRI{} -> - assert get_in(graph_with_list, [list_node, RDF.first]) == [element] - %BlankNode{} -> - assert get_in(graph_with_list, [list_node, RDF.first]) == [element] - %Literal{} -> - assert get_in(graph_with_list, [list_node, RDF.first]) == [element] - element when is_boolean(element) -> - assert get_in(graph_with_list, [list_node, RDF.first]) == [RDF.Literal.new(element)] - element when is_atom(element) -> - assert get_in(graph_with_list, [list_node, RDF.first]) == [RDF.iri(element)] - _ -> - assert get_in(graph_with_list, [list_node, RDF.first]) == [RDF.Literal.new(element)] - end - [next] = get_in(graph_with_list, [list_node, RDF.rest]) - unless next == RDF.nil do - assert %BlankNode{} = next - end - next - end - end - end) + @tag list: list + test "list with multiple elements: #{desc}", %{list: list} do + assert %RDF.List{head: bnode, graph: graph_with_list} = RDF.List.from(list) + + assert RDF.nil() == + Enum.reduce(list, bnode, fn element, list_node -> + case element do + %IRI{} -> + assert get_in(graph_with_list, [list_node, RDF.first()]) == [element] + + %BlankNode{} -> + assert get_in(graph_with_list, [list_node, RDF.first()]) == [element] + + %Literal{} -> + assert get_in(graph_with_list, [list_node, RDF.first()]) == [element] + + element when is_boolean(element) -> + assert get_in(graph_with_list, [list_node, RDF.first()]) == [ + RDF.Literal.new(element) + ] + + element when is_atom(element) -> + assert get_in(graph_with_list, [list_node, RDF.first()]) == [ + RDF.iri(element) + ] + + _ -> + assert get_in(graph_with_list, [list_node, RDF.first()]) == [ + RDF.Literal.new(element) + ] + end + + [next] = get_in(graph_with_list, [list_node, RDF.rest()]) + + unless next == RDF.nil() do + assert %BlankNode{} = next + end + + next + end) + end + end) test "an enumerable" do assert RDF.List.from(MapSet.new([42]), head: ~B) == - RDF.List.from([42], head: ~B) + RDF.List.from([42], head: ~B) end test "head option with unresolved namespace-qualified name" do @@ -251,43 +285,42 @@ defmodule RDF.ListTest do end end - describe "values/1" do test "the empty list", %{empty: empty} do assert RDF.List.values(empty) == [] end test "list with one element", %{one: one} do - assert RDF.List.values(one) == [EX.element] + assert RDF.List.values(one) == [EX.element()] end test "list with multiple elements", %{abc: abc, ten: ten} do assert RDF.List.values(abc) == ~w[a b c] |> Enum.map(&Literal.new/1) - assert RDF.List.values(ten) == 1..10 |> Enum.to_list |> Enum.map(&Literal.new/1) + assert RDF.List.values(ten) == 1..10 |> Enum.to_list() |> Enum.map(&Literal.new/1) end test "list with non-blank list nodes" do - assert RDF.List.from([EX.element], head: EX.Foo) - |> RDF.List.values == [EX.element] + assert RDF.List.from([EX.element()], head: EX.Foo) + |> RDF.List.values() == [EX.element()] end test "nested list", %{nested: nested} do assert RDF.List.values(nested) == - [~L"foo", [XSD.integer(1), XSD.integer(2)], ~L"bar"] + [~L"foo", [XSD.integer(1), XSD.integer(2)], ~L"bar"] - assert RDF.list(["foo", [1, 2]]) |> RDF.List.values == - [~L"foo", [XSD.integer(1), XSD.integer(2)]] + assert RDF.list(["foo", [1, 2]]) |> RDF.List.values() == + [~L"foo", [XSD.integer(1), XSD.integer(2)]] - assert RDF.list([[1, 2], "foo"]) |> RDF.List.values == - [[XSD.integer(1), XSD.integer(2)], ~L"foo"] + assert RDF.list([[1, 2], "foo"]) |> RDF.List.values() == + [[XSD.integer(1), XSD.integer(2)], ~L"foo"] inner_list = RDF.list([1, 2], head: ~B) + assert RDF.list(["foo", ~B], graph: inner_list.graph) - |> RDF.List.values == [~L"foo", [XSD.integer(1), XSD.integer(2)]] + |> RDF.List.values() == [~L"foo", [XSD.integer(1), XSD.integer(2)]] end end - describe "nodes/1" do test "the empty list", %{empty: empty} do assert RDF.List.nodes(empty) == [] @@ -299,12 +332,12 @@ defmodule RDF.ListTest do test "nested list", %{nested: nested} do assert RDF.list([[1, 2, 3]], head: ~B) - |> RDF.List.nodes == [~B] + |> RDF.List.nodes() == [~B] + assert [~B, _, _] = RDF.List.nodes(nested) end end - describe "valid?/2" do test "the empty list", %{empty: empty} do assert RDF.List.valid?(empty) @@ -324,25 +357,27 @@ defmodule RDF.ListTest do end test "a non-blank list node is not valid" do - assert RDF.list([EX.element], head: EX.Foo) |> RDF.List.valid? == false + assert RDF.list([EX.element()], head: EX.Foo) |> RDF.List.valid?() == false end test "a non-blank list node on later nodes makes the whole list invalid" do - assert RDF.List.new(~B, + assert RDF.List.new( + ~B, Graph.new( - ~B - |> RDF.first(1) - |> RDF.rest(EX.Foo)) + ~B + |> RDF.first(1) + |> RDF.rest(EX.Foo) + ) |> Graph.add( - EX.Foo - |> RDF.first(2) - |> RDF.rest(RDF.nil)) + EX.Foo + |> RDF.first(2) + |> RDF.rest(RDF.nil()) + ) ) - |> RDF.List.valid? == false + |> RDF.List.valid?() == false end end - describe "node?" do test "the empty list", %{empty: empty} do assert RDF.List.node?(empty.head, empty.graph) == true @@ -362,33 +397,34 @@ defmodule RDF.ListTest do end test "unresolved namespace-qualified name" do - assert RDF.List.node?(EX.Foo, - RDF.List.from([EX.element], head: EX.Foo).graph) == true + assert RDF.List.node?( + EX.Foo, + RDF.List.from([EX.element()], head: EX.Foo).graph + ) == true end test "when given list node doesn't exist in the given graph" do - assert RDF.List.node?(RDF.bnode, RDF.Graph.new) == false + assert RDF.List.node?(RDF.bnode(), RDF.Graph.new()) == false end test "literal" do - assert RDF.List.node?(~L"Foo", RDF.Graph.new) == false - assert RDF.List.node?(42, RDF.Graph.new) == false - assert RDF.List.node?(true, RDF.Graph.new) == false - assert RDF.List.node?(false, RDF.Graph.new) == false - assert RDF.List.node?(nil, RDF.Graph.new) == false + assert RDF.List.node?(~L"Foo", RDF.Graph.new()) == false + assert RDF.List.node?(42, RDF.Graph.new()) == false + assert RDF.List.node?(true, RDF.Graph.new()) == false + assert RDF.List.node?(false, RDF.Graph.new()) == false + assert RDF.List.node?(nil, RDF.Graph.new()) == false end test "non-list node" do - assert RDF.List.node?(EX.Foo, RDF.Graph.new({EX.Foo, EX.bar, EX.Baz})) == false + assert RDF.List.node?(EX.Foo, RDF.Graph.new({EX.Foo, EX.bar(), EX.Baz})) == false end test "incomplete list nodes" do - assert RDF.List.node?(EX.Foo, RDF.Graph.new({EX.Foo, RDF.first, EX.Baz})) == false - assert RDF.List.node?(EX.Foo, RDF.Graph.new({EX.Foo, RDF.rest, RDF.nil})) == false + assert RDF.List.node?(EX.Foo, RDF.Graph.new({EX.Foo, RDF.first(), EX.Baz})) == false + assert RDF.List.node?(EX.Foo, RDF.Graph.new({EX.Foo, RDF.rest(), RDF.nil()})) == false end end - describe "Enumerable.reduce" do test "the empty list", %{empty: empty} do assert Enum.reduce(empty, [], fn description, acc -> [description | acc] end) == [] @@ -396,23 +432,19 @@ defmodule RDF.ListTest do test "a valid list", %{one: one} do assert [one.graph[one.head]] == - Enum.reduce(one, [], fn description, acc -> [description | acc] end) + Enum.reduce(one, [], fn description, acc -> [description | acc] end) end - end - defp one_element_list(element), - do: one_element_list(element, RDF.bnode) + do: one_element_list(element, RDF.bnode()) defp one_element_list(element, bnode) do {bnode, - Graph.new( - bnode - |> RDF.first(element) - |> RDF.rest(RDF.nil) - ) - } + Graph.new( + bnode + |> RDF.first(element) + |> RDF.rest(RDF.nil()) + )} end - end diff --git a/test/unit/literal/datatype/registry_test.exs b/test/unit/literal/datatype/registry_test.exs index b43801e..3b7c925 100644 --- a/test/unit/literal/datatype/registry_test.exs +++ b/test/unit/literal/datatype/registry_test.exs @@ -32,11 +32,12 @@ defmodule RDF.Literal.Datatype.RegistryTest do gMonth gMonthDay ] - |> Enum.map(fn xsd_datatype_name -> RDF.iri(NS.XSD.__base_iri__ <> xsd_datatype_name) end) + |> Enum.map(fn xsd_datatype_name -> + RDF.iri(NS.XSD.__base_iri__() <> xsd_datatype_name) + end) @supported_xsd_datatypes RDF.NS.XSD.__iris__() -- @unsupported_xsd_datatypes - describe "datatype/1" do test "builtin datatypes" do Enum.each(Datatype.Registry.builtin_datatypes(), fn datatype -> @@ -60,7 +61,7 @@ defmodule RDF.Literal.Datatype.RegistryTest do end test "with IRI of custom datatype" do - assert Age == Datatype.Registry.datatype(Age.id) + assert Age == Datatype.Registry.datatype(Age.id()) end test "with namespace terms" do @@ -72,7 +73,9 @@ defmodule RDF.Literal.Datatype.RegistryTest do assert XSD.Integer == Datatype.Registry.datatype(XSD.integer(42)) assert XSD.Byte == Datatype.Registry.datatype(XSD.byte(42)) assert RDF.LangString == Datatype.Registry.datatype(~L"foo"en) - assert RDF.Literal.Generic == Datatype.Registry.datatype(RDF.literal("foo", datatype: "http://example.com")) + + assert RDF.Literal.Generic == + Datatype.Registry.datatype(RDF.literal("foo", datatype: "http://example.com")) end end @@ -100,7 +103,6 @@ defmodule RDF.Literal.Datatype.RegistryTest do refute Datatype.Registry.xsd_datatype?(42) end - test "numeric_datatype?/1" do assert Datatype.Registry.numeric_datatype?(XSD.integer(42)) assert Datatype.Registry.numeric_datatype?(XSD.byte(42)) diff --git a/test/unit/literal_test.exs b/test/unit/literal_test.exs index 060288e..77b0ae2 100644 --- a/test/unit/literal_test.exs +++ b/test/unit/literal_test.exs @@ -12,29 +12,31 @@ defmodule RDF.LiteralTest do alias RDF.NS @examples %{ - XSD.String => ["foo"], + XSD.String => ["foo"], XSD.Integer => [42], - XSD.Double => [3.14], + XSD.Double => [3.14], XSD.Decimal => [Decimal.from_float(3.14)], - XSD.Boolean => [true, false], + XSD.Boolean => [true, false] } describe "new/1" do - Enum.each @examples, fn {datatype, example_values} -> + Enum.each(@examples, fn {datatype, example_values} -> @tag example: %{datatype: datatype, values: example_values} - test "coercion from #{datatype |> Module.split |> List.last |> to_string}", %{example: example} do - Enum.each example.values, fn example_value -> + test "coercion from #{datatype |> Module.split() |> List.last() |> to_string}", %{ + example: example + } do + Enum.each(example.values, fn example_value -> assert Literal.new(example_value) == example.datatype.new(example_value) assert Literal.new!(example_value) == example.datatype.new!(example_value) - end + end) end - end + end) test "with builtin datatype literals" do - Enum.each Datatype.Registry.builtin_datatypes(), fn datatype -> + Enum.each(Datatype.Registry.builtin_datatypes(), fn datatype -> datatype_literal = datatype.new("foo").literal assert %Literal{literal: ^datatype_literal} = Literal.new(datatype_literal) - end + end) end test "with custom datatype literals" do @@ -44,44 +46,45 @@ defmodule RDF.LiteralTest do test "when options without datatype given" do assert Literal.new(true, []) == XSD.Boolean.new(true) - assert Literal.new(42, []) == XSD.Integer.new(42) + assert Literal.new(42, []) == XSD.Integer.new(42) assert Literal.new!(true, []) == XSD.Boolean.new!(true) - assert Literal.new!(42, []) == XSD.Integer.new!(42) + assert Literal.new!(42, []) == XSD.Integer.new!(42) end end describe "typed construction" do test "boolean" do - assert Literal.new(true, datatype: NS.XSD.boolean) == XSD.Boolean.new(true) - assert Literal.new(false, datatype: NS.XSD.boolean) == XSD.Boolean.new(false) - assert Literal.new("true", datatype: NS.XSD.boolean) == XSD.Boolean.new("true") - assert Literal.new("false", datatype: NS.XSD.boolean) == XSD.Boolean.new("false") + assert Literal.new(true, datatype: NS.XSD.boolean()) == XSD.Boolean.new(true) + assert Literal.new(false, datatype: NS.XSD.boolean()) == XSD.Boolean.new(false) + assert Literal.new("true", datatype: NS.XSD.boolean()) == XSD.Boolean.new("true") + assert Literal.new("false", datatype: NS.XSD.boolean()) == XSD.Boolean.new("false") end test "integer" do - assert Literal.new(42, datatype: NS.XSD.integer) == XSD.Integer.new(42) - assert Literal.new("42", datatype: NS.XSD.integer) == XSD.Integer.new("42") + assert Literal.new(42, datatype: NS.XSD.integer()) == XSD.Integer.new(42) + assert Literal.new("42", datatype: NS.XSD.integer()) == XSD.Integer.new("42") end test "double" do - assert Literal.new(3.14, datatype: NS.XSD.double) == XSD.Double.new(3.14) - assert Literal.new("3.14", datatype: NS.XSD.double) == XSD.Double.new("3.14") + assert Literal.new(3.14, datatype: NS.XSD.double()) == XSD.Double.new(3.14) + assert Literal.new("3.14", datatype: NS.XSD.double()) == XSD.Double.new("3.14") end test "decimal" do - assert Literal.new(3.14, datatype: NS.XSD.decimal) == XSD.Decimal.new(3.14) - assert Literal.new("3.14", datatype: NS.XSD.decimal) == XSD.Decimal.new("3.14") - assert Literal.new(Decimal.from_float(3.14), datatype: NS.XSD.decimal) == + assert Literal.new(3.14, datatype: NS.XSD.decimal()) == XSD.Decimal.new(3.14) + assert Literal.new("3.14", datatype: NS.XSD.decimal()) == XSD.Decimal.new("3.14") + + assert Literal.new(Decimal.from_float(3.14), datatype: NS.XSD.decimal()) == XSD.Decimal.new(Decimal.from_float(3.14)) end test "unsignedInt" do - assert Literal.new(42, datatype: NS.XSD.unsignedInt) == XSD.UnsignedInt.new(42) - assert Literal.new("42", datatype: NS.XSD.unsignedInt) == XSD.UnsignedInt.new("42") + assert Literal.new(42, datatype: NS.XSD.unsignedInt()) == XSD.UnsignedInt.new(42) + assert Literal.new("42", datatype: NS.XSD.unsignedInt()) == XSD.UnsignedInt.new("42") end test "string" do - assert Literal.new("foo", datatype: NS.XSD.string) == XSD.String.new("foo") + assert Literal.new("foo", datatype: NS.XSD.string()) == XSD.String.new("foo") end test "registered custom datatype" do @@ -106,17 +109,19 @@ defmodule RDF.LiteralTest do end test "construction of an other than rdf:langString typed and language-tagged literal fails" do - assert Literal.new("Eule", datatype: RDF.langString, language: "de") == + assert Literal.new("Eule", datatype: RDF.langString(), language: "de") == LangString.new("Eule", language: "de") + assert_raise ArgumentError, fn -> - Literal.new("Eule", datatype: NS.XSD.string, language: "de") + Literal.new("Eule", datatype: NS.XSD.string(), language: "de") end end test "construction of a rdf:langString works, but results in an invalid literal" do - assert Literal.new("Eule", datatype: RDF.langString) == LangString.new("Eule", []) + assert Literal.new("Eule", datatype: RDF.langString()) == LangString.new("Eule", []) + assert_raise RDF.Literal.InvalidError, fn -> - Literal.new!("Eule", datatype: RDF.langString) + Literal.new!("Eule", datatype: RDF.langString()) end end end @@ -197,7 +202,10 @@ defmodule RDF.LiteralTest do assert ~L"foo"en |> Literal.is_a?(RDF.LangString) assert XSD.integer(42) |> Literal.is_a?(XSD.Integer) assert XSD.byte(42) |> Literal.is_a?(XSD.Integer) - assert RDF.literal("foo", datatype: "http://example.com/dt") |> RDF.Literal.is_a?(RDF.Literal.Generic) + + assert RDF.literal("foo", datatype: "http://example.com/dt") + |> RDF.Literal.is_a?(RDF.Literal.Generic) + refute XSD.float(3.14) |> Literal.is_a?(XSD.Integer) end @@ -230,91 +238,94 @@ defmodule RDF.LiteralTest do end describe "has_datatype?" do - Enum.each literals(~W[all_simple all_plain_lang]a), fn literal -> + Enum.each(literals(~W[all_simple all_plain_lang]a), fn literal -> @tag literal: literal - test "#{inspect literal} has no datatype", %{literal: literal} do + test "#{inspect(literal)} has no datatype", %{literal: literal} do refute Literal.has_datatype?(literal) end - end + end) - Enum.each literals(:all) -- literals(~W[all_simple all_plain_lang]a), fn literal -> + Enum.each(literals(:all) -- literals(~W[all_simple all_plain_lang]a), fn literal -> @tag literal: literal - test "Literal for #{inspect literal} has a datatype", %{literal: literal} do + test "Literal for #{inspect(literal)} has a datatype", %{literal: literal} do assert Literal.has_datatype?(literal) end - end + end) end describe "plain?" do - Enum.each literals(:all_plain), fn literal -> + Enum.each(literals(:all_plain), fn literal -> @tag literal: literal - test "#{inspect literal} is plain", %{literal: literal} do + test "#{inspect(literal)} is plain", %{literal: literal} do assert Literal.plain?(literal) end - end - Enum.each literals(:all) -- literals(:all_plain), fn literal -> + end) + + Enum.each(literals(:all) -- literals(:all_plain), fn literal -> @tag literal: literal - test "Literal for #{inspect literal} is not plain", %{literal: literal} do + test "Literal for #{inspect(literal)} is not plain", %{literal: literal} do refute Literal.plain?(literal) end - end + end) end describe "simple?" do - Enum.each literals(:all_simple), fn literal -> + Enum.each(literals(:all_simple), fn literal -> @tag literal: literal - test "#{inspect literal} is simple", %{literal: literal} do + test "#{inspect(literal)} is simple", %{literal: literal} do assert Literal.simple?(literal) end - end - Enum.each literals(:all) -- literals(:all_simple), fn literal -> + end) + + Enum.each(literals(:all) -- literals(:all_simple), fn literal -> @tag literal: literal - test "Literal for #{inspect literal} is not simple", %{literal: literal} do + test "Literal for #{inspect(literal)} is not simple", %{literal: literal} do refute Literal.simple?(literal) end - end + end) end describe "datatype_id/1" do - Enum.each literals(:all_simple), fn literal -> + Enum.each(literals(:all_simple), fn literal -> @tag literal: literal - test "simple literal #{inspect literal} has datatype xsd:string", %{literal: literal} do - assert Literal.datatype_id(literal) == NS.XSD.string + test "simple literal #{inspect(literal)} has datatype xsd:string", %{literal: literal} do + assert Literal.datatype_id(literal) == NS.XSD.string() end - end + end) %{ - 123 => "integer", - true => "boolean", - false => "boolean", - 9223372036854775807 => "integer", - 3.1415 => "double", - ~D[2017-04-13] => "date", - ~N[2017-04-14 15:32:07] => "dateTime", - ~T[01:02:03] => "time" + 123 => "integer", + true => "boolean", + false => "boolean", + 9_223_372_036_854_775_807 => "integer", + 3.1415 => "double", + ~D[2017-04-13] => "date", + ~N[2017-04-14 15:32:07] => "dateTime", + ~T[01:02:03] => "time" } |> Enum.each(fn {value, type} -> - @tag data: %{literal: literal = Literal.new(value), type: type} - test "Literal for #{inspect literal} has datatype xsd:#{type}", - %{data: %{literal: literal, type: type}} do - assert Literal.datatype_id(literal) == apply(NS.XSD, String.to_atom(type), []) - end - end) + @tag data: %{literal: literal = Literal.new(value), type: type} + test "Literal for #{inspect(literal)} has datatype xsd:#{type}", + %{data: %{literal: literal, type: type}} do + assert Literal.datatype_id(literal) == apply(NS.XSD, String.to_atom(type), []) + end + end) end describe "language" do - Enum.each literals(:all_plain_lang), fn literal -> + Enum.each(literals(:all_plain_lang), fn literal -> @tag literal: literal - test "#{inspect literal} has correct language", %{literal: literal} do + test "#{inspect(literal)} has correct language", %{literal: literal} do assert Literal.language(literal) == "en" end - end - Enum.each literals(:all) -- literals(:all_plain_lang), fn literal -> + end) + + Enum.each(literals(:all) -- literals(:all_plain_lang), fn literal -> @tag literal: literal - test "Literal for #{inspect literal} has no language", %{literal: literal} do + test "Literal for #{inspect(literal)} has no language", %{literal: literal} do assert is_nil(Literal.language(literal)) end - end + end) test "with RDF.LangString literal" do assert Literal.new("Upper", language: "en") |> Literal.language() == "en" @@ -358,15 +369,17 @@ defmodule RDF.LiteralTest do test "with XSD.Datatype literal" do [ XSD.String.new("foo"), - XSD.Byte.new(42), - + XSD.Byte.new(42) ] |> Enum.each(fn canonical_literal -> assert Literal.canonical(canonical_literal) == canonical_literal end) + assert XSD.Integer.new("042") |> Literal.canonical() == Literal.new(42) - assert Literal.new(3.14) |> Literal.canonical() == Literal.new(3.14) |> XSD.Double.canonical() + + assert Literal.new(3.14) |> Literal.canonical() == + Literal.new(3.14) |> XSD.Double.canonical() end test "with RDF.LangString literal" do @@ -425,16 +438,24 @@ defmodule RDF.LiteralTest do end test "with RDF.LangString literal" do - assert Literal.equal_value?(Literal.new("foo", language: "en"), - Literal.new("foo", language: "en")) == true + assert Literal.equal_value?( + Literal.new("foo", language: "en"), + Literal.new("foo", language: "en") + ) == true + assert Literal.equal_value?(Literal.new("foo", language: "en"), Literal.new("foo")) == nil end test "with generic literal" do - assert Literal.equal_value?(Literal.new("foo", datatype: "http://example.com/dt"), - Literal.new("foo", datatype: "http://example.com/dt")) == true - assert Literal.equal_value?(Literal.new("foo", datatype: "http://example.com/dt"), - Literal.new("foo")) == nil + assert Literal.equal_value?( + Literal.new("foo", datatype: "http://example.com/dt"), + Literal.new("foo", datatype: "http://example.com/dt") + ) == true + + assert Literal.equal_value?( + Literal.new("foo", datatype: "http://example.com/dt"), + Literal.new("foo") + ) == nil end end @@ -445,57 +466,62 @@ defmodule RDF.LiteralTest do end test "with RDF.LangString literal" do - assert Literal.compare(Literal.new("foo", language: "en"), - Literal.new("bar", language: "en")) == :gt + assert Literal.compare( + Literal.new("foo", language: "en"), + Literal.new("bar", language: "en") + ) == :gt end test "with generic literal" do - assert Literal.compare(Literal.new("foo", datatype: "http://example.com/dt"), - Literal.new("bar", datatype: "http://example.com/dt")) == :gt + assert Literal.compare( + Literal.new("foo", datatype: "http://example.com/dt"), + Literal.new("bar", datatype: "http://example.com/dt") + ) == :gt end end - @poem XSD.String.new """ - - Kaum hat dies der Hahn gesehen, - Fängt er auch schon an zu krähen: - Kikeriki! Kikikerikih!! - Tak, tak, tak! - da kommen sie. - - """ + @poem XSD.String.new(""" + + Kaum hat dies der Hahn gesehen, + Fängt er auch schon an zu krähen: + Kikeriki! Kikikerikih!! + Tak, tak, tak! - da kommen sie. + + """) describe "matches?" do test "without flags" do [ - {~L"abracadabra", ~L"bra", true}, + {~L"abracadabra", ~L"bra", true}, {~L"abracadabra", ~L"^a.*a$", true}, - {~L"abracadabra", ~L"^bra", false}, - {@poem, ~L"Kaum.*krähen", false}, + {~L"abracadabra", ~L"^bra", false}, + {@poem, ~L"Kaum.*krähen", false}, {@poem, ~L"^Kaum.*gesehen,$", false}, - {~L"foobar", ~L"foo$", false}, - + {~L"foobar", ~L"foo$", false}, {~L"noe\u0308l", ~L"noe\\u0308l", true}, {~L"noe\\u0308l", ~L"noe\\\\u0308l", true}, {~L"\u{01D4B8}", ~L"\\U0001D4B8", true}, {~L"\\U0001D4B8", ~L"\\\U0001D4B8", true}, - {~L"abracadabra"en, ~L"bra", true}, - {"abracadabra", "bra", true}, - {XSD.Integer.new("42"), ~L"4", true}, - {XSD.Integer.new("42"), ~L"en", false}, + {"abracadabra", "bra", true}, + {XSD.Integer.new("42"), ~L"4", true}, + {XSD.Integer.new("42"), ~L"en", false} ] |> Enum.each(fn {literal, pattern, expected_result} -> result = Literal.matches?(literal, pattern) + assert result == expected_result, - "expected RDF.Literal.matches?(#{inspect literal}, #{inspect pattern}) to return #{inspect expected_result}, but got #{result}" + "expected RDF.Literal.matches?(#{inspect(literal)}, #{inspect(pattern)}) to return #{ + inspect(expected_result) + }, but got #{result}" end) end test "with flags" do [ - {@poem, ~L"Kaum.*krähen", ~L"s", true}, + {@poem, ~L"Kaum.*krähen", ~L"s", true}, {@poem, ~L"^Kaum.*gesehen,$", ~L"m", true}, - {@poem, ~L"kiki", ~L"i", true}, + {@poem, ~L"kiki", ~L"i", true} ] |> Enum.each(fn {literal, pattern, flags, result} -> assert Literal.matches?(literal, pattern, flags) == result @@ -504,13 +530,13 @@ defmodule RDF.LiteralTest do test "with q flag" do [ - {~L"abcd", ~L".*", ~L"q", false}, + {~L"abcd", ~L".*", ~L"q", false}, {~L"Mr. B. Obama", ~L"B. OBAMA", ~L"iq", true}, # If the q flag is used together with the m, s, or x flag, that flag has no effect. - {~L"abcd", ~L".*", ~L"mq", true}, - {~L"abcd", ~L".*", ~L"qim", true}, - {~L"abcd", ~L".*", ~L"xqm", true}, + {~L"abcd", ~L".*", ~L"mq", true}, + {~L"abcd", ~L".*", ~L"qim", true}, + {~L"abcd", ~L".*", ~L"xqm", true} ] |> Enum.each(fn {literal, pattern, flags, result} -> assert Literal.matches?(literal, pattern, flags) == result @@ -523,10 +549,13 @@ defmodule RDF.LiteralTest do assert XSD.string("foo") |> Literal.update(fn s when is_binary(s) -> s <> "bar" end) == XSD.string("foobar") + assert XSD.integer(1) |> Literal.update(fn i when is_integer(i) -> i + 1 end) == XSD.integer(2) + assert XSD.byte(42) |> Literal.update(fn i when is_integer(i) -> i + 1 end) == XSD.byte(43) + assert XSD.integer(1) |> Literal.update(fn i when is_integer(i) -> "0" <> to_string(i) end) == XSD.integer("01") @@ -546,7 +575,7 @@ defmodule RDF.LiteralTest do test "with as: :lexical opt it passes the lexical form" do assert XSD.integer(1) - |> Literal.update(fn i when is_binary(i) -> "0" <> i end, as: :lexical) == + |> Literal.update(fn i when is_binary(i) -> "0" <> i end, as: :lexical) == XSD.integer("01") end end diff --git a/test/unit/namespace_test.exs b/test/unit/namespace_test.exs index bf8583a..ada595b 100644 --- a/test/unit/namespace_test.exs +++ b/test/unit/namespace_test.exs @@ -2,5 +2,4 @@ defmodule RDF.NamespaceTest do use ExUnit.Case doctest RDF.Namespace - end diff --git a/test/unit/nquads_decoder_test.exs b/test/unit/nquads_decoder_test.exs index 85b1ec7..801635c 100644 --- a/test/unit/nquads_decoder_test.exs +++ b/test/unit/nquads_decoder_test.exs @@ -7,148 +7,164 @@ defmodule RDF.NQuads.DecoderTest do import RDF.Sigils - use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.org/#", - terms: [], strict: false - - defvocab P, - base_iri: "http://www.perceive.net/schemas/relationship/", - terms: [], strict: false + defvocab EX, base_iri: "http://example.org/#", terms: [], strict: false + defvocab P, base_iri: "http://www.perceive.net/schemas/relationship/", terms: [], strict: false test "an empty string is deserialized to an empty graph" do - assert RDF.NQuads.Decoder.decode!("") == Dataset.new - assert RDF.NQuads.Decoder.decode!(" \n\r\r\n ") == Dataset.new + assert RDF.NQuads.Decoder.decode!("") == Dataset.new() + assert RDF.NQuads.Decoder.decode!(" \n\r\r\n ") == Dataset.new() end test "decoding comments" do - assert RDF.NQuads.Decoder.decode!("# just a comment") == Dataset.new + assert RDF.NQuads.Decoder.decode!("# just a comment") == Dataset.new() assert RDF.NQuads.Decoder.decode!(""" - _:1 . # a comment - """) == Dataset.new({EX.S, EX.p, RDF.bnode("1"), EX.G}) + _:1 . # a comment + """) == Dataset.new({EX.S, EX.p(), RDF.bnode("1"), EX.G}) assert RDF.NQuads.Decoder.decode!(""" - # a comment - . - """) == Dataset.new({EX.S, EX.p, EX.O, EX.G}) + # a comment + . + """) == Dataset.new({EX.S, EX.p(), EX.O, EX.G}) assert RDF.NQuads.Decoder.decode!(""" - . - # a comment - """) == Dataset.new({EX.S, EX.p, EX.O, EX.G}) + . + # a comment + """) == Dataset.new({EX.S, EX.p(), EX.O, EX.G}) assert RDF.NQuads.Decoder.decode!(""" - # Header line 1 - # Header line 2 - . - # 1st comment - . # 2nd comment - # last comment - """) == Dataset.new([ - {EX.S1, EX.p1, EX.O1, EX.G}, - {EX.S1, EX.p2, EX.O2}, - ]) + # Header line 1 + # Header line 2 + . + # 1st comment + . # 2nd comment + # last comment + """) == + Dataset.new([ + {EX.S1, EX.p1(), EX.O1, EX.G}, + {EX.S1, EX.p2(), EX.O2} + ]) end test "empty lines" do assert RDF.NQuads.Decoder.decode!(""" - . - """) == Dataset.new({EX.spiderman, P.enemyOf, EX.green_goblin, ~I}) + . + """) == + Dataset.new( + {EX.spiderman(), P.enemyOf(), EX.green_goblin(), + ~I} + ) assert RDF.NQuads.Decoder.decode!(""" - . + . - """) == Dataset.new({EX.spiderman, P.enemyOf, EX.green_goblin, ~I}) + """) == + Dataset.new( + {EX.spiderman(), P.enemyOf(), EX.green_goblin(), + ~I} + ) assert RDF.NQuads.Decoder.decode!(""" - . + . - . + . - """) == Dataset.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p2, EX.O2, EX.G}, - ]) + """) == + Dataset.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p2(), EX.O2, EX.G} + ]) end test "decoding a single statement with iris" do assert RDF.NQuads.Decoder.decode!(""" - . - """) == Dataset.new({EX.spiderman, P.enemyOf, EX.green_goblin}) + . + """) == Dataset.new({EX.spiderman(), P.enemyOf(), EX.green_goblin()}) assert RDF.NQuads.Decoder.decode!(""" - . - """) == Dataset.new({EX.spiderman, P.enemyOf, EX.green_goblin, ~I}) + . + """) == + Dataset.new( + {EX.spiderman(), P.enemyOf(), EX.green_goblin(), + ~I} + ) end test "decoding a single statement with a blank node" do assert RDF.NQuads.Decoder.decode!(""" - _:foo . - """) == Dataset.new({RDF.bnode("foo"), EX.p, EX.O, EX.G}) + _:foo . + """) == Dataset.new({RDF.bnode("foo"), EX.p(), EX.O, EX.G}) + assert RDF.NQuads.Decoder.decode!(""" - _:1 . - """) == Dataset.new({EX.S, EX.p, RDF.bnode("1"), EX.G}) + _:1 . + """) == Dataset.new({EX.S, EX.p(), RDF.bnode("1"), EX.G}) + assert RDF.NQuads.Decoder.decode!(""" - _:foo _:bar . - """) == Dataset.new({RDF.bnode("foo"), EX.p, RDF.bnode("bar"), EX.G}) + _:foo _:bar . + """) == Dataset.new({RDF.bnode("foo"), EX.p(), RDF.bnode("bar"), EX.G}) + assert RDF.NQuads.Decoder.decode!(""" - _:1 _:G . - """) == Dataset.new({EX.S, EX.p, RDF.bnode("1"), RDF.bnode("G")}) + _:1 _:G . + """) == Dataset.new({EX.S, EX.p(), RDF.bnode("1"), RDF.bnode("G")}) end test "decoding a single statement with an untyped string literal" do assert RDF.NQuads.Decoder.decode!(""" - "Peter Parker" . - """) == Dataset.new({EX.spiderman, P.realname, RDF.literal("Peter Parker"), EX.G}) + "Peter Parker" . + """) == Dataset.new({EX.spiderman(), P.realname(), RDF.literal("Peter Parker"), EX.G}) + assert RDF.NQuads.Decoder.decode!(""" - "Peter Parker" . - """) == Dataset.new({EX.spiderman, P.realname, RDF.literal("Peter Parker")}) + "Peter Parker" . + """) == Dataset.new({EX.spiderman(), P.realname(), RDF.literal("Peter Parker")}) end test "decoding a single statement with a typed literal" do assert RDF.NQuads.Decoder.decode!(""" - "42"^^ . - """) == Dataset.new({EX.spiderman, EX.p, RDF.literal(42), EX.G}) + "42"^^ . + """) == Dataset.new({EX.spiderman(), EX.p(), RDF.literal(42), EX.G}) + assert RDF.NQuads.Decoder.decode!(""" - "42"^^ . - """) == Dataset.new({EX.spiderman, EX.p, RDF.literal(42)}) + "42"^^ . + """) == Dataset.new({EX.spiderman(), EX.p(), RDF.literal(42)}) end test "decoding a single statement with a language tagged literal" do assert RDF.NQuads.Decoder.decode!(""" - "foo"@en . - """) == Dataset.new({EX.S, EX.p, RDF.literal("foo", language: "en"), EX.G}) + "foo"@en . + """) == Dataset.new({EX.S, EX.p(), RDF.literal("foo", language: "en"), EX.G}) + assert RDF.NQuads.Decoder.decode!(""" - "foo"@en . - """) == Dataset.new({EX.S, EX.p, RDF.literal("foo", language: "en")}) + "foo"@en . + """) == Dataset.new({EX.S, EX.p(), RDF.literal("foo", language: "en")}) end test "decoding multiple statements" do assert RDF.NQuads.Decoder.decode!(""" - . - . - """) == Dataset.new([ - {EX.S1, EX.p1, EX.O1, EX.G}, - {EX.S1, EX.p2, EX.O2, EX.G}, - ]) - assert RDF.NQuads.Decoder.decode!(""" - . - . - . - . - """) == Dataset.new([ - {EX.S1, EX.p1, EX.O1, EX.G}, - {EX.S1, EX.p2, EX.O2, EX.G}, - {EX.S2, EX.p3, EX.O3, EX.G}, - {EX.S2, EX.p3, EX.O3} - ]) - end + . + . + """) == + Dataset.new([ + {EX.S1, EX.p1(), EX.O1, EX.G}, + {EX.S1, EX.p2(), EX.O2, EX.G} + ]) + assert RDF.NQuads.Decoder.decode!(""" + . + . + . + . + """) == + Dataset.new([ + {EX.S1, EX.p1(), EX.O1, EX.G}, + {EX.S1, EX.p2(), EX.O2, EX.G}, + {EX.S2, EX.p3(), EX.O3, EX.G}, + {EX.S2, EX.p3(), EX.O3} + ]) + end end diff --git a/test/unit/nquads_encoder_test.exs b/test/unit/nquads_encoder_test.exs index b308ae2..603f46f 100644 --- a/test/unit/nquads_encoder_test.exs +++ b/test/unit/nquads_encoder_test.exs @@ -12,107 +12,115 @@ defmodule RDF.NQuads.EncoderTest do use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.org/#", - terms: [], strict: false - + defvocab EX, base_iri: "http://example.org/#", terms: [], strict: false describe "serializing a graph" do test "an empty graph is serialized to an empty string" do - assert NQuads.Encoder.encode!(Graph.new) == "" + assert NQuads.Encoder.encode!(Graph.new()) == "" end test "statements with IRIs only" do - assert NQuads.Encoder.encode!(Graph.new [ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p1, EX.O2}, - {EX.S1, EX.p2, EX.O3}, - {EX.S2, EX.p3, EX.O4}, - ]) == - """ - . - . - . - . - """ + assert NQuads.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p1(), EX.O2}, + {EX.S1, EX.p2(), EX.O3}, + {EX.S2, EX.p3(), EX.O4} + ]) + ) == + """ + . + . + . + . + """ end test "statements with literals" do - assert NQuads.Encoder.encode!(Graph.new [ - {EX.S1, EX.p1, ~L"foo"}, - {EX.S1, EX.p1, ~L"foo"en}, - {EX.S1, EX.p2, 42}, - {EX.S2, EX.p3, RDF.literal("strange things", datatype: EX.custom)}, - ]) == - """ - "foo"@en . - "foo" . - "42"^^<#{XSD.integer}> . - "strange things"^^<#{EX.custom}> . - """ + assert NQuads.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), ~L"foo"}, + {EX.S1, EX.p1(), ~L"foo"en}, + {EX.S1, EX.p2(), 42}, + {EX.S2, EX.p3(), RDF.literal("strange things", datatype: EX.custom())} + ]) + ) == + """ + "foo"@en . + "foo" . + "42"^^<#{XSD.integer()}> . + "strange things"^^<#{EX.custom()}> . + """ end test "statements with blank nodes" do - assert NQuads.Encoder.encode!(Graph.new [ - {EX.S1, EX.p1, RDF.bnode(1)}, - {EX.S1, EX.p1, RDF.bnode("foo")}, - {EX.S1, EX.p1, RDF.bnode(:bar)}, - ]) == - """ - _:1 . - _:bar . - _:foo . - """ + assert NQuads.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), RDF.bnode(1)}, + {EX.S1, EX.p1(), RDF.bnode("foo")}, + {EX.S1, EX.p1(), RDF.bnode(:bar)} + ]) + ) == + """ + _:1 . + _:bar . + _:foo . + """ end end describe "serializing a dataset" do test "an empty dataset is serialized to an empty string" do - assert NQuads.Encoder.encode!(Dataset.new) == "" + assert NQuads.Encoder.encode!(Dataset.new()) == "" end test "statements with IRIs only" do - assert NQuads.Encoder.encode!(Dataset.new [ - {EX.S1, EX.p1, EX.O1, EX.G}, - {EX.S1, EX.p1, EX.O2, EX.G}, - {EX.S1, EX.p2, EX.O3, EX.G}, - {EX.S2, EX.p3, EX.O4}, - ]) == - """ - . - . - . - . - """ + assert NQuads.Encoder.encode!( + Dataset.new([ + {EX.S1, EX.p1(), EX.O1, EX.G}, + {EX.S1, EX.p1(), EX.O2, EX.G}, + {EX.S1, EX.p2(), EX.O3, EX.G}, + {EX.S2, EX.p3(), EX.O4} + ]) + ) == + """ + . + . + . + . + """ end test "statements with literals" do - assert NQuads.Encoder.encode!(Dataset.new [ - {EX.S1, EX.p1, ~L"foo", EX.G1}, - {EX.S1, EX.p1, ~L"foo"en, EX.G2}, - {EX.S1, EX.p2, 42, EX.G3}, - {EX.S2, EX.p3, RDF.literal("strange things", datatype: EX.custom), EX.G3}, - ]) == - """ - "foo" . - "foo"@en . - "42"^^<#{XSD.integer}> . - "strange things"^^<#{EX.custom}> . - """ + assert NQuads.Encoder.encode!( + Dataset.new([ + {EX.S1, EX.p1(), ~L"foo", EX.G1}, + {EX.S1, EX.p1(), ~L"foo"en, EX.G2}, + {EX.S1, EX.p2(), 42, EX.G3}, + {EX.S2, EX.p3(), RDF.literal("strange things", datatype: EX.custom()), EX.G3} + ]) + ) == + """ + "foo" . + "foo"@en . + "42"^^<#{XSD.integer()}> . + "strange things"^^<#{EX.custom()}> . + """ end test "statements with blank nodes" do - assert NQuads.Encoder.encode!(Dataset.new [ - {EX.S1, EX.p1, RDF.bnode(1)}, - {EX.S1, EX.p1, RDF.bnode("foo"), EX.G}, - {EX.S1, EX.p1, RDF.bnode(:bar)}, - ]) == - """ - _:1 . - _:bar . - _:foo . - """ + assert NQuads.Encoder.encode!( + Dataset.new([ + {EX.S1, EX.p1(), RDF.bnode(1)}, + {EX.S1, EX.p1(), RDF.bnode("foo"), EX.G}, + {EX.S1, EX.p1(), RDF.bnode(:bar)} + ]) + ) == + """ + _:1 . + _:bar . + _:foo . + """ end end - end diff --git a/test/unit/ntriples_decoder_test.exs b/test/unit/ntriples_decoder_test.exs index cf7c918..d5e75a1 100644 --- a/test/unit/ntriples_decoder_test.exs +++ b/test/unit/ntriples_decoder_test.exs @@ -5,130 +5,130 @@ defmodule RDF.NTriples.DecoderTest do alias RDF.Graph - use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.org/#", - terms: [], strict: false - - defvocab P, - base_iri: "http://www.perceive.net/schemas/relationship/", - terms: [], strict: false + defvocab EX, base_iri: "http://example.org/#", terms: [], strict: false + defvocab P, base_iri: "http://www.perceive.net/schemas/relationship/", terms: [], strict: false test "an empty string is deserialized to an empty graph" do - assert RDF.NTriples.Decoder.decode!("") == Graph.new - assert RDF.NTriples.Decoder.decode!(" \n\r\r\n ") == Graph.new + assert RDF.NTriples.Decoder.decode!("") == Graph.new() + assert RDF.NTriples.Decoder.decode!(" \n\r\r\n ") == Graph.new() end test "decoding comments" do - assert RDF.NTriples.Decoder.decode!("# just a comment") == Graph.new + assert RDF.NTriples.Decoder.decode!("# just a comment") == Graph.new() assert RDF.NTriples.Decoder.decode!(""" - _:1 . # a comment - """) == Graph.new({EX.S, EX.p, RDF.bnode("1")}) + _:1 . # a comment + """) == Graph.new({EX.S, EX.p(), RDF.bnode("1")}) assert RDF.NTriples.Decoder.decode!(""" - # a comment - . - """) == Graph.new({EX.S, EX.p, EX.O}) + # a comment + . + """) == Graph.new({EX.S, EX.p(), EX.O}) assert RDF.NTriples.Decoder.decode!(""" - . - # a comment - """) == Graph.new({EX.S, EX.p, EX.O}) + . + # a comment + """) == Graph.new({EX.S, EX.p(), EX.O}) assert RDF.NTriples.Decoder.decode!(""" - # Header line 1 - # Header line 2 - . - # 1st comment - . # 2nd comment - # last comment - """) == Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p2, EX.O2}, - ]) + # Header line 1 + # Header line 2 + . + # 1st comment + . # 2nd comment + # last comment + """) == + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p2(), EX.O2} + ]) end test "empty lines" do assert RDF.NTriples.Decoder.decode!(""" - . - """) == Graph.new({EX.spiderman, P.enemyOf, EX.green_goblin}) + . + """) == Graph.new({EX.spiderman(), P.enemyOf(), EX.green_goblin()}) assert RDF.NTriples.Decoder.decode!(""" - . + . - """) == Graph.new({EX.spiderman, P.enemyOf, EX.green_goblin}) + """) == Graph.new({EX.spiderman(), P.enemyOf(), EX.green_goblin()}) assert RDF.NTriples.Decoder.decode!(""" - . + . - . + . - """) == Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p2, EX.O2}, - ]) + """) == + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p2(), EX.O2} + ]) end test "decoding a single triple with iris" do assert RDF.NTriples.Decoder.decode!(""" - . - """) == Graph.new({EX.spiderman, P.enemyOf, EX.green_goblin}) + . + """) == Graph.new({EX.spiderman(), P.enemyOf(), EX.green_goblin()}) end test "decoding a single triple with a blank node" do assert RDF.NTriples.Decoder.decode!(""" - _:foo . - """) == Graph.new({RDF.bnode("foo"), EX.p, EX.O}) + _:foo . + """) == Graph.new({RDF.bnode("foo"), EX.p(), EX.O}) + assert RDF.NTriples.Decoder.decode!(""" - _:1 . - """) == Graph.new({EX.S, EX.p, RDF.bnode("1")}) + _:1 . + """) == Graph.new({EX.S, EX.p(), RDF.bnode("1")}) + assert RDF.NTriples.Decoder.decode!(""" - _:foo _:bar . - """) == Graph.new({RDF.bnode("foo"), EX.p, RDF.bnode("bar")}) + _:foo _:bar . + """) == Graph.new({RDF.bnode("foo"), EX.p(), RDF.bnode("bar")}) end test "decoding a single triple with an untyped string literal" do assert RDF.NTriples.Decoder.decode!(""" - "Peter Parker" . - """) == Graph.new({EX.spiderman, P.realname, RDF.literal("Peter Parker")}) + "Peter Parker" . + """) == Graph.new({EX.spiderman(), P.realname(), RDF.literal("Peter Parker")}) end test "decoding a single triple with a typed literal" do assert RDF.NTriples.Decoder.decode!(""" - "42"^^ . - """) == Graph.new({EX.spiderman, EX.p, RDF.literal(42)}) + "42"^^ . + """) == Graph.new({EX.spiderman(), EX.p(), RDF.literal(42)}) end test "decoding a single triple with a language tagged literal" do assert RDF.NTriples.Decoder.decode!(""" - "foo"@en . - """) == Graph.new({EX.S, EX.p, RDF.literal("foo", language: "en")}) + "foo"@en . + """) == Graph.new({EX.S, EX.p(), RDF.literal("foo", language: "en")}) end test "decoding multiple triples" do assert RDF.NTriples.Decoder.decode!(""" - . - . - """) == Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p2, EX.O2}, - ]) - assert RDF.NTriples.Decoder.decode!(""" - . - . - . - """) == Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p2, EX.O2}, - {EX.S2, EX.p3, EX.O3} - ]) - end + . + . + """) == + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p2(), EX.O2} + ]) + assert RDF.NTriples.Decoder.decode!(""" + . + . + . + """) == + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p2(), EX.O2}, + {EX.S2, EX.p3(), EX.O3} + ]) + end end diff --git a/test/unit/ntriples_encoder_test.exs b/test/unit/ntriples_encoder_test.exs index 8e7699e..2919493 100644 --- a/test/unit/ntriples_encoder_test.exs +++ b/test/unit/ntriples_encoder_test.exs @@ -12,58 +12,60 @@ defmodule RDF.NTriples.EncoderTest do use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.org/#", - terms: [], strict: false - + defvocab EX, base_iri: "http://example.org/#", terms: [], strict: false describe "serializing a graph" do test "an empty graph is serialized to an empty string" do - assert NTriples.Encoder.encode!(Graph.new) == "" + assert NTriples.Encoder.encode!(Graph.new()) == "" end test "statements with IRIs only" do - assert NTriples.Encoder.encode!(Graph.new [ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p1, EX.O2}, - {EX.S1, EX.p2, EX.O3}, - {EX.S2, EX.p3, EX.O4}, - ]) == - """ - . - . - . - . - """ + assert NTriples.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p1(), EX.O2}, + {EX.S1, EX.p2(), EX.O3}, + {EX.S2, EX.p3(), EX.O4} + ]) + ) == + """ + . + . + . + . + """ end test "statements with literals" do - assert NTriples.Encoder.encode!(Graph.new [ - {EX.S1, EX.p1, ~L"foo"}, - {EX.S1, EX.p1, ~L"foo"en}, - {EX.S1, EX.p2, 42}, - {EX.S2, EX.p3, RDF.literal("strange things", datatype: EX.custom)}, - ]) == - """ - "foo"@en . - "foo" . - "42"^^<#{XSD.integer}> . - "strange things"^^<#{EX.custom}> . - """ + assert NTriples.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), ~L"foo"}, + {EX.S1, EX.p1(), ~L"foo"en}, + {EX.S1, EX.p2(), 42}, + {EX.S2, EX.p3(), RDF.literal("strange things", datatype: EX.custom())} + ]) + ) == + """ + "foo"@en . + "foo" . + "42"^^<#{XSD.integer()}> . + "strange things"^^<#{EX.custom()}> . + """ end test "statements with blank nodes" do - assert NTriples.Encoder.encode!(Graph.new [ - {EX.S1, EX.p1, RDF.bnode(1)}, - {EX.S1, EX.p1, RDF.bnode("foo")}, - {EX.S1, EX.p1, RDF.bnode(:bar)}, - ]) == - """ - _:1 . - _:bar . - _:foo . - """ + assert NTriples.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), RDF.bnode(1)}, + {EX.S1, EX.p1(), RDF.bnode("foo")}, + {EX.S1, EX.p1(), RDF.bnode(:bar)} + ]) + ) == + """ + _:1 . + _:bar . + _:foo . + """ end end - end diff --git a/test/unit/prefix_map_test.exs b/test/unit/prefix_map_test.exs index 66f195b..2e8a862 100644 --- a/test/unit/prefix_map_test.exs +++ b/test/unit/prefix_map_test.exs @@ -10,21 +10,27 @@ defmodule RDF.PrefixMapTest do @example1 %PrefixMap{map: %{ex1: @ex_ns1}} - @example2 %PrefixMap{map: %{ - ex1: @ex_ns1, - ex2: @ex_ns2 - }} + @example2 %PrefixMap{ + map: %{ + ex1: @ex_ns1, + ex2: @ex_ns2 + } + } - @example3 %PrefixMap{map: %{ - ex1: @ex_ns1, - ex2: @ex_ns2, - ex3: @ex_ns3 - }} + @example3 %PrefixMap{ + map: %{ + ex1: @ex_ns1, + ex2: @ex_ns2, + ex3: @ex_ns3 + } + } - @example4 %PrefixMap{map: %{ - ex1: @ex_ns1, - ex: RDF.iri(EX.__base_iri__) - }} + @example4 %PrefixMap{ + map: %{ + ex1: @ex_ns1, + ex: RDF.iri(EX.__base_iri__()) + } + } test "new/0" do assert PrefixMap.new() == %PrefixMap{} @@ -75,7 +81,7 @@ defmodule RDF.PrefixMapTest do end test "when the IRI namespace is given as a RDF.Vocabulary.Namespace which is not loaded yet" do - assert {:ok, prefix_map} = PrefixMap.new |> PrefixMap.add(:rdfs, RDF.NS.RDFS) + assert {:ok, prefix_map} = PrefixMap.new() |> PrefixMap.add(:rdfs, RDF.NS.RDFS) assert PrefixMap.has_prefix?(prefix_map, :rdfs) end @@ -120,6 +126,7 @@ defmodule RDF.PrefixMapTest do test "when the prefix maps share some prefixes and both map to different namespaces" do other_prefix_map = PrefixMap.new(ex3: @ex_ns4) + assert PrefixMap.merge(@example3, other_prefix_map) == {:error, [:ex3]} end @@ -130,37 +137,41 @@ defmodule RDF.PrefixMapTest do end test "when the second argument is not convertible to a prefix map" do - assert_raise ArgumentError, ~S["not convertible" is not convertible to a RDF.PrefixMap], fn -> - PrefixMap.merge(@example2, "not convertible") - end + assert_raise ArgumentError, + ~S["not convertible" is not convertible to a RDF.PrefixMap], + fn -> + PrefixMap.merge(@example2, "not convertible") + end end end describe "merge/3" do test "with a function resolving conflicts by choosing one of the inputs" do other_prefix_map = PrefixMap.new(ex3: @ex_ns4) - assert PrefixMap.merge(@example3, other_prefix_map, - fn _prefix, ns1, _ns2 -> ns1 end) == {:ok, @example3} - assert PrefixMap.merge(@example1, %{ex1: EX}, - fn _prefix, _ns1, ns2 -> ns2 end) == {:ok, PrefixMap.new(ex1: EX)} + assert PrefixMap.merge(@example3, other_prefix_map, fn _prefix, ns1, _ns2 -> ns1 end) == + {:ok, @example3} + + assert PrefixMap.merge(@example1, %{ex1: EX}, fn _prefix, _ns1, ns2 -> ns2 end) == + {:ok, PrefixMap.new(ex1: EX)} end test "with a function which does not resolve by returning nil" do other_prefix_map = PrefixMap.new(ex3: @ex_ns4) + assert PrefixMap.merge(@example3, other_prefix_map, fn _, _, _ -> nil end) == PrefixMap.merge(@example3, other_prefix_map) end test "with a function just partially resolving handling conflicts" do - assert PrefixMap.merge(@example3, @example3, - fn prefix, ns1, _ -> if prefix == :ex2, do: ns1 end) == + assert PrefixMap.merge(@example3, @example3, fn prefix, ns1, _ -> + if prefix == :ex2, do: ns1 + end) == {:error, [:ex3, :ex1]} end test "when the function returns a non-IRI value which is convertible" do - assert PrefixMap.merge(@example1, @example1, - fn _, _, _ -> "http://example.com/" end) == + assert PrefixMap.merge(@example1, @example1, fn _, _, _ -> "http://example.com/" end) == {:ok, PrefixMap.new(ex1: "http://example.com/")} end end @@ -181,14 +192,14 @@ defmodule RDF.PrefixMapTest do describe "merge!/3" do test "when all conflicts can be resolved" do other_prefix_map = PrefixMap.new(ex3: @ex_ns4) - assert PrefixMap.merge!(@example3, other_prefix_map, - fn _prefix, ns1, _ns2 -> ns1 end) == @example3 + + assert PrefixMap.merge!(@example3, other_prefix_map, fn _prefix, ns1, _ns2 -> ns1 end) == + @example3 end test "when not all conflicts can be resolved" do assert_raise RuntimeError, "conflicting prefix mappings: :ex1", fn -> - PrefixMap.merge!(@example2, @example2, - fn prefix, ns1, _ -> if prefix == :ex2, do: ns1 end) + PrefixMap.merge!(@example2, @example2, fn prefix, ns1, _ -> if prefix == :ex2, do: ns1 end) end end end @@ -265,17 +276,17 @@ defmodule RDF.PrefixMapTest do test "prefixes/1" do assert PrefixMap.prefixes(@example2) == ~w[ex1 ex2]a - assert PrefixMap.prefixes(PrefixMap.new) == ~w[]a + assert PrefixMap.prefixes(PrefixMap.new()) == ~w[]a end describe "namespaces/1" do assert PrefixMap.namespaces(@example2) == [@ex_ns1, @ex_ns2] - assert PrefixMap.namespaces(PrefixMap.new) == ~w[]a + assert PrefixMap.namespaces(PrefixMap.new()) == ~w[]a end describe "Enumerable protocol" do test "Enum.count" do - assert Enum.count(PrefixMap.new) == 0 + assert Enum.count(PrefixMap.new()) == 0 assert Enum.count(@example1) == 1 assert Enum.count(@example2) == 2 end @@ -288,7 +299,7 @@ defmodule RDF.PrefixMapTest do end test "Enum.reduce" do - assert Enum.reduce(@example2, [], fn(mapping, acc) -> [mapping | acc] end) == + assert Enum.reduce(@example2, [], fn mapping, acc -> [mapping | acc] end) == [{:ex2, @ex_ns2}, {:ex1, @ex_ns1}] end end diff --git a/test/unit/quad_test.exs b/test/unit/quad_test.exs index a84d4a0..70acbbb 100644 --- a/test/unit/quad_test.exs +++ b/test/unit/quad_test.exs @@ -7,10 +7,16 @@ defmodule RDF.QuadTest do describe "values/1" do test "with a valid RDF.Quad" do - assert Quad.values({~I, ~I, XSD.integer(42), ~I}) - == {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"} - assert Quad.values({~I, ~I, XSD.integer(42), nil}) - == {"http://example.com/S", "http://example.com/p", 42, nil} + assert Quad.values( + {~I, ~I, XSD.integer(42), + ~I} + ) == + {"http://example.com/S", "http://example.com/p", 42, "http://example.com/Graph"} + + assert Quad.values( + {~I, ~I, XSD.integer(42), nil} + ) == + {"http://example.com/S", "http://example.com/p", 42, nil} end test "with an invalid RDF.Quad" do @@ -20,14 +26,14 @@ defmodule RDF.QuadTest do end test "values/2" do - assert {~I, ~I, XSD.integer(42), ~I} + assert {~I, ~I, XSD.integer(42), + ~I} |> Quad.values(fn {:subject, subject} -> subject |> to_string() |> String.last() |> String.to_atom() - {:predicate, _} -> :p - {:object, object} -> object |> RDF.Term.value() |> Kernel.+(1) - {:graph_name, _} -> nil - end) - == {:S, :p, 43, nil} + {:predicate, _} -> :p + {:object, object} -> object |> RDF.Term.value() |> Kernel.+(1) + {:graph_name, _} -> nil + end) == + {:S, :p, 43, nil} end - end diff --git a/test/unit/query/bgp/query_planner_test.exs b/test/unit/query/bgp/query_planner_test.exs index dd2ed77..412fb61 100644 --- a/test/unit/query/bgp/query_planner_test.exs +++ b/test/unit/query/bgp/query_planner_test.exs @@ -30,7 +30,7 @@ defmodule RDF.Query.BGP.QueryPlannerTest do {:s4, :p4, ~L"foo"}, {:s, :p, :o}, {{:s}, {:p}, :o2}, - {:s2, :p2, {:o2}}, + {:s2, :p2, {:o2}} ] end end diff --git a/test/unit/query/bgp/simple_test.exs b/test/unit/query/bgp/simple_test.exs index 8714622..0efa786 100644 --- a/test/unit/query/bgp/simple_test.exs +++ b/test/unit/query/bgp/simple_test.exs @@ -4,34 +4,34 @@ defmodule RDF.Query.BGP.SimpleTest do import RDF.Query.BGP.Simple, only: [execute: 2] @example_graph Graph.new([ - {EX.s1, EX.p1, EX.o1}, - {EX.s1, EX.p2, EX.o2}, - {EX.s3, EX.p3, EX.o2} - ]) + {EX.s1(), EX.p1(), EX.o1()}, + {EX.s1(), EX.p2(), EX.o2()}, + {EX.s3(), EX.p3(), EX.o2()} + ]) test "empty bgp" do assert bgp_struct() |> execute(@example_graph) == [%{}] end test "single {s ?p ?o}" do - assert bgp_struct({EX.s1, :p, :o}) |> execute(@example_graph) == - [ - %{p: EX.p1, o: EX.o1}, - %{p: EX.p2, o: EX.o2} - ] + assert bgp_struct({EX.s1(), :p, :o}) |> execute(@example_graph) == + [ + %{p: EX.p1(), o: EX.o1()}, + %{p: EX.p2(), o: EX.o2()} + ] end test "single {?s ?p o}" do - assert bgp_struct({:s, :p, EX.o2}) |> execute(@example_graph) == - [ - %{s: EX.s3, p: EX.p3}, - %{s: EX.s1, p: EX.p2} - ] + assert bgp_struct({:s, :p, EX.o2()}) |> execute(@example_graph) == + [ + %{s: EX.s3(), p: EX.p3()}, + %{s: EX.s1(), p: EX.p2()} + ] end test "single {?s p ?o}" do - assert bgp_struct({:s, EX.p3, :o}) |> execute(@example_graph) == - [%{s: EX.s3, o: EX.o2}] + assert bgp_struct({:s, EX.p3(), :o}) |> execute(@example_graph) == + [%{s: EX.s3(), o: EX.o2()}] end test "with no solutions" do @@ -39,198 +39,214 @@ defmodule RDF.Query.BGP.SimpleTest do end test "with solutions on one triple pattern but none on another one" do - example_graph = Graph.new([ - {EX.x, EX.y, EX.z}, - {EX.y, EX.y, EX.z}, - ]) + example_graph = + Graph.new([ + {EX.x(), EX.y(), EX.z()}, + {EX.y(), EX.y(), EX.z()} + ]) assert bgp_struct([ - {:a, EX.p1, ~L"unmatched" }, - {:a, EX.y, EX.z} - ]) |> execute(example_graph) == [] + {:a, EX.p1(), ~L"unmatched"}, + {:a, EX.y(), EX.z()} + ]) + |> execute(example_graph) == [] end test "repeated variable: {?a ?a ?b}" do - example_graph = Graph.new([ - {EX.y, EX.y, EX.x}, - {EX.x, EX.y, EX.y}, - {EX.y, EX.x, EX.y} - ]) + example_graph = + Graph.new([ + {EX.y(), EX.y(), EX.x()}, + {EX.x(), EX.y(), EX.y()}, + {EX.y(), EX.x(), EX.y()} + ]) assert bgp_struct({:a, :a, :b}) |> execute(example_graph) == - [%{a: EX.y, b: EX.x}] + [%{a: EX.y(), b: EX.x()}] end test "repeated variable: {?a ?b ?a}" do - example_graph = Graph.new([ - {EX.y, EX.y, EX.x}, - {EX.x, EX.y, EX.y}, - {EX.y, EX.x, EX.y} - ]) + example_graph = + Graph.new([ + {EX.y(), EX.y(), EX.x()}, + {EX.x(), EX.y(), EX.y()}, + {EX.y(), EX.x(), EX.y()} + ]) assert bgp_struct({:a, :b, :a}) |> execute(example_graph) == - [%{a: EX.y, b: EX.x}] + [%{a: EX.y(), b: EX.x()}] end test "repeated variable: {?b ?a ?a}" do - example_graph = Graph.new([ - {EX.y, EX.y, EX.x}, - {EX.x, EX.y, EX.y}, - {EX.y, EX.x, EX.y} - ]) + example_graph = + Graph.new([ + {EX.y(), EX.y(), EX.x()}, + {EX.x(), EX.y(), EX.y()}, + {EX.y(), EX.x(), EX.y()} + ]) assert bgp_struct({:b, :a, :a}) |> execute(example_graph) == - [%{a: EX.y, b: EX.x}] + [%{a: EX.y(), b: EX.x()}] end test "repeated variable: {?a ?a ?a}" do - example_graph = Graph.new([ - {EX.y, EX.y, EX.x}, - {EX.x, EX.y, EX.y}, - {EX.y, EX.x, EX.y}, - {EX.y, EX.y, EX.y}, - ]) + example_graph = + Graph.new([ + {EX.y(), EX.y(), EX.x()}, + {EX.x(), EX.y(), EX.y()}, + {EX.y(), EX.x(), EX.y()}, + {EX.y(), EX.y(), EX.y()} + ]) - assert bgp_struct({:a, :a, :a}) |> execute(example_graph) == [%{a: EX.y}] + assert bgp_struct({:a, :a, :a}) |> execute(example_graph) == [%{a: EX.y()}] end test "two connected triple patterns with a match" do - assert execute(bgp_struct([ - {EX.s1, :p, :o}, - {EX.s3, :p2, :o } - ]), @example_graph) == [%{ - p: EX.p2, - p2: EX.p3, - o: EX.o2 - }] + assert execute( + bgp_struct([ + {EX.s1(), :p, :o}, + {EX.s3(), :p2, :o} + ]), + @example_graph + ) == [ + %{ + p: EX.p2(), + p2: EX.p3(), + o: EX.o2() + } + ] assert bgp_struct([ - {EX.s1, :p, :o1}, - {EX.s1, :p, :o2} + {EX.s1(), :p, :o1}, + {EX.s1(), :p, :o2} ]) |> execute(@example_graph) == - [ - %{ - p: EX.p1, - o1: EX.o1, - o2: EX.o1, - }, - %{ - p: EX.p2, - o1: EX.o2, - o2: EX.o2, - }, - ] + [ + %{ + p: EX.p1(), + o1: EX.o1(), + o2: EX.o1() + }, + %{ + p: EX.p2(), + o1: EX.o2(), + o2: EX.o2() + } + ] assert bgp_struct([ - {EX.s1, EX.p1, :o}, - {EX.s3, :p, :o} - ]) - |> execute(Graph.new([ - {EX.s1, EX.p1, EX.o1}, - {EX.s3, EX.p2, EX.o2}, - {EX.s3, EX.p3, EX.o1} - ])) == [%{p: EX.p3, o: EX.o1}] + {EX.s1(), EX.p1(), :o}, + {EX.s3(), :p, :o} + ]) + |> execute( + Graph.new([ + {EX.s1(), EX.p1(), EX.o1()}, + {EX.s3(), EX.p2(), EX.o2()}, + {EX.s3(), EX.p3(), EX.o1()} + ]) + ) == [%{p: EX.p3(), o: EX.o1()}] end test "a triple pattern with dependent variables from separate triple patterns" do assert bgp_struct([ - {EX.s1, EX.p1, :o}, - {EX.s2, :p, EX.o2}, - {:s, :p, :o} - ]) - |> execute(Graph.new([ - {EX.s1, EX.p1, EX.o1}, - {EX.s2, EX.p2, EX.o2}, - {EX.s3, EX.p2, EX.o1} - ])) == [ + {EX.s1(), EX.p1(), :o}, + {EX.s2(), :p, EX.o2()}, + {:s, :p, :o} + ]) + |> execute( + Graph.new([ + {EX.s1(), EX.p1(), EX.o1()}, + {EX.s2(), EX.p2(), EX.o2()}, + {EX.s3(), EX.p2(), EX.o1()} + ]) + ) == [ %{ - s: EX.s3, - p: EX.p2, - o: EX.o1, - }, + s: EX.s3(), + p: EX.p2(), + o: EX.o1() + } ] end test "when no solutions" do - assert bgp_struct({EX.s, EX.p, :o}) |> execute(@example_graph) == [] + assert bgp_struct({EX.s(), EX.p(), :o}) |> execute(@example_graph) == [] end test "multiple triple patterns with a constant unmatched triple has no solutions" do assert bgp_struct([ - {EX.s1, :p, :o}, - {EX.s, EX.p, EX.o} - ]) |> execute(@example_graph) == [] + {EX.s1(), :p, :o}, + {EX.s(), EX.p(), EX.o()} + ]) + |> execute(@example_graph) == [] end test "independent triple patterns lead to cross-products" do assert bgp_struct([ - {EX.s1, :p1, :o}, - {:s, :p2, EX.o2} + {EX.s1(), :p1, :o}, + {:s, :p2, EX.o2()} ]) |> execute(@example_graph) == [ - %{ - p1: EX.p1, - o: EX.o1, - s: EX.s3, - p2: EX.p3, - }, - %{ - p1: EX.p2, - o: EX.o2, - s: EX.s3, - p2: EX.p3, - }, - %{ - p1: EX.p1, - o: EX.o1, - s: EX.s1, - p2: EX.p2, - }, - %{ - p1: EX.p2, - o: EX.o2, - s: EX.s1, - p2: EX.p2, - }, - ] + %{ + p1: EX.p1(), + o: EX.o1(), + s: EX.s3(), + p2: EX.p3() + }, + %{ + p1: EX.p2(), + o: EX.o2(), + s: EX.s3(), + p2: EX.p3() + }, + %{ + p1: EX.p1(), + o: EX.o1(), + s: EX.s1(), + p2: EX.p2() + }, + %{ + p1: EX.p2(), + o: EX.o2(), + s: EX.s1(), + p2: EX.p2() + } + ] end test "blank nodes behave like variables, but don't appear in the solution" do assert bgp_struct([ - {EX.s1, :p, RDF.bnode("o")}, - {EX.s3, :p2, RDF.bnode("o")} + {EX.s1(), :p, RDF.bnode("o")}, + {EX.s3(), :p2, RDF.bnode("o")} ]) - |> execute(@example_graph) == [%{p: EX.p2, p2: EX.p3}] + |> execute(@example_graph) == [%{p: EX.p2(), p2: EX.p3()}] end test "cross-product with blank nodes" do assert bgp_struct([ - {EX.s1, :p1, :o}, - {RDF.bnode("s"), :p2, EX.o2} + {EX.s1(), :p1, :o}, + {RDF.bnode("s"), :p2, EX.o2()} ]) |> execute(@example_graph) == - [ - %{ - p1: EX.p1, - o: EX.o1, - p2: EX.p3, - }, - %{ - p1: EX.p2, - o: EX.o2, - p2: EX.p3, - }, - %{ - p1: EX.p1, - o: EX.o1, - p2: EX.p2, - }, - %{ - p1: EX.p2, - o: EX.o2, - p2: EX.p2, - }, - ] + [ + %{ + p1: EX.p1(), + o: EX.o1(), + p2: EX.p3() + }, + %{ + p1: EX.p2(), + o: EX.o2(), + p2: EX.p3() + }, + %{ + p1: EX.p1(), + o: EX.o1(), + p2: EX.p2() + }, + %{ + p1: EX.p2(), + o: EX.o2(), + p2: EX.p2() + } + ] end end diff --git a/test/unit/query/bgp/stream_test.exs b/test/unit/query/bgp/stream_test.exs index 509003a..4c3578b 100644 --- a/test/unit/query/bgp/stream_test.exs +++ b/test/unit/query/bgp/stream_test.exs @@ -4,35 +4,34 @@ defmodule RDF.Query.BGP.StreamTest do import RDF.Query.BGP.Stream, only: [execute: 2] @example_graph Graph.new([ - {EX.s1, EX.p1, EX.o1}, - {EX.s1, EX.p2, EX.o2}, - {EX.s3, EX.p3, EX.o2} - ]) - + {EX.s1(), EX.p1(), EX.o1()}, + {EX.s1(), EX.p2(), EX.o2()}, + {EX.s3(), EX.p3(), EX.o2()} + ]) test "empty bgp" do assert bgp_struct() |> execute(@example_graph) == [%{}] end test "single {s ?p ?o}" do - assert bgp_struct({EX.s1, :p, :o}) |> execute(@example_graph) == - [ - %{p: EX.p1, o: EX.o1}, - %{p: EX.p2, o: EX.o2} - ] + assert bgp_struct({EX.s1(), :p, :o}) |> execute(@example_graph) == + [ + %{p: EX.p1(), o: EX.o1()}, + %{p: EX.p2(), o: EX.o2()} + ] end test "single {?s ?p o}" do - assert bgp_struct({:s, :p, EX.o2}) |> execute(@example_graph) == - [ - %{s: EX.s1, p: EX.p2}, - %{s: EX.s3, p: EX.p3} - ] + assert bgp_struct({:s, :p, EX.o2()}) |> execute(@example_graph) == + [ + %{s: EX.s1(), p: EX.p2()}, + %{s: EX.s3(), p: EX.p3()} + ] end test "single {?s p ?o}" do - assert bgp_struct({:s, EX.p3, :o}) |> execute(@example_graph) == - [%{s: EX.s3, o: EX.o2}] + assert bgp_struct({:s, EX.p3(), :o}) |> execute(@example_graph) == + [%{s: EX.s3(), o: EX.o2()}] end test "with no solutions" do @@ -40,201 +39,217 @@ defmodule RDF.Query.BGP.StreamTest do end test "with solutions on one triple pattern but none on another one" do - example_graph = Graph.new([ - {EX.x, EX.y, EX.z}, - {EX.y, EX.y, EX.z}, - ]) + example_graph = + Graph.new([ + {EX.x(), EX.y(), EX.z()}, + {EX.y(), EX.y(), EX.z()} + ]) assert bgp_struct([ - {:a, EX.p1, ~L"unmatched" }, - {:a, EX.y, EX.z} - ]) |> execute(example_graph) == [] + {:a, EX.p1(), ~L"unmatched"}, + {:a, EX.y(), EX.z()} + ]) + |> execute(example_graph) == [] end test "repeated variable: {?a ?a ?b}" do - example_graph = Graph.new([ - {EX.y, EX.y, EX.x}, - {EX.x, EX.y, EX.y}, - {EX.y, EX.x, EX.y} - ]) + example_graph = + Graph.new([ + {EX.y(), EX.y(), EX.x()}, + {EX.x(), EX.y(), EX.y()}, + {EX.y(), EX.x(), EX.y()} + ]) assert bgp_struct({:a, :a, :b}) |> execute(example_graph) == - [%{a: EX.y, b: EX.x}] + [%{a: EX.y(), b: EX.x()}] end test "repeated variable: {?a ?b ?a}" do - example_graph = Graph.new([ - {EX.y, EX.y, EX.x}, - {EX.x, EX.y, EX.y}, - {EX.y, EX.x, EX.y} - ]) + example_graph = + Graph.new([ + {EX.y(), EX.y(), EX.x()}, + {EX.x(), EX.y(), EX.y()}, + {EX.y(), EX.x(), EX.y()} + ]) assert bgp_struct({:a, :b, :a}) |> execute(example_graph) == - [%{a: EX.y, b: EX.x}] + [%{a: EX.y(), b: EX.x()}] end test "repeated variable: {?b ?a ?a}" do - example_graph = Graph.new([ - {EX.y, EX.y, EX.x}, - {EX.x, EX.y, EX.y}, - {EX.y, EX.x, EX.y} - ]) + example_graph = + Graph.new([ + {EX.y(), EX.y(), EX.x()}, + {EX.x(), EX.y(), EX.y()}, + {EX.y(), EX.x(), EX.y()} + ]) assert bgp_struct({:b, :a, :a}) |> execute(example_graph) == - [%{a: EX.y, b: EX.x}] + [%{a: EX.y(), b: EX.x()}] end test "repeated variable: {?a ?a ?a}" do - example_graph = Graph.new([ - {EX.y, EX.y, EX.x}, - {EX.x, EX.y, EX.y}, - {EX.y, EX.x, EX.y}, - {EX.y, EX.y, EX.y}, - ]) + example_graph = + Graph.new([ + {EX.y(), EX.y(), EX.x()}, + {EX.x(), EX.y(), EX.y()}, + {EX.y(), EX.x(), EX.y()}, + {EX.y(), EX.y(), EX.y()} + ]) - assert bgp_struct({:a, :a, :a}) |> execute(example_graph) == [%{a: EX.y}] + assert bgp_struct({:a, :a, :a}) |> execute(example_graph) == [%{a: EX.y()}] end test "two connected triple patterns with a match" do - assert execute(bgp_struct([ - {EX.s1, :p, :o}, - {EX.s3, :p2, :o } - ]), @example_graph) == [%{ - p: EX.p2, - p2: EX.p3, - o: EX.o2 - }] + assert execute( + bgp_struct([ + {EX.s1(), :p, :o}, + {EX.s3(), :p2, :o} + ]), + @example_graph + ) == [ + %{ + p: EX.p2(), + p2: EX.p3(), + o: EX.o2() + } + ] assert bgp_struct([ - {EX.s1, :p, :o1}, - {EX.s1, :p, :o2} + {EX.s1(), :p, :o1}, + {EX.s1(), :p, :o2} ]) |> execute(@example_graph) == - [ - %{ - p: EX.p1, - o1: EX.o1, - o2: EX.o1, - }, - %{ - p: EX.p2, - o1: EX.o2, - o2: EX.o2, - }, - ] + [ + %{ + p: EX.p1(), + o1: EX.o1(), + o2: EX.o1() + }, + %{ + p: EX.p2(), + o1: EX.o2(), + o2: EX.o2() + } + ] assert bgp_struct([ - {EX.s1, EX.p1, :o}, - {EX.s3, :p, :o} - ]) - |> execute(Graph.new([ - {EX.s1, EX.p1, EX.o1}, - {EX.s3, EX.p2, EX.o2}, - {EX.s3, EX.p3, EX.o1} - ])) == [%{p: EX.p3, o: EX.o1}] + {EX.s1(), EX.p1(), :o}, + {EX.s3(), :p, :o} + ]) + |> execute( + Graph.new([ + {EX.s1(), EX.p1(), EX.o1()}, + {EX.s3(), EX.p2(), EX.o2()}, + {EX.s3(), EX.p3(), EX.o1()} + ]) + ) == [%{p: EX.p3(), o: EX.o1()}] end test "a triple pattern with dependent variables from separate triple patterns" do assert bgp_struct([ - {EX.s1, EX.p1, :o}, - {EX.s2, :p, EX.o2}, - {:s, :p, :o} - ]) - |> execute(Graph.new([ - {EX.s1, EX.p1, EX.o1}, - {EX.s2, EX.p2, EX.o2}, - {EX.s3, EX.p2, EX.o1} - ])) == [ + {EX.s1(), EX.p1(), :o}, + {EX.s2(), :p, EX.o2()}, + {:s, :p, :o} + ]) + |> execute( + Graph.new([ + {EX.s1(), EX.p1(), EX.o1()}, + {EX.s2(), EX.p2(), EX.o2()}, + {EX.s3(), EX.p2(), EX.o1()} + ]) + ) == [ %{ - s: EX.s3, - p: EX.p2, - o: EX.o1, - }, + s: EX.s3(), + p: EX.p2(), + o: EX.o1() + } ] end test "when no solutions" do - assert bgp_struct({EX.s, EX.p, :o}) |> execute(@example_graph) == [] + assert bgp_struct({EX.s(), EX.p(), :o}) |> execute(@example_graph) == [] end test "multiple triple patterns with a constant unmatched triple has no solutions" do assert bgp_struct([ - {EX.s1, :p, :o}, - {EX.s, EX.p, EX.o} - ]) |> execute(@example_graph) == [] + {EX.s1(), :p, :o}, + {EX.s(), EX.p(), EX.o()} + ]) + |> execute(@example_graph) == [] end test "independent triple patterns lead to cross-products" do assert bgp_struct([ - {EX.s1, :p1, :o}, - {:s, :p2, EX.o2} + {EX.s1(), :p1, :o}, + {:s, :p2, EX.o2()} ]) |> execute(@example_graph) - |> MapSet.new() == MapSet.new([ - %{ - p1: EX.p1, - o: EX.o1, - s: EX.s3, - p2: EX.p3, - }, - %{ - p1: EX.p2, - o: EX.o2, - s: EX.s3, - p2: EX.p3, - }, - %{ - p1: EX.p1, - o: EX.o1, - s: EX.s1, - p2: EX.p2, - }, - %{ - p1: EX.p2, - o: EX.o2, - s: EX.s1, - p2: EX.p2, - }, - ]) + |> MapSet.new() == + MapSet.new([ + %{ + p1: EX.p1(), + o: EX.o1(), + s: EX.s3(), + p2: EX.p3() + }, + %{ + p1: EX.p2(), + o: EX.o2(), + s: EX.s3(), + p2: EX.p3() + }, + %{ + p1: EX.p1(), + o: EX.o1(), + s: EX.s1(), + p2: EX.p2() + }, + %{ + p1: EX.p2(), + o: EX.o2(), + s: EX.s1(), + p2: EX.p2() + } + ]) end test "blank nodes behave like variables, but don't appear in the solution" do assert bgp_struct([ - {EX.s1, :p, RDF.bnode("o")}, - {EX.s3, :p2, RDF.bnode("o")} + {EX.s1(), :p, RDF.bnode("o")}, + {EX.s3(), :p2, RDF.bnode("o")} ]) - |> execute(@example_graph) == [%{p: EX.p2, p2: EX.p3}] + |> execute(@example_graph) == [%{p: EX.p2(), p2: EX.p3()}] end test "cross-product with blank nodes" do assert bgp_struct([ - {EX.s1, :p1, :o}, - {RDF.bnode("s"), :p2, EX.o2} + {EX.s1(), :p1, :o}, + {RDF.bnode("s"), :p2, EX.o2()} ]) |> execute(@example_graph) - |> MapSet.new() == MapSet.new( - [ - %{ - p1: EX.p1, - o: EX.o1, - p2: EX.p3, - }, - %{ - p1: EX.p2, - o: EX.o2, - p2: EX.p3, - }, - %{ - p1: EX.p1, - o: EX.o1, - p2: EX.p2, - }, - %{ - p1: EX.p2, - o: EX.o2, - p2: EX.p2, - }, - ] - ) + |> MapSet.new() == + MapSet.new([ + %{ + p1: EX.p1(), + o: EX.o1(), + p2: EX.p3() + }, + %{ + p1: EX.p2(), + o: EX.o2(), + p2: EX.p3() + }, + %{ + p1: EX.p1(), + o: EX.o1(), + p2: EX.p2() + }, + %{ + p1: EX.p2(), + o: EX.o2(), + p2: EX.p2() + } + ]) end end diff --git a/test/unit/query/builder_test.exs b/test/unit/query/builder_test.exs index 8a06e75..7cd0845 100644 --- a/test/unit/query/builder_test.exs +++ b/test/unit/query/builder_test.exs @@ -9,178 +9,188 @@ defmodule RDF.Query.BuilderTest do end test "one triple pattern doesn't require list brackets" do - assert Builder.bgp({EX.s, EX.p, EX.o}) == - ok_bgp_struct [{EX.s, EX.p, EX.o}] + assert Builder.bgp({EX.s(), EX.p(), EX.o()}) == + ok_bgp_struct([{EX.s(), EX.p(), EX.o()}]) end test "variables" do - assert Builder.bgp([{:s?, :p?, :o?}]) == ok_bgp_struct [{:s, :p, :o}] + assert Builder.bgp([{:s?, :p?, :o?}]) == ok_bgp_struct([{:s, :p, :o}]) end test "blank nodes" do assert Builder.bgp([{RDF.bnode("s"), RDF.bnode("p"), RDF.bnode("o")}]) == - ok_bgp_struct [{RDF.bnode("s"), RDF.bnode("p"), RDF.bnode("o")}] + ok_bgp_struct([{RDF.bnode("s"), RDF.bnode("p"), RDF.bnode("o")}]) end test "blank nodes as atoms" do assert Builder.bgp([{:_s, :_p, :_o}]) == - ok_bgp_struct [{RDF.bnode("s"), RDF.bnode("p"), RDF.bnode("o")}] + ok_bgp_struct([{RDF.bnode("s"), RDF.bnode("p"), RDF.bnode("o")}]) end test "variable notation has precedence over blank node notation" do - assert Builder.bgp([{:_s?, :_p?, :_o?}]) == ok_bgp_struct [{:_s, :_p, :_o}] + assert Builder.bgp([{:_s?, :_p?, :_o?}]) == ok_bgp_struct([{:_s, :_p, :_o}]) end test "IRIs" do - assert Builder.bgp([{ - RDF.iri("http://example.com/s"), - RDF.iri("http://example.com/p"), - RDF.iri("http://example.com/o")}] - ) == ok_bgp_struct [{EX.s, EX.p, EX.o}] + assert Builder.bgp([ + { + RDF.iri("http://example.com/s"), + RDF.iri("http://example.com/p"), + RDF.iri("http://example.com/o") + } + ]) == ok_bgp_struct([{EX.s(), EX.p(), EX.o()}]) - assert Builder.bgp([{ - ~I, - ~I, - ~I}] - ) == ok_bgp_struct [{EX.s, EX.p, EX.o}] + assert Builder.bgp([ + { + ~I, + ~I, + ~I + } + ]) == ok_bgp_struct([{EX.s(), EX.p(), EX.o()}]) - assert Builder.bgp([{EX.s, EX.p, EX.o}]) == - ok_bgp_struct [{EX.s, EX.p, EX.o}] + assert Builder.bgp([{EX.s(), EX.p(), EX.o()}]) == + ok_bgp_struct([{EX.s(), EX.p(), EX.o()}]) end test "vocabulary term atoms" do assert Builder.bgp([{EX.S, EX.P, EX.O}]) == - ok_bgp_struct [{RDF.iri(EX.S), RDF.iri(EX.P), RDF.iri(EX.O)}] + ok_bgp_struct([{RDF.iri(EX.S), RDF.iri(EX.P), RDF.iri(EX.O)}]) end test "special :a atom for rdf:type" do assert Builder.bgp([{EX.S, :a, EX.O}]) == - ok_bgp_struct [{RDF.iri(EX.S), RDF.type, RDF.iri(EX.O)}] + ok_bgp_struct([{RDF.iri(EX.S), RDF.type(), RDF.iri(EX.O)}]) end test "URIs" do - assert Builder.bgp([{ - URI.parse("http://example.com/s"), - URI.parse("http://example.com/p"), - URI.parse("http://example.com/o")}] - ) == ok_bgp_struct [{EX.s, EX.p, EX.o}] + assert Builder.bgp([ + { + URI.parse("http://example.com/s"), + URI.parse("http://example.com/p"), + URI.parse("http://example.com/o") + } + ]) == ok_bgp_struct([{EX.s(), EX.p(), EX.o()}]) end test "literals" do - assert Builder.bgp([{EX.s, EX.p, ~L"foo"}]) == - ok_bgp_struct [{EX.s, EX.p, ~L"foo"}] + assert Builder.bgp([{EX.s(), EX.p(), ~L"foo"}]) == + ok_bgp_struct([{EX.s(), EX.p(), ~L"foo"}]) end test "values coercible to literals" do - assert Builder.bgp([{EX.s, EX.p, "foo"}]) == - ok_bgp_struct [{EX.s, EX.p, ~L"foo"}] - assert Builder.bgp([{EX.s, EX.p, 42}]) == - ok_bgp_struct [{EX.s, EX.p, RDF.literal(42)}] - assert Builder.bgp([{EX.s, EX.p, true}]) == - ok_bgp_struct [{EX.s, EX.p, XSD.true}] + assert Builder.bgp([{EX.s(), EX.p(), "foo"}]) == + ok_bgp_struct([{EX.s(), EX.p(), ~L"foo"}]) + + assert Builder.bgp([{EX.s(), EX.p(), 42}]) == + ok_bgp_struct([{EX.s(), EX.p(), RDF.literal(42)}]) + + assert Builder.bgp([{EX.s(), EX.p(), true}]) == + ok_bgp_struct([{EX.s(), EX.p(), XSD.true()}]) end test "literals on non-object positions" do - assert {:error, %RDF.Query.InvalidError{}} = - Builder.bgp([{~L"foo", EX.p, ~L"bar"}]) + assert {:error, %RDF.Query.InvalidError{}} = Builder.bgp([{~L"foo", EX.p(), ~L"bar"}]) end test "multiple triple patterns" do assert Builder.bgp([ - {EX.S, EX.p, :o?}, - {:o?, EX.p2, 42} + {EX.S, EX.p(), :o?}, + {:o?, EX.p2(), 42} ]) == - ok_bgp_struct [ - {RDF.iri(EX.S), EX.p, :o}, - {:o, EX.p2, RDF.literal(42)} - ] + ok_bgp_struct([ + {RDF.iri(EX.S), EX.p(), :o}, + {:o, EX.p2(), RDF.literal(42)} + ]) end test "multiple objects to the same subject-predicate" do - assert Builder.bgp([{EX.s, EX.p, EX.o1, EX.o2}]) == - ok_bgp_struct [ - {EX.s, EX.p, EX.o1}, - {EX.s, EX.p, EX.o2} - ] + assert Builder.bgp([{EX.s(), EX.p(), EX.o1(), EX.o2()}]) == + ok_bgp_struct([ + {EX.s(), EX.p(), EX.o1()}, + {EX.s(), EX.p(), EX.o2()} + ]) - assert Builder.bgp({EX.s, EX.p, EX.o1, EX.o2}) == - ok_bgp_struct [ - {EX.s, EX.p, EX.o1}, - {EX.s, EX.p, EX.o2} - ] + assert Builder.bgp({EX.s(), EX.p(), EX.o1(), EX.o2()}) == + ok_bgp_struct([ + {EX.s(), EX.p(), EX.o1()}, + {EX.s(), EX.p(), EX.o2()} + ]) - assert Builder.bgp({EX.s, EX.p, :o?, false, 42, "foo"}) == - ok_bgp_struct [ - {EX.s, EX.p, :o}, - {EX.s, EX.p, XSD.false}, - {EX.s, EX.p, RDF.literal(42)}, - {EX.s, EX.p, RDF.literal("foo")} - ] + assert Builder.bgp({EX.s(), EX.p(), :o?, false, 42, "foo"}) == + ok_bgp_struct([ + {EX.s(), EX.p(), :o}, + {EX.s(), EX.p(), XSD.false()}, + {EX.s(), EX.p(), RDF.literal(42)}, + {EX.s(), EX.p(), RDF.literal("foo")} + ]) end test "multiple predicate-object pairs to the same subject" do - assert Builder.bgp([{ - EX.s, - [EX.p1, EX.o1], - [EX.p2, EX.o2], - }]) == - ok_bgp_struct [ - {EX.s, EX.p1, EX.o1}, - {EX.s, EX.p2, EX.o2} - ] + assert Builder.bgp([ + { + EX.s(), + [EX.p1(), EX.o1()], + [EX.p2(), EX.o2()] + } + ]) == + ok_bgp_struct([ + {EX.s(), EX.p1(), EX.o1()}, + {EX.s(), EX.p2(), EX.o2()} + ]) - assert Builder.bgp([{ - EX.s, - [:a, :o?], - [EX.p1, 42, 3.14], - [EX.p2, "foo", true], - }]) == - ok_bgp_struct [ - {EX.s, RDF.type, :o}, - {EX.s, EX.p1, RDF.literal(42)}, - {EX.s, EX.p1, RDF.literal(3.14)}, - {EX.s, EX.p2, RDF.literal("foo")}, - {EX.s, EX.p2, XSD.true} - ] + assert Builder.bgp([ + { + EX.s(), + [:a, :o?], + [EX.p1(), 42, 3.14], + [EX.p2(), "foo", true] + } + ]) == + ok_bgp_struct([ + {EX.s(), RDF.type(), :o}, + {EX.s(), EX.p1(), RDF.literal(42)}, + {EX.s(), EX.p1(), RDF.literal(3.14)}, + {EX.s(), EX.p2(), RDF.literal("foo")}, + {EX.s(), EX.p2(), XSD.true()} + ]) - assert Builder.bgp([{EX.s, [EX.p, EX.o]}]) == - ok_bgp_struct [{EX.s, EX.p, EX.o}] + assert Builder.bgp([{EX.s(), [EX.p(), EX.o()]}]) == + ok_bgp_struct([{EX.s(), EX.p(), EX.o()}]) end end - describe "path/2" do test "element count == 3" do - assert Builder.path([EX.s, EX.p, EX.o]) == ok_bgp_struct [{EX.s, EX.p, EX.o}] - assert Builder.path([:s?, :p?, :o?]) == ok_bgp_struct [{:s, :p, :o}] + assert Builder.path([EX.s(), EX.p(), EX.o()]) == ok_bgp_struct([{EX.s(), EX.p(), EX.o()}]) + assert Builder.path([:s?, :p?, :o?]) == ok_bgp_struct([{:s, :p, :o}]) end test "element count > 3" do - assert Builder.path([EX.s, EX.p1, EX.p2, EX.o]) == - ok_bgp_struct [ - {EX.s, EX.p1, RDF.bnode("0")}, - {RDF.bnode("0"), EX.p2, EX.o}, - ] + assert Builder.path([EX.s(), EX.p1(), EX.p2(), EX.o()]) == + ok_bgp_struct([ + {EX.s(), EX.p1(), RDF.bnode("0")}, + {RDF.bnode("0"), EX.p2(), EX.o()} + ]) assert Builder.path([:s?, :p1?, :p2?, :o?]) == - ok_bgp_struct [ + ok_bgp_struct([ {:s, :p1, RDF.bnode("0")}, - {RDF.bnode("0"), :p2, :o}, - ] + {RDF.bnode("0"), :p2, :o} + ]) end test "element count < 3" do - assert {:error, %RDF.Query.InvalidError{}} = Builder.path([EX.s, EX.p]) - assert {:error, %RDF.Query.InvalidError{}} = Builder.path([EX.s]) + assert {:error, %RDF.Query.InvalidError{}} = Builder.path([EX.s(), EX.p()]) + assert {:error, %RDF.Query.InvalidError{}} = Builder.path([EX.s()]) assert {:error, %RDF.Query.InvalidError{}} = Builder.path([]) end test "with_elements: true" do - assert Builder.path([EX.s, EX.p1, EX.p2, :o?], with_elements: true) == - ok_bgp_struct [ - {EX.s, EX.p1, :el0}, - {:el0, EX.p2, :o}, - ] + assert Builder.path([EX.s(), EX.p1(), EX.p2(), :o?], with_elements: true) == + ok_bgp_struct([ + {EX.s(), EX.p1(), :el0}, + {:el0, EX.p2(), :o} + ]) end end end diff --git a/test/unit/query/query_test.exs b/test/unit/query/query_test.exs index 66505b1..81bc736 100644 --- a/test/unit/query/query_test.exs +++ b/test/unit/query/query_test.exs @@ -4,52 +4,53 @@ defmodule RDF.QueryTest do doctest RDF.Query @example_graph """ - @prefix foaf: . - @prefix ex: . + @prefix foaf: . + @prefix ex: . - ex:Outlaw - foaf:name "Johnny Lee Outlaw" ; - foaf:mbox . + ex:Outlaw + foaf:name "Johnny Lee Outlaw" ; + foaf:mbox . - ex:Goodguy - foaf:name "Peter Goodguy" ; - foaf:mbox ; - foaf:friend ex:Outlaw . - """ |> RDF.Turtle.read_string!() + ex:Goodguy + foaf:name "Peter Goodguy" ; + foaf:mbox ; + foaf:friend ex:Outlaw . + """ + |> RDF.Turtle.read_string!() def example_graph, do: @example_graph - @example_query [{:s?, FOAF.name, ~L"Peter Goodguy"}] + @example_query [{:s?, FOAF.name(), ~L"Peter Goodguy"}] test "execute/2" do assert RDF.Query.execute(RDF.Query.bgp(@example_query), @example_graph) == - {:ok, BGP.Stream.execute(RDF.Query.bgp(@example_query), @example_graph)} + {:ok, BGP.Stream.execute(RDF.Query.bgp(@example_query), @example_graph)} assert RDF.Query.execute(@example_query, @example_graph) == - {:ok, BGP.Stream.execute(RDF.Query.bgp(@example_query), @example_graph)} + {:ok, BGP.Stream.execute(RDF.Query.bgp(@example_query), @example_graph)} end test "execute!/2" do assert RDF.Query.execute!(RDF.Query.bgp(@example_query), @example_graph) == - BGP.Stream.execute(RDF.Query.bgp(@example_query), @example_graph) + BGP.Stream.execute(RDF.Query.bgp(@example_query), @example_graph) assert RDF.Query.execute!(@example_query, @example_graph) == - BGP.Stream.execute(RDF.Query.bgp(@example_query), @example_graph) + BGP.Stream.execute(RDF.Query.bgp(@example_query), @example_graph) end test "stream/2" do assert RDF.Query.stream(RDF.Query.bgp(@example_query), @example_graph) == - {:ok, BGP.Stream.stream(RDF.Query.bgp(@example_query), @example_graph)} + {:ok, BGP.Stream.stream(RDF.Query.bgp(@example_query), @example_graph)} assert RDF.Query.stream(@example_query, @example_graph) == - {:ok, BGP.Stream.stream(RDF.Query.bgp(@example_query), @example_graph)} + {:ok, BGP.Stream.stream(RDF.Query.bgp(@example_query), @example_graph)} end test "stream!/2" do assert RDF.Query.stream!(RDF.Query.bgp(@example_query), @example_graph) == - BGP.Stream.stream(RDF.Query.bgp(@example_query), @example_graph) + BGP.Stream.stream(RDF.Query.bgp(@example_query), @example_graph) assert RDF.Query.stream!(@example_query, @example_graph) == - BGP.Stream.stream(RDF.Query.bgp(@example_query), @example_graph) + BGP.Stream.stream(RDF.Query.bgp(@example_query), @example_graph) end end diff --git a/test/unit/serialization/format_test.exs b/test/unit/serialization/format_test.exs index 9707008..ba28fda 100644 --- a/test/unit/serialization/format_test.exs +++ b/test/unit/serialization/format_test.exs @@ -2,5 +2,4 @@ defmodule RDF.Serialization.FormatTest do use ExUnit.Case doctest RDF.Serialization.Format - end diff --git a/test/unit/serialization/parse_helper_test.exs b/test/unit/serialization/parse_helper_test.exs index cd97361..6486eae 100644 --- a/test/unit/serialization/parse_helper_test.exs +++ b/test/unit/serialization/parse_helper_test.exs @@ -4,45 +4,43 @@ defmodule RDF.Serialization.ParseHelperTest do alias RDF.Serialization.ParseHelper @unicode_seq_4digit %{ - ~S"\u0020" => " ", + ~S"\u0020" => " ", ~S"" => "", - ~S"\u03B1:a" => "\xCE\xB1:a", - ~S"a\u003Ab" => "a\x3Ab", + ~S"\u03B1:a" => "\xCE\xB1:a", + ~S"a\u003Ab" => "a\x3Ab" } @unicode_seq_8digit %{ - ~S"\U00000020" => " ", - ~S"\U00010000" => "\xF0\x90\x80\x80", - ~S"\U000EFFFF" => "\xF3\xAF\xBF\xBF", + ~S"\U00000020" => " ", + ~S"\U00010000" => "\xF0\x90\x80\x80", + ~S"\U000EFFFF" => "\xF3\xAF\xBF\xBF" } - describe "string escaping" do test "unescaping of \\uXXXX codepoint escape sequences" do - Enum.each @unicode_seq_4digit, fn {input, output} -> + Enum.each(@unicode_seq_4digit, fn {input, output} -> assert ParseHelper.string_unescape(input) == output - end + end) end test "unescaping of \\UXXXXXXXX codepoint escape sequences" do - Enum.each @unicode_seq_8digit, fn {input, output} -> + Enum.each(@unicode_seq_8digit, fn {input, output} -> assert ParseHelper.string_unescape(input) == output - end + end) end end describe "IRI escaping" do test "unescaping of \\uXXXX codepoint escape sequences" do - Enum.each @unicode_seq_4digit, fn {input, output} -> + Enum.each(@unicode_seq_4digit, fn {input, output} -> assert ParseHelper.iri_unescape(input) == output - end + end) end test "unescaping of \\UXXXXXXXX codepoint escape sequences" do - Enum.each @unicode_seq_8digit, fn {input, output} -> + Enum.each(@unicode_seq_8digit, fn {input, output} -> assert ParseHelper.iri_unescape(input) == output - end + end) end end - end diff --git a/test/unit/serialization/serialization_test.exs b/test/unit/serialization/serialization_test.exs index f85d481..5d75882 100644 --- a/test/unit/serialization/serialization_test.exs +++ b/test/unit/serialization/serialization_test.exs @@ -5,9 +5,7 @@ defmodule RDF.SerializationTest do use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.org/", - terms: [], strict: false + defvocab EX, base_iri: "http://example.org/", terms: [], strict: false @example_turtle_file "test/data/cbd.ttl" @example_turtle_string """ @@ -15,9 +13,9 @@ defmodule RDF.SerializationTest do ex:Aaron ex:Person . """ - @example_graph RDF.Graph.new [{EX.S, EX.p, EX.O}] + @example_graph RDF.Graph.new([{EX.S, EX.p(), EX.O}]) @example_graph_turtle """ - @prefix : <#{to_string(EX.__base_iri__)}> . + @prefix : <#{to_string(EX.__base_iri__())}> . :S :p :O . @@ -25,33 +23,32 @@ defmodule RDF.SerializationTest do defp file(name), do: System.tmp_dir!() |> Path.join(name) - describe "read_string/2" do test "with correct format name" do assert {:ok, %RDF.Graph{}} = - RDF.Serialization.read_string(@example_turtle_string, format: :turtle) + RDF.Serialization.read_string(@example_turtle_string, format: :turtle) end test "with wrong format name" do assert {:error, "N-Triple scanner error" <> _} = - RDF.Serialization.read_string(@example_turtle_string, format: :ntriples) + RDF.Serialization.read_string(@example_turtle_string, format: :ntriples) end test "with invalid format name" do assert {:error, "unable to detect serialization format"} == - RDF.Serialization.read_string(@example_turtle_string, format: :foo) + RDF.Serialization.read_string(@example_turtle_string, format: :foo) end test "with media_type" do assert {:ok, %RDF.Graph{}} = - RDF.Serialization.read_string(@example_turtle_string, media_type: "text/turtle") + RDF.Serialization.read_string(@example_turtle_string, media_type: "text/turtle") end end describe "read_string!/2" do test "with correct format name" do assert %RDF.Graph{} = - RDF.Serialization.read_string!(@example_turtle_string, format: :turtle) + RDF.Serialization.read_string!(@example_turtle_string, format: :turtle) end test "with wrong format name" do @@ -68,7 +65,7 @@ defmodule RDF.SerializationTest do test "with media_type" do assert %RDF.Graph{} = - RDF.Serialization.read_string!(@example_turtle_string, media_type: "text/turtle") + RDF.Serialization.read_string!(@example_turtle_string, media_type: "text/turtle") end end @@ -79,12 +76,12 @@ defmodule RDF.SerializationTest do test "with correct format name" do assert {:ok, %RDF.Graph{}} = - RDF.Serialization.read_file(@example_turtle_file, format: :turtle) + RDF.Serialization.read_file(@example_turtle_file, format: :turtle) end test "with wrong format name" do assert {:error, "N-Triple scanner error" <> _} = - RDF.Serialization.read_file(@example_turtle_file, format: :ntriples) + RDF.Serialization.read_file(@example_turtle_file, format: :ntriples) end test "with invalid format name, but correct file extension" do @@ -93,7 +90,7 @@ defmodule RDF.SerializationTest do test "with media_type" do assert {:ok, %RDF.Graph{}} = - RDF.Serialization.read_file(@example_turtle_file, media_type: "text/turtle") + RDF.Serialization.read_file(@example_turtle_file, media_type: "text/turtle") end end @@ -103,8 +100,7 @@ defmodule RDF.SerializationTest do end test "with correct format name" do - assert %RDF.Graph{} = - RDF.Serialization.read_file!(@example_turtle_file, format: :turtle) + assert %RDF.Graph{} = RDF.Serialization.read_file!(@example_turtle_file, format: :turtle) end test "with wrong format name" do @@ -115,48 +111,60 @@ defmodule RDF.SerializationTest do test "with media_type name" do assert %RDF.Graph{} = - RDF.Serialization.read_file!(@example_turtle_file, media_type: "text/turtle") + RDF.Serialization.read_file!(@example_turtle_file, media_type: "text/turtle") end end describe "write_string/2" do test "with name of available format" do - assert RDF.Serialization.write_string(@example_graph, format: :turtle, - prefixes: %{"" => EX.__base_iri__}) == - {:ok, @example_graph_turtle} + assert RDF.Serialization.write_string(@example_graph, + format: :turtle, + prefixes: %{"" => EX.__base_iri__()} + ) == + {:ok, @example_graph_turtle} end test "with invalid format name" do - assert RDF.Serialization.write_string(@example_graph, format: :foo, - prefixes: %{"" => EX.__base_iri__}) == - {:error, "unable to detect serialization format"} + assert RDF.Serialization.write_string(@example_graph, + format: :foo, + prefixes: %{"" => EX.__base_iri__()} + ) == + {:error, "unable to detect serialization format"} end test "with media type" do - assert RDF.Serialization.write_string(@example_graph, media_type: "text/turtle", - prefixes: %{"" => EX.__base_iri__}) == - {:ok, @example_graph_turtle} + assert RDF.Serialization.write_string(@example_graph, + media_type: "text/turtle", + prefixes: %{"" => EX.__base_iri__()} + ) == + {:ok, @example_graph_turtle} end end describe "write_string!/2" do test "with name of available format" do - assert RDF.Serialization.write_string!(@example_graph, format: :turtle, - prefixes: %{"" => EX.__base_iri__}) == - @example_graph_turtle + assert RDF.Serialization.write_string!(@example_graph, + format: :turtle, + prefixes: %{"" => EX.__base_iri__()} + ) == + @example_graph_turtle end test "with invalid format name" do assert_raise RuntimeError, "unable to detect serialization format", fn -> - RDF.Serialization.write_string!(@example_graph, format: :foo, - prefixes: %{"" => EX.__base_iri__}) + RDF.Serialization.write_string!(@example_graph, + format: :foo, + prefixes: %{"" => EX.__base_iri__()} + ) end end test "with media type" do - assert RDF.Serialization.write_string!(@example_graph, media_type: "text/turtle", - prefixes: %{"" => EX.__base_iri__}) == - @example_graph_turtle + assert RDF.Serialization.write_string!(@example_graph, + media_type: "text/turtle", + prefixes: %{"" => EX.__base_iri__()} + ) == + @example_graph_turtle end end @@ -164,8 +172,11 @@ defmodule RDF.SerializationTest do test "without arguments, i.e. via file extension" do file = file("write_file_test.ttl") if File.exists?(file), do: File.rm(file) + assert RDF.Serialization.write_file(@example_graph, file, - prefixes: %{"" => EX.__base_iri__}) == :ok + prefixes: %{"" => EX.__base_iri__()} + ) == :ok + assert File.exists?(file) assert File.read!(file) == @example_graph_turtle File.rm(file) @@ -174,8 +185,12 @@ defmodule RDF.SerializationTest do test "with format name" do file = file("write_file_test.nt") if File.exists?(file), do: File.rm(file) - assert RDF.Serialization.write_file(@example_graph, file, format: :turtle, - prefixes: %{"" => EX.__base_iri__}) == :ok + + assert RDF.Serialization.write_file(@example_graph, file, + format: :turtle, + prefixes: %{"" => EX.__base_iri__()} + ) == :ok + assert File.exists?(file) assert File.read!(file) == @example_graph_turtle File.rm(file) @@ -186,8 +201,11 @@ defmodule RDF.SerializationTest do test "without arguments, i.e. via file extension" do file = file("write_file_test.ttl") if File.exists?(file), do: File.rm(file) + assert RDF.Serialization.write_file!(@example_graph, file, - prefixes: %{"" => EX.__base_iri__}) == :ok + prefixes: %{"" => EX.__base_iri__()} + ) == :ok + assert File.exists?(file) assert File.read!(file) == @example_graph_turtle File.rm(file) @@ -196,8 +214,12 @@ defmodule RDF.SerializationTest do test "with format name" do file = file("write_file_test.nt") if File.exists?(file), do: File.rm(file) - assert RDF.Serialization.write_file!(@example_graph, file, format: :turtle, - prefixes: %{"" => EX.__base_iri__}) == :ok + + assert RDF.Serialization.write_file!(@example_graph, file, + format: :turtle, + prefixes: %{"" => EX.__base_iri__()} + ) == :ok + assert File.exists?(file) assert File.read!(file) == @example_graph_turtle File.rm(file) diff --git a/test/unit/sigils_test.exs b/test/unit/sigils_test.exs index d9fa4cb..718f8ea 100644 --- a/test/unit/sigils_test.exs +++ b/test/unit/sigils_test.exs @@ -26,5 +26,4 @@ defmodule RDF.SigilsTest do assert ~L"foo"en == RDF.literal("foo", language: "en") end end - end diff --git a/test/unit/statement_test.exs b/test/unit/statement_test.exs index 14c0db7..1550afa 100644 --- a/test/unit/statement_test.exs +++ b/test/unit/statement_test.exs @@ -10,68 +10,68 @@ defmodule RDF.StatementTest do @invalid_literal XSD.integer("foo") @valid_triples [ - {@iri, @iri, @iri}, + {@iri, @iri, @iri}, {@bnode, @iri, @iri}, - {@iri, @iri, @bnode}, + {@iri, @iri, @bnode}, {@bnode, @iri, @bnode}, - {@iri, @iri, @valid_literal}, + {@iri, @iri, @valid_literal}, {@bnode, @iri, @valid_literal}, - {@iri, @iri, @invalid_literal}, - {@bnode, @iri, @invalid_literal}, + {@iri, @iri, @invalid_literal}, + {@bnode, @iri, @invalid_literal} ] @valid_quads [ - {@iri, @iri, @iri , @iri}, - {@bnode, @iri, @iri , @iri}, - {@iri, @iri, @bnode , @iri}, - {@bnode, @iri, @bnode , @iri}, - {@iri, @iri, @valid_literal , @iri}, - {@bnode, @iri, @valid_literal , @iri}, - {@iri, @iri, @invalid_literal, @iri}, - {@bnode, @iri, @invalid_literal, @iri}, + {@iri, @iri, @iri, @iri}, + {@bnode, @iri, @iri, @iri}, + {@iri, @iri, @bnode, @iri}, + {@bnode, @iri, @bnode, @iri}, + {@iri, @iri, @valid_literal, @iri}, + {@bnode, @iri, @valid_literal, @iri}, + {@iri, @iri, @invalid_literal, @iri}, + {@bnode, @iri, @invalid_literal, @iri} ] test "valid triples" do - Enum.each @valid_triples, fn argument -> + Enum.each(@valid_triples, fn argument -> assert RDF.Statement.valid?(argument) == true assert RDF.Triple.valid?(argument) == true refute RDF.Quad.valid?(argument) - end + end) end test "valid quads" do - Enum.each @valid_quads, fn argument -> + Enum.each(@valid_quads, fn argument -> assert RDF.Statement.valid?(argument) == true assert RDF.Quad.valid?(argument) == true refute RDF.Triple.valid?(argument) - end + end) end test "with invalid triples" do [ - {@iri, @bnode, @iri}, - {@valid_literal, @iri, @iri}, - {@iri, @valid_literal, @iri}, + {@iri, @bnode, @iri}, + {@valid_literal, @iri, @iri}, + {@iri, @valid_literal, @iri} ] |> Enum.each(fn argument -> - assert RDF.Statement.valid?(argument) == false - assert RDF.Triple.valid?(argument) == false - assert RDF.Quad.valid?(argument) == false - end) + assert RDF.Statement.valid?(argument) == false + assert RDF.Triple.valid?(argument) == false + assert RDF.Quad.valid?(argument) == false + end) end test "with invalid quads" do [ - {@iri, @bnode, @iri, @iri}, - {@iri, @iri, @iri, @bnode}, - {@valid_literal, @iri, @iri, @iri}, - {@iri, @valid_literal, @iri, @iri}, - {@iri, @iri , @iri, @valid_literal}, + {@iri, @bnode, @iri, @iri}, + {@iri, @iri, @iri, @bnode}, + {@valid_literal, @iri, @iri, @iri}, + {@iri, @valid_literal, @iri, @iri}, + {@iri, @iri, @iri, @valid_literal} ] |> Enum.each(fn argument -> - assert RDF.Statement.valid?(argument) == false - assert RDF.Triple.valid?(argument) == false - assert RDF.Quad.valid?(argument) == false + assert RDF.Statement.valid?(argument) == false + assert RDF.Triple.valid?(argument) == false + assert RDF.Quad.valid?(argument) == false end) end @@ -93,12 +93,12 @@ defmodule RDF.StatementTest do 42, "foo", @iri, - @bnode, + @bnode ] |> Enum.each(fn arg -> - refute RDF.Statement.valid?(arg) - refute RDF.Triple.valid?(arg) - refute RDF.Quad.valid?(arg) + refute RDF.Statement.valid?(arg) + refute RDF.Triple.valid?(arg) + refute RDF.Quad.valid?(arg) end) end end diff --git a/test/unit/term_test.exs b/test/unit/term_test.exs index 99fd074..70afd99 100644 --- a/test/unit/term_test.exs +++ b/test/unit/term_test.exs @@ -29,8 +29,8 @@ defmodule RDF.TermTest do end test "with boolean" do - assert RDF.Term.coerce(true) == XSD.true - assert RDF.Term.coerce(false) == XSD.false + assert RDF.Term.coerce(true) == XSD.true() + assert RDF.Term.coerce(false) == XSD.false() end test "with string" do @@ -51,19 +51,20 @@ defmodule RDF.TermTest do test "with datetime" do assert DateTime.from_iso8601("2002-04-02T12:00:00+00:00") |> elem(1) |> RDF.Term.coerce() == - DateTime.from_iso8601("2002-04-02T12:00:00+00:00") |> elem(1) |> XSD.datetime() + DateTime.from_iso8601("2002-04-02T12:00:00+00:00") |> elem(1) |> XSD.datetime() + assert ~N"2002-04-02T12:00:00" |> RDF.Term.coerce() == - ~N"2002-04-02T12:00:00" |> XSD.datetime() + ~N"2002-04-02T12:00:00" |> XSD.datetime() end test "with date" do assert ~D"2002-04-02" |> RDF.Term.coerce() == - ~D"2002-04-02" |> XSD.date() + ~D"2002-04-02" |> XSD.date() end test "with time" do assert ~T"12:00:00" |> RDF.Term.coerce() == - ~T"12:00:00" |> XSD.time() + ~T"12:00:00" |> XSD.time() end test "with reference" do @@ -126,7 +127,8 @@ defmodule RDF.TermTest do test "with datetime" do assert DateTime.from_iso8601("2002-04-02T12:00:00+00:00") |> elem(1) |> RDF.Term.value() == - DateTime.from_iso8601("2002-04-02T12:00:00+00:00") |> elem(1) + DateTime.from_iso8601("2002-04-02T12:00:00+00:00") |> elem(1) + assert ~N"2002-04-02T12:00:00" |> RDF.Term.value() == ~N"2002-04-02T12:00:00" end diff --git a/test/unit/triple_test.exs b/test/unit/triple_test.exs index bda63ca..cbd4500 100644 --- a/test/unit/triple_test.exs +++ b/test/unit/triple_test.exs @@ -7,8 +7,8 @@ defmodule RDF.TripleTest do describe "values/1" do test "with a valid RDF.Triple" do - assert Triple.values({~I, ~I, XSD.integer(42)}) - == {"http://example.com/S", "http://example.com/p", 42} + assert Triple.values({~I, ~I, XSD.integer(42)}) == + {"http://example.com/S", "http://example.com/p", 42} end test "with an invalid RDF.Triple" do @@ -20,10 +20,9 @@ defmodule RDF.TripleTest do test "values/2" do assert {~I, ~I, XSD.integer(42)} |> Triple.values(fn - {:object, object} -> object |> RDF.Term.value() |> Kernel.+(1) - {_, term} -> term |> to_string() |> String.last() - end) - == {"S", "p", 43} + {:object, object} -> object |> RDF.Term.value() |> Kernel.+(1) + {_, term} -> term |> to_string() |> String.last() + end) == + {"S", "p", 43} end - end diff --git a/test/unit/turtle_decoder_test.exs b/test/unit/turtle_decoder_test.exs index c0641fc..66c9dc3 100644 --- a/test/unit/turtle_decoder_test.exs +++ b/test/unit/turtle_decoder_test.exs @@ -9,396 +9,423 @@ defmodule RDF.Turtle.DecoderTest do use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.org/#", - terms: [], strict: false - - defvocab P, - base_iri: "http://www.perceive.net/schemas/relationship/", - terms: [], strict: false + defvocab EX, base_iri: "http://example.org/#", terms: [], strict: false + defvocab P, base_iri: "http://www.perceive.net/schemas/relationship/", terms: [], strict: false test "an empty string is deserialized to an empty graph" do - assert Turtle.Decoder.decode!("") == Graph.new - assert Turtle.Decoder.decode!(" \n\r\r\n ") == Graph.new + assert Turtle.Decoder.decode!("") == Graph.new() + assert Turtle.Decoder.decode!(" \n\r\r\n ") == Graph.new() end test "comments" do - assert Turtle.Decoder.decode!("# just a comment") == Graph.new + assert Turtle.Decoder.decode!("# just a comment") == Graph.new() assert Turtle.Decoder.decode!(""" - _:1 . # a comment - """) == Graph.new({EX.S, EX.p, RDF.bnode("1")}) + _:1 . # a comment + """) == Graph.new({EX.S, EX.p(), RDF.bnode("1")}) assert Turtle.Decoder.decode!(""" - # a comment - . - """) == Graph.new({EX.S, EX.p, EX.O}) + # a comment + . + """) == Graph.new({EX.S, EX.p(), EX.O}) assert Turtle.Decoder.decode!(""" - . - # a comment - """) == Graph.new({EX.S, EX.p, EX.O}) + . + # a comment + """) == Graph.new({EX.S, EX.p(), EX.O}) assert Turtle.Decoder.decode!(""" - # Header line 1 - # Header line 2 - . - # 1st comment - . # 2nd comment - # last comment - """) == Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p2, EX.O2}, - ]) + # Header line 1 + # Header line 2 + . + # 1st comment + . # 2nd comment + # last comment + """) == + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p2(), EX.O2} + ]) end test "empty lines" do assert Turtle.Decoder.decode!(""" - . - """) == Graph.new({EX.spiderman, P.enemyOf, EX.green_goblin}) + . + """) == Graph.new({EX.spiderman(), P.enemyOf(), EX.green_goblin()}) assert Turtle.Decoder.decode!(""" - . + . - """) == Graph.new({EX.spiderman, P.enemyOf, EX.green_goblin}) + """) == Graph.new({EX.spiderman(), P.enemyOf(), EX.green_goblin()}) assert Turtle.Decoder.decode!(""" - . + . - . + . - """) == Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p2, EX.O2}, - ]) + """) == + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p2(), EX.O2} + ]) end - describe "statements" do test "a N-Triple-style statement" do assert Turtle.Decoder.decode!( - " ." - ) == Graph.new({EX.Aaron, RDF.type, EX.Person}) + " ." + ) == Graph.new({EX.Aaron, RDF.type(), EX.Person}) end test "a statement with the 'a' keyword" do assert Turtle.Decoder.decode!(""" - a . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}) + a . + """) == Graph.new({EX.Aaron, RDF.type(), EX.Person}) end test "multiple N-Triple-style statement" do assert Turtle.Decoder.decode!(""" - . - . - """) == Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p2, EX.O2}, - ]) + . + . + """) == + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p2(), EX.O2} + ]) + assert Turtle.Decoder.decode!(""" - . - . - . - """) == Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p2, EX.O2}, - {EX.S2, EX.p3, EX.O3} - ]) + . + . + . + """) == + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p2(), EX.O2}, + {EX.S2, EX.p3(), EX.O3} + ]) end test "statement with multiple objects" do assert Turtle.Decoder.decode!(""" - "baz", 1, true . - """) == Graph.new([ - {EX.Foo, EX.bar, "baz"}, - {EX.Foo, EX.bar, 1}, - {EX.Foo, EX.bar, true}, - ]) + "baz", 1, true . + """) == + Graph.new([ + {EX.Foo, EX.bar(), "baz"}, + {EX.Foo, EX.bar(), 1}, + {EX.Foo, EX.bar(), true} + ]) end test "statement with multiple predications" do assert Turtle.Decoder.decode!(""" - "baz"; - 42 . - """) == Graph.new([ - {EX.Foo, EX.bar, "baz"}, - {EX.Foo, EX.baz, 42}, - ]) + "baz"; + 42 . + """) == + Graph.new([ + {EX.Foo, EX.bar(), "baz"}, + {EX.Foo, EX.baz(), 42} + ]) end end describe "blank node property lists" do test "blank node property list on object position" do assert Turtle.Decoder.decode!(""" - [ 42 ] . - """) == Graph.new([ - {EX.Foo, EX.bar, RDF.bnode("b0")}, - {RDF.bnode("b0"), EX.baz, 42}, - ]) + [ 42 ] . + """) == + Graph.new([ + {EX.Foo, EX.bar(), RDF.bnode("b0")}, + {RDF.bnode("b0"), EX.baz(), 42} + ]) end test "blank node property list on subject position" do assert Turtle.Decoder.decode!(""" - [ 42 ] false . - """) == Graph.new([ - {RDF.bnode("b0"), EX.baz, 42}, - {RDF.bnode("b0"), EX.bar, false}, - ]) + [ 42 ] false . + """) == + Graph.new([ + {RDF.bnode("b0"), EX.baz(), 42}, + {RDF.bnode("b0"), EX.bar(), false} + ]) end test "a single blank node property list" do assert Turtle.Decoder.decode!("[ 42 ] .") == - Graph.new([{RDF.bnode("b0"), EX.foo, 42}]) + Graph.new([{RDF.bnode("b0"), EX.foo(), 42}]) end test "nested blank node property list" do assert Turtle.Decoder.decode!(""" - [ [ ] ; ]. - """) == Graph.new([ - {RDF.bnode("b0"), EX.p1, RDF.bnode("b1")}, - {RDF.bnode("b1"), EX.p2, EX.o2}, - {RDF.bnode("b0"), EX.p, EX.o}, - ]) + [ [ ] ; ]. + """) == + Graph.new([ + {RDF.bnode("b0"), EX.p1(), RDF.bnode("b1")}, + {RDF.bnode("b1"), EX.p2(), EX.o2()}, + {RDF.bnode("b0"), EX.p(), EX.o()} + ]) end test "blank node via []" do assert Turtle.Decoder.decode!(""" - [] "Aaron Swartz" . - """) == Graph.new({RDF.bnode("b0"), ~I, "Aaron Swartz"}) + [] "Aaron Swartz" . + """) == + Graph.new({RDF.bnode("b0"), ~I, "Aaron Swartz"}) assert Turtle.Decoder.decode!(""" - [] . - """) == Graph.new({EX.Foo, EX.bar, RDF.bnode("b0")}) + [] . + """) == Graph.new({EX.Foo, EX.bar(), RDF.bnode("b0")}) assert Turtle.Decoder.decode!(""" - [ ] . - """) == Graph.new({EX.Foo, EX.bar, RDF.bnode("b0")}) + [ ] . + """) == Graph.new({EX.Foo, EX.bar(), RDF.bnode("b0")}) end end - test "blank node" do assert Turtle.Decoder.decode!(""" - _:foo . - """) == Graph.new({RDF.bnode("foo"), EX.p, EX.O}) + _:foo . + """) == Graph.new({RDF.bnode("foo"), EX.p(), EX.O}) + assert Turtle.Decoder.decode!(""" - _:1 . - """) == Graph.new({EX.S, EX.p, RDF.bnode("1")}) + _:1 . + """) == Graph.new({EX.S, EX.p(), RDF.bnode("1")}) + assert Turtle.Decoder.decode!(""" - _:foo _:bar . - """) == Graph.new({RDF.bnode("foo"), EX.p, RDF.bnode("bar")}) + _:foo _:bar . + """) == Graph.new({RDF.bnode("foo"), EX.p(), RDF.bnode("bar")}) end describe "quoted literals" do test "an untyped string literal" do assert Turtle.Decoder.decode!(""" - "Peter Parker" . - """) == Graph.new({EX.spiderman, P.realname, RDF.literal("Peter Parker")}) + "Peter Parker" . + """) == Graph.new({EX.spiderman(), P.realname(), RDF.literal("Peter Parker")}) end test "an untyped long quoted string literal" do assert Turtle.Decoder.decode!(""" - '''Peter Parker''' . - """) == Graph.new({EX.spiderman, P.realname, RDF.literal("Peter Parker")}) + '''Peter Parker''' . + """) == Graph.new({EX.spiderman(), P.realname(), RDF.literal("Peter Parker")}) end test "a typed literal" do assert Turtle.Decoder.decode!(""" - "42"^^ . - """) == Graph.new({EX.spiderman, EX.p, RDF.literal(42)}) + "42"^^ . + """) == Graph.new({EX.spiderman(), EX.p(), RDF.literal(42)}) end test "a typed literal with type as a prefixed name" do assert Turtle.Decoder.decode!(""" - PREFIX xsd: - "42"^^xsd:integer . - """) == Graph.new({EX.spiderman, EX.p, RDF.literal(42)}, prefixes: %{xsd: NS.XSD}) + PREFIX xsd: + "42"^^xsd:integer . + """) == + Graph.new({EX.spiderman(), EX.p(), RDF.literal(42)}, prefixes: %{xsd: NS.XSD}) end test "a language tagged literal" do assert Turtle.Decoder.decode!(""" - "foo"@en . - """) == Graph.new({EX.S, EX.p, RDF.literal("foo", language: "en")}) + "foo"@en . + """) == Graph.new({EX.S, EX.p(), RDF.literal("foo", language: "en")}) end test "a '@prefix' or '@base' language tagged literal" do assert Turtle.Decoder.decode!(""" - "foo"@prefix . - """) == Graph.new({EX.S, EX.p, RDF.literal("foo", language: "prefix")}) + "foo"@prefix . + """) == Graph.new({EX.S, EX.p(), RDF.literal("foo", language: "prefix")}) assert Turtle.Decoder.decode!(""" - "foo"@base . - """) == Graph.new({EX.S, EX.p, RDF.literal("foo", language: "base")}) + "foo"@base . + """) == Graph.new({EX.S, EX.p(), RDF.literal("foo", language: "base")}) end end describe "shorthand literals" do test "boolean" do assert Turtle.Decoder.decode!(""" - true . - """) == Graph.new({EX.Foo, EX.bar, XSD.true}) + true . + """) == Graph.new({EX.Foo, EX.bar(), XSD.true()}) + assert Turtle.Decoder.decode!(""" - false . - """) == Graph.new({EX.Foo, EX.bar, XSD.false}) + false . + """) == Graph.new({EX.Foo, EX.bar(), XSD.false()}) end test "integer" do assert Turtle.Decoder.decode!(""" - 42 . - """) == Graph.new({EX.Foo, EX.bar, XSD.integer(42)}) + 42 . + """) == Graph.new({EX.Foo, EX.bar(), XSD.integer(42)}) end test "decimal" do assert Turtle.Decoder.decode!(""" - 3.14 . - """) == Graph.new({EX.Foo, EX.bar, XSD.decimal("3.14")}) + 3.14 . + """) == Graph.new({EX.Foo, EX.bar(), XSD.decimal("3.14")}) end test "double" do assert Turtle.Decoder.decode!(""" - 1.2e3 . - """) == Graph.new({EX.Foo, EX.bar, XSD.double("1.2e3")}) + 1.2e3 . + """) == Graph.new({EX.Foo, EX.bar(), XSD.double("1.2e3")}) end end - describe "prefixed names" do test "non-empty prefixed names" do prefixes = RDF.PrefixMap.new(ex: ~I) - assert Turtle.Decoder.decode!(""" - @prefix ex: . - ex:Aaron ex:Person . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes) assert Turtle.Decoder.decode!(""" - @prefix ex: . - ex:Aaron ex:Person . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes) + @prefix ex: . + ex:Aaron ex:Person . + """) == Graph.new({EX.Aaron, RDF.type(), EX.Person}, prefixes: prefixes) assert Turtle.Decoder.decode!(""" - PREFIX ex: - ex:Aaron ex:Person . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes) + @prefix ex: . + ex:Aaron ex:Person . + """) == Graph.new({EX.Aaron, RDF.type(), EX.Person}, prefixes: prefixes) assert Turtle.Decoder.decode!(""" - prefix ex: - ex:Aaron ex:Person . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes) + PREFIX ex: + ex:Aaron ex:Person . + """) == Graph.new({EX.Aaron, RDF.type(), EX.Person}, prefixes: prefixes) + + assert Turtle.Decoder.decode!(""" + prefix ex: + ex:Aaron ex:Person . + """) == Graph.new({EX.Aaron, RDF.type(), EX.Person}, prefixes: prefixes) end test "empty prefixed name" do prefixes = RDF.PrefixMap.new("": ~I) - assert Turtle.Decoder.decode!(""" - @prefix : . - :Aaron :Person . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes) assert Turtle.Decoder.decode!(""" - PREFIX : - :Aaron :Person . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, prefixes: prefixes) + @prefix : . + :Aaron :Person . + """) == Graph.new({EX.Aaron, RDF.type(), EX.Person}, prefixes: prefixes) + + assert Turtle.Decoder.decode!(""" + PREFIX : + :Aaron :Person . + """) == Graph.new({EX.Aaron, RDF.type(), EX.Person}, prefixes: prefixes) end end describe "collections" do test "non-empty collection" do assert Turtle.Decoder.decode!(""" - @prefix : . - :subject :predicate ( :a :b :c ) . - """) == Graph.new([ - {EX.subject, EX.predicate, RDF.bnode("b0")}, - {RDF.bnode("b0"), RDF.first, EX.a}, - {RDF.bnode("b0"), RDF.rest, RDF.bnode("b1")}, - {RDF.bnode("b1"), RDF.first, EX.b}, - {RDF.bnode("b1"), RDF.rest, RDF.bnode("b2")}, - {RDF.bnode("b2"), RDF.first, EX.c}, - {RDF.bnode("b2"), RDF.rest, RDF.nil}, - ], prefixes: %{"": ~I}) + @prefix : . + :subject :predicate ( :a :b :c ) . + """) == + Graph.new( + [ + {EX.subject(), EX.predicate(), RDF.bnode("b0")}, + {RDF.bnode("b0"), RDF.first(), EX.a()}, + {RDF.bnode("b0"), RDF.rest(), RDF.bnode("b1")}, + {RDF.bnode("b1"), RDF.first(), EX.b()}, + {RDF.bnode("b1"), RDF.rest(), RDF.bnode("b2")}, + {RDF.bnode("b2"), RDF.first(), EX.c()}, + {RDF.bnode("b2"), RDF.rest(), RDF.nil()} + ], + prefixes: %{"": ~I} + ) end test "empty collection" do assert Turtle.Decoder.decode!(""" - @prefix : . - :subject :predicate () . - """) == Graph.new({EX.subject, EX.predicate, RDF.nil}, prefixes: %{"": ~I}) + @prefix : . + :subject :predicate () . + """) == + Graph.new({EX.subject(), EX.predicate(), RDF.nil()}, + prefixes: %{"": ~I} + ) end test "nested collection" do assert Turtle.Decoder.decode!(""" - @prefix : . - :subject :predicate ( :a (:b :c) ) . - """) == Graph.new([ - {EX.subject, EX.predicate, RDF.bnode("b0")}, - {RDF.bnode("b0"), RDF.first, EX.a}, - {RDF.bnode("b0"), RDF.rest, RDF.bnode("b3")}, - {RDF.bnode("b3"), RDF.first, RDF.bnode("b1")}, - {RDF.bnode("b3"), RDF.rest, RDF.nil}, - - {RDF.bnode("b1"), RDF.first, EX.b}, - {RDF.bnode("b1"), RDF.rest, RDF.bnode("b2")}, - {RDF.bnode("b2"), RDF.first, EX.c}, - {RDF.bnode("b2"), RDF.rest, RDF.nil}, - ], prefixes: %{"": ~I}) + @prefix : . + :subject :predicate ( :a (:b :c) ) . + """) == + Graph.new( + [ + {EX.subject(), EX.predicate(), RDF.bnode("b0")}, + {RDF.bnode("b0"), RDF.first(), EX.a()}, + {RDF.bnode("b0"), RDF.rest(), RDF.bnode("b3")}, + {RDF.bnode("b3"), RDF.first(), RDF.bnode("b1")}, + {RDF.bnode("b3"), RDF.rest(), RDF.nil()}, + {RDF.bnode("b1"), RDF.first(), EX.b()}, + {RDF.bnode("b1"), RDF.rest(), RDF.bnode("b2")}, + {RDF.bnode("b2"), RDF.first(), EX.c()}, + {RDF.bnode("b2"), RDF.rest(), RDF.nil()} + ], + prefixes: %{"": ~I} + ) end end - describe "relative IRIs" do test "without explicit in-doc base and no document_base option option given" do assert_raise RuntimeError, fn -> Turtle.Decoder.decode!( - "<#Aaron> <#Person> .") + "<#Aaron> <#Person> ." + ) end end test "without explicit in-doc base, but document_base option given" do - assert Turtle.Decoder.decode!(""" - <#Aaron> <#Person> . - """, base: "http://example.org/") == - Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I) + assert Turtle.Decoder.decode!( + """ + <#Aaron> <#Person> . + """, + base: "http://example.org/" + ) == + Graph.new({EX.Aaron, RDF.type(), EX.Person}, base_iri: ~I) end test "with @base given" do assert Turtle.Decoder.decode!(""" - @base . - <#Aaron> <#Person> . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I) + @base . + <#Aaron> <#Person> . + """) == + Graph.new({EX.Aaron, RDF.type(), EX.Person}, base_iri: ~I) assert Turtle.Decoder.decode!(""" - @base . - <#Aaron> <#Person> . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I) + @base . + <#Aaron> <#Person> . + """) == + Graph.new({EX.Aaron, RDF.type(), EX.Person}, base_iri: ~I) end test "with BASE given" do assert Turtle.Decoder.decode!(""" - BASE - <#Aaron> <#Person> . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I) + BASE + <#Aaron> <#Person> . + """) == + Graph.new({EX.Aaron, RDF.type(), EX.Person}, base_iri: ~I) assert Turtle.Decoder.decode!(""" - base - <#Aaron> <#Person> . - """) == Graph.new({EX.Aaron, RDF.type, EX.Person}, base_iri: ~I) + base + <#Aaron> <#Person> . + """) == + Graph.new({EX.Aaron, RDF.type(), EX.Person}, base_iri: ~I) end test "when a given base is itself relative" do assert_raise RuntimeError, fn -> Turtle.Decoder.decode!(""" - @base . - <#Aaron> <#Person> . - """) + @base . + <#Aaron> <#Person> . + """) end + assert_raise RuntimeError, fn -> Turtle.Decoder.decode!( "<#Aaron> <#Person> .", - base: "foo") + base: "foo" + ) end end end - end diff --git a/test/unit/turtle_encoder_test.exs b/test/unit/turtle_encoder_test.exs index 3032001..aa866bc 100644 --- a/test/unit/turtle_encoder_test.exs +++ b/test/unit/turtle_encoder_test.exs @@ -13,68 +13,76 @@ defmodule RDF.Turtle.EncoderTest do use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.org/#", - terms: [], strict: false - + defvocab EX, base_iri: "http://example.org/#", terms: [], strict: false describe "serializing a graph" do test "an empty graph is serialized to an empty string" do - assert Turtle.Encoder.encode!(Graph.new, prefixes: %{}) == "" + assert Turtle.Encoder.encode!(Graph.new(), prefixes: %{}) == "" end test "statements with IRIs only" do - assert Turtle.Encoder.encode!(Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p1, EX.O2}, - {EX.S1, EX.p2, EX.O3}, - {EX.S2, EX.p3, EX.O4}, - ]), prefixes: %{}) == - """ - - , ; - . + assert Turtle.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p1(), EX.O2}, + {EX.S1, EX.p2(), EX.O3}, + {EX.S2, EX.p3(), EX.O4} + ]), + prefixes: %{} + ) == + """ + + , ; + . - - . - """ + + . + """ end test "statements with prefixed names" do - assert Turtle.Encoder.encode!(Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p1, EX.O2}, - {EX.S1, EX.p2, EX.O3}, - {EX.S2, EX.p3, EX.O4}, - ]), prefixes: %{ - ex: EX.__base_iri__, - xsd: NS.XSD.__base_iri__ - }) == - """ - @prefix ex: <#{to_string(EX.__base_iri__)}> . - @prefix xsd: . + assert Turtle.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p1(), EX.O2}, + {EX.S1, EX.p2(), EX.O3}, + {EX.S2, EX.p3(), EX.O4} + ]), + prefixes: %{ + ex: EX.__base_iri__(), + xsd: NS.XSD.__base_iri__() + } + ) == + """ + @prefix ex: <#{to_string(EX.__base_iri__())}> . + @prefix xsd: . - ex:S1 - ex:p1 ex:O1, ex:O2 ; - ex:p2 ex:O3 . + ex:S1 + ex:p1 ex:O1, ex:O2 ; + ex:p2 ex:O3 . - ex:S2 - ex:p3 ex:O4 . - """ + ex:S2 + ex:p3 ex:O4 . + """ end test "when no prefixes are given, the prefixes from the given graph are used" do - assert Turtle.Encoder.encode!(Graph.new([ - {EX.S1, EX.p1, EX.O1}, - {EX.S1, EX.p1, EX.O2}, - {EX.S1, EX.p2, NS.XSD.integer}, - {EX.S2, EX.p3, EX.O4}, - ], prefixes: %{ - "": EX.__base_iri__, - xsd: NS.XSD.__base_iri__ - })) == + assert Turtle.Encoder.encode!( + Graph.new( + [ + {EX.S1, EX.p1(), EX.O1}, + {EX.S1, EX.p1(), EX.O2}, + {EX.S1, EX.p2(), NS.XSD.integer()}, + {EX.S2, EX.p3(), EX.O4} + ], + prefixes: %{ + "": EX.__base_iri__(), + xsd: NS.XSD.__base_iri__() + } + ) + ) == """ - @prefix : <#{to_string(EX.__base_iri__)}> . + @prefix : <#{to_string(EX.__base_iri__())}> . @prefix xsd: . :S1 @@ -87,31 +95,40 @@ defmodule RDF.Turtle.EncoderTest do end test "when no base IRI is given, the base IRI from the given graph is used" do - assert Turtle.Encoder.encode!(Graph.new([{EX.S1, EX.p1, EX.O1}], prefixes: %{}, - base_iri: EX.__base_iri__)) == + assert Turtle.Encoder.encode!( + Graph.new([{EX.S1, EX.p1(), EX.O1}], + prefixes: %{}, + base_iri: EX.__base_iri__() + ) + ) == """ - @base <#{to_string(EX.__base_iri__)}> . + @base <#{to_string(EX.__base_iri__())}> . . """ end test "when a base IRI is given, it has used instead of the base IRI of the given graph" do - assert Turtle.Encoder.encode!(Graph.new([{EX.S1, EX.p1, EX.O1}], prefixes: %{}, - base_iri: EX.other), base_iri: EX.__base_iri__) == + assert Turtle.Encoder.encode!( + Graph.new([{EX.S1, EX.p1(), EX.O1}], + prefixes: %{}, + base_iri: EX.other() + ), + base_iri: EX.__base_iri__() + ) == """ - @base <#{to_string(EX.__base_iri__)}> . + @base <#{to_string(EX.__base_iri__())}> . . """ end test "when no prefixes are given and no prefixes are in the given graph the default_prefixes are used" do - assert Turtle.Encoder.encode!(Graph.new({EX.S, EX.p, NS.XSD.string})) == + assert Turtle.Encoder.encode!(Graph.new({EX.S, EX.p(), NS.XSD.string()})) == """ - @prefix rdf: <#{to_string(RDF.__base_iri__)}> . - @prefix rdfs: <#{to_string(RDFS.__base_iri__)}> . - @prefix xsd: <#{to_string(NS.XSD.__base_iri__)}> . + @prefix rdf: <#{to_string(RDF.__base_iri__())}> . + @prefix rdfs: <#{to_string(RDFS.__base_iri__())}> . + @prefix xsd: <#{to_string(NS.XSD.__base_iri__())}> . xsd:string . @@ -119,112 +136,119 @@ defmodule RDF.Turtle.EncoderTest do end test "statements with empty prefixed names" do - assert Turtle.Encoder.encode!(Graph.new({EX.S, EX.p, EX.O}), - prefixes: %{"" => EX.__base_iri__}) == - """ - @prefix : <#{to_string(EX.__base_iri__)}> . + assert Turtle.Encoder.encode!(Graph.new({EX.S, EX.p(), EX.O}), + prefixes: %{"" => EX.__base_iri__()} + ) == + """ + @prefix : <#{to_string(EX.__base_iri__())}> . - :S - :p :O . - """ + :S + :p :O . + """ end test "statements with literals" do - assert Turtle.Encoder.encode!(Graph.new([ - {EX.S1, EX.p1, ~L"foo"}, - {EX.S1, EX.p1, ~L"foo"en}, - {EX.S2, EX.p2, RDF.literal("strange things", datatype: EX.custom)}, - ]), prefixes: %{}) == - """ - - "foo"@en, "foo" . + assert Turtle.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), ~L"foo"}, + {EX.S1, EX.p1(), ~L"foo"en}, + {EX.S2, EX.p2(), RDF.literal("strange things", datatype: EX.custom())} + ]), + prefixes: %{} + ) == + """ + + "foo"@en, "foo" . - - "strange things"^^<#{EX.custom}> . - """ + + "strange things"^^<#{EX.custom()}> . + """ end test "statements with blank nodes" do - assert Turtle.Encoder.encode!(Graph.new([ - {EX.S1, EX.p1, [RDF.bnode(1), RDF.bnode("foo"), RDF.bnode(:bar)]}, - {EX.S2, EX.p1, [RDF.bnode(1), RDF.bnode("foo"), RDF.bnode(:bar)]}, - ]), prefixes: %{}) == - """ - - _:1, _:bar, _:foo . + assert Turtle.Encoder.encode!( + Graph.new([ + {EX.S1, EX.p1(), [RDF.bnode(1), RDF.bnode("foo"), RDF.bnode(:bar)]}, + {EX.S2, EX.p1(), [RDF.bnode(1), RDF.bnode("foo"), RDF.bnode(:bar)]} + ]), + prefixes: %{} + ) == + """ + + _:1, _:bar, _:foo . - - _:1, _:bar, _:foo . - """ + + _:1, _:bar, _:foo . + """ end test "ordering of descriptions" do - assert Turtle.Encoder.encode!(Graph.new([ - {EX.__base_iri__, RDF.type, OWL.Ontology}, - {EX.S1, RDF.type, EX.O}, - {EX.S2, RDF.type, RDFS.Class}, - {EX.S3, RDF.type, RDF.Property}, - ]), - base_iri: EX.__base_iri__, - prefixes: %{ - rdf: RDF.__base_iri__, - rdfs: RDFS.__base_iri__, - owl: OWL.__base_iri__, - }) == - """ - @base <#{to_string(EX.__base_iri__)}> . - @prefix rdf: <#{to_string(RDF.__base_iri__)}> . - @prefix rdfs: <#{to_string(RDFS.__base_iri__)}> . - @prefix owl: <#{to_string(OWL.__base_iri__)}> . + assert Turtle.Encoder.encode!( + Graph.new([ + {EX.__base_iri__(), RDF.type(), OWL.Ontology}, + {EX.S1, RDF.type(), EX.O}, + {EX.S2, RDF.type(), RDFS.Class}, + {EX.S3, RDF.type(), RDF.Property} + ]), + base_iri: EX.__base_iri__(), + prefixes: %{ + rdf: RDF.__base_iri__(), + rdfs: RDFS.__base_iri__(), + owl: OWL.__base_iri__() + } + ) == + """ + @base <#{to_string(EX.__base_iri__())}> . + @prefix rdf: <#{to_string(RDF.__base_iri__())}> . + @prefix rdfs: <#{to_string(RDFS.__base_iri__())}> . + @prefix owl: <#{to_string(OWL.__base_iri__())}> . - <> - a owl:Ontology . + <> + a owl:Ontology . - - a rdfs:Class . + + a rdfs:Class . - - a . + + a . - - a rdf:Property . - """ + + a rdf:Property . + """ end end - describe "prefixed_name/2" do setup do {:ok, - prefixes: %{ - RDF.iri(EX.__base_iri__) => "ex", - ~I => "ex2" - } - } + prefixes: %{ + RDF.iri(EX.__base_iri__()) => "ex", + ~I => "ex2" + }} end test "hash iri with existing prefix", %{prefixes: prefixes} do - assert Turtle.Encoder.prefixed_name(EX.foo, prefixes) == - "ex:foo" + assert Turtle.Encoder.prefixed_name(EX.foo(), prefixes) == + "ex:foo" end test "hash iri namespace without name", %{prefixes: prefixes} do - assert Turtle.Encoder.prefixed_name(RDF.iri(EX.__base_iri__), prefixes) == - "ex:" + assert Turtle.Encoder.prefixed_name(RDF.iri(EX.__base_iri__()), prefixes) == + "ex:" end test "hash iri with non-existing prefix" do - refute Turtle.Encoder.prefixed_name(EX.foo, %{}) + refute Turtle.Encoder.prefixed_name(EX.foo(), %{}) end test "slash iri with existing prefix", %{prefixes: prefixes} do assert Turtle.Encoder.prefixed_name(~I, prefixes) == - "ex2:foo" + "ex2:foo" end test "slash iri namespace without name", %{prefixes: prefixes} do assert Turtle.Encoder.prefixed_name(~I, prefixes) == - "ex2:" + "ex2:" end test "slash iri with non-existing prefix" do @@ -232,15 +256,14 @@ defmodule RDF.Turtle.EncoderTest do end end - %{ "full IRIs without base" => %{ input: " .", - matches: [~r(\s+\s+\s+\.)], + matches: [~r(\s+\s+\s+\.)] }, "relative IRIs with base" => %{ input: " .", - matches: [ ~r(@base\s+\s+\.), ~r(\s+\s+\s+\.)m], + matches: [~r(@base\s+\s+\.), ~r(\s+\s+\s+\.)m], base_iri: "http://a/" }, "pname IRIs with prefix" => %{ @@ -253,7 +276,7 @@ defmodule RDF.Turtle.EncoderTest do }, "pname IRIs with empty prefix" => %{ input: " .", - matches: [ + matches: [ ~r(@prefix\s+:\s+\s+\.), ~r(:b\s+:c\s+:d\s+\.) ], @@ -263,7 +286,7 @@ defmodule RDF.Turtle.EncoderTest do input: "@prefix ex: . ex:b ex:c ex:d, ex:e .", matches: [ ~r(@prefix\s+ex:\s+\s+\.), - ~r(ex:b\s+ex:c\s+ex:[de],\s++ex:[de]\s+\.)m, + ~r(ex:b\s+ex:c\s+ex:[de],\s++ex:[de]\s+\.)m ], prefixes: %{"ex" => "http://example.com/"} }, @@ -301,24 +324,24 @@ defmodule RDF.Turtle.EncoderTest do prefixes: %{"ex" => "http://example.com/"} }, -# "generated BNodes with :unique_bnodes" => %{ -# input: "@prefix ex: . _:a ex:b _:a .", -# matches: [~r(^\s+*_:g\w+\s+ex:b\s+_:g\w+\s+\.$)], -# unique_bnodes: true -# }, -# "standard prefixes" => %{ -# input: """ -# a ; -# "Person" . -# """, -# matches: [ -# ~r(^@prefix foaf: \.$), -# ~r(^@prefix dc: \.$), -# ~r(^ a foaf:Person;$), -# ~r(dc:title "Person" \.$), -# ], -# standard_prefixes: true, prefixes: %{} -# } + # "generated BNodes with :unique_bnodes" => %{ + # input: "@prefix ex: . _:a ex:b _:a .", + # matches: [~r(^\s+*_:g\w+\s+ex:b\s+_:g\w+\s+\.$)], + # unique_bnodes: true + # }, + # "standard prefixes" => %{ + # input: """ + # a ; + # "Person" . + # """, + # matches: [ + # ~r(^@prefix foaf: \.$), + # ~r(^@prefix dc: \.$), + # ~r(^ a foaf:Person;$), + # ~r(dc:title "Person" \.$), + # ], + # standard_prefixes: true, prefixes: %{} + # } "order properties" => %{ input: """ @prefix ex: . @@ -336,19 +359,18 @@ defmodule RDF.Turtle.EncoderTest do ~r(ex:d\s*;\s+dc:title\s+"title"\s+\.)m ], prefixes: %{ - "ex" => "http://example.com/", - "dc" => "http://purl.org/dc/elements/1.1/", - "rdfs" => "http://www.w3.org/2000/01/rdf-schema#", + "ex" => "http://example.com/", + "dc" => "http://purl.org/dc/elements/1.1/", + "rdfs" => "http://www.w3.org/2000/01/rdf-schema#" } - }, + } } |> Enum.each(fn {name, data} -> - @tag data: data - test name, %{data: data} do - assert_serialization Turtle.read_string!(data.input), Keyword.new(data) - end - end) - + @tag data: data + test name, %{data: data} do + assert_serialization(Turtle.read_string!(data.input), Keyword.new(data)) + end + end) describe "lists" do test "should generate literal list" do @@ -356,64 +378,62 @@ defmodule RDF.Turtle.EncoderTest do ~s[@prefix ex: . ex:a ex:b ( "apple" "banana" ) .] ) |> assert_serialization( - prefixes: %{ex: ~I}, - matches: [ - {~r[ex:a\s+ex:b\s+\("apple" "banana"\)\s+\.], "doesn't include the list as a Turtle list"} - ] - ) + prefixes: %{ex: ~I}, + matches: [ + {~r[ex:a\s+ex:b\s+\("apple" "banana"\)\s+\.], + "doesn't include the list as a Turtle list"} + ] + ) end test "should generate empty list" do - Turtle.read_string!( - ~s[@prefix ex: . ex:a ex:b () .] - ) + Turtle.read_string!(~s[@prefix ex: . ex:a ex:b () .]) |> assert_serialization( - prefixes: %{ex: ~I}, - matches: [ - {~r[ex:a\s+ex:b\s+\(\)\s+\.], "doesn't include the list as a Turtle list"} - ] - ) + prefixes: %{ex: ~I}, + matches: [ + {~r[ex:a\s+ex:b\s+\(\)\s+\.], "doesn't include the list as a Turtle list"} + ] + ) end test "should generate empty list as subject" do - Turtle.read_string!( - ~s[@prefix ex: . () ex:a ex:b .] - ) + Turtle.read_string!(~s[@prefix ex: . () ex:a ex:b .]) |> assert_serialization( - prefixes: %{ex: ~I}, - matches: [ - {~r[\(\)\s+ex:a\s+ex:b\s+\.], "doesn't include the list as a Turtle list"} - ] - ) + prefixes: %{ex: ~I}, + matches: [ + {~r[\(\)\s+ex:a\s+ex:b\s+\.], "doesn't include the list as a Turtle list"} + ] + ) end test "should generate list as subject" do - Turtle.read_string!( - ~s[@prefix ex: . (ex:a) ex:b ex:c .] - ) + Turtle.read_string!(~s[@prefix ex: . (ex:a) ex:b ex:c .]) |> assert_serialization( - prefixes: %{ex: ~I}, - matches: [ - {~r[\(ex:a\)\s+ex:b\s+ex:c\s+\.], "doesn't include the list as a Turtle list"} - ] - ) + prefixes: %{ex: ~I}, + matches: [ + {~r[\(ex:a\)\s+ex:b\s+ex:c\s+\.], "doesn't include the list as a Turtle list"} + ] + ) end test "should generate list of empties" do - graph = Turtle.read_string!( - ~s{@prefix ex: . [ex:listOf2Empties (() ())] .} - ) - serialization = - assert_serialization graph, - prefixes: %{ex: ~I}, - matches: [ - {~r[\[\s*ex:listOf2Empties \(\(\) \(\)\)\s\]\s+\.], "doesn't include the list as a Turtle list"} - ] + graph = + Turtle.read_string!(~s{@prefix ex: . [ex:listOf2Empties (() ())] .}) - refute String.contains?(serialization, to_string(RDF.first)), - ~s[output\n\n#{serialization}\n\ncontains #{to_string(RDF.first)}] - refute String.contains?(serialization, to_string(RDF.rest)), - ~s[output\n\n#{serialization}\n\ncontains #{to_string(RDF.rest)}] + serialization = + assert_serialization(graph, + prefixes: %{ex: ~I}, + matches: [ + {~r[\[\s*ex:listOf2Empties \(\(\) \(\)\)\s\]\s+\.], + "doesn't include the list as a Turtle list"} + ] + ) + + refute String.contains?(serialization, to_string(RDF.first())), + ~s[output\n\n#{serialization}\n\ncontains #{to_string(RDF.first())}] + + refute String.contains?(serialization, to_string(RDF.rest())), + ~s[output\n\n#{serialization}\n\ncontains #{to_string(RDF.rest())}] end test "should generate list anon" do @@ -421,105 +441,100 @@ defmodule RDF.Turtle.EncoderTest do ~s{@prefix ex: . [ex:twoAnons ([a ex:mother] [a ex:father])] .} ) |> assert_serialization( - prefixes: %{ex: ~I}, - matches: [ - {~r[\[\s*ex:twoAnons \(\[\s*a ex:mother\s*\]\s+\[\s*a ex:father\s*\]\s*\)\s*\]\s+\.], - "doesn't include the list as a Turtle list"} - ] - ) + prefixes: %{ex: ~I}, + matches: [ + {~r[\[\s*ex:twoAnons \(\[\s*a ex:mother\s*\]\s+\[\s*a ex:father\s*\]\s*\)\s*\]\s+\.], + "doesn't include the list as a Turtle list"} + ] + ) end -# TODO: Why should this test from RDF.rb work? Why should the `a owl:Class` statements about the list nodes be ignored? -# test "should generate owl:unionOf list" do -# Turtle.read_string!(""" -# @prefix ex: . -# @prefix owl: . -# @prefix rdf: . -# @prefix rdfs: . -# ex:a rdfs:domain [ -# a owl:Class; -# owl:unionOf [ -# a owl:Class; -# rdf:first ex:b; -# rdf:rest [ -# a owl:Class; -# rdf:first ex:c; -# rdf:rest rdf:nil -# ] -# ] -# ] . -# """) -# |> assert_serialization( -# prefixes: %{ -# ex: ~I, -# rdf: RDF.NS.RDF.__base_iri__, -# rdfs: RDFS.__base_iri__, -# owl: OWL.__base_iri__, -# }, -# matches: [ -# {~r[ex:a\s+rdfs:domain \[\s+a owl:Class;\s+owl:unionOf\s+\(ex:b\s+ex:c\)\s*\]\s*\.], -# "doesn't include the list as a Turtle list"} -# ] -# ) -# -# end + # TODO: Why should this test from RDF.rb work? Why should the `a owl:Class` statements about the list nodes be ignored? + # test "should generate owl:unionOf list" do + # Turtle.read_string!(""" + # @prefix ex: . + # @prefix owl: . + # @prefix rdf: . + # @prefix rdfs: . + # ex:a rdfs:domain [ + # a owl:Class; + # owl:unionOf [ + # a owl:Class; + # rdf:first ex:b; + # rdf:rest [ + # a owl:Class; + # rdf:first ex:c; + # rdf:rest rdf:nil + # ] + # ] + # ] . + # """) + # |> assert_serialization( + # prefixes: %{ + # ex: ~I, + # rdf: RDF.NS.RDF.__base_iri__, + # rdfs: RDFS.__base_iri__, + # owl: OWL.__base_iri__, + # }, + # matches: [ + # {~r[ex:a\s+rdfs:domain \[\s+a owl:Class;\s+owl:unionOf\s+\(ex:b\s+ex:c\)\s*\]\s*\.], + # "doesn't include the list as a Turtle list"} + # ] + # ) + # + # end test "when one of the list nodes is referenced in other statements the whole list is not represented as a Turtle list structure" do Graph.new( - ~B - |> RDF.first(EX.Foo) - |> RDF.rest(~B)) + ~B + |> RDF.first(EX.Foo) + |> RDF.rest(~B) + ) |> Graph.add( - ~B - |> RDF.first(EX.Bar) - |> RDF.rest(RDF.nil)) - |> Graph.add({EX.Baz, EX.quux, ~B}) + ~B + |> RDF.first(EX.Bar) + |> RDF.rest(RDF.nil()) + ) + |> Graph.add({EX.Baz, EX.quux(), ~B}) |> assert_serialization( - prefixes: %{ex: EX.__base_iri__}, - # TODO: provide a positive match - neg_matches: [ - {~r[\(\s*ex:Foo\s+ex:Bar\s*\)], "does include the list as a Turtle list"} - ] - ) + prefixes: %{ex: EX.__base_iri__()}, + # TODO: provide a positive match + neg_matches: [ + {~r[\(\s*ex:Foo\s+ex:Bar\s*\)], "does include the list as a Turtle list"} + ] + ) end test "when given an invalid list" do Graph.new( - ~B - |> RDF.first(1) - |> RDF.rest(EX.Foo) + ~B + |> RDF.first(1) + |> RDF.rest(EX.Foo) ) |> assert_serialization( - prefixes: %{ex: ~I}, - # TODO: provide a positive match - neg_matches: [ - {~r[\[\s*_:Foo \(\(\) \(\)\)\]\s+\.], "does include the invalid list as a Turtle list"} - ] - ) + prefixes: %{ex: ~I}, + # TODO: provide a positive match + neg_matches: [ + {~r[\[\s*_:Foo \(\(\) \(\)\)\]\s+\.], "does include the invalid list as a Turtle list"} + ] + ) end end - describe "literals" do test "plain literals with newlines embedded are encoded with long quotes" do - Turtle.read_string!( - ~s[ """testing string parsing in Turtle. - """ .] - ) - |> assert_serialization( - matches: [~s["""testing string parsing in Turtle.\n]] - ) + Turtle.read_string!(~s[ """testing string parsing in Turtle. + """ .]) + |> assert_serialization(matches: [~s["""testing string parsing in Turtle.\n]]) end test "plain literals escaping" do - Turtle.read_string!( - ~s[ """string with " escaped quote marks""" .] - ) + Turtle.read_string!(~s[ """string with " escaped quote marks""" .]) |> assert_serialization( - matches: [ - ~r[string with \\" escaped quote mark] - ] - ) + matches: [ + ~r[string with \\" escaped quote mark] + ] + ) end test "language tagged literals specifies language for literal with language" do @@ -532,10 +547,10 @@ defmodule RDF.Turtle.EncoderTest do ~s[@prefix xsd: . "http://foo/"^^xsd:anyURI .] ) |> assert_serialization( - matches: [ - ~r["http://foo/"\^\^ \.] - ] - ) + matches: [ + ~r["http://foo/"\^\^ \.] + ] + ) end test "typed literals use declared prefixes" do @@ -543,174 +558,175 @@ defmodule RDF.Turtle.EncoderTest do ~s[@prefix xsd: . "http://foo/"^^xsd:anyURI .] ) |> assert_serialization( - matches: [ - ~r[@prefix xsd: \.], - ~r["http://foo/"\^\^xsd:anyURI \.] - ], - prefixes: %{xsd: NS.XSD.__base_iri__} - ) + matches: [ + ~r[@prefix xsd: \.], + ~r["http://foo/"\^\^xsd:anyURI \.] + ], + prefixes: %{xsd: NS.XSD.__base_iri__()} + ) end test "valid booleans" do [ - {true, "true ."}, - {"true", "true ."}, - {"1", "true ."}, - {false, "false ."}, + {true, "true ."}, + {"true", "true ."}, + {"1", "true ."}, + {false, "false ."}, {"false", "false ."}, - {"0", "false ."}, + {"0", "false ."} ] |> Enum.each(fn {value, output} -> - Graph.new({EX.S, EX.p, RDF.XSD.boolean(value)}) - |> assert_serialization(matches: [output]) - end) + Graph.new({EX.S, EX.p(), RDF.XSD.boolean(value)}) + |> assert_serialization(matches: [output]) + end) end test "invalid booleans" do [ {"string", ~s{"string"^^}}, - {"42", ~s{"42"^^}}, - {"TrUe", ~s{"TrUe"^^}}, - {"FaLsE", ~s{"FaLsE"^^}}, + {"42", ~s{"42"^^}}, + {"TrUe", ~s{"TrUe"^^}}, + {"FaLsE", ~s{"FaLsE"^^}} ] |> Enum.each(fn {value, output} -> - Graph.new({EX.S, EX.p, RDF.XSD.boolean(value)}) - |> assert_serialization(matches: [output]) - end) + Graph.new({EX.S, EX.p(), RDF.XSD.boolean(value)}) + |> assert_serialization(matches: [output]) + end) end test "valid integers" do [ - {0, "0 ."}, - {"0", "0 ."}, - {1, "1 ."}, - {"1", "1 ."}, - {-1, "-1 ."}, - {"-1", "-1 ."}, - {10, "10 ."}, - {"10", "10 ."}, - {"0010", "10 ."}, + {0, "0 ."}, + {"0", "0 ."}, + {1, "1 ."}, + {"1", "1 ."}, + {-1, "-1 ."}, + {"-1", "-1 ."}, + {10, "10 ."}, + {"10", "10 ."}, + {"0010", "10 ."} ] |> Enum.each(fn {value, output} -> - Graph.new({EX.S, EX.p, RDF.XSD.integer(value)}) - |> assert_serialization(matches: [output]) - end) + Graph.new({EX.S, EX.p(), RDF.XSD.integer(value)}) + |> assert_serialization(matches: [output]) + end) end test "invalid integers" do [ {"string", ~s{"string"^^}}, - {"true", ~s{"true"^^}}, + {"true", ~s{"true"^^}} ] |> Enum.each(fn {value, output} -> - Graph.new({EX.S, EX.p, RDF.XSD.integer(value)}) - |> assert_serialization(matches: [output]) - end) + Graph.new({EX.S, EX.p(), RDF.XSD.integer(value)}) + |> assert_serialization(matches: [output]) + end) end test "valid decimals" do [ - {1.0, "1.0 ."}, - {"1.0", "1.0 ."}, - {0.1, "0.1 ."}, - {"0.1", "0.1 ."}, - {-1, "-1.0 ."}, - {"-1", "-1.0 ."}, - {10.02, "10.02 ."}, - {"10.02", "10.02 ."}, - {"010.020", "10.02 ."}, + {1.0, "1.0 ."}, + {"1.0", "1.0 ."}, + {0.1, "0.1 ."}, + {"0.1", "0.1 ."}, + {-1, "-1.0 ."}, + {"-1", "-1.0 ."}, + {10.02, "10.02 ."}, + {"10.02", "10.02 ."}, + {"010.020", "10.02 ."} ] |> Enum.each(fn {value, output} -> - Graph.new({EX.S, EX.p, RDF.XSD.decimal(value)}) - |> assert_serialization(matches: [output]) - end) + Graph.new({EX.S, EX.p(), RDF.XSD.decimal(value)}) + |> assert_serialization(matches: [output]) + end) end test "invalid decimals" do [ {"string", ~s{"string"^^}}, - {"true", ~s{"true"^^}}, + {"true", ~s{"true"^^}} ] |> Enum.each(fn {value, output} -> - Graph.new({EX.S, EX.p, RDF.XSD.decimal(value)}) - |> assert_serialization(matches: [output]) - end) + Graph.new({EX.S, EX.p(), RDF.XSD.decimal(value)}) + |> assert_serialization(matches: [output]) + end) end test "valid doubles" do [ - {1.0e1, "1.0E1 ."}, - {"1.0e1", "1.0E1 ."}, - {0.1e1, "1.0E0 ."}, - {"0.1e1", "1.0E0 ."}, - {10.02e1, "1.002E2 ."}, - {"10.02e1", "1.002E2 ."}, - {"010.020", "1.002E1 ."}, - {14, "1.4E1 ."}, - {-1, "-1.0E0 ."}, - {"-1", "-1.0E0 ."}, + {1.0e1, "1.0E1 ."}, + {"1.0e1", "1.0E1 ."}, + {0.1e1, "1.0E0 ."}, + {"0.1e1", "1.0E0 ."}, + {10.02e1, "1.002E2 ."}, + {"10.02e1", "1.002E2 ."}, + {"010.020", "1.002E1 ."}, + {14, "1.4E1 ."}, + {-1, "-1.0E0 ."}, + {"-1", "-1.0E0 ."} ] |> Enum.each(fn {value, output} -> - Graph.new({EX.S, EX.p, RDF.XSD.double(value)}) - |> assert_serialization(matches: [output]) - end) + Graph.new({EX.S, EX.p(), RDF.XSD.double(value)}) + |> assert_serialization(matches: [output]) + end) end test "invalid doubles" do [ {"string", ~s{"string"^^}}, - {"true", ~s{"true"^^}}, + {"true", ~s{"true"^^}} ] |> Enum.each(fn {value, output} -> - Graph.new({EX.S, EX.p, RDF.XSD.double(value)}) - |> assert_serialization(matches: [output]) - end) + Graph.new({EX.S, EX.p(), RDF.XSD.double(value)}) + |> assert_serialization(matches: [output]) + end) end end - describe "W3C test suite roundtrip" do @tag skip: "TODO: We need a Graph isomorphism comparison to implement this." test "..." end - defp assert_serialization(graph, opts) do - with prefixes = Keyword.get(opts, :prefixes, %{}), - base_iri = Keyword.get(opts, :base_iri), - matches = Keyword.get(opts, :matches, []), - neg_matches = Keyword.get(opts, :neg_matches, []) - do + with prefixes = Keyword.get(opts, :prefixes, %{}), + base_iri = Keyword.get(opts, :base_iri), + matches = Keyword.get(opts, :matches, []), + neg_matches = Keyword.get(opts, :neg_matches, []) do assert {:ok, serialized} = - Turtle.write_string(graph, prefixes: prefixes, base_iri: base_iri) + Turtle.write_string(graph, prefixes: prefixes, base_iri: base_iri) matches |> Stream.map(fn - {pattern, message} -> - {pattern, ~s[output\n\n#{serialized}\n\n#{message}]} - pattern -> - {pattern, ~s[output\n\n#{serialized}\n\ndoesn't include #{inspect pattern}]} - end) + {pattern, message} -> + {pattern, ~s[output\n\n#{serialized}\n\n#{message}]} + + pattern -> + {pattern, ~s[output\n\n#{serialized}\n\ndoesn't include #{inspect(pattern)}]} + end) |> Enum.each(fn - {%Regex{} = pattern, message} -> - assert Regex.match?(pattern, serialized), message - {contents, message} -> - assert String.contains?(serialized, contents), message - end) + {%Regex{} = pattern, message} -> + assert Regex.match?(pattern, serialized), message + + {contents, message} -> + assert String.contains?(serialized, contents), message + end) neg_matches |> Stream.map(fn - {pattern, message} -> - {pattern, ~s[output\n\n#{serialized}\n\n#{message}]} - pattern -> - {pattern, ~s[output\n\n#{serialized}\n\ndoes include #{inspect pattern}]} - end) + {pattern, message} -> + {pattern, ~s[output\n\n#{serialized}\n\n#{message}]} + + pattern -> + {pattern, ~s[output\n\n#{serialized}\n\ndoes include #{inspect(pattern)}]} + end) |> Enum.each(fn - {%Regex{} = pattern, message} -> - refute Regex.match?(pattern, serialized), message - {contents, message} -> - refute String.contains?(serialized, contents), message - end) + {%Regex{} = pattern, message} -> + refute Regex.match?(pattern, serialized), message + + {contents, message} -> + refute String.contains?(serialized, contents), message + end) serialized end diff --git a/test/unit/vocabulary_namespace_test.exs b/test/unit/vocabulary_namespace_test.exs index f95df60..6a9f612 100644 --- a/test/unit/vocabulary_namespace_test.exs +++ b/test/unit/vocabulary_namespace_test.exs @@ -11,22 +11,25 @@ defmodule RDF.Vocabulary.NamespaceTest do @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.TestNS.ExampleFromGraph} @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.TestNS.ExampleFromNTriplesFile} @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.TestNS.NonStrictExampleFromTerms} - @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.TestNS.NonStrictExampleFromAliasedTerms} + @compile {:no_warn_undefined, + RDF.Vocabulary.NamespaceTest.TestNS.NonStrictExampleFromAliasedTerms} @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.TestNS.StrictExampleFromTerms} @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.NSofEdgeCases.Example} @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.NSWithAliasesForElixirTerms.Example} @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.NSwithUnderscoreTerms.Example} - @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.NSWithIgnoredTerms.ExampleIgnoredLowercasedTerm} - @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.NSWithIgnoredTerms.ExampleIgnoredNonStrictLowercasedTerm} - @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.NSWithIgnoredTerms.ExampleIgnoredLowercasedTermWithAlias} - @compile {:no_warn_undefined, RDF.Vocabulary.NamespaceTest.NSWithIgnoredTerms.ExampleIgnoredLowercasedAlias} + @compile {:no_warn_undefined, + RDF.Vocabulary.NamespaceTest.NSWithIgnoredTerms.ExampleIgnoredLowercasedTerm} + @compile {:no_warn_undefined, + RDF.Vocabulary.NamespaceTest.NSWithIgnoredTerms.ExampleIgnoredNonStrictLowercasedTerm} + @compile {:no_warn_undefined, + RDF.Vocabulary.NamespaceTest.NSWithIgnoredTerms.ExampleIgnoredLowercasedTermWithAlias} + @compile {:no_warn_undefined, + RDF.Vocabulary.NamespaceTest.NSWithIgnoredTerms.ExampleIgnoredLowercasedAlias} defmodule TestNS do use RDF.Vocabulary.Namespace - defvocab EX, - base_iri: "http://example.com/", - terms: ~w[], strict: false + defvocab EX, base_iri: "http://example.com/", terms: ~w[], strict: false defvocab EXS, base_iri: "http://example.com/strict#", @@ -34,17 +37,28 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab ExampleFromGraph, base_iri: "http://example.com/from_graph#", - data: RDF.Graph.new([ - {~I, ~I, ~I}, - {~I, ~I, ~I} - ]) + data: + RDF.Graph.new([ + {~I, + ~I, + ~I}, + {~I, + ~I, + ~I} + ]) defvocab ExampleFromDataset, base_iri: "http://example.com/from_dataset#", - data: RDF.Dataset.new([ - {~I, ~I, ~I}, - {~I, ~I, ~I, ~I} - ]) + data: + RDF.Dataset.new([ + {~I, + ~I, + ~I}, + {~I, + ~I, + ~I, + ~I} + ]) defvocab ExampleFromNTriplesFile, base_iri: "http://example.com/from_ntriples/", @@ -60,43 +74,40 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab StrictExampleFromTerms, base_iri: "http://example.com/strict_from_terms#", - terms: ~w[foo Bar] + terms: ~w[foo Bar] defvocab NonStrictExampleFromTerms, base_iri: "http://example.com/non_strict_from_terms#", - terms: ~w[foo Bar], + terms: ~w[foo Bar], strict: false defvocab StrictExampleFromAliasedTerms, base_iri: "http://example.com/strict_from_aliased_terms#", terms: ~w[term1 Term2 Term-3 term-4], alias: [ - Term1: "term1", - term2: "Term2", - Term3: "Term-3", - term4: "term-4", - ] + Term1: "term1", + term2: "Term2", + Term3: "Term-3", + term4: "term-4" + ] defvocab NonStrictExampleFromAliasedTerms, base_iri: "http://example.com/non_strict_from_aliased_terms#", terms: ~w[], alias: [ - Term1: "term1", - term2: "Term2", - Term3: "Term-3", - term4: "term-4", - ], + Term1: "term1", + term2: "Term2", + Term3: "Term-3", + term4: "term-4" + ], strict: false defvocab ExampleWithSynonymAliases, base_iri: "http://example.com/ex#", - terms: ~w[bar Bar], - alias: [foo: "bar", baz: "bar", - Foo: "Bar", Baz: "Bar"] - + terms: ~w[bar Bar], + alias: [foo: "bar", baz: "bar", Foo: "Bar", Baz: "Bar"] end - describe "defvocab with bad base iri" do test "without a base_iri, an error is raised" do assert_raise KeyError, fn -> @@ -130,6 +141,7 @@ defmodule RDF.Vocabulary.NamespaceTest do terms: [] end end + assert_raise RDF.Namespace.InvalidVocabBaseIRIError, fn -> defmodule NSWithInvalidBaseIRI3 do use RDF.Vocabulary.Namespace @@ -142,7 +154,6 @@ defmodule RDF.Vocabulary.NamespaceTest do end end - describe "defvocab with bad terms" do test "when the given file not found, an error is raised" do assert_raise File.Error, fn -> @@ -157,7 +168,6 @@ defmodule RDF.Vocabulary.NamespaceTest do end end - describe "defvocab with bad aliases" do test "when an alias contains invalid characters, an error is raised" do assert_raise RDF.Namespace.InvalidAliasError, fn -> @@ -166,8 +176,8 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", - terms: ~w[foo], - alias: ["foo-bar": "foo"] + terms: ~w[foo], + alias: ["foo-bar": "foo"] end end end @@ -179,8 +189,8 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", - terms: ~w[foo bar], - alias: [foo: "bar"] + terms: ~w[foo bar], + alias: [foo: "bar"] end end end @@ -192,8 +202,8 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", - terms: ~w[], - alias: [foo: "bar"] + terms: ~w[], + alias: [foo: "bar"] end end end @@ -205,14 +215,13 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", - terms: ~w[bar], - alias: [foo: "bar", baz: "foo"] + terms: ~w[bar], + alias: [foo: "bar", baz: "foo"] end end end end - test "defvocab with special terms" do defmodule NSofEdgeCases do use RDF.Vocabulary.Namespace @@ -242,61 +251,63 @@ defmodule RDF.Vocabulary.NamespaceTest do __ENV__ __CALLER__ ] - # This one also passes the tests, but causes some warnings: - # __block__ + + # This one also passes the tests, but causes some warnings: + # __block__ end + alias NSofEdgeCases.Example alias TestNS.EX - assert Example.nil == ~I - assert Example.true == ~I - assert Example.false == ~I - assert Example.do == ~I - assert Example.end == ~I - assert Example.else == ~I - assert Example.try == ~I - assert Example.rescue == ~I - assert Example.catch == ~I - assert Example.after == ~I - assert Example.not == ~I - assert Example.cond == ~I - assert Example.inbits == ~I - assert Example.inlist == ~I - assert Example.receive == ~I -# assert Example.__block__ == ~I - assert Example.__info__ == ~I - assert Example.__MODULE__ == ~I - assert Example.__FILE__ == ~I - assert Example.__DIR__ == ~I - assert Example.__ENV__ == ~I - assert Example.__CALLER__ == ~I + assert Example.nil() == ~I + assert Example.true() == ~I + assert Example.false() == ~I + assert Example.do() == ~I + assert Example.end() == ~I + assert Example.else() == ~I + assert Example.try() == ~I + assert Example.rescue() == ~I + assert Example.catch() == ~I + assert Example.after() == ~I + assert Example.not() == ~I + assert Example.cond() == ~I + assert Example.inbits() == ~I + assert Example.inlist() == ~I + assert Example.receive() == ~I + # assert Example.__block__ == ~I + assert Example.__info__() == ~I + assert Example.__MODULE__() == ~I + assert Example.__FILE__() == ~I + assert Example.__DIR__() == ~I + assert Example.__ENV__() == ~I + assert Example.__CALLER__() == ~I - assert Example.nil( EX.S, 1) == RDF.description(EX.S, Example.nil , 1) - assert Example.true( EX.S, 1) == RDF.description(EX.S, Example.true , 1) - assert Example.false( EX.S, 1) == RDF.description(EX.S, Example.false , 1) - assert Example.do( EX.S, 1) == RDF.description(EX.S, Example.do , 1) - assert Example.end( EX.S, 1) == RDF.description(EX.S, Example.end , 1) - assert Example.else( EX.S, 1) == RDF.description(EX.S, Example.else , 1) - assert Example.try( EX.S, 1) == RDF.description(EX.S, Example.try , 1) - assert Example.rescue( EX.S, 1) == RDF.description(EX.S, Example.rescue , 1) - assert Example.catch( EX.S, 1) == RDF.description(EX.S, Example.catch , 1) - assert Example.after( EX.S, 1) == RDF.description(EX.S, Example.after , 1) - assert Example.not( EX.S, 1) == RDF.description(EX.S, Example.not , 1) - assert Example.cond( EX.S, 1) == RDF.description(EX.S, Example.cond , 1) - assert Example.inbits( EX.S, 1) == RDF.description(EX.S, Example.inbits , 1) - assert Example.inlist( EX.S, 1) == RDF.description(EX.S, Example.inlist , 1) - assert Example.receive(EX.S, 1) == RDF.description(EX.S, Example.receive , 1) + assert Example.nil(EX.S, 1) == RDF.description(EX.S, Example.nil(), 1) + assert Example.true(EX.S, 1) == RDF.description(EX.S, Example.true(), 1) + assert Example.false(EX.S, 1) == RDF.description(EX.S, Example.false(), 1) + assert Example.do(EX.S, 1) == RDF.description(EX.S, Example.do(), 1) + assert Example.end(EX.S, 1) == RDF.description(EX.S, Example.end(), 1) + assert Example.else(EX.S, 1) == RDF.description(EX.S, Example.else(), 1) + assert Example.try(EX.S, 1) == RDF.description(EX.S, Example.try(), 1) + assert Example.rescue(EX.S, 1) == RDF.description(EX.S, Example.rescue(), 1) + assert Example.catch(EX.S, 1) == RDF.description(EX.S, Example.catch(), 1) + assert Example.after(EX.S, 1) == RDF.description(EX.S, Example.after(), 1) + assert Example.not(EX.S, 1) == RDF.description(EX.S, Example.not(), 1) + assert Example.cond(EX.S, 1) == RDF.description(EX.S, Example.cond(), 1) + assert Example.inbits(EX.S, 1) == RDF.description(EX.S, Example.inbits(), 1) + assert Example.inlist(EX.S, 1) == RDF.description(EX.S, Example.inlist(), 1) + assert Example.receive(EX.S, 1) == RDF.description(EX.S, Example.receive(), 1) end - describe "defvocab with invalid terms" do test "terms with a special meaning for Elixir cause a failure" do assert_raise RDF.Namespace.InvalidTermError, ~r/unquote_splicing/s, fn -> defmodule NSWithElixirTerms do use RDF.Vocabulary.Namespace + defvocab Example, base_iri: "http://example.com/example#", - terms: RDF.Vocabulary.Namespace.invalid_terms + terms: RDF.Vocabulary.Namespace.invalid_terms() end end end @@ -305,30 +316,31 @@ defmodule RDF.Vocabulary.NamespaceTest do assert_raise RDF.Namespace.InvalidTermError, ~r/unquote_splicing/s, fn -> defmodule NSWithElixirAliasTerms do use RDF.Vocabulary.Namespace + defvocab Example, base_iri: "http://example.com/example#", - terms: ~w[foo], - alias: [ - and: "foo", - or: "foo", - xor: "foo", - in: "foo", - fn: "foo", - def: "foo", - when: "foo", - if: "foo", - for: "foo", - case: "foo", - with: "foo", - quote: "foo", - unquote: "foo", - unquote_splicing: "foo", - alias: "foo", - import: "foo", - require: "foo", - super: "foo", - __aliases__: "foo", - ] + terms: ~w[foo], + alias: [ + and: "foo", + or: "foo", + xor: "foo", + in: "foo", + fn: "foo", + def: "foo", + when: "foo", + if: "foo", + for: "foo", + case: "foo", + with: "foo", + quote: "foo", + unquote: "foo", + unquote_splicing: "foo", + alias: "foo", + import: "foo", + require: "foo", + super: "foo", + __aliases__: "foo" + ] end end end @@ -336,62 +348,65 @@ defmodule RDF.Vocabulary.NamespaceTest do test "terms with a special meaning for Elixir don't cause a failure when they are ignored" do defmodule NSWithIgnoredElixirTerms do use RDF.Vocabulary.Namespace + defvocab Example, base_iri: "http://example.com/example#", - terms: RDF.Vocabulary.Namespace.invalid_terms, - ignore: RDF.Vocabulary.Namespace.invalid_terms + terms: RDF.Vocabulary.Namespace.invalid_terms(), + ignore: RDF.Vocabulary.Namespace.invalid_terms() end end test "terms with a special meaning for Elixir don't cause a failure when an alias is defined" do defmodule NSWithAliasesForElixirTerms do use RDF.Vocabulary.Namespace + defvocab Example, base_iri: "http://example.com/example#", - terms: RDF.Vocabulary.Namespace.invalid_terms, + terms: RDF.Vocabulary.Namespace.invalid_terms(), alias: [ - and_: "and", - or_: "or", - xor_: "xor", - in_: "in", - fn_: "fn", - def_: "def", - when_: "when", - if_: "if", - for_: "for", - case_: "case", - with_: "with", - quote_: "quote", - unquote_: "unquote", - unquote_splicing_: "unquote_splicing", - alias_: "alias", - import_: "import", - require_: "require", - super_: "super", - _aliases_: "__aliases__" - ] + and_: "and", + or_: "or", + xor_: "xor", + in_: "in", + fn_: "fn", + def_: "def", + when_: "when", + if_: "if", + for_: "for", + case_: "case", + with_: "with", + quote_: "quote", + unquote_: "unquote", + unquote_splicing_: "unquote_splicing", + alias_: "alias", + import_: "import", + require_: "require", + super_: "super", + _aliases_: "__aliases__" + ] end + alias NSWithAliasesForElixirTerms.Example - assert Example.and_ == ~I - assert Example.or_ == ~I - assert Example.xor_ == ~I - assert Example.in_ == ~I - assert Example.fn_ == ~I - assert Example.def_ == ~I - assert Example.when_ == ~I - assert Example.if_ == ~I - assert Example.for_ == ~I - assert Example.case_ == ~I - assert Example.with_ == ~I - assert Example.quote_ == ~I - assert Example.unquote_ == ~I - assert Example.unquote_splicing_ == ~I - assert Example.alias_ == ~I - assert Example.import_ == ~I - assert Example.require_ == ~I - assert Example.super_ == ~I - assert Example._aliases_ == ~I + assert Example.and_() == ~I + assert Example.or_() == ~I + assert Example.xor_() == ~I + assert Example.in_() == ~I + assert Example.fn_() == ~I + assert Example.def_() == ~I + assert Example.when_() == ~I + assert Example.if_() == ~I + assert Example.for_() == ~I + assert Example.case_() == ~I + assert Example.with_() == ~I + assert Example.quote_() == ~I + assert Example.unquote_() == ~I + assert Example.unquote_splicing_() == ~I + assert Example.alias_() == ~I + assert Example.import_() == ~I + assert Example.require_() == ~I + assert Example.super_() == ~I + assert Example._aliases_() == ~I end end @@ -400,9 +415,10 @@ defmodule RDF.Vocabulary.NamespaceTest do assert_raise RDF.Namespace.InvalidTermError, ~r/Foo-bar.*foo-bar/s, fn -> defmodule NSWithInvalidTerms1 do use RDF.Vocabulary.Namespace + defvocab Example, base_iri: "http://example.com/example#", - terms: ~w[Foo-bar foo-bar] + terms: ~w[Foo-bar foo-bar] end end end @@ -410,15 +426,15 @@ defmodule RDF.Vocabulary.NamespaceTest do test "when a term contains unallowed characters it does not fail when invalid_characters = :ignore" do defmodule NSWithInvalidTerms2 do use RDF.Vocabulary.Namespace + defvocab Example, base_iri: "http://example.com/example#", - terms: ~w[Foo-bar foo-bar], + terms: ~w[Foo-bar foo-bar], invalid_characters: :ignore end end end - describe "defvocab case violation handling" do test "aliases can fix case violations" do defmodule NSWithBadCasedTerms1 do @@ -427,13 +443,16 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", case_violations: :fail, - data: RDF.Graph.new([ - {~I, ~I, ~I}, - {~I, ~I, ~I} - ]), + data: + RDF.Graph.new([ + {~I, ~I, + ~I}, + {~I, ~I, + ~I} + ]), alias: [ foo: "Foo", - Bar: "bar", + Bar: "bar" ] end end @@ -445,13 +464,16 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", case_violations: :ignore, - data: RDF.Graph.new([ - {~I, ~I, ~I}, - {~I, ~I, ~I} - ]), + data: + RDF.Graph.new([ + {~I, ~I, + ~I}, + {~I, ~I, + ~I} + ]), alias: [ foo: "Foo", - Bar: "bar", + Bar: "bar" ] end end @@ -464,9 +486,12 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", case_violations: :fail, - data: RDF.Graph.new([ - {~I, ~I, ~I}, - ]) + data: + RDF.Graph.new([ + {~I, + ~I, + ~I} + ]) end end end @@ -479,14 +504,16 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", case_violations: :fail, - data: RDF.Graph.new([ - {~I, ~I, ~I} - ]) + data: + RDF.Graph.new([ + {~I, + ~I, + ~I} + ]) end end end - test "a capitalized alias for a property and :case_violations == :fail, raises an error" do assert_raise RDF.Namespace.InvalidTermError, fn -> defmodule NSWithBadCasedTerms5 do @@ -495,9 +522,12 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", case_violations: :fail, - data: RDF.Graph.new([ - {~I, ~I, ~I}, - ]), + data: + RDF.Graph.new([ + {~I, + ~I, + ~I} + ]), alias: [Foo: "foo"] end end @@ -511,9 +541,12 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", case_violations: :fail, - data: RDF.Graph.new([ - {~I, ~I, ~I} - ]), + data: + RDF.Graph.new([ + {~I, + ~I, + ~I} + ]), alias: [bar: "Bar"] end end @@ -526,82 +559,93 @@ defmodule RDF.Vocabulary.NamespaceTest do defvocab Example, base_iri: "http://example.com/ex#", case_violations: :fail, - data: RDF.Graph.new([ - {~I, ~I, ~I}, - {~I, ~I, ~I} - ]) + data: + RDF.Graph.new([ + {~I, + ~I, + ~I}, + {~I, + ~I, + ~I} + ]) end end end - describe "defvocab ignore terms" do defmodule NSWithIgnoredTerms do use RDF.Vocabulary.Namespace defvocab ExampleIgnoredLowercasedTerm, base_iri: "http://example.com/", - data: RDF.Graph.new([ - {~I, ~I, ~I}, - {~I, ~I, ~I} - ]), + data: + RDF.Graph.new([ + {~I, ~I, + ~I}, + {~I, ~I, + ~I} + ]), ignore: ["foo"] defvocab ExampleIgnoredCapitalizedTerm, base_iri: "http://example.com/", - data: RDF.Dataset.new([ - {~I, ~I, ~I}, - {~I, ~I, ~I, ~I} - ]), + data: + RDF.Dataset.new([ + {~I, ~I, + ~I}, + {~I, ~I, + ~I, + ~I} + ]), ignore: ~w[Bar] defvocab ExampleIgnoredLowercasedTermWithAlias, base_iri: "http://example.com/", - terms: ~w[foo Bar], - alias: [Foo: "foo"], - ignore: ~w[foo]a + terms: ~w[foo Bar], + alias: [Foo: "foo"], + ignore: ~w[foo]a defvocab ExampleIgnoredCapitalizedTermWithAlias, base_iri: "http://example.com/", - terms: ~w[foo Bar], - alias: [bar: "Bar"], - ignore: ~w[Bar]a + terms: ~w[foo Bar], + alias: [bar: "Bar"], + ignore: ~w[Bar]a defvocab ExampleIgnoredLowercasedAlias, base_iri: "http://example.com/", - terms: ~w[foo Bar], - alias: [bar: "Bar"], - ignore: ~w[bar]a + terms: ~w[foo Bar], + alias: [bar: "Bar"], + ignore: ~w[bar]a defvocab ExampleIgnoredCapitalizedAlias, base_iri: "http://example.com/", - terms: ~w[foo Bar], - alias: [Foo: "foo"], - ignore: ~w[Foo]a + terms: ~w[foo Bar], + alias: [Foo: "foo"], + ignore: ~w[Foo]a defvocab ExampleIgnoredNonStrictLowercasedTerm, base_iri: "http://example.com/", - terms: ~w[], - strict: false, - ignore: ~w[foo]a + terms: ~w[], + strict: false, + ignore: ~w[foo]a defvocab ExampleIgnoredNonStrictCapitalizedTerm, base_iri: "http://example.com/", - terms: ~w[], - strict: false, - ignore: ~w[Bar]a - + terms: ~w[], + strict: false, + ignore: ~w[Bar]a end test "resolution of ignored lowercased term on a strict vocab fails" do alias NSWithIgnoredTerms.ExampleIgnoredLowercasedTerm - assert ExampleIgnoredLowercasedTerm.__terms__ == [:Bar] - assert_raise UndefinedFunctionError, fn -> ExampleIgnoredLowercasedTerm.foo end + assert ExampleIgnoredLowercasedTerm.__terms__() == [:Bar] + assert_raise UndefinedFunctionError, fn -> ExampleIgnoredLowercasedTerm.foo() end end test "resolution of ignored capitalized term on a strict vocab fails" do alias NSWithIgnoredTerms.ExampleIgnoredCapitalizedTerm - assert ExampleIgnoredCapitalizedTerm.__terms__ == [:foo] + assert ExampleIgnoredCapitalizedTerm.__terms__() == [:foo] + assert_raise RDF.Namespace.UndefinedTermError, fn -> RDF.iri(ExampleIgnoredCapitalizedTerm.Bar) end @@ -609,33 +653,37 @@ defmodule RDF.Vocabulary.NamespaceTest do test "resolution of ignored lowercased term with alias on a strict vocab fails" do alias NSWithIgnoredTerms.ExampleIgnoredLowercasedTermWithAlias - assert ExampleIgnoredLowercasedTermWithAlias.__terms__ == [:Bar, :Foo] - assert_raise UndefinedFunctionError, fn -> ExampleIgnoredLowercasedTermWithAlias.foo end + assert ExampleIgnoredLowercasedTermWithAlias.__terms__() == [:Bar, :Foo] + assert_raise UndefinedFunctionError, fn -> ExampleIgnoredLowercasedTermWithAlias.foo() end assert RDF.iri(ExampleIgnoredLowercasedTermWithAlias.Foo) == ~I end test "resolution of ignored capitalized term with alias on a strict vocab fails" do alias NSWithIgnoredTerms.ExampleIgnoredCapitalizedTermWithAlias - assert ExampleIgnoredCapitalizedTermWithAlias.__terms__ == [:bar, :foo] + assert ExampleIgnoredCapitalizedTermWithAlias.__terms__() == [:bar, :foo] + assert_raise RDF.Namespace.UndefinedTermError, fn -> RDF.iri(ExampleIgnoredCapitalizedTermWithAlias.Bar) end - assert RDF.iri(ExampleIgnoredCapitalizedTermWithAlias.bar) == ~I + + assert RDF.iri(ExampleIgnoredCapitalizedTermWithAlias.bar()) == ~I end test "resolution of ignored lowercased alias on a strict vocab fails" do alias NSWithIgnoredTerms.ExampleIgnoredLowercasedAlias - assert ExampleIgnoredLowercasedAlias.__terms__ == [:Bar, :foo] + assert ExampleIgnoredLowercasedAlias.__terms__() == [:Bar, :foo] assert RDF.iri(ExampleIgnoredLowercasedAlias.Bar) == ~I + assert_raise UndefinedFunctionError, fn -> - RDF.iri(ExampleIgnoredLowercasedAlias.bar) + RDF.iri(ExampleIgnoredLowercasedAlias.bar()) end end test "resolution of ignored capitalized alias on a strict vocab fails" do alias NSWithIgnoredTerms.ExampleIgnoredCapitalizedAlias - assert ExampleIgnoredCapitalizedAlias.__terms__ == [:Bar, :foo] - assert RDF.iri(ExampleIgnoredCapitalizedAlias.foo) == ~I + assert ExampleIgnoredCapitalizedAlias.__terms__() == [:Bar, :foo] + assert RDF.iri(ExampleIgnoredCapitalizedAlias.foo()) == ~I + assert_raise RDF.Namespace.UndefinedTermError, fn -> RDF.iri(ExampleIgnoredCapitalizedAlias.Foo) end @@ -643,13 +691,15 @@ defmodule RDF.Vocabulary.NamespaceTest do test "resolution of ignored lowercased term on a non-strict vocab fails" do alias NSWithIgnoredTerms.ExampleIgnoredNonStrictLowercasedTerm + assert_raise UndefinedFunctionError, fn -> - ExampleIgnoredNonStrictLowercasedTerm.foo + ExampleIgnoredNonStrictLowercasedTerm.foo() end end test "resolution of ignored capitalized term on a non-strict vocab fails" do alias NSWithIgnoredTerms.ExampleIgnoredNonStrictCapitalizedTerm + assert_raise RDF.Namespace.UndefinedTermError, fn -> RDF.iri(ExampleIgnoredNonStrictCapitalizedTerm.Bar) end @@ -658,92 +708,97 @@ defmodule RDF.Vocabulary.NamespaceTest do test "ignored terms with invalid characters do not raise anything" do defmodule IgnoredTermWithInvalidCharacters do use RDF.Vocabulary.Namespace + defvocab Example, base_iri: "http://example.com/", - terms: ~w[foo-bar], - ignore: ~w[foo-bar]a + terms: ~w[foo-bar], + ignore: ~w[foo-bar]a end end test "ignored terms with case violations do not raise anything" do defmodule IgnoredTermWithCaseViolations do use RDF.Vocabulary.Namespace + defvocab Example, base_iri: "http://example.com/", - data: RDF.Dataset.new([ - {~I, ~I, ~I}, - {~I, ~I, ~I, ~I} - ]), + data: + RDF.Dataset.new([ + {~I, ~I, + ~I}, + {~I, ~I, + ~I, + ~I} + ]), case_violations: :fail, - ignore: ~w[Foo bar]a + ignore: ~w[Foo bar]a end end end - test "__base_iri__ returns the base_iri" do alias TestNS.ExampleFromGraph, as: HashVocab alias TestNS.ExampleFromNTriplesFile, as: SlashVocab - assert HashVocab.__base_iri__ == "http://example.com/from_graph#" - assert SlashVocab.__base_iri__ == "http://example.com/from_ntriples/" + assert HashVocab.__base_iri__() == "http://example.com/from_graph#" + assert SlashVocab.__base_iri__() == "http://example.com/from_ntriples/" end - test "__iris__ returns all IRIs of the vocabulary" do alias TestNS.ExampleFromGraph, as: Example1 - assert length(Example1.__iris__) == 2 - assert RDF.iri(Example1.foo) in Example1.__iris__ - assert RDF.iri(Example1.Bar) in Example1.__iris__ + assert length(Example1.__iris__()) == 2 + assert RDF.iri(Example1.foo()) in Example1.__iris__() + assert RDF.iri(Example1.Bar) in Example1.__iris__() alias TestNS.ExampleFromNTriplesFile, as: Example2 - assert length(Example2.__iris__) == 2 - assert RDF.iri(Example2.foo) in Example2.__iris__ - assert RDF.iri(Example2.Bar) in Example2.__iris__ + assert length(Example2.__iris__()) == 2 + assert RDF.iri(Example2.foo()) in Example2.__iris__() + assert RDF.iri(Example2.Bar) in Example2.__iris__() alias TestNS.ExampleFromNQuadsFile, as: Example3 - assert length(Example3.__iris__) == 2 - assert RDF.iri(Example3.foo) in Example3.__iris__ - assert RDF.iri(Example3.Bar) in Example3.__iris__ + assert length(Example3.__iris__()) == 2 + assert RDF.iri(Example3.foo()) in Example3.__iris__() + assert RDF.iri(Example3.Bar) in Example3.__iris__() alias TestNS.ExampleFromTurtleFile, as: Example4 - assert length(Example4.__iris__) == 2 - assert RDF.iri(Example4.foo) in Example4.__iris__ - assert RDF.iri(Example4.Bar) in Example4.__iris__ + assert length(Example4.__iris__()) == 2 + assert RDF.iri(Example4.foo()) in Example4.__iris__() + assert RDF.iri(Example4.Bar) in Example4.__iris__() alias TestNS.StrictExampleFromAliasedTerms, as: Example4 - assert length(Example4.__iris__) == 4 - assert RDF.iri(Example4.Term1) in Example4.__iris__ - assert RDF.iri(Example4.term2) in Example4.__iris__ - assert RDF.iri(Example4.Term3) in Example4.__iris__ - assert RDF.iri(Example4.term4) in Example4.__iris__ + assert length(Example4.__iris__()) == 4 + assert RDF.iri(Example4.Term1) in Example4.__iris__() + assert RDF.iri(Example4.term2()) in Example4.__iris__() + assert RDF.iri(Example4.Term3) in Example4.__iris__() + assert RDF.iri(Example4.term4()) in Example4.__iris__() end - describe "__terms__" do alias TestNS.{ExampleFromGraph, ExampleFromDataset, StrictExampleFromAliasedTerms} test "includes all defined terms" do - assert length(ExampleFromGraph.__terms__) == 2 + assert length(ExampleFromGraph.__terms__()) == 2 + for term <- ~w[foo Bar]a do - assert term in ExampleFromGraph.__terms__ + assert term in ExampleFromGraph.__terms__() end - assert length(ExampleFromDataset.__terms__) == 2 + assert length(ExampleFromDataset.__terms__()) == 2 + for term <- ~w[foo Bar]a do - assert term in ExampleFromDataset.__terms__ + assert term in ExampleFromDataset.__terms__() end end test "includes aliases" do - assert length(StrictExampleFromAliasedTerms.__terms__) == 8 + assert length(StrictExampleFromAliasedTerms.__terms__()) == 8 + for term <- ~w[term1 Term1 term2 Term2 Term3 term4 Term-3 term-4]a do - assert term in StrictExampleFromAliasedTerms.__terms__ + assert term in StrictExampleFromAliasedTerms.__terms__() end end end - test "resolving an unqualified term raises an error" do assert_raise RDF.Namespace.UndefinedTermError, fn -> RDF.iri(:foo) end end @@ -767,48 +822,54 @@ defmodule RDF.Vocabulary.NamespaceTest do test "undefined terms" do assert_raise UndefinedFunctionError, fn -> - ExampleFromGraph.undefined + ExampleFromGraph.undefined() end + assert_raise UndefinedFunctionError, fn -> - ExampleFromNTriplesFile.undefined + ExampleFromNTriplesFile.undefined() end + assert_raise UndefinedFunctionError, fn -> - StrictExampleFromTerms.undefined + StrictExampleFromTerms.undefined() end assert {:error, %RDF.Namespace.UndefinedTermError{}} = RDF.Namespace.resolve_term(TestNS.ExampleFromGraph.Undefined) + assert {:error, %RDF.Namespace.UndefinedTermError{}} = RDF.Namespace.resolve_term(ExampleFromNTriplesFile.Undefined) + assert {:error, %RDF.Namespace.UndefinedTermError{}} = RDF.Namespace.resolve_term(StrictExampleFromTerms.Undefined) assert_raise RDF.Namespace.UndefinedTermError, fn -> RDF.Namespace.resolve_term!(TestNS.ExampleFromGraph.Undefined) end + assert_raise RDF.Namespace.UndefinedTermError, fn -> RDF.Namespace.resolve_term!(ExampleFromNTriplesFile.Undefined) end + assert_raise RDF.Namespace.UndefinedTermError, fn -> RDF.Namespace.resolve_term!(StrictExampleFromTerms.Undefined) end end test "lowercased terms" do - assert ExampleFromGraph.foo == ~I - assert RDF.iri(ExampleFromGraph.foo) == ~I + assert ExampleFromGraph.foo() == ~I + assert RDF.iri(ExampleFromGraph.foo()) == ~I - assert ExampleFromNTriplesFile.foo == ~I - assert RDF.iri(ExampleFromNTriplesFile.foo) == ~I + assert ExampleFromNTriplesFile.foo() == ~I + assert RDF.iri(ExampleFromNTriplesFile.foo()) == ~I - assert StrictExampleFromTerms.foo == ~I - assert RDF.iri(StrictExampleFromTerms.foo) == ~I + assert StrictExampleFromTerms.foo() == ~I + assert RDF.iri(StrictExampleFromTerms.foo()) == ~I end test "capitalized terms" do - assert RDF.iri(ExampleFromGraph.Bar) == ~I + assert RDF.iri(ExampleFromGraph.Bar) == ~I assert RDF.iri(ExampleFromNTriplesFile.Bar) == ~I - assert RDF.iri(StrictExampleFromTerms.Bar) == ~I + assert RDF.iri(StrictExampleFromTerms.Bar) == ~I end test "terms starting with an underscore" do @@ -819,58 +880,62 @@ defmodule RDF.Vocabulary.NamespaceTest do base_iri: "http://example.com/ex#", terms: ~w[_foo] end + alias NSwithUnderscoreTerms.Example alias TestNS.EX - assert Example._foo == ~I - assert Example._foo(EX.S, 1) == RDF.description(EX.S, Example._foo, 1) + assert Example._foo() == ~I + assert Example._foo(EX.S, 1) == RDF.description(EX.S, Example._foo(), 1) end end - describe "term resolution in a non-strict vocab namespace" do alias TestNS.NonStrictExampleFromTerms + test "undefined lowercased terms" do - assert NonStrictExampleFromTerms.random == ~I + assert NonStrictExampleFromTerms.random() == + ~I end test "undefined capitalized terms" do - assert RDF.iri(NonStrictExampleFromTerms.Random) == ~I + assert RDF.iri(NonStrictExampleFromTerms.Random) == + ~I end test "undefined terms starting with an underscore" do - assert NonStrictExampleFromTerms._random == ~I + assert NonStrictExampleFromTerms._random() == + ~I end test "defined lowercase terms" do - assert NonStrictExampleFromTerms.foo == ~I + assert NonStrictExampleFromTerms.foo() == ~I end test "defined capitalized terms" do - assert RDF.iri(NonStrictExampleFromTerms.Bar) == ~I + assert RDF.iri(NonStrictExampleFromTerms.Bar) == + ~I end end - describe "term resolution of aliases on a strict vocabulary" do alias TestNS.StrictExampleFromAliasedTerms, as: Example test "the alias resolves to the correct IRI" do assert RDF.iri(Example.Term1) == ~I - assert RDF.iri(Example.term2) == ~I + assert RDF.iri(Example.term2()) == ~I assert RDF.iri(Example.Term3) == ~I - assert RDF.iri(Example.term4) == ~I + assert RDF.iri(Example.term4()) == ~I end test "the old term remains resolvable" do - assert RDF.iri(Example.term1) == ~I + assert RDF.iri(Example.term1()) == ~I assert RDF.iri(Example.Term2) == ~I end test "defining multiple aliases for a term" do alias TestNS.ExampleWithSynonymAliases, as: Example - assert Example.foo == Example.baz - assert RDF.iri(Example.foo) == RDF.iri(Example.baz) + assert Example.foo() == Example.baz() + assert RDF.iri(Example.foo()) == RDF.iri(Example.baz()) end end @@ -879,23 +944,29 @@ defmodule RDF.Vocabulary.NamespaceTest do test "the alias resolves to the correct IRI" do assert RDF.iri(Example.Term1) == ~I - assert RDF.iri(Example.term2) == ~I + + assert RDF.iri(Example.term2()) == + ~I + assert RDF.iri(Example.Term3) == ~I - assert RDF.iri(Example.term4) == ~I + + assert RDF.iri(Example.term4()) == + ~I end test "the old term remains resolvable" do - assert RDF.iri(Example.term1) == ~I + assert RDF.iri(Example.term1()) == + ~I + assert RDF.iri(Example.Term2) == ~I end end - describe "description DSL" do alias TestNS.{EX, EXS} - + test "one statement with a strict property term" do - assert EXS.foo(EX.S, EX.O) == Description.new(EX.S, EXS.foo, EX.O) + assert EXS.foo(EX.S, EX.O) == Description.new(EX.S, EXS.foo(), EX.O) end test "multiple statements with strict property terms and one object" do @@ -903,7 +974,8 @@ defmodule RDF.Vocabulary.NamespaceTest do EX.S |> EXS.foo(EX.O1) |> EXS.bar(EX.O2) - assert description == Description.new(EX.S, [{EXS.foo, EX.O1}, {EXS.bar, EX.O2}]) + + assert description == Description.new(EX.S, [{EXS.foo(), EX.O1}, {EXS.bar(), EX.O2}]) end test "multiple statements with strict property terms and multiple objects in a list" do @@ -911,12 +983,14 @@ defmodule RDF.Vocabulary.NamespaceTest do EX.S |> EXS.foo([EX.O1, EX.O2]) |> EXS.bar([EX.O3, EX.O4]) - assert description == Description.new(EX.S, [ - {EXS.foo, EX.O1}, - {EXS.foo, EX.O2}, - {EXS.bar, EX.O3}, - {EXS.bar, EX.O4} - ]) + + assert description == + Description.new(EX.S, [ + {EXS.foo(), EX.O1}, + {EXS.foo(), EX.O2}, + {EXS.bar(), EX.O3}, + {EXS.bar(), EX.O4} + ]) end test "multiple statements with strict property terms and multiple objects as arguments" do @@ -924,17 +998,19 @@ defmodule RDF.Vocabulary.NamespaceTest do EX.S |> EXS.foo(EX.O1, EX.O2) |> EXS.bar(EX.O3, EX.O4, EX.O5) - assert description == Description.new(EX.S, [ - {EXS.foo, EX.O1}, - {EXS.foo, EX.O2}, - {EXS.bar, EX.O3}, - {EXS.bar, EX.O4}, - {EXS.bar, EX.O5} - ]) + + assert description == + Description.new(EX.S, [ + {EXS.foo(), EX.O1}, + {EXS.foo(), EX.O2}, + {EXS.bar(), EX.O3}, + {EXS.bar(), EX.O4}, + {EXS.bar(), EX.O5} + ]) end test "one statement with a non-strict property term" do - assert EX.p(EX.S, EX.O) == Description.new(EX.S, EX.p, EX.O) + assert EX.p(EX.S, EX.O) == Description.new(EX.S, EX.p(), EX.O) end test "multiple statements with non-strict property terms and one object" do @@ -942,7 +1018,8 @@ defmodule RDF.Vocabulary.NamespaceTest do EX.S |> EX.p1(EX.O1) |> EX.p2(EX.O2) - assert description == Description.new(EX.S, [{EX.p1, EX.O1}, {EX.p2, EX.O2}]) + + assert description == Description.new(EX.S, [{EX.p1(), EX.O1}, {EX.p2(), EX.O2}]) end test "multiple statements with non-strict property terms and multiple objects in a list" do @@ -950,12 +1027,14 @@ defmodule RDF.Vocabulary.NamespaceTest do EX.S |> EX.p1([EX.O1, EX.O2]) |> EX.p2([EX.O3, EX.O4]) - assert description == Description.new(EX.S, [ - {EX.p1, EX.O1}, - {EX.p1, EX.O2}, - {EX.p2, EX.O3}, - {EX.p2, EX.O4} - ]) + + assert description == + Description.new(EX.S, [ + {EX.p1(), EX.O1}, + {EX.p1(), EX.O2}, + {EX.p2(), EX.O3}, + {EX.p2(), EX.O4} + ]) end test "multiple statements with non-strict property terms and multiple objects as arguments" do @@ -963,55 +1042,60 @@ defmodule RDF.Vocabulary.NamespaceTest do EX.S |> EX.p1(EX.O1, EX.O2) |> EX.p2(EX.O3, EX.O4) - assert description == Description.new(EX.S, [ - {EX.p1, EX.O1}, - {EX.p1, EX.O2}, - {EX.p2, EX.O3}, - {EX.p2, EX.O4} - ]) + + assert description == + Description.new(EX.S, [ + {EX.p1(), EX.O1}, + {EX.p1(), EX.O2}, + {EX.p2(), EX.O3}, + {EX.p2(), EX.O4} + ]) end end - describe "term resolution on the top-level RDF module" do test "capitalized terms" do - assert RDF.iri(RDF.Property) == ~I - assert RDF.iri(RDF.Statement) == ~I - assert RDF.iri(RDF.List) == ~I - assert RDF.iri(RDF.Nil) == ~I - assert RDF.iri(RDF.Seq) == ~I - assert RDF.iri(RDF.Bag) == ~I - assert RDF.iri(RDF.Alt) == ~I - assert RDF.iri(RDF.LangString) == ~I - assert RDF.iri(RDF.PlainLiteral) == ~I - assert RDF.iri(RDF.XMLLiteral) == ~I - assert RDF.iri(RDF.HTML) == ~I - assert RDF.iri(RDF.Property) == ~I + assert RDF.iri(RDF.Property) == ~I + assert RDF.iri(RDF.Statement) == ~I + assert RDF.iri(RDF.List) == ~I + assert RDF.iri(RDF.Nil) == ~I + assert RDF.iri(RDF.Seq) == ~I + assert RDF.iri(RDF.Bag) == ~I + assert RDF.iri(RDF.Alt) == ~I + assert RDF.iri(RDF.LangString) == ~I + + assert RDF.iri(RDF.PlainLiteral) == + ~I + + assert RDF.iri(RDF.XMLLiteral) == ~I + assert RDF.iri(RDF.HTML) == ~I + assert RDF.iri(RDF.Property) == ~I end test "lowercase terms" do - assert RDF.type == ~I - assert RDF.subject == ~I - assert RDF.predicate == ~I - assert RDF.object == ~I - assert RDF.first == ~I - assert RDF.rest == ~I - assert RDF.value == ~I + assert RDF.type() == ~I + assert RDF.subject() == ~I + assert RDF.predicate() == ~I + assert RDF.object() == ~I + assert RDF.first() == ~I + assert RDF.rest() == ~I + assert RDF.value() == ~I - assert RDF.langString == ~I - assert RDF.nil == ~I + assert RDF.langString() == ~I + assert RDF.nil() == ~I end test "description DSL" do alias TestNS.EX - assert RDF.type( EX.S, 1) == RDF.NS.RDF.type( EX.S, 1) - assert RDF.subject( EX.S, 1, 2) == RDF.NS.RDF.subject( EX.S, 1, 2) - assert RDF.predicate(EX.S, 1, 2, 3) == RDF.NS.RDF.predicate(EX.S, 1, 2, 3) - assert RDF.object( EX.S, 1, 2, 3, 4) == RDF.NS.RDF.object( EX.S, 1, 2, 3, 4) - assert RDF.first( EX.S, 1, 2, 3, 4, 5) == RDF.NS.RDF.first( EX.S, 1, 2, 3, 4, 5) - assert RDF.rest( EX.S, [1, 2, 3, 4, 5, 6]) == RDF.NS.RDF.rest( EX.S, [1, 2, 3, 4, 5, 6]) - assert RDF.value( EX.S, [1, 2, 3, 4, 5, 6, 7]) == RDF.NS.RDF.value( EX.S, [1, 2, 3, 4, 5, 6, 7]) + assert RDF.type(EX.S, 1) == RDF.NS.RDF.type(EX.S, 1) + assert RDF.subject(EX.S, 1, 2) == RDF.NS.RDF.subject(EX.S, 1, 2) + assert RDF.predicate(EX.S, 1, 2, 3) == RDF.NS.RDF.predicate(EX.S, 1, 2, 3) + assert RDF.object(EX.S, 1, 2, 3, 4) == RDF.NS.RDF.object(EX.S, 1, 2, 3, 4) + assert RDF.first(EX.S, 1, 2, 3, 4, 5) == RDF.NS.RDF.first(EX.S, 1, 2, 3, 4, 5) + assert RDF.rest(EX.S, [1, 2, 3, 4, 5, 6]) == RDF.NS.RDF.rest(EX.S, [1, 2, 3, 4, 5, 6]) + + assert RDF.value(EX.S, [1, 2, 3, 4, 5, 6, 7]) == + RDF.NS.RDF.value(EX.S, [1, 2, 3, 4, 5, 6, 7]) end end - end diff --git a/test/unit/xsd/comparison_test.exs b/test/unit/xsd/comparison_test.exs index 94aefbb..fc1a6a3 100644 --- a/test/unit/xsd/comparison_test.exs +++ b/test/unit/xsd/comparison_test.exs @@ -2,7 +2,15 @@ defmodule RDF.XSD.ComparisonTest do use ExUnit.Case alias RDF.XSD - alias RDF.TestDatatypes.{Initials, Age, DecimalUnitInterval, CustomTime, DateWithoutTz, DateTimeWithTz} + + alias RDF.TestDatatypes.{ + Initials, + Age, + DecimalUnitInterval, + CustomTime, + DateWithoutTz, + DateTimeWithTz + } describe "XSD.String" do @ordered_strings [ @@ -65,7 +73,7 @@ defmodule RDF.XSD.ComparisonTest do {XSD.non_negative_integer(1), Age.new(2)}, {Age.new(1), XSD.decimal(2.1)}, {XSD.decimal(0.1), DecimalUnitInterval.new(0.2)}, - {DecimalUnitInterval.new(0.3), Age.new(2)}, + {DecimalUnitInterval.new(0.3), Age.new(2)} ], &assert_order/1 ) @@ -104,7 +112,10 @@ defmodule RDF.XSD.ComparisonTest do ) assert_order({XSD.datetime("2000-01-15T12:00:00"), XSD.datetime("2000-01-16T12:00:00Z")}) - assert_order({XSD.datetime("2000-01-15T12:00:00"), DateTimeWithTz.new("2000-01-16T12:00:00Z")}) + + assert_order( + {XSD.datetime("2000-01-15T12:00:00"), DateTimeWithTz.new("2000-01-16T12:00:00Z")} + ) end test "when unequal due to missing time zone" do @@ -127,7 +138,8 @@ defmodule RDF.XSD.ComparisonTest do ) assert_equal( - {DateTimeWithTz.new("2002-04-02T23:00:00-04:00"), XSD.datetime("2002-04-03T02:00:00-01:00")} + {DateTimeWithTz.new("2002-04-02T23:00:00-04:00"), + XSD.datetime("2002-04-03T02:00:00-01:00")} ) assert_equal({XSD.datetime("1999-12-31T24:00:00"), XSD.datetime("2000-01-01T00:00:00")}) @@ -224,12 +236,12 @@ defmodule RDF.XSD.ComparisonTest do assert_equal({CustomTime.new("12:00:00+01:00"), XSD.time("12:00:00+01:00")}) end -# TODO: -# test "when indeterminate" do -# assert_indeterminate({XSD.time("12:00:00Z"), XSD.time("12:00:00")}) -# assert_indeterminate({XSD.time("12:00:00+00:00"), XSD.time("12:00:00")}) -# assert_indeterminate({XSD.time("12:00:00-00:00"), XSD.time("12:00:00")}) -# end + # TODO: + # test "when indeterminate" do + # assert_indeterminate({XSD.time("12:00:00Z"), XSD.time("12:00:00")}) + # assert_indeterminate({XSD.time("12:00:00+00:00"), XSD.time("12:00:00")}) + # assert_indeterminate({XSD.time("12:00:00-00:00"), XSD.time("12:00:00")}) + # end end describe "incomparable" do diff --git a/test/unit/xsd/datatypes/any_uri_test.exs b/test/unit/xsd/datatypes/any_uri_test.exs index a666b60..9e6236e 100644 --- a/test/unit/xsd/datatypes/any_uri_test.exs +++ b/test/unit/xsd/datatypes/any_uri_test.exs @@ -24,15 +24,15 @@ defmodule RDF.XSD.AnyURITest do RDF.iri("http://example.com/foo") => {URI.parse("http://example.com/foo"), nil, "http://example.com/foo"}, RDF.List => - {URI.parse("http://www.w3.org/1999/02/22-rdf-syntax-ns#List"), nil, "http://www.w3.org/1999/02/22-rdf-syntax-ns#List"}, + {URI.parse("http://www.w3.org/1999/02/22-rdf-syntax-ns#List"), nil, + "http://www.w3.org/1999/02/22-rdf-syntax-ns#List"} }, invalid: [42, 3.14, Foo, :foo, true, false] - describe "cast/1" do test "casting an anyURI returns the input as it is" do assert XSD.anyURI("http://example.com/") |> XSD.AnyURI.cast() == - XSD.anyURI("http://example.com/") + XSD.anyURI("http://example.com/") end test "casting an RDF.IRI" do diff --git a/test/unit/xsd/datatypes/date_test.exs b/test/unit/xsd/datatypes/date_test.exs index 397b1e7..2c4263e 100644 --- a/test/unit/xsd/datatypes/date_test.exs +++ b/test/unit/xsd/datatypes/date_test.exs @@ -53,16 +53,20 @@ defmodule RDF.XSD.DateTest do %RDF.Literal{literal: %XSD.Date{value: {~D[2010-01-01], "+01:00"}}} assert XSD.Date.new("2010-01-01", tz: "+00:00") == - %RDF.Literal{literal: %XSD.Date{ - value: {~D[2010-01-01], "Z"}, - uncanonical_lexical: "2010-01-01+00:00" - }} + %RDF.Literal{ + literal: %XSD.Date{ + value: {~D[2010-01-01], "Z"}, + uncanonical_lexical: "2010-01-01+00:00" + } + } assert XSD.Date.new(~D[2010-01-01], tz: "+00:00") == - %RDF.Literal{literal: %XSD.Date{ - value: {~D[2010-01-01], "Z"}, - uncanonical_lexical: "2010-01-01+00:00" - }} + %RDF.Literal{ + literal: %XSD.Date{ + value: {~D[2010-01-01], "Z"}, + uncanonical_lexical: "2010-01-01+00:00" + } + } end test "with date string including a timezone and tz opt" do @@ -73,10 +77,12 @@ defmodule RDF.XSD.DateTest do %RDF.Literal{literal: %XSD.Date{value: {~D[2010-01-01], "Z"}}} assert XSD.Date.new("2010-01-01+01:00", tz: "+00:00") == - %RDF.Literal{literal: %XSD.Date{ - value: {~D[2010-01-01], "Z"}, - uncanonical_lexical: "2010-01-01+00:00" - }} + %RDF.Literal{ + literal: %XSD.Date{ + value: {~D[2010-01-01], "Z"}, + uncanonical_lexical: "2010-01-01+00:00" + } + } end test "with invalid tz opt" do diff --git a/test/unit/xsd/datatypes/integer_test.exs b/test/unit/xsd/datatypes/integer_test.exs index 703bbba..ac572d7 100644 --- a/test/unit/xsd/datatypes/integer_test.exs +++ b/test/unit/xsd/datatypes/integer_test.exs @@ -32,14 +32,16 @@ defmodule RDF.XSD.IntegerTest do end test "with another datatype" do - assert_raise RDF.XSD.Datatype.Mismatch, "'#{inspect(XSD.decimal(42).literal)}' is not a #{XSD.Integer}", fn -> - XSD.decimal(42) |> XSD.Integer.value() - end + assert_raise RDF.XSD.Datatype.Mismatch, + "'#{inspect(XSD.decimal(42).literal)}' is not a #{XSD.Integer}", + fn -> + XSD.decimal(42) |> XSD.Integer.value() + end end test "with a non-literal" do assert_raise RDF.XSD.Datatype.Mismatch, "'42' is not a #{XSD.Integer}", fn -> - XSD.Integer.value(42) + XSD.Integer.value(42) end end end diff --git a/test/unit/xsd/datatypes/numeric_test.exs b/test/unit/xsd/datatypes/numeric_test.exs index 98ee426..6a7c98f 100644 --- a/test/unit/xsd/datatypes/numeric_test.exs +++ b/test/unit/xsd/datatypes/numeric_test.exs @@ -75,49 +75,79 @@ defmodule RDF.XSD.NumericTest do end test "xsd:double literal + xsd:integer literal" do - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.add(XSD.double(1.1), XSD.integer(2)) - assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(3.1)), 0.000000000000001 + assert result = + %RDF.Literal{literal: %XSD.Double{}} = Numeric.add(XSD.double(1.1), XSD.integer(2)) - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.add(XSD.double(1.1), Age.new(2)) assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(3.1)), 0.000000000000001 + RDF.Literal.value(XSD.double(3.1)), + 0.000000000000001 + + assert result = + %RDF.Literal{literal: %XSD.Double{}} = Numeric.add(XSD.double(1.1), Age.new(2)) - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.add(DoubleUnitInterval.new(0.5), Age.new(2)) assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(2.5)), 0.000000000000001 + RDF.Literal.value(XSD.double(3.1)), + 0.000000000000001 + + assert result = + %RDF.Literal{literal: %XSD.Double{}} = + Numeric.add(DoubleUnitInterval.new(0.5), Age.new(2)) + + assert_in_delta RDF.Literal.value(result), + RDF.Literal.value(XSD.double(2.5)), + 0.000000000000001 end test "xsd:decimal literal + xsd:double literal" do - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.add(XSD.decimal(1.1), XSD.double(2.2)) - assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(3.3)), 0.000000000000001 + assert result = + %RDF.Literal{literal: %XSD.Double{}} = + Numeric.add(XSD.decimal(1.1), XSD.double(2.2)) - assert result = %RDF.Literal{literal: %XSD.Double{}} = - Numeric.add(DecimalUnitInterval.new(0.5), DoubleUnitInterval.new(0.5)) assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(1.0)), 0.000000000000001 + RDF.Literal.value(XSD.double(3.3)), + 0.000000000000001 + + assert result = + %RDF.Literal{literal: %XSD.Double{}} = + Numeric.add(DecimalUnitInterval.new(0.5), DoubleUnitInterval.new(0.5)) + + assert_in_delta RDF.Literal.value(result), + RDF.Literal.value(XSD.double(1.0)), + 0.000000000000001 end test "xsd:float literal + xsd:integer literal" do - assert result = %RDF.Literal{literal: %XSD.Float{}} = Numeric.add(XSD.float(1.1), XSD.integer(2)) + assert result = + %RDF.Literal{literal: %XSD.Float{}} = Numeric.add(XSD.float(1.1), XSD.integer(2)) + assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.float(3.1)), 0.000000000000001 - assert result = %RDF.Literal{literal: %XSD.Float{}} = + RDF.Literal.value(XSD.float(3.1)), + 0.000000000000001 + + assert result = + %RDF.Literal{literal: %XSD.Float{}} = Numeric.add(Age.new(42), FloatUnitInterval.new(0.5)) + assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.float(42.5)), 0.000000000000001 + RDF.Literal.value(XSD.float(42.5)), + 0.000000000000001 end test "xsd:decimal literal + xsd:float literal" do - assert result = %RDF.Literal{literal: %XSD.Float{}} = Numeric.add(XSD.decimal(1.1), XSD.float(2.2)) - assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.float(3.3)), 0.000000000000001 + assert result = + %RDF.Literal{literal: %XSD.Float{}} = Numeric.add(XSD.decimal(1.1), XSD.float(2.2)) - assert result = %RDF.Literal{literal: %XSD.Float{}} = - Numeric.add(DecimalUnitInterval.new(0.5), FloatUnitInterval.new(0.5)) assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.float(1.0)), 0.000000000000001 + RDF.Literal.value(XSD.float(3.3)), + 0.000000000000001 + + assert result = + %RDF.Literal{literal: %XSD.Float{}} = + Numeric.add(DecimalUnitInterval.new(0.5), FloatUnitInterval.new(0.5)) + + assert_in_delta RDF.Literal.value(result), + RDF.Literal.value(XSD.float(1.0)), + 0.000000000000001 end test "if one of the operands is a zero or a finite number and the other is INF or -INF, INF or -INF is returned" do @@ -180,15 +210,23 @@ defmodule RDF.XSD.NumericTest do end test "xsd:double literal - xsd:integer literal" do - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.subtract(XSD.double(3.3), XSD.integer(2)) + assert result = + %RDF.Literal{literal: %XSD.Double{}} = + Numeric.subtract(XSD.double(3.3), XSD.integer(2)) + assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(1.3)), 0.000000000000001 + RDF.Literal.value(XSD.double(1.3)), + 0.000000000000001 end test "xsd:decimal literal - xsd:double literal" do - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.subtract(XSD.decimal(3.3), XSD.double(2.2)) + assert result = + %RDF.Literal{literal: %XSD.Double{}} = + Numeric.subtract(XSD.decimal(3.3), XSD.double(2.2)) + assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(1.1)), 0.000000000000001 + RDF.Literal.value(XSD.double(1.1)), + 0.000000000000001 end test "if one of the operands is a zero or a finite number and the other is INF or -INF, an infinity of the appropriate sign is returned" do @@ -232,15 +270,23 @@ defmodule RDF.XSD.NumericTest do end test "xsd:double literal * xsd:integer literal" do - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.multiply(XSD.double(1.5), XSD.integer(3)) + assert result = + %RDF.Literal{literal: %XSD.Double{}} = + Numeric.multiply(XSD.double(1.5), XSD.integer(3)) + assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(4.5)), 0.000000000000001 + RDF.Literal.value(XSD.double(4.5)), + 0.000000000000001 end test "xsd:decimal literal * xsd:double literal" do - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.multiply(XSD.decimal(0.5), XSD.double(2.5)) + assert result = + %RDF.Literal{literal: %XSD.Double{}} = + Numeric.multiply(XSD.decimal(0.5), XSD.double(2.5)) + assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(1.25)), 0.000000000000001 + RDF.Literal.value(XSD.double(1.25)), + 0.000000000000001 end test "if one of the operands is a zero and the other is an infinity, NaN is returned" do @@ -300,15 +346,23 @@ defmodule RDF.XSD.NumericTest do end test "xsd:double literal / xsd:integer literal" do - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.divide(XSD.double(4), XSD.integer(2)) + assert result = + %RDF.Literal{literal: %XSD.Double{}} = + Numeric.divide(XSD.double(4), XSD.integer(2)) + assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(2)), 0.000000000000001 + RDF.Literal.value(XSD.double(2)), + 0.000000000000001 end test "xsd:decimal literal / xsd:double literal" do - assert result = %RDF.Literal{literal: %XSD.Double{}} = Numeric.divide(XSD.decimal(4), XSD.double(2)) + assert result = + %RDF.Literal{literal: %XSD.Double{}} = + Numeric.divide(XSD.decimal(4), XSD.double(2)) + assert_in_delta RDF.Literal.value(result), - RDF.Literal.value(XSD.double(2)), 0.000000000000001 + RDF.Literal.value(XSD.double(2)), + 0.000000000000001 end test "a positive number divided by positive zero returns INF" do @@ -652,173 +706,173 @@ defmodule RDF.XSD.NumericTest do test "result_type/3 (type-promotion)" do %{ XSD.Integer => %{ - XSD.Integer => XSD.Integer, + XSD.Integer => XSD.Integer, XSD.NonPositiveInteger => XSD.Integer, - XSD.NegativeInteger => XSD.Integer, - XSD.Long => XSD.Integer, - XSD.Int => XSD.Integer, - XSD.Short => XSD.Integer, - XSD.Byte => XSD.Integer, + XSD.NegativeInteger => XSD.Integer, + XSD.Long => XSD.Integer, + XSD.Int => XSD.Integer, + XSD.Short => XSD.Integer, + XSD.Byte => XSD.Integer, XSD.NonNegativeInteger => XSD.Integer, - XSD.UnsignedLong => XSD.Integer, - XSD.UnsignedInt => XSD.Integer, - XSD.UnsignedShort => XSD.Integer, - XSD.UnsignedByte => XSD.Integer, - XSD.PositiveInteger => XSD.Integer, - XSD.Decimal => XSD.Decimal, - XSD.Float => XSD.Float, - XSD.Double => XSD.Double, - DecimalUnitInterval => XSD.Decimal, - FloatUnitInterval => XSD.Float, - DoubleUnitInterval => XSD.Double, + XSD.UnsignedLong => XSD.Integer, + XSD.UnsignedInt => XSD.Integer, + XSD.UnsignedShort => XSD.Integer, + XSD.UnsignedByte => XSD.Integer, + XSD.PositiveInteger => XSD.Integer, + XSD.Decimal => XSD.Decimal, + XSD.Float => XSD.Float, + XSD.Double => XSD.Double, + DecimalUnitInterval => XSD.Decimal, + FloatUnitInterval => XSD.Float, + DoubleUnitInterval => XSD.Double }, XSD.Byte => %{ - XSD.Integer => XSD.Integer, + XSD.Integer => XSD.Integer, XSD.NonPositiveInteger => XSD.Integer, - XSD.NegativeInteger => XSD.Integer, - XSD.Long => XSD.Integer, - XSD.Int => XSD.Integer, - XSD.Short => XSD.Integer, - XSD.Byte => XSD.Integer, + XSD.NegativeInteger => XSD.Integer, + XSD.Long => XSD.Integer, + XSD.Int => XSD.Integer, + XSD.Short => XSD.Integer, + XSD.Byte => XSD.Integer, XSD.NonNegativeInteger => XSD.Integer, - XSD.UnsignedLong => XSD.Integer, - XSD.UnsignedInt => XSD.Integer, - XSD.UnsignedShort => XSD.Integer, - XSD.UnsignedByte => XSD.Integer, - XSD.PositiveInteger => XSD.Integer, - XSD.Decimal => XSD.Decimal, - XSD.Float => XSD.Float, - XSD.Double => XSD.Double, - DecimalUnitInterval => XSD.Decimal, - FloatUnitInterval => XSD.Float, - DoubleUnitInterval => XSD.Double, + XSD.UnsignedLong => XSD.Integer, + XSD.UnsignedInt => XSD.Integer, + XSD.UnsignedShort => XSD.Integer, + XSD.UnsignedByte => XSD.Integer, + XSD.PositiveInteger => XSD.Integer, + XSD.Decimal => XSD.Decimal, + XSD.Float => XSD.Float, + XSD.Double => XSD.Double, + DecimalUnitInterval => XSD.Decimal, + FloatUnitInterval => XSD.Float, + DoubleUnitInterval => XSD.Double }, XSD.Decimal => %{ - XSD.Integer => XSD.Decimal, + XSD.Integer => XSD.Decimal, XSD.NonPositiveInteger => XSD.Decimal, - XSD.NegativeInteger => XSD.Decimal, - XSD.Long => XSD.Decimal, - XSD.Int => XSD.Decimal, - XSD.Short => XSD.Decimal, - XSD.Byte => XSD.Decimal, + XSD.NegativeInteger => XSD.Decimal, + XSD.Long => XSD.Decimal, + XSD.Int => XSD.Decimal, + XSD.Short => XSD.Decimal, + XSD.Byte => XSD.Decimal, XSD.NonNegativeInteger => XSD.Decimal, - XSD.UnsignedLong => XSD.Decimal, - XSD.UnsignedInt => XSD.Decimal, - XSD.UnsignedShort => XSD.Decimal, - XSD.UnsignedByte => XSD.Decimal, - XSD.PositiveInteger => XSD.Decimal, - XSD.Decimal => XSD.Decimal, - XSD.Float => XSD.Float, - XSD.Double => XSD.Double, - DecimalUnitInterval => XSD.Decimal, - FloatUnitInterval => XSD.Float, - DoubleUnitInterval => XSD.Double, + XSD.UnsignedLong => XSD.Decimal, + XSD.UnsignedInt => XSD.Decimal, + XSD.UnsignedShort => XSD.Decimal, + XSD.UnsignedByte => XSD.Decimal, + XSD.PositiveInteger => XSD.Decimal, + XSD.Decimal => XSD.Decimal, + XSD.Float => XSD.Float, + XSD.Double => XSD.Double, + DecimalUnitInterval => XSD.Decimal, + FloatUnitInterval => XSD.Float, + DoubleUnitInterval => XSD.Double }, DecimalUnitInterval => %{ - XSD.Integer => XSD.Decimal, + XSD.Integer => XSD.Decimal, XSD.NonPositiveInteger => XSD.Decimal, - XSD.NegativeInteger => XSD.Decimal, - XSD.Long => XSD.Decimal, - XSD.Int => XSD.Decimal, - XSD.Short => XSD.Decimal, - XSD.Byte => XSD.Decimal, + XSD.NegativeInteger => XSD.Decimal, + XSD.Long => XSD.Decimal, + XSD.Int => XSD.Decimal, + XSD.Short => XSD.Decimal, + XSD.Byte => XSD.Decimal, XSD.NonNegativeInteger => XSD.Decimal, - XSD.UnsignedLong => XSD.Decimal, - XSD.UnsignedInt => XSD.Decimal, - XSD.UnsignedShort => XSD.Decimal, - XSD.UnsignedByte => XSD.Decimal, - XSD.PositiveInteger => XSD.Decimal, - XSD.Decimal => XSD.Decimal, - XSD.Float => XSD.Float, - XSD.Double => XSD.Double, - DecimalUnitInterval => XSD.Decimal, - FloatUnitInterval => XSD.Float, - DoubleUnitInterval => XSD.Double, + XSD.UnsignedLong => XSD.Decimal, + XSD.UnsignedInt => XSD.Decimal, + XSD.UnsignedShort => XSD.Decimal, + XSD.UnsignedByte => XSD.Decimal, + XSD.PositiveInteger => XSD.Decimal, + XSD.Decimal => XSD.Decimal, + XSD.Float => XSD.Float, + XSD.Double => XSD.Double, + DecimalUnitInterval => XSD.Decimal, + FloatUnitInterval => XSD.Float, + DoubleUnitInterval => XSD.Double }, XSD.Float => %{ - XSD.Integer => XSD.Float, + XSD.Integer => XSD.Float, XSD.NonPositiveInteger => XSD.Float, - XSD.NegativeInteger => XSD.Float, - XSD.Long => XSD.Float, - XSD.Int => XSD.Float, - XSD.Short => XSD.Float, - XSD.Byte => XSD.Float, + XSD.NegativeInteger => XSD.Float, + XSD.Long => XSD.Float, + XSD.Int => XSD.Float, + XSD.Short => XSD.Float, + XSD.Byte => XSD.Float, XSD.NonNegativeInteger => XSD.Float, - XSD.UnsignedLong => XSD.Float, - XSD.UnsignedInt => XSD.Float, - XSD.UnsignedShort => XSD.Float, - XSD.UnsignedByte => XSD.Float, - XSD.PositiveInteger => XSD.Float, - XSD.Decimal => XSD.Float, - XSD.Float => XSD.Float, - XSD.Double => XSD.Double, - DecimalUnitInterval => XSD.Float, - FloatUnitInterval => XSD.Float, - DoubleUnitInterval => XSD.Double, + XSD.UnsignedLong => XSD.Float, + XSD.UnsignedInt => XSD.Float, + XSD.UnsignedShort => XSD.Float, + XSD.UnsignedByte => XSD.Float, + XSD.PositiveInteger => XSD.Float, + XSD.Decimal => XSD.Float, + XSD.Float => XSD.Float, + XSD.Double => XSD.Double, + DecimalUnitInterval => XSD.Float, + FloatUnitInterval => XSD.Float, + DoubleUnitInterval => XSD.Double }, FloatUnitInterval => %{ - XSD.Integer => XSD.Float, + XSD.Integer => XSD.Float, XSD.NonPositiveInteger => XSD.Float, - XSD.NegativeInteger => XSD.Float, - XSD.Long => XSD.Float, - XSD.Int => XSD.Float, - XSD.Short => XSD.Float, - XSD.Byte => XSD.Float, + XSD.NegativeInteger => XSD.Float, + XSD.Long => XSD.Float, + XSD.Int => XSD.Float, + XSD.Short => XSD.Float, + XSD.Byte => XSD.Float, XSD.NonNegativeInteger => XSD.Float, - XSD.UnsignedLong => XSD.Float, - XSD.UnsignedInt => XSD.Float, - XSD.UnsignedShort => XSD.Float, - XSD.UnsignedByte => XSD.Float, - XSD.PositiveInteger => XSD.Float, - XSD.Decimal => XSD.Float, - XSD.Float => XSD.Float, - XSD.Double => XSD.Double, - DecimalUnitInterval => XSD.Float, - FloatUnitInterval => XSD.Float, - DoubleUnitInterval => XSD.Double, + XSD.UnsignedLong => XSD.Float, + XSD.UnsignedInt => XSD.Float, + XSD.UnsignedShort => XSD.Float, + XSD.UnsignedByte => XSD.Float, + XSD.PositiveInteger => XSD.Float, + XSD.Decimal => XSD.Float, + XSD.Float => XSD.Float, + XSD.Double => XSD.Double, + DecimalUnitInterval => XSD.Float, + FloatUnitInterval => XSD.Float, + DoubleUnitInterval => XSD.Double }, XSD.Double => %{ - XSD.Integer => XSD.Double, + XSD.Integer => XSD.Double, XSD.NonPositiveInteger => XSD.Double, - XSD.NegativeInteger => XSD.Double, - XSD.Long => XSD.Double, - XSD.Int => XSD.Double, - XSD.Short => XSD.Double, - XSD.Byte => XSD.Double, + XSD.NegativeInteger => XSD.Double, + XSD.Long => XSD.Double, + XSD.Int => XSD.Double, + XSD.Short => XSD.Double, + XSD.Byte => XSD.Double, XSD.NonNegativeInteger => XSD.Double, - XSD.UnsignedLong => XSD.Double, - XSD.UnsignedInt => XSD.Double, - XSD.UnsignedShort => XSD.Double, - XSD.UnsignedByte => XSD.Double, - XSD.PositiveInteger => XSD.Double, - XSD.Decimal => XSD.Double, - XSD.Float => XSD.Double, - XSD.Double => XSD.Double, - DecimalUnitInterval => XSD.Double, - FloatUnitInterval => XSD.Double, - DoubleUnitInterval => XSD.Double, + XSD.UnsignedLong => XSD.Double, + XSD.UnsignedInt => XSD.Double, + XSD.UnsignedShort => XSD.Double, + XSD.UnsignedByte => XSD.Double, + XSD.PositiveInteger => XSD.Double, + XSD.Decimal => XSD.Double, + XSD.Float => XSD.Double, + XSD.Double => XSD.Double, + DecimalUnitInterval => XSD.Double, + FloatUnitInterval => XSD.Double, + DoubleUnitInterval => XSD.Double }, DoubleUnitInterval => %{ - XSD.Integer => XSD.Double, + XSD.Integer => XSD.Double, XSD.NonPositiveInteger => XSD.Double, - XSD.NegativeInteger => XSD.Double, - XSD.Long => XSD.Double, - XSD.Int => XSD.Double, - XSD.Short => XSD.Double, - XSD.Byte => XSD.Double, + XSD.NegativeInteger => XSD.Double, + XSD.Long => XSD.Double, + XSD.Int => XSD.Double, + XSD.Short => XSD.Double, + XSD.Byte => XSD.Double, XSD.NonNegativeInteger => XSD.Double, - XSD.UnsignedLong => XSD.Double, - XSD.UnsignedInt => XSD.Double, - XSD.UnsignedShort => XSD.Double, - XSD.UnsignedByte => XSD.Double, - XSD.PositiveInteger => XSD.Double, - XSD.Decimal => XSD.Double, - XSD.Float => XSD.Double, - XSD.Double => XSD.Double, - DecimalUnitInterval => XSD.Double, - FloatUnitInterval => XSD.Double, - DoubleUnitInterval => XSD.Double, - }, + XSD.UnsignedLong => XSD.Double, + XSD.UnsignedInt => XSD.Double, + XSD.UnsignedShort => XSD.Double, + XSD.UnsignedByte => XSD.Double, + XSD.PositiveInteger => XSD.Double, + XSD.Decimal => XSD.Double, + XSD.Float => XSD.Double, + XSD.Double => XSD.Double, + DecimalUnitInterval => XSD.Double, + FloatUnitInterval => XSD.Double, + DoubleUnitInterval => XSD.Double + } } |> Enum.each(fn {left, right_result} -> Enum.each(right_result, fn {right, result} -> diff --git a/test/unit/xsd/datatypes/string_test.exs b/test/unit/xsd/datatypes/string_test.exs index 4165eb3..3e28520 100644 --- a/test/unit/xsd/datatypes/string_test.exs +++ b/test/unit/xsd/datatypes/string_test.exs @@ -128,7 +128,8 @@ defmodule RDF.XSD.StringTest do end test "casting an IRI" do - assert RDF.iri("http://example.com") |> XSD.String.cast() == XSD.string("http://example.com") + assert RDF.iri("http://example.com") |> XSD.String.cast() == + XSD.string("http://example.com") end test "with invalid literals" do diff --git a/test/unit/xsd/datatypes/time_test.exs b/test/unit/xsd/datatypes/time_test.exs index 232b503..f9d2064 100644 --- a/test/unit/xsd/datatypes/time_test.exs +++ b/test/unit/xsd/datatypes/time_test.exs @@ -49,45 +49,57 @@ defmodule RDF.XSD.TimeTest do describe "new/2" do test "with date and tz opt" do assert XSD.Time.new("12:00:00", tz: "+01:00") == - %RDF.Literal{literal: %XSD.Time{ - value: {~T[11:00:00], true}, - uncanonical_lexical: "12:00:00+01:00" - }} + %RDF.Literal{ + literal: %XSD.Time{ + value: {~T[11:00:00], true}, + uncanonical_lexical: "12:00:00+01:00" + } + } assert XSD.Time.new(~T[12:00:00], tz: "+01:00") == - %RDF.Literal{literal: %XSD.Time{ - value: {~T[11:00:00], true}, - uncanonical_lexical: "12:00:00+01:00" - }} + %RDF.Literal{ + literal: %XSD.Time{ + value: {~T[11:00:00], true}, + uncanonical_lexical: "12:00:00+01:00" + } + } assert XSD.Time.new("12:00:00", tz: "+00:00") == - %RDF.Literal{literal: %XSD.Time{ - value: {~T[12:00:00], true}, - uncanonical_lexical: "12:00:00+00:00" - }} + %RDF.Literal{ + literal: %XSD.Time{ + value: {~T[12:00:00], true}, + uncanonical_lexical: "12:00:00+00:00" + } + } assert XSD.Time.new(~T[12:00:00], tz: "+00:00") == - %RDF.Literal{literal: %XSD.Time{ - value: {~T[12:00:00], true}, - uncanonical_lexical: "12:00:00+00:00" - }} + %RDF.Literal{ + literal: %XSD.Time{ + value: {~T[12:00:00], true}, + uncanonical_lexical: "12:00:00+00:00" + } + } end test "with date string including a timezone and tz opt" do assert XSD.Time.new("12:00:00+00:00", tz: "+01:00") == - %RDF.Literal{literal: %XSD.Time{ - value: {~T[11:00:00], true}, - uncanonical_lexical: "12:00:00+01:00" - }} + %RDF.Literal{ + literal: %XSD.Time{ + value: {~T[11:00:00], true}, + uncanonical_lexical: "12:00:00+01:00" + } + } assert XSD.Time.new("12:00:00+01:00", tz: "Z") == %RDF.Literal{literal: %XSD.Time{value: {~T[12:00:00], true}}} assert XSD.Time.new("12:00:00+01:00", tz: "+00:00") == - %RDF.Literal{literal: %XSD.Time{ - value: {~T[12:00:00], true}, - uncanonical_lexical: "12:00:00+00:00" - }} + %RDF.Literal{ + literal: %XSD.Time{ + value: {~T[12:00:00], true}, + uncanonical_lexical: "12:00:00+00:00" + } + } end test "with invalid tz opt" do diff --git a/test/unit/xsd/facets/explicit_timezone_test.exs b/test/unit/xsd/facets/explicit_timezone_test.exs index b77eece..d204867 100644 --- a/test/unit/xsd/facets/explicit_timezone_test.exs +++ b/test/unit/xsd/facets/explicit_timezone_test.exs @@ -19,7 +19,7 @@ defmodule RDF.XSD.Facets.ExplicitTimezoneTest do end test "CustomTime" do - assert CustomTime.new(~T[00:00:00] ) |> RDF.Literal.valid?() + assert CustomTime.new(~T[00:00:00]) |> RDF.Literal.valid?() assert CustomTime.new("00:00:00Z") |> RDF.Literal.valid?() assert CustomTime.new("00:00:00") |> RDF.Literal.valid?() end diff --git a/test/unit/xsd/xsd_test.exs b/test/unit/xsd/xsd_test.exs index 290310f..ea43979 100644 --- a/test/unit/xsd/xsd_test.exs +++ b/test/unit/xsd/xsd_test.exs @@ -11,7 +11,7 @@ defmodule RDF.XSDTest do end test "true and false aliases" do - assert XSD.true == XSD.Boolean.new(true) - assert XSD.false == XSD.Boolean.new(false) + assert XSD.true() == XSD.Boolean.new(true) + assert XSD.false() == XSD.Boolean.new(false) end end