module SPARQL; module Algebra
class Operator
##
# The SPARQL `replace` operator.
#
# @example
# (prefix ((: )
# (xsd: ))
# (project (?s ?new)
# (extend ((?new (replace ?str "[^a-z0-9]" "-")))
# (bgp (triple ?s :str ?str)))))
#
# @see https://www.w3.org/TR/sparql11-query/#funcex-replace
# @see https://www.w3.org/TR/xpath-functions/#func-replace
class Replace < Operator::Quaternary
include Evaluatable
NAME = :replace
##
# Initializes a new operator instance.
#
# @param [RDF::Literal] text
# @param [RDF::Literal] pattern
# @param [RDF::Literal] replacement
# @param [RDF::Literal] flags
# @param [Hash{Symbol => Object}] options
# any additional options (see {Operator#initialize})
# @raise [TypeError] if any operand is invalid
def initialize(text, pattern, replacement, flags = RDF::Literal(''), **options)
super
end
##
# Matches `text` against a regular expression `pattern`.
#
# @param [RDF::Literal] text a simple literal
# @param [RDF::Literal] pattern a simple literal
# @param [RDF::Literal] replacement
# @param [RDF::Literal] flags
# a simple literal (defaults to an empty string)
# @return [RDF::Literal]
# @raise [TypeError] if any operand is unbound
# @raise [TypeError] if any operand is not a plain literal
def apply(text, pattern, replacement, flags = RDF::Literal(''))
raise TypeError, "expected a plain RDF::Literal, but got #{text.inspect}" unless text.literal? && text.plain?
# TODO: validate text syntax
raise TypeError, "expected a plain RDF::Literal, but got #{pattern.inspect}" unless pattern.literal? && pattern.plain?
pattern = pattern.to_s
# TODO: validate pattern syntax
raise TypeError, "expected a plain RDF::Literal, but got #{replacement.inspect}" unless replacement.literal? && replacement.plain?
replacement = replacement.to_s.gsub('$', '\\') # Replace references
# TODO: validate flag syntax
raise TypeError, "expected a plain RDF::Literal, but got #{flags.inspect}" unless flags.literal? && flags.plain?
flags = flags.to_s
# TODO: validate flag syntax
options = 0
raise NotImplementedError, "unsupported regular expression flag: /s" if flags.include?(?s) # FIXME
options |= Regexp::MULTILINE if flags.include?(?m)
options |= Regexp::IGNORECASE if flags.include?(?i)
options |= Regexp::EXTENDED if flags.include?(?x)
RDF::Literal(text.to_s.gsub(Regexp.new(pattern, options), replacement), datatype: text.datatype, language: text.language)
end
##
# Returns the SPARQL S-Expression (SSE) representation of this expression.
#
# Remove the optional argument.
#
# @return [Array] `self`
# @see https://openjena.org/wiki/SSE
def to_sxp_bin
[NAME] + operands.reject {|o| o.to_s == ""}
end
end # Replace
end # Operator
end; end # SPARQL::Algebra