Skip to content

Commit

Permalink
Update string:concatenation to use XPath casting functions from SPARQL.
Browse files Browse the repository at this point in the history
  • Loading branch information
gkellogg committed Nov 18, 2020
1 parent 2cf09a3 commit 044743f
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 8 deletions.
2 changes: 1 addition & 1 deletion lib/rdf/n3/algebra/resource_operator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ def valid?(subject, object)
end

##
# Returns a literal for the numeric argument, with doubles canonicalized using a lower-case 'e'.
# Returns a literal for the numeric argument.
def as_literal(object)
case object
when Float
Expand Down
10 changes: 8 additions & 2 deletions lib/rdf/n3/algebra/str/concatenation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,19 @@ class Concatenation < RDF::N3::Algebra::ListOperator
URI = RDF::N3::Str.concatenation

##
# The string:concatenation operator takes a list of terms evaluating to strings and either binds the result of concatenating them to the output variable, removes a solution that does equal.
# The string:concatenation operator takes a list of terms cast to strings and either binds the result of concatenating them to the output variable, removes a solution that does equal the literal object.
#
# List entries are stringified using {SPARQL::Algebra::Expression.cast}.
#
# @param [RDF::N3::List] list
# @return [RDF::Term]
# @see RDF::N3::ListOperator#evaluate
def resolve(list)
RDF::Literal(list.to_a.map(&:canonicalize).join(""))
RDF::Literal(
list.to_a.map do |o|
SPARQL::Algebra::Expression.cast(RDF::XSD.string, o)
end.join("")
)
end
end
end
84 changes: 79 additions & 5 deletions spec/reasoner_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -285,14 +285,14 @@
<http://www.w3.org/2000/10/swap/test/crypto/acc.n3#foo> <http://www.w3.org/2000/10/swap/test/crypto/acc.n3#credential> <http://example.com/access-tina-cert.n3>;
<http://www.w3.org/2000/10/swap/test/crypto/acc.n3#forDocument> <http://www.w3.org/Member>;
<http://www.w3.org/2000/10/swap/test/crypto/acc.n3#junk> "32746213462187364732164732164321" .
} a <#result> .
} a <http://example.com/#result> .
)
}
}.each do |name, options|
it name do
logger.info "input: #{options[:input]}"
pending(options[:pending]) if options[:pending]
options = {data: false, conclusions: true}.merge(options)
options = {data: false, conclusions: true, base_uri: 'http://example.com/'}.merge(options)
expected = parse(options[:expect])
result = reason(options[:input], **options)
expect(result).to be_equivalent_graph(expected, logger: logger, format: :n3)
Expand Down Expand Up @@ -878,6 +878,80 @@
end

context "n3:string" do
context "string:concatenation" do
{
"string": {
input: %(
@prefix string: <http://www.w3.org/2000/10/swap/string#>.
{("foo" "bar") string:concatenation ?x} => {:test :is ?x}.
),
expect: %(:test :is "foobar" .)
},
"integer": {
input: %(
@prefix string: <http://www.w3.org/2000/10/swap/string#>.
{(1 01) string:concatenation ?x} => {:test :is ?x}.
),
expect: %(:test :is "11" .)
},
"decimal": {
input: %(
@prefix string: <http://www.w3.org/2000/10/swap/string#>.
{(0.0 1.0 2.5 -2.5) string:concatenation ?x} => {:test :is ?x}.
),
expect: %(:test :is "012.5-2.5" .)
},
"boolean": {
input: %(
@prefix string: <http://www.w3.org/2000/10/swap/string#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
{(
true
false
"0"^^xsd:boolean
) string:concatenation ?x} => {:test :is ?x}.
),
expect: %(:test :is "truefalsefalse" .)
},
"float": {
input: %(
@prefix string: <http://www.w3.org/2000/10/swap/string#>.
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
{(
"0E1"^^xsd:float
"1E0"^^xsd:float
"1.25"^^xsd:float
"-7.875"^^xsd:float
) string:concatenation ?x} => {:test :is ?x}.
),
expect: %(:test :is "011.25-7.875" .)
},
"double": {
input: %(
@prefix string: <http://www.w3.org/2000/10/swap/string#>.
{(0E1 1E0 1.23E3) string:concatenation ?x} => {:test :is ?x}.
),
expect: %(:test :is "011230" .)
},
"IRI": {
input: %(
@prefix string: <http://www.w3.org/2000/10/swap/string#>.
{(:a " " :b) string:concatenation ?x} => {:test :is ?x}.
),
expect: %(:test :is "http://example.org/a http://example.org/b" .),
base_uri: "http://example.org/"
},
}.each do |name, options|
it name do
logger.info "input: #{options[:input]}"
pending(options[:pending]) if options[:pending]
options = {conclusions: true}.merge(options)
expected = parse(options[:expect], base_uri: options[:base_uri])
expect(reason(options[:input], **options)).to be_equivalent_graph(expected, logger: logger)
end
end
end

context "string:startsWith" do
{
"literal starts with literal" => {
Expand Down Expand Up @@ -946,9 +1020,9 @@ def parse(input, **options)
end

# Reason over input, returning a repo
def reason(input, base_uri: 'http://example.com/', conclusions: false, data: true, think: true, **options)
input = parse(input, list_terms: true, **options) if input.is_a?(String)
reasoner = RDF::N3::Reasoner.new(input, base_uri: base_uri, logger: logger)
def reason(input, base_uri: nil, conclusions: false, data: true, think: true, **options)
input = parse(input, list_terms: true, base_uri: base_uri, **options) if input.is_a?(String)
reasoner = RDF::N3::Reasoner.new(input, logger: logger, base_uri: base_uri)
repo = RDF::N3:: Repository.new

reasoner.execute(think: think)
Expand Down

0 comments on commit 044743f

Please sign in to comment.