Apply mix formatter
This commit is contained in:
parent
9314cc6757
commit
b06586c387
4
.formatter.exs
Normal file
4
.formatter.exs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
[
|
||||||
|
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
|
||||||
|
import_deps: [:rdf]
|
||||||
|
]
|
|
@ -4,32 +4,37 @@ defmodule JSON.LD.Compaction do
|
||||||
import JSON.LD.Utils
|
import JSON.LD.Utils
|
||||||
alias JSON.LD.Context
|
alias JSON.LD.Context
|
||||||
|
|
||||||
|
|
||||||
def compact(input, context, options \\ %JSON.LD.Options{}) do
|
def compact(input, context, options \\ %JSON.LD.Options{}) do
|
||||||
with options = JSON.LD.Options.new(options),
|
with options = JSON.LD.Options.new(options),
|
||||||
active_context = JSON.LD.context(context, options),
|
active_context = JSON.LD.context(context, options),
|
||||||
inverse_context = Context.inverse(active_context),
|
inverse_context = Context.inverse(active_context),
|
||||||
expanded = JSON.LD.expand(input, options)
|
expanded = JSON.LD.expand(input, options) do
|
||||||
do
|
|
||||||
result =
|
result =
|
||||||
case do_compact(expanded, active_context, inverse_context, nil, options.compact_arrays) do
|
case do_compact(expanded, active_context, inverse_context, nil, options.compact_arrays) do
|
||||||
[] ->
|
[] ->
|
||||||
%{}
|
%{}
|
||||||
|
|
||||||
result when is_list(result) ->
|
result when is_list(result) ->
|
||||||
# TODO: Spec fixme? We're setting vocab to true, as other implementations do it, but this is not mentioned in the spec
|
# TODO: Spec fixme? We're setting vocab to true, as other implementations do it, but this is not mentioned in the spec
|
||||||
%{compact_iri("@graph", active_context, inverse_context, nil, true) => result}
|
%{compact_iri("@graph", active_context, inverse_context, nil, true) => result}
|
||||||
|
|
||||||
result ->
|
result ->
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
if Context.empty?(active_context),
|
if Context.empty?(active_context),
|
||||||
do: result,
|
do: result,
|
||||||
else: Map.put(result, "@context", context["@context"] || context)
|
else: Map.put(result, "@context", context["@context"] || context)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp do_compact(element, active_context, inverse_context, active_property,
|
defp do_compact(
|
||||||
compact_arrays \\ true)
|
element,
|
||||||
|
active_context,
|
||||||
|
inverse_context,
|
||||||
|
active_property,
|
||||||
|
compact_arrays \\ true
|
||||||
|
)
|
||||||
|
|
||||||
# 1) If element is a scalar, it is already in its most compact form, so simply return element.
|
# 1) If element is a scalar, it is already in its most compact form, so simply return element.
|
||||||
defp do_compact(element, _, _, _, _)
|
defp do_compact(element, _, _, _, _)
|
||||||
|
@ -39,14 +44,19 @@ defmodule JSON.LD.Compaction do
|
||||||
# 2) If element is an array
|
# 2) If element is an array
|
||||||
defp do_compact(element, active_context, inverse_context, active_property, compact_arrays)
|
defp do_compact(element, active_context, inverse_context, active_property, compact_arrays)
|
||||||
when is_list(element) do
|
when is_list(element) do
|
||||||
result = Enum.reduce(element, [], fn (item, result) ->
|
result =
|
||||||
|
Enum.reduce(element, [], fn item, result ->
|
||||||
case do_compact(item, active_context, inverse_context, active_property, compact_arrays) do
|
case do_compact(item, active_context, inverse_context, active_property, compact_arrays) do
|
||||||
nil -> result
|
nil -> result
|
||||||
compacted_item -> [compacted_item | result]
|
compacted_item -> [compacted_item | result]
|
||||||
end
|
end
|
||||||
end) |> Enum.reverse
|
end)
|
||||||
|
|> Enum.reverse()
|
||||||
|
|
||||||
if compact_arrays and length(result) == 1 and
|
if compact_arrays and length(result) == 1 and
|
||||||
is_nil((term_def = active_context.term_defs[active_property]) && term_def.container_mapping) do
|
is_nil(
|
||||||
|
(term_def = active_context.term_defs[active_property]) && term_def.container_mapping
|
||||||
|
) do
|
||||||
List.first(result)
|
List.first(result)
|
||||||
else
|
else
|
||||||
result
|
result
|
||||||
|
@ -57,50 +67,81 @@ defmodule JSON.LD.Compaction do
|
||||||
defp do_compact(element, active_context, inverse_context, active_property, compact_arrays)
|
defp do_compact(element, active_context, inverse_context, active_property, compact_arrays)
|
||||||
when is_map(element) do
|
when is_map(element) do
|
||||||
# 4)
|
# 4)
|
||||||
if (Map.has_key?(element, "@value") or Map.has_key?(element, "@id")) do
|
if Map.has_key?(element, "@value") or Map.has_key?(element, "@id") do
|
||||||
result = compact_value(element, active_context, inverse_context, active_property)
|
result = compact_value(element, active_context, inverse_context, active_property)
|
||||||
|
|
||||||
if scalar?(result) do
|
if scalar?(result) do
|
||||||
result
|
result
|
||||||
else
|
else
|
||||||
do_compact_non_scalar(element, active_context, inverse_context, active_property, compact_arrays)
|
do_compact_non_scalar(
|
||||||
|
element,
|
||||||
|
active_context,
|
||||||
|
inverse_context,
|
||||||
|
active_property,
|
||||||
|
compact_arrays
|
||||||
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
do_compact_non_scalar(element, active_context, inverse_context, active_property, compact_arrays)
|
do_compact_non_scalar(
|
||||||
|
element,
|
||||||
|
active_context,
|
||||||
|
inverse_context,
|
||||||
|
active_property,
|
||||||
|
compact_arrays
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp do_compact_non_scalar(element, active_context, inverse_context, active_property, compact_arrays) do
|
defp do_compact_non_scalar(
|
||||||
|
element,
|
||||||
|
active_context,
|
||||||
|
inverse_context,
|
||||||
|
active_property,
|
||||||
|
compact_arrays
|
||||||
|
) do
|
||||||
# 5)
|
# 5)
|
||||||
inside_reverse = active_property == "@reverse"
|
inside_reverse = active_property == "@reverse"
|
||||||
# 6) + 7)
|
# 6) + 7)
|
||||||
element
|
element
|
||||||
|> Enum.sort_by(fn {expanded_property, _} -> expanded_property end)
|
|> Enum.sort_by(fn {expanded_property, _} -> expanded_property end)
|
||||||
|> Enum.reduce(%{}, fn ({expanded_property, expanded_value}, result) ->
|
|> Enum.reduce(%{}, fn {expanded_property, expanded_value}, result ->
|
||||||
cond do
|
cond do
|
||||||
# 7.1)
|
# 7.1)
|
||||||
expanded_property in ~w[@id @type] ->
|
expanded_property in ~w[@id @type] ->
|
||||||
# 7.1.1)
|
# 7.1.1)
|
||||||
compacted_value =
|
compacted_value =
|
||||||
if is_binary(expanded_value) do
|
if is_binary(expanded_value) do
|
||||||
compact_iri(expanded_value, active_context, inverse_context, nil,
|
compact_iri(
|
||||||
expanded_property == "@type")
|
expanded_value,
|
||||||
|
active_context,
|
||||||
|
inverse_context,
|
||||||
|
nil,
|
||||||
|
expanded_property == "@type"
|
||||||
|
)
|
||||||
|
|
||||||
# 7.1.2)
|
# 7.1.2)
|
||||||
else
|
else
|
||||||
# 7.1.2.1)
|
# 7.1.2.1)
|
||||||
# TODO: RDF.rb calls also Array#compact
|
# TODO: RDF.rb calls also Array#compact
|
||||||
if(is_list(expanded_value),
|
if(is_list(expanded_value),
|
||||||
do: expanded_value,
|
do: expanded_value,
|
||||||
else: [expanded_value])
|
else: [expanded_value]
|
||||||
|
)
|
||||||
# 7.1.2.2)
|
# 7.1.2.2)
|
||||||
|> Enum.reduce([], fn (expanded_type, compacted_value) ->
|
|> Enum.reduce([], fn expanded_type, compacted_value ->
|
||||||
compacted_value ++
|
compacted_value ++
|
||||||
[compact_iri(expanded_type, active_context, inverse_context, nil, true)]
|
[compact_iri(expanded_type, active_context, inverse_context, nil, true)]
|
||||||
end)
|
end)
|
||||||
# 7.1.2.3)
|
# 7.1.2.3)
|
||||||
|> case(do: (
|
|> case(
|
||||||
|
do:
|
||||||
|
(
|
||||||
[compacted_value] -> compacted_value
|
[compacted_value] -> compacted_value
|
||||||
compacted_value -> compacted_value))
|
compacted_value -> compacted_value
|
||||||
|
)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
# 7.1.3)
|
# 7.1.3)
|
||||||
alias = compact_iri(expanded_property, active_context, inverse_context, nil, true)
|
alias = compact_iri(expanded_property, active_context, inverse_context, nil, true)
|
||||||
# 7.1.4)
|
# 7.1.4)
|
||||||
|
@ -109,11 +150,13 @@ defmodule JSON.LD.Compaction do
|
||||||
# 7.2)
|
# 7.2)
|
||||||
expanded_property == "@reverse" ->
|
expanded_property == "@reverse" ->
|
||||||
# 7.2.1)
|
# 7.2.1)
|
||||||
compacted_value = do_compact(expanded_value, active_context, inverse_context, "@reverse")
|
compacted_value =
|
||||||
|
do_compact(expanded_value, active_context, inverse_context, "@reverse")
|
||||||
|
|
||||||
# 7.2.2)
|
# 7.2.2)
|
||||||
{compacted_value, result} =
|
{compacted_value, result} =
|
||||||
Enum.reduce compacted_value, {%{}, result},
|
Enum.reduce(compacted_value, {%{}, result}, fn {property, value},
|
||||||
fn ({property, value}, {compacted_value, result}) ->
|
{compacted_value, result} ->
|
||||||
term_def = active_context.term_defs[property]
|
term_def = active_context.term_defs[property]
|
||||||
# 7.2.2.1)
|
# 7.2.2.1)
|
||||||
if term_def && term_def.reverse_property do
|
if term_def && term_def.reverse_property do
|
||||||
|
@ -125,12 +168,14 @@ defmodule JSON.LD.Compaction do
|
||||||
else
|
else
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
|
|
||||||
# 7.2.2.1.2) + 7.2.2.1.3)
|
# 7.2.2.1.2) + 7.2.2.1.3)
|
||||||
{compacted_value, merge_compacted_value(result, property, value)}
|
{compacted_value, merge_compacted_value(result, property, value)}
|
||||||
else
|
else
|
||||||
{Map.put(compacted_value, property, value), result}
|
{Map.put(compacted_value, property, value), result}
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
|
|
||||||
# 7.2.3)
|
# 7.2.3)
|
||||||
unless Enum.empty?(compacted_value) do
|
unless Enum.empty?(compacted_value) do
|
||||||
# 7.2.3.1)
|
# 7.2.3.1)
|
||||||
|
@ -160,8 +205,15 @@ defmodule JSON.LD.Compaction do
|
||||||
if expanded_value == [] do
|
if expanded_value == [] do
|
||||||
# 7.5.1)
|
# 7.5.1)
|
||||||
item_active_property =
|
item_active_property =
|
||||||
compact_iri(expanded_property, active_context, inverse_context,
|
compact_iri(
|
||||||
expanded_value, true, inside_reverse)
|
expanded_property,
|
||||||
|
active_context,
|
||||||
|
inverse_context,
|
||||||
|
expanded_value,
|
||||||
|
true,
|
||||||
|
inside_reverse
|
||||||
|
)
|
||||||
|
|
||||||
# 7.5.2)
|
# 7.5.2)
|
||||||
Map.update(result, item_active_property, [], fn
|
Map.update(result, item_active_property, [], fn
|
||||||
value when not is_list(value) -> [value]
|
value when not is_list(value) -> [value]
|
||||||
|
@ -172,11 +224,17 @@ defmodule JSON.LD.Compaction do
|
||||||
end
|
end
|
||||||
|
|
||||||
# 7.6)
|
# 7.6)
|
||||||
Enum.reduce(expanded_value, result, fn (expanded_item, result) ->
|
Enum.reduce(expanded_value, result, fn expanded_item, result ->
|
||||||
# 7.6.1)
|
# 7.6.1)
|
||||||
item_active_property =
|
item_active_property =
|
||||||
compact_iri(expanded_property, active_context, inverse_context,
|
compact_iri(
|
||||||
expanded_item, true, inside_reverse)
|
expanded_property,
|
||||||
|
active_context,
|
||||||
|
inverse_context,
|
||||||
|
expanded_item,
|
||||||
|
true,
|
||||||
|
inside_reverse
|
||||||
|
)
|
||||||
|
|
||||||
# 7.6.2)
|
# 7.6.2)
|
||||||
term_def = active_context.term_defs[item_active_property]
|
term_def = active_context.term_defs[item_active_property]
|
||||||
|
@ -184,38 +242,50 @@ defmodule JSON.LD.Compaction do
|
||||||
|
|
||||||
# 7.6.3)
|
# 7.6.3)
|
||||||
value = (is_map(expanded_item) && expanded_item["@list"]) || expanded_item
|
value = (is_map(expanded_item) && expanded_item["@list"]) || expanded_item
|
||||||
|
|
||||||
compacted_item =
|
compacted_item =
|
||||||
do_compact(value, active_context, inverse_context,
|
do_compact(
|
||||||
item_active_property, compact_arrays)
|
value,
|
||||||
|
active_context,
|
||||||
|
inverse_context,
|
||||||
|
item_active_property,
|
||||||
|
compact_arrays
|
||||||
|
)
|
||||||
|
|
||||||
# 7.6.4)
|
# 7.6.4)
|
||||||
compacted_item =
|
compacted_item =
|
||||||
if list?(expanded_item) do
|
if list?(expanded_item) do
|
||||||
# 7.6.4.1)
|
# 7.6.4.1)
|
||||||
compacted_item =
|
compacted_item =
|
||||||
unless is_list(compacted_item),
|
unless is_list(compacted_item), do: [compacted_item], else: compacted_item
|
||||||
do: [compacted_item], else: compacted_item
|
|
||||||
# 7.6.4.2)
|
# 7.6.4.2)
|
||||||
unless container == "@list" do
|
unless container == "@list" do
|
||||||
# 7.6.4.2.1)
|
# 7.6.4.2.1)
|
||||||
compacted_item = %{
|
compacted_item = %{
|
||||||
# TODO: Spec fixme? We're setting vocab to true, as other implementations do it, but this is not mentioned in the spec
|
# TODO: Spec fixme? We're setting vocab to true, as other implementations do it, but this is not mentioned in the spec
|
||||||
compact_iri("@list", active_context, inverse_context, nil, true) =>
|
compact_iri("@list", active_context, inverse_context, nil, true) =>
|
||||||
compacted_item}
|
compacted_item
|
||||||
|
}
|
||||||
|
|
||||||
# 7.6.4.2.2)
|
# 7.6.4.2.2)
|
||||||
if Map.has_key?(expanded_item, "@index") do
|
if Map.has_key?(expanded_item, "@index") do
|
||||||
Map.put(compacted_item,
|
Map.put(
|
||||||
|
compacted_item,
|
||||||
# TODO: Spec fixme? We're setting vocab to true, as other implementations do it, but this is not mentioned in the spec
|
# TODO: Spec fixme? We're setting vocab to true, as other implementations do it, but this is not mentioned in the spec
|
||||||
compact_iri("@index", active_context, inverse_context, nil, true),
|
compact_iri("@index", active_context, inverse_context, nil, true),
|
||||||
expanded_item["@index"])
|
expanded_item["@index"]
|
||||||
|
)
|
||||||
else
|
else
|
||||||
compacted_item
|
compacted_item
|
||||||
end
|
end
|
||||||
|
|
||||||
# 7.6.4.3)
|
# 7.6.4.3)
|
||||||
else
|
else
|
||||||
if Map.has_key?(result, item_active_property) do
|
if Map.has_key?(result, item_active_property) do
|
||||||
raise JSON.LD.CompactionToListOfListsError,
|
raise JSON.LD.CompactionToListOfListsError,
|
||||||
message: "The compacted document contains a list of lists as multiple lists have been compacted to the same term."
|
message:
|
||||||
|
"The compacted document contains a list of lists as multiple lists have been compacted to the same term."
|
||||||
else
|
else
|
||||||
compacted_item
|
compacted_item
|
||||||
end
|
end
|
||||||
|
@ -227,11 +297,13 @@ defmodule JSON.LD.Compaction do
|
||||||
# 7.6.5)
|
# 7.6.5)
|
||||||
if container in ~w[@language @index] do
|
if container in ~w[@language @index] do
|
||||||
map_object = result[item_active_property] || %{}
|
map_object = result[item_active_property] || %{}
|
||||||
|
|
||||||
compacted_item =
|
compacted_item =
|
||||||
if container == "@language" and
|
if container == "@language" and
|
||||||
is_map(compacted_item) and Map.has_key?(compacted_item, "@value"),
|
is_map(compacted_item) and Map.has_key?(compacted_item, "@value"),
|
||||||
do: compacted_item["@value"],
|
do: compacted_item["@value"],
|
||||||
else: compacted_item
|
else: compacted_item
|
||||||
|
|
||||||
map_key = expanded_item[container]
|
map_key = expanded_item[container]
|
||||||
map_object = merge_compacted_value(map_object, map_key, compacted_item)
|
map_object = merge_compacted_value(map_object, map_key, compacted_item)
|
||||||
Map.put(result, item_active_property, map_object)
|
Map.put(result, item_active_property, map_object)
|
||||||
|
@ -239,10 +311,12 @@ defmodule JSON.LD.Compaction do
|
||||||
# 7.6.6)
|
# 7.6.6)
|
||||||
else
|
else
|
||||||
compacted_item =
|
compacted_item =
|
||||||
if !is_list(compacted_item) and (!compact_arrays or
|
if !is_list(compacted_item) and
|
||||||
|
(!compact_arrays or
|
||||||
container in ~w[@set @list] or expanded_property in ~w[@list @graph]),
|
container in ~w[@set @list] or expanded_property in ~w[@list @graph]),
|
||||||
do: [compacted_item],
|
do: [compacted_item],
|
||||||
else: compacted_item
|
else: compacted_item
|
||||||
|
|
||||||
merge_compacted_value(result, item_active_property, compacted_item)
|
merge_compacted_value(result, item_active_property, compacted_item)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -251,42 +325,53 @@ defmodule JSON.LD.Compaction do
|
||||||
end
|
end
|
||||||
|
|
||||||
defp merge_compacted_value(map, key, value) do
|
defp merge_compacted_value(map, key, value) do
|
||||||
Map.update map, key, value, fn
|
Map.update(map, key, value, fn
|
||||||
old_value when is_list(old_value) and is_list(value) ->
|
old_value when is_list(old_value) and is_list(value) ->
|
||||||
old_value ++ value
|
old_value ++ value
|
||||||
|
|
||||||
old_value when is_list(old_value) ->
|
old_value when is_list(old_value) ->
|
||||||
old_value ++ [value]
|
old_value ++ [value]
|
||||||
|
|
||||||
old_value when is_list(value) ->
|
old_value when is_list(value) ->
|
||||||
[old_value | value]
|
[old_value | value]
|
||||||
|
|
||||||
old_value ->
|
old_value ->
|
||||||
[old_value, value]
|
[old_value, value]
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
IRI Compaction
|
IRI Compaction
|
||||||
|
|
||||||
Details at <https://www.w3.org/TR/json-ld-api/#iri-compaction>
|
Details at <https://www.w3.org/TR/json-ld-api/#iri-compaction>
|
||||||
"""
|
"""
|
||||||
def compact_iri(iri, active_context, inverse_context,
|
def compact_iri(
|
||||||
value \\ nil, vocab \\ false, reverse \\ false)
|
iri,
|
||||||
|
active_context,
|
||||||
|
inverse_context,
|
||||||
|
value \\ nil,
|
||||||
|
vocab \\ false,
|
||||||
|
reverse \\ false
|
||||||
|
)
|
||||||
|
|
||||||
# 1) If iri is null, return null.
|
# 1) If iri is null, return null.
|
||||||
def compact_iri(nil, _, _, _, _, _), do: nil
|
def compact_iri(nil, _, _, _, _, _), do: nil
|
||||||
|
|
||||||
def compact_iri(iri, active_context, inverse_context, value, vocab, reverse) do
|
def compact_iri(iri, active_context, inverse_context, value, vocab, reverse) do
|
||||||
# 2) If vocab is true and iri is a key in inverse context:
|
# 2) If vocab is true and iri is a key in inverse context:
|
||||||
term = if vocab && Map.has_key?(inverse_context, iri) do
|
term =
|
||||||
|
if vocab && Map.has_key?(inverse_context, iri) do
|
||||||
# 2.1) Initialize default language to active context's default language, if it has one, otherwise to @none.
|
# 2.1) Initialize default language to active context's default language, if it has one, otherwise to @none.
|
||||||
# TODO: Spec fixme: This step is effectively useless; see Spec fixme on step 2.6.3
|
# TODO: Spec fixme: This step is effectively useless; see Spec fixme on step 2.6.3
|
||||||
# default_language = active_context.default_language || "@none"
|
# default_language = active_context.default_language || "@none"
|
||||||
# 2.3) Initialize type/language to @language, and type/language value to @null. These two variables will keep track of the preferred type mapping or language mapping for a term, based on what is compatible with value.
|
# 2.3) Initialize type/language to @language, and type/language value to @null. These two variables will keep track of the preferred type mapping or language mapping for a term, based on what is compatible with value.
|
||||||
type_language = "@language"
|
type_language = "@language"
|
||||||
type_language_value = "@null"
|
type_language_value = "@null"
|
||||||
|
|
||||||
# 2.2) Initialize containers to an empty array. This array will be used to keep track of an ordered list of preferred container mappings for a term, based on what is compatible with value.
|
# 2.2) Initialize containers to an empty array. This array will be used to keep track of an ordered list of preferred container mappings for a term, based on what is compatible with value.
|
||||||
# 2.4) If value is a JSON object that contains the key @index, then append the value @index to containers.
|
# 2.4) If value is a JSON object that contains the key @index, then append the value @index to containers.
|
||||||
containers = if index?(value), do: ["@index"], else: []
|
containers = if index?(value), do: ["@index"], else: []
|
||||||
|
|
||||||
{containers, type_language, type_language_value} =
|
{containers, type_language, type_language_value} =
|
||||||
cond do
|
cond do
|
||||||
# 2.5) If reverse is true, set type/language to @type, type/language value to @reverse, and append @set to containers.
|
# 2.5) If reverse is true, set type/language to @type, type/language value to @reverse, and append @set to containers.
|
||||||
|
@ -295,24 +380,27 @@ defmodule JSON.LD.Compaction do
|
||||||
type_language = "@type"
|
type_language = "@type"
|
||||||
type_language_value = "@reverse"
|
type_language_value = "@reverse"
|
||||||
{containers, type_language, type_language_value}
|
{containers, type_language, type_language_value}
|
||||||
|
|
||||||
# 2.6) Otherwise, if value is a list object, then set type/language and type/language value to the most specific values that work for all items in the list as follows:
|
# 2.6) Otherwise, if value is a list object, then set type/language and type/language value to the most specific values that work for all items in the list as follows:
|
||||||
list?(value) ->
|
list?(value) ->
|
||||||
# 2.6.1) If @index is a not key in value, then append @list to containers.
|
# 2.6.1) If @index is a not key in value, then append @list to containers.
|
||||||
containers =
|
containers = if not index?(value), do: containers ++ ["@list"], else: containers
|
||||||
if not index?(value),
|
|
||||||
do: containers ++ ["@list"], else: containers
|
|
||||||
# 2.6.2) Initialize list to the array associated with the key @list in value.
|
# 2.6.2) Initialize list to the array associated with the key @list in value.
|
||||||
list = value["@list"]
|
list = value["@list"]
|
||||||
|
|
||||||
# 2.6.3) Initialize common type and common language to null. If list is empty, set common language to default language.
|
# 2.6.3) Initialize common type and common language to null. If list is empty, set common language to default language.
|
||||||
# TODO: Spec fixme: Setting common language to default language is effectively useless, since the only place it is used is the follow loop in 2.6.4, which is immediately left when the list is empty
|
# TODO: Spec fixme: Setting common language to default language is effectively useless, since the only place it is used is the follow loop in 2.6.4, which is immediately left when the list is empty
|
||||||
{common_type, common_language} = {nil, nil}
|
{common_type, common_language} = {nil, nil}
|
||||||
|
|
||||||
{type_language, type_language_value} =
|
{type_language, type_language_value} =
|
||||||
if Enum.empty?(list) do
|
if Enum.empty?(list) do
|
||||||
{type_language, type_language_value}
|
{type_language, type_language_value}
|
||||||
else
|
else
|
||||||
# 2.6.4) For each item in list:
|
# 2.6.4) For each item in list:
|
||||||
{common_type, common_language} = Enum.reduce_while list, {common_type, common_language},
|
{common_type, common_language} =
|
||||||
fn (item, {common_type, common_language}) ->
|
Enum.reduce_while(list, {common_type, common_language}, fn item,
|
||||||
|
{common_type,
|
||||||
|
common_language} ->
|
||||||
# 2.6.4.1) Initialize item language to @none and item type to @none.
|
# 2.6.4.1) Initialize item language to @none and item type to @none.
|
||||||
{item_type, item_language} = {"@none", "@none"}
|
{item_type, item_language} = {"@none", "@none"}
|
||||||
# 2.6.4.2) If item contains the key @value:
|
# 2.6.4.2) If item contains the key @value:
|
||||||
|
@ -322,50 +410,62 @@ defmodule JSON.LD.Compaction do
|
||||||
# 2.6.4.2.1) If item contains the key @language, then set item language to its associated value.
|
# 2.6.4.2.1) If item contains the key @language, then set item language to its associated value.
|
||||||
Map.has_key?(item, "@language") ->
|
Map.has_key?(item, "@language") ->
|
||||||
{item_type, item["@language"]}
|
{item_type, item["@language"]}
|
||||||
|
|
||||||
# 2.6.4.2.2) Otherwise, if item contains the key @type, set item type to its associated value.
|
# 2.6.4.2.2) Otherwise, if item contains the key @type, set item type to its associated value.
|
||||||
Map.has_key?(item, "@type") ->
|
Map.has_key?(item, "@type") ->
|
||||||
{item["@type"], item_language}
|
{item["@type"], item_language}
|
||||||
|
|
||||||
# 2.6.4.2.3) Otherwise, set item language to @null.
|
# 2.6.4.2.3) Otherwise, set item language to @null.
|
||||||
true ->
|
true ->
|
||||||
{item_type, "@null"}
|
{item_type, "@null"}
|
||||||
end
|
end
|
||||||
|
|
||||||
# 2.6.4.3) Otherwise, set item type to @id.
|
# 2.6.4.3) Otherwise, set item type to @id.
|
||||||
else
|
else
|
||||||
{"@id", item_language}
|
{"@id", item_language}
|
||||||
end
|
end
|
||||||
|
|
||||||
common_language =
|
common_language =
|
||||||
cond do
|
cond do
|
||||||
# 2.6.4.4) If common language is null, set it to item language.
|
# 2.6.4.4) If common language is null, set it to item language.
|
||||||
is_nil(common_language) ->
|
is_nil(common_language) ->
|
||||||
item_language
|
item_language
|
||||||
|
|
||||||
# 2.6.4.5) Otherwise, if item language does not equal common language and item contains the key @value, then set common language to @none because list items have conflicting languages.
|
# 2.6.4.5) Otherwise, if item language does not equal common language and item contains the key @value, then set common language to @none because list items have conflicting languages.
|
||||||
item_language != common_language and Map.has_key?(item, "@value") ->
|
item_language != common_language and Map.has_key?(item, "@value") ->
|
||||||
"@none"
|
"@none"
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
common_language
|
common_language
|
||||||
end
|
end
|
||||||
|
|
||||||
common_type =
|
common_type =
|
||||||
cond do
|
cond do
|
||||||
# 2.6.4.6) If common type is null, set it to item type.
|
# 2.6.4.6) If common type is null, set it to item type.
|
||||||
is_nil(common_type) ->
|
is_nil(common_type) ->
|
||||||
item_type
|
item_type
|
||||||
|
|
||||||
# 2.6.4.7) Otherwise, if item type does not equal common type, then set common type to @none because list items have conflicting types.
|
# 2.6.4.7) Otherwise, if item type does not equal common type, then set common type to @none because list items have conflicting types.
|
||||||
item_type != common_type ->
|
item_type != common_type ->
|
||||||
"@none"
|
"@none"
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
common_type
|
common_type
|
||||||
end
|
end
|
||||||
|
|
||||||
# 2.6.4.8) If common language is @none and common type is @none, then stop processing items in the list because it has been detected that there is no common language or type amongst the items.
|
# 2.6.4.8) If common language is @none and common type is @none, then stop processing items in the list because it has been detected that there is no common language or type amongst the items.
|
||||||
if common_language == "@none" and common_type == "@none" do
|
if common_language == "@none" and common_type == "@none" do
|
||||||
{:halt, {common_type, common_language}}
|
{:halt, {common_type, common_language}}
|
||||||
else
|
else
|
||||||
{:cont, {common_type, common_language}}
|
{:cont, {common_type, common_language}}
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
|
|
||||||
# 2.6.5) If common language is null, set it to @none.
|
# 2.6.5) If common language is null, set it to @none.
|
||||||
common_language = if is_nil(common_language), do: "@none", else: common_language
|
common_language = if is_nil(common_language), do: "@none", else: common_language
|
||||||
# 2.6.6) If common type is null, set it to @none.
|
# 2.6.6) If common type is null, set it to @none.
|
||||||
common_type = if is_nil(common_type), do: "@none", else: common_type
|
common_type = if is_nil(common_type), do: "@none", else: common_type
|
||||||
|
|
||||||
# 2.6.7) If common type is not @none then set type/language to @type and type/language value to common type.
|
# 2.6.7) If common type is not @none then set type/language to @type and type/language value to common type.
|
||||||
if common_type != "@none" do
|
if common_type != "@none" do
|
||||||
type_language = "@type"
|
type_language = "@type"
|
||||||
|
@ -377,7 +477,9 @@ defmodule JSON.LD.Compaction do
|
||||||
{type_language, type_language_value}
|
{type_language, type_language_value}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
{containers, type_language, type_language_value}
|
{containers, type_language, type_language_value}
|
||||||
|
|
||||||
# 2.7) Otherwise
|
# 2.7) Otherwise
|
||||||
true ->
|
true ->
|
||||||
# 2.7.1) If value is a value object:
|
# 2.7.1) If value is a value object:
|
||||||
|
@ -398,20 +500,26 @@ defmodule JSON.LD.Compaction do
|
||||||
{containers, type_language, type_language_value}
|
{containers, type_language, type_language_value}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# 2.7.2) Otherwise, set type/language to @type and set type/language value to @id.
|
# 2.7.2) Otherwise, set type/language to @type and set type/language value to @id.
|
||||||
else
|
else
|
||||||
type_language = "@type"
|
type_language = "@type"
|
||||||
type_language_value = "@id"
|
type_language_value = "@id"
|
||||||
{containers, type_language, type_language_value}
|
{containers, type_language, type_language_value}
|
||||||
end
|
end
|
||||||
|
|
||||||
# 2.7.3) Append @set to containers.
|
# 2.7.3) Append @set to containers.
|
||||||
containers = containers ++ ["@set"]
|
containers = containers ++ ["@set"]
|
||||||
{containers, type_language, type_language_value}
|
{containers, type_language, type_language_value}
|
||||||
end
|
end
|
||||||
|
|
||||||
# 2.8) Append @none to containers. This represents the non-existence of a container mapping, and it will be the last container mapping value to be checked as it is the most generic.
|
# 2.8) Append @none to containers. This represents the non-existence of a container mapping, and it will be the last container mapping value to be checked as it is the most generic.
|
||||||
containers = containers ++ ["@none"]
|
containers = containers ++ ["@none"]
|
||||||
|
|
||||||
# 2.9) If type/language value is null, set it to @null. This is the key under which null values are stored in the inverse context entry.
|
# 2.9) If type/language value is null, set it to @null. This is the key under which null values are stored in the inverse context entry.
|
||||||
type_language_value = if is_nil(type_language_value), do: "@null", else: type_language_value
|
type_language_value =
|
||||||
|
if is_nil(type_language_value), do: "@null", else: type_language_value
|
||||||
|
|
||||||
# 2.10) Initialize preferred values to an empty array. This array will indicate, in order, the preferred values for a term's type mapping or language mapping.
|
# 2.10) Initialize preferred values to an empty array. This array will indicate, in order, the preferred values for a term's type mapping or language mapping.
|
||||||
preferred_values = []
|
preferred_values = []
|
||||||
# 2.11) If type/language value is @reverse, append @reverse to preferred values.
|
# 2.11) If type/language value is @reverse, append @reverse to preferred values.
|
||||||
|
@ -419,38 +527,49 @@ defmodule JSON.LD.Compaction do
|
||||||
if type_language_value == "@reverse",
|
if type_language_value == "@reverse",
|
||||||
do: preferred_values ++ ["@reverse"],
|
do: preferred_values ++ ["@reverse"],
|
||||||
else: preferred_values
|
else: preferred_values
|
||||||
|
|
||||||
# 2.12) If type/language value is @id or @reverse and value has an @id member:
|
# 2.12) If type/language value is @id or @reverse and value has an @id member:
|
||||||
preferred_values =
|
preferred_values =
|
||||||
if type_language_value in ~w[@id @reverse] and is_map(value) and Map.has_key?(value, "@id") do
|
if type_language_value in ~w[@id @reverse] and is_map(value) and
|
||||||
|
Map.has_key?(value, "@id") do
|
||||||
# 2.12.1) If the result of using the IRI compaction algorithm, passing active context, inverse context, the value associated with the @id key in value for iri, true for vocab, and true for document relative has a term definition in the active context with an IRI mapping that equals the value associated with the @id key in value, then append @vocab, @id, and @none, in that order, to preferred values.
|
# 2.12.1) If the result of using the IRI compaction algorithm, passing active context, inverse context, the value associated with the @id key in value for iri, true for vocab, and true for document relative has a term definition in the active context with an IRI mapping that equals the value associated with the @id key in value, then append @vocab, @id, and @none, in that order, to preferred values.
|
||||||
# TODO: Spec fixme? document_relative is not a specified parameter of compact_iri
|
# TODO: Spec fixme? document_relative is not a specified parameter of compact_iri
|
||||||
compact_id = compact_iri(value["@id"], active_context, inverse_context, nil, true)
|
compact_id = compact_iri(value["@id"], active_context, inverse_context, nil, true)
|
||||||
if (term_def = active_context.term_defs[compact_id]) && term_def.iri_mapping == value["@id"] do
|
|
||||||
|
if (term_def = active_context.term_defs[compact_id]) &&
|
||||||
|
term_def.iri_mapping == value["@id"] do
|
||||||
preferred_values ++ ~w[@vocab @id @none]
|
preferred_values ++ ~w[@vocab @id @none]
|
||||||
|
|
||||||
# 2.12.2) Otherwise, append @id, @vocab, and @none, in that order, to preferred values.
|
# 2.12.2) Otherwise, append @id, @vocab, and @none, in that order, to preferred values.
|
||||||
else
|
else
|
||||||
preferred_values ++ ~w[@id @vocab @none]
|
preferred_values ++ ~w[@id @vocab @none]
|
||||||
end
|
end
|
||||||
|
|
||||||
# 2.13) Otherwise, append type/language value and @none, in that order, to preferred values.
|
# 2.13) Otherwise, append type/language value and @none, in that order, to preferred values.
|
||||||
else
|
else
|
||||||
preferred_values ++ [type_language_value, "@none"]
|
preferred_values ++ [type_language_value, "@none"]
|
||||||
end
|
end
|
||||||
|
|
||||||
# 2.14) Initialize term to the result of the Term Selection algorithm, passing inverse context, iri, containers, type/language, and preferred values.
|
# 2.14) Initialize term to the result of the Term Selection algorithm, passing inverse context, iri, containers, type/language, and preferred values.
|
||||||
select_term(inverse_context, iri, containers, type_language, preferred_values)
|
select_term(inverse_context, iri, containers, type_language, preferred_values)
|
||||||
end
|
end
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
# 2.15) If term is not null, return term.
|
# 2.15) If term is not null, return term.
|
||||||
not is_nil(term) ->
|
not is_nil(term) ->
|
||||||
term
|
term
|
||||||
|
|
||||||
# 3) At this point, there is no simple term that iri can be compacted to. If vocab is true and active context has a vocabulary mapping:
|
# 3) At this point, there is no simple term that iri can be compacted to. If vocab is true and active context has a vocabulary mapping:
|
||||||
# 3.1) If iri begins with the vocabulary mapping's value but is longer, then initialize suffix to the substring of iri that does not match. If suffix does not have a term definition in active context, then return suffix.
|
# 3.1) If iri begins with the vocabulary mapping's value but is longer, then initialize suffix to the substring of iri that does not match. If suffix does not have a term definition in active context, then return suffix.
|
||||||
vocab && active_context.vocab && String.starts_with?(iri, active_context.vocab) ->
|
vocab && active_context.vocab && String.starts_with?(iri, active_context.vocab) ->
|
||||||
suffix = String.replace_prefix(iri, active_context.vocab, "")
|
suffix = String.replace_prefix(iri, active_context.vocab, "")
|
||||||
|
|
||||||
if suffix != "" && is_nil(active_context.term_defs[suffix]) do
|
if suffix != "" && is_nil(active_context.term_defs[suffix]) do
|
||||||
String.replace_prefix(iri, active_context.vocab, "")
|
String.replace_prefix(iri, active_context.vocab, "")
|
||||||
else
|
else
|
||||||
create_compact_iri(iri, active_context, value, vocab)
|
create_compact_iri(iri, active_context, value, vocab)
|
||||||
end
|
end
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
create_compact_iri(iri, active_context, value, vocab)
|
create_compact_iri(iri, active_context, value, vocab)
|
||||||
end
|
end
|
||||||
|
@ -458,20 +577,25 @@ defmodule JSON.LD.Compaction do
|
||||||
|
|
||||||
defp create_compact_iri(iri, active_context, value, vocab) do
|
defp create_compact_iri(iri, active_context, value, vocab) do
|
||||||
# 4) The iri could not be compacted using the active context's vocabulary mapping. Try to create a compact IRI, starting by initializing compact IRI to null. This variable will be used to tore the created compact IRI, if any.
|
# 4) The iri could not be compacted using the active context's vocabulary mapping. Try to create a compact IRI, starting by initializing compact IRI to null. This variable will be used to tore the created compact IRI, if any.
|
||||||
compact_iri =
|
|
||||||
# 5) For each key term and value term definition in the active context:
|
# 5) For each key term and value term definition in the active context:
|
||||||
Enum.reduce(active_context.term_defs, nil, fn ({term, term_def}, compact_iri) ->
|
compact_iri =
|
||||||
|
Enum.reduce(active_context.term_defs, nil, fn {term, term_def}, compact_iri ->
|
||||||
cond do
|
cond do
|
||||||
# 5.1) If the term contains a colon (:), then continue to the next term because terms with colons can't be used as prefixes.
|
# 5.1) If the term contains a colon (:), then continue to the next term because terms with colons can't be used as prefixes.
|
||||||
String.contains?(term, ":") ->
|
String.contains?(term, ":") ->
|
||||||
compact_iri
|
compact_iri
|
||||||
|
|
||||||
# 5.2) If the term definition is null, its IRI mapping equals iri, or its IRI mapping is not a substring at the beginning of iri, the term cannot be used as a prefix because it is not a partial match with iri. Continue with the next term.
|
# 5.2) If the term definition is null, its IRI mapping equals iri, or its IRI mapping is not a substring at the beginning of iri, the term cannot be used as a prefix because it is not a partial match with iri. Continue with the next term.
|
||||||
is_nil(term_def) || term_def.iri_mapping == iri ||
|
is_nil(term_def) || term_def.iri_mapping == iri ||
|
||||||
not String.starts_with?(iri, term_def.iri_mapping) ->
|
not String.starts_with?(iri, term_def.iri_mapping) ->
|
||||||
compact_iri
|
compact_iri
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
# 5.3) Initialize candidate by concatenating term, a colon (:), and the substring of iri that follows after the value of the term definition's IRI mapping.
|
# 5.3) Initialize candidate by concatenating term, a colon (:), and the substring of iri that follows after the value of the term definition's IRI mapping.
|
||||||
candidate = term <> ":" <> (String.split_at(iri, String.length(term_def.iri_mapping)) |> elem(1))
|
candidate =
|
||||||
|
term <>
|
||||||
|
":" <> (String.split_at(iri, String.length(term_def.iri_mapping)) |> elem(1))
|
||||||
|
|
||||||
# 5.4) If either compact IRI is null or candidate is shorter or the same length but lexicographically less than compact IRI and candidate does not have a term definition in active context or if the term definition has an IRI mapping that equals iri and value is null, set compact IRI to candidate.
|
# 5.4) If either compact IRI is null or candidate is shorter or the same length but lexicographically less than compact IRI and candidate does not have a term definition in active context or if the term definition has an IRI mapping that equals iri and value is null, set compact IRI to candidate.
|
||||||
# TODO: Spec fixme: The specified expression is pretty ambiguous without brackets ...
|
# TODO: Spec fixme: The specified expression is pretty ambiguous without brackets ...
|
||||||
# TODO: Spec fixme: "if the term definition has an IRI mapping that equals iri" is already catched in 5.2, so will never happen here ...
|
# TODO: Spec fixme: "if the term definition has an IRI mapping that equals iri" is already catched in 5.2, so will never happen here ...
|
||||||
|
@ -484,13 +608,16 @@ defmodule JSON.LD.Compaction do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
# 6) If compact IRI is not null, return compact IRI.
|
# 6) If compact IRI is not null, return compact IRI.
|
||||||
not is_nil(compact_iri) ->
|
not is_nil(compact_iri) ->
|
||||||
compact_iri
|
compact_iri
|
||||||
|
|
||||||
# 7) If vocab is false then transform iri to a relative IRI using the document's base IRI.
|
# 7) If vocab is false then transform iri to a relative IRI using the document's base IRI.
|
||||||
not vocab ->
|
not vocab ->
|
||||||
remove_base(iri, Context.base(active_context))
|
remove_base(iri, Context.base(active_context))
|
||||||
|
|
||||||
# 8) Finally, return iri as is.
|
# 8) Finally, return iri as is.
|
||||||
true ->
|
true ->
|
||||||
iri
|
iri
|
||||||
|
@ -506,11 +633,14 @@ defmodule JSON.LD.Compaction do
|
||||||
|
|
||||||
defp remove_base(iri, base) do
|
defp remove_base(iri, base) do
|
||||||
base_len = String.length(base)
|
base_len = String.length(base)
|
||||||
|
|
||||||
if String.starts_with?(iri, base) and String.at(iri, base_len) in ~w(? #) do
|
if String.starts_with?(iri, base) and String.at(iri, base_len) in ~w(? #) do
|
||||||
String.split_at(iri, base_len) |> elem(1)
|
String.split_at(iri, base_len) |> elem(1)
|
||||||
else
|
else
|
||||||
case URI.parse(base) do
|
case URI.parse(base) do
|
||||||
%URI{path: nil} -> iri
|
%URI{path: nil} ->
|
||||||
|
iri
|
||||||
|
|
||||||
base ->
|
base ->
|
||||||
do_remove_base(iri, %URI{base | path: parent_path(base.path)}, 0)
|
do_remove_base(iri, %URI{base | path: parent_path(base.path)}, 0)
|
||||||
end
|
end
|
||||||
|
@ -519,6 +649,7 @@ defmodule JSON.LD.Compaction do
|
||||||
|
|
||||||
defp do_remove_base(iri, base, index) do
|
defp do_remove_base(iri, base, index) do
|
||||||
base_str = URI.to_string(base)
|
base_str = URI.to_string(base)
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
String.starts_with?(iri, base_str) ->
|
String.starts_with?(iri, base_str) ->
|
||||||
case String.duplicate("../", index) <>
|
case String.duplicate("../", index) <>
|
||||||
|
@ -526,13 +657,17 @@ defmodule JSON.LD.Compaction do
|
||||||
"" -> "./"
|
"" -> "./"
|
||||||
rel -> rel
|
rel -> rel
|
||||||
end
|
end
|
||||||
base.path == "/" -> iri
|
|
||||||
|
base.path == "/" ->
|
||||||
|
iri
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
do_remove_base(iri, %URI{base | path: parent_path(base.path)}, index + 1)
|
do_remove_base(iri, %URI{base | path: parent_path(base.path)}, index + 1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp parent_path("/"), do: "/"
|
defp parent_path("/"), do: "/"
|
||||||
|
|
||||||
defp parent_path(path) do
|
defp parent_path(path) do
|
||||||
case Path.dirname(String.trim_trailing(path, "/")) do
|
case Path.dirname(String.trim_trailing(path, "/")) do
|
||||||
"/" -> "/"
|
"/" -> "/"
|
||||||
|
@ -549,16 +684,21 @@ defmodule JSON.LD.Compaction do
|
||||||
term_def = active_context.term_defs[active_property]
|
term_def = active_context.term_defs[active_property]
|
||||||
# 1) Initialize number members to the number of members value contains.
|
# 1) Initialize number members to the number of members value contains.
|
||||||
number_members = Enum.count(value)
|
number_members = Enum.count(value)
|
||||||
|
|
||||||
# 2) If value has an @index member and the container mapping associated to active property is set to @index, decrease number members by 1.
|
# 2) If value has an @index member and the container mapping associated to active property is set to @index, decrease number members by 1.
|
||||||
number_members =
|
number_members =
|
||||||
if term_def != nil and Map.has_key?(value, "@index") and
|
if term_def != nil and Map.has_key?(value, "@index") and
|
||||||
term_def.container_mapping == "@index",
|
term_def.container_mapping == "@index",
|
||||||
do: number_members - 1, else: number_members
|
do: number_members - 1,
|
||||||
|
else: number_members
|
||||||
|
|
||||||
# 3) If number members is greater than 2, return value as it cannot be compacted.
|
# 3) If number members is greater than 2, return value as it cannot be compacted.
|
||||||
unless number_members > 2 do
|
unless number_members > 2 do
|
||||||
{type_mapping, language_mapping} = if term_def,
|
{type_mapping, language_mapping} =
|
||||||
|
if term_def,
|
||||||
do: {term_def.type_mapping, term_def.language_mapping},
|
do: {term_def.type_mapping, term_def.language_mapping},
|
||||||
else: {nil, nil}
|
else: {nil, nil}
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
# 4) If value has an @id member
|
# 4) If value has an @id member
|
||||||
id = Map.get(value, "@id") ->
|
id = Map.get(value, "@id") ->
|
||||||
|
@ -566,28 +706,33 @@ defmodule JSON.LD.Compaction do
|
||||||
# 4.1) If number members is 1 and the type mapping of active property is set to @id, return the result of using the IRI compaction algorithm, passing active context, inverse context, and the value of the @id member for iri.
|
# 4.1) If number members is 1 and the type mapping of active property is set to @id, return the result of using the IRI compaction algorithm, passing active context, inverse context, and the value of the @id member for iri.
|
||||||
number_members == 1 and type_mapping == "@id" ->
|
number_members == 1 and type_mapping == "@id" ->
|
||||||
compact_iri(id, active_context, inverse_context)
|
compact_iri(id, active_context, inverse_context)
|
||||||
|
|
||||||
# 4.2) Otherwise, if number members is 1 and the type mapping of active property is set to @vocab, return the result of using the IRI compaction algorithm, passing active context, inverse context, the value of the @id member for iri, and true for vocab.
|
# 4.2) Otherwise, if number members is 1 and the type mapping of active property is set to @vocab, return the result of using the IRI compaction algorithm, passing active context, inverse context, the value of the @id member for iri, and true for vocab.
|
||||||
number_members == 1 and type_mapping == "@vocab" ->
|
number_members == 1 and type_mapping == "@vocab" ->
|
||||||
compact_iri(id, active_context, inverse_context, nil, true)
|
compact_iri(id, active_context, inverse_context, nil, true)
|
||||||
|
|
||||||
# 4.3) Otherwise, return value as is.
|
# 4.3) Otherwise, return value as is.
|
||||||
true ->
|
true ->
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
|
|
||||||
# 5) Otherwise, if value has an @type member whose value matches the type mapping of active property, return the value associated with the @value member of value.
|
# 5) Otherwise, if value has an @type member whose value matches the type mapping of active property, return the value associated with the @value member of value.
|
||||||
(type = Map.get(value, "@type")) && type == type_mapping ->
|
(type = Map.get(value, "@type")) && type == type_mapping ->
|
||||||
value["@value"]
|
value["@value"]
|
||||||
|
|
||||||
# 6) Otherwise, if value has an @language member whose value matches the language mapping of active property, return the value associated with the @value member of value.
|
# 6) Otherwise, if value has an @language member whose value matches the language mapping of active property, return the value associated with the @value member of value.
|
||||||
(language = Map.get(value, "@language")) &&
|
|
||||||
# TODO: Spec fixme: doesn't specify to check default language as well
|
# TODO: Spec fixme: doesn't specify to check default language as well
|
||||||
|
(language = Map.get(value, "@language")) &&
|
||||||
language in [language_mapping, active_context.default_language] ->
|
language in [language_mapping, active_context.default_language] ->
|
||||||
value["@value"]
|
value["@value"]
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
# 7) Otherwise, if number members equals 1 and either the value of the @value member is not a string, or the active context has no default language, or the language mapping of active property is set to null,, return the value associated with the @value member.
|
# 7) Otherwise, if number members equals 1 and either the value of the @value member is not a string, or the active context has no default language, or the language mapping of active property is set to null,, return the value associated with the @value member.
|
||||||
value_value = value["@value"]
|
value_value = value["@value"]
|
||||||
|
# TODO: Spec fixme: doesn't specify to check default language as well
|
||||||
if number_members == 1 and
|
if number_members == 1 and
|
||||||
(not is_binary(value_value) or
|
(not is_binary(value_value) or
|
||||||
!active_context.default_language or
|
!active_context.default_language or
|
||||||
# TODO: Spec fixme: doesn't specify to check default language as well
|
|
||||||
Context.language(active_context, active_property) == nil) do
|
Context.language(active_context, active_property) == nil) do
|
||||||
value_value
|
value_value
|
||||||
# 8) Otherwise, return value as is.
|
# 8) Otherwise, return value as is.
|
||||||
|
@ -607,12 +752,12 @@ defmodule JSON.LD.Compaction do
|
||||||
"""
|
"""
|
||||||
def select_term(inverse_context, iri, containers, type_language, preferred_values) do
|
def select_term(inverse_context, iri, containers, type_language, preferred_values) do
|
||||||
container_map = inverse_context[iri]
|
container_map = inverse_context[iri]
|
||||||
Enum.find_value containers, fn container ->
|
|
||||||
|
Enum.find_value(containers, fn container ->
|
||||||
if type_language_map = container_map[container] do
|
if type_language_map = container_map[container] do
|
||||||
value_map = type_language_map[type_language]
|
value_map = type_language_map[type_language]
|
||||||
Enum.find_value preferred_values, fn item -> value_map[item] end
|
Enum.find_value(preferred_values, fn item -> value_map[item] end)
|
||||||
|
end
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
|
@ -11,26 +11,24 @@ defmodule JSON.LD.Context do
|
||||||
alias JSON.LD.Context.TermDefinition
|
alias JSON.LD.Context.TermDefinition
|
||||||
alias RDF.IRI
|
alias RDF.IRI
|
||||||
|
|
||||||
|
|
||||||
def base(%JSON.LD.Context{base_iri: false, api_base_iri: api_base_iri}),
|
def base(%JSON.LD.Context{base_iri: false, api_base_iri: api_base_iri}),
|
||||||
do: api_base_iri
|
do: api_base_iri
|
||||||
|
|
||||||
def base(%JSON.LD.Context{base_iri: base_iri}),
|
def base(%JSON.LD.Context{base_iri: base_iri}),
|
||||||
do: base_iri
|
do: base_iri
|
||||||
|
|
||||||
|
|
||||||
def new(options \\ %JSON.LD.Options{}),
|
def new(options \\ %JSON.LD.Options{}),
|
||||||
do: %JSON.LD.Context{api_base_iri: JSON.LD.Options.new(options).base}
|
do: %JSON.LD.Context{api_base_iri: JSON.LD.Options.new(options).base}
|
||||||
|
|
||||||
def create(%{"@context" => json_ld_context}, options),
|
def create(%{"@context" => json_ld_context}, options),
|
||||||
do: new(options) |> update(json_ld_context, [], options)
|
do: new(options) |> update(json_ld_context, [], options)
|
||||||
|
|
||||||
|
|
||||||
def update(active, local, remote \\ [], options \\ %JSON.LD.Options{})
|
def update(active, local, remote \\ [], options \\ %JSON.LD.Options{})
|
||||||
|
|
||||||
def update(%JSON.LD.Context{} = active, local, remote, options) when is_list(local) do
|
def update(%JSON.LD.Context{} = active, local, remote, options) when is_list(local) do
|
||||||
Enum.reduce local, active, fn (local, result) ->
|
Enum.reduce(local, active, fn local, result ->
|
||||||
do_update(result, local, remote, options)
|
do_update(result, local, remote, options)
|
||||||
end
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
# 2) If local context is not an array, set it to an array containing only local context.
|
# 2) If local context is not an array, set it to an array containing only local context.
|
||||||
|
@ -38,7 +36,6 @@ defmodule JSON.LD.Context do
|
||||||
update(active, [local], remote, options)
|
update(active, [local], remote, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# 3.1) If context is null, set result to a newly-initialized active context and continue with the next context. The base IRI of the active context is set to the IRI of the currently being processed document (which might be different from the currently being processed context), if available; otherwise to null. If set, the base option of a JSON-LD API Implementation overrides the base IRI.
|
# 3.1) If context is null, set result to a newly-initialized active context and continue with the next context. The base IRI of the active context is set to the IRI of the currently being processed document (which might be different from the currently being processed context), if available; otherwise to null. If set, the base option of a JSON-LD API Implementation overrides the base IRI.
|
||||||
defp do_update(%JSON.LD.Context{}, nil, _remote, options) do
|
defp do_update(%JSON.LD.Context{}, nil, _remote, options) do
|
||||||
new(options)
|
new(options)
|
||||||
|
@ -54,6 +51,7 @@ defmodule JSON.LD.Context do
|
||||||
raise JSON.LD.RecursiveContextInclusionError,
|
raise JSON.LD.RecursiveContextInclusionError,
|
||||||
message: "Recursive context inclusion: #{local}"
|
message: "Recursive context inclusion: #{local}"
|
||||||
end
|
end
|
||||||
|
|
||||||
remote = remote ++ [local]
|
remote = remote ++ [local]
|
||||||
|
|
||||||
# 3.2.3)
|
# 3.2.3)
|
||||||
|
@ -61,25 +59,38 @@ defmodule JSON.LD.Context do
|
||||||
|
|
||||||
document =
|
document =
|
||||||
case apply(document_loader, :load, [local, options]) do
|
case apply(document_loader, :load, [local, options]) do
|
||||||
{:ok, result} -> result.document
|
{:ok, result} ->
|
||||||
{:error, reason} -> raise JSON.LD.LoadingRemoteContextFailedError,
|
result.document
|
||||||
message: "Could not load remote context (#{local}): #{inspect reason}"
|
|
||||||
|
{:error, reason} ->
|
||||||
|
raise JSON.LD.LoadingRemoteContextFailedError,
|
||||||
|
message: "Could not load remote context (#{local}): #{inspect(reason)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
document = cond do
|
document =
|
||||||
is_map(document) -> document
|
cond do
|
||||||
is_binary(document) -> case Jason.decode(document) do
|
is_map(document) ->
|
||||||
{:ok, result} -> result
|
document
|
||||||
{:error, reason} -> raise JSON.LD.InvalidRemoteContextError,
|
|
||||||
message: "Context is not a valid JSON document: #{inspect reason}"
|
|
||||||
end
|
|
||||||
true -> raise JSON.LD.InvalidRemoteContextError,
|
|
||||||
message: "Context is not a valid JSON object: #{inspect document}"
|
|
||||||
end
|
|
||||||
|
|
||||||
local = document["@context"] ||
|
is_binary(document) ->
|
||||||
|
case Jason.decode(document) do
|
||||||
|
{:ok, result} ->
|
||||||
|
result
|
||||||
|
|
||||||
|
{:error, reason} ->
|
||||||
raise JSON.LD.InvalidRemoteContextError,
|
raise JSON.LD.InvalidRemoteContextError,
|
||||||
message: "Invalid remote context: No @context key in #{inspect document}"
|
message: "Context is not a valid JSON document: #{inspect(reason)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
true ->
|
||||||
|
raise JSON.LD.InvalidRemoteContextError,
|
||||||
|
message: "Context is not a valid JSON object: #{inspect(document)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
local =
|
||||||
|
document["@context"] ||
|
||||||
|
raise JSON.LD.InvalidRemoteContextError,
|
||||||
|
message: "Invalid remote context: No @context key in #{inspect(document)}"
|
||||||
|
|
||||||
# 3.2.4) - 3.2.5)
|
# 3.2.4) - 3.2.5)
|
||||||
do_update(active, local, remote, options)
|
do_update(active, local, remote, options)
|
||||||
|
@ -100,45 +111,56 @@ defmodule JSON.LD.Context do
|
||||||
|
|
||||||
# 3.3) If context is not a JSON object, an invalid local context error has been detected and processing is aborted.
|
# 3.3) If context is not a JSON object, an invalid local context error has been detected and processing is aborted.
|
||||||
defp do_update(_, local, _, _),
|
defp do_update(_, local, _, _),
|
||||||
do: raise JSON.LD.InvalidLocalContextError,
|
do:
|
||||||
message: "#{inspect local} is not a valid @context value"
|
raise(JSON.LD.InvalidLocalContextError,
|
||||||
|
message: "#{inspect(local)} is not a valid @context value"
|
||||||
|
)
|
||||||
|
|
||||||
defp set_base(active, false, _),
|
defp set_base(active, false, _),
|
||||||
do: active
|
do: active
|
||||||
|
|
||||||
defp set_base(active, _, remote) when is_list(remote) and length(remote) > 0,
|
defp set_base(active, _, remote) when is_list(remote) and length(remote) > 0,
|
||||||
do: active
|
do: active
|
||||||
|
|
||||||
defp set_base(active, base, _) do
|
defp set_base(active, base, _) do
|
||||||
cond do
|
cond do
|
||||||
# TODO: this slightly differs from the spec, due to our false special value for base_iri; add more tests
|
# TODO: this slightly differs from the spec, due to our false special value for base_iri; add more tests
|
||||||
is_nil(base) or IRI.absolute?(base) ->
|
is_nil(base) or IRI.absolute?(base) ->
|
||||||
%JSON.LD.Context{active | base_iri: base}
|
%JSON.LD.Context{active | base_iri: base}
|
||||||
|
|
||||||
active.base_iri ->
|
active.base_iri ->
|
||||||
%JSON.LD.Context{active | base_iri: absolute_iri(base, active.base_iri)}
|
%JSON.LD.Context{active | base_iri: absolute_iri(base, active.base_iri)}
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
raise JSON.LD.InvalidBaseIRIError,
|
raise JSON.LD.InvalidBaseIRIError,
|
||||||
message: "#{inspect base} is a relative IRI, but no active base IRI defined"
|
message: "#{inspect(base)} is a relative IRI, but no active base IRI defined"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp set_vocab(active, false), do: active
|
defp set_vocab(active, false), do: active
|
||||||
|
|
||||||
defp set_vocab(active, vocab) do
|
defp set_vocab(active, vocab) do
|
||||||
if is_nil(vocab) or IRI.absolute?(vocab) or blank_node_id?(vocab) do
|
if is_nil(vocab) or IRI.absolute?(vocab) or blank_node_id?(vocab) do
|
||||||
%JSON.LD.Context{active | vocab: vocab}
|
%JSON.LD.Context{active | vocab: vocab}
|
||||||
else
|
else
|
||||||
raise JSON.LD.InvalidVocabMappingError,
|
raise JSON.LD.InvalidVocabMappingError,
|
||||||
message: "#{inspect vocab} is not a valid vocabulary mapping"
|
message: "#{inspect(vocab)} is not a valid vocabulary mapping"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp set_language(active, false), do: active
|
defp set_language(active, false), do: active
|
||||||
|
|
||||||
defp set_language(active, nil),
|
defp set_language(active, nil),
|
||||||
do: %JSON.LD.Context{active | default_language: nil}
|
do: %JSON.LD.Context{active | default_language: nil}
|
||||||
|
|
||||||
defp set_language(active, language) when is_binary(language),
|
defp set_language(active, language) when is_binary(language),
|
||||||
do: %JSON.LD.Context{active | default_language: String.downcase(language)}
|
do: %JSON.LD.Context{active | default_language: String.downcase(language)}
|
||||||
|
|
||||||
defp set_language(_, language),
|
defp set_language(_, language),
|
||||||
do: raise JSON.LD.InvalidDefaultLanguageError,
|
do:
|
||||||
message: "#{inspect language} is not a valid language"
|
raise(JSON.LD.InvalidDefaultLanguageError,
|
||||||
|
message: "#{inspect(language)} is not a valid language"
|
||||||
|
)
|
||||||
|
|
||||||
def language(active, term) do
|
def language(active, term) do
|
||||||
case Map.get(active.term_defs, term, %TermDefinition{}).language_mapping do
|
case Map.get(active.term_defs, term, %TermDefinition{}).language_mapping do
|
||||||
|
@ -149,9 +171,10 @@ defmodule JSON.LD.Context do
|
||||||
|
|
||||||
defp create_term_definitions(active, local, defined \\ %{}) do
|
defp create_term_definitions(active, local, defined \\ %{}) do
|
||||||
{active, _} =
|
{active, _} =
|
||||||
Enum.reduce local, {active, defined}, fn ({term, value}, {active, defined}) ->
|
Enum.reduce(local, {active, defined}, fn {term, value}, {active, defined} ->
|
||||||
create_term_definition(active, local, term, value, defined)
|
create_term_definition(active, local, term, value, defined)
|
||||||
end
|
end)
|
||||||
|
|
||||||
active
|
active
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -168,15 +191,30 @@ defmodule JSON.LD.Context do
|
||||||
|
|
||||||
def create_term_definition(active, local, term, value, defined) do
|
def create_term_definition(active, local, term, value, defined) do
|
||||||
# 3)
|
# 3)
|
||||||
if term in JSON.LD.keywords,
|
if term in JSON.LD.keywords(),
|
||||||
do: raise JSON.LD.KeywordRedefinitionError,
|
do:
|
||||||
message: "#{inspect term} is a keyword and can not be defined in context"
|
raise(JSON.LD.KeywordRedefinitionError,
|
||||||
|
message: "#{inspect(term)} is a keyword and can not be defined in context"
|
||||||
|
)
|
||||||
|
|
||||||
# 1)
|
# 1)
|
||||||
case defined[term] do
|
case defined[term] do
|
||||||
true -> {active, defined}
|
true ->
|
||||||
false -> raise JSON.LD.CyclicIRIMappingError #, message: "#{inspect term} .."
|
{active, defined}
|
||||||
nil -> do_create_term_definition(active, local, term, value,
|
|
||||||
Map.put(defined, term, false)) # 2)
|
# , message: "#{inspect term} .."
|
||||||
|
false ->
|
||||||
|
raise JSON.LD.CyclicIRIMappingError
|
||||||
|
|
||||||
|
nil ->
|
||||||
|
do_create_term_definition(
|
||||||
|
active,
|
||||||
|
local,
|
||||||
|
term,
|
||||||
|
value,
|
||||||
|
# 2)
|
||||||
|
Map.put(defined, term, false)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -186,7 +224,8 @@ defmodule JSON.LD.Context do
|
||||||
# do: put_in(active, [:term_defs, term], nil),
|
# do: put_in(active, [:term_defs, term], nil),
|
||||||
# else: raise "NotImplemented"),
|
# else: raise "NotImplemented"),
|
||||||
%JSON.LD.Context{active | term_defs: Map.put(active.term_defs, term, nil)},
|
%JSON.LD.Context{active | term_defs: Map.put(active.term_defs, term, nil)},
|
||||||
Map.put(defined, term, true)}
|
Map.put(defined, term, true)
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp do_create_term_definition(active, local, term, %{"@id" => nil}, defined),
|
defp do_create_term_definition(active, local, term, %{"@id" => nil}, defined),
|
||||||
|
@ -196,46 +235,55 @@ defmodule JSON.LD.Context do
|
||||||
do: do_create_term_definition(active, local, term, %{"@id" => value}, defined)
|
do: do_create_term_definition(active, local, term, %{"@id" => value}, defined)
|
||||||
|
|
||||||
defp do_create_term_definition(active, local, term, %{} = value, defined) do
|
defp do_create_term_definition(active, local, term, %{} = value, defined) do
|
||||||
definition = %TermDefinition{} # 9)
|
# 9)
|
||||||
|
definition = %TermDefinition{}
|
||||||
|
|
||||||
{definition, active, defined} =
|
{definition, active, defined} =
|
||||||
do_create_type_definition(definition, active, local, value, defined)
|
do_create_type_definition(definition, active, local, value, defined)
|
||||||
|
|
||||||
{done, definition, active, defined} =
|
{done, definition, active, defined} =
|
||||||
do_create_reverse_definition(definition, active, local, value, defined)
|
do_create_reverse_definition(definition, active, local, value, defined)
|
||||||
|
|
||||||
{definition, active, defined} =
|
{definition, active, defined} =
|
||||||
unless done do
|
unless done do
|
||||||
{definition, active, defined} =
|
{definition, active, defined} =
|
||||||
do_create_id_definition(definition, active, local, term, value, defined)
|
do_create_id_definition(definition, active, local, term, value, defined)
|
||||||
|
|
||||||
definition = do_create_container_definition(definition, value)
|
definition = do_create_container_definition(definition, value)
|
||||||
definition = do_create_language_definition(definition, value)
|
definition = do_create_language_definition(definition, value)
|
||||||
{definition, active, defined}
|
{definition, active, defined}
|
||||||
else
|
else
|
||||||
{definition, active, defined}
|
{definition, active, defined}
|
||||||
end
|
end
|
||||||
|
|
||||||
# 18 / 11.6) Set the term definition of term in active context to definition and set the value associated with defined's key term to true.
|
# 18 / 11.6) Set the term definition of term in active context to definition and set the value associated with defined's key term to true.
|
||||||
{%JSON.LD.Context{active | term_defs: Map.put(active.term_defs, term, definition)},
|
{%JSON.LD.Context{active | term_defs: Map.put(active.term_defs, term, definition)},
|
||||||
Map.put(defined, term, true)}
|
Map.put(defined, term, true)}
|
||||||
end
|
end
|
||||||
|
|
||||||
defp do_create_term_definition(_, _, _, value, _),
|
defp do_create_term_definition(_, _, _, value, _),
|
||||||
do: raise JSON.LD.InvalidTermDefinitionError,
|
do:
|
||||||
message: "#{inspect value} is not a valid term definition"
|
raise(JSON.LD.InvalidTermDefinitionError,
|
||||||
|
message: "#{inspect(value)} is not a valid term definition"
|
||||||
|
)
|
||||||
|
|
||||||
# 10.1)
|
# 10.1)
|
||||||
# TODO: RDF.rb implementation says: "SPEC FIXME: @type may be nil"
|
# TODO: RDF.rb implementation says: "SPEC FIXME: @type may be nil"
|
||||||
defp do_create_type_definition(_, _, _, %{"@type" => type}, _) when not is_binary(type),
|
defp do_create_type_definition(_, _, _, %{"@type" => type}, _) when not is_binary(type),
|
||||||
do: raise JSON.LD.InvalidTypeMappingError,
|
do:
|
||||||
message: "#{inspect type} is not a valid type mapping"
|
raise(JSON.LD.InvalidTypeMappingError,
|
||||||
|
message: "#{inspect(type)} is not a valid type mapping"
|
||||||
|
)
|
||||||
|
|
||||||
# 10.2) and 10.3)
|
# 10.2) and 10.3)
|
||||||
defp do_create_type_definition(definition, active, local, %{"@type" => type}, defined) do
|
defp do_create_type_definition(definition, active, local, %{"@type" => type}, defined) do
|
||||||
{expanded_type, active, defined} =
|
{expanded_type, active, defined} = expand_iri(type, active, false, true, local, defined)
|
||||||
expand_iri(type, active, false, true, local, defined)
|
|
||||||
if IRI.absolute?(expanded_type) or expanded_type in ~w[@id @vocab] do
|
if IRI.absolute?(expanded_type) or expanded_type in ~w[@id @vocab] do
|
||||||
{%TermDefinition{definition | type_mapping: expanded_type}, active, defined}
|
{%TermDefinition{definition | type_mapping: expanded_type}, active, defined}
|
||||||
else
|
else
|
||||||
raise JSON.LD.InvalidTypeMappingError,
|
raise JSON.LD.InvalidTypeMappingError,
|
||||||
message: "#{inspect type} is not a valid type mapping"
|
message: "#{inspect(type)} is not a valid type mapping"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -243,35 +291,52 @@ defmodule JSON.LD.Context do
|
||||||
do: {definition, active, defined}
|
do: {definition, active, defined}
|
||||||
|
|
||||||
# 11) If value contains the key @reverse
|
# 11) If value contains the key @reverse
|
||||||
defp do_create_reverse_definition(definition, active, local,
|
defp do_create_reverse_definition(
|
||||||
%{"@reverse" => reverse} = value, defined) do
|
definition,
|
||||||
|
active,
|
||||||
|
local,
|
||||||
|
%{"@reverse" => reverse} = value,
|
||||||
|
defined
|
||||||
|
) do
|
||||||
cond do
|
cond do
|
||||||
Map.has_key?(value, "@id") -> # 11.1)
|
# 11.1)
|
||||||
|
Map.has_key?(value, "@id") ->
|
||||||
raise JSON.LD.InvalidReversePropertyError,
|
raise JSON.LD.InvalidReversePropertyError,
|
||||||
message: "#{inspect reverse} is not a valid reverse property"
|
message: "#{inspect(reverse)} is not a valid reverse property"
|
||||||
not is_binary(reverse) -> # 11.2)
|
|
||||||
|
# 11.2)
|
||||||
|
not is_binary(reverse) ->
|
||||||
raise JSON.LD.InvalidIRIMappingError,
|
raise JSON.LD.InvalidIRIMappingError,
|
||||||
message: "Expected String for @reverse value. got #{inspect reverse}"
|
message: "Expected String for @reverse value. got #{inspect(reverse)}"
|
||||||
true -> # 11.3)
|
|
||||||
|
# 11.3)
|
||||||
|
true ->
|
||||||
{expanded_reverse, active, defined} =
|
{expanded_reverse, active, defined} =
|
||||||
expand_iri(reverse, active, false, true, local, defined)
|
expand_iri(reverse, active, false, true, local, defined)
|
||||||
|
|
||||||
definition =
|
definition =
|
||||||
if IRI.absolute?(expanded_reverse) or blank_node_id?(expanded_reverse) do
|
if IRI.absolute?(expanded_reverse) or blank_node_id?(expanded_reverse) do
|
||||||
%TermDefinition{definition | iri_mapping: expanded_reverse}
|
%TermDefinition{definition | iri_mapping: expanded_reverse}
|
||||||
else
|
else
|
||||||
raise JSON.LD.InvalidIRIMappingError,
|
raise JSON.LD.InvalidIRIMappingError,
|
||||||
message: "Non-absolute @reverse IRI: #{inspect reverse}"
|
message: "Non-absolute @reverse IRI: #{inspect(reverse)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 11.4)
|
||||||
definition =
|
definition =
|
||||||
case Map.get(value, "@container", {false}) do # 11.4)
|
case Map.get(value, "@container", {false}) do
|
||||||
{false} ->
|
{false} ->
|
||||||
definition
|
definition
|
||||||
|
|
||||||
container when is_nil(container) or container in ~w[@set @index] ->
|
container when is_nil(container) or container in ~w[@set @index] ->
|
||||||
%TermDefinition{definition | container_mapping: container}
|
%TermDefinition{definition | container_mapping: container}
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
raise JSON.LD.InvalidReversePropertyError,
|
raise JSON.LD.InvalidReversePropertyError,
|
||||||
message: "#{inspect reverse} is not a valid reverse property; reverse properties only support set- and index-containers"
|
message:
|
||||||
|
"#{inspect(reverse)} is not a valid reverse property; reverse properties only support set- and index-containers"
|
||||||
end
|
end
|
||||||
|
|
||||||
# 11.5) & 11.6)
|
# 11.5) & 11.6)
|
||||||
{true, %TermDefinition{definition | reverse_property: true}, active, defined}
|
{true, %TermDefinition{definition | reverse_property: true}, active, defined}
|
||||||
end
|
end
|
||||||
|
@ -280,29 +345,32 @@ defmodule JSON.LD.Context do
|
||||||
defp do_create_reverse_definition(definition, active, _, _, defined),
|
defp do_create_reverse_definition(definition, active, _, _, defined),
|
||||||
do: {false, definition, active, defined}
|
do: {false, definition, active, defined}
|
||||||
|
|
||||||
|
|
||||||
# 13)
|
# 13)
|
||||||
defp do_create_id_definition(definition, active, local, term,
|
defp do_create_id_definition(definition, active, local, term, %{"@id" => id}, defined)
|
||||||
%{"@id" => id}, defined) when id != term do
|
when id != term do
|
||||||
|
# 13.1)
|
||||||
if is_binary(id) do
|
if is_binary(id) do
|
||||||
# 13.2)
|
# 13.2)
|
||||||
{expanded_id, active, defined} =
|
{expanded_id, active, defined} = expand_iri(id, active, false, true, local, defined)
|
||||||
expand_iri(id, active, false, true, local, defined)
|
|
||||||
cond do
|
cond do
|
||||||
expanded_id == "@context" ->
|
expanded_id == "@context" ->
|
||||||
raise JSON.LD.InvalidKeywordAliasError,
|
raise JSON.LD.InvalidKeywordAliasError,
|
||||||
message: "cannot alias @context"
|
message: "cannot alias @context"
|
||||||
|
|
||||||
JSON.LD.keyword?(expanded_id) or
|
JSON.LD.keyword?(expanded_id) or
|
||||||
IRI.absolute?(expanded_id) or
|
IRI.absolute?(expanded_id) or
|
||||||
blank_node_id?(expanded_id) ->
|
blank_node_id?(expanded_id) ->
|
||||||
{%TermDefinition{definition | iri_mapping: expanded_id}, active, defined}
|
{%TermDefinition{definition | iri_mapping: expanded_id}, active, defined}
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
raise JSON.LD.InvalidIRIMappingError,
|
raise JSON.LD.InvalidIRIMappingError,
|
||||||
message: "#{inspect id} is not a valid IRI mapping; resulting IRI mapping should be a keyword, absolute IRI or blank node"
|
message:
|
||||||
|
"#{inspect(id)} is not a valid IRI mapping; resulting IRI mapping should be a keyword, absolute IRI or blank node"
|
||||||
end
|
end
|
||||||
else # 13.1)
|
else
|
||||||
raise JSON.LD.InvalidIRIMappingError,
|
raise JSON.LD.InvalidIRIMappingError,
|
||||||
message: "expected value of @id to be a string, but got #{inspect id}"
|
message: "expected value of @id to be a string, but got #{inspect(id)}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -314,59 +382,72 @@ defmodule JSON.LD.Context do
|
||||||
case compact_iri_parts(term) do
|
case compact_iri_parts(term) do
|
||||||
[prefix, suffix] ->
|
[prefix, suffix] ->
|
||||||
prefix_mapping = local[prefix]
|
prefix_mapping = local[prefix]
|
||||||
|
|
||||||
{active, defined} =
|
{active, defined} =
|
||||||
if prefix_mapping do
|
if prefix_mapping do
|
||||||
do_create_term_definition(active, local, prefix, prefix_mapping, defined)
|
do_create_term_definition(active, local, prefix, prefix_mapping, defined)
|
||||||
else
|
else
|
||||||
{active, defined}
|
{active, defined}
|
||||||
end
|
end
|
||||||
|
|
||||||
if prefix_def = active.term_defs[prefix] do
|
if prefix_def = active.term_defs[prefix] do
|
||||||
{%TermDefinition{definition | iri_mapping: prefix_def.iri_mapping <> suffix}, active, defined}
|
{%TermDefinition{definition | iri_mapping: prefix_def.iri_mapping <> suffix}, active,
|
||||||
|
defined}
|
||||||
else
|
else
|
||||||
{%TermDefinition{definition | iri_mapping: term}, active, defined}
|
{%TermDefinition{definition | iri_mapping: term}, active, defined}
|
||||||
end
|
end
|
||||||
nil -> {%TermDefinition{definition | iri_mapping: term}, active, defined}
|
|
||||||
|
nil ->
|
||||||
|
{%TermDefinition{definition | iri_mapping: term}, active, defined}
|
||||||
end
|
end
|
||||||
|
|
||||||
# 15)
|
# 15)
|
||||||
else
|
else
|
||||||
if active.vocab do
|
if active.vocab do
|
||||||
{%TermDefinition{definition | iri_mapping: active.vocab <> term}, active, defined}
|
{%TermDefinition{definition | iri_mapping: active.vocab <> term}, active, defined}
|
||||||
else
|
else
|
||||||
raise JSON.LD.InvalidIRIMappingError,
|
raise JSON.LD.InvalidIRIMappingError,
|
||||||
message: "#{inspect term} is not a valid IRI mapping; relative term definition without vocab mapping"
|
message:
|
||||||
|
"#{inspect(term)} is not a valid IRI mapping; relative term definition without vocab mapping"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# 16.1)
|
# 16.1)
|
||||||
defp do_create_container_definition(_, %{"@container" => container})
|
defp do_create_container_definition(_, %{"@container" => container})
|
||||||
when container not in ~w[@list @set @index @language],
|
when container not in ~w[@list @set @index @language],
|
||||||
do: raise JSON.LD.InvalidContainerMappingError,
|
do:
|
||||||
message: "#{inspect container} is not a valid container mapping; @container must be either @list, @set, @index, or @language"
|
raise(JSON.LD.InvalidContainerMappingError,
|
||||||
|
message:
|
||||||
|
"#{inspect(container)} is not a valid container mapping; @container must be either @list, @set, @index, or @language"
|
||||||
|
)
|
||||||
|
|
||||||
# 16.2)
|
# 16.2)
|
||||||
defp do_create_container_definition(definition, %{"@container" => container}),
|
defp do_create_container_definition(definition, %{"@container" => container}),
|
||||||
do: %TermDefinition{definition | container_mapping: container}
|
do: %TermDefinition{definition | container_mapping: container}
|
||||||
|
|
||||||
defp do_create_container_definition(definition, _),
|
defp do_create_container_definition(definition, _),
|
||||||
do: definition
|
do: definition
|
||||||
|
|
||||||
|
|
||||||
# 17)
|
# 17)
|
||||||
defp do_create_language_definition(definition, %{"@language" => language} = value) do
|
defp do_create_language_definition(definition, %{"@language" => language} = value) do
|
||||||
unless Map.has_key?(value, "@type") do
|
unless Map.has_key?(value, "@type") do
|
||||||
case language do
|
case language do
|
||||||
language when is_binary(language) ->
|
language when is_binary(language) ->
|
||||||
%TermDefinition{definition | language_mapping: String.downcase(language)}
|
%TermDefinition{definition | language_mapping: String.downcase(language)}
|
||||||
|
|
||||||
language when is_nil(language) ->
|
language when is_nil(language) ->
|
||||||
%TermDefinition{definition | language_mapping: nil}
|
%TermDefinition{definition | language_mapping: nil}
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
raise JSON.LD.InvalidLanguageMappingError,
|
raise JSON.LD.InvalidLanguageMappingError,
|
||||||
message: "#{inspect language} is not a valid language mapping; @language must be a string or null"
|
message:
|
||||||
|
"#{inspect(language)} is not a valid language mapping; @language must be a string or null"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
defp do_create_language_definition(definition, _), do: definition
|
|
||||||
|
|
||||||
|
defp do_create_language_definition(definition, _), do: definition
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Inverse Context Creation algorithm
|
Inverse Context Creation algorithm
|
||||||
|
@ -376,10 +457,11 @@ defmodule JSON.LD.Context do
|
||||||
def inverse(%JSON.LD.Context{} = context) do
|
def inverse(%JSON.LD.Context{} = context) do
|
||||||
# 2) Initialize default language to @none. If the active context has a default language, set default language to it.
|
# 2) Initialize default language to @none. If the active context has a default language, set default language to it.
|
||||||
default_language = context.default_language || "@none"
|
default_language = context.default_language || "@none"
|
||||||
|
|
||||||
# 3) For each key term and value term definition in the active context, ordered by shortest term first (breaking ties by choosing the lexicographically least term)
|
# 3) For each key term and value term definition in the active context, ordered by shortest term first (breaking ties by choosing the lexicographically least term)
|
||||||
context.term_defs
|
context.term_defs
|
||||||
|> Enum.sort_by(fn {term, _} -> String.length(term) end)
|
|> Enum.sort_by(fn {term, _} -> String.length(term) end)
|
||||||
|> Enum.reduce(%{}, fn ({term, term_def}, result) ->
|
|> Enum.reduce(%{}, fn {term, term_def}, result ->
|
||||||
# 3.1) If the term definition is null, term cannot be selected during compaction, so continue to the next term.
|
# 3.1) If the term definition is null, term cannot be selected during compaction, so continue to the next term.
|
||||||
if term_def do
|
if term_def do
|
||||||
# 3.2) Initialize container to @none. If there is a container mapping in term definition, set container to its associated value.
|
# 3.2) Initialize container to @none. If there is a container mapping in term definition, set container to its associated value.
|
||||||
|
@ -395,15 +477,18 @@ defmodule JSON.LD.Context do
|
||||||
# 3.8) If the term definition indicates that the term represents a reverse property
|
# 3.8) If the term definition indicates that the term represents a reverse property
|
||||||
%TermDefinition{reverse_property: true} ->
|
%TermDefinition{reverse_property: true} ->
|
||||||
{Map.put_new(type_map, "@reverse", term), language_map}
|
{Map.put_new(type_map, "@reverse", term), language_map}
|
||||||
|
|
||||||
# 3.9) Otherwise, if term definition has a type mapping
|
# 3.9) Otherwise, if term definition has a type mapping
|
||||||
%TermDefinition{type_mapping: type_mapping}
|
%TermDefinition{type_mapping: type_mapping}
|
||||||
when type_mapping != false ->
|
when type_mapping != false ->
|
||||||
{Map.put_new(type_map, type_mapping, term), language_map}
|
{Map.put_new(type_map, type_mapping, term), language_map}
|
||||||
|
|
||||||
# 3.10) Otherwise, if term definition has a language mapping (might be null)
|
# 3.10) Otherwise, if term definition has a language mapping (might be null)
|
||||||
%TermDefinition{language_mapping: language_mapping}
|
%TermDefinition{language_mapping: language_mapping}
|
||||||
when language_mapping != false ->
|
when language_mapping != false ->
|
||||||
language = language_mapping || "@null"
|
language = language_mapping || "@null"
|
||||||
{type_map, Map.put_new(language_map, language, term)}
|
{type_map, Map.put_new(language_map, language, term)}
|
||||||
|
|
||||||
# 3.11) Otherwise
|
# 3.11) Otherwise
|
||||||
_ ->
|
_ ->
|
||||||
language_map = Map.put_new(language_map, default_language, term)
|
language_map = Map.put_new(language_map, default_language, term)
|
||||||
|
@ -415,10 +500,10 @@ defmodule JSON.LD.Context do
|
||||||
result
|
result
|
||||||
|> Map.put_new(iri, %{})
|
|> Map.put_new(iri, %{})
|
||||||
|> Map.update(iri, %{}, fn container_map ->
|
|> Map.update(iri, %{}, fn container_map ->
|
||||||
Map.put container_map, container, %{
|
Map.put(container_map, container, %{
|
||||||
"@type" => type_map,
|
"@type" => type_map,
|
||||||
"@language" => language_map,
|
"@language" => language_map
|
||||||
}
|
})
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
result
|
result
|
||||||
|
@ -426,10 +511,15 @@ defmodule JSON.LD.Context do
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def empty?(%JSON.LD.Context{term_defs: term_defs, vocab: nil, base_iri: false, default_language: nil})
|
def empty?(%JSON.LD.Context{
|
||||||
|
term_defs: term_defs,
|
||||||
|
vocab: nil,
|
||||||
|
base_iri: false,
|
||||||
|
default_language: nil
|
||||||
|
})
|
||||||
when map_size(term_defs) == 0,
|
when map_size(term_defs) == 0,
|
||||||
do: true
|
do: true
|
||||||
|
|
||||||
def empty?(_),
|
def empty?(_),
|
||||||
do: false
|
do: false
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
defmodule JSON.LD.Context.TermDefinition do
|
defmodule JSON.LD.Context.TermDefinition do
|
||||||
defstruct iri_mapping: nil,
|
defstruct iri_mapping: nil,
|
||||||
reverse_property: false,
|
reverse_property: false,
|
||||||
type_mapping: false, language_mapping: false,
|
type_mapping: false,
|
||||||
|
language_mapping: false,
|
||||||
container_mapping: nil
|
container_mapping: nil
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -8,7 +8,6 @@ defmodule JSON.LD.Decoder do
|
||||||
alias JSON.LD.NodeIdentifierMap
|
alias JSON.LD.NodeIdentifierMap
|
||||||
alias RDF.{Dataset, Graph, NS}
|
alias RDF.{Dataset, Graph, NS}
|
||||||
|
|
||||||
|
|
||||||
@impl RDF.Serialization.Decoder
|
@impl RDF.Serialization.Decoder
|
||||||
def decode(content, opts \\ []) do
|
def decode(content, opts \\ []) do
|
||||||
with {:ok, json_ld_object} <- parse_json(content),
|
with {:ok, json_ld_object} <- parse_json(content),
|
||||||
|
@ -19,62 +18,79 @@ defmodule JSON.LD.Decoder do
|
||||||
|
|
||||||
def to_rdf(element, options \\ %JSON.LD.Options{}) do
|
def to_rdf(element, options \\ %JSON.LD.Options{}) do
|
||||||
with options = JSON.LD.Options.new(options) do
|
with options = JSON.LD.Options.new(options) do
|
||||||
{:ok, node_id_map} = NodeIdentifierMap.start_link
|
{:ok, node_id_map} = NodeIdentifierMap.start_link()
|
||||||
|
|
||||||
try do
|
try do
|
||||||
element
|
element
|
||||||
|> JSON.LD.expand(options)
|
|> JSON.LD.expand(options)
|
||||||
|> JSON.LD.node_map(node_id_map)
|
|> JSON.LD.node_map(node_id_map)
|
||||||
|> Enum.sort_by(fn {graph_name, _} -> graph_name end)
|
|> Enum.sort_by(fn {graph_name, _} -> graph_name end)
|
||||||
|> Enum.reduce(Dataset.new, fn ({graph_name, graph}, dataset) ->
|
|> Enum.reduce(Dataset.new(), fn {graph_name, graph}, dataset ->
|
||||||
unless relative_iri?(graph_name) do
|
unless relative_iri?(graph_name) do
|
||||||
rdf_graph =
|
rdf_graph =
|
||||||
graph
|
graph
|
||||||
|> Enum.sort_by(fn {subject, _} -> subject end)
|
|> Enum.sort_by(fn {subject, _} -> subject end)
|
||||||
|> Enum.reduce(Graph.new, fn ({subject, node}, rdf_graph) ->
|
|> Enum.reduce(Graph.new(), fn {subject, node}, rdf_graph ->
|
||||||
unless relative_iri?(subject) do
|
unless relative_iri?(subject) do
|
||||||
node
|
node
|
||||||
|> Enum.sort_by(fn {property, _} -> property end)
|
|> Enum.sort_by(fn {property, _} -> property end)
|
||||||
|> Enum.reduce(rdf_graph, fn ({property, values}, rdf_graph) ->
|
|> Enum.reduce(rdf_graph, fn {property, values}, rdf_graph ->
|
||||||
cond do
|
cond do
|
||||||
property == "@type" ->
|
property == "@type" ->
|
||||||
Graph.add rdf_graph,
|
Graph.add(
|
||||||
node_to_rdf(subject), RDF.NS.RDF.type,
|
rdf_graph,
|
||||||
|
node_to_rdf(subject),
|
||||||
|
RDF.NS.RDF.type(),
|
||||||
Enum.map(values, &node_to_rdf/1)
|
Enum.map(values, &node_to_rdf/1)
|
||||||
|
)
|
||||||
|
|
||||||
JSON.LD.keyword?(property) ->
|
JSON.LD.keyword?(property) ->
|
||||||
rdf_graph
|
rdf_graph
|
||||||
|
|
||||||
not options.produce_generalized_rdf and
|
not options.produce_generalized_rdf and
|
||||||
blank_node_id?(property) ->
|
blank_node_id?(property) ->
|
||||||
rdf_graph
|
rdf_graph
|
||||||
|
|
||||||
relative_iri?(property) ->
|
relative_iri?(property) ->
|
||||||
rdf_graph
|
rdf_graph
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
Enum.reduce values, rdf_graph, fn
|
Enum.reduce(values, rdf_graph, fn
|
||||||
(%{"@list" => list}, rdf_graph) ->
|
%{"@list" => list}, rdf_graph ->
|
||||||
with {list_triples, first} <-
|
with {list_triples, first} <-
|
||||||
list_to_rdf(list, node_id_map) do
|
list_to_rdf(list, node_id_map) do
|
||||||
rdf_graph
|
rdf_graph
|
||||||
|> Graph.add({node_to_rdf(subject), node_to_rdf(property), first})
|
|> Graph.add({node_to_rdf(subject), node_to_rdf(property), first})
|
||||||
|> Graph.add(list_triples)
|
|> Graph.add(list_triples)
|
||||||
end
|
end
|
||||||
(item, rdf_graph) ->
|
|
||||||
|
item, rdf_graph ->
|
||||||
case object_to_rdf(item) do
|
case object_to_rdf(item) do
|
||||||
nil -> rdf_graph
|
nil ->
|
||||||
|
rdf_graph
|
||||||
|
|
||||||
object ->
|
object ->
|
||||||
Graph.add rdf_graph,
|
Graph.add(
|
||||||
|
rdf_graph,
|
||||||
{node_to_rdf(subject), node_to_rdf(property), object}
|
{node_to_rdf(subject), node_to_rdf(property), object}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
else
|
else
|
||||||
rdf_graph
|
rdf_graph
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if Enum.empty?(rdf_graph) do
|
if Enum.empty?(rdf_graph) do
|
||||||
dataset
|
dataset
|
||||||
else
|
else
|
||||||
Dataset.add(dataset, rdf_graph,
|
Dataset.add(
|
||||||
if(graph_name == "@default", do: nil, else: graph_name))
|
dataset,
|
||||||
|
rdf_graph,
|
||||||
|
if(graph_name == "@default", do: nil, else: graph_name)
|
||||||
|
)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
dataset
|
dataset
|
||||||
|
@ -95,11 +111,12 @@ defmodule JSON.LD.Decoder do
|
||||||
end
|
end
|
||||||
|
|
||||||
def node_to_rdf(nil), do: nil
|
def node_to_rdf(nil), do: nil
|
||||||
|
|
||||||
def node_to_rdf(node) do
|
def node_to_rdf(node) do
|
||||||
if blank_node_id?(node) do
|
if blank_node_id?(node) do
|
||||||
node
|
node
|
||||||
|> String.trim_leading("_:")
|
|> String.trim_leading("_:")
|
||||||
|> RDF.bnode
|
|> RDF.bnode()
|
||||||
else
|
else
|
||||||
RDF.uri(node)
|
RDF.uri(node)
|
||||||
end
|
end
|
||||||
|
@ -113,28 +130,49 @@ defmodule JSON.LD.Decoder do
|
||||||
|
|
||||||
defp object_to_rdf(%{"@value" => value} = item) do
|
defp object_to_rdf(%{"@value" => value} = item) do
|
||||||
datatype = item["@type"]
|
datatype = item["@type"]
|
||||||
|
|
||||||
{value, datatype} =
|
{value, datatype} =
|
||||||
cond do
|
cond do
|
||||||
is_boolean(value) ->
|
is_boolean(value) ->
|
||||||
value = value |> RDF.XSD.Boolean.new() |> RDF.XSD.Boolean.canonical() |> RDF.XSD.Boolean.lexical()
|
value =
|
||||||
datatype = if is_nil(datatype), do: NS.XSD.boolean, else: datatype
|
value
|
||||||
|
|> RDF.XSD.Boolean.new()
|
||||||
|
|> RDF.XSD.Boolean.canonical()
|
||||||
|
|> RDF.XSD.Boolean.lexical()
|
||||||
|
|
||||||
|
datatype = if is_nil(datatype), do: NS.XSD.boolean(), else: datatype
|
||||||
{value, datatype}
|
{value, datatype}
|
||||||
is_float(value) or (is_number(value) and datatype == to_string(NS.XSD.double)) ->
|
|
||||||
value = value |> RDF.XSD.Double.new() |> RDF.XSD.Double.canonical() |> RDF.XSD.Double.lexical()
|
is_float(value) or (is_number(value) and datatype == to_string(NS.XSD.double())) ->
|
||||||
datatype = if is_nil(datatype), do: NS.XSD.double, else: datatype
|
value =
|
||||||
|
value
|
||||||
|
|> RDF.XSD.Double.new()
|
||||||
|
|> RDF.XSD.Double.canonical()
|
||||||
|
|> RDF.XSD.Double.lexical()
|
||||||
|
|
||||||
|
datatype = if is_nil(datatype), do: NS.XSD.double(), else: datatype
|
||||||
{value, datatype}
|
{value, datatype}
|
||||||
is_integer(value) or (is_number(value) and datatype == to_string(NS.XSD.integer)) ->
|
|
||||||
value = value |> RDF.XSD.Integer.new() |> RDF.XSD.Integer.canonical() |> RDF.XSD.Integer.lexical()
|
is_integer(value) or (is_number(value) and datatype == to_string(NS.XSD.integer())) ->
|
||||||
datatype = if is_nil(datatype), do: NS.XSD.integer, else: datatype
|
value =
|
||||||
|
value
|
||||||
|
|> RDF.XSD.Integer.new()
|
||||||
|
|> RDF.XSD.Integer.canonical()
|
||||||
|
|> RDF.XSD.Integer.lexical()
|
||||||
|
|
||||||
|
datatype = if is_nil(datatype), do: NS.XSD.integer(), else: datatype
|
||||||
{value, datatype}
|
{value, datatype}
|
||||||
|
|
||||||
is_nil(datatype) ->
|
is_nil(datatype) ->
|
||||||
datatype =
|
datatype =
|
||||||
if Map.has_key?(item, "@language") do
|
if Map.has_key?(item, "@language") do
|
||||||
RDF.langString
|
RDF.langString()
|
||||||
else
|
else
|
||||||
NS.XSD.string
|
NS.XSD.string()
|
||||||
end
|
end
|
||||||
|
|
||||||
{value, datatype}
|
{value, datatype}
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
{value, datatype}
|
{value, datatype}
|
||||||
end
|
end
|
||||||
|
@ -149,22 +187,23 @@ defmodule JSON.LD.Decoder do
|
||||||
defp list_to_rdf(list, node_id_map) do
|
defp list_to_rdf(list, node_id_map) do
|
||||||
{list_triples, first, last} =
|
{list_triples, first, last} =
|
||||||
list
|
list
|
||||||
|> Enum.reduce({[], nil, nil}, fn (item, {list_triples, first, last}) ->
|
|> Enum.reduce({[], nil, nil}, fn item, {list_triples, first, last} ->
|
||||||
case object_to_rdf(item) do
|
case object_to_rdf(item) do
|
||||||
nil -> {list_triples, first, last}
|
nil ->
|
||||||
|
{list_triples, first, last}
|
||||||
|
|
||||||
object ->
|
object ->
|
||||||
with bnode = node_to_rdf(generate_blank_node_id(node_id_map)) do
|
with bnode = node_to_rdf(generate_blank_node_id(node_id_map)) do
|
||||||
if last do
|
if last do
|
||||||
{
|
{
|
||||||
list_triples ++
|
list_triples ++
|
||||||
[{last, RDF.NS.RDF.rest, bnode},
|
[{last, RDF.NS.RDF.rest(), bnode}, {bnode, RDF.NS.RDF.first(), object}],
|
||||||
{bnode, RDF.NS.RDF.first, object}],
|
|
||||||
first,
|
first,
|
||||||
bnode
|
bnode
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
list_triples ++ [{bnode, RDF.NS.RDF.first, object}],
|
list_triples ++ [{bnode, RDF.NS.RDF.first(), object}],
|
||||||
bnode,
|
bnode,
|
||||||
bnode
|
bnode
|
||||||
}
|
}
|
||||||
|
@ -172,10 +211,11 @@ defmodule JSON.LD.Decoder do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
if last do
|
if last do
|
||||||
{list_triples ++ [{last, RDF.NS.RDF.rest, RDF.NS.RDF.nil}], first}
|
{list_triples ++ [{last, RDF.NS.RDF.rest(), RDF.NS.RDF.nil()}], first}
|
||||||
else
|
else
|
||||||
{[], RDF.NS.RDF.nil}
|
{[], RDF.NS.RDF.nil()}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -198,5 +238,4 @@ defmodule JSON.LD.Decoder do
|
||||||
# end
|
# end
|
||||||
# end)
|
# end)
|
||||||
# end
|
# end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,5 +7,5 @@ defmodule JSON.LD.DocumentLoader do
|
||||||
|
|
||||||
alias JSON.LD.DocumentLoader.RemoteDocument
|
alias JSON.LD.DocumentLoader.RemoteDocument
|
||||||
|
|
||||||
@callback load(String.t, JSON.LD.Options.t) :: {:ok, RemoteDocument.t} | {:error, any}
|
@callback load(String.t(), JSON.LD.Options.t()) :: {:ok, RemoteDocument.t()} | {:error, any}
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,6 @@ defmodule JSON.LD.DocumentLoader.Default do
|
||||||
defp http_get(url) do
|
defp http_get(url) do
|
||||||
HTTPoison.get(url, [accept: "application/ld+json"], follow_redirect: true)
|
HTTPoison.get(url, [accept: "application/ld+json"], follow_redirect: true)
|
||||||
rescue
|
rescue
|
||||||
e -> {:error, "HTTPoison failed: #{inspect e}"}
|
e -> {:error, "HTTPoison failed: #{inspect(e)}"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
defmodule JSON.LD.DocumentLoader.RemoteDocument do
|
defmodule JSON.LD.DocumentLoader.RemoteDocument do
|
||||||
@type t :: %__MODULE__{
|
@type t :: %__MODULE__{
|
||||||
context_url: String.t,
|
context_url: String.t(),
|
||||||
document_url: String.t,
|
document_url: String.t(),
|
||||||
document: any
|
document: any
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,10 @@ defmodule JSON.LD.Encoder do
|
||||||
|
|
||||||
alias RDF.{IRI, BlankNode, Literal, XSD, NS}
|
alias RDF.{IRI, BlankNode, Literal, XSD, NS}
|
||||||
|
|
||||||
@rdf_type to_string(RDF.NS.RDF.type)
|
@rdf_type to_string(RDF.NS.RDF.type())
|
||||||
@rdf_nil to_string(RDF.NS.RDF.nil)
|
@rdf_nil to_string(RDF.NS.RDF.nil())
|
||||||
@rdf_first to_string(RDF.NS.RDF.first)
|
@rdf_first to_string(RDF.NS.RDF.first())
|
||||||
@rdf_rest to_string(RDF.NS.RDF.rest)
|
@rdf_rest to_string(RDF.NS.RDF.rest())
|
||||||
@rdf_list to_string(RDF.uri(RDF.NS.RDF.List))
|
@rdf_list to_string(RDF.uri(RDF.NS.RDF.List))
|
||||||
|
|
||||||
@impl RDF.Serialization.Encoder
|
@impl RDF.Serialization.Encoder
|
||||||
|
@ -38,66 +38,76 @@ defmodule JSON.LD.Encoder do
|
||||||
def from_rdf!(%RDF.Dataset{} = dataset, options) do
|
def from_rdf!(%RDF.Dataset{} = dataset, options) do
|
||||||
with options = JSON.LD.Options.new(options) do
|
with options = JSON.LD.Options.new(options) do
|
||||||
graph_map =
|
graph_map =
|
||||||
Enum.reduce RDF.Dataset.graphs(dataset), %{},
|
Enum.reduce(RDF.Dataset.graphs(dataset), %{}, fn graph, graph_map ->
|
||||||
fn graph, graph_map ->
|
|
||||||
# 3.1)
|
# 3.1)
|
||||||
name = to_string(graph.name || "@default")
|
name = to_string(graph.name || "@default")
|
||||||
|
|
||||||
# 3.3)
|
# 3.3)
|
||||||
graph_map =
|
graph_map =
|
||||||
if graph.name && !get_in(graph_map, ["@default", name]) do
|
if graph.name && !get_in(graph_map, ["@default", name]) do
|
||||||
Map.update graph_map, "@default", %{name => %{"@id" => name}},
|
Map.update(graph_map, "@default", %{name => %{"@id" => name}}, fn default_graph ->
|
||||||
fn default_graph ->
|
|
||||||
Map.put(default_graph, name, %{"@id" => name})
|
Map.put(default_graph, name, %{"@id" => name})
|
||||||
end
|
end)
|
||||||
else
|
else
|
||||||
graph_map
|
graph_map
|
||||||
end
|
end
|
||||||
|
|
||||||
# 3.2 + 3.4)
|
# 3.2 + 3.4)
|
||||||
Map.put(graph_map, name,
|
Map.put(
|
||||||
node_map_from_graph(graph, Map.get(graph_map, name, %{}),
|
graph_map,
|
||||||
options.use_native_types, options.use_rdf_type))
|
name,
|
||||||
end
|
node_map_from_graph(
|
||||||
|
graph,
|
||||||
|
Map.get(graph_map, name, %{}),
|
||||||
|
options.use_native_types,
|
||||||
|
options.use_rdf_type
|
||||||
|
)
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
|
||||||
# 4)
|
# 4)
|
||||||
graph_map =
|
graph_map =
|
||||||
Enum.reduce graph_map, %{}, fn ({name, graph_object}, graph_map) ->
|
Enum.reduce(graph_map, %{}, fn {name, graph_object}, graph_map ->
|
||||||
Map.put(graph_map, name, convert_list(graph_object))
|
Map.put(graph_map, name, convert_list(graph_object))
|
||||||
end
|
end)
|
||||||
|
|
||||||
# 5+6)
|
# 5+6)
|
||||||
Map.get(graph_map, "@default", %{})
|
Map.get(graph_map, "@default", %{})
|
||||||
|> Enum.sort_by(fn {subject, _} -> subject end)
|
|> Enum.sort_by(fn {subject, _} -> subject end)
|
||||||
|> Enum.reduce([], fn ({subject, node}, result) ->
|
|> Enum.reduce([], fn {subject, node}, result ->
|
||||||
# 6.1)
|
# 6.1)
|
||||||
node =
|
node =
|
||||||
if Map.has_key?(graph_map, subject) do
|
if Map.has_key?(graph_map, subject) do
|
||||||
Map.put node, "@graph",
|
Map.put(
|
||||||
|
node,
|
||||||
|
"@graph",
|
||||||
graph_map[subject]
|
graph_map[subject]
|
||||||
|> Enum.sort_by(fn {s, _} -> s end)
|
|> Enum.sort_by(fn {s, _} -> s end)
|
||||||
|> Enum.reduce([], fn ({_s, n}, graph_nodes) ->
|
|> Enum.reduce([], fn {_s, n}, graph_nodes ->
|
||||||
n = Map.delete(n, "usages")
|
n = Map.delete(n, "usages")
|
||||||
|
|
||||||
if map_size(n) == 1 and Map.has_key?(n, "@id") do
|
if map_size(n) == 1 and Map.has_key?(n, "@id") do
|
||||||
graph_nodes
|
graph_nodes
|
||||||
else
|
else
|
||||||
[n | graph_nodes]
|
[n | graph_nodes]
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|> Enum.reverse
|
|> Enum.reverse()
|
||||||
|
)
|
||||||
else
|
else
|
||||||
node
|
node
|
||||||
end
|
end
|
||||||
|
|
||||||
# 6.2)
|
# 6.2)
|
||||||
node = Map.delete(node, "usages")
|
node = Map.delete(node, "usages")
|
||||||
|
|
||||||
if map_size(node) == 1 and Map.has_key?(node, "@id") do
|
if map_size(node) == 1 and Map.has_key?(node, "@id") do
|
||||||
result
|
result
|
||||||
else
|
else
|
||||||
[node | result]
|
[node | result]
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|> Enum.reverse
|
|> Enum.reverse()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -106,30 +116,34 @@ defmodule JSON.LD.Encoder do
|
||||||
|
|
||||||
# 3.5)
|
# 3.5)
|
||||||
defp node_map_from_graph(graph, current, use_native_types, use_rdf_type) do
|
defp node_map_from_graph(graph, current, use_native_types, use_rdf_type) do
|
||||||
Enum.reduce(graph, current, fn ({subject, predicate, object}, node_map) ->
|
Enum.reduce(graph, current, fn {subject, predicate, object}, node_map ->
|
||||||
{subject, predicate, node_object} =
|
{subject, predicate, node_object} = {to_string(subject), to_string(predicate), nil}
|
||||||
{to_string(subject), to_string(predicate), nil}
|
|
||||||
node = Map.get(node_map, subject, %{"@id" => subject})
|
node = Map.get(node_map, subject, %{"@id" => subject})
|
||||||
|
|
||||||
{node_object, node_map} =
|
{node_object, node_map} =
|
||||||
if is_node_object = (match?(%IRI{}, object) || match?(%BlankNode{}, object)) do
|
if is_node_object = match?(%IRI{}, object) || match?(%BlankNode{}, object) do
|
||||||
node_object = to_string(object)
|
node_object = to_string(object)
|
||||||
node_map = Map.put_new(node_map, node_object, %{"@id" => node_object})
|
node_map = Map.put_new(node_map, node_object, %{"@id" => node_object})
|
||||||
{node_object, node_map}
|
{node_object, node_map}
|
||||||
else
|
else
|
||||||
{node_object, node_map}
|
{node_object, node_map}
|
||||||
end
|
end
|
||||||
|
|
||||||
{node, node_map} =
|
{node, node_map} =
|
||||||
if is_node_object and !use_rdf_type and predicate == @rdf_type do
|
if is_node_object and !use_rdf_type and predicate == @rdf_type do
|
||||||
node = Map.update(node, "@type", [node_object], fn types ->
|
node =
|
||||||
|
Map.update(node, "@type", [node_object], fn types ->
|
||||||
if node_object in types do
|
if node_object in types do
|
||||||
types
|
types
|
||||||
else
|
else
|
||||||
types ++ [node_object]
|
types ++ [node_object]
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
{node, node_map}
|
{node, node_map}
|
||||||
else
|
else
|
||||||
value = rdf_to_object(object, use_native_types)
|
value = rdf_to_object(object, use_native_types)
|
||||||
|
|
||||||
node =
|
node =
|
||||||
Map.update(node, predicate, [value], fn objects ->
|
Map.update(node, predicate, [value], fn objects ->
|
||||||
if value in objects do
|
if value in objects do
|
||||||
|
@ -138,13 +152,15 @@ defmodule JSON.LD.Encoder do
|
||||||
objects ++ [value]
|
objects ++ [value]
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
node_map =
|
node_map =
|
||||||
if is_node_object do
|
if is_node_object do
|
||||||
usage = %{
|
usage = %{
|
||||||
"node" => node,
|
"node" => node,
|
||||||
"property" => predicate,
|
"property" => predicate,
|
||||||
"value" => value,
|
"value" => value
|
||||||
}
|
}
|
||||||
|
|
||||||
Map.update(node_map, node_object, %{"usages" => [usage]}, fn object_node ->
|
Map.update(node_map, node_object, %{"usages" => [usage]}, fn object_node ->
|
||||||
Map.update(object_node, "usages", [usage], fn usages ->
|
Map.update(object_node, "usages", [usage], fn usages ->
|
||||||
usages ++ [usage]
|
usages ++ [usage]
|
||||||
|
@ -153,8 +169,10 @@ defmodule JSON.LD.Encoder do
|
||||||
else
|
else
|
||||||
node_map
|
node_map
|
||||||
end
|
end
|
||||||
|
|
||||||
{node, node_map}
|
{node, node_map}
|
||||||
end
|
end
|
||||||
|
|
||||||
Map.put(node_map, subject, node)
|
Map.put(node_map, subject, node)
|
||||||
end)
|
end)
|
||||||
|> update_node_usages
|
|> update_node_usages
|
||||||
|
@ -163,38 +181,41 @@ defmodule JSON.LD.Encoder do
|
||||||
# This function is necessary because we have no references and must update the
|
# This function is necessary because we have no references and must update the
|
||||||
# node member of the usage maps with later enhanced usages
|
# node member of the usage maps with later enhanced usages
|
||||||
defp update_node_usages(node_map) do
|
defp update_node_usages(node_map) do
|
||||||
Enum.reduce node_map, node_map, fn
|
Enum.reduce(node_map, node_map, fn
|
||||||
({subject, %{"usages" => _usages} = _node}, node_map) ->
|
{subject, %{"usages" => _usages} = _node}, node_map ->
|
||||||
update_in node_map, [subject, "usages"], fn usages ->
|
update_in(node_map, [subject, "usages"], fn usages ->
|
||||||
Enum.map usages, fn usage ->
|
Enum.map(usages, fn usage ->
|
||||||
Map.update! usage, "node", fn %{"@id" => subject} ->
|
Map.update!(usage, "node", fn %{"@id" => subject} ->
|
||||||
node_map[subject]
|
node_map[subject]
|
||||||
end
|
end)
|
||||||
end
|
end)
|
||||||
end
|
end)
|
||||||
(_, node_map) -> node_map
|
|
||||||
end
|
_, node_map ->
|
||||||
|
node_map
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
# This function is necessary because we have no references and use this
|
# This function is necessary because we have no references and use this
|
||||||
# instead to update the head by path
|
# instead to update the head by path
|
||||||
defp update_head(graph_object, path, old, new) do
|
defp update_head(graph_object, path, old, new) do
|
||||||
update_in graph_object, path, fn objects ->
|
update_in(graph_object, path, fn objects ->
|
||||||
Enum.map objects, fn
|
Enum.map(objects, fn
|
||||||
^old -> new
|
^old -> new
|
||||||
current -> current
|
current -> current
|
||||||
end
|
end)
|
||||||
end
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
# 4)
|
# 4)
|
||||||
defp convert_list(%{@rdf_nil => nil_node} = graph_object) do
|
defp convert_list(%{@rdf_nil => nil_node} = graph_object) do
|
||||||
Enum.reduce nil_node["usages"], graph_object,
|
Enum.reduce(
|
||||||
|
nil_node["usages"],
|
||||||
|
graph_object,
|
||||||
# 4.3.1)
|
# 4.3.1)
|
||||||
fn (usage, graph_object) ->
|
fn usage, graph_object ->
|
||||||
# 4.3.2) + 4.3.3)
|
# 4.3.2) + 4.3.3)
|
||||||
{list, list_nodes, [subject, property] = head_path, head} =
|
{list, list_nodes, [subject, property] = head_path, head} = extract_list(usage)
|
||||||
extract_list(usage)
|
|
||||||
|
|
||||||
# 4.3.4)
|
# 4.3.4)
|
||||||
{skip, list, list_nodes, head_path, head} =
|
{skip, list, list_nodes, head_path, head} =
|
||||||
|
@ -214,62 +235,85 @@ defmodule JSON.LD.Encoder do
|
||||||
else
|
else
|
||||||
{false, list, list_nodes, head_path, head}
|
{false, list, list_nodes, head_path, head}
|
||||||
end
|
end
|
||||||
|
|
||||||
if skip do
|
if skip do
|
||||||
graph_object
|
graph_object
|
||||||
else
|
else
|
||||||
graph_object =
|
graph_object =
|
||||||
update_head graph_object, head_path, head,
|
update_head(
|
||||||
|
graph_object,
|
||||||
|
head_path,
|
||||||
|
head,
|
||||||
head
|
head
|
||||||
# 4.3.5)
|
# 4.3.5)
|
||||||
|> Map.delete("@id")
|
|> Map.delete("@id")
|
||||||
# 4.3.6) isn't necessary, since we built the list in reverse order
|
# 4.3.6) isn't necessary, since we built the list in reverse order
|
||||||
# 4.3.7)
|
# 4.3.7)
|
||||||
|> Map.put("@list", list)
|
|> Map.put("@list", list)
|
||||||
|
)
|
||||||
|
|
||||||
# 4.3.8)
|
# 4.3.8)
|
||||||
Enum.reduce(list_nodes, graph_object, fn (node_id, graph_object) ->
|
Enum.reduce(list_nodes, graph_object, fn node_id, graph_object ->
|
||||||
Map.delete(graph_object, node_id)
|
Map.delete(graph_object, node_id)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp convert_list(graph_object), do: graph_object
|
defp convert_list(graph_object), do: graph_object
|
||||||
|
|
||||||
|
|
||||||
# 4.3.3)
|
# 4.3.3)
|
||||||
defp extract_list(usage, list \\ [], list_nodes \\ [])
|
defp extract_list(usage, list \\ [], list_nodes \\ [])
|
||||||
|
|
||||||
defp extract_list(
|
defp extract_list(
|
||||||
%{"node" => %{
|
%{
|
||||||
|
"node" =>
|
||||||
|
%{
|
||||||
# Spec FIXME: no mention of @id
|
# Spec FIXME: no mention of @id
|
||||||
"@id" => id = ("_:" <> _), # contrary to spec we assume/require this to be even on the initial call to be a blank node
|
# contrary to spec we assume/require this to be even on the initial call to be a blank node
|
||||||
|
"@id" => id = "_:" <> _,
|
||||||
"usages" => [usage],
|
"usages" => [usage],
|
||||||
@rdf_first => [first],
|
@rdf_first => [first],
|
||||||
@rdf_rest => [_rest],
|
@rdf_rest => [_rest]
|
||||||
} = node,
|
} = node,
|
||||||
"property" => @rdf_rest}, list, list_nodes) when map_size(node) == 4 do
|
"property" => @rdf_rest
|
||||||
|
},
|
||||||
|
list,
|
||||||
|
list_nodes
|
||||||
|
)
|
||||||
|
when map_size(node) == 4 do
|
||||||
extract_list(usage, [first | list], [id | list_nodes])
|
extract_list(usage, [first | list], [id | list_nodes])
|
||||||
end
|
end
|
||||||
|
|
||||||
defp extract_list(
|
defp extract_list(
|
||||||
%{"node" => %{
|
%{
|
||||||
|
"node" =>
|
||||||
|
%{
|
||||||
# Spec FIXME: no mention of @id
|
# Spec FIXME: no mention of @id
|
||||||
"@id" => id = ("_:" <> _), # contrary to spec we assume/require this to be even on the initial call to be a blank node
|
# contrary to spec we assume/require this to be even on the initial call to be a blank node
|
||||||
|
"@id" => id = "_:" <> _,
|
||||||
"@type" => [@rdf_list],
|
"@type" => [@rdf_list],
|
||||||
"usages" => [usage],
|
"usages" => [usage],
|
||||||
@rdf_first => [first],
|
@rdf_first => [first],
|
||||||
@rdf_rest => [_rest],
|
@rdf_rest => [_rest]
|
||||||
} = node,
|
} = node,
|
||||||
"property" => @rdf_rest}, list, list_nodes) when map_size(node) == 5 do
|
"property" => @rdf_rest
|
||||||
|
},
|
||||||
|
list,
|
||||||
|
list_nodes
|
||||||
|
)
|
||||||
|
when map_size(node) == 5 do
|
||||||
extract_list(usage, [first | list], [id | list_nodes])
|
extract_list(usage, [first | list], [id | list_nodes])
|
||||||
end
|
end
|
||||||
|
|
||||||
defp extract_list(%{"node" => %{"@id" => subject}, "property" => property, "value" => head},
|
defp extract_list(
|
||||||
list, list_nodes),
|
%{"node" => %{"@id" => subject}, "property" => property, "value" => head},
|
||||||
|
list,
|
||||||
|
list_nodes
|
||||||
|
),
|
||||||
do: {list, list_nodes, [subject, property], head}
|
do: {list, list_nodes, [subject, property], head}
|
||||||
|
|
||||||
|
|
||||||
defp rdf_to_object(%IRI{} = iri, _use_native_types) do
|
defp rdf_to_object(%IRI{} = iri, _use_native_types) do
|
||||||
%{"@id" => to_string(iri)}
|
%{"@id" => to_string(iri)}
|
||||||
end
|
end
|
||||||
|
@ -283,23 +327,27 @@ defmodule JSON.LD.Encoder do
|
||||||
value = Literal.value(literal)
|
value = Literal.value(literal)
|
||||||
converted_value = literal
|
converted_value = literal
|
||||||
type = nil
|
type = nil
|
||||||
|
|
||||||
{converted_value, type, result} =
|
{converted_value, type, result} =
|
||||||
if use_native_types do
|
if use_native_types do
|
||||||
cond do
|
cond do
|
||||||
datatype == XSD.String ->
|
datatype == XSD.String ->
|
||||||
{value, type, result}
|
{value, type, result}
|
||||||
|
|
||||||
datatype == XSD.Boolean ->
|
datatype == XSD.Boolean ->
|
||||||
if RDF.XSD.Boolean.valid?(literal) do
|
if RDF.XSD.Boolean.valid?(literal) do
|
||||||
{value, type, result}
|
{value, type, result}
|
||||||
else
|
else
|
||||||
{converted_value, NS.XSD.boolean, result}
|
{converted_value, NS.XSD.boolean(), result}
|
||||||
end
|
end
|
||||||
|
|
||||||
datatype in [XSD.Integer, XSD.Double] ->
|
datatype in [XSD.Integer, XSD.Double] ->
|
||||||
if Literal.valid?(literal) do
|
if Literal.valid?(literal) do
|
||||||
{value, type, result}
|
{value, type, result}
|
||||||
else
|
else
|
||||||
{converted_value, type, result}
|
{converted_value, type, result}
|
||||||
end
|
end
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
{converted_value, Literal.datatype_id(literal), result}
|
{converted_value, Literal.datatype_id(literal), result}
|
||||||
end
|
end
|
||||||
|
@ -307,18 +355,23 @@ defmodule JSON.LD.Encoder do
|
||||||
cond do
|
cond do
|
||||||
datatype == RDF.LangString ->
|
datatype == RDF.LangString ->
|
||||||
{converted_value, type, Map.put(result, "@language", Literal.language(literal))}
|
{converted_value, type, Map.put(result, "@language", Literal.language(literal))}
|
||||||
|
|
||||||
datatype == XSD.String ->
|
datatype == XSD.String ->
|
||||||
{converted_value, type, result}
|
{converted_value, type, result}
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
{Literal.lexical(literal), Literal.datatype_id(literal), result}
|
{Literal.lexical(literal), Literal.datatype_id(literal), result}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
result = type && Map.put(result, "@type", to_string(type)) || result
|
result = (type && Map.put(result, "@type", to_string(type))) || result
|
||||||
Map.put(result, "@value",
|
|
||||||
match?(%Literal{}, converted_value) && Literal.lexical(converted_value) || converted_value)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
Map.put(
|
||||||
|
result,
|
||||||
|
"@value",
|
||||||
|
(match?(%Literal{}, converted_value) && Literal.lexical(converted_value)) || converted_value
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
defp encode_json(value, opts) do
|
defp encode_json(value, opts) do
|
||||||
Jason.encode(value, opts)
|
Jason.encode(value, opts)
|
||||||
|
|
|
@ -187,7 +187,6 @@ defmodule JSON.LD.InvalidLanguageTaggedStringError do
|
||||||
defexception code: "invalid language-tagged string", message: nil
|
defexception code: "invalid language-tagged string", message: nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
defmodule JSON.LD.InvalidLanguageTaggedValueError do
|
defmodule JSON.LD.InvalidLanguageTaggedValueError do
|
||||||
@moduledoc """
|
@moduledoc """
|
||||||
A number, true, or false with an associated language tag was detected.
|
A number, true, or false with an associated language tag was detected.
|
||||||
|
|
|
@ -3,17 +3,17 @@ defmodule JSON.LD.Expansion do
|
||||||
|
|
||||||
import JSON.LD.{IRIExpansion, Utils}
|
import JSON.LD.{IRIExpansion, Utils}
|
||||||
|
|
||||||
|
|
||||||
def expand(input, options \\ %JSON.LD.Options{}) do
|
def expand(input, options \\ %JSON.LD.Options{}) do
|
||||||
with options = JSON.LD.Options.new(options),
|
with options = JSON.LD.Options.new(options),
|
||||||
active_context = JSON.LD.Context.new(options)
|
active_context = JSON.LD.Context.new(options) do
|
||||||
do
|
|
||||||
active_context =
|
active_context =
|
||||||
case options.expand_context do
|
case options.expand_context do
|
||||||
%{"@context" => context} ->
|
%{"@context" => context} ->
|
||||||
JSON.LD.Context.update(active_context, context)
|
JSON.LD.Context.update(active_context, context)
|
||||||
|
|
||||||
%{} = context ->
|
%{} = context ->
|
||||||
JSON.LD.Context.update(active_context, context)
|
JSON.LD.Context.update(active_context, context)
|
||||||
|
|
||||||
nil ->
|
nil ->
|
||||||
active_context
|
active_context
|
||||||
end
|
end
|
||||||
|
@ -21,11 +21,15 @@ defmodule JSON.LD.Expansion do
|
||||||
case do_expand(active_context, nil, input, options) do
|
case do_expand(active_context, nil, input, options) do
|
||||||
result = %{"@graph" => graph} when map_size(result) == 1 ->
|
result = %{"@graph" => graph} when map_size(result) == 1 ->
|
||||||
graph
|
graph
|
||||||
|
|
||||||
nil ->
|
nil ->
|
||||||
[]
|
[]
|
||||||
|
|
||||||
result when not is_list(result) ->
|
result when not is_list(result) ->
|
||||||
[result]
|
[result]
|
||||||
result -> result
|
|
||||||
|
result ->
|
||||||
|
result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -50,17 +54,25 @@ defmodule JSON.LD.Expansion do
|
||||||
when is_list(element) do
|
when is_list(element) do
|
||||||
term_def = active_context.term_defs[active_property]
|
term_def = active_context.term_defs[active_property]
|
||||||
container_mapping = term_def && term_def.container_mapping
|
container_mapping = term_def && term_def.container_mapping
|
||||||
|
|
||||||
element
|
element
|
||||||
|> Enum.reduce([], fn (item, result) ->
|
|> Enum.reduce([], fn item, result ->
|
||||||
expanded_item = do_expand(active_context, active_property, item, options)
|
expanded_item = do_expand(active_context, active_property, item, options)
|
||||||
|
|
||||||
if (active_property == "@list" or container_mapping == "@list") and
|
if (active_property == "@list" or container_mapping == "@list") and
|
||||||
(is_list(expanded_item) or Map.has_key?(expanded_item, "@list")),
|
(is_list(expanded_item) or Map.has_key?(expanded_item, "@list")),
|
||||||
do: raise JSON.LD.ListOfListsError,
|
do:
|
||||||
message: "List of lists in #{inspect element}"
|
raise(JSON.LD.ListOfListsError,
|
||||||
|
message: "List of lists in #{inspect(element)}"
|
||||||
|
)
|
||||||
|
|
||||||
case expanded_item do
|
case expanded_item do
|
||||||
nil -> result
|
nil ->
|
||||||
|
result
|
||||||
|
|
||||||
list when is_list(list) ->
|
list when is_list(list) ->
|
||||||
result ++ list
|
result ++ list
|
||||||
|
|
||||||
expanded_item ->
|
expanded_item ->
|
||||||
result ++ [expanded_item]
|
result ++ [expanded_item]
|
||||||
end
|
end
|
||||||
|
@ -77,44 +89,71 @@ defmodule JSON.LD.Expansion do
|
||||||
else
|
else
|
||||||
active_context
|
active_context
|
||||||
end
|
end
|
||||||
# 6) and 7)
|
|
||||||
result = element
|
|
||||||
|> Enum.sort_by(fn {key, _} -> key end)
|
|
||||||
|> Enum.reduce(%{}, fn ({key, value}, result) ->
|
|
||||||
if key != "@context" do # 7.1)
|
|
||||||
expanded_property = expand_iri(key, active_context, false, true)
|
|
||||||
if expanded_property && # 7.2)
|
|
||||||
(String.contains?(expanded_property, ":") || JSON.LD.keyword?(expanded_property)) do # 7.3)
|
|
||||||
if JSON.LD.keyword?(expanded_property) do # 7.4)
|
|
||||||
if active_property == "@reverse", # 7.4.1)
|
|
||||||
do: raise JSON.LD.InvalidReversePropertyMapError,
|
|
||||||
message: "An invalid reverse property map has been detected. No keywords apart from @context are allowed in reverse property maps."
|
|
||||||
if Map.has_key?(result, expanded_property), # 7.4.2)
|
|
||||||
do: raise JSON.LD.CollidingKeywordsError,
|
|
||||||
message: "Two properties which expand to the same keyword have been detected. This might occur if a keyword and an alias thereof are used at the same time."
|
|
||||||
|
|
||||||
expanded_value = case expanded_property do
|
# 6) and 7)
|
||||||
"@id" -> # 7.4.3)
|
result =
|
||||||
|
element
|
||||||
|
|> Enum.sort_by(fn {key, _} -> key end)
|
||||||
|
|> Enum.reduce(%{}, fn {key, value}, result ->
|
||||||
|
# 7.1)
|
||||||
|
if key != "@context" do
|
||||||
|
expanded_property = expand_iri(key, active_context, false, true)
|
||||||
|
# 7.2)
|
||||||
|
# 7.3)
|
||||||
|
if expanded_property &&
|
||||||
|
(String.contains?(expanded_property, ":") || JSON.LD.keyword?(expanded_property)) do
|
||||||
|
# 7.4)
|
||||||
|
# expanded_property is not a keyword
|
||||||
|
if JSON.LD.keyword?(expanded_property) do
|
||||||
|
# 7.4.1)
|
||||||
|
if active_property == "@reverse",
|
||||||
|
do:
|
||||||
|
raise(JSON.LD.InvalidReversePropertyMapError,
|
||||||
|
message:
|
||||||
|
"An invalid reverse property map has been detected. No keywords apart from @context are allowed in reverse property maps."
|
||||||
|
)
|
||||||
|
|
||||||
|
# 7.4.2)
|
||||||
|
if Map.has_key?(result, expanded_property),
|
||||||
|
do:
|
||||||
|
raise(JSON.LD.CollidingKeywordsError,
|
||||||
|
message:
|
||||||
|
"Two properties which expand to the same keyword have been detected. This might occur if a keyword and an alias thereof are used at the same time."
|
||||||
|
)
|
||||||
|
|
||||||
|
expanded_value =
|
||||||
|
case expanded_property do
|
||||||
|
# 7.4.3)
|
||||||
|
"@id" ->
|
||||||
if is_binary(value) do
|
if is_binary(value) do
|
||||||
expand_iri(value, active_context, true)
|
expand_iri(value, active_context, true)
|
||||||
else
|
else
|
||||||
raise JSON.LD.InvalidIdValueError,
|
raise JSON.LD.InvalidIdValueError,
|
||||||
message: "#{inspect value} is not a valid @id value"
|
message: "#{inspect(value)} is not a valid @id value"
|
||||||
end
|
end
|
||||||
"@type" -> # 7.4.4)
|
|
||||||
|
# 7.4.4)
|
||||||
|
"@type" ->
|
||||||
cond do
|
cond do
|
||||||
is_binary(value) ->
|
is_binary(value) ->
|
||||||
expand_iri(value, active_context, true, true)
|
expand_iri(value, active_context, true, true)
|
||||||
|
|
||||||
is_list(value) and Enum.all?(value, &is_binary/1) ->
|
is_list(value) and Enum.all?(value, &is_binary/1) ->
|
||||||
Enum.map value, fn item ->
|
Enum.map(value, fn item ->
|
||||||
expand_iri(item, active_context, true, true) end
|
expand_iri(item, active_context, true, true)
|
||||||
|
end)
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
raise JSON.LD.InvalidTypeValueError,
|
raise JSON.LD.InvalidTypeValueError,
|
||||||
message: "#{inspect value} is not a valid @type value"
|
message: "#{inspect(value)} is not a valid @type value"
|
||||||
end
|
end
|
||||||
"@graph" -> # 7.4.5)
|
|
||||||
|
# 7.4.5)
|
||||||
|
"@graph" ->
|
||||||
do_expand(active_context, "@graph", value, options)
|
do_expand(active_context, "@graph", value, options)
|
||||||
"@value" -> # 7.4.6)
|
|
||||||
|
# 7.4.6)
|
||||||
|
"@value" ->
|
||||||
if scalar?(value) or is_nil(value) do
|
if scalar?(value) or is_nil(value) do
|
||||||
if is_nil(value) do
|
if is_nil(value) do
|
||||||
{:skip, Map.put(result, "@value", nil)}
|
{:skip, Map.put(result, "@value", nil)}
|
||||||
|
@ -123,172 +162,237 @@ defmodule JSON.LD.Expansion do
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
raise JSON.LD.InvalidValueObjectValueError,
|
raise JSON.LD.InvalidValueObjectValueError,
|
||||||
message: "#{inspect value} is not a valid value for the @value member of a value object; neither a scalar nor null"
|
message:
|
||||||
|
"#{inspect(value)} is not a valid value for the @value member of a value object; neither a scalar nor null"
|
||||||
end
|
end
|
||||||
"@language" -> # 7.4.7)
|
|
||||||
|
# 7.4.7)
|
||||||
|
"@language" ->
|
||||||
if is_binary(value),
|
if is_binary(value),
|
||||||
do: String.downcase(value),
|
do: String.downcase(value),
|
||||||
else: raise JSON.LD.InvalidLanguageTaggedStringError,
|
else:
|
||||||
message: "#{inspect value} is not a valid language-tag"
|
raise(JSON.LD.InvalidLanguageTaggedStringError,
|
||||||
"@index" -> # 7.4.8)
|
message: "#{inspect(value)} is not a valid language-tag"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 7.4.8)
|
||||||
|
"@index" ->
|
||||||
if is_binary(value),
|
if is_binary(value),
|
||||||
do: value,
|
do: value,
|
||||||
else: raise JSON.LD.InvalidIndexValueError,
|
else:
|
||||||
message: "#{inspect value} is not a valid @index value"
|
raise(JSON.LD.InvalidIndexValueError,
|
||||||
"@list" -> # 7.4.9)
|
message: "#{inspect(value)} is not a valid @index value"
|
||||||
if active_property in [nil, "@graph"] do # 7.4.9.1)
|
)
|
||||||
|
|
||||||
|
# 7.4.9)
|
||||||
|
"@list" ->
|
||||||
|
# 7.4.9.1)
|
||||||
|
if active_property in [nil, "@graph"] do
|
||||||
{:skip, result}
|
{:skip, result}
|
||||||
else
|
else
|
||||||
value = do_expand(active_context, active_property, value, options)
|
value = do_expand(active_context, active_property, value, options)
|
||||||
|
|
||||||
# Spec FIXME: need to be sure that result is a list [from RDF.rb implementation]
|
# Spec FIXME: need to be sure that result is a list [from RDF.rb implementation]
|
||||||
value = if is_list(value),
|
value =
|
||||||
|
if is_list(value),
|
||||||
do: value,
|
do: value,
|
||||||
else: [value]
|
else: [value]
|
||||||
|
|
||||||
# If expanded value is a list object, a list of lists error has been detected and processing is aborted.
|
# If expanded value is a list object, a list of lists error has been detected and processing is aborted.
|
||||||
# Spec FIXME: Also look at each object if result is a list [from RDF.rb implementation]
|
# Spec FIXME: Also look at each object if result is a list [from RDF.rb implementation]
|
||||||
if Enum.any?(value, fn v -> Map.has_key?(v, "@list") end),
|
if Enum.any?(value, fn v -> Map.has_key?(v, "@list") end),
|
||||||
do: raise JSON.LD.ListOfListsError,
|
do:
|
||||||
message: "List of lists in #{inspect value}"
|
raise(JSON.LD.ListOfListsError,
|
||||||
|
message: "List of lists in #{inspect(value)}"
|
||||||
|
)
|
||||||
|
|
||||||
value
|
value
|
||||||
end
|
end
|
||||||
"@set" -> # 7.4.10)
|
|
||||||
|
# 7.4.10)
|
||||||
|
"@set" ->
|
||||||
do_expand(active_context, active_property, value, options)
|
do_expand(active_context, active_property, value, options)
|
||||||
"@reverse" -> # 7.4.11)
|
|
||||||
|
# 7.4.11)
|
||||||
|
"@reverse" ->
|
||||||
unless is_map(value),
|
unless is_map(value),
|
||||||
do: raise JSON.LD.InvalidReverseValueError,
|
do:
|
||||||
message: "#{inspect value} is not a valid @reverse value"
|
raise(JSON.LD.InvalidReverseValueError,
|
||||||
expanded_value = do_expand(active_context, "@reverse", value, options) # 7.4.11.1)
|
message: "#{inspect(value)} is not a valid @reverse value"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 7.4.11.1)
|
||||||
|
expanded_value = do_expand(active_context, "@reverse", value, options)
|
||||||
|
|
||||||
|
# 7.4.11.2) If expanded value contains an @reverse member, i.e., properties that are reversed twice, execute for each of its property and item the following steps:
|
||||||
new_result =
|
new_result =
|
||||||
if Map.has_key?(expanded_value, "@reverse") do # 7.4.11.2) If expanded value contains an @reverse member, i.e., properties that are reversed twice, execute for each of its property and item the following steps:
|
if Map.has_key?(expanded_value, "@reverse") do
|
||||||
Enum.reduce expanded_value["@reverse"], result,
|
Enum.reduce(expanded_value["@reverse"], result, fn {property, item},
|
||||||
fn ({property, item}, new_result) ->
|
new_result ->
|
||||||
items = if is_list(item),
|
items =
|
||||||
|
if is_list(item),
|
||||||
do: item,
|
do: item,
|
||||||
else: [item]
|
else: [item]
|
||||||
|
|
||||||
Map.update(new_result, property, items, fn members ->
|
Map.update(new_result, property, items, fn members ->
|
||||||
members ++ items
|
members ++ items
|
||||||
end)
|
end)
|
||||||
end
|
end)
|
||||||
else
|
else
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# 7.4.11.3)
|
||||||
new_result =
|
new_result =
|
||||||
if Map.keys(expanded_value) != ["@reverse"] do # 7.4.11.3)
|
if Map.keys(expanded_value) != ["@reverse"] do
|
||||||
reverse_map =
|
reverse_map =
|
||||||
Enum.reduce expanded_value, Map.get(new_result, "@reverse", %{}), fn
|
Enum.reduce(expanded_value, Map.get(new_result, "@reverse", %{}), fn
|
||||||
({property, items}, reverse_map) when property != "@reverse" ->
|
{property, items}, reverse_map when property != "@reverse" ->
|
||||||
Enum.each(items, fn item ->
|
Enum.each(items, fn item ->
|
||||||
if Map.has_key?(item, "@value") or Map.has_key?(item, "@list"),
|
if Map.has_key?(item, "@value") or Map.has_key?(item, "@list"),
|
||||||
do: raise JSON.LD.InvalidReversePropertyValueError,
|
do:
|
||||||
message: "invalid value for a reverse property in #{inspect item}"
|
raise(JSON.LD.InvalidReversePropertyValueError,
|
||||||
|
message:
|
||||||
|
"invalid value for a reverse property in #{inspect(item)}"
|
||||||
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
Map.update(reverse_map, property, items, fn members ->
|
Map.update(reverse_map, property, items, fn members ->
|
||||||
members ++ items
|
members ++ items
|
||||||
end)
|
end)
|
||||||
(_, reverse_map) -> reverse_map
|
|
||||||
end
|
_, reverse_map ->
|
||||||
|
reverse_map
|
||||||
|
end)
|
||||||
|
|
||||||
Map.put(new_result, "@reverse", reverse_map)
|
Map.put(new_result, "@reverse", reverse_map)
|
||||||
else
|
else
|
||||||
new_result
|
new_result
|
||||||
end
|
end
|
||||||
|
|
||||||
{:skip, new_result}
|
{:skip, new_result}
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# 7.4.12)
|
# 7.4.12)
|
||||||
case expanded_value do
|
case expanded_value do
|
||||||
nil ->
|
nil ->
|
||||||
result
|
result
|
||||||
|
|
||||||
{:skip, new_result} ->
|
{:skip, new_result} ->
|
||||||
new_result
|
new_result
|
||||||
|
|
||||||
expanded_value ->
|
expanded_value ->
|
||||||
Map.put(result, expanded_property, expanded_value)
|
Map.put(result, expanded_property, expanded_value)
|
||||||
end
|
end
|
||||||
|
else
|
||||||
else # expanded_property is not a keyword
|
|
||||||
term_def = active_context.term_defs[key]
|
term_def = active_context.term_defs[key]
|
||||||
expanded_value = cond do
|
|
||||||
|
expanded_value =
|
||||||
|
cond do
|
||||||
# 7.5) Otherwise, if key's container mapping in active context is @language and value is a JSON object then value is expanded from a language map as follows:
|
# 7.5) Otherwise, if key's container mapping in active context is @language and value is a JSON object then value is expanded from a language map as follows:
|
||||||
is_map(value) && term_def && term_def.container_mapping == "@language" ->
|
is_map(value) && term_def && term_def.container_mapping == "@language" ->
|
||||||
value
|
value
|
||||||
|> Enum.sort_by(fn {language, _} -> language end)
|
|> Enum.sort_by(fn {language, _} -> language end)
|
||||||
|> Enum.reduce([], fn ({language, language_value}, language_map_result) ->
|
|> Enum.reduce([], fn {language, language_value}, language_map_result ->
|
||||||
language_map_result ++ (
|
language_map_result ++
|
||||||
if(is_list(language_value),
|
(if(is_list(language_value),
|
||||||
do: language_value,
|
do: language_value,
|
||||||
else: [language_value])
|
else: [language_value]
|
||||||
|
)
|
||||||
|> Enum.map(fn
|
|> Enum.map(fn
|
||||||
item when is_binary(item) ->
|
item when is_binary(item) ->
|
||||||
%{
|
%{
|
||||||
"@value" => item,
|
"@value" => item,
|
||||||
"@language" => String.downcase(language)
|
"@language" => String.downcase(language)
|
||||||
}
|
}
|
||||||
|
|
||||||
item ->
|
item ->
|
||||||
raise JSON.LD.InvalidLanguageMapValueError,
|
raise JSON.LD.InvalidLanguageMapValueError,
|
||||||
message: "#{inspect item} is not a valid language map value"
|
message: "#{inspect(item)} is not a valid language map value"
|
||||||
|
end))
|
||||||
|
end)
|
||||||
|
|
||||||
end)
|
|
||||||
)
|
|
||||||
end)
|
|
||||||
# 7.6)
|
# 7.6)
|
||||||
is_map(value) && term_def && term_def.container_mapping == "@index" ->
|
is_map(value) && term_def && term_def.container_mapping == "@index" ->
|
||||||
value
|
value
|
||||||
|> Enum.sort_by(fn {index, _} -> index end)
|
|> Enum.sort_by(fn {index, _} -> index end)
|
||||||
|> Enum.reduce([], fn ({index, index_value}, index_map_result) ->
|
|> Enum.reduce([], fn {index, index_value}, index_map_result ->
|
||||||
index_map_result ++ (
|
index_map_result ++
|
||||||
index_value = if(is_list(index_value),
|
(
|
||||||
|
index_value =
|
||||||
|
if(is_list(index_value),
|
||||||
do: index_value,
|
do: index_value,
|
||||||
else: [index_value])
|
else: [index_value]
|
||||||
|
)
|
||||||
|
|
||||||
index_value = do_expand(active_context, key, index_value, options)
|
index_value = do_expand(active_context, key, index_value, options)
|
||||||
|
|
||||||
Enum.map(index_value, fn item ->
|
Enum.map(index_value, fn item ->
|
||||||
Map.put_new(item, "@index", index)
|
Map.put_new(item, "@index", index)
|
||||||
end)
|
end)
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
# 7.7)
|
# 7.7)
|
||||||
true ->
|
true ->
|
||||||
do_expand(active_context, key, value, options)
|
do_expand(active_context, key, value, options)
|
||||||
end
|
end
|
||||||
|
|
||||||
# 7.8)
|
# 7.8)
|
||||||
if is_nil(expanded_value) do
|
if is_nil(expanded_value) do
|
||||||
result
|
result
|
||||||
else
|
else
|
||||||
# 7.9)
|
# 7.9)
|
||||||
expanded_value =
|
expanded_value =
|
||||||
if (term_def && term_def.container_mapping == "@list") &&
|
if term_def && term_def.container_mapping == "@list" &&
|
||||||
!(is_map(expanded_value) && Map.has_key?(expanded_value, "@list")) do
|
!(is_map(expanded_value) && Map.has_key?(expanded_value, "@list")) do
|
||||||
%{"@list" =>
|
%{
|
||||||
(if is_list(expanded_value),
|
"@list" =>
|
||||||
|
if(is_list(expanded_value),
|
||||||
do: expanded_value,
|
do: expanded_value,
|
||||||
else: [expanded_value])}
|
else: [expanded_value]
|
||||||
|
)
|
||||||
|
}
|
||||||
else
|
else
|
||||||
expanded_value
|
expanded_value
|
||||||
end
|
end
|
||||||
|
|
||||||
# 7.10) Otherwise, if the term definition associated to key indicates that it is a reverse property
|
# 7.10) Otherwise, if the term definition associated to key indicates that it is a reverse property
|
||||||
# Spec FIXME: this is not an otherwise [from RDF.rb implementation]
|
# Spec FIXME: this is not an otherwise [from RDF.rb implementation]
|
||||||
|
# 7.11)
|
||||||
if term_def && term_def.reverse_property do
|
if term_def && term_def.reverse_property do
|
||||||
reverse_map = Map.get(result, "@reverse", %{})
|
reverse_map = Map.get(result, "@reverse", %{})
|
||||||
|
|
||||||
reverse_map =
|
reverse_map =
|
||||||
if(is_list(expanded_value),
|
if(is_list(expanded_value),
|
||||||
do: expanded_value,
|
do: expanded_value,
|
||||||
else: [expanded_value])
|
else: [expanded_value]
|
||||||
|> Enum.reduce(reverse_map, fn (item, reverse_map) ->
|
)
|
||||||
|
|> Enum.reduce(reverse_map, fn item, reverse_map ->
|
||||||
if Map.has_key?(item, "@value") or Map.has_key?(item, "@list"),
|
if Map.has_key?(item, "@value") or Map.has_key?(item, "@list"),
|
||||||
do: raise JSON.LD.InvalidReversePropertyValueError,
|
do:
|
||||||
message: "invalid value for a reverse property in #{inspect item}"
|
raise(JSON.LD.InvalidReversePropertyValueError,
|
||||||
Map.update reverse_map, expanded_property, [item], fn members ->
|
message: "invalid value for a reverse property in #{inspect(item)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
Map.update(reverse_map, expanded_property, [item], fn members ->
|
||||||
members ++ [item]
|
members ++ [item]
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
Map.put(result, "@reverse", reverse_map)
|
Map.put(result, "@reverse", reverse_map)
|
||||||
else # 7.11)
|
else
|
||||||
expanded_value = if is_list(expanded_value),
|
expanded_value =
|
||||||
|
if is_list(expanded_value),
|
||||||
do: expanded_value,
|
do: expanded_value,
|
||||||
else: [expanded_value]
|
else: [expanded_value]
|
||||||
Map.update result, expanded_property, expanded_value,
|
|
||||||
fn values -> expanded_value ++ values end
|
Map.update(result, expanded_property, expanded_value, fn values ->
|
||||||
|
expanded_value ++ values
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -300,90 +404,118 @@ defmodule JSON.LD.Expansion do
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
result = case result do
|
result =
|
||||||
|
case result do
|
||||||
# 8)
|
# 8)
|
||||||
%{"@value" => value} ->
|
%{"@value" => value} ->
|
||||||
with keys = Map.keys(result) do # 8.1)
|
# 8.1)
|
||||||
|
with keys = Map.keys(result) do
|
||||||
if Enum.any?(keys, &(&1 not in ~w[@value @language @type @index])) ||
|
if Enum.any?(keys, &(&1 not in ~w[@value @language @type @index])) ||
|
||||||
("@language" in keys and "@type" in keys) do
|
("@language" in keys and "@type" in keys) do
|
||||||
raise JSON.LD.InvalidValueObjectError,
|
raise JSON.LD.InvalidValueObjectError,
|
||||||
message: "value object with disallowed members"
|
message: "value object with disallowed members"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
value == nil -> nil # 8.2)
|
# 8.2)
|
||||||
!is_binary(value) and Map.has_key?(result, "@language") -> # 8.3)
|
value == nil ->
|
||||||
|
nil
|
||||||
|
|
||||||
|
# 8.3)
|
||||||
|
!is_binary(value) and Map.has_key?(result, "@language") ->
|
||||||
raise JSON.LD.InvalidLanguageTaggedValueError,
|
raise JSON.LD.InvalidLanguageTaggedValueError,
|
||||||
message: "@value '#{inspect value}' is tagged with a language"
|
message: "@value '#{inspect(value)}' is tagged with a language"
|
||||||
(type = result["@type"]) && !RDF.uri?(type) -> # 8.4)
|
|
||||||
|
# 8.4)
|
||||||
|
(type = result["@type"]) && !RDF.uri?(type) ->
|
||||||
raise JSON.LD.InvalidTypedValueError,
|
raise JSON.LD.InvalidTypedValueError,
|
||||||
message: "@value '#{inspect value}' has invalid type #{inspect type}"
|
message: "@value '#{inspect(value)}' has invalid type #{inspect(type)}"
|
||||||
true -> result
|
|
||||||
|
true ->
|
||||||
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
# 9)
|
# 9)
|
||||||
%{"@type" => type} when not is_list(type) ->
|
%{"@type" => type} when not is_list(type) ->
|
||||||
Map.put(result, "@type", [type])
|
Map.put(result, "@type", [type])
|
||||||
|
|
||||||
# 10)
|
# 10)
|
||||||
%{"@set" => set} ->
|
%{"@set" => set} ->
|
||||||
validate_set_or_list_object(result)
|
validate_set_or_list_object(result)
|
||||||
set
|
set
|
||||||
|
|
||||||
%{"@list" => _} ->
|
%{"@list" => _} ->
|
||||||
validate_set_or_list_object(result)
|
validate_set_or_list_object(result)
|
||||||
result
|
result
|
||||||
_ -> result
|
|
||||||
|
_ ->
|
||||||
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
# 11) If result contains only the key @language, set result to null.
|
# 11) If result contains only the key @language, set result to null.
|
||||||
result = if is_map(result) and map_size(result) == 1 and Map.has_key?(result, "@language"),
|
result =
|
||||||
do: nil, else: result
|
if is_map(result) and map_size(result) == 1 and Map.has_key?(result, "@language"),
|
||||||
|
do: nil,
|
||||||
|
else: result
|
||||||
|
|
||||||
# 12) If active property is null or @graph, drop free-floating values as follows:
|
# 12) If active property is null or @graph, drop free-floating values as follows:
|
||||||
# Spec FIXME: Due to case 10) we might land with a list here; other implementations deal with that, by just returning in step 10)
|
# Spec FIXME: Due to case 10) we might land with a list here; other implementations deal with that, by just returning in step 10)
|
||||||
result = if is_map(result) and active_property in [nil, "@graph"] and (
|
result =
|
||||||
Enum.empty?(result) or
|
if is_map(result) and active_property in [nil, "@graph"] and
|
||||||
|
(Enum.empty?(result) or
|
||||||
Map.has_key?(result, "@value") or Map.has_key?(result, "@list") or
|
Map.has_key?(result, "@value") or Map.has_key?(result, "@list") or
|
||||||
(map_size(result) == 1 and Map.has_key?(result, "@id"))),
|
(map_size(result) == 1 and Map.has_key?(result, "@id"))),
|
||||||
do: nil, else: result
|
do: nil,
|
||||||
|
else: result
|
||||||
|
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
defp validate_set_or_list_object(object) when map_size(object) == 1, do: true
|
defp validate_set_or_list_object(object) when map_size(object) == 1, do: true
|
||||||
|
|
||||||
defp validate_set_or_list_object(object = %{"@index" => _})
|
defp validate_set_or_list_object(object = %{"@index" => _})
|
||||||
when map_size(object) == 2, do: true
|
when map_size(object) == 2,
|
||||||
|
do: true
|
||||||
|
|
||||||
defp validate_set_or_list_object(object) do
|
defp validate_set_or_list_object(object) do
|
||||||
raise JSON.LD.InvalidSetOrListObjectError,
|
raise JSON.LD.InvalidSetOrListObjectError,
|
||||||
message: "set or list object with disallowed members: #{inspect object}"
|
message: "set or list object with disallowed members: #{inspect(object)}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Details at <http://json-ld.org/spec/latest/json-ld-api/#value-expansion>
|
Details at <http://json-ld.org/spec/latest/json-ld-api/#value-expansion>
|
||||||
"""
|
"""
|
||||||
def expand_value(active_context, active_property, value) do
|
def expand_value(active_context, active_property, value) do
|
||||||
with term_def = Map.get(active_context.term_defs, active_property,
|
with term_def =
|
||||||
%JSON.LD.Context.TermDefinition{}) do
|
Map.get(active_context.term_defs, active_property, %JSON.LD.Context.TermDefinition{}) do
|
||||||
cond do
|
cond do
|
||||||
term_def.type_mapping == "@id" ->
|
term_def.type_mapping == "@id" ->
|
||||||
%{"@id" => expand_iri(value, active_context, true, false)}
|
%{"@id" => expand_iri(value, active_context, true, false)}
|
||||||
|
|
||||||
term_def.type_mapping == "@vocab" ->
|
term_def.type_mapping == "@vocab" ->
|
||||||
%{"@id" => expand_iri(value, active_context, true, true)}
|
%{"@id" => expand_iri(value, active_context, true, true)}
|
||||||
|
|
||||||
type_mapping = term_def.type_mapping ->
|
type_mapping = term_def.type_mapping ->
|
||||||
%{"@value" => value, "@type" => type_mapping}
|
%{"@value" => value, "@type" => type_mapping}
|
||||||
|
|
||||||
is_binary(value) ->
|
is_binary(value) ->
|
||||||
language_mapping = term_def.language_mapping
|
language_mapping = term_def.language_mapping
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
language_mapping ->
|
language_mapping ->
|
||||||
%{"@value" => value, "@language" => language_mapping}
|
%{"@value" => value, "@language" => language_mapping}
|
||||||
|
|
||||||
language_mapping == false && active_context.default_language ->
|
language_mapping == false && active_context.default_language ->
|
||||||
%{"@value" => value, "@language" => active_context.default_language}
|
%{"@value" => value, "@language" => active_context.default_language}
|
||||||
|
|
||||||
true ->
|
true ->
|
||||||
%{"@value" => value}
|
%{"@value" => value}
|
||||||
end
|
end
|
||||||
true ->
|
|
||||||
%{"@value" => value}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
true ->
|
||||||
|
%{"@value" => value}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,16 +4,16 @@ defmodule JSON.LD.Flattening do
|
||||||
import JSON.LD.{NodeIdentifierMap, Utils}
|
import JSON.LD.{NodeIdentifierMap, Utils}
|
||||||
alias JSON.LD.NodeIdentifierMap
|
alias JSON.LD.NodeIdentifierMap
|
||||||
|
|
||||||
|
|
||||||
def flatten(input, context \\ nil, options \\ %JSON.LD.Options{}) do
|
def flatten(input, context \\ nil, options \\ %JSON.LD.Options{}) do
|
||||||
with options = JSON.LD.Options.new(options),
|
with options = JSON.LD.Options.new(options),
|
||||||
expanded = JSON.LD.expand(input, options),
|
expanded = JSON.LD.expand(input, options),
|
||||||
node_map = node_map(expanded)
|
node_map = node_map(expanded) do
|
||||||
do
|
|
||||||
default_graph =
|
default_graph =
|
||||||
Enum.reduce node_map, node_map["@default"], fn
|
Enum.reduce(node_map, node_map["@default"], fn
|
||||||
({"@default", _}, default_graph) -> default_graph
|
{"@default", _}, default_graph ->
|
||||||
({graph_name, graph}, default_graph) ->
|
default_graph
|
||||||
|
|
||||||
|
{graph_name, graph}, default_graph ->
|
||||||
entry =
|
entry =
|
||||||
if Map.has_key?(default_graph, graph_name) do
|
if Map.has_key?(default_graph, graph_name) do
|
||||||
default_graph[graph_name]
|
default_graph[graph_name]
|
||||||
|
@ -24,31 +24,32 @@ defmodule JSON.LD.Flattening do
|
||||||
graph_entry =
|
graph_entry =
|
||||||
graph
|
graph
|
||||||
|> Stream.reject(fn {_, node} ->
|
|> Stream.reject(fn {_, node} ->
|
||||||
Map.has_key?(node, "@id") and map_size(node) == 1 end)
|
Map.has_key?(node, "@id") and map_size(node) == 1
|
||||||
|
end)
|
||||||
|> Enum.sort_by(fn {id, _} -> id end)
|
|> Enum.sort_by(fn {id, _} -> id end)
|
||||||
# TODO: Spec fixme: Spec doesn't handle the case, when a "@graph" member already exists
|
# TODO: Spec fixme: Spec doesn't handle the case, when a "@graph" member already exists
|
||||||
|> Enum.reduce(Map.get(entry, "@graph", []), fn ({_, node}, graph_entry) ->
|
|> Enum.reduce(Map.get(entry, "@graph", []), fn {_, node}, graph_entry ->
|
||||||
[node | graph_entry]
|
[node | graph_entry]
|
||||||
end)
|
end)
|
||||||
|> Enum.reverse
|
|> Enum.reverse()
|
||||||
|
|
||||||
Map.put(default_graph, graph_name,
|
Map.put(default_graph, graph_name, Map.put(entry, "@graph", graph_entry))
|
||||||
Map.put(entry, "@graph", graph_entry))
|
end)
|
||||||
end
|
|
||||||
|
|
||||||
flattened =
|
flattened =
|
||||||
default_graph
|
default_graph
|
||||||
|> Enum.sort_by(fn {id, _} -> id end)
|
|> Enum.sort_by(fn {id, _} -> id end)
|
||||||
|> Enum.reduce([], fn ({_, node}, flattened) ->
|
|> Enum.reduce([], fn {_, node}, flattened ->
|
||||||
if not (Enum.count(node) == 1 and Map.has_key?(node, "@id")) do
|
if not (Enum.count(node) == 1 and Map.has_key?(node, "@id")) do
|
||||||
[node | flattened]
|
[node | flattened]
|
||||||
else
|
else
|
||||||
flattened
|
flattened
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|> Enum.reverse
|
|> Enum.reverse()
|
||||||
|
|
||||||
if context && !Enum.empty?(flattened) do # TODO: Spec fixme: !Enum.empty?(flattened) is not in the spec, but in other implementations (Ruby, Java, Go, ...)
|
# TODO: Spec fixme: !Enum.empty?(flattened) is not in the spec, but in other implementations (Ruby, Java, Go, ...)
|
||||||
|
if context && !Enum.empty?(flattened) do
|
||||||
JSON.LD.compact(flattened, context, options)
|
JSON.LD.compact(flattened, context, options)
|
||||||
else
|
else
|
||||||
flattened
|
flattened
|
||||||
|
@ -59,7 +60,8 @@ defmodule JSON.LD.Flattening do
|
||||||
def node_map(input, node_id_map \\ nil)
|
def node_map(input, node_id_map \\ nil)
|
||||||
|
|
||||||
def node_map(input, nil) do
|
def node_map(input, nil) do
|
||||||
{:ok, node_id_map} = NodeIdentifierMap.start_link
|
{:ok, node_id_map} = NodeIdentifierMap.start_link()
|
||||||
|
|
||||||
try do
|
try do
|
||||||
node_map(input, node_id_map)
|
node_map(input, node_id_map)
|
||||||
after
|
after
|
||||||
|
@ -76,30 +78,59 @@ defmodule JSON.LD.Flattening do
|
||||||
|
|
||||||
Details at <https://www.w3.org/TR/json-ld-api/#node-map-generation>
|
Details at <https://www.w3.org/TR/json-ld-api/#node-map-generation>
|
||||||
"""
|
"""
|
||||||
def generate_node_map(element, node_map, node_id_map, active_graph \\ "@default",
|
def generate_node_map(
|
||||||
active_subject \\ nil, active_property \\ nil, list \\ nil)
|
element,
|
||||||
|
node_map,
|
||||||
|
node_id_map,
|
||||||
|
active_graph \\ "@default",
|
||||||
|
active_subject \\ nil,
|
||||||
|
active_property \\ nil,
|
||||||
|
list \\ nil
|
||||||
|
)
|
||||||
|
|
||||||
# 1)
|
# 1)
|
||||||
def generate_node_map(element, node_map, node_id_map, active_graph, active_subject,
|
def generate_node_map(
|
||||||
active_property, list) when is_list(element) do
|
element,
|
||||||
Enum.reduce element, node_map, fn (item, node_map) ->
|
node_map,
|
||||||
generate_node_map(item, node_map, node_id_map, active_graph, active_subject,
|
node_id_map,
|
||||||
active_property, list)
|
active_graph,
|
||||||
|
active_subject,
|
||||||
|
active_property,
|
||||||
|
list
|
||||||
|
)
|
||||||
|
when is_list(element) do
|
||||||
|
Enum.reduce(element, node_map, fn item, node_map ->
|
||||||
|
generate_node_map(
|
||||||
|
item,
|
||||||
|
node_map,
|
||||||
|
node_id_map,
|
||||||
|
active_graph,
|
||||||
|
active_subject,
|
||||||
|
active_property,
|
||||||
|
list
|
||||||
|
)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
# 2)
|
# 2)
|
||||||
def generate_node_map(element, node_map, node_id_map, active_graph, active_subject,
|
def generate_node_map(
|
||||||
active_property, list) when is_map(element) do
|
element,
|
||||||
|
node_map,
|
||||||
|
node_id_map,
|
||||||
|
active_graph,
|
||||||
|
active_subject,
|
||||||
|
active_property,
|
||||||
|
list
|
||||||
|
)
|
||||||
|
when is_map(element) do
|
||||||
node_map = Map.put_new(node_map, active_graph, %{})
|
node_map = Map.put_new(node_map, active_graph, %{})
|
||||||
node = node_map[active_graph][active_subject]
|
node = node_map[active_graph][active_subject]
|
||||||
|
|
||||||
# 3)
|
# 3)
|
||||||
element =
|
element =
|
||||||
if old_types = Map.get(element, "@type") do
|
if old_types = Map.get(element, "@type") do
|
||||||
new_types = Enum.reduce(List.wrap(old_types), [],
|
new_types =
|
||||||
fn (item, types) ->
|
Enum.reduce(List.wrap(old_types), [], fn item, types ->
|
||||||
if blank_node_id?(item) do
|
if blank_node_id?(item) do
|
||||||
identifier = generate_blank_node_id(node_id_map, item)
|
identifier = generate_blank_node_id(node_id_map, item)
|
||||||
types ++ [identifier]
|
types ++ [identifier]
|
||||||
|
@ -107,20 +138,25 @@ defmodule JSON.LD.Flattening do
|
||||||
types ++ [item]
|
types ++ [item]
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
Map.put(element, "@type",
|
|
||||||
if(is_list(old_types), do: new_types, else: List.first(new_types)))
|
Map.put(
|
||||||
|
element,
|
||||||
|
"@type",
|
||||||
|
if(is_list(old_types), do: new_types, else: List.first(new_types))
|
||||||
|
)
|
||||||
else
|
else
|
||||||
element
|
element
|
||||||
end
|
end
|
||||||
|
|
||||||
cond do
|
cond do
|
||||||
|
|
||||||
# 4)
|
# 4)
|
||||||
Map.has_key?(element, "@value") ->
|
Map.has_key?(element, "@value") ->
|
||||||
if is_nil(list) do
|
if is_nil(list) do
|
||||||
if node do
|
if node do
|
||||||
update_in(node_map, [active_graph, active_subject, active_property], fn
|
update_in(node_map, [active_graph, active_subject, active_property], fn
|
||||||
nil -> [element]
|
nil ->
|
||||||
|
[element]
|
||||||
|
|
||||||
items ->
|
items ->
|
||||||
unless element in items,
|
unless element in items,
|
||||||
do: items ++ [element],
|
do: items ++ [element],
|
||||||
|
@ -137,16 +173,25 @@ defmodule JSON.LD.Flattening do
|
||||||
# 5)
|
# 5)
|
||||||
Map.has_key?(element, "@list") ->
|
Map.has_key?(element, "@list") ->
|
||||||
{:ok, result_list} = new_list()
|
{:ok, result_list} = new_list()
|
||||||
|
|
||||||
{node_map, result} =
|
{node_map, result} =
|
||||||
try do
|
try do
|
||||||
{
|
{
|
||||||
generate_node_map(element["@list"], node_map, node_id_map,
|
generate_node_map(
|
||||||
active_graph, active_subject, active_property, result_list),
|
element["@list"],
|
||||||
|
node_map,
|
||||||
|
node_id_map,
|
||||||
|
active_graph,
|
||||||
|
active_subject,
|
||||||
|
active_property,
|
||||||
|
result_list
|
||||||
|
),
|
||||||
get_list(result_list)
|
get_list(result_list)
|
||||||
}
|
}
|
||||||
after
|
after
|
||||||
terminate_list(result_list)
|
terminate_list(result_list)
|
||||||
end
|
end
|
||||||
|
|
||||||
if node do
|
if node do
|
||||||
update_in(node_map, [active_graph, active_subject, active_property], fn
|
update_in(node_map, [active_graph, active_subject, active_property], fn
|
||||||
nil -> [result]
|
nil -> [result]
|
||||||
|
@ -160,6 +205,7 @@ defmodule JSON.LD.Flattening do
|
||||||
true ->
|
true ->
|
||||||
# 6.1)
|
# 6.1)
|
||||||
{id, element} = Map.pop(element, "@id")
|
{id, element} = Map.pop(element, "@id")
|
||||||
|
|
||||||
id =
|
id =
|
||||||
if id do
|
if id do
|
||||||
if blank_node_id?(id) do
|
if blank_node_id?(id) do
|
||||||
|
@ -167,6 +213,7 @@ defmodule JSON.LD.Flattening do
|
||||||
else
|
else
|
||||||
id
|
id
|
||||||
end
|
end
|
||||||
|
|
||||||
# 6.2)
|
# 6.2)
|
||||||
else
|
else
|
||||||
generate_blank_node_id(node_id_map)
|
generate_blank_node_id(node_id_map)
|
||||||
|
@ -190,7 +237,9 @@ defmodule JSON.LD.Flattening do
|
||||||
if is_map(active_subject) do
|
if is_map(active_subject) do
|
||||||
unless Map.has_key?(node, active_property) do
|
unless Map.has_key?(node, active_property) do
|
||||||
update_in(node_map, [active_graph, id, active_property], fn
|
update_in(node_map, [active_graph, id, active_property], fn
|
||||||
nil -> [active_subject]
|
nil ->
|
||||||
|
[active_subject]
|
||||||
|
|
||||||
items ->
|
items ->
|
||||||
unless active_subject in items,
|
unless active_subject in items,
|
||||||
do: items ++ [active_subject],
|
do: items ++ [active_subject],
|
||||||
|
@ -199,18 +248,23 @@ defmodule JSON.LD.Flattening do
|
||||||
else
|
else
|
||||||
node_map
|
node_map
|
||||||
end
|
end
|
||||||
|
|
||||||
# 6.6)
|
# 6.6)
|
||||||
else
|
else
|
||||||
unless is_nil(active_property) do
|
unless is_nil(active_property) do
|
||||||
reference = %{"@id" => id}
|
reference = %{"@id" => id}
|
||||||
|
|
||||||
if is_nil(list) do
|
if is_nil(list) do
|
||||||
update_in(node_map, [active_graph, active_subject, active_property], fn
|
update_in(node_map, [active_graph, active_subject, active_property], fn
|
||||||
nil -> [reference]
|
nil ->
|
||||||
|
[reference]
|
||||||
|
|
||||||
items ->
|
items ->
|
||||||
unless reference in items,
|
unless reference in items,
|
||||||
do: items ++ [reference],
|
do: items ++ [reference],
|
||||||
else: items
|
else: items
|
||||||
end)
|
end)
|
||||||
|
|
||||||
# 6.6.3) TODO: Spec fixme: specs says to add ELEMENT to @list member, should be REFERENCE
|
# 6.6.3) TODO: Spec fixme: specs says to add ELEMENT to @list member, should be REFERENCE
|
||||||
else
|
else
|
||||||
append_to_list(list, reference)
|
append_to_list(list, reference)
|
||||||
|
@ -225,15 +279,18 @@ defmodule JSON.LD.Flattening do
|
||||||
{node_map, element} =
|
{node_map, element} =
|
||||||
if Map.has_key?(element, "@type") do
|
if Map.has_key?(element, "@type") do
|
||||||
node_map =
|
node_map =
|
||||||
Enum.reduce element["@type"], node_map, fn (type, node_map) ->
|
Enum.reduce(element["@type"], node_map, fn type, node_map ->
|
||||||
update_in(node_map, [active_graph, id, "@type"], fn
|
update_in(node_map, [active_graph, id, "@type"], fn
|
||||||
nil -> [type]
|
nil ->
|
||||||
|
[type]
|
||||||
|
|
||||||
items ->
|
items ->
|
||||||
unless type in items,
|
unless type in items,
|
||||||
do: items ++ [type],
|
do: items ++ [type],
|
||||||
else: items
|
else: items
|
||||||
end)
|
end)
|
||||||
end
|
end)
|
||||||
|
|
||||||
element = Map.delete(element, "@type")
|
element = Map.delete(element, "@type")
|
||||||
{node_map, element}
|
{node_map, element}
|
||||||
else
|
else
|
||||||
|
@ -244,6 +301,7 @@ defmodule JSON.LD.Flattening do
|
||||||
{node_map, element} =
|
{node_map, element} =
|
||||||
if Map.has_key?(element, "@index") do
|
if Map.has_key?(element, "@index") do
|
||||||
{element_index, element} = Map.pop(element, "@index")
|
{element_index, element} = Map.pop(element, "@index")
|
||||||
|
|
||||||
node_map =
|
node_map =
|
||||||
if node_index = get_in(node_map, [active_graph, id, "@index"]) do
|
if node_index = get_in(node_map, [active_graph, id, "@index"]) do
|
||||||
if not deep_compare(node_index, element_index) do
|
if not deep_compare(node_index, element_index) do
|
||||||
|
@ -251,10 +309,11 @@ defmodule JSON.LD.Flattening do
|
||||||
message: "Multiple conflicting indexes have been found for the same node."
|
message: "Multiple conflicting indexes have been found for the same node."
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
update_in node_map, [active_graph, id], fn node ->
|
update_in(node_map, [active_graph, id], fn node ->
|
||||||
Map.put(node, "@index", element_index)
|
Map.put(node, "@index", element_index)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
|
||||||
{node_map, element}
|
{node_map, element}
|
||||||
else
|
else
|
||||||
{node_map, element}
|
{node_map, element}
|
||||||
|
@ -265,12 +324,21 @@ defmodule JSON.LD.Flattening do
|
||||||
if Map.has_key?(element, "@reverse") do
|
if Map.has_key?(element, "@reverse") do
|
||||||
referenced_node = %{"@id" => id}
|
referenced_node = %{"@id" => id}
|
||||||
{reverse_map, element} = Map.pop(element, "@reverse")
|
{reverse_map, element} = Map.pop(element, "@reverse")
|
||||||
node_map = Enum.reduce reverse_map, node_map, fn ({property, values}, node_map) ->
|
|
||||||
Enum.reduce values, node_map, fn (value, node_map) ->
|
node_map =
|
||||||
generate_node_map(value, node_map, node_id_map, active_graph,
|
Enum.reduce(reverse_map, node_map, fn {property, values}, node_map ->
|
||||||
referenced_node, property)
|
Enum.reduce(values, node_map, fn value, node_map ->
|
||||||
end
|
generate_node_map(
|
||||||
end
|
value,
|
||||||
|
node_map,
|
||||||
|
node_id_map,
|
||||||
|
active_graph,
|
||||||
|
referenced_node,
|
||||||
|
property
|
||||||
|
)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
{node_map, element}
|
{node_map, element}
|
||||||
else
|
else
|
||||||
{node_map, element}
|
{node_map, element}
|
||||||
|
@ -288,21 +356,23 @@ defmodule JSON.LD.Flattening do
|
||||||
# 6.11)
|
# 6.11)
|
||||||
element
|
element
|
||||||
|> Enum.sort_by(fn {property, _} -> property end)
|
|> Enum.sort_by(fn {property, _} -> property end)
|
||||||
|> Enum.reduce(node_map, fn ({property, value}, node_map) ->
|
|> Enum.reduce(node_map, fn {property, value}, node_map ->
|
||||||
property =
|
property =
|
||||||
if blank_node_id?(property) do
|
if blank_node_id?(property) do
|
||||||
generate_blank_node_id(node_id_map, property)
|
generate_blank_node_id(node_id_map, property)
|
||||||
else
|
else
|
||||||
property
|
property
|
||||||
end
|
end
|
||||||
|
|
||||||
node_map =
|
node_map =
|
||||||
unless Map.has_key?(node_map[active_graph][id], property) do
|
unless Map.has_key?(node_map[active_graph][id], property) do
|
||||||
update_in node_map, [active_graph, id], fn node ->
|
update_in(node_map, [active_graph, id], fn node ->
|
||||||
Map.put(node, property, [])
|
Map.put(node, property, [])
|
||||||
end
|
end)
|
||||||
else
|
else
|
||||||
node_map
|
node_map
|
||||||
end
|
end
|
||||||
|
|
||||||
generate_node_map(value, node_map, node_id_map, active_graph, id, property)
|
generate_node_map(value, node_map, node_id_map, active_graph, id, property)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -314,29 +384,29 @@ defmodule JSON.LD.Flattening do
|
||||||
Map.has_key?(v2, k) && deep_compare(v, v2[k])
|
Map.has_key?(v2, k) && deep_compare(v, v2[k])
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp deep_compare(v1, v2) when is_list(v1) and is_list(v2) do
|
defp deep_compare(v1, v2) when is_list(v1) and is_list(v2) do
|
||||||
Enum.count(v1) == Enum.count(v2) && MapSet.new(v1) == MapSet.new(v2)
|
Enum.count(v1) == Enum.count(v2) && MapSet.new(v1) == MapSet.new(v2)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp deep_compare(v, v), do: true
|
defp deep_compare(v, v), do: true
|
||||||
defp deep_compare(_, _), do: false
|
defp deep_compare(_, _), do: false
|
||||||
|
|
||||||
|
|
||||||
defp new_list do
|
defp new_list do
|
||||||
Agent.start_link fn -> %{"@list" => []} end
|
Agent.start_link(fn -> %{"@list" => []} end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp terminate_list(pid) do
|
defp terminate_list(pid) do
|
||||||
Agent.stop pid
|
Agent.stop(pid)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_list(pid) do
|
defp get_list(pid) do
|
||||||
Agent.get pid, fn list_node -> list_node end
|
Agent.get(pid, fn list_node -> list_node end)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp append_to_list(pid, element) do
|
defp append_to_list(pid, element) do
|
||||||
Agent.update pid, fn list_node ->
|
Agent.update(pid, fn list_node ->
|
||||||
Map.update(list_node, "@list", [element], fn list -> list ++ [element] end)
|
Map.update(list_node, "@list", [element], fn list -> list ++ [element] end)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
defmodule JSON.LD.IRIExpansion do
|
defmodule JSON.LD.IRIExpansion do
|
||||||
|
|
||||||
import JSON.LD.Utils
|
import JSON.LD.Utils
|
||||||
|
|
||||||
@keywords JSON.LD.keywords # to allow this to be used in function guard clauses, we redefine this here
|
# to allow this to be used in function guard clauses, we redefine this here
|
||||||
|
@keywords JSON.LD.keywords()
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
see http://json-ld.org/spec/latest/json-ld-api/#iri-expansion
|
see http://json-ld.org/spec/latest/json-ld-api/#iri-expansion
|
||||||
"""
|
"""
|
||||||
def expand_iri(value, active_context, doc_relative \\ false, vocab \\ false,
|
def expand_iri(
|
||||||
local_context \\ nil, defined \\ nil)
|
value,
|
||||||
|
active_context,
|
||||||
|
doc_relative \\ false,
|
||||||
|
vocab \\ false,
|
||||||
|
local_context \\ nil,
|
||||||
|
defined \\ nil
|
||||||
|
)
|
||||||
|
|
||||||
# 1) If value is a keyword or null, return value as is.
|
# 1) If value is a keyword or null, return value as is.
|
||||||
def expand_iri(value, active_context, _, _, local_context, defined)
|
def expand_iri(value, active_context, _, _, local_context, defined)
|
||||||
|
@ -25,8 +31,14 @@ defmodule JSON.LD.IRIExpansion do
|
||||||
{active_context, defined} =
|
{active_context, defined} =
|
||||||
if local_context && local_context[value] && defined[value] != true do
|
if local_context && local_context[value] && defined[value] != true do
|
||||||
local_def = local_context[value]
|
local_def = local_context[value]
|
||||||
|
|
||||||
JSON.LD.Context.create_term_definition(
|
JSON.LD.Context.create_term_definition(
|
||||||
active_context, local_context, value, local_def, defined)
|
active_context,
|
||||||
|
local_context,
|
||||||
|
value,
|
||||||
|
local_def,
|
||||||
|
defined
|
||||||
|
)
|
||||||
else
|
else
|
||||||
{active_context, defined}
|
{active_context, defined}
|
||||||
end
|
end
|
||||||
|
@ -37,6 +49,7 @@ defmodule JSON.LD.IRIExpansion do
|
||||||
vocab && Map.has_key?(active_context.term_defs, value) ->
|
vocab && Map.has_key?(active_context.term_defs, value) ->
|
||||||
result = (term_def = active_context.term_defs[value]) && term_def.iri_mapping
|
result = (term_def = active_context.term_defs[value]) && term_def.iri_mapping
|
||||||
{result, active_context, defined}
|
{result, active_context, defined}
|
||||||
|
|
||||||
# 4) If value contains a colon (:), it is either an absolute IRI, a compact IRI, or a blank node identifier
|
# 4) If value contains a colon (:), it is either an absolute IRI, a compact IRI, or a blank node identifier
|
||||||
String.contains?(value, ":") ->
|
String.contains?(value, ":") ->
|
||||||
case compact_iri_parts(value) do
|
case compact_iri_parts(value) do
|
||||||
|
@ -45,29 +58,43 @@ defmodule JSON.LD.IRIExpansion do
|
||||||
{active_context, defined} =
|
{active_context, defined} =
|
||||||
if local_context && local_context[prefix] && defined[prefix] != true do
|
if local_context && local_context[prefix] && defined[prefix] != true do
|
||||||
local_def = local_context[prefix]
|
local_def = local_context[prefix]
|
||||||
|
|
||||||
JSON.LD.Context.create_term_definition(
|
JSON.LD.Context.create_term_definition(
|
||||||
active_context, local_context, prefix, local_def, defined)
|
active_context,
|
||||||
|
local_context,
|
||||||
|
prefix,
|
||||||
|
local_def,
|
||||||
|
defined
|
||||||
|
)
|
||||||
else
|
else
|
||||||
{active_context, defined}
|
{active_context, defined}
|
||||||
end
|
end
|
||||||
|
|
||||||
# 4.4)
|
# 4.4)
|
||||||
result =
|
result =
|
||||||
if prefix_def = active_context.term_defs[prefix] do
|
if prefix_def = active_context.term_defs[prefix] do
|
||||||
prefix_def.iri_mapping <> suffix
|
prefix_def.iri_mapping <> suffix
|
||||||
else
|
else
|
||||||
value # 4.5)
|
# 4.5)
|
||||||
|
value
|
||||||
end
|
end
|
||||||
|
|
||||||
{result, active_context, defined}
|
{result, active_context, defined}
|
||||||
|
|
||||||
nil ->
|
nil ->
|
||||||
{value, active_context, defined} # 4.2)
|
# 4.2)
|
||||||
|
{value, active_context, defined}
|
||||||
end
|
end
|
||||||
|
|
||||||
# 5) If vocab is true, and active context has a vocabulary mapping, return the result of concatenating the vocabulary mapping with value.
|
# 5) If vocab is true, and active context has a vocabulary mapping, return the result of concatenating the vocabulary mapping with value.
|
||||||
vocab && active_context.vocab ->
|
vocab && active_context.vocab ->
|
||||||
vocabulary_mapping = active_context.vocab
|
vocabulary_mapping = active_context.vocab
|
||||||
{vocabulary_mapping <> value, active_context, defined}
|
{vocabulary_mapping <> value, active_context, defined}
|
||||||
|
|
||||||
# 6) Otherwise, if document relative is true, set value to the result of resolving value against the base IRI. Only the basic algorithm in section 5.2 of [RFC3986] is used; neither Syntax-Based Normalization nor Scheme-Based Normalization are performed. Characters additionally allowed in IRI references are treated in the same way that unreserved characters are treated in URI references, per section 6.5 of [RFC3987].
|
# 6) Otherwise, if document relative is true, set value to the result of resolving value against the base IRI. Only the basic algorithm in section 5.2 of [RFC3986] is used; neither Syntax-Based Normalization nor Scheme-Based Normalization are performed. Characters additionally allowed in IRI references are treated in the same way that unreserved characters are treated in URI references, per section 6.5 of [RFC3987].
|
||||||
doc_relative ->
|
doc_relative ->
|
||||||
{absolute_iri(value, JSON.LD.Context.base(active_context)), active_context, defined}
|
{absolute_iri(value, JSON.LD.Context.base(active_context)), active_context, defined}
|
||||||
|
|
||||||
# TODO: RDF.rb's implementation differs from the spec here, by checking if base_iri is actually present in the previous clause and adding the following additional clause. Another Spec error?
|
# TODO: RDF.rb's implementation differs from the spec here, by checking if base_iri is actually present in the previous clause and adding the following additional clause. Another Spec error?
|
||||||
# if local_context && RDF::URI(value).relative?
|
# if local_context && RDF::URI(value).relative?
|
||||||
# # If local context is not null and value is not an absolute IRI, an invalid IRI mapping error has been detected and processing is aborted.
|
# # If local context is not null and value is not an absolute IRI, an invalid IRI mapping error has been detected and processing is aborted.
|
||||||
|
@ -83,5 +110,4 @@ defmodule JSON.LD.IRIExpansion do
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,7 +22,6 @@ defmodule JSON.LD.NodeIdentifierMap do
|
||||||
GenServer.call(pid, {:generate_id, identifier})
|
GenServer.call(pid, {:generate_id, identifier})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Server Callbacks
|
# Server Callbacks
|
||||||
|
|
||||||
def init(:ok) do
|
def init(:ok) do
|
||||||
|
@ -34,7 +33,9 @@ defmodule JSON.LD.NodeIdentifierMap do
|
||||||
{:reply, map[identifier], state}
|
{:reply, map[identifier], state}
|
||||||
else
|
else
|
||||||
blank_node_id = "_:b#{counter}"
|
blank_node_id = "_:b#{counter}"
|
||||||
{:reply, blank_node_id, %{
|
|
||||||
|
{:reply, blank_node_id,
|
||||||
|
%{
|
||||||
counter: counter + 1,
|
counter: counter + 1,
|
||||||
map:
|
map:
|
||||||
if identifier do
|
if identifier do
|
||||||
|
@ -45,5 +46,4 @@ defmodule JSON.LD.NodeIdentifierMap do
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,5 +17,4 @@ defmodule JSON.LD.Options do
|
||||||
def new(), do: %JSON.LD.Options{}
|
def new(), do: %JSON.LD.Options{}
|
||||||
def new(%JSON.LD.Options{} = options), do: options
|
def new(%JSON.LD.Options{} = options), do: options
|
||||||
def new(options), do: struct(JSON.LD.Options, options)
|
def new(options), do: struct(JSON.LD.Options, options)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defmodule JSON.LD.Utils do
|
defmodule JSON.LD.Utils do
|
||||||
|
|
||||||
alias RDF.IRI
|
alias RDF.IRI
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
|
@ -16,16 +15,16 @@ defmodule JSON.LD.Utils do
|
||||||
|
|
||||||
def absolute_iri(value, nil),
|
def absolute_iri(value, nil),
|
||||||
do: value
|
do: value
|
||||||
|
|
||||||
def absolute_iri(value, base_iri),
|
def absolute_iri(value, base_iri),
|
||||||
do: value |> RDF.IRI.absolute(base_iri) |> to_string
|
do: value |> RDF.IRI.absolute(base_iri) |> to_string
|
||||||
|
|
||||||
|
|
||||||
def relative_iri?(value),
|
def relative_iri?(value),
|
||||||
do: not (JSON.LD.keyword?(value) or IRI.absolute?(value) or blank_node_id?(value))
|
do: not (JSON.LD.keyword?(value) or IRI.absolute?(value) or blank_node_id?(value))
|
||||||
|
|
||||||
def compact_iri_parts(compact_iri, exclude_bnode \\ true) do
|
def compact_iri_parts(compact_iri, exclude_bnode \\ true) do
|
||||||
with [prefix, suffix] <- String.split(compact_iri, ":", parts: 2) do
|
with [prefix, suffix] <- String.split(compact_iri, ":", parts: 2) do
|
||||||
if not(String.starts_with?(suffix, "//")) and
|
if not String.starts_with?(suffix, "//") and
|
||||||
not (exclude_bnode and prefix == "_"),
|
not (exclude_bnode and prefix == "_"),
|
||||||
do: [prefix, suffix]
|
do: [prefix, suffix]
|
||||||
else
|
else
|
||||||
|
@ -33,7 +32,6 @@ defmodule JSON.LD.Utils do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Checks if the given value is a blank node identifier.
|
Checks if the given value is a blank node identifier.
|
||||||
|
|
||||||
|
@ -47,9 +45,11 @@ defmodule JSON.LD.Utils do
|
||||||
def blank_node_id?("_:" <> _), do: true
|
def blank_node_id?("_:" <> _), do: true
|
||||||
def blank_node_id?(_), do: false
|
def blank_node_id?(_), do: false
|
||||||
|
|
||||||
|
def scalar?(value)
|
||||||
|
when is_binary(value) or is_number(value) or
|
||||||
|
is_boolean(value),
|
||||||
|
do: true
|
||||||
|
|
||||||
def scalar?(value) when is_binary(value) or is_number(value) or
|
|
||||||
is_boolean(value), do: true
|
|
||||||
def scalar?(_), do: false
|
def scalar?(_), do: false
|
||||||
|
|
||||||
def list?(%{"@list" => _}), do: true
|
def list?(%{"@list" => _}), do: true
|
||||||
|
@ -58,5 +58,4 @@ defmodule JSON.LD.Utils do
|
||||||
def index?(_), do: false
|
def index?(_), do: false
|
||||||
def value?(%{"@value" => _}), do: true
|
def value?(%{"@value" => _}), do: true
|
||||||
def value?(_), do: false
|
def value?(_), do: false
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defmodule JSON.LD do
|
defmodule JSON.LD do
|
||||||
|
|
||||||
use RDF.Serialization.Format
|
use RDF.Serialization.Format
|
||||||
|
|
||||||
import RDF.Sigils
|
import RDF.Sigils
|
||||||
|
@ -9,7 +8,7 @@ defmodule JSON.LD do
|
||||||
@extension "jsonld"
|
@extension "jsonld"
|
||||||
@media_type "application/ld+json"
|
@media_type "application/ld+json"
|
||||||
|
|
||||||
def options, do: JSON.LD.Options.new
|
def options, do: JSON.LD.Options.new()
|
||||||
|
|
||||||
@keywords ~w[
|
@keywords ~w[
|
||||||
@base
|
@base
|
||||||
|
@ -42,7 +41,6 @@ defmodule JSON.LD do
|
||||||
def keyword?(value) when is_binary(value) and value in @keywords, do: true
|
def keyword?(value) when is_binary(value) and value in @keywords, do: true
|
||||||
def keyword?(_value), do: false
|
def keyword?(_value), do: false
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Expands the given input according to the steps in the JSON-LD Expansion Algorithm.
|
Expands the given input according to the steps in the JSON-LD Expansion Algorithm.
|
||||||
|
|
||||||
|
@ -57,7 +55,6 @@ defmodule JSON.LD do
|
||||||
defdelegate expand(input, options \\ %JSON.LD.Options{}),
|
defdelegate expand(input, options \\ %JSON.LD.Options{}),
|
||||||
to: JSON.LD.Expansion
|
to: JSON.LD.Expansion
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Compacts the given input according to the steps in the JSON-LD Compaction Algorithm.
|
Compacts the given input according to the steps in the JSON-LD Compaction Algorithm.
|
||||||
|
|
||||||
|
@ -74,7 +71,6 @@ defmodule JSON.LD do
|
||||||
defdelegate compact(input, context, options \\ %JSON.LD.Options{}),
|
defdelegate compact(input, context, options \\ %JSON.LD.Options{}),
|
||||||
to: JSON.LD.Compaction
|
to: JSON.LD.Compaction
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Flattens the given input according to the steps in the JSON-LD Flattening Algorithm.
|
Flattens the given input according to the steps in the JSON-LD Flattening Algorithm.
|
||||||
|
|
||||||
|
@ -90,7 +86,6 @@ defmodule JSON.LD do
|
||||||
defdelegate flatten(input, context \\ nil, options \\ %JSON.LD.Options{}),
|
defdelegate flatten(input, context \\ nil, options \\ %JSON.LD.Options{}),
|
||||||
to: JSON.LD.Flattening
|
to: JSON.LD.Flattening
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Generator function for `JSON.LD.Context`s.
|
Generator function for `JSON.LD.Context`s.
|
||||||
|
|
||||||
|
@ -105,11 +100,9 @@ defmodule JSON.LD do
|
||||||
def context(context, options),
|
def context(context, options),
|
||||||
do: JSON.LD.Context.create(%{"@context" => context}, options)
|
do: JSON.LD.Context.create(%{"@context" => context}, options)
|
||||||
|
|
||||||
|
|
||||||
@doc """
|
@doc """
|
||||||
Generator function for JSON-LD node maps.
|
Generator function for JSON-LD node maps.
|
||||||
"""
|
"""
|
||||||
def node_map(input, node_id_map \\ nil),
|
def node_map(input, node_id_map \\ nil),
|
||||||
do: JSON.LD.Flattening.node_map(input, node_id_map)
|
do: JSON.LD.Flattening.node_map(input, node_id_map)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
14
mix.exs
14
mix.exs
|
@ -3,15 +3,15 @@ defmodule JSON.LD.Mixfile do
|
||||||
|
|
||||||
@repo_url "https://github.com/rdf-elixir/jsonld-ex"
|
@repo_url "https://github.com/rdf-elixir/jsonld-ex"
|
||||||
|
|
||||||
@version File.read!("VERSION") |> String.trim
|
@version File.read!("VERSION") |> String.trim()
|
||||||
|
|
||||||
def project do
|
def project do
|
||||||
[
|
[
|
||||||
app: :json_ld,
|
app: :json_ld,
|
||||||
version: @version,
|
version: @version,
|
||||||
elixir: "~> 1.8",
|
elixir: "~> 1.8",
|
||||||
build_embedded: Mix.env == :prod,
|
build_embedded: Mix.env() == :prod,
|
||||||
start_permanent: Mix.env == :prod,
|
start_permanent: Mix.env() == :prod,
|
||||||
deps: deps(),
|
deps: deps(),
|
||||||
elixirc_paths: elixirc_paths(Mix.env()),
|
elixirc_paths: elixirc_paths(Mix.env()),
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ defmodule JSON.LD.Mixfile do
|
||||||
main: "JSON.LD",
|
main: "JSON.LD",
|
||||||
source_url: @repo_url,
|
source_url: @repo_url,
|
||||||
source_ref: "v#{@version}",
|
source_ref: "v#{@version}",
|
||||||
extras: ["README.md"],
|
extras: ["README.md"]
|
||||||
],
|
],
|
||||||
|
|
||||||
# ExCoveralls
|
# ExCoveralls
|
||||||
|
@ -35,7 +35,7 @@ defmodule JSON.LD.Mixfile do
|
||||||
"coveralls.detail": :test,
|
"coveralls.detail": :test,
|
||||||
"coveralls.post": :test,
|
"coveralls.post": :test,
|
||||||
"coveralls.html": :test
|
"coveralls.html": :test
|
||||||
],
|
]
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -63,12 +63,12 @@ defmodule JSON.LD.Mixfile do
|
||||||
{:rdf, "~> 0.8"},
|
{:rdf, "~> 0.8"},
|
||||||
{:jason, "~> 1.2"},
|
{:jason, "~> 1.2"},
|
||||||
{:httpoison, "~> 1.7"},
|
{:httpoison, "~> 1.7"},
|
||||||
|
|
||||||
{:credo, "~> 1.4", only: [:dev, :test], runtime: false},
|
{:credo, "~> 1.4", only: [:dev, :test], runtime: false},
|
||||||
{:dialyxir, "~> 1.0", only: :dev, runtime: false},
|
{:dialyxir, "~> 1.0", only: :dev, runtime: false},
|
||||||
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
|
{:ex_doc, "~> 0.22", only: :dev, runtime: false},
|
||||||
{:bypass, "~> 1.0", only: :test},
|
{:bypass, "~> 1.0", only: :test},
|
||||||
{:plug_cowboy, "~> 1.0", only: :test}, # in order to run under OTP 21 we need to keep this dependency of bypass on 1.0
|
# in order to run under OTP 21 we need to keep this dependency of bypass on 1.0
|
||||||
|
{:plug_cowboy, "~> 1.0", only: :test},
|
||||||
{:excoveralls, "~> 0.13", only: :test}
|
{:excoveralls, "~> 0.13", only: :test}
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,9 +13,12 @@ defmodule JSON.LD.TestSuite.CompactTest do
|
||||||
@tag :compact_test_suite
|
@tag :compact_test_suite
|
||||||
@tag data: test_case
|
@tag data: test_case
|
||||||
test "#{input}: #{name}",
|
test "#{input}: #{name}",
|
||||||
%{data: %{"input" => input, "expect" => output, "context" => context} = test_case, base_iri: base_iri} do
|
%{
|
||||||
assert JSON.LD.compact(j(input), j(context), test_case_options(test_case, base_iri)) == j(output)
|
data: %{"input" => input, "expect" => output, "context" => context} = test_case,
|
||||||
|
base_iri: base_iri
|
||||||
|
} do
|
||||||
|
assert JSON.LD.compact(j(input), j(context), test_case_options(test_case, base_iri)) ==
|
||||||
|
j(output)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -24,8 +24,6 @@ defmodule JSON.LD.TestSuite.ErrorTest do
|
||||||
assert_raise exception(error), fn ->
|
assert_raise exception(error), fn ->
|
||||||
JSON.LD.flatten(j(input), context, test_case_options(test_case, base_iri))
|
JSON.LD.flatten(j(input), context, test_case_options(test_case, base_iri))
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,6 +16,7 @@ defmodule JSON.LD.TestSuite.ExpandTest do
|
||||||
if input in ~w[expand-0034-in.jsonld expand-0035-in.jsonld expand-0038-in.jsonld] do
|
if input in ~w[expand-0034-in.jsonld expand-0035-in.jsonld expand-0038-in.jsonld] do
|
||||||
@tag skip: "TODO: Actually correct values are expanded, but the ordering is different."
|
@tag skip: "TODO: Actually correct values are expanded, but the ordering is different."
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag :test_suite
|
@tag :test_suite
|
||||||
@tag :expand_test_suite
|
@tag :expand_test_suite
|
||||||
@tag data: test_case
|
@tag data: test_case
|
||||||
|
@ -24,5 +25,4 @@ defmodule JSON.LD.TestSuite.ExpandTest do
|
||||||
assert JSON.LD.expand(j(input), test_case_options(test_case, base_iri)) == j(output)
|
assert JSON.LD.expand(j(input), test_case_options(test_case, base_iri)) == j(output)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,6 +16,7 @@ defmodule JSON.LD.TestSuite.FlattenTest do
|
||||||
if input in ~w[flatten-0034-in.jsonld flatten-0035-in.jsonld flatten-0038-in.jsonld] do
|
if input in ~w[flatten-0034-in.jsonld flatten-0035-in.jsonld flatten-0038-in.jsonld] do
|
||||||
@tag skip: "TODO: Actually correct values are expanded, but the ordering is different."
|
@tag skip: "TODO: Actually correct values are expanded, but the ordering is different."
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag :test_suite
|
@tag :test_suite
|
||||||
@tag :flatten_test_suite
|
@tag :flatten_test_suite
|
||||||
@tag data: test_case
|
@tag data: test_case
|
||||||
|
@ -26,8 +27,9 @@ defmodule JSON.LD.TestSuite.FlattenTest do
|
||||||
nil -> nil
|
nil -> nil
|
||||||
context -> j(context)
|
context -> j(context)
|
||||||
end
|
end
|
||||||
assert JSON.LD.flatten(j(input), context, test_case_options(test_case, base_iri)) == j(output)
|
|
||||||
|
assert JSON.LD.flatten(j(input), context, test_case_options(test_case, base_iri)) ==
|
||||||
|
j(output)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -3,7 +3,6 @@ defmodule JSON.LD.TestSuite.FromRdfTest do
|
||||||
|
|
||||||
import JSON.LD.TestSuite
|
import JSON.LD.TestSuite
|
||||||
|
|
||||||
|
|
||||||
setup_all do
|
setup_all do
|
||||||
[base_iri: manifest("fromRdf")["baseIri"]]
|
[base_iri: manifest("fromRdf")["baseIri"]]
|
||||||
end
|
end
|
||||||
|
@ -26,9 +25,11 @@ defmodule JSON.LD.TestSuite.FromRdfTest do
|
||||||
So, fixing that would require a different representation of graphs in general.
|
So, fixing that would require a different representation of graphs in general.
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
if input in ~w[fromRdf-0020-in.nq fromRdf-0021-in.nq] do
|
if input in ~w[fromRdf-0020-in.nq fromRdf-0021-in.nq] do
|
||||||
@tag skip: "https://github.com/json-ld/json-ld.org/issues/357"
|
@tag skip: "https://github.com/json-ld/json-ld.org/issues/357"
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag :test_suite
|
@tag :test_suite
|
||||||
@tag :from_rdf_test_suite
|
@tag :from_rdf_test_suite
|
||||||
@tag data: test_case
|
@tag data: test_case
|
||||||
|
@ -41,14 +42,14 @@ defmodule JSON.LD.TestSuite.FromRdfTest do
|
||||||
def serialize(filename, options) do
|
def serialize(filename, options) do
|
||||||
filename
|
filename
|
||||||
|> file
|
|> file
|
||||||
|> RDF.NQuads.read_file!
|
|> RDF.NQuads.read_file!()
|
||||||
|> JSON.LD.Encoder.from_rdf!(options)
|
|> JSON.LD.Encoder.from_rdf!(options)
|
||||||
end
|
end
|
||||||
|
|
||||||
def json(filename) do
|
def json(filename) do
|
||||||
filename
|
filename
|
||||||
|> file
|
|> file
|
||||||
|> File.read!
|
|> File.read!()
|
||||||
|> Jason.decode!
|
|> Jason.decode!()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -18,13 +18,15 @@ defmodule JSON.LD.TestSuite.ToRdfTest do
|
||||||
during expansion the generated blank nodes are named different.
|
during expansion the generated blank nodes are named different.
|
||||||
"""
|
"""
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag :test_suite
|
@tag :test_suite
|
||||||
@tag :to_rdf_test_suite
|
@tag :to_rdf_test_suite
|
||||||
@tag data: test_case
|
@tag data: test_case
|
||||||
test "#{input}: #{name}",
|
test "#{input}: #{name}",
|
||||||
%{data: %{"input" => input, "expect" => output} = test_case, base_iri: base_iri} do
|
%{data: %{"input" => input, "expect" => output} = test_case, base_iri: base_iri} do
|
||||||
# This requires a special handling, since the N-Quad ouput file is not valid, by using blank nodes as predicates
|
# This requires a special handling, since the N-Quad ouput file is not valid, by using blank nodes as predicates
|
||||||
dataset = if input == "toRdf-0118-in.jsonld",
|
dataset =
|
||||||
|
if input == "toRdf-0118-in.jsonld",
|
||||||
do: toRdf_0118_dataset(),
|
do: toRdf_0118_dataset(),
|
||||||
else: RDF.NQuads.read_file!(file(output))
|
else: RDF.NQuads.read_file!(file(output))
|
||||||
|
|
||||||
|
@ -42,7 +44,7 @@ defmodule JSON.LD.TestSuite.ToRdfTest do
|
||||||
{RDF.bnode("b0"), RDF.bnode("b0"), RDF.bnode("b2")},
|
{RDF.bnode("b0"), RDF.bnode("b0"), RDF.bnode("b2")},
|
||||||
{RDF.bnode("b0"), RDF.bnode("b0"), RDF.bnode("b3")},
|
{RDF.bnode("b0"), RDF.bnode("b0"), RDF.bnode("b3")},
|
||||||
{RDF.bnode("b1"), RDF.bnode("b0"), "term"},
|
{RDF.bnode("b1"), RDF.bnode("b0"), "term"},
|
||||||
{RDF.bnode("b2"), RDF.bnode("b0"), "termId"},
|
{RDF.bnode("b2"), RDF.bnode("b0"), "termId"}
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
defmodule JSON.LD.TestData do
|
defmodule JSON.LD.TestData do
|
||||||
|
@dir Path.join(File.cwd!(), "test/data/")
|
||||||
@dir Path.join(File.cwd!, "test/data/")
|
|
||||||
def dir, do: @dir
|
def dir, do: @dir
|
||||||
|
|
||||||
def file(name) do
|
def file(name) do
|
||||||
|
@ -10,5 +9,4 @@ defmodule JSON.LD.TestData do
|
||||||
raise "Test data file '#{name}' not found"
|
raise "Test data file '#{name}' not found"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
defmodule JSON.LD.TestSuite do
|
defmodule JSON.LD.TestSuite do
|
||||||
|
|
||||||
@test_suite_dir "json-ld.org-test-suite"
|
@test_suite_dir "json-ld.org-test-suite"
|
||||||
def test_suite_dir, do: @test_suite_dir
|
def test_suite_dir, do: @test_suite_dir
|
||||||
|
|
||||||
|
@ -43,7 +42,7 @@ defmodule JSON.LD.TestSuite do
|
||||||
|> Map.get("option", %{})
|
|> Map.get("option", %{})
|
||||||
|> Map.put_new("base", base_iri <> test_case["input"])
|
|> Map.put_new("base", base_iri <> test_case["input"])
|
||||||
|> Enum.map(fn {key, value} ->
|
|> Enum.map(fn {key, value} ->
|
||||||
{key |> Macro.underscore |> String.to_atom, value}
|
{key |> Macro.underscore() |> String.to_atom(), value}
|
||||||
end)
|
end)
|
||||||
|> Enum.map(fn
|
|> Enum.map(fn
|
||||||
{:expand_context, file} -> {:expand_context, j(file)}
|
{:expand_context, file} -> {:expand_context, j(file)}
|
||||||
|
@ -52,13 +51,14 @@ defmodule JSON.LD.TestSuite do
|
||||||
end
|
end
|
||||||
|
|
||||||
def exception(error) do
|
def exception(error) do
|
||||||
error = error
|
error =
|
||||||
|
error
|
||||||
|> String.replace(" ", "_")
|
|> String.replace(" ", "_")
|
||||||
|> String.replace("-", "_")
|
|> String.replace("-", "_")
|
||||||
|> String.replace("@", "_")
|
|> String.replace("@", "_")
|
||||||
|> Macro.camelize
|
|> Macro.camelize()
|
||||||
|> String.replace("_", "")
|
|> String.replace("_", "")
|
||||||
|
|
||||||
String.to_existing_atom("Elixir.JSON.LD.#{error}Error")
|
String.to_existing_atom("Elixir.JSON.LD.#{error}Error")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,8 @@ defmodule JSON.LD.CompactionTest do
|
||||||
alias RDF.NS.{RDFS, XSD}
|
alias RDF.NS.{RDFS, XSD}
|
||||||
|
|
||||||
test "Flattened form of a JSON-LD document (EXAMPLES 57-59 of https://www.w3.org/TR/json-ld/#compacted-document-form)" do
|
test "Flattened form of a JSON-LD document (EXAMPLES 57-59 of https://www.w3.org/TR/json-ld/#compacted-document-form)" do
|
||||||
input = Jason.decode! """
|
input =
|
||||||
|
Jason.decode!("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"http://xmlns.com/foaf/0.1/name": [ "Manu Sporny" ],
|
"http://xmlns.com/foaf/0.1/name": [ "Manu Sporny" ],
|
||||||
|
@ -15,8 +16,10 @@ defmodule JSON.LD.CompactionTest do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
"""
|
""")
|
||||||
context = Jason.decode! """
|
|
||||||
|
context =
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": {
|
"@context": {
|
||||||
"name": "http://xmlns.com/foaf/0.1/name",
|
"name": "http://xmlns.com/foaf/0.1/name",
|
||||||
|
@ -26,8 +29,10 @@ defmodule JSON.LD.CompactionTest do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"""
|
""")
|
||||||
assert JSON.LD.compact(input, context) == Jason.decode! """
|
|
||||||
|
assert JSON.LD.compact(input, context) ==
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": {
|
"@context": {
|
||||||
"name": "http://xmlns.com/foaf/0.1/name",
|
"name": "http://xmlns.com/foaf/0.1/name",
|
||||||
|
@ -39,10 +44,9 @@ defmodule JSON.LD.CompactionTest do
|
||||||
"name": "Manu Sporny",
|
"name": "Manu Sporny",
|
||||||
"homepage": "http://manu.sporny.org/"
|
"homepage": "http://manu.sporny.org/"
|
||||||
}
|
}
|
||||||
"""
|
""")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
"prefix" => %{
|
"prefix" => %{
|
||||||
input: %{
|
input: %{
|
||||||
|
@ -111,15 +115,15 @@ defmodule JSON.LD.CompactionTest do
|
||||||
},
|
},
|
||||||
"xsd:date coercion" => %{
|
"xsd:date coercion" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"http://example.com/b" => %{"@value" => "2012-01-04", "@type" => to_string(XSD.date)}
|
"http://example.com/b" => %{"@value" => "2012-01-04", "@type" => to_string(XSD.date())}
|
||||||
},
|
},
|
||||||
context: %{
|
context: %{
|
||||||
"xsd" => XSD.__base_iri__,
|
"xsd" => XSD.__base_iri__(),
|
||||||
"b" => %{"@id" => "http://example.com/b", "@type" => "xsd:date"}
|
"b" => %{"@id" => "http://example.com/b", "@type" => "xsd:date"}
|
||||||
},
|
},
|
||||||
output: %{
|
output: %{
|
||||||
"@context" => %{
|
"@context" => %{
|
||||||
"xsd" => XSD.__base_iri__,
|
"xsd" => XSD.__base_iri__(),
|
||||||
"b" => %{"@id" => "http://example.com/b", "@type" => "xsd:date"}
|
"b" => %{"@id" => "http://example.com/b", "@type" => "xsd:date"}
|
||||||
},
|
},
|
||||||
"b" => "2012-01-04"
|
"b" => "2012-01-04"
|
||||||
|
@ -138,7 +142,7 @@ defmodule JSON.LD.CompactionTest do
|
||||||
"@list coercion (integer)" => %{
|
"@list coercion (integer)" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"http://example.com/term" => [
|
"http://example.com/term" => [
|
||||||
%{"@list" => [1]},
|
%{"@list" => [1]}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
context: %{
|
context: %{
|
||||||
|
@ -150,7 +154,7 @@ defmodule JSON.LD.CompactionTest do
|
||||||
"term4" => %{"@id" => "http://example.com/term", "@container" => "@list"},
|
"term4" => %{"@id" => "http://example.com/term", "@container" => "@list"},
|
||||||
"@language" => "de"
|
"@language" => "de"
|
||||||
},
|
},
|
||||||
"term4" => [1],
|
"term4" => [1]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@set coercion" => %{
|
"@set coercion" => %{
|
||||||
|
@ -176,24 +180,24 @@ defmodule JSON.LD.CompactionTest do
|
||||||
"@type with string @id" => %{
|
"@type with string @id" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@id" => "http://example.com/",
|
"@id" => "http://example.com/",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
},
|
},
|
||||||
context: %{},
|
context: %{},
|
||||||
output: %{
|
output: %{
|
||||||
"@id" => "http://example.com/",
|
"@id" => "http://example.com/",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
"@type with array @id" => %{
|
"@type with array @id" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@id" => "http://example.com/",
|
"@id" => "http://example.com/",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
},
|
},
|
||||||
context: %{},
|
context: %{},
|
||||||
output: %{
|
output: %{
|
||||||
"@id" => "http://example.com/",
|
"@id" => "http://example.com/",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
"default language" => %{
|
"default language" => %{
|
||||||
input: %{
|
input: %{
|
||||||
|
@ -213,9 +217,9 @@ defmodule JSON.LD.CompactionTest do
|
||||||
},
|
},
|
||||||
"term5" => ["v5", "plain literal"]
|
"term5" => ["v5", "plain literal"]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.compact(data.input, data.context) == data.output
|
assert JSON.LD.compact(data.input, data.context) == data.output
|
||||||
|
@ -227,24 +231,24 @@ defmodule JSON.LD.CompactionTest do
|
||||||
"@id" => %{
|
"@id" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@id" => "",
|
"@id" => "",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
},
|
},
|
||||||
context: %{"id" => "@id"},
|
context: %{"id" => "@id"},
|
||||||
output: %{
|
output: %{
|
||||||
"@context" => %{"id" => "@id"},
|
"@context" => %{"id" => "@id"},
|
||||||
"id" => "",
|
"id" => "",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@type" => %{
|
"@type" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string),
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string,
|
||||||
"http://example.org/foo" => %{"@value" => "bar", "@type" => "http://example.com/type"}
|
"http://example.org/foo" => %{"@value" => "bar", "@type" => "http://example.com/type"}
|
||||||
},
|
},
|
||||||
context: %{"type" => "@type"},
|
context: %{"type" => "@type"},
|
||||||
output: %{
|
output: %{
|
||||||
"@context" => %{"type" => "@type"},
|
"@context" => %{"type" => "@type"},
|
||||||
"type" => (RDFS.Resource |> RDF.uri |> to_string),
|
"type" => RDFS.Resource |> RDF.uri() |> to_string,
|
||||||
"http://example.org/foo" => %{"@value" => "bar", "type" => "http://example.com/type"}
|
"http://example.org/foo" => %{"@value" => "bar", "type" => "http://example.com/type"}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -277,9 +281,9 @@ defmodule JSON.LD.CompactionTest do
|
||||||
"@context" => %{"list" => "@list"},
|
"@context" => %{"list" => "@list"},
|
||||||
"http://example.org/foo" => %{"list" => ["bar"]}
|
"http://example.org/foo" => %{"list" => ["bar"]}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.compact(data.input, data.context) == data.output
|
assert JSON.LD.compact(data.input, data.context) == data.output
|
||||||
|
@ -290,9 +294,11 @@ defmodule JSON.LD.CompactionTest do
|
||||||
describe "term selection" do
|
describe "term selection" do
|
||||||
%{
|
%{
|
||||||
"Uses term with nil language when two terms conflict on language" => %{
|
"Uses term with nil language when two terms conflict on language" => %{
|
||||||
input: [%{
|
input: [
|
||||||
|
%{
|
||||||
"http://example.com/term" => %{"@value" => "v1"}
|
"http://example.com/term" => %{"@value" => "v1"}
|
||||||
}],
|
}
|
||||||
|
],
|
||||||
context: %{
|
context: %{
|
||||||
"term5" => %{"@id" => "http://example.com/term", "@language" => nil},
|
"term5" => %{"@id" => "http://example.com/term", "@language" => nil},
|
||||||
"@language" => "de"
|
"@language" => "de"
|
||||||
|
@ -302,14 +308,16 @@ defmodule JSON.LD.CompactionTest do
|
||||||
"term5" => %{"@id" => "http://example.com/term", "@language" => nil},
|
"term5" => %{"@id" => "http://example.com/term", "@language" => nil},
|
||||||
"@language" => "de"
|
"@language" => "de"
|
||||||
},
|
},
|
||||||
"term5" => "v1",
|
"term5" => "v1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Uses subject alias" => %{
|
"Uses subject alias" => %{
|
||||||
input: [%{
|
input: [
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/id1",
|
"@id" => "http://example.com/id1",
|
||||||
"http://example.com/id1" => %{"@value" => "foo", "@language" => "de"}
|
"http://example.com/id1" => %{"@value" => "foo", "@language" => "de"}
|
||||||
}],
|
}
|
||||||
|
],
|
||||||
context: %{
|
context: %{
|
||||||
"id1" => "http://example.com/id1",
|
"id1" => "http://example.com/id1",
|
||||||
"@language" => "de"
|
"@language" => "de"
|
||||||
|
@ -324,16 +332,19 @@ defmodule JSON.LD.CompactionTest do
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"compact-0007" => %{
|
"compact-0007" => %{
|
||||||
input: Jason.decode!("""
|
input:
|
||||||
|
Jason.decode!("""
|
||||||
{"http://example.org/vocab#contains": "this-is-not-an-IRI"}
|
{"http://example.org/vocab#contains": "this-is-not-an-IRI"}
|
||||||
"""),
|
"""),
|
||||||
context: Jason.decode!("""
|
context:
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"ex": "http://example.org/vocab#",
|
"ex": "http://example.org/vocab#",
|
||||||
"ex:contains": {"@type": "@id"}
|
"ex:contains": {"@type": "@id"}
|
||||||
}
|
}
|
||||||
"""),
|
"""),
|
||||||
output: Jason.decode!("""
|
output:
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": {
|
"@context": {
|
||||||
"ex": "http://example.org/vocab#",
|
"ex": "http://example.org/vocab#",
|
||||||
|
@ -341,10 +352,10 @@ defmodule JSON.LD.CompactionTest do
|
||||||
},
|
},
|
||||||
"http://example.org/vocab#contains": "this-is-not-an-IRI"
|
"http://example.org/vocab#contains": "this-is-not-an-IRI"
|
||||||
}
|
}
|
||||||
"""),
|
""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.compact(data.input, data.context) == data.output
|
assert JSON.LD.compact(data.input, data.context) == data.output
|
||||||
|
@ -355,7 +366,8 @@ defmodule JSON.LD.CompactionTest do
|
||||||
describe "@reverse" do
|
describe "@reverse" do
|
||||||
%{
|
%{
|
||||||
"compact-0033" => %{
|
"compact-0033" => %{
|
||||||
input: Jason.decode!("""
|
input:
|
||||||
|
Jason.decode!("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"@id": "http://example.com/people/markus",
|
"@id": "http://example.com/people/markus",
|
||||||
|
@ -371,13 +383,15 @@ defmodule JSON.LD.CompactionTest do
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
"""),
|
"""),
|
||||||
context: Jason.decode!("""
|
context:
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"name": "http://xmlns.com/foaf/0.1/name",
|
"name": "http://xmlns.com/foaf/0.1/name",
|
||||||
"isKnownBy": { "@reverse": "http://xmlns.com/foaf/0.1/knows" }
|
"isKnownBy": { "@reverse": "http://xmlns.com/foaf/0.1/knows" }
|
||||||
}
|
}
|
||||||
"""),
|
"""),
|
||||||
output: Jason.decode!("""
|
output:
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": {
|
"@context": {
|
||||||
"name": "http://xmlns.com/foaf/0.1/name",
|
"name": "http://xmlns.com/foaf/0.1/name",
|
||||||
|
@ -395,7 +409,7 @@ defmodule JSON.LD.CompactionTest do
|
||||||
""")
|
""")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.compact(data.input, data.context) == data.output
|
assert JSON.LD.compact(data.input, data.context) == data.output
|
||||||
|
@ -408,15 +422,18 @@ defmodule JSON.LD.CompactionTest do
|
||||||
context = %{
|
context = %{
|
||||||
"foo" => "http://example.com/"
|
"foo" => "http://example.com/"
|
||||||
}
|
}
|
||||||
|
|
||||||
input = %{
|
input = %{
|
||||||
"http://example.com/" => "bar"
|
"http://example.com/" => "bar"
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = %{
|
expected = %{
|
||||||
"@context" => %{
|
"@context" => %{
|
||||||
"foo" => "http://example.com/"
|
"foo" => "http://example.com/"
|
||||||
},
|
},
|
||||||
"foo" => "bar"
|
"foo" => "bar"
|
||||||
}
|
}
|
||||||
|
|
||||||
assert JSON.LD.compact(input, context) == expected
|
assert JSON.LD.compact(input, context) == expected
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -443,27 +460,45 @@ defmodule JSON.LD.CompactionTest do
|
||||||
describe "@list" do
|
describe "@list" do
|
||||||
%{
|
%{
|
||||||
"1 term 2 lists 2 languages" => %{
|
"1 term 2 lists 2 languages" => %{
|
||||||
input: [%{
|
input: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [
|
"http://example.com/foo" => [
|
||||||
%{"@list" => [%{"@value" => "en", "@language" => "en"}]},
|
%{"@list" => [%{"@value" => "en", "@language" => "en"}]},
|
||||||
%{"@list" => [%{"@value" => "de", "@language" => "de"}]}
|
%{"@list" => [%{"@value" => "de", "@language" => "de"}]}
|
||||||
]
|
]
|
||||||
}],
|
}
|
||||||
|
],
|
||||||
context: %{
|
context: %{
|
||||||
"foo_en" => %{"@id" => "http://example.com/foo", "@container" => "@list", "@language" => "en"},
|
"foo_en" => %{
|
||||||
"foo_de" => %{"@id" => "http://example.com/foo", "@container" => "@list", "@language" => "de"}
|
"@id" => "http://example.com/foo",
|
||||||
|
"@container" => "@list",
|
||||||
|
"@language" => "en"
|
||||||
|
},
|
||||||
|
"foo_de" => %{
|
||||||
|
"@id" => "http://example.com/foo",
|
||||||
|
"@container" => "@list",
|
||||||
|
"@language" => "de"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
output: %{
|
output: %{
|
||||||
"@context" => %{
|
"@context" => %{
|
||||||
"foo_en" => %{"@id" => "http://example.com/foo", "@container" => "@list", "@language" => "en"},
|
"foo_en" => %{
|
||||||
"foo_de" => %{"@id" => "http://example.com/foo", "@container" => "@list", "@language" => "de"}
|
"@id" => "http://example.com/foo",
|
||||||
|
"@container" => "@list",
|
||||||
|
"@language" => "en"
|
||||||
|
},
|
||||||
|
"foo_de" => %{
|
||||||
|
"@id" => "http://example.com/foo",
|
||||||
|
"@container" => "@list",
|
||||||
|
"@language" => "de"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"foo_en" => ["en"],
|
"foo_en" => ["en"],
|
||||||
"foo_de" => ["de"]
|
"foo_de" => ["de"]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.compact(data.input, data.context) == data.output
|
assert JSON.LD.compact(data.input, data.context) == data.output
|
||||||
|
@ -499,9 +534,9 @@ defmodule JSON.LD.CompactionTest do
|
||||||
"de" => ["Die Königin", "Ihre Majestät"]
|
"de" => ["Die Königin", "Ihre Majestät"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.compact(data.input, data.context) == data.output
|
assert JSON.LD.compact(data.input, data.context) == data.output
|
||||||
|
@ -524,9 +559,9 @@ defmodule JSON.LD.CompactionTest do
|
||||||
%{"ex:bar" => "bar"}
|
%{"ex:bar" => "bar"}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.compact(data.input, data.context) == data.output
|
assert JSON.LD.compact(data.input, data.context) == data.output
|
||||||
|
@ -548,14 +583,13 @@ defmodule JSON.LD.CompactionTest do
|
||||||
"http://example.org/foo" => [%{"@list" => ["baz"]}]
|
"http://example.org/foo" => [%{"@list" => ["baz"]}]
|
||||||
},
|
},
|
||||||
exception: JSON.LD.ListOfListsError
|
exception: JSON.LD.ListOfListsError
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert_raise data.exception, fn -> JSON.LD.compact(data.input, %{}) end
|
assert_raise data.exception, fn -> JSON.LD.compact(data.input, %{}) end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,40 +32,39 @@ defmodule JSON.LD.ContextTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "associates @list container mapping with predicate" do
|
test "associates @list container mapping with predicate" do
|
||||||
c = JSON.LD.context(%{"foo" =>
|
c = JSON.LD.context(%{"foo" => %{"@id" => "http://example.com/", "@container" => "@list"}})
|
||||||
%{"@id" => "http://example.com/", "@container" => "@list"}})
|
|
||||||
assert c.term_defs["foo"]
|
assert c.term_defs["foo"]
|
||||||
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
||||||
assert c.term_defs["foo"].container_mapping == "@list"
|
assert c.term_defs["foo"].container_mapping == "@list"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "associates @set container mapping with predicate" do
|
test "associates @set container mapping with predicate" do
|
||||||
c = JSON.LD.context(%{"foo" =>
|
c = JSON.LD.context(%{"foo" => %{"@id" => "http://example.com/", "@container" => "@set"}})
|
||||||
%{"@id" => "http://example.com/", "@container" => "@set"}})
|
|
||||||
assert c.term_defs["foo"]
|
assert c.term_defs["foo"]
|
||||||
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
||||||
assert c.term_defs["foo"].container_mapping == "@set"
|
assert c.term_defs["foo"].container_mapping == "@set"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "associates @id container mapping with predicate" do
|
test "associates @id container mapping with predicate" do
|
||||||
c = JSON.LD.context(%{"foo" =>
|
c = JSON.LD.context(%{"foo" => %{"@id" => "http://example.com/", "@type" => "@id"}})
|
||||||
%{"@id" => "http://example.com/", "@type" => "@id"}})
|
|
||||||
assert c.term_defs["foo"]
|
assert c.term_defs["foo"]
|
||||||
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
||||||
assert c.term_defs["foo"].type_mapping == "@id"
|
assert c.term_defs["foo"].type_mapping == "@id"
|
||||||
end
|
end
|
||||||
|
|
||||||
test "associates type mapping with predicate" do
|
test "associates type mapping with predicate" do
|
||||||
c = JSON.LD.context(%{"foo" =>
|
c =
|
||||||
%{"@id" => "http://example.com/", "@type" => to_string(XSD.string)}})
|
JSON.LD.context(%{
|
||||||
|
"foo" => %{"@id" => "http://example.com/", "@type" => to_string(XSD.string())}
|
||||||
|
})
|
||||||
|
|
||||||
assert c.term_defs["foo"]
|
assert c.term_defs["foo"]
|
||||||
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
||||||
assert c.term_defs["foo"].type_mapping == to_string(XSD.string)
|
assert c.term_defs["foo"].type_mapping == to_string(XSD.string())
|
||||||
end
|
end
|
||||||
|
|
||||||
test "associates language mapping with predicate" do
|
test "associates language mapping with predicate" do
|
||||||
c = JSON.LD.context(%{"foo" =>
|
c = JSON.LD.context(%{"foo" => %{"@id" => "http://example.com/", "@language" => "en"}})
|
||||||
%{"@id" => "http://example.com/", "@language" => "en"}})
|
|
||||||
assert c.term_defs["foo"]
|
assert c.term_defs["foo"]
|
||||||
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
assert c.term_defs["foo"].iri_mapping == "http://example.com/"
|
||||||
assert c.term_defs["foo"].language_mapping == "en"
|
assert c.term_defs["foo"].language_mapping == "en"
|
||||||
|
@ -76,7 +75,8 @@ defmodule JSON.LD.ContextTest do
|
||||||
"foo" => "bar",
|
"foo" => "bar",
|
||||||
"bar" => "baz",
|
"bar" => "baz",
|
||||||
"baz" => "http://example.com/"
|
"baz" => "http://example.com/"
|
||||||
}) |> iri_mappings == %{
|
})
|
||||||
|
|> iri_mappings == %{
|
||||||
"foo" => "http://example.com/",
|
"foo" => "http://example.com/",
|
||||||
"bar" => "http://example.com/",
|
"bar" => "http://example.com/",
|
||||||
"baz" => "http://example.com/"
|
"baz" => "http://example.com/"
|
||||||
|
@ -84,9 +84,12 @@ defmodule JSON.LD.ContextTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "expands terms using @vocab" do
|
test "expands terms using @vocab" do
|
||||||
c = JSON.LD.context(%{
|
c =
|
||||||
|
JSON.LD.context(%{
|
||||||
"foo" => "bar",
|
"foo" => "bar",
|
||||||
"@vocab" => "http://example.com/"})
|
"@vocab" => "http://example.com/"
|
||||||
|
})
|
||||||
|
|
||||||
assert c.term_defs["foo"]
|
assert c.term_defs["foo"]
|
||||||
assert c.term_defs["foo"].iri_mapping == "http://example.com/bar"
|
assert c.term_defs["foo"].iri_mapping == "http://example.com/bar"
|
||||||
end
|
end
|
||||||
|
@ -97,7 +100,8 @@ defmodule JSON.LD.ContextTest do
|
||||||
assert JSON.LD.context([
|
assert JSON.LD.context([
|
||||||
%{"foo" => "http://example.com/foo"},
|
%{"foo" => "http://example.com/foo"},
|
||||||
%{"bar" => "foo"}
|
%{"bar" => "foo"}
|
||||||
]) |> iri_mappings == %{
|
])
|
||||||
|
|> iri_mappings == %{
|
||||||
"foo" => "http://example.com/foo",
|
"foo" => "http://example.com/foo",
|
||||||
"bar" => "http://example.com/foo"
|
"bar" => "http://example.com/foo"
|
||||||
}
|
}
|
||||||
|
@ -120,10 +124,13 @@ defmodule JSON.LD.ContextTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "removes term if set to null with @vocab" do
|
test "removes term if set to null with @vocab" do
|
||||||
assert JSON.LD.context([%{
|
assert JSON.LD.context([
|
||||||
|
%{
|
||||||
"@vocab" => "http://schema.org/",
|
"@vocab" => "http://schema.org/",
|
||||||
"term" => nil
|
"term" => nil
|
||||||
}]) |> iri_mappings == %{
|
}
|
||||||
|
])
|
||||||
|
|> iri_mappings == %{
|
||||||
"term" => nil
|
"term" => nil
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
@ -133,7 +140,7 @@ defmodule JSON.LD.ContextTest do
|
||||||
end
|
end
|
||||||
|
|
||||||
test "loads initial context" do
|
test "loads initial context" do
|
||||||
init_ec = JSON.LD.Context.new
|
init_ec = JSON.LD.Context.new()
|
||||||
nil_ec = JSON.LD.context(nil)
|
nil_ec = JSON.LD.context(nil)
|
||||||
assert nil_ec.default_language == init_ec.default_language
|
assert nil_ec.default_language == init_ec.default_language
|
||||||
assert nil_ec |> coercions == init_ec |> coercions
|
assert nil_ec |> coercions == init_ec |> coercions
|
||||||
|
@ -200,9 +207,9 @@ defmodule JSON.LD.ContextTest do
|
||||||
"@vocab as @id" => %{
|
"@vocab as @id" => %{
|
||||||
input: %{"@vocab" => %{"@id" => "http://example.com/"}},
|
input: %{"@vocab" => %{"@id" => "http://example.com/"}},
|
||||||
exception: JSON.LD.InvalidVocabMappingError
|
exception: JSON.LD.InvalidVocabMappingError
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert_raise data.exception, fn ->
|
assert_raise data.exception, fn ->
|
||||||
|
@ -211,7 +218,7 @@ defmodule JSON.LD.ContextTest do
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
(JSON.LD.keywords -- ~w[@base @language @vocab])
|
(JSON.LD.keywords() -- ~w[@base @language @vocab])
|
||||||
|> Enum.each(fn keyword ->
|
|> Enum.each(fn keyword ->
|
||||||
@tag keyword: keyword
|
@tag keyword: keyword
|
||||||
test "does not redefine #{keyword} as a string", %{keyword: keyword} do
|
test "does not redefine #{keyword} as a string", %{keyword: keyword} do
|
||||||
|
@ -237,29 +244,27 @@ defmodule JSON.LD.ContextTest do
|
||||||
@tag :skip
|
@tag :skip
|
||||||
test "warn on terms starting with a @"
|
test "warn on terms starting with a @"
|
||||||
|
|
||||||
|
|
||||||
def iri_mappings(%JSON.LD.Context{term_defs: term_defs}) do
|
def iri_mappings(%JSON.LD.Context{term_defs: term_defs}) do
|
||||||
Enum.reduce term_defs, %{}, fn ({term, term_def}, iri_mappings) ->
|
Enum.reduce(term_defs, %{}, fn {term, term_def}, iri_mappings ->
|
||||||
Map.put iri_mappings, term, (term_def && term_def.iri_mapping) || nil
|
Map.put(iri_mappings, term, (term_def && term_def.iri_mapping) || nil)
|
||||||
end
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def languages(%JSON.LD.Context{term_defs: term_defs}) do
|
def languages(%JSON.LD.Context{term_defs: term_defs}) do
|
||||||
Enum.reduce term_defs, %{}, fn ({term, term_def}, language_mappings) ->
|
Enum.reduce(term_defs, %{}, fn {term, term_def}, language_mappings ->
|
||||||
Map.put language_mappings, term, term_def.language_mapping
|
Map.put(language_mappings, term, term_def.language_mapping)
|
||||||
end
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def coercions(%JSON.LD.Context{term_defs: term_defs}) do
|
def coercions(%JSON.LD.Context{term_defs: term_defs}) do
|
||||||
Enum.reduce term_defs, %{}, fn ({term, term_def}, type_mappings) ->
|
Enum.reduce(term_defs, %{}, fn {term, term_def}, type_mappings ->
|
||||||
Map.put type_mappings, term, term_def.type_mapping
|
Map.put(type_mappings, term, term_def.type_mapping)
|
||||||
end
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
def containers(%JSON.LD.Context{term_defs: term_defs}) do
|
def containers(%JSON.LD.Context{term_defs: term_defs}) do
|
||||||
Enum.reduce term_defs, %{}, fn ({term, term_def}, type_mappings) ->
|
Enum.reduce(term_defs, %{}, fn {term, term_def}, type_mappings ->
|
||||||
Map.put type_mappings, term, term_def.container_mapping
|
Map.put(type_mappings, term, term_def.container_mapping)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
|
||||||
|
|
|
@ -17,9 +17,8 @@ defmodule JSON.LD.DecoderTest do
|
||||||
|
|
||||||
alias TestNS.{EX, S}
|
alias TestNS.{EX, S}
|
||||||
|
|
||||||
|
|
||||||
test "an empty JSON document is deserialized to an empty graph" do
|
test "an empty JSON document is deserialized to an empty graph" do
|
||||||
assert JSON.LD.Decoder.decode!("{}") == Dataset.new
|
assert JSON.LD.Decoder.decode!("{}") == Dataset.new()
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "unnamed nodes" do
|
describe "unnamed nodes" do
|
||||||
|
@ -43,9 +42,9 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"http://example.com/foo": {"@id": "_:a"}
|
"http://example.com/foo": {"@id": "_:a"}
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.bnode("b0")}
|
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.bnode("b0")}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -61,9 +60,9 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"http://example.com/foo": "bar"
|
"http://example.com/foo": "bar"
|
||||||
}),
|
}),
|
||||||
{~I<http://example.com/a>, ~I<http://example.com/foo>, RDF.literal("bar")}
|
{~I<http://example.com/a>, ~I<http://example.com/foo>, RDF.literal("bar")}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -76,24 +75,24 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"@id": "",
|
"@id": "",
|
||||||
"@type": "#{RDF.uri(RDFS.Resource)}"
|
"@type": "#{RDF.uri(RDFS.Resource)}"
|
||||||
}),
|
}),
|
||||||
{~I<http://example.org/>, NS.RDF.type, RDF.uri(RDFS.Resource)}
|
{~I<http://example.org/>, NS.RDF.type(), RDF.uri(RDFS.Resource)}
|
||||||
},
|
},
|
||||||
"relative" => {
|
"relative" => {
|
||||||
~s({
|
~s({
|
||||||
"@id": "a/b",
|
"@id": "a/b",
|
||||||
"@type": "#{RDF.uri(RDFS.Resource)}"
|
"@type": "#{RDF.uri(RDFS.Resource)}"
|
||||||
}),
|
}),
|
||||||
{~I<http://example.org/a/b>, NS.RDF.type, RDF.uri(RDFS.Resource)}
|
{~I<http://example.org/a/b>, NS.RDF.type(), RDF.uri(RDFS.Resource)}
|
||||||
},
|
},
|
||||||
"hash" => {
|
"hash" => {
|
||||||
~s({
|
~s({
|
||||||
"@id": "#a",
|
"@id": "#a",
|
||||||
"@type": "#{RDF.uri(RDFS.Resource)}"
|
"@type": "#{RDF.uri(RDFS.Resource)}"
|
||||||
}),
|
}),
|
||||||
{~I<http://example.org/#a>, NS.RDF.type, RDF.uri(RDFS.Resource)}
|
{~I<http://example.org/#a>, NS.RDF.type(), RDF.uri(RDFS.Resource)}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test "when relative IRIs #{title}", %{data: {input, output}} do
|
test "when relative IRIs #{title}", %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input, base: "http://example.org/") ==
|
assert JSON.LD.Decoder.decode!(input, base: "http://example.org/") ==
|
||||||
|
@ -108,25 +107,25 @@ defmodule JSON.LD.DecoderTest do
|
||||||
~s({
|
~s({
|
||||||
"@type": "http://example.com/foo"
|
"@type": "http://example.com/foo"
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), NS.RDF.type, ~I<http://example.com/foo>}
|
{RDF.bnode("b0"), NS.RDF.type(), ~I<http://example.com/foo>}
|
||||||
},
|
},
|
||||||
"two types" => {
|
"two types" => {
|
||||||
~s({
|
~s({
|
||||||
"@type": ["http://example.com/foo", "http://example.com/baz"]
|
"@type": ["http://example.com/foo", "http://example.com/baz"]
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{RDF.bnode("b0"), NS.RDF.type, ~I<http://example.com/foo>},
|
{RDF.bnode("b0"), NS.RDF.type(), ~I<http://example.com/foo>},
|
||||||
{RDF.bnode("b0"), NS.RDF.type, ~I<http://example.com/baz>},
|
{RDF.bnode("b0"), NS.RDF.type(), ~I<http://example.com/baz>}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"blank node type" => {
|
"blank node type" => {
|
||||||
~s({
|
~s({
|
||||||
"@type": "_:foo"
|
"@type": "_:foo"
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b1"), NS.RDF.type, RDF.bnode("b0")}
|
{RDF.bnode("b1"), NS.RDF.type(), RDF.bnode("b0")}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -148,7 +147,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.literal("bar")},
|
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.literal("bar")},
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.literal("baz")},
|
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.literal("baz")}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"IRI" => {
|
"IRI" => {
|
||||||
|
@ -163,11 +162,11 @@ defmodule JSON.LD.DecoderTest do
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo>, ~I<http://example.com/bar>},
|
{RDF.bnode("b0"), ~I<http://example.com/foo>, ~I<http://example.com/bar>},
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo>, ~I<http://example.com/baz>},
|
{RDF.bnode("b0"), ~I<http://example.com/foo>, ~I<http://example.com/baz>}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -177,23 +176,21 @@ defmodule JSON.LD.DecoderTest do
|
||||||
|
|
||||||
describe "literals" do
|
describe "literals" do
|
||||||
%{
|
%{
|
||||||
"plain literal" =>
|
"plain literal" => {
|
||||||
{
|
|
||||||
~s({"@id": "http://greggkellogg.net/foaf#me", "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg"}),
|
~s({"@id": "http://greggkellogg.net/foaf#me", "http://xmlns.com/foaf/0.1/name": "Gregg Kellogg"}),
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/name>, RDF.literal("Gregg Kellogg")},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/name>,
|
||||||
|
RDF.literal("Gregg Kellogg")}
|
||||||
},
|
},
|
||||||
"explicit plain literal" =>
|
"explicit plain literal" => {
|
||||||
{
|
|
||||||
~s({"http://xmlns.com/foaf/0.1/name": {"@value": "Gregg Kellogg"}}),
|
~s({"http://xmlns.com/foaf/0.1/name": {"@value": "Gregg Kellogg"}}),
|
||||||
{RDF.bnode("b0"), ~I<http://xmlns.com/foaf/0.1/name>, RDF.literal("Gregg Kellogg")}
|
{RDF.bnode("b0"), ~I<http://xmlns.com/foaf/0.1/name>, RDF.literal("Gregg Kellogg")}
|
||||||
},
|
},
|
||||||
"language tagged literal" =>
|
"language tagged literal" => {
|
||||||
{
|
|
||||||
~s({"http://www.w3.org/2000/01/rdf-schema#label": {"@value": "A plain literal with a lang tag.", "@language": "en-us"}}),
|
~s({"http://www.w3.org/2000/01/rdf-schema#label": {"@value": "A plain literal with a lang tag.", "@language": "en-us"}}),
|
||||||
{RDF.bnode("b0"), RDFS.label, RDF.literal("A plain literal with a lang tag.", language: "en-us")}
|
{RDF.bnode("b0"), RDFS.label(),
|
||||||
|
RDF.literal("A plain literal with a lang tag.", language: "en-us")}
|
||||||
},
|
},
|
||||||
"I18N literal with language" =>
|
"I18N literal with language" => {
|
||||||
{
|
|
||||||
~s([{
|
~s([{
|
||||||
"@id": "http://greggkellogg.net/foaf#me",
|
"@id": "http://greggkellogg.net/foaf#me",
|
||||||
"http://xmlns.com/foaf/0.1/knows": {"@id": "http://www.ivan-herman.net/foaf#me"}
|
"http://xmlns.com/foaf/0.1/knows": {"@id": "http://www.ivan-herman.net/foaf#me"}
|
||||||
|
@ -202,20 +199,22 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"http://xmlns.com/foaf/0.1/name": {"@value": "Herman Iván", "@language": "hu"}
|
"http://xmlns.com/foaf/0.1/name": {"@value": "Herman Iván", "@language": "hu"}
|
||||||
}]),
|
}]),
|
||||||
[
|
[
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, ~I<http://www.ivan-herman.net/foaf#me>},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>,
|
||||||
{~I<http://www.ivan-herman.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/name>, RDF.literal("Herman Iv\u00E1n", language: "hu")},
|
~I<http://www.ivan-herman.net/foaf#me>},
|
||||||
|
{~I<http://www.ivan-herman.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/name>,
|
||||||
|
RDF.literal("Herman Iv\u00E1n", language: "hu")}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"explicit datatyped literal" =>
|
"explicit datatyped literal" => {
|
||||||
{
|
|
||||||
~s({
|
~s({
|
||||||
"@id": "http://greggkellogg.net/foaf#me",
|
"@id": "http://greggkellogg.net/foaf#me",
|
||||||
"http://purl.org/dc/terms/created": {"@value": "1957-02-27", "@type": "http://www.w3.org/2001/XMLSchema#date"}
|
"http://purl.org/dc/terms/created": {"@value": "1957-02-27", "@type": "http://www.w3.org/2001/XMLSchema#date"}
|
||||||
}),
|
}),
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://purl.org/dc/terms/created>, RDF.literal("1957-02-27", datatype: XSD.date)},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://purl.org/dc/terms/created>,
|
||||||
},
|
RDF.literal("1957-02-27", datatype: XSD.date())}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -239,8 +238,8 @@ defmodule JSON.LD.DecoderTest do
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/default#foo>, RDF.literal("bar")}
|
{RDF.bnode("b0"), ~I<http://example.com/default#foo>, RDF.literal("bar")}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
if title == "empty suffix", do: @tag :skip
|
if title == "empty suffix", do: @tag(:skip)
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -258,12 +257,13 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"name": "Gregg Kellogg"
|
"name": "Gregg Kellogg"
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{~I<http://example.com/about#gregg>, NS.RDF.type, ~I<http://schema.org/Person>},
|
{~I<http://example.com/about#gregg>, NS.RDF.type(), ~I<http://schema.org/Person>},
|
||||||
{~I<http://example.com/about#gregg>, ~I<http://schema.org/name>, RDF.literal("Gregg Kellogg")},
|
{~I<http://example.com/about#gregg>, ~I<http://schema.org/name>,
|
||||||
|
RDF.literal("Gregg Kellogg")}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -273,8 +273,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
|
|
||||||
describe "chaining" do
|
describe "chaining" do
|
||||||
%{
|
%{
|
||||||
"explicit subject" =>
|
"explicit subject" => {
|
||||||
{
|
|
||||||
~s({
|
~s({
|
||||||
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
|
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
|
||||||
"@id": "http://greggkellogg.net/foaf#me",
|
"@id": "http://greggkellogg.net/foaf#me",
|
||||||
|
@ -284,12 +283,13 @@ defmodule JSON.LD.DecoderTest do
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, ~I<http://www.ivan-herman.net/foaf#me>},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>,
|
||||||
{~I<http://www.ivan-herman.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/name>, RDF.literal("Ivan Herman")},
|
~I<http://www.ivan-herman.net/foaf#me>},
|
||||||
|
{~I<http://www.ivan-herman.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/name>,
|
||||||
|
RDF.literal("Ivan Herman")}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"implicit subject" =>
|
"implicit subject" => {
|
||||||
{
|
|
||||||
~s({
|
~s({
|
||||||
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
|
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
|
||||||
"@id": "http://greggkellogg.net/foaf#me",
|
"@id": "http://greggkellogg.net/foaf#me",
|
||||||
|
@ -298,12 +298,13 @@ defmodule JSON.LD.DecoderTest do
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, RDF.bnode("b0")},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>,
|
||||||
{RDF.bnode("b0"), ~I<http://xmlns.com/foaf/0.1/name>, RDF.literal("Manu Sporny")},
|
RDF.bnode("b0")},
|
||||||
|
{RDF.bnode("b0"), ~I<http://xmlns.com/foaf/0.1/name>, RDF.literal("Manu Sporny")}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -313,20 +314,21 @@ defmodule JSON.LD.DecoderTest do
|
||||||
|
|
||||||
describe "multiple values" do
|
describe "multiple values" do
|
||||||
%{
|
%{
|
||||||
"literals" =>
|
"literals" => {
|
||||||
{
|
|
||||||
~s({
|
~s({
|
||||||
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
|
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
|
||||||
"@id": "http://greggkellogg.net/foaf#me",
|
"@id": "http://greggkellogg.net/foaf#me",
|
||||||
"foaf:knows": ["Manu Sporny", "Ivan Herman"]
|
"foaf:knows": ["Manu Sporny", "Ivan Herman"]
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, RDF.literal("Manu Sporny")},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>,
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, RDF.literal("Ivan Herman")},
|
RDF.literal("Manu Sporny")},
|
||||||
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>,
|
||||||
|
RDF.literal("Ivan Herman")}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -342,7 +344,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"@id": "http://greggkellogg.net/foaf#me",
|
"@id": "http://greggkellogg.net/foaf#me",
|
||||||
"foaf:knows": {"@list": []}
|
"foaf:knows": {"@list": []}
|
||||||
}),
|
}),
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, NS.RDF.nil}
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, NS.RDF.nil()}
|
||||||
},
|
},
|
||||||
"single value" => {
|
"single value" => {
|
||||||
~s({
|
~s({
|
||||||
|
@ -351,9 +353,10 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"foaf:knows": {"@list": ["Manu Sporny"]}
|
"foaf:knows": {"@list": ["Manu Sporny"]}
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, RDF.bnode("b0")},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>,
|
||||||
{RDF.bnode("b0"), NS.RDF.first, RDF.literal("Manu Sporny")},
|
RDF.bnode("b0")},
|
||||||
{RDF.bnode("b0"), NS.RDF.rest, NS.RDF.nil},
|
{RDF.bnode("b0"), NS.RDF.first(), RDF.literal("Manu Sporny")},
|
||||||
|
{RDF.bnode("b0"), NS.RDF.rest(), NS.RDF.nil()}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"single value (with coercion)" => {
|
"single value (with coercion)" => {
|
||||||
|
@ -366,9 +369,10 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"foaf:knows": ["Manu Sporny"]
|
"foaf:knows": ["Manu Sporny"]
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, RDF.bnode("b0")},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>,
|
||||||
{RDF.bnode("b0"), NS.RDF.first, RDF.literal("Manu Sporny")},
|
RDF.bnode("b0")},
|
||||||
{RDF.bnode("b0"), NS.RDF.rest, NS.RDF.nil},
|
{RDF.bnode("b0"), NS.RDF.first(), RDF.literal("Manu Sporny")},
|
||||||
|
{RDF.bnode("b0"), NS.RDF.rest(), NS.RDF.nil()}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"multiple values" => {
|
"multiple values" => {
|
||||||
|
@ -378,15 +382,16 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"foaf:knows": {"@list": ["Manu Sporny", "Dave Longley"]}
|
"foaf:knows": {"@list": ["Manu Sporny", "Dave Longley"]}
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, RDF.bnode("b0")},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>,
|
||||||
{RDF.bnode("b0"), NS.RDF.first, RDF.literal("Manu Sporny")},
|
RDF.bnode("b0")},
|
||||||
{RDF.bnode("b0"), NS.RDF.rest, RDF.bnode("b1")},
|
{RDF.bnode("b0"), NS.RDF.first(), RDF.literal("Manu Sporny")},
|
||||||
{RDF.bnode("b1"), NS.RDF.first, RDF.literal("Dave Longley")},
|
{RDF.bnode("b0"), NS.RDF.rest(), RDF.bnode("b1")},
|
||||||
{RDF.bnode("b1"), NS.RDF.rest, NS.RDF.nil},
|
{RDF.bnode("b1"), NS.RDF.first(), RDF.literal("Dave Longley")},
|
||||||
|
{RDF.bnode("b1"), NS.RDF.rest(), NS.RDF.nil()}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -396,8 +401,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
|
|
||||||
describe "context" do
|
describe "context" do
|
||||||
%{
|
%{
|
||||||
"@id coersion" =>
|
"@id coersion" => {
|
||||||
{
|
|
||||||
~s({
|
~s({
|
||||||
"@context": {
|
"@context": {
|
||||||
"knows": {"@id": "http://xmlns.com/foaf/0.1/knows", "@type": "@id"}
|
"knows": {"@id": "http://xmlns.com/foaf/0.1/knows", "@type": "@id"}
|
||||||
|
@ -405,10 +409,10 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"@id": "http://greggkellogg.net/foaf#me",
|
"@id": "http://greggkellogg.net/foaf#me",
|
||||||
"knows": "http://www.ivan-herman.net/foaf#me"
|
"knows": "http://www.ivan-herman.net/foaf#me"
|
||||||
}),
|
}),
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>, ~I<http://www.ivan-herman.net/foaf#me>},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://xmlns.com/foaf/0.1/knows>,
|
||||||
|
~I<http://www.ivan-herman.net/foaf#me>}
|
||||||
},
|
},
|
||||||
"datatype coersion" =>
|
"datatype coersion" => {
|
||||||
{
|
|
||||||
~s({
|
~s({
|
||||||
"@context": {
|
"@context": {
|
||||||
"dcterms": "http://purl.org/dc/terms/",
|
"dcterms": "http://purl.org/dc/terms/",
|
||||||
|
@ -418,7 +422,8 @@ defmodule JSON.LD.DecoderTest do
|
||||||
"@id": "http://greggkellogg.net/foaf#me",
|
"@id": "http://greggkellogg.net/foaf#me",
|
||||||
"created": "1957-02-27"
|
"created": "1957-02-27"
|
||||||
}),
|
}),
|
||||||
{~I<http://greggkellogg.net/foaf#me>, ~I<http://purl.org/dc/terms/created>, RDF.literal("1957-02-27", datatype: XSD.date)},
|
{~I<http://greggkellogg.net/foaf#me>, ~I<http://purl.org/dc/terms/created>,
|
||||||
|
RDF.literal("1957-02-27", datatype: XSD.date())}
|
||||||
},
|
},
|
||||||
"sub-objects with context" => {
|
"sub-objects with context" => {
|
||||||
~s({
|
~s({
|
||||||
|
@ -430,7 +435,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.bnode("b1")},
|
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.bnode("b1")},
|
||||||
{RDF.bnode("b1"), ~I<http://example.org/foo>, RDF.literal("bar")},
|
{RDF.bnode("b1"), ~I<http://example.org/foo>, RDF.literal("bar")}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"contexts with a list processed in order" => {
|
"contexts with a list processed in order" => {
|
||||||
|
@ -441,7 +446,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
],
|
],
|
||||||
"foo": "bar"
|
"foo": "bar"
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://example.org/foo>, RDF.literal("bar")},
|
{RDF.bnode("b0"), ~I<http://example.org/foo>, RDF.literal("bar")}
|
||||||
},
|
},
|
||||||
"term definition resolves term as IRI" => {
|
"term definition resolves term as IRI" => {
|
||||||
~s({
|
~s({
|
||||||
|
@ -451,7 +456,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
],
|
],
|
||||||
"bar": "bar"
|
"bar": "bar"
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.literal("bar")},
|
{RDF.bnode("b0"), ~I<http://example.com/foo>, RDF.literal("bar")}
|
||||||
},
|
},
|
||||||
"term definition resolves prefix as IRI" => {
|
"term definition resolves prefix as IRI" => {
|
||||||
~s({
|
~s({
|
||||||
|
@ -461,7 +466,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
],
|
],
|
||||||
"bar": "bar"
|
"bar": "bar"
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo#bar>, RDF.literal("bar")},
|
{RDF.bnode("b0"), ~I<http://example.com/foo#bar>, RDF.literal("bar")}
|
||||||
},
|
},
|
||||||
"@language" => {
|
"@language" => {
|
||||||
~s({
|
~s({
|
||||||
|
@ -471,7 +476,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
},
|
},
|
||||||
"foo:bar": "baz"
|
"foo:bar": "baz"
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo#bar>, RDF.literal("baz", language: "en")},
|
{RDF.bnode("b0"), ~I<http://example.com/foo#bar>, RDF.literal("baz", language: "en")}
|
||||||
},
|
},
|
||||||
"@language with override" => {
|
"@language with override" => {
|
||||||
~s({
|
~s({
|
||||||
|
@ -481,7 +486,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
},
|
},
|
||||||
"foo:bar": {"@value": "baz", "@language": "fr"}
|
"foo:bar": {"@value": "baz", "@language": "fr"}
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo#bar>, RDF.literal("baz", language: "fr")},
|
{RDF.bnode("b0"), ~I<http://example.com/foo#bar>, RDF.literal("baz", language: "fr")}
|
||||||
},
|
},
|
||||||
"@language with plain" => {
|
"@language with plain" => {
|
||||||
~s({
|
~s({
|
||||||
|
@ -491,10 +496,10 @@ defmodule JSON.LD.DecoderTest do
|
||||||
},
|
},
|
||||||
"foo:bar": {"@value": "baz"}
|
"foo:bar": {"@value": "baz"}
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://example.com/foo#bar>, RDF.literal("baz")},
|
{RDF.bnode("b0"), ~I<http://example.com/foo#bar>, RDF.literal("baz")}
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -510,7 +515,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
],
|
],
|
||||||
"foo": "bar"
|
"foo": "bar"
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://example.org/foo#>, RDF.literal("bar", datatype: XSD.date)},
|
{RDF.bnode("b0"), ~I<http://example.org/foo#>, RDF.literal("bar", datatype: XSD.date())}
|
||||||
},
|
},
|
||||||
"@id with term" => {
|
"@id with term" => {
|
||||||
~s({
|
~s({
|
||||||
|
@ -519,7 +524,7 @@ defmodule JSON.LD.DecoderTest do
|
||||||
],
|
],
|
||||||
"foo": "http://example.org/foo#bar"
|
"foo": "http://example.org/foo#bar"
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://example.org/foo#bar>, ~I<http://example.org/foo#bar>},
|
{RDF.bnode("b0"), ~I<http://example.org/foo#bar>, ~I<http://example.org/foo#bar>}
|
||||||
},
|
},
|
||||||
"coercion without term definition" => {
|
"coercion without term definition" => {
|
||||||
~s({
|
~s({
|
||||||
|
@ -534,10 +539,11 @@ defmodule JSON.LD.DecoderTest do
|
||||||
],
|
],
|
||||||
"dc:date": "2011-11-23"
|
"dc:date": "2011-11-23"
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://purl.org/dc/terms/date>, RDF.literal("2011-11-23", datatype: XSD.date)},
|
{RDF.bnode("b0"), ~I<http://purl.org/dc/terms/date>,
|
||||||
},
|
RDF.literal("2011-11-23", datatype: XSD.date())}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test "term def with @id + @type coercion: #{title}", %{data: {input, output}} do
|
test "term def with @id + @type coercion: #{title}", %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -555,8 +561,8 @@ defmodule JSON.LD.DecoderTest do
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{RDF.bnode("b0"), ~I<http://example.org/foo#>, RDF.bnode("b1")},
|
{RDF.bnode("b0"), ~I<http://example.org/foo#>, RDF.bnode("b1")},
|
||||||
{RDF.bnode("b1"), NS.RDF.first, RDF.literal("bar", datatype: XSD.date)},
|
{RDF.bnode("b1"), NS.RDF.first(), RDF.literal("bar", datatype: XSD.date())},
|
||||||
{RDF.bnode("b1"), NS.RDF.rest, NS.RDF.nil},
|
{RDF.bnode("b1"), NS.RDF.rest(), NS.RDF.nil()}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"@id with term" => {
|
"@id with term" => {
|
||||||
|
@ -568,12 +574,12 @@ defmodule JSON.LD.DecoderTest do
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{RDF.bnode("b0"), ~I<http://example.org/foo#bar>, RDF.bnode("b1")},
|
{RDF.bnode("b0"), ~I<http://example.org/foo#bar>, RDF.bnode("b1")},
|
||||||
{RDF.bnode("b1"), NS.RDF.first, ~I<http://example.org/foo#bar>},
|
{RDF.bnode("b1"), NS.RDF.first(), ~I<http://example.org/foo#bar>},
|
||||||
{RDF.bnode("b1"), NS.RDF.rest, NS.RDF.nil},
|
{RDF.bnode("b1"), NS.RDF.rest(), NS.RDF.nil()}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test "term def with @id + @type + @container list: #{title}", %{data: {input, output}} do
|
test "term def with @id + @type + @container list: #{title}", %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
|
@ -601,39 +607,37 @@ defmodule JSON.LD.DecoderTest do
|
||||||
|
|
||||||
describe "advanced features" do
|
describe "advanced features" do
|
||||||
%{
|
%{
|
||||||
"number syntax (decimal)" =>
|
"number syntax (decimal)" => {
|
||||||
{
|
|
||||||
~s({"@context": { "measure": "http://example/measure#"}, "measure:cups": 5.3}),
|
~s({"@context": { "measure": "http://example/measure#"}, "measure:cups": 5.3}),
|
||||||
{RDF.bnode("b0"), ~I<http://example/measure#cups>, RDF.literal("5.3E0", datatype: XSD.double)}
|
{RDF.bnode("b0"), ~I<http://example/measure#cups>,
|
||||||
|
RDF.literal("5.3E0", datatype: XSD.double())}
|
||||||
},
|
},
|
||||||
"number syntax (double)" =>
|
"number syntax (double)" => {
|
||||||
{
|
|
||||||
~s({"@context": { "measure": "http://example/measure#"}, "measure:cups": 5.3e0}),
|
~s({"@context": { "measure": "http://example/measure#"}, "measure:cups": 5.3e0}),
|
||||||
{RDF.bnode("b0"), ~I<http://example/measure#cups>, RDF.literal("5.3E0", datatype: XSD.double)}
|
{RDF.bnode("b0"), ~I<http://example/measure#cups>,
|
||||||
|
RDF.literal("5.3E0", datatype: XSD.double())}
|
||||||
},
|
},
|
||||||
"number syntax (integer)" =>
|
"number syntax (integer)" => {
|
||||||
{
|
|
||||||
~s({"@context": { "chem": "http://example/chem#"}, "chem:protons": 12}),
|
~s({"@context": { "chem": "http://example/chem#"}, "chem:protons": 12}),
|
||||||
{RDF.bnode("b0"), ~I<http://example/chem#protons>, RDF.literal("12", datatype: XSD.integer)}
|
{RDF.bnode("b0"), ~I<http://example/chem#protons>,
|
||||||
|
RDF.literal("12", datatype: XSD.integer())}
|
||||||
},
|
},
|
||||||
"boolan syntax" =>
|
"boolan syntax" => {
|
||||||
{
|
|
||||||
~s({"@context": { "sensor": "http://example/sensor#"}, "sensor:active": true}),
|
~s({"@context": { "sensor": "http://example/sensor#"}, "sensor:active": true}),
|
||||||
{RDF.bnode("b0"), ~I<http://example/sensor#active>, RDF.literal("true", datatype: XSD.boolean)}
|
{RDF.bnode("b0"), ~I<http://example/sensor#active>,
|
||||||
|
RDF.literal("true", datatype: XSD.boolean())}
|
||||||
},
|
},
|
||||||
"Array top element" =>
|
"Array top element" => {
|
||||||
{
|
|
||||||
~s([
|
~s([
|
||||||
{"@id": "http://example.com/#me", "@type": "http://xmlns.com/foaf/0.1/Person"},
|
{"@id": "http://example.com/#me", "@type": "http://xmlns.com/foaf/0.1/Person"},
|
||||||
{"@id": "http://example.com/#you", "@type": "http://xmlns.com/foaf/0.1/Person"}
|
{"@id": "http://example.com/#you", "@type": "http://xmlns.com/foaf/0.1/Person"}
|
||||||
]),
|
]),
|
||||||
[
|
[
|
||||||
{~I<http://example.com/#me>, NS.RDF.type, ~I<http://xmlns.com/foaf/0.1/Person>},
|
{~I<http://example.com/#me>, NS.RDF.type(), ~I<http://xmlns.com/foaf/0.1/Person>},
|
||||||
{~I<http://example.com/#you>, NS.RDF.type, ~I<http://xmlns.com/foaf/0.1/Person>}
|
{~I<http://example.com/#you>, NS.RDF.type(), ~I<http://xmlns.com/foaf/0.1/Person>}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"@graph with array of objects value" =>
|
"@graph with array of objects value" => {
|
||||||
{
|
|
||||||
~s({
|
~s({
|
||||||
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
|
"@context": {"foaf": "http://xmlns.com/foaf/0.1/"},
|
||||||
"@graph": [
|
"@graph": [
|
||||||
|
@ -642,27 +646,26 @@ defmodule JSON.LD.DecoderTest do
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{~I<http://example.com/#me>, NS.RDF.type, ~I<http://xmlns.com/foaf/0.1/Person>},
|
{~I<http://example.com/#me>, NS.RDF.type(), ~I<http://xmlns.com/foaf/0.1/Person>},
|
||||||
{~I<http://example.com/#you>, NS.RDF.type, ~I<http://xmlns.com/foaf/0.1/Person>}
|
{~I<http://example.com/#you>, NS.RDF.type(), ~I<http://xmlns.com/foaf/0.1/Person>}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"XMLLiteral" =>
|
"XMLLiteral" => {
|
||||||
{
|
|
||||||
~s({
|
~s({
|
||||||
"http://rdfs.org/sioc/ns#content": {
|
"http://rdfs.org/sioc/ns#content": {
|
||||||
"@value": "foo",
|
"@value": "foo",
|
||||||
"@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral"
|
"@type": "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral"
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
{RDF.bnode("b0"), ~I<http://rdfs.org/sioc/ns#content>, RDF.literal("foo", datatype: "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral")}
|
{RDF.bnode("b0"), ~I<http://rdfs.org/sioc/ns#content>,
|
||||||
|
RDF.literal("foo", datatype: "http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral")}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
assert JSON.LD.Decoder.decode!(input) == RDF.Dataset.new(output)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -19,16 +19,16 @@ defmodule JSON.LD.EncoderTest do
|
||||||
@compile {:no_warn_undefined, JSON.LD.EncoderTest.TestNS.EX}
|
@compile {:no_warn_undefined, JSON.LD.EncoderTest.TestNS.EX}
|
||||||
@compile {:no_warn_undefined, JSON.LD.EncoderTest.TestNS.S}
|
@compile {:no_warn_undefined, JSON.LD.EncoderTest.TestNS.S}
|
||||||
|
|
||||||
|
|
||||||
def gets_serialized_to(input, output, opts \\ []) do
|
def gets_serialized_to(input, output, opts \\ []) do
|
||||||
data_structs = Keyword.get(opts, :data_structs, [Dataset, Graph])
|
data_structs = Keyword.get(opts, :data_structs, [Dataset, Graph])
|
||||||
Enum.each data_structs, fn data_struct ->
|
|
||||||
|
Enum.each(data_structs, fn data_struct ->
|
||||||
assert JSON.LD.Encoder.from_rdf!(data_struct.new(input), opts) == output
|
assert JSON.LD.Encoder.from_rdf!(data_struct.new(input), opts) == output
|
||||||
end
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "pretty printing" do
|
test "pretty printing" do
|
||||||
dataset = Dataset.new {~I<http://a/b>, ~I<http://a/c>, ~I<http://a/d>}
|
dataset = Dataset.new({~I<http://a/b>, ~I<http://a/c>, ~I<http://a/d>})
|
||||||
|
|
||||||
assert JSON.LD.Encoder.encode!(dataset) ==
|
assert JSON.LD.Encoder.encode!(dataset) ==
|
||||||
"[{\"@id\":\"http://a/b\",\"http://a/c\":[{\"@id\":\"http://a/d\"}]}]"
|
"[{\"@id\":\"http://a/b\",\"http://a/c\":[{\"@id\":\"http://a/d\"}]}]"
|
||||||
|
@ -45,119 +45,193 @@ defmodule JSON.LD.EncoderTest do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
""" |> String.trim()
|
"""
|
||||||
|
|> String.trim()
|
||||||
end
|
end
|
||||||
|
|
||||||
test "an empty RDF.Dataset is serialized to an JSON array string" do
|
test "an empty RDF.Dataset is serialized to an JSON array string" do
|
||||||
assert JSON.LD.Encoder.encode!(Dataset.new) == "[]"
|
assert JSON.LD.Encoder.encode!(Dataset.new()) == "[]"
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "simple tests" do
|
describe "simple tests" do
|
||||||
test "One subject IRI object" do
|
test "One subject IRI object" do
|
||||||
{~I<http://a/b>, ~I<http://a/c>, ~I<http://a/d>}
|
{~I<http://a/b>, ~I<http://a/c>, ~I<http://a/d>}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://a/b",
|
"@id" => "http://a/b",
|
||||||
"http://a/c" => [%{"@id" => "http://a/d"}]
|
"http://a/c" => [%{"@id" => "http://a/d"}]
|
||||||
}], data_structs: [Dataset, Graph, Description])
|
}
|
||||||
|
],
|
||||||
|
data_structs: [Dataset, Graph, Description]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "should generate object list" do
|
test "should generate object list" do
|
||||||
[{EX.b, EX.c, EX.d}, {EX.b, EX.c, EX.e}]
|
[{EX.b(), EX.c(), EX.d()}, {EX.b(), EX.c(), EX.e()}]
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/b",
|
"@id" => "http://example.com/b",
|
||||||
"http://example.com/c" => [
|
"http://example.com/c" => [
|
||||||
%{"@id" => "http://example.com/d"},
|
%{"@id" => "http://example.com/d"},
|
||||||
%{"@id" => "http://example.com/e"}
|
%{"@id" => "http://example.com/e"}
|
||||||
]
|
]
|
||||||
}], data_structs: [Dataset, Graph, Description])
|
}
|
||||||
|
],
|
||||||
|
data_structs: [Dataset, Graph, Description]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "should generate property list" do
|
test "should generate property list" do
|
||||||
[{EX.b, EX.c, EX.d}, {EX.b, EX.e, EX.f}]
|
[{EX.b(), EX.c(), EX.d()}, {EX.b(), EX.e(), EX.f()}]
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/b",
|
"@id" => "http://example.com/b",
|
||||||
"http://example.com/c" => [%{"@id" => "http://example.com/d"}],
|
"http://example.com/c" => [%{"@id" => "http://example.com/d"}],
|
||||||
"http://example.com/e" => [%{"@id" => "http://example.com/f"}]
|
"http://example.com/e" => [%{"@id" => "http://example.com/f"}]
|
||||||
}], data_structs: [Dataset, Graph, Description])
|
}
|
||||||
|
],
|
||||||
|
data_structs: [Dataset, Graph, Description]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "serializes multiple subjects" do
|
test "serializes multiple subjects" do
|
||||||
[
|
[
|
||||||
{~I<http://test-cases/0001>, NS.RDF.type, ~I<http://www.w3.org/2006/03/test-description#TestCase>},
|
{~I<http://test-cases/0001>, NS.RDF.type(),
|
||||||
{~I<http://test-cases/0002>, NS.RDF.type, ~I<http://www.w3.org/2006/03/test-description#TestCase>}
|
~I<http://www.w3.org/2006/03/test-description#TestCase>},
|
||||||
|
{~I<http://test-cases/0002>, NS.RDF.type(),
|
||||||
|
~I<http://www.w3.org/2006/03/test-description#TestCase>}
|
||||||
]
|
]
|
||||||
|> gets_serialized_to([
|
|> gets_serialized_to([
|
||||||
%{"@id" => "http://test-cases/0001", "@type" => ["http://www.w3.org/2006/03/test-description#TestCase"]},
|
%{
|
||||||
%{"@id" => "http://test-cases/0002", "@type" => ["http://www.w3.org/2006/03/test-description#TestCase"]},
|
"@id" => "http://test-cases/0001",
|
||||||
|
"@type" => ["http://www.w3.org/2006/03/test-description#TestCase"]
|
||||||
|
},
|
||||||
|
%{
|
||||||
|
"@id" => "http://test-cases/0002",
|
||||||
|
"@type" => ["http://www.w3.org/2006/03/test-description#TestCase"]
|
||||||
|
}
|
||||||
])
|
])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "literal coercion" do
|
describe "literal coercion" do
|
||||||
test "typed literal" do
|
test "typed literal" do
|
||||||
{EX.a, EX.b, RDF.literal("foo", datatype: EX.d)}
|
{EX.a(), EX.b(), RDF.literal("foo", datatype: EX.d())}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => "foo", "@type" => "http://example.com/d"}]
|
"http://example.com/b" => [%{"@value" => "foo", "@type" => "http://example.com/d"}]
|
||||||
}], data_structs: [Dataset, Graph, Description])
|
}
|
||||||
|
],
|
||||||
|
data_structs: [Dataset, Graph, Description]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "integer" do
|
test "integer" do
|
||||||
{EX.a, EX.b, RDF.literal(1)}
|
{EX.a(), EX.b(), RDF.literal(1)}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => 1}]
|
"http://example.com/b" => [%{"@value" => 1}]
|
||||||
}], use_native_types: true)
|
}
|
||||||
|
],
|
||||||
|
use_native_types: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "integer (non-native)" do
|
test "integer (non-native)" do
|
||||||
{EX.a, EX.b, RDF.literal(1)}
|
{EX.a(), EX.b(), RDF.literal(1)}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => "1","@type" => "http://www.w3.org/2001/XMLSchema#integer"}]
|
"http://example.com/b" => [
|
||||||
}], use_native_types: false)
|
%{"@value" => "1", "@type" => "http://www.w3.org/2001/XMLSchema#integer"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
use_native_types: false
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "boolean" do
|
test "boolean" do
|
||||||
{EX.a, EX.b, RDF.literal(true)}
|
{EX.a(), EX.b(), RDF.literal(true)}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => true}]
|
"http://example.com/b" => [%{"@value" => true}]
|
||||||
}], use_native_types: true)
|
}
|
||||||
|
],
|
||||||
|
use_native_types: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "boolean (non-native)" do
|
test "boolean (non-native)" do
|
||||||
{EX.a, EX.b, RDF.literal(true)}
|
{EX.a(), EX.b(), RDF.literal(true)}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => "true","@type" => "http://www.w3.org/2001/XMLSchema#boolean"}]
|
"http://example.com/b" => [
|
||||||
}], use_native_types: false)
|
%{"@value" => "true", "@type" => "http://www.w3.org/2001/XMLSchema#boolean"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
use_native_types: false
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag skip: "TODO: Is this spec conformant or RDF.rb specific? RDF.rb doesn't use the specified RDF to Object Conversion algorithm but reuses a generalized expand_value algorithm"
|
@tag skip:
|
||||||
|
"TODO: Is this spec conformant or RDF.rb specific? RDF.rb doesn't use the specified RDF to Object Conversion algorithm but reuses a generalized expand_value algorithm"
|
||||||
test "decimal" do
|
test "decimal" do
|
||||||
{EX.a, EX.b, RDF.literal(1.0)}
|
{EX.a(), EX.b(), RDF.literal(1.0)}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => "1.0", "@type" => "http://www.w3.org/2001/XMLSchema#decimal"}]
|
"http://example.com/b" => [
|
||||||
}], use_native_types: true)
|
%{"@value" => "1.0", "@type" => "http://www.w3.org/2001/XMLSchema#decimal"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
use_native_types: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "double" do
|
test "double" do
|
||||||
{EX.a, EX.b, RDF.literal(1.0e0)}
|
{EX.a(), EX.b(), RDF.literal(1.0e0)}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => 1.0E0}]
|
"http://example.com/b" => [%{"@value" => 1.0e0}]
|
||||||
}], use_native_types: true)
|
}
|
||||||
|
],
|
||||||
|
use_native_types: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag skip: "TODO: Is this spec conformant or RDF.rb specific? RDF.rb doesn't use the specified RDF to Object Conversion algorithm but reuses a generalized expand_value algorithm"
|
@tag skip:
|
||||||
|
"TODO: Is this spec conformant or RDF.rb specific? RDF.rb doesn't use the specified RDF to Object Conversion algorithm but reuses a generalized expand_value algorithm"
|
||||||
test "double (non-native)" do
|
test "double (non-native)" do
|
||||||
{EX.a, EX.b, RDF.literal(1.0e0)}
|
{EX.a(), EX.b(), RDF.literal(1.0e0)}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => "1.0E0", "@type" => "http://www.w3.org/2001/XMLSchema#double"}]
|
"http://example.com/b" => [
|
||||||
}], use_native_types: false)
|
%{"@value" => "1.0E0", "@type" => "http://www.w3.org/2001/XMLSchema#double"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
use_native_types: false
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -168,50 +242,70 @@ defmodule JSON.LD.EncoderTest do
|
||||||
nonNegativeInteger: 1,
|
nonNegativeInteger: 1,
|
||||||
float: 1.0,
|
float: 1.0,
|
||||||
nonPositiveInteger: -1,
|
nonPositiveInteger: -1,
|
||||||
negativeInteger: -1,
|
negativeInteger: -1
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({type, _} = data) ->
|
|> Enum.each(fn {type, _} = data ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test "#{type}", %{data: {type, value}} do
|
test "#{type}", %{data: {type, value}} do
|
||||||
{EX.a, EX.b, RDF.literal(value, datatype: apply(NS.XSD, type, []))}
|
{EX.a(), EX.b(), RDF.literal(value, datatype: apply(NS.XSD, type, []))}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => "#{value}", "@type" => "http://www.w3.org/2001/XMLSchema##{type}"}]
|
"http://example.com/b" => [
|
||||||
}], use_native_types: false)
|
%{"@value" => "#{value}", "@type" => "http://www.w3.org/2001/XMLSchema##{type}"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
use_native_types: false
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
test "when useNativeTypes" do
|
test "when useNativeTypes" do
|
||||||
{EX.a, EX.b, RDF.literal("foo", datatype: EX.customType)}
|
{EX.a(), EX.b(), RDF.literal("foo", datatype: EX.customType())}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => "foo", "@type" => to_string(EX.customType)}]
|
"http://example.com/b" => [
|
||||||
}], use_native_types: true)
|
%{"@value" => "foo", "@type" => to_string(EX.customType())}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
use_native_types: true
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
test "encodes language literal" do
|
test "encodes language literal" do
|
||||||
{EX.a, EX.b, RDF.literal("foo", language: "en-us")}
|
{EX.a(), EX.b(), RDF.literal("foo", language: "en-us")}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to([
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@value" => "foo", "@language" => "en-us"}]
|
"http://example.com/b" => [%{"@value" => "foo", "@language" => "en-us"}]
|
||||||
}])
|
}
|
||||||
|
])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
describe "blank nodes" do
|
describe "blank nodes" do
|
||||||
test "should generate blank nodes" do
|
test "should generate blank nodes" do
|
||||||
{RDF.bnode(:a), EX.a, EX.b}
|
{RDF.bnode(:a), EX.a(), EX.b()}
|
||||||
|> gets_serialized_to([%{
|
|> gets_serialized_to(
|
||||||
|
[
|
||||||
|
%{
|
||||||
"@id" => "_:a",
|
"@id" => "_:a",
|
||||||
"http://example.com/a" => [%{"@id" => "http://example.com/b"}]
|
"http://example.com/a" => [%{"@id" => "http://example.com/b"}]
|
||||||
}], data_structs: [Dataset, Graph, Description])
|
}
|
||||||
|
],
|
||||||
|
data_structs: [Dataset, Graph, Description]
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
test "should generate blank nodes as object" do
|
test "should generate blank nodes as object" do
|
||||||
[
|
[
|
||||||
{EX.a, EX.b, RDF.bnode(:a)},
|
{EX.a(), EX.b(), RDF.bnode(:a)},
|
||||||
{RDF.bnode(:a), EX.c, EX.d}
|
{RDF.bnode(:a), EX.c(), EX.d()}
|
||||||
]
|
]
|
||||||
|> gets_serialized_to([
|
|> gets_serialized_to([
|
||||||
%{
|
%{
|
||||||
|
@ -230,63 +324,75 @@ defmodule JSON.LD.EncoderTest do
|
||||||
%{
|
%{
|
||||||
"literal list" => {
|
"literal list" => {
|
||||||
[
|
[
|
||||||
{EX.a, EX.b, RDF.bnode(:e1) },
|
{EX.a(), EX.b(), RDF.bnode(:e1)},
|
||||||
{RDF.bnode(:e1), NS.RDF.first, ~L"apple"},
|
{RDF.bnode(:e1), NS.RDF.first(), ~L"apple"},
|
||||||
{RDF.bnode(:e1), NS.RDF.rest, RDF.bnode(:e2)},
|
{RDF.bnode(:e1), NS.RDF.rest(), RDF.bnode(:e2)},
|
||||||
{RDF.bnode(:e2), NS.RDF.first, ~L"banana"},
|
{RDF.bnode(:e2), NS.RDF.first(), ~L"banana"},
|
||||||
{RDF.bnode(:e2), NS.RDF.rest, NS.RDF.nil},
|
{RDF.bnode(:e2), NS.RDF.rest(), NS.RDF.nil()}
|
||||||
],
|
],
|
||||||
[%{
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{
|
"http://example.com/b" => [
|
||||||
|
%{
|
||||||
"@list" => [
|
"@list" => [
|
||||||
%{"@value" => "apple"},
|
%{"@value" => "apple"},
|
||||||
%{"@value" => "banana"}
|
%{"@value" => "banana"}
|
||||||
]
|
]
|
||||||
}]
|
}
|
||||||
}]
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"iri list" => {
|
"iri list" => {
|
||||||
[
|
[
|
||||||
{EX.a, EX.b, RDF.bnode(:list)},
|
{EX.a(), EX.b(), RDF.bnode(:list)},
|
||||||
{RDF.bnode(:list), NS.RDF.first, EX.c},
|
{RDF.bnode(:list), NS.RDF.first(), EX.c()},
|
||||||
{RDF.bnode(:list), NS.RDF.rest, NS.RDF.nil},
|
{RDF.bnode(:list), NS.RDF.rest(), NS.RDF.nil()}
|
||||||
],
|
],
|
||||||
[%{
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{
|
"http://example.com/b" => [
|
||||||
|
%{
|
||||||
"@list" => [
|
"@list" => [
|
||||||
%{"@id" => "http://example.com/c"}
|
%{"@id" => "http://example.com/c"}
|
||||||
]
|
]
|
||||||
}]
|
}
|
||||||
}]
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"empty list" => {
|
"empty list" => {
|
||||||
[
|
[
|
||||||
{EX.a, EX.b, NS.RDF.nil},
|
{EX.a(), EX.b(), NS.RDF.nil()}
|
||||||
],
|
],
|
||||||
[%{
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@list" => []}]
|
"http://example.com/b" => [%{"@list" => []}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"single element list" => {
|
"single element list" => {
|
||||||
[
|
[
|
||||||
{EX.a, EX.b, RDF.bnode(:list)},
|
{EX.a(), EX.b(), RDF.bnode(:list)},
|
||||||
{RDF.bnode(:list), NS.RDF.first, ~L"apple"},
|
{RDF.bnode(:list), NS.RDF.first(), ~L"apple"},
|
||||||
{RDF.bnode(:list), NS.RDF.rest, NS.RDF.nil},
|
{RDF.bnode(:list), NS.RDF.rest(), NS.RDF.nil()}
|
||||||
],
|
],
|
||||||
[%{
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@list" => [%{"@value" => "apple"}]}]
|
"http://example.com/b" => [%{"@list" => [%{"@value" => "apple"}]}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"single element list without @type" => {
|
"single element list without @type" => {
|
||||||
[
|
[
|
||||||
{EX.a, EX.b, RDF.bnode(:list)},
|
{EX.a(), EX.b(), RDF.bnode(:list)},
|
||||||
{RDF.bnode(:list), NS.RDF.first, RDF.bnode(:a)},
|
{RDF.bnode(:list), NS.RDF.first(), RDF.bnode(:a)},
|
||||||
{RDF.bnode(:list), NS.RDF.rest, NS.RDF.nil},
|
{RDF.bnode(:list), NS.RDF.rest(), NS.RDF.nil()},
|
||||||
{RDF.bnode(:a), EX.b, ~L"foo"},
|
{RDF.bnode(:a), EX.b(), ~L"foo"}
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
%{
|
%{
|
||||||
|
@ -296,46 +402,55 @@ defmodule JSON.LD.EncoderTest do
|
||||||
%{
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@list" => [%{"@id" => "_:a"}]}]
|
"http://example.com/b" => [%{"@list" => [%{"@id" => "_:a"}]}]
|
||||||
},
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"multiple graphs with shared BNode" => {
|
"multiple graphs with shared BNode" => {
|
||||||
[
|
[
|
||||||
{EX.z, EX.q, RDF.bnode(:z0), EX.G},
|
{EX.z(), EX.q(), RDF.bnode(:z0), EX.G},
|
||||||
{RDF.bnode(:z0), NS.RDF.first, ~L"cell-A", EX.G},
|
{RDF.bnode(:z0), NS.RDF.first(), ~L"cell-A", EX.G},
|
||||||
{RDF.bnode(:z0), NS.RDF.rest, RDF.bnode(:z1), EX.G},
|
{RDF.bnode(:z0), NS.RDF.rest(), RDF.bnode(:z1), EX.G},
|
||||||
{RDF.bnode(:z1), NS.RDF.first, ~L"cell-B", EX.G},
|
{RDF.bnode(:z1), NS.RDF.first(), ~L"cell-B", EX.G},
|
||||||
{RDF.bnode(:z1), NS.RDF.rest, NS.RDF.nil, EX.G},
|
{RDF.bnode(:z1), NS.RDF.rest(), NS.RDF.nil(), EX.G},
|
||||||
{EX.x, EX.p, RDF.bnode(:z1), EX.G1},
|
{EX.x(), EX.p(), RDF.bnode(:z1), EX.G1}
|
||||||
],
|
],
|
||||||
[%{
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://www.example.com/G",
|
"@id" => "http://www.example.com/G",
|
||||||
"@graph" => [%{
|
"@graph" => [
|
||||||
|
%{
|
||||||
"@id" => "_:z0",
|
"@id" => "_:z0",
|
||||||
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first" => [%{"@value" => "cell-A"}],
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first" => [%{"@value" => "cell-A"}],
|
||||||
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" => [%{"@id" => "_:z1"}]
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" => [%{"@id" => "_:z1"}]
|
||||||
}, %{
|
},
|
||||||
|
%{
|
||||||
"@id" => "_:z1",
|
"@id" => "_:z1",
|
||||||
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first" => [%{"@value" => "cell-B"}],
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#first" => [%{"@value" => "cell-B"}],
|
||||||
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" => [%{"@list" => []}]
|
"http://www.w3.org/1999/02/22-rdf-syntax-ns#rest" => [%{"@list" => []}]
|
||||||
}, %{
|
},
|
||||||
|
%{
|
||||||
"@id" => "http://www.example.com/z",
|
"@id" => "http://www.example.com/z",
|
||||||
"http://www.example.com/q" => [%{"@id" => "_:z0"}]
|
"http://www.example.com/q" => [%{"@id" => "_:z0"}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"@id" => "http://www.example.com/G1",
|
"@id" => "http://www.example.com/G1",
|
||||||
"@graph" => [%{
|
"@graph" => [
|
||||||
|
%{
|
||||||
"@id" => "http://www.example.com/x",
|
"@id" => "http://www.example.com/x",
|
||||||
"http://www.example.com/p" => [%{"@id" => "_:z1"}]
|
"http://www.example.com/p" => [%{"@id" => "_:z1"}]
|
||||||
}]
|
|
||||||
}]
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
if title == "multiple graphs with shared BNode" do
|
if title == "multiple graphs with shared BNode" do
|
||||||
@tag skip: "TODO: https://github.com/json-ld/json-ld.org/issues/357"
|
@tag skip: "TODO: https://github.com/json-ld/json-ld.org/issues/357"
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
input |> gets_serialized_to(output)
|
input |> gets_serialized_to(output)
|
||||||
|
@ -346,61 +461,23 @@ defmodule JSON.LD.EncoderTest do
|
||||||
describe "quads" do
|
describe "quads" do
|
||||||
%{
|
%{
|
||||||
"simple named graph" => %{
|
"simple named graph" => %{
|
||||||
input: {EX.a, EX.b, EX.c, EX.U},
|
input: {EX.a(), EX.b(), EX.c(), EX.U},
|
||||||
output: [
|
output: [
|
||||||
%{
|
%{
|
||||||
"@id" => "http://example.com/U",
|
"@id" => "http://example.com/U",
|
||||||
"@graph" => [%{
|
"@graph" => [
|
||||||
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{"@id" => "http://example.com/c"}]
|
"http://example.com/b" => [%{"@id" => "http://example.com/c"}]
|
||||||
}]
|
}
|
||||||
},
|
]
|
||||||
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"with properties" => %{
|
"with properties" => %{
|
||||||
input: [
|
input: [
|
||||||
{EX.a, EX.b, EX.c, EX.U},
|
{EX.a(), EX.b(), EX.c(), EX.U},
|
||||||
{EX.U, EX.d, EX.e},
|
{EX.U, EX.d(), EX.e()}
|
||||||
],
|
|
||||||
output: [
|
|
||||||
%{
|
|
||||||
"@id" => "http://example.com/U",
|
|
||||||
"@graph" => [%{
|
|
||||||
"@id" => "http://example.com/a",
|
|
||||||
"http://example.com/b" => [%{"@id" => "http://example.com/c"}]
|
|
||||||
}],
|
|
||||||
"http://example.com/d" => [%{"@id" => "http://example.com/e"}]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"with lists" => %{
|
|
||||||
input: [
|
|
||||||
{EX.a, EX.b, RDF.bnode(:a), EX.U},
|
|
||||||
{RDF.bnode(:a), NS.RDF.first, EX.c, EX.U},
|
|
||||||
{RDF.bnode(:a), NS.RDF.rest, NS.RDF.nil, EX.U},
|
|
||||||
{EX.U, EX.d, RDF.bnode(:b)},
|
|
||||||
{RDF.bnode(:b), NS.RDF.first, EX.e},
|
|
||||||
{RDF.bnode(:b), NS.RDF.rest, NS.RDF.nil},
|
|
||||||
],
|
|
||||||
output: [
|
|
||||||
%{
|
|
||||||
"@id" => "http://example.com/U",
|
|
||||||
"@graph" => [%{
|
|
||||||
"@id" => "http://example.com/a",
|
|
||||||
"http://example.com/b" => [%{"@list" => [%{"@id" => "http://example.com/c"}]}]
|
|
||||||
}],
|
|
||||||
"http://example.com/d" => [%{"@list" => [%{"@id" => "http://example.com/e"}]}]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"Two Graphs with same subject and lists" => %{
|
|
||||||
input: [
|
|
||||||
{EX.a, EX.b, RDF.bnode(:a), EX.U},
|
|
||||||
{RDF.bnode(:a), NS.RDF.first, EX.c, EX.U},
|
|
||||||
{RDF.bnode(:a), NS.RDF.rest, NS.RDF.nil, EX.U},
|
|
||||||
{EX.a, EX.b, RDF.bnode(:b), EX.V},
|
|
||||||
{RDF.bnode(:b), NS.RDF.first, EX.e, EX.V},
|
|
||||||
{RDF.bnode(:b), NS.RDF.rest, NS.RDF.nil, EX.V},
|
|
||||||
],
|
],
|
||||||
output: [
|
output: [
|
||||||
%{
|
%{
|
||||||
|
@ -408,9 +485,55 @@ defmodule JSON.LD.EncoderTest do
|
||||||
"@graph" => [
|
"@graph" => [
|
||||||
%{
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{
|
"http://example.com/b" => [%{"@id" => "http://example.com/c"}]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"http://example.com/d" => [%{"@id" => "http://example.com/e"}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"with lists" => %{
|
||||||
|
input: [
|
||||||
|
{EX.a(), EX.b(), RDF.bnode(:a), EX.U},
|
||||||
|
{RDF.bnode(:a), NS.RDF.first(), EX.c(), EX.U},
|
||||||
|
{RDF.bnode(:a), NS.RDF.rest(), NS.RDF.nil(), EX.U},
|
||||||
|
{EX.U, EX.d(), RDF.bnode(:b)},
|
||||||
|
{RDF.bnode(:b), NS.RDF.first(), EX.e()},
|
||||||
|
{RDF.bnode(:b), NS.RDF.rest(), NS.RDF.nil()}
|
||||||
|
],
|
||||||
|
output: [
|
||||||
|
%{
|
||||||
|
"@id" => "http://example.com/U",
|
||||||
|
"@graph" => [
|
||||||
|
%{
|
||||||
|
"@id" => "http://example.com/a",
|
||||||
|
"http://example.com/b" => [%{"@list" => [%{"@id" => "http://example.com/c"}]}]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"http://example.com/d" => [%{"@list" => [%{"@id" => "http://example.com/e"}]}]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Two Graphs with same subject and lists" => %{
|
||||||
|
input: [
|
||||||
|
{EX.a(), EX.b(), RDF.bnode(:a), EX.U},
|
||||||
|
{RDF.bnode(:a), NS.RDF.first(), EX.c(), EX.U},
|
||||||
|
{RDF.bnode(:a), NS.RDF.rest(), NS.RDF.nil(), EX.U},
|
||||||
|
{EX.a(), EX.b(), RDF.bnode(:b), EX.V},
|
||||||
|
{RDF.bnode(:b), NS.RDF.first(), EX.e(), EX.V},
|
||||||
|
{RDF.bnode(:b), NS.RDF.rest(), NS.RDF.nil(), EX.V}
|
||||||
|
],
|
||||||
|
output: [
|
||||||
|
%{
|
||||||
|
"@id" => "http://example.com/U",
|
||||||
|
"@graph" => [
|
||||||
|
%{
|
||||||
|
"@id" => "http://example.com/a",
|
||||||
|
"http://example.com/b" => [
|
||||||
|
%{
|
||||||
"@list" => [%{"@id" => "http://example.com/c"}]
|
"@list" => [%{"@id" => "http://example.com/c"}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -419,16 +542,18 @@ defmodule JSON.LD.EncoderTest do
|
||||||
"@graph" => [
|
"@graph" => [
|
||||||
%{
|
%{
|
||||||
"@id" => "http://example.com/a",
|
"@id" => "http://example.com/a",
|
||||||
"http://example.com/b" => [%{
|
"http://example.com/b" => [
|
||||||
|
%{
|
||||||
"@list" => [%{"@id" => "http://example.com/e"}]
|
"@list" => [%{"@id" => "http://example.com/e"}]
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: %{input: input, output: output}} do
|
test title, %{data: %{input: input, output: output}} do
|
||||||
input |> gets_serialized_to(output, data_structs: [Dataset])
|
input |> gets_serialized_to(output, data_structs: [Dataset])
|
||||||
|
@ -439,21 +564,22 @@ defmodule JSON.LD.EncoderTest do
|
||||||
describe "problems" do
|
describe "problems" do
|
||||||
%{
|
%{
|
||||||
"xsd:boolean as value" => {
|
"xsd:boolean as value" => {
|
||||||
{~I<http://data.wikia.com/terms#playable>, NS.RDFS.range, NS.XSD.boolean},
|
{~I<http://data.wikia.com/terms#playable>, NS.RDFS.range(), NS.XSD.boolean()},
|
||||||
[%{
|
[
|
||||||
|
%{
|
||||||
"@id" => "http://data.wikia.com/terms#playable",
|
"@id" => "http://data.wikia.com/terms#playable",
|
||||||
"http://www.w3.org/2000/01/rdf-schema#range" => [
|
"http://www.w3.org/2000/01/rdf-schema#range" => [
|
||||||
%{"@id" => "http://www.w3.org/2001/XMLSchema#boolean"}
|
%{"@id" => "http://www.w3.org/2001/XMLSchema#boolean"}
|
||||||
]
|
]
|
||||||
}]
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: {input, output}} do
|
test title, %{data: {input, output}} do
|
||||||
input |> gets_serialized_to(output)
|
input |> gets_serialized_to(output)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,7 +6,8 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
alias RDF.NS.{RDFS, XSD}
|
alias RDF.NS.{RDFS, XSD}
|
||||||
|
|
||||||
test "Expanded form of a JSON-LD document (EXAMPLE 55 and 56 of https://www.w3.org/TR/json-ld/#expanded-document-form)" do
|
test "Expanded form of a JSON-LD document (EXAMPLE 55 and 56 of https://www.w3.org/TR/json-ld/#expanded-document-form)" do
|
||||||
input = Jason.decode! """
|
input =
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context":
|
"@context":
|
||||||
{
|
{
|
||||||
|
@ -19,8 +20,10 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"name": "Manu Sporny",
|
"name": "Manu Sporny",
|
||||||
"homepage": "http://manu.sporny.org/"
|
"homepage": "http://manu.sporny.org/"
|
||||||
}
|
}
|
||||||
"""
|
""")
|
||||||
assert JSON.LD.expand(input) == Jason.decode! """
|
|
||||||
|
assert JSON.LD.expand(input) ==
|
||||||
|
Jason.decode!("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"http://xmlns.com/foaf/0.1/name": [
|
"http://xmlns.com/foaf/0.1/name": [
|
||||||
|
@ -31,7 +34,7 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
"""
|
""")
|
||||||
end
|
end
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
@ -44,19 +47,23 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"@context" => %{
|
"@context" => %{
|
||||||
"foo" => %{"@id" => "http://example.com/foo", "@container" => "@list"}
|
"foo" => %{"@id" => "http://example.com/foo", "@container" => "@list"}
|
||||||
},
|
},
|
||||||
"foo" => [%{"@value" => "bar"}]\
|
"foo" => [%{"@value" => "bar"}]
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [%{"@list" => [%{"@value" => "bar"}]}]
|
"http://example.com/foo" => [%{"@list" => [%{"@value" => "bar"}]}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"native values in list" => %{
|
"native values in list" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"http://example.com/foo" => %{"@list" => [1, 2]}
|
"http://example.com/foo" => %{"@list" => [1, 2]}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [%{"@list" => [%{"@value" => 1}, %{"@value" => 2}]}]
|
"http://example.com/foo" => [%{"@list" => [%{"@value" => 1}, %{"@value" => 2}]}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"@graph" => %{
|
"@graph" => %{
|
||||||
input: %{
|
input: %{
|
||||||
|
@ -94,7 +101,7 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
output: [%{"http://example.com/ex" => [%{"@value" => false}]}]
|
output: [%{"http://example.com/ex" => [%{"@value" => false}]}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -106,43 +113,51 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"base" => %{
|
"base" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@id" => "",
|
"@id" => "",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"@id" => "http://example.org/",
|
"@id" => "http://example.org/",
|
||||||
"@type" => [RDFS.Resource |> RDF.uri |> to_string]
|
"@type" => [RDFS.Resource |> RDF.uri() |> to_string]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"relative" => %{
|
"relative" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@id" => "a/b",
|
"@id" => "a/b",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"@id" => "http://example.org/a/b",
|
"@id" => "http://example.org/a/b",
|
||||||
"@type" => [RDFS.Resource |> RDF.uri |> to_string]
|
"@type" => [RDFS.Resource |> RDF.uri() |> to_string]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"hash" => %{
|
"hash" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@id" => "#a",
|
"@id" => "#a",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"@id" => "http://example.org/#a",
|
"@id" => "http://example.org/#a",
|
||||||
"@type" => [RDFS.Resource |> RDF.uri |> to_string]
|
"@type" => [RDFS.Resource |> RDF.uri() |> to_string]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"unmapped @id" => %{
|
"unmapped @id" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"http://example.com/foo" => %{"@id" => "bar"}
|
"http://example.com/foo" => %{"@id" => "bar"}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [%{"@id" => "http://example.org/bar"}]
|
"http://example.com/foo" => [%{"@id" => "http://example.org/bar"}]
|
||||||
}]
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input, base: "http://example.org/") == data.output
|
assert JSON.LD.expand(data.input, base: "http://example.org/") == data.output
|
||||||
|
@ -156,53 +171,65 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"id" => "@id"},
|
"@context" => %{"id" => "@id"},
|
||||||
"id" => "",
|
"id" => "",
|
||||||
"@type" => (RDFS.Resource |> RDF.uri |> to_string)
|
"@type" => RDFS.Resource |> RDF.uri() |> to_string
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"@id" => "",
|
"@id" => "",
|
||||||
"@type" =>[ (RDFS.Resource |> RDF.uri |> to_string)]
|
"@type" => [RDFS.Resource |> RDF.uri() |> to_string]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"@type" => %{
|
"@type" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"type" => "@type"},
|
"@context" => %{"type" => "@type"},
|
||||||
"type" => (RDFS.Resource |> RDF.uri |> to_string),
|
"type" => RDFS.Resource |> RDF.uri() |> to_string,
|
||||||
"http://example.com/foo" => %{"@value" => "bar", "type" => "http://example.com/baz"}
|
"http://example.com/foo" => %{"@value" => "bar", "type" => "http://example.com/baz"}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
"@type" => [RDFS.Resource |> RDF.uri |> to_string],
|
%{
|
||||||
"http://example.com/foo" => [%{"@value" => "bar", "@type" => "http://example.com/baz"}]
|
"@type" => [RDFS.Resource |> RDF.uri() |> to_string],
|
||||||
}]
|
"http://example.com/foo" => [
|
||||||
|
%{"@value" => "bar", "@type" => "http://example.com/baz"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"@language" => %{
|
"@language" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"language" => "@language"},
|
"@context" => %{"language" => "@language"},
|
||||||
"http://example.com/foo" => %{"@value" => "bar", "language" => "baz"}
|
"http://example.com/foo" => %{"@value" => "bar", "language" => "baz"}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [%{"@value" => "bar", "@language" => "baz"}]
|
"http://example.com/foo" => [%{"@value" => "bar", "@language" => "baz"}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"@value" => %{
|
"@value" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"literal" => "@value"},
|
"@context" => %{"literal" => "@value"},
|
||||||
"http://example.com/foo" => %{"literal" => "bar"}
|
"http://example.com/foo" => %{"literal" => "bar"}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [%{"@value" => "bar"}]
|
"http://example.com/foo" => [%{"@value" => "bar"}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"@list" => %{
|
"@list" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"list" => "@list"},
|
"@context" => %{"list" => "@list"},
|
||||||
"http://example.com/foo" => %{"list" => ["bar"]}
|
"http://example.com/foo" => %{"list" => ["bar"]}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [%{"@list" => [%{"@value" => "bar"}]}]
|
"http://example.com/foo" => [%{"@list" => [%{"@value" => "bar"}]}]
|
||||||
}]
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -217,48 +244,58 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"@context" => %{"e" => "http://example.org/vocab#"},
|
"@context" => %{"e" => "http://example.org/vocab#"},
|
||||||
"e:bool" => true
|
"e:bool" => true
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.org/vocab#bool" => [%{"@value" => true}]
|
"http://example.org/vocab#bool" => [%{"@value" => true}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"false" => %{
|
"false" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"e" => "http://example.org/vocab#"},
|
"@context" => %{"e" => "http://example.org/vocab#"},
|
||||||
"e:bool" => false
|
"e:bool" => false
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.org/vocab#bool" => [%{"@value" => false}]
|
"http://example.org/vocab#bool" => [%{"@value" => false}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"double" => %{
|
"double" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"e" => "http://example.org/vocab#"},
|
"@context" => %{"e" => "http://example.org/vocab#"},
|
||||||
"e:double" => 1.23
|
"e:double" => 1.23
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.org/vocab#double" => [%{"@value" => 1.23}]
|
"http://example.org/vocab#double" => [%{"@value" => 1.23}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"double-zero" => %{
|
"double-zero" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"e" => "http://example.org/vocab#"},
|
"@context" => %{"e" => "http://example.org/vocab#"},
|
||||||
"e:double-zero" => 0.0e0
|
"e:double-zero" => 0.0e0
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.org/vocab#double-zero" => [%{"@value" => 0.0e0}]
|
"http://example.org/vocab#double-zero" => [%{"@value" => 0.0e0}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"integer" => %{
|
"integer" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"e" => "http://example.org/vocab#"},
|
"@context" => %{"e" => "http://example.org/vocab#"},
|
||||||
"e:integer" => 123
|
"e:integer" => 123
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.org/vocab#integer" => [%{"@value" => 123}]
|
"http://example.org/vocab#integer" => [%{"@value" => 123}]
|
||||||
}]
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -270,24 +307,36 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
%{
|
%{
|
||||||
"boolean" => %{
|
"boolean" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"foo" => %{"@id" => "http://example.org/foo", "@type" => to_string(XSD.boolean)}},
|
"@context" => %{
|
||||||
|
"foo" => %{"@id" => "http://example.org/foo", "@type" => to_string(XSD.boolean())}
|
||||||
|
},
|
||||||
"foo" => "true"
|
"foo" => "true"
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
"http://example.org/foo" => [%{"@value" => "true", "@type" => to_string(XSD.boolean)}]
|
%{
|
||||||
}]
|
"http://example.org/foo" => [
|
||||||
|
%{"@value" => "true", "@type" => to_string(XSD.boolean())}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"date" => %{
|
"date" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"foo" => %{"@id" => "http://example.org/foo", "@type" => to_string(XSD.date)}},
|
"@context" => %{
|
||||||
|
"foo" => %{"@id" => "http://example.org/foo", "@type" => to_string(XSD.date())}
|
||||||
|
},
|
||||||
"foo" => "2011-03-26"
|
"foo" => "2011-03-26"
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
"http://example.org/foo" => [%{"@value" => "2011-03-26", "@type" => to_string(XSD.date)}]
|
%{
|
||||||
}]
|
"http://example.org/foo" => [
|
||||||
},
|
%{"@value" => "2011-03-26", "@type" => to_string(XSD.date())}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -317,9 +366,11 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
input: %{
|
input: %{
|
||||||
"http://example.com/foo" => [nil]
|
"http://example.com/foo" => [nil]
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => []
|
"http://example.com/foo" => []
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"@set with null @value" => %{
|
"@set with null @value" => %{
|
||||||
input: %{
|
input: %{
|
||||||
|
@ -327,12 +378,14 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
%{"@value" => nil, "@type" => "http://example.org/Type"}
|
%{"@value" => nil, "@type" => "http://example.org/Type"}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => []
|
"http://example.com/foo" => []
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -359,9 +412,9 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"http://example.org/vocab#nolang" => [%{"@value" => "no language"}]
|
"http://example.org/vocab#nolang" => [%{"@value" => "no language"}]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -376,18 +429,24 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"@context" => %{"@vocab" => "http://example.com/"},
|
"@context" => %{"@vocab" => "http://example.com/"},
|
||||||
"verb" => %{"@value" => "foo"}
|
"verb" => %{"@value" => "foo"}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/verb" => [%{"@value" => "foo"}]
|
"http://example.com/verb" => [%{"@value" => "foo"}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"datatype" => %{
|
"datatype" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"@vocab" => "http://example.com/"},
|
"@context" => %{"@vocab" => "http://example.com/"},
|
||||||
"http://example.org/verb" => %{"@value" => "foo", "@type" => "string"}
|
"http://example.org/verb" => %{"@value" => "foo", "@type" => "string"}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
"http://example.org/verb" => [%{"@value" => "foo", "@type" => "http://example.com/string"}]
|
%{
|
||||||
}]
|
"http://example.org/verb" => [
|
||||||
|
%{"@value" => "foo", "@type" => "http://example.com/string"}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"expand-0028" => %{
|
"expand-0028" => %{
|
||||||
input: %{
|
input: %{
|
||||||
|
@ -428,7 +487,7 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input, base: "http://foo/bar/") == data.output
|
assert JSON.LD.expand(data.input, base: "http://foo/bar/") == data.output
|
||||||
|
@ -448,9 +507,11 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
input: %{
|
input: %{
|
||||||
"http://example.com/foo" => %{"@value" => "bar", "@type" => "baz"}
|
"http://example.com/foo" => %{"@value" => "bar", "@type" => "baz"}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [%{"@value" => "bar", "@type" => "http://example/baz"}]
|
"http://example.com/foo" => [%{"@value" => "bar", "@type" => "http://example/baz"}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"unknown keyword" => %{
|
"unknown keyword" => %{
|
||||||
input: %{
|
input: %{
|
||||||
|
@ -477,14 +538,16 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"prop" => "prop"
|
"prop" => "prop"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"@id" => "http://example.org/id1",
|
"@id" => "http://example.org/id1",
|
||||||
"http://example.org/prop" => [%{"@value" => "prop"}],
|
"http://example.org/prop" => [%{"@value" => "prop"}],
|
||||||
"http://example.org/chain" => [%{"@id" => "http://example.org/id2"}]
|
"http://example.org/chain" => [%{"@id" => "http://example.org/id2"}]
|
||||||
}
|
}
|
||||||
]}
|
]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input, base: "http://example/") == data.output
|
assert JSON.LD.expand(data.input, base: "http://example/") == data.output
|
||||||
|
@ -517,27 +580,39 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"@context" => %{"http://example.com/foo" => %{"@container" => "@list"}},
|
"@context" => %{"http://example.com/foo" => %{"@container" => "@list"}},
|
||||||
"http://example.com/foo" => ["foo", "bar"]
|
"http://example.com/foo" => ["foo", "bar"]
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
"http://example.com/foo" => [%{"@list" => [ %{"@value" => "foo"}, %{"@value" => "bar"} ]}]
|
%{
|
||||||
}]
|
"http://example.com/foo" => [
|
||||||
|
%{"@list" => [%{"@value" => "foo"}, %{"@value" => "bar"}]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"explicit list with coerced @id values" => %{
|
"explicit list with coerced @id values" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"http://example.com/foo" => %{"@type" => "@id"}},
|
"@context" => %{"http://example.com/foo" => %{"@type" => "@id"}},
|
||||||
"http://example.com/foo" => %{"@list" => ["http://foo", "http://bar"]}
|
"http://example.com/foo" => %{"@list" => ["http://foo", "http://bar"]}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
"http://example.com/foo" => [%{"@list" => [%{"@id" => "http://foo"}, %{"@id" => "http://bar"}]}]
|
%{
|
||||||
}]
|
"http://example.com/foo" => [
|
||||||
|
%{"@list" => [%{"@id" => "http://foo"}, %{"@id" => "http://bar"}]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"explicit list with coerced datatype values" => %{
|
"explicit list with coerced datatype values" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"http://example.com/foo" => %{"@type" => to_string(XSD.date)}},
|
"@context" => %{"http://example.com/foo" => %{"@type" => to_string(XSD.date())}},
|
||||||
"http://example.com/foo" => %{"@list" => ["2012-04-12"]}
|
"http://example.com/foo" => %{"@list" => ["2012-04-12"]}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
"http://example.com/foo" => [%{"@list" => [%{"@value" => "2012-04-12", "@type" => to_string(XSD.date)}]}]
|
%{
|
||||||
}]
|
"http://example.com/foo" => [
|
||||||
|
%{"@list" => [%{"@value" => "2012-04-12", "@type" => to_string(XSD.date())}]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"expand-0004" => %{
|
"expand-0004" => %{
|
||||||
input: Jason.decode!(~s({
|
input: Jason.decode!(~s({
|
||||||
|
@ -564,7 +639,7 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
]))
|
]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -578,47 +653,57 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
input: %{
|
input: %{
|
||||||
"http://example.com/foo" => %{"@set" => []}
|
"http://example.com/foo" => %{"@set" => []}
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => []
|
"http://example.com/foo" => []
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"coerced empty" => %{
|
"coerced empty" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"http://example.com/foo" => %{"@container" => "@set"}},
|
"@context" => %{"http://example.com/foo" => %{"@container" => "@set"}},
|
||||||
"http://example.com/foo" => []
|
"http://example.com/foo" => []
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => []
|
"http://example.com/foo" => []
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"coerced single element" => %{
|
"coerced single element" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"http://example.com/foo" => %{"@container" => "@set"}},
|
"@context" => %{"http://example.com/foo" => %{"@container" => "@set"}},
|
||||||
"http://example.com/foo" => ["foo"]
|
"http://example.com/foo" => ["foo"]
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [%{"@value" => "foo"}]
|
"http://example.com/foo" => [%{"@value" => "foo"}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"coerced multiple elements" => %{
|
"coerced multiple elements" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"@context" => %{"http://example.com/foo" => %{"@container" => "@set"}},
|
"@context" => %{"http://example.com/foo" => %{"@container" => "@set"}},
|
||||||
"http://example.com/foo" => ["foo", "bar"]
|
"http://example.com/foo" => ["foo", "bar"]
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => [%{"@value" => "foo"}, %{"@value" => "bar"}]
|
"http://example.com/foo" => [%{"@value" => "foo"}, %{"@value" => "bar"}]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"array containing set" => %{
|
"array containing set" => %{
|
||||||
input: %{
|
input: %{
|
||||||
"http://example.com/foo" => [%{"@set" => []}]
|
"http://example.com/foo" => [%{"@set" => []}]
|
||||||
},
|
},
|
||||||
output: [%{
|
output: [
|
||||||
|
%{
|
||||||
"http://example.com/foo" => []
|
"http://example.com/foo" => []
|
||||||
}]
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -653,7 +738,7 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
}
|
||||||
# TODO: Only the order of result is not correct, the content seems ok (although
|
# TODO: Only the order of result is not correct, the content seems ok (although
|
||||||
# it's not clear why, since the "http://example.com/vocab/label" object is not handled in 7.5 code (at least debug statement are not printed
|
# it's not clear why, since the "http://example.com/vocab/label" object is not handled in 7.5 code (at least debug statement are not printed
|
||||||
# "expand-0035" => %{
|
# "expand-0035" => %{
|
||||||
|
@ -689,7 +774,7 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
# ]
|
# ]
|
||||||
# }
|
# }
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -785,9 +870,9 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]))
|
]))
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -821,9 +906,9 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
}
|
||||||
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.expand(data.input) == data.output
|
assert JSON.LD.expand(data.input) == data.output
|
||||||
|
@ -868,7 +953,6 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
},
|
},
|
||||||
exception: JSON.LD.ListOfListsError
|
exception: JSON.LD.ListOfListsError
|
||||||
},
|
},
|
||||||
|
|
||||||
"@reverse object with an @id property" => %{
|
"@reverse object with an @id property" => %{
|
||||||
input: Jason.decode!(~s({
|
input: Jason.decode!(~s({
|
||||||
"@id": "http://example/foo",
|
"@id": "http://example/foo",
|
||||||
|
@ -876,7 +960,7 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"@id": "http://example/bar"
|
"@id": "http://example/bar"
|
||||||
}
|
}
|
||||||
})),
|
})),
|
||||||
exception: JSON.LD.InvalidReversePropertyMapError,
|
exception: JSON.LD.InvalidReversePropertyMapError
|
||||||
},
|
},
|
||||||
"colliding keywords" => %{
|
"colliding keywords" => %{
|
||||||
input: Jason.decode!(~s({
|
input: Jason.decode!(~s({
|
||||||
|
@ -887,10 +971,10 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"id": "http://example/foo",
|
"id": "http://example/foo",
|
||||||
"ID": "http://example/bar"
|
"ID": "http://example/bar"
|
||||||
})),
|
})),
|
||||||
exception: JSON.LD.CollidingKeywordsError,
|
exception: JSON.LD.CollidingKeywordsError
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert_raise data.exception, fn -> JSON.LD.expand(data.input) end
|
assert_raise data.exception, fn -> JSON.LD.expand(data.input) end
|
||||||
|
@ -900,24 +984,29 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
|
|
||||||
describe "expand_value" do
|
describe "expand_value" do
|
||||||
setup do
|
setup do
|
||||||
context = JSON.LD.context(%{
|
context =
|
||||||
"dc" => "http://purl.org/dc/terms/", # TODO: RDF::Vocab::DC.to_uri.to_s,
|
JSON.LD.context(%{
|
||||||
|
# TODO: RDF::Vocab::DC.to_uri.to_s,
|
||||||
|
"dc" => "http://purl.org/dc/terms/",
|
||||||
"ex" => "http://example.org/",
|
"ex" => "http://example.org/",
|
||||||
"foaf" => "http://xmlns.com/foaf/0.1/", # TODO: RDF::Vocab::FOAF.to_uri.to_s,
|
# TODO: RDF::Vocab::FOAF.to_uri.to_s,
|
||||||
|
"foaf" => "http://xmlns.com/foaf/0.1/",
|
||||||
"xsd" => "http://www.w3.org/2001/XMLSchema#",
|
"xsd" => "http://www.w3.org/2001/XMLSchema#",
|
||||||
"foaf:age" => %{"@type" => "xsd:integer"},
|
"foaf:age" => %{"@type" => "xsd:integer"},
|
||||||
"foaf:knows" => %{"@type" => "@id"},
|
"foaf:knows" => %{"@type" => "@id"},
|
||||||
"dc:created" => %{"@type" => "xsd:date"},
|
"dc:created" => %{"@type" => "xsd:date"},
|
||||||
"ex:integer" => %{"@type" => "xsd:integer"},
|
"ex:integer" => %{"@type" => "xsd:integer"},
|
||||||
"ex:double" => %{"@type" => "xsd:double"},
|
"ex:double" => %{"@type" => "xsd:double"},
|
||||||
"ex:boolean" => %{"@type" => "xsd:boolean"},
|
"ex:boolean" => %{"@type" => "xsd:boolean"}
|
||||||
})
|
})
|
||||||
|
|
||||||
%{example_context: context}
|
%{example_context: context}
|
||||||
end
|
end
|
||||||
|
|
||||||
~w(boolean integer string dateTime date time)
|
~w(boolean integer string dateTime date time)
|
||||||
|> Enum.each(fn dt ->
|
|> Enum.each(fn dt ->
|
||||||
@tag skip: "This seems to be RDF.rb specific. The @id keys are produced when value is an RDF::URI or RDF::Node. Do we need/want something similar?"
|
@tag skip:
|
||||||
|
"This seems to be RDF.rb specific. The @id keys are produced when value is an RDF::URI or RDF::Node. Do we need/want something similar?"
|
||||||
@tag dt: dt
|
@tag dt: dt
|
||||||
test "expands datatype xsd:#{dt}", %{dt: dt, example_context: context} do
|
test "expands datatype xsd:#{dt}", %{dt: dt, example_context: context} do
|
||||||
assert expand_value(context, "foo", apply(XSD, String.to_atom(dt), []) |> to_string) ==
|
assert expand_value(context, "foo", apply(XSD, String.to_atom(dt), []) |> to_string) ==
|
||||||
|
@ -932,11 +1021,15 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
"no IRI" => ["foo", "http://example.com/", %{"@value" => "http://example.com/"}],
|
"no IRI" => ["foo", "http://example.com/", %{"@value" => "http://example.com/"}],
|
||||||
"no term" => ["foo", "ex", %{"@value" => "ex"}],
|
"no term" => ["foo", "ex", %{"@value" => "ex"}],
|
||||||
"no prefix" => ["foo", "ex:suffix", %{"@value" => "ex:suffix"}],
|
"no prefix" => ["foo", "ex:suffix", %{"@value" => "ex:suffix"}],
|
||||||
"integer" => ["foaf:age", "54", %{"@value" => "54", "@type" => XSD.integer |> to_string}],
|
"integer" => ["foaf:age", "54", %{"@value" => "54", "@type" => XSD.integer() |> to_string}],
|
||||||
"date " => ["dc:created", "2011-12-27Z", %{"@value" => "2011-12-27Z", "@type" => XSD.date |> to_string}],
|
"date " => [
|
||||||
|
"dc:created",
|
||||||
|
"2011-12-27Z",
|
||||||
|
%{"@value" => "2011-12-27Z", "@type" => XSD.date() |> to_string}
|
||||||
|
],
|
||||||
"native boolean" => ["foo", true, %{"@value" => true}],
|
"native boolean" => ["foo", true, %{"@value" => true}],
|
||||||
"native integer" => ["foo", 1, %{"@value" => 1}],
|
"native integer" => ["foo", 1, %{"@value" => 1}],
|
||||||
"native double" => ["foo", 1.1e1, %{"@value" => 1.1E1}],
|
"native double" => ["foo", 1.1e1, %{"@value" => 1.1e1}]
|
||||||
# TODO: Do we really want to support the following? RDF.rb has another implementation and uses this function
|
# TODO: Do we really want to support the following? RDF.rb has another implementation and uses this function
|
||||||
# for its implementation of fromRdf, instead of the RDF to Object Conversion algorithm in the spec ...
|
# for its implementation of fromRdf, instead of the RDF to Object Conversion algorithm in the spec ...
|
||||||
# "native date" => ["foo", ~D[2011-12-27], %{"@value" => "2011-12-27", "@type" => XSD.date |> to_string}],
|
# "native date" => ["foo", ~D[2011-12-27], %{"@value" => "2011-12-27", "@type" => XSD.date |> to_string}],
|
||||||
|
@ -951,7 +1044,7 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
# "rdf nonNeg" => ["foo", RDF::Literal::NonNegativeInteger.new(1), %{"@value" => "1", "@type" => XSD.nonNegativeInteger |> to_string}],
|
# "rdf nonNeg" => ["foo", RDF::Literal::NonNegativeInteger.new(1), %{"@value" => "1", "@type" => XSD.nonNegativeInteger |> to_string}],
|
||||||
# "rdf float" => ["foo", RDF::Literal::Float.new(1.0), %{"@value" => "1.0", "@type" => XSD.float |> to_string}],
|
# "rdf float" => ["foo", RDF::Literal::Float.new(1.0), %{"@value" => "1.0", "@type" => XSD.float |> to_string}],
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: [key, compacted, expanded], example_context: context} do
|
test title, %{data: [key, compacted, expanded], example_context: context} do
|
||||||
assert expand_value(context, key, compacted) == expanded
|
assert expand_value(context, key, compacted) == expanded
|
||||||
|
@ -961,17 +1054,22 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
# context "@language" do
|
# context "@language" do
|
||||||
# before(:each) {subject.default_language = "en"}
|
# before(:each) {subject.default_language = "en"}
|
||||||
%{
|
%{
|
||||||
"no IRI" => ["foo", "http://example.com/", %{"@value" => "http://example.com/", "@language" => "en"}],
|
"no IRI" => [
|
||||||
|
"foo",
|
||||||
|
"http://example.com/",
|
||||||
|
%{"@value" => "http://example.com/", "@language" => "en"}
|
||||||
|
],
|
||||||
"no term" => ["foo", "ex", %{"@value" => "ex", "@language" => "en"}],
|
"no term" => ["foo", "ex", %{"@value" => "ex", "@language" => "en"}],
|
||||||
"no prefix" => ["foo", "ex:suffix", %{"@value" => "ex:suffix", "@language" => "en"}],
|
"no prefix" => ["foo", "ex:suffix", %{"@value" => "ex:suffix", "@language" => "en"}],
|
||||||
"native boolean" => ["foo", true, %{"@value" => true}],
|
"native boolean" => ["foo", true, %{"@value" => true}],
|
||||||
"native integer" => ["foo", 1, %{"@value" => 1}],
|
"native integer" => ["foo", 1, %{"@value" => 1}],
|
||||||
"native double" => ["foo", 1.1, %{"@value" => 1.1}],
|
"native double" => ["foo", 1.1, %{"@value" => 1.1}]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
# TODO
|
# TODO
|
||||||
# @tag skip: "Do these errors originate from the differing context setup?"
|
# @tag skip: "Do these errors originate from the differing context setup?"
|
||||||
@tag skip: "Why does this produce @language tags in RDF.rb, although no term definition of foo exists? Is this also RDF.rb specific?"
|
@tag skip:
|
||||||
|
"Why does this produce @language tags in RDF.rb, although no term definition of foo exists? Is this also RDF.rb specific?"
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test "@language #{title}", %{data: [key, compacted, expanded], example_context: context} do
|
test "@language #{title}", %{data: [key, compacted, expanded], example_context: context} do
|
||||||
assert expand_value(context, key, compacted) == expanded
|
assert expand_value(context, key, compacted) == expanded
|
||||||
|
@ -979,25 +1077,68 @@ defmodule JSON.LD.ExpansionTest do
|
||||||
end)
|
end)
|
||||||
|
|
||||||
%{
|
%{
|
||||||
"boolean-boolean" => ["ex:boolean", true, %{"@value" => true, "@type" => XSD.boolean |> to_string}],
|
"boolean-boolean" => [
|
||||||
"boolean-integer" => ["ex:integer", true, %{"@value" => true, "@type" => XSD.integer |> to_string}],
|
"ex:boolean",
|
||||||
"boolean-double" => ["ex:double", true, %{"@value" => true, "@type" => XSD.double |> to_string}],
|
true,
|
||||||
"double-boolean" => ["ex:boolean", 1.1, %{"@value" => 1.1, "@type" => XSD.boolean |> to_string}],
|
%{"@value" => true, "@type" => XSD.boolean() |> to_string}
|
||||||
"double-double" => ["ex:double", 1.1, %{"@value" => 1.1, "@type" => XSD.double |> to_string}],
|
],
|
||||||
"double-integer" => ["foaf:age", 1.1, %{"@value" => 1.1, "@type" => XSD.integer |> to_string}],
|
"boolean-integer" => [
|
||||||
"integer-boolean" => ["ex:boolean", 1, %{"@value" => 1, "@type" => XSD.boolean |> to_string}],
|
"ex:integer",
|
||||||
"integer-double" => ["ex:double", 1, %{"@value" => 1, "@type" => XSD.double |> to_string}],
|
true,
|
||||||
"integer-integer" => ["foaf:age", 1, %{"@value" => 1, "@type" => XSD.integer |> to_string}],
|
%{"@value" => true, "@type" => XSD.integer() |> to_string}
|
||||||
"string-boolean" => ["ex:boolean", "foo", %{"@value" => "foo", "@type" => XSD.boolean |> to_string}],
|
],
|
||||||
"string-double" => ["ex:double", "foo", %{"@value" => "foo", "@type" => XSD.double |> to_string}],
|
"boolean-double" => [
|
||||||
"string-integer" => ["foaf:age", "foo", %{"@value" => "foo", "@type" => XSD.integer |> to_string}],
|
"ex:double",
|
||||||
|
true,
|
||||||
|
%{"@value" => true, "@type" => XSD.double() |> to_string}
|
||||||
|
],
|
||||||
|
"double-boolean" => [
|
||||||
|
"ex:boolean",
|
||||||
|
1.1,
|
||||||
|
%{"@value" => 1.1, "@type" => XSD.boolean() |> to_string}
|
||||||
|
],
|
||||||
|
"double-double" => [
|
||||||
|
"ex:double",
|
||||||
|
1.1,
|
||||||
|
%{"@value" => 1.1, "@type" => XSD.double() |> to_string}
|
||||||
|
],
|
||||||
|
"double-integer" => [
|
||||||
|
"foaf:age",
|
||||||
|
1.1,
|
||||||
|
%{"@value" => 1.1, "@type" => XSD.integer() |> to_string}
|
||||||
|
],
|
||||||
|
"integer-boolean" => [
|
||||||
|
"ex:boolean",
|
||||||
|
1,
|
||||||
|
%{"@value" => 1, "@type" => XSD.boolean() |> to_string}
|
||||||
|
],
|
||||||
|
"integer-double" => ["ex:double", 1, %{"@value" => 1, "@type" => XSD.double() |> to_string}],
|
||||||
|
"integer-integer" => [
|
||||||
|
"foaf:age",
|
||||||
|
1,
|
||||||
|
%{"@value" => 1, "@type" => XSD.integer() |> to_string}
|
||||||
|
],
|
||||||
|
"string-boolean" => [
|
||||||
|
"ex:boolean",
|
||||||
|
"foo",
|
||||||
|
%{"@value" => "foo", "@type" => XSD.boolean() |> to_string}
|
||||||
|
],
|
||||||
|
"string-double" => [
|
||||||
|
"ex:double",
|
||||||
|
"foo",
|
||||||
|
%{"@value" => "foo", "@type" => XSD.double() |> to_string}
|
||||||
|
],
|
||||||
|
"string-integer" => [
|
||||||
|
"foaf:age",
|
||||||
|
"foo",
|
||||||
|
%{"@value" => "foo", "@type" => XSD.integer() |> to_string}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test "coercion #{title}", %{data: [key, compacted, expanded], example_context: context} do
|
test "coercion #{title}", %{data: [key, compacted, expanded], example_context: context} do
|
||||||
assert expand_value(context, key, compacted) == expanded
|
assert expand_value(context, key, compacted) == expanded
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,8 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
alias RDF.NS.RDFS
|
alias RDF.NS.RDFS
|
||||||
|
|
||||||
test "Flattened form of a JSON-LD document (EXAMPLE 60 and 61 of https://www.w3.org/TR/json-ld/#flattened-document-form)" do
|
test "Flattened form of a JSON-LD document (EXAMPLE 60 and 61 of https://www.w3.org/TR/json-ld/#flattened-document-form)" do
|
||||||
input = Jason.decode! """
|
input =
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": {
|
"@context": {
|
||||||
"name": "http://xmlns.com/foaf/0.1/name",
|
"name": "http://xmlns.com/foaf/0.1/name",
|
||||||
|
@ -22,8 +23,10 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
"""
|
""")
|
||||||
assert JSON.LD.flatten(input, input) == Jason.decode! """
|
|
||||||
|
assert JSON.LD.flatten(input, input) ==
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": {
|
"@context": {
|
||||||
"name": "http://xmlns.com/foaf/0.1/name",
|
"name": "http://xmlns.com/foaf/0.1/name",
|
||||||
|
@ -48,10 +51,9 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
"""
|
""")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
"single object" => %{
|
"single object" => %{
|
||||||
input: %{"@id" => "http://example.com", "@type" => to_string(RDF.uri(RDFS.Resource))},
|
input: %{"@id" => "http://example.com", "@type" => to_string(RDF.uri(RDFS.Resource))},
|
||||||
|
@ -66,16 +68,20 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
},
|
},
|
||||||
"@id" => "http://greggkellogg.net/foaf",
|
"@id" => "http://greggkellogg.net/foaf",
|
||||||
"@type" => ["foaf:PersonalProfileDocument"],
|
"@type" => ["foaf:PersonalProfileDocument"],
|
||||||
"foaf:primaryTopic" => [%{
|
"foaf:primaryTopic" => [
|
||||||
|
%{
|
||||||
"@id" => "http://greggkellogg.net/foaf#me",
|
"@id" => "http://greggkellogg.net/foaf#me",
|
||||||
"@type" => ["foaf:Person"]
|
"@type" => ["foaf:Person"]
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
output: [
|
output: [
|
||||||
%{
|
%{
|
||||||
"@id" => "http://greggkellogg.net/foaf",
|
"@id" => "http://greggkellogg.net/foaf",
|
||||||
"@type" => ["http://xmlns.com/foaf/0.1/PersonalProfileDocument"],
|
"@type" => ["http://xmlns.com/foaf/0.1/PersonalProfileDocument"],
|
||||||
"http://xmlns.com/foaf/0.1/primaryTopic" => [%{"@id" => "http://greggkellogg.net/foaf#me"}]
|
"http://xmlns.com/foaf/0.1/primaryTopic" => [
|
||||||
|
%{"@id" => "http://greggkellogg.net/foaf#me"}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
%{
|
%{
|
||||||
"@id" => "http://greggkellogg.net/foaf#me",
|
"@id" => "http://greggkellogg.net/foaf#me",
|
||||||
|
@ -107,7 +113,8 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"reverse properties" => %{
|
"reverse properties" => %{
|
||||||
input: Jason.decode!("""
|
input:
|
||||||
|
Jason.decode!("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"@id": "http://example.com/people/markus",
|
"@id": "http://example.com/people/markus",
|
||||||
|
@ -125,7 +132,8 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
"""),
|
"""),
|
||||||
output: Jason.decode!("""
|
output:
|
||||||
|
Jason.decode!("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"@id": "http://example.com/people/dave",
|
"@id": "http://example.com/people/dave",
|
||||||
|
@ -155,7 +163,8 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
""")
|
""")
|
||||||
},
|
},
|
||||||
"Simple named graph (Wikidata)" => %{
|
"Simple named graph (Wikidata)" => %{
|
||||||
input: Jason.decode!("""
|
input:
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": {
|
"@context": {
|
||||||
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
||||||
|
@ -187,7 +196,8 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
"""),
|
"""),
|
||||||
output: Jason.decode!("""
|
output:
|
||||||
|
Jason.decode!("""
|
||||||
[{
|
[{
|
||||||
"@id": "http://example.org/ParisFact1",
|
"@id": "http://example.org/ParisFact1",
|
||||||
"@type": ["http://www.w3.org/1999/02/22-rdf-syntax-ns#Graph"],
|
"@type": ["http://www.w3.org/1999/02/22-rdf-syntax-ns#Graph"],
|
||||||
|
@ -212,7 +222,8 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
""")
|
""")
|
||||||
},
|
},
|
||||||
"Test Manifest (shortened)" => %{
|
"Test Manifest (shortened)" => %{
|
||||||
input: Jason.decode!("""
|
input:
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@id": "",
|
"@id": "",
|
||||||
"http://example/sequence": {"@list": [
|
"http://example/sequence": {"@list": [
|
||||||
|
@ -224,7 +235,8 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
]}
|
]}
|
||||||
}
|
}
|
||||||
"""),
|
"""),
|
||||||
output: Jason.decode!("""
|
output:
|
||||||
|
Jason.decode!("""
|
||||||
[{
|
[{
|
||||||
"@id": "",
|
"@id": "",
|
||||||
"http://example/sequence": [{"@list": [{"@id": "#t0001"}]}]
|
"http://example/sequence": [{"@list": [{"@id": "#t0001"}]}]
|
||||||
|
@ -237,7 +249,8 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
options: %{}
|
options: %{}
|
||||||
},
|
},
|
||||||
"@reverse bnode issue (0045)" => %{
|
"@reverse bnode issue (0045)" => %{
|
||||||
input: Jason.decode!("""
|
input:
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": {
|
"@context": {
|
||||||
"foo": "http://example.org/foo",
|
"foo": "http://example.org/foo",
|
||||||
|
@ -247,7 +260,8 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
"bar": [ "http://example.org/origin", "_:b0" ]
|
"bar": [ "http://example.org/origin", "_:b0" ]
|
||||||
}
|
}
|
||||||
"""),
|
"""),
|
||||||
output: Jason.decode!("""
|
output:
|
||||||
|
Jason.decode!("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"@id": "_:b0",
|
"@id": "_:b0",
|
||||||
|
@ -266,11 +280,10 @@ defmodule JSON.LD.FlatteningTest do
|
||||||
options: %{}
|
options: %{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: data} do
|
test title, %{data: data} do
|
||||||
assert JSON.LD.flatten(data.input) == data.output
|
assert JSON.LD.flatten(data.input) == data.output
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,11 +6,13 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
alias RDF.NS.{XSD}
|
alias RDF.NS.{XSD}
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
context = JSON.LD.context(%{
|
context =
|
||||||
|
JSON.LD.context(%{
|
||||||
"@base" => "http://base/",
|
"@base" => "http://base/",
|
||||||
"xsd" => "http://www.w3.org/2001/XMLSchema#",
|
"xsd" => "http://www.w3.org/2001/XMLSchema#",
|
||||||
"ex" => "http://example.org/",
|
"ex" => "http://example.org/",
|
||||||
"" => "http://empty/", # TODO: "Invalid JSON-LD syntax; a term cannot be an empty string."
|
# TODO: "Invalid JSON-LD syntax; a term cannot be an empty string."
|
||||||
|
"" => "http://empty/",
|
||||||
"_" => "http://underscore/",
|
"_" => "http://underscore/",
|
||||||
"rex" => %{"@reverse" => "ex"},
|
"rex" => %{"@reverse" => "ex"},
|
||||||
"lex" => %{"@id" => "ex", "@language" => "en"},
|
"lex" => %{"@id" => "ex", "@language" => "en"},
|
||||||
|
@ -18,6 +20,7 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
"exp" => %{"@id" => "ex:pert"},
|
"exp" => %{"@id" => "ex:pert"},
|
||||||
"experts" => %{"@id" => "ex:perts"}
|
"experts" => %{"@id" => "ex:perts"}
|
||||||
})
|
})
|
||||||
|
|
||||||
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -34,8 +37,11 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
}
|
}
|
||||||
|> Enum.each(fn {title, data} ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: [result, input], example_context: context,
|
test title, %{
|
||||||
inverse_context: inverse_context} do
|
data: [result, input],
|
||||||
|
example_context: context,
|
||||||
|
inverse_context: inverse_context
|
||||||
|
} do
|
||||||
assert compact_iri(input, context, inverse_context) == result
|
assert compact_iri(input, context, inverse_context) == result
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -53,8 +59,11 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
}
|
}
|
||||||
|> Enum.each(fn {title, data} ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: [result, input], example_context: context,
|
test title, %{
|
||||||
inverse_context: inverse_context} do
|
data: [result, input],
|
||||||
|
example_context: context,
|
||||||
|
inverse_context: inverse_context
|
||||||
|
} do
|
||||||
assert compact_iri(input, context, inverse_context, nil, true) == result
|
assert compact_iri(input, context, inverse_context, nil, true) == result
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -78,8 +87,11 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
}
|
}
|
||||||
|> Enum.each(fn {title, data} ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: [result, input], example_context: context,
|
test title, %{
|
||||||
inverse_context: inverse_context} do
|
data: [result, input],
|
||||||
|
example_context: context,
|
||||||
|
inverse_context: inverse_context
|
||||||
|
} do
|
||||||
assert compact_iri(input, context, inverse_context, nil, true) == result
|
assert compact_iri(input, context, inverse_context, nil, true) == result
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -95,8 +107,9 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
|
|
||||||
describe "with value" do
|
describe "with value" do
|
||||||
setup do
|
setup do
|
||||||
context = JSON.LD.context(%{
|
context =
|
||||||
"xsd" => XSD.__base_iri__,
|
JSON.LD.context(%{
|
||||||
|
"xsd" => XSD.__base_iri__(),
|
||||||
"plain" => "http://example.com/plain",
|
"plain" => "http://example.com/plain",
|
||||||
"lang" => %{"@id" => "http://example.com/lang", "@language" => "en"},
|
"lang" => %{"@id" => "http://example.com/lang", "@language" => "en"},
|
||||||
"bool" => %{"@id" => "http://example.com/bool", "@type" => "xsd:boolean"},
|
"bool" => %{"@id" => "http://example.com/bool", "@type" => "xsd:boolean"},
|
||||||
|
@ -105,21 +118,66 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
"date" => %{"@id" => "http://example.com/date", "@type" => "xsd:date"},
|
"date" => %{"@id" => "http://example.com/date", "@type" => "xsd:date"},
|
||||||
"id" => %{"@id" => "http://example.com/id", "@type" => "@id"},
|
"id" => %{"@id" => "http://example.com/id", "@type" => "@id"},
|
||||||
"listplain" => %{"@id" => "http://example.com/plain", "@container" => "@list"},
|
"listplain" => %{"@id" => "http://example.com/plain", "@container" => "@list"},
|
||||||
"listlang" => %{"@id" => "http://example.com/lang", "@language" => "en", "@container" => "@list"},
|
"listlang" => %{
|
||||||
"listbool" => %{"@id" => "http://example.com/bool", "@type" => "xsd:boolean", "@container" => "@list"},
|
"@id" => "http://example.com/lang",
|
||||||
"listinteger" => %{"@id" => "http://example.com/integer", "@type" => "xsd:integer", "@container" => "@list"},
|
"@language" => "en",
|
||||||
"listdouble" => %{"@id" => "http://example.com/double", "@type" => "xsd:double", "@container" => "@list"},
|
"@container" => "@list"
|
||||||
"listdate" => %{"@id" => "http://example.com/date", "@type" => "xsd:date", "@container" => "@list"},
|
},
|
||||||
"listid" => %{"@id" => "http://example.com/id", "@type" => "@id", "@container" => "@list"},
|
"listbool" => %{
|
||||||
|
"@id" => "http://example.com/bool",
|
||||||
|
"@type" => "xsd:boolean",
|
||||||
|
"@container" => "@list"
|
||||||
|
},
|
||||||
|
"listinteger" => %{
|
||||||
|
"@id" => "http://example.com/integer",
|
||||||
|
"@type" => "xsd:integer",
|
||||||
|
"@container" => "@list"
|
||||||
|
},
|
||||||
|
"listdouble" => %{
|
||||||
|
"@id" => "http://example.com/double",
|
||||||
|
"@type" => "xsd:double",
|
||||||
|
"@container" => "@list"
|
||||||
|
},
|
||||||
|
"listdate" => %{
|
||||||
|
"@id" => "http://example.com/date",
|
||||||
|
"@type" => "xsd:date",
|
||||||
|
"@container" => "@list"
|
||||||
|
},
|
||||||
|
"listid" => %{
|
||||||
|
"@id" => "http://example.com/id",
|
||||||
|
"@type" => "@id",
|
||||||
|
"@container" => "@list"
|
||||||
|
},
|
||||||
"setplain" => %{"@id" => "http://example.com/plain", "@container" => "@set"},
|
"setplain" => %{"@id" => "http://example.com/plain", "@container" => "@set"},
|
||||||
"setlang" => %{"@id" => "http://example.com/lang", "@language" => "en", "@container" => "@set"},
|
"setlang" => %{
|
||||||
"setbool" => %{"@id" => "http://example.com/bool", "@type" => "xsd:boolean", "@container" => "@set"},
|
"@id" => "http://example.com/lang",
|
||||||
"setinteger" => %{"@id" => "http://example.com/integer", "@type" => "xsd:integer", "@container" => "@set"},
|
"@language" => "en",
|
||||||
"setdouble" => %{"@id" => "http://example.com/double", "@type" => "xsd:double", "@container" => "@set"},
|
"@container" => "@set"
|
||||||
"setdate" => %{"@id" => "http://example.com/date", "@type" => "xsd:date", "@container" => "@set"},
|
},
|
||||||
|
"setbool" => %{
|
||||||
|
"@id" => "http://example.com/bool",
|
||||||
|
"@type" => "xsd:boolean",
|
||||||
|
"@container" => "@set"
|
||||||
|
},
|
||||||
|
"setinteger" => %{
|
||||||
|
"@id" => "http://example.com/integer",
|
||||||
|
"@type" => "xsd:integer",
|
||||||
|
"@container" => "@set"
|
||||||
|
},
|
||||||
|
"setdouble" => %{
|
||||||
|
"@id" => "http://example.com/double",
|
||||||
|
"@type" => "xsd:double",
|
||||||
|
"@container" => "@set"
|
||||||
|
},
|
||||||
|
"setdate" => %{
|
||||||
|
"@id" => "http://example.com/date",
|
||||||
|
"@type" => "xsd:date",
|
||||||
|
"@container" => "@set"
|
||||||
|
},
|
||||||
"setid" => %{"@id" => "http://example.com/id", "@type" => "@id", "@container" => "@set"},
|
"setid" => %{"@id" => "http://example.com/id", "@type" => "@id", "@container" => "@set"},
|
||||||
"langmap" => %{"@id" => "http://example.com/langmap", "@container" => "@language"},
|
"langmap" => %{"@id" => "http://example.com/langmap", "@container" => "@language"}
|
||||||
})
|
})
|
||||||
|
|
||||||
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -130,11 +188,15 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
}
|
}
|
||||||
|> Enum.each(fn {prop, value} ->
|
|> Enum.each(fn {prop, value} ->
|
||||||
@tag data: {prop, value}
|
@tag data: {prop, value}
|
||||||
test "uses #{prop} for #{inspect value}",
|
test "uses #{prop} for #{inspect(value)}",
|
||||||
%{data: {prop, value}, example_context: context,
|
%{data: {prop, value}, example_context: context, inverse_context: inverse_context} do
|
||||||
inverse_context: inverse_context} do
|
assert compact_iri(
|
||||||
assert compact_iri("http://example.com/#{String.replace(prop, "set", "")}",
|
"http://example.com/#{String.replace(prop, "set", "")}",
|
||||||
context, inverse_context, value, true) == prop
|
context,
|
||||||
|
inverse_context,
|
||||||
|
value,
|
||||||
|
true
|
||||||
|
) == prop
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
@ -148,25 +210,30 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
[%{"@value" => "de", "@language" => "de"}, %{"@value" => "jp", "@language" => "jp"}],
|
[%{"@value" => "de", "@language" => "de"}, %{"@value" => "jp", "@language" => "jp"}],
|
||||||
[%{"@value" => true}],
|
[%{"@value" => true}],
|
||||||
[%{"@value" => false}],
|
[%{"@value" => false}],
|
||||||
[%{"@value" => 1}], [%{"@value" => 1.1}],
|
[%{"@value" => 1}],
|
||||||
|
[%{"@value" => 1.1}]
|
||||||
],
|
],
|
||||||
"listlang" => [[%{"@value" => "en", "@language" => "en"}]],
|
"listlang" => [[%{"@value" => "en", "@language" => "en"}]],
|
||||||
"listbool" => [[%{"@value" => "true", "@type" => to_string(XSD.boolean)}]],
|
"listbool" => [[%{"@value" => "true", "@type" => to_string(XSD.boolean())}]],
|
||||||
"listinteger" => [[%{"@value" => "1", "@type" => to_string(XSD.integer)}]],
|
"listinteger" => [[%{"@value" => "1", "@type" => to_string(XSD.integer())}]],
|
||||||
"listdouble" => [[%{"@value" => "1", "@type" => to_string(XSD.double)}]],
|
"listdouble" => [[%{"@value" => "1", "@type" => to_string(XSD.double())}]],
|
||||||
"listdate" => [[%{"@value" => "2012-04-17", "@type" => to_string(XSD.date)}]],
|
"listdate" => [[%{"@value" => "2012-04-17", "@type" => to_string(XSD.date())}]]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn {prop, values} ->
|
|> Enum.each(fn {prop, values} ->
|
||||||
Enum.each values, fn value ->
|
Enum.each(values, fn value ->
|
||||||
@tag data: {prop, value}
|
@tag data: {prop, value}
|
||||||
test "for @list uses #{prop} for #{inspect %{"@list" => value}}",
|
test "for @list uses #{prop} for #{inspect(%{"@list" => value})}",
|
||||||
%{data: {prop, value}, example_context: context,
|
%{data: {prop, value}, example_context: context, inverse_context: inverse_context} do
|
||||||
inverse_context: inverse_context} do
|
assert compact_iri(
|
||||||
assert compact_iri("http://example.com/#{String.replace(prop, "list", "")}",
|
"http://example.com/#{String.replace(prop, "list", "")}",
|
||||||
context, inverse_context, %{"@list" => value}, true) == prop
|
context,
|
||||||
end
|
inverse_context,
|
||||||
|
%{"@list" => value},
|
||||||
|
true
|
||||||
|
) == prop
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
# describe "with :simple_compact_iris" do
|
# describe "with :simple_compact_iris" do
|
||||||
|
@ -210,7 +277,9 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
|
|
||||||
describe "compact-0018" do
|
describe "compact-0018" do
|
||||||
setup do
|
setup do
|
||||||
context = JSON.LD.context(Jason.decode! """
|
context =
|
||||||
|
JSON.LD.context(
|
||||||
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"id1": "http://example.com/id1",
|
"id1": "http://example.com/id1",
|
||||||
"type1": "http://example.com/t1",
|
"type1": "http://example.com/t1",
|
||||||
|
@ -245,10 +314,11 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
|
)
|
||||||
|
|
||||||
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
%{
|
%{
|
||||||
"term" => [
|
"term" => [
|
||||||
'{ "@value": "v0.1", "@language": "de" }',
|
'{ "@value": "v0.1", "@language": "de" }',
|
||||||
|
@ -317,20 +387,21 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
{ "@value": "v5.6", "@type": "http://example.com/t2" }
|
{ "@value": "v5.6", "@type": "http://example.com/t2" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
""",
|
"""
|
||||||
}
|
}
|
||||||
|> Enum.each(fn {term, values} ->
|
|> Enum.each(fn {term, values} ->
|
||||||
values = if is_binary(values),
|
values =
|
||||||
|
if is_binary(values),
|
||||||
do: [values],
|
do: [values],
|
||||||
else: values
|
else: values
|
||||||
|
|
||||||
Enum.each(values, fn value ->
|
Enum.each(values, fn value ->
|
||||||
value = Jason.decode!(value)
|
value = Jason.decode!(value)
|
||||||
@tag data: {term, value}
|
@tag data: {term, value}
|
||||||
test "uses #{term} for #{inspect value, limit: 3}",
|
test "uses #{term} for #{inspect(value, limit: 3)}",
|
||||||
%{data: {term, value}, example_context: context,
|
%{data: {term, value}, example_context: context, inverse_context: inverse_context} do
|
||||||
inverse_context: inverse_context} do
|
assert compact_iri("http://example.com/term", context, inverse_context, value, true) ==
|
||||||
assert compact_iri("http://example.com/term", context, inverse_context,
|
term
|
||||||
value, true) == term
|
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end)
|
end)
|
||||||
|
@ -338,17 +409,23 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
|
|
||||||
describe "compact-0020" do
|
describe "compact-0020" do
|
||||||
setup do
|
setup do
|
||||||
context = JSON.LD.context(%{
|
context =
|
||||||
|
JSON.LD.context(%{
|
||||||
"ex" => "http://example.org/ns#",
|
"ex" => "http://example.org/ns#",
|
||||||
"ex:property" => %{"@container" => "@list"}
|
"ex:property" => %{"@container" => "@list"}
|
||||||
})
|
})
|
||||||
|
|
||||||
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
||||||
end
|
end
|
||||||
|
|
||||||
@tag skip: "TODO: we don't support 'position: :subject'"
|
@tag skip: "TODO: we don't support 'position: :subject'"
|
||||||
test "Compact @id that is a property IRI when @container is @list", %{
|
test "Compact @id that is a property IRI when @container is @list", %{
|
||||||
example_context: context, inverse_context: inverse_context} do
|
example_context: context,
|
||||||
assert compact_iri("http://example.org/ns#property", context, inverse_context) == "ex:property"
|
inverse_context: inverse_context
|
||||||
|
} do
|
||||||
|
assert compact_iri("http://example.org/ns#property", context, inverse_context) ==
|
||||||
|
"ex:property"
|
||||||
|
|
||||||
# expect(ctx.compact_iri("http://example.org/ns#property", position: :subject)).
|
# expect(ctx.compact_iri("http://example.org/ns#property", position: :subject)).
|
||||||
# to produce("ex:property", logger)
|
# to produce("ex:property", logger)
|
||||||
end
|
end
|
||||||
|
@ -356,20 +433,22 @@ defmodule JSON.LD.IRICompactionTest do
|
||||||
|
|
||||||
describe "compact-0041" do
|
describe "compact-0041" do
|
||||||
setup do
|
setup do
|
||||||
context = JSON.LD.context(%{
|
context =
|
||||||
|
JSON.LD.context(%{
|
||||||
"name" => %{"@id" => "http://example.com/property", "@container" => "@list"}
|
"name" => %{"@id" => "http://example.com/property", "@container" => "@list"}
|
||||||
})
|
})
|
||||||
|
|
||||||
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
||||||
end
|
end
|
||||||
|
|
||||||
test "Does not use @list with @index", %{
|
test "Does not use @list with @index", %{
|
||||||
example_context: context, inverse_context: inverse_context} do
|
example_context: context,
|
||||||
assert compact_iri("http://example.com/property", context, inverse_context,
|
inverse_context: inverse_context
|
||||||
%{
|
} do
|
||||||
|
assert compact_iri("http://example.com/property", context, inverse_context, %{
|
||||||
"@list" => ["one item"],
|
"@list" => ["one item"],
|
||||||
"@index" => "an annotation"
|
"@index" => "an annotation"
|
||||||
}) == "http://example.com/property"
|
}) == "http://example.com/property"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,13 +4,15 @@ defmodule JSON.LD.IRIExpansionTest do
|
||||||
import JSON.LD.IRIExpansion
|
import JSON.LD.IRIExpansion
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
context = JSON.LD.context(%{
|
context =
|
||||||
|
JSON.LD.context(%{
|
||||||
"@base" => "http://base/",
|
"@base" => "http://base/",
|
||||||
"@vocab" => "http://vocab/",
|
"@vocab" => "http://vocab/",
|
||||||
"ex" => "http://example.org/",
|
"ex" => "http://example.org/",
|
||||||
"" => "http://empty/",
|
"" => "http://empty/",
|
||||||
"_" => "http://underscore/"
|
"_" => "http://underscore/"
|
||||||
})
|
})
|
||||||
|
|
||||||
%{example_context: context}
|
%{example_context: context}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -43,12 +45,11 @@ defmodule JSON.LD.IRIExpansionTest do
|
||||||
"unmapped" => ["foo", "foo"],
|
"unmapped" => ["foo", "foo"],
|
||||||
"empty term" => ["", ""],
|
"empty term" => ["", ""],
|
||||||
"another abs IRI" => ["ex://foo", "ex://foo"],
|
"another abs IRI" => ["ex://foo", "ex://foo"],
|
||||||
"absolute IRI looking like a curie" =>
|
"absolute IRI looking like a curie" => ["foo:bar", "foo:bar"],
|
||||||
["foo:bar", "foo:bar"],
|
|
||||||
"bnode" => ["_:t0", "_:t0"],
|
"bnode" => ["_:t0", "_:t0"],
|
||||||
"_" => ["_", "_"],
|
"_" => ["_", "_"]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: [input, result], example_context: context} do
|
test title, %{data: [input, result], example_context: context} do
|
||||||
assert expand_iri(input, context) == result
|
assert expand_iri(input, context) == result
|
||||||
|
@ -81,12 +82,11 @@ defmodule JSON.LD.IRIExpansionTest do
|
||||||
"unmapped" => ["foo", "http://base/foo"],
|
"unmapped" => ["foo", "http://base/foo"],
|
||||||
"empty term" => ["", "http://base/"],
|
"empty term" => ["", "http://base/"],
|
||||||
"another abs IRI" => ["ex://foo", "ex://foo"],
|
"another abs IRI" => ["ex://foo", "ex://foo"],
|
||||||
"absolute IRI looking like a curie" =>
|
"absolute IRI looking like a curie" => ["foo:bar", "foo:bar"],
|
||||||
["foo:bar", "foo:bar"],
|
|
||||||
"bnode" => ["_:t0", "_:t0"],
|
"bnode" => ["_:t0", "_:t0"],
|
||||||
"_" => ["_", "http://base/_"],
|
"_" => ["_", "http://base/_"]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: [input, result], example_context: context} do
|
test title, %{data: [input, result], example_context: context} do
|
||||||
assert expand_iri(input, context, true) == result
|
assert expand_iri(input, context, true) == result
|
||||||
|
@ -119,17 +119,15 @@ defmodule JSON.LD.IRIExpansionTest do
|
||||||
"unmapped" => ["foo", "http://vocab/foo"],
|
"unmapped" => ["foo", "http://vocab/foo"],
|
||||||
"empty term" => ["", "http://empty/"],
|
"empty term" => ["", "http://empty/"],
|
||||||
"another abs IRI" => ["ex://foo", "ex://foo"],
|
"another abs IRI" => ["ex://foo", "ex://foo"],
|
||||||
"absolute IRI looking like a curie" =>
|
"absolute IRI looking like a curie" => ["foo:bar", "foo:bar"],
|
||||||
["foo:bar", "foo:bar"],
|
|
||||||
"bnode" => ["_:t0", "_:t0"],
|
"bnode" => ["_:t0", "_:t0"],
|
||||||
"_" => ["_", "http://underscore/"],
|
"_" => ["_", "http://underscore/"]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: [input, result], example_context: context} do
|
test title, %{data: [input, result], example_context: context} do
|
||||||
assert expand_iri(input, context, false, true) == result
|
assert expand_iri(input, context, false, true) == result
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ defmodule JSON.LD.RemoteContextTest do
|
||||||
|
|
||||||
setup_all do
|
setup_all do
|
||||||
local =
|
local =
|
||||||
Jason.decode! """
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": {
|
"@context": {
|
||||||
"name": "http://xmlns.com/foaf/0.1/name",
|
"name": "http://xmlns.com/foaf/0.1/name",
|
||||||
|
@ -14,16 +14,16 @@ defmodule JSON.LD.RemoteContextTest do
|
||||||
"name": "Manu Sporny",
|
"name": "Manu Sporny",
|
||||||
"homepage": "http://manu.sporny.org/"
|
"homepage": "http://manu.sporny.org/"
|
||||||
}
|
}
|
||||||
"""
|
""")
|
||||||
|
|
||||||
remote =
|
remote =
|
||||||
Jason.decode! """
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": "http://example.com/test-context",
|
"@context": "http://example.com/test-context",
|
||||||
"name": "Manu Sporny",
|
"name": "Manu Sporny",
|
||||||
"homepage": "http://manu.sporny.org/"
|
"homepage": "http://manu.sporny.org/"
|
||||||
}
|
}
|
||||||
"""
|
""")
|
||||||
|
|
||||||
{:ok, local: local, remote: remote}
|
{:ok, local: local, remote: remote}
|
||||||
end
|
end
|
||||||
|
@ -42,13 +42,13 @@ defmodule JSON.LD.RemoteContextTest do
|
||||||
|
|
||||||
test "failed loading of remote context" do
|
test "failed loading of remote context" do
|
||||||
remote =
|
remote =
|
||||||
Jason.decode! """
|
Jason.decode!("""
|
||||||
{
|
{
|
||||||
"@context": "http://fake.com/fake-context",
|
"@context": "http://fake.com/fake-context",
|
||||||
"name": "Manu Sporny",
|
"name": "Manu Sporny",
|
||||||
"homepage": "http://manu.sporny.org/"
|
"homepage": "http://manu.sporny.org/"
|
||||||
}
|
}
|
||||||
"""
|
""")
|
||||||
|
|
||||||
assert_raise LoadingRemoteContextFailedError, fn ->
|
assert_raise LoadingRemoteContextFailedError, fn ->
|
||||||
JSON.LD.flatten(remote, nil, %Options{document_loader: DocumentLoader.Test})
|
JSON.LD.flatten(remote, nil, %Options{document_loader: DocumentLoader.Test})
|
||||||
|
|
|
@ -17,5 +17,4 @@ defmodule JSON.LD.UtilsTest do
|
||||||
assert compact_iri_parts("_:bar") == nil
|
assert compact_iri_parts("_:bar") == nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -6,42 +6,69 @@ defmodule JSON.LD.ValueCompactionTest do
|
||||||
alias RDF.NS.{XSD}
|
alias RDF.NS.{XSD}
|
||||||
|
|
||||||
setup do
|
setup do
|
||||||
context = JSON.LD.context(%{
|
context =
|
||||||
"dc" => "http://purl.org/dc/terms/", # TODO: RDF::Vocab::DC.to_uri.to_s,
|
JSON.LD.context(%{
|
||||||
|
# TODO: RDF::Vocab::DC.to_uri.to_s,
|
||||||
|
"dc" => "http://purl.org/dc/terms/",
|
||||||
"ex" => "http://example.org/",
|
"ex" => "http://example.org/",
|
||||||
"foaf" => "http://xmlns.com/foaf/0.1/", # TODO: RDF::Vocab::FOAF.to_uri.to_s,
|
# TODO: RDF::Vocab::FOAF.to_uri.to_s,
|
||||||
"xsd" => to_string(XSD.__base_iri__),
|
"foaf" => "http://xmlns.com/foaf/0.1/",
|
||||||
|
"xsd" => to_string(XSD.__base_iri__()),
|
||||||
"langmap" => %{"@id" => "http://example.com/langmap", "@container" => "@language"},
|
"langmap" => %{"@id" => "http://example.com/langmap", "@container" => "@language"},
|
||||||
"list" => %{"@id" => "http://example.org/list", "@container" => "@list"},
|
"list" => %{"@id" => "http://example.org/list", "@container" => "@list"},
|
||||||
"nolang" => %{"@id" => "http://example.org/nolang", "@language" => nil},
|
"nolang" => %{"@id" => "http://example.org/nolang", "@language" => nil},
|
||||||
"dc:created" => %{"@type" => to_string(XSD.date)},
|
"dc:created" => %{"@type" => to_string(XSD.date())},
|
||||||
"foaf:age" => %{"@type" => to_string(XSD.integer)},
|
"foaf:age" => %{"@type" => to_string(XSD.integer())},
|
||||||
"foaf:knows" => %{"@type" => "@id"},
|
"foaf:knows" => %{"@type" => "@id"}
|
||||||
})
|
})
|
||||||
|
|
||||||
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
%{example_context: context, inverse_context: JSON.LD.Context.inverse(context)}
|
||||||
end
|
end
|
||||||
|
|
||||||
%{
|
%{
|
||||||
"absolute IRI" => ["foaf:knows", "http://example.com/", %{"@id" => "http://example.com/"}],
|
"absolute IRI" => ["foaf:knows", "http://example.com/", %{"@id" => "http://example.com/"}],
|
||||||
"prefix:suffix" => ["foaf:knows", "ex:suffix", %{"@id" => "http://example.org/suffix"}],
|
"prefix:suffix" => ["foaf:knows", "ex:suffix", %{"@id" => "http://example.org/suffix"}],
|
||||||
"integer" => ["foaf:age", "54", %{"@value" => "54", "@type" => to_string(XSD.integer)}],
|
"integer" => ["foaf:age", "54", %{"@value" => "54", "@type" => to_string(XSD.integer())}],
|
||||||
"date " => ["dc:created", "2011-12-27Z", %{"@value" => "2011-12-27Z", "@type" => to_string(XSD.date)}],
|
"date " => [
|
||||||
|
"dc:created",
|
||||||
|
"2011-12-27Z",
|
||||||
|
%{"@value" => "2011-12-27Z", "@type" => to_string(XSD.date())}
|
||||||
|
],
|
||||||
"no IRI" => ["foo", %{"@id" => "http://example.com/"}, %{"@id" => "http://example.com/"}],
|
"no IRI" => ["foo", %{"@id" => "http://example.com/"}, %{"@id" => "http://example.com/"}],
|
||||||
"no IRI (CURIE)" => ["foo", %{"@id" => "http://xmlns.com/foaf/0.1/Person"}, %{"@id" => "http://xmlns.com/foaf/0.1/Person"}],
|
"no IRI (CURIE)" => [
|
||||||
"no boolean" => ["foo", %{"@value" => "true", "@type" => to_string(XSD.boolean)},%{"@value" => "true", "@type" => to_string(XSD.boolean)}],
|
"foo",
|
||||||
"no integer" => ["foo", %{"@value" => "54", "@type" => to_string(XSD.integer)},%{"@value" => "54", "@type" => to_string(XSD.integer)}],
|
%{"@id" => "http://xmlns.com/foaf/0.1/Person"},
|
||||||
"no date " => ["foo", %{"@value" => "2011-12-27Z", "@type" => to_string(XSD.date)}, %{"@value" => "2011-12-27Z", "@type" => to_string(XSD.date)}],
|
%{"@id" => "http://xmlns.com/foaf/0.1/Person"}
|
||||||
|
],
|
||||||
|
"no boolean" => [
|
||||||
|
"foo",
|
||||||
|
%{"@value" => "true", "@type" => to_string(XSD.boolean())},
|
||||||
|
%{"@value" => "true", "@type" => to_string(XSD.boolean())}
|
||||||
|
],
|
||||||
|
"no integer" => [
|
||||||
|
"foo",
|
||||||
|
%{"@value" => "54", "@type" => to_string(XSD.integer())},
|
||||||
|
%{"@value" => "54", "@type" => to_string(XSD.integer())}
|
||||||
|
],
|
||||||
|
"no date " => [
|
||||||
|
"foo",
|
||||||
|
%{"@value" => "2011-12-27Z", "@type" => to_string(XSD.date())},
|
||||||
|
%{"@value" => "2011-12-27Z", "@type" => to_string(XSD.date())}
|
||||||
|
],
|
||||||
"no string " => ["foo", "string", %{"@value" => "string"}],
|
"no string " => ["foo", "string", %{"@value" => "string"}],
|
||||||
"no lang " => ["nolang", "string", %{"@value" => "string"}],
|
"no lang " => ["nolang", "string", %{"@value" => "string"}],
|
||||||
"native boolean" => ["foo", true, %{"@value" => true}],
|
"native boolean" => ["foo", true, %{"@value" => true}],
|
||||||
"native integer" => ["foo", 1, %{"@value" => 1}],
|
"native integer" => ["foo", 1, %{"@value" => 1}],
|
||||||
"native integer(list)" => ["list", 1, %{"@value" => 1}],
|
"native integer(list)" => ["list", 1, %{"@value" => 1}],
|
||||||
"native double" => ["foo", 1.1e1, %{"@value" => 1.1E1}],
|
"native double" => ["foo", 1.1e1, %{"@value" => 1.1e1}]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: [key, compacted, expanded], example_context: context,
|
test title, %{
|
||||||
inverse_context: inverse_context} do
|
data: [key, compacted, expanded],
|
||||||
|
example_context: context,
|
||||||
|
inverse_context: inverse_context
|
||||||
|
} do
|
||||||
assert compact_value(expanded, context, inverse_context, key) == compacted
|
assert compact_value(expanded, context, inverse_context, key) == compacted
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -54,28 +81,55 @@ defmodule JSON.LD.ValueCompactionTest do
|
||||||
|
|
||||||
%{
|
%{
|
||||||
"@id" => ["foo", %{"@id" => "foo"}, %{"@id" => "foo"}],
|
"@id" => ["foo", %{"@id" => "foo"}, %{"@id" => "foo"}],
|
||||||
"integer" => ["foo", %{"@value" => "54", "@type" => to_string(XSD.integer)}, %{"@value" => "54", "@type" => to_string(XSD.integer)}],
|
"integer" => [
|
||||||
"date" => ["foo", %{"@value" => "2011-12-27Z","@type" => to_string(XSD.date)},%{"@value" => "2011-12-27Z", "@type" => to_string(XSD.date)}],
|
"foo",
|
||||||
|
%{"@value" => "54", "@type" => to_string(XSD.integer())},
|
||||||
|
%{"@value" => "54", "@type" => to_string(XSD.integer())}
|
||||||
|
],
|
||||||
|
"date" => [
|
||||||
|
"foo",
|
||||||
|
%{"@value" => "2011-12-27Z", "@type" => to_string(XSD.date())},
|
||||||
|
%{"@value" => "2011-12-27Z", "@type" => to_string(XSD.date())}
|
||||||
|
],
|
||||||
"no lang" => ["foo", %{"@value" => "foo"}, %{"@value" => "foo"}],
|
"no lang" => ["foo", %{"@value" => "foo"}, %{"@value" => "foo"}],
|
||||||
"same lang" => ["foo", "foo", %{"@value" => "foo", "@language" => "en"}],
|
"same lang" => ["foo", "foo", %{"@value" => "foo", "@language" => "en"}],
|
||||||
"other lang" => ["foo", %{"@value" => "foo", "@language" => "bar"}, %{"@value" => "foo", "@language" => "bar"}],
|
"other lang" => [
|
||||||
|
"foo",
|
||||||
|
%{"@value" => "foo", "@language" => "bar"},
|
||||||
|
%{"@value" => "foo", "@language" => "bar"}
|
||||||
|
],
|
||||||
"langmap" => ["langmap", "en", %{"@value" => "en", "@language" => "en"}],
|
"langmap" => ["langmap", "en", %{"@value" => "en", "@language" => "en"}],
|
||||||
"no lang with @type coercion" => ["dc:created", %{"@value" => "foo"}, %{"@value" => "foo"}],
|
"no lang with @type coercion" => ["dc:created", %{"@value" => "foo"}, %{"@value" => "foo"}],
|
||||||
"no lang with @id coercion" => ["foaf:knows", %{"@value" => "foo"}, %{"@value" => "foo"}],
|
"no lang with @id coercion" => ["foaf:knows", %{"@value" => "foo"}, %{"@value" => "foo"}],
|
||||||
"no lang with @language=null" => ["nolang", "string", %{"@value" => "string"}],
|
"no lang with @language=null" => ["nolang", "string", %{"@value" => "string"}],
|
||||||
"same lang with @type coercion" => ["dc:created", %{"@value" => "foo"}, %{"@value" => "foo"}],
|
"same lang with @type coercion" => [
|
||||||
|
"dc:created",
|
||||||
|
%{"@value" => "foo"},
|
||||||
|
%{"@value" => "foo"}
|
||||||
|
],
|
||||||
"same lang with @id coercion" => ["foaf:knows", %{"@value" => "foo"}, %{"@value" => "foo"}],
|
"same lang with @id coercion" => ["foaf:knows", %{"@value" => "foo"}, %{"@value" => "foo"}],
|
||||||
"other lang with @type coercion" => ["dc:created", %{"@value" => "foo", "@language" => "bar"}, %{"@value" => "foo", "@language" => "bar"}],
|
"other lang with @type coercion" => [
|
||||||
"other lang with @id coercion" => ["foaf:knows", %{"@value" => "foo", "@language" => "bar"}, %{"@value" => "foo", "@language" => "bar"}],
|
"dc:created",
|
||||||
|
%{"@value" => "foo", "@language" => "bar"},
|
||||||
|
%{"@value" => "foo", "@language" => "bar"}
|
||||||
|
],
|
||||||
|
"other lang with @id coercion" => [
|
||||||
|
"foaf:knows",
|
||||||
|
%{"@value" => "foo", "@language" => "bar"},
|
||||||
|
%{"@value" => "foo", "@language" => "bar"}
|
||||||
|
],
|
||||||
"native boolean" => ["foo", true, %{"@value" => true}],
|
"native boolean" => ["foo", true, %{"@value" => true}],
|
||||||
"native integer" => ["foo", 1, %{"@value" => 1}],
|
"native integer" => ["foo", 1, %{"@value" => 1}],
|
||||||
"native integer(list)" => ["list", 1, %{"@value" => 1}],
|
"native integer(list)" => ["list", 1, %{"@value" => 1}],
|
||||||
"native double" => ["foo", 1.1e1, %{"@value" => 1.1E1}],
|
"native double" => ["foo", 1.1e1, %{"@value" => 1.1e1}]
|
||||||
}
|
}
|
||||||
|> Enum.each(fn ({title, data}) ->
|
|> Enum.each(fn {title, data} ->
|
||||||
@tag data: data
|
@tag data: data
|
||||||
test title, %{data: [key, compacted, expanded], example_context: context,
|
test title, %{
|
||||||
inverse_context: inverse_context} do
|
data: [key, compacted, expanded],
|
||||||
|
example_context: context,
|
||||||
|
inverse_context: inverse_context
|
||||||
|
} do
|
||||||
assert compact_value(expanded, context, inverse_context, key) == compacted
|
assert compact_value(expanded, context, inverse_context, key) == compacted
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
@ -103,5 +157,4 @@ defmodule JSON.LD.ValueCompactionTest do
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
# end
|
# end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue