lib/sxp/extensions.rb in sxp-1.1.0 vs lib/sxp/extensions.rb in sxp-1.2.0

- old
+ new

@@ -1,26 +1,326 @@ +# -*- encoding: utf-8 -*- +require 'bigdecimal' +require 'matrix' +require 'time' + ## +# Extensions for Ruby's `Object` class. +class Object + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + to_s.to_json + end +end + +## +# Extensions for Ruby's `NilClass` class. +class NilClass + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + '#n' + end +end + +## +# Extensions for Ruby's `FalseClass` class. +class FalseClass + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + '#f' + end +end + +## +# Extensions for Ruby's `TrueClass` class. +class TrueClass + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + '#t' + end +end + +## +# Extensions for Ruby's `String` class. +class String + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + inspect + end +end + +## # Extensions for Ruby's `Symbol` class. class Symbol ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + to_s + end + + ## # Returns `true` if this is a keyword symbol. # # @return [Boolean] def keyword? to_s[-1] == ?: end end -# Update RDF::URI if RDF is loaded +## +# Extensions for Ruby's `Integer` class. +class Integer + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + to_s + end +end + +## +# Extensions for Ruby's `BigDecimal` class. +class BigDecimal + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + to_f.to_s + end +end + +## +# Extensions for Ruby's `Float` class. +class Float + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + case + when nan? then 'nan.0' + when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0') + else to_s + end + end +end + +## +# Extensions for Ruby's `Array` class. +class Array + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp() + '(' << map { |x| x.to_sxp(**options) }.join(' ') << ')' + end +end + +## +# Extensions for Ruby's `Vector` class. +class Vector + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + '#(' << to_a.map { |x| x.to_sxp(**options) }.join(' ') << ')' + end +end + +## +# Extensions for Ruby's `Hash` class. +class Hash + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + to_a.to_sxp(**options) + end +end + +## +# Extensions for Ruby's `Time` class. +class Time + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + '#@' << (respond_to?(:xmlschema) ? xmlschema : to_i).to_s + end +end + +## +# Extensions for Ruby's `Regexp` class. +class Regexp + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + '#' << inspect + end +end + begin - require 'rdf' + require 'rdf' # For SPARQL/RDF ## - # Extensions for RDF::URI + # Extensions for Ruby's `Array` class. + # These extensions depend on RDF being loaded + class Array + ## + # Returns the SXP representation of this object. + # + # If array is of the form `[:base, uri, ..]`, the base_uri is taken from the second value + # + # If array is of the form `[:prefix, [..], ..]`, prefixes are taken from the second value + # + # Prefixes always are terminated by a ':' + # + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil, **options) + if self.first == :base && self.length == 3 && self[1].is_a?(RDF::URI) + base_uri = self[1] + '(' << ( + self[0,2].map(&:to_sxp) << + self.last.to_sxp(prefixes: prefixes, base_uri: base_uri, **options) + ).join(' ') << ')' + elsif self.first == :prefix && self.length == 3 && self[1].is_a?(Array) + prefixes = prefixes ? prefixes.dup : {} + self[1].each do |defn| + prefixes[defn.first.to_s.chomp(':').to_sym] = RDF::URI(defn.last) if + defn.is_a?(Array) && defn.length == 2 + end + pfx_sxp = self[1].map {|(p,s)|["#{p.to_s.chomp(':')}:".to_sym, RDF::URI(s)]}.to_sxp + '(' << [ + :prefix, + pfx_sxp, + self.last.to_sxp(prefixes: prefixes, base_uri: base_uri, **options) + ].join(' ') << ')' + else + '(' << map { |x| x.to_sxp(prefixes: prefixes, base_uri: base_uri, **options) }.join(' ') << ')' + end + end + end + class RDF::URI + ## + # Returns the SXP representation of this a URI. Uses Lexical representation, if set, otherwise, any PName match, otherwise, the relativized version of the URI if a base_uri is given, otherwise just the URI. + # + # @param [Hash{Symbol => RDF::URI}] prefixes(nil) + # @param [RDF::URI] base_uri(nil) + # @return [String] + def to_sxp(prefixes: nil, base_uri: nil, **options) + return lexical if lexical + pn = pname(prefixes: prefixes || {}) + return pn unless to_s == pn + md = self == base_uri ? '' : self.relativize(base_uri) + "<#{md}>" + end + # Original lexical value of this URI to allow for round-trip serialization. def lexical=(value); @lexical = value; end def lexical; @lexical; end end + + class RDF::Node + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + to_s + end + end + + class RDF::Literal + ## + # Returns the SXP representation of a Literal. + # + # @return [String] + def to_sxp(**options) + case datatype + when RDF::XSD.boolean, RDF::XSD.integer, RDF::XSD.double, RDF::XSD.decimal, RDF::XSD.time + # Retain stated lexical form if possible + valid? ? to_s : object.to_sxp(**options) + else + text = value.dump + text << "@#{language}" if self.has_language? + text << "^^#{datatype.to_sxp(**options)}" if self.has_datatype? + text + end + end + + class Double + ## + # Returns the SXP representation of this object. + # + # @return [String] + def to_sxp(**options) + case + when nan? then 'nan.0' + when infinite? then (infinite? > 0 ? '+inf.0' : '-inf.0') + else canonicalize.to_s.downcase + end + end + end + end + + class RDF::Query + # Transform Query into an Array form of an SXP + # + # If Query is named, it's treated as a GroupGraphPattern, otherwise, a BGP + # + # @return [Array] + def to_sxp(**options) + res = [:bgp] + patterns + (named? ? [:graph, graph_name, res] : res).to_sxp(**options) + end + end + + class RDF::Query::Pattern + # Transform Query Pattern into an SXP + # + # @return [String] + def to_sxp(**options) + [:triple, subject, predicate, object].to_sxp(**options) + end + end + + class RDF::Query::Variable + ## + # Transform Query variable into an SXP. + # + # @return [String] + def to_sxp(**options) + prefix = distinguished? ? (existential? ? '$' : '?') : (existential? ? '$$' : '??') + unbound? ? "#{prefix}#{name}".to_sym.to_sxp : ["#{prefix}#{name}".to_sym, value].to_sxp + end + end rescue LoadError - # Ignore + # Ignore if RDF not loaded end