Add RDF.LangString.match_language?/2
This commit is contained in:
parent
4cea91e52f
commit
34898cd696
3 changed files with 106 additions and 2 deletions
|
@ -18,7 +18,8 @@ This project adheres to [Semantic Versioning](http://semver.org/) and
|
|||
all numeric literals, eg. arithmetic functions
|
||||
- the logical operators and the Effective Boolean Value (EBV) coercion algorithm
|
||||
from the XPath and SPARQL specs on `RDF.Boolean`
|
||||
- `RDF.Term.equal?/2` and `RDF.Term.equal_value?/2`
|
||||
- `RDF.Term.equal?/2` and `RDF.Term.equal_value?/2`
|
||||
- `RDF.LangString.match_language?/2`
|
||||
|
||||
|
||||
### Changed
|
||||
|
|
|
@ -22,4 +22,35 @@ defmodule RDF.LangString do
|
|||
def valid?(%Literal{language: nil}), do: false
|
||||
def valid?(literal), do: super(literal)
|
||||
|
||||
|
||||
@doc """
|
||||
Checks if a language tagged string literal or language tag matches a language range.
|
||||
|
||||
The check is performed per the basic filtering scheme defined in
|
||||
[RFC4647](http://www.ietf.org/rfc/rfc4647.txt) section 3.3.1.
|
||||
A language range is a basic language range per _Matching of Language Tags_ in
|
||||
RFC4647 section 2.1.
|
||||
A language range of `"*"` matches any non-empty language-tag string.
|
||||
|
||||
see <https://www.w3.org/TR/sparql11-query/#func-langMatches>
|
||||
"""
|
||||
def match_language?(language_tag, language_range)
|
||||
|
||||
def match_language?(%Literal{language: nil}, _), do: false
|
||||
def match_language?(%Literal{language: language_tag}, language_range),
|
||||
do: match_language?(language_tag, language_range)
|
||||
|
||||
def match_language?("", "*"), do: false
|
||||
def match_language?(_, "*"), do: true
|
||||
|
||||
def match_language?(language_tag, language_range) do
|
||||
language_tag = String.downcase(language_tag)
|
||||
language_range = String.downcase(language_range)
|
||||
|
||||
case String.split(language_tag, language_range, parts: 2) do
|
||||
[_, rest] -> rest == "" or String.starts_with?(rest, "-")
|
||||
_ -> false
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -146,5 +146,77 @@ defmodule RDF.LangStringTest do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
describe "match_language?/2" do
|
||||
@positive_examples [
|
||||
{"de", "de"},
|
||||
{"de", "DE"},
|
||||
{"de-DE", "de"},
|
||||
{"de-CH", "de"},
|
||||
{"de-CH", "de-ch"},
|
||||
{"de-DE-1996", "de-de"},
|
||||
]
|
||||
|
||||
@negative_examples [
|
||||
{"en", "de"},
|
||||
{"de", "de-CH"},
|
||||
{"de-Deva", "de-de"},
|
||||
{"de-Latn-DE", "de-de"},
|
||||
]
|
||||
|
||||
test "with a language tag and a matching non-'*' language range" do
|
||||
Enum.each @positive_examples, fn {language_tag, language_range} ->
|
||||
assert LangString.match_language?(language_tag, language_range),
|
||||
"expected language range #{inspect language_range} to match language tag #{inspect language_tag}, but it didn't"
|
||||
end
|
||||
end
|
||||
|
||||
test "with a language tag and a non-matching non-'*' language range" do
|
||||
Enum.each @negative_examples, fn {language_tag, language_range} ->
|
||||
refute LangString.match_language?(language_tag, language_range),
|
||||
"expected language range #{inspect language_range} to not match language tag #{inspect language_tag}, but it did"
|
||||
end
|
||||
end
|
||||
|
||||
test "with a language tag and '*' language range" do
|
||||
Enum.each @positive_examples ++ @negative_examples, fn {language_tag, _} ->
|
||||
assert LangString.match_language?(language_tag, "*"),
|
||||
~s[expected language range "*" to match language tag #{inspect language_tag}, but it didn't]
|
||||
end
|
||||
end
|
||||
|
||||
test "with the empty string as language tag" do
|
||||
refute LangString.match_language?("", "de")
|
||||
refute LangString.match_language?("", "*")
|
||||
end
|
||||
|
||||
test "with the empty string as language range" do
|
||||
refute LangString.match_language?("de", "")
|
||||
end
|
||||
|
||||
test "with a language-tagged literal and a language range" do
|
||||
Enum.each @positive_examples, fn {language_tag, language_range} ->
|
||||
literal = RDF.lang_string("foo", language: language_tag)
|
||||
assert LangString.match_language?(literal, language_range),
|
||||
"expected language range #{inspect language_range} to match #{inspect literal}, but it didn't"
|
||||
end
|
||||
Enum.each @negative_examples, fn {language_tag, language_range} ->
|
||||
literal = RDF.lang_string("foo", language: language_tag)
|
||||
refute LangString.match_language?(literal, language_range),
|
||||
"expected language range #{inspect language_range} to not match #{inspect literal}, but it did"
|
||||
end
|
||||
refute LangString.match_language?(RDF.lang_string("foo", language: ""), "de")
|
||||
refute LangString.match_language?(RDF.lang_string("foo", language: ""), "*")
|
||||
refute LangString.match_language?(RDF.lang_string("foo", language: nil), "de")
|
||||
refute LangString.match_language?(RDF.lang_string("foo", language: nil), "*")
|
||||
end
|
||||
|
||||
test "with a non-language-tagged literal" do
|
||||
refute RDF.string("42") |> LangString.match_language?("de")
|
||||
refute RDF.string("42") |> LangString.match_language?("")
|
||||
refute RDF.integer("42") |> LangString.match_language?("de")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue