Module: RDF::Reasoner::RDFS

Defined in:
vendor/bundler/ruby/2.5.0/bundler/gems/rdf-reasoner-0705d0a3eca4/lib/rdf/reasoner/rdfs.rb

Overview

Rules for generating RDFS entailment triples

Extends RDF::URI and RDF::Statement with specific entailment capabilities

Instance Method Summary collapse

Instance Method Details

#domain_compatible_rdfs?(resource, queryable, options = {}) ⇒ Boolean

RDFS requires that if the property has a domain, and the resource has a type that some type matches every domain.

Note that this is different than standard entailment, which simply asserts that the resource has every type in the domain, but this is more useful to check if published data is consistent with the vocabulary definition.

Parameters:

Options Hash (options):

Returns:

  • (Boolean)

Raises:



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'vendor/bundler/ruby/2.5.0/bundler/gems/rdf-reasoner-0705d0a3eca4/lib/rdf/reasoner/rdfs.rb', line 194

def domain_compatible_rdfs?(resource, queryable, options = {})
  raise RDF::Reasoner::Error, "#{self} can't get domains" unless property?
  domains = Array(self.domain).reject(&:node?) - [RDF::OWL.Thing, RDF::RDFS.Resource]

  # Fully entailed types of the resource
  types = options.fetch(:types) do
    queryable.query(subject: resource, predicate: RDF.type).
      map {|s| (t = (RDF::Vocabulary.find_term(s.object)) rescue nil) && t.entail(:subClassOf)}.
      flatten.
      uniq.
      compact
  end unless domains.empty?

  # Every domain must match some entailed type
  Array(types).empty? || domains.all? {|d| types.include?(d)}
end

#range_compatible_rdfs?(resource, queryable, options = {}) ⇒ Boolean

RDFS requires that if the property has a range, and the resource has a type that some type matches every range. If the resource is a datatyped Literal, and the range includes a datatype, the resource must be consistent with that.

Note that this is different than standard entailment, which simply asserts that the resource has every type in the range, but this is more useful to check if published data is consistent with the vocabulary definition.

Parameters:

Options Hash (options):

Returns:

  • (Boolean)

Raises:



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'vendor/bundler/ruby/2.5.0/bundler/gems/rdf-reasoner-0705d0a3eca4/lib/rdf/reasoner/rdfs.rb', line 221

def range_compatible_rdfs?(resource, queryable, options = {})
  raise RDF::Reasoner::Error, "#{self} can't get ranges" unless property?
  if !(ranges = Array(self.range).reject(&:node?) - [RDF::OWL.Thing, RDF::RDFS.Resource]).empty?
    if resource.literal?
      ranges.all? do |range|
        if [RDF::RDFS.Literal, RDF.XMLLiteral, RDF.HTML].include?(range)
          true  # Don't bother checking for validity
        elsif range == RDF.langString
          # Value must have a language
          resource.has_language?
        elsif range.start_with?(RDF::XSD)
          # XSD types are valid if the datatype matches, or they are plain and valid according to the grammar of the range
            resource.datatype == range ||
            resource.plain? && RDF::Literal.new(resource.value, datatype: range).valid?
        elsif range.start_with?(RDF::Vocab::OGC)
          case range
          when RDF::Vocab::OGC.boolean_str
            [RDF::Vocab::OGC.boolean_str, RDF::XSD.boolean].include?(resource.datatype) ||
            resource.plain? && RDF::Literal::Boolean.new(resource.value).valid?
          when RDF::Vocab::OGC.date_time_str
            # Schema.org date based on ISO 8601, mapped to appropriate XSD types for validation
            case resource
            when RDF::Literal::Date, RDF::Literal::Time, RDF::Literal::DateTime, RDF::Literal::Duration
              resource.valid?
            else
              ISO_8601.match(resource.value)
            end
          when RDF::Vocab::OGC.determiner_str
            # The lexical space: "", "the", "a", "an", and "auto".
            resource.plain? && (%w(the a an auto) + [""]).include?(resource.value)
          when RDF::Vocab::OGC.float_str
            # A string representation of a 64-bit signed floating point number.  Example lexical values include "1.234", "-1.234", "1.2e3", "-1.2e3", and "7E-10".
            [RDF::Vocab::OGC.float_str, RDF::Literal::Double, RDF::Literal::Float].include?(resource.datatype) ||
            resource.plain? && RDF::Literal::Double.new(resource.value).valid?
          when RDF::Vocab::OGC.integer_str
            resource.is_a?(RDF::Literal::Integer) ||
            [RDF::Vocab::OGC.integer_str].include?(resource.datatype) ||
            resource.plain? && RDF::Literal::Integer.new(resource.value).valid?
          when RDF::Vocab::OGC.mime_type_str
            # Valid mime type strings \(e.g., "application/mp3"\).
            [RDF::Vocab::OGC.mime_type_str].include?(resource.datatype) ||
            resource.plain? && resource.value =~ %r(^[\w\-\+]+/[\w\-\+]+$)
          when RDF::Vocab::OGC.string
            resource.plain?
          when RDF::Vocab::OGC.url
            # A string of Unicode characters forming a valid URL having the http or https scheme.
            u = RDF::URI(resource.value)
            resource.datatype == RDF::Vocab::OGC.url ||
            resource.datatype == RDF::XSD.anyURI ||
            resource.simple? && u.valid? && u.scheme.to_s =~ /^https?$/
          else
            # Unknown datatype
            false
          end
        else
          false
        end
      end
    else
      # Fully entailed types of the resource
      types = options.fetch(:types) do
        queryable.query(subject: resource, predicate: RDF.type).
          map {|s| (t = (RDF::Vocabulary.find_term(s.object) rescue nil)) && t.entail(:subClassOf)}.
          flatten.
          uniq.
          compact
      end

      # If any type is a class, add rdfs:Class
      if types.any? {|t| t.is_a?(RDF::Vocabulary::Term) && t.class?} && !types.include?(RDF::RDFS.Class)
        types << RDF::RDFS.Class
      end

      # Every range must match some entailed type
      Array(types).empty? || ranges.all? {|d| types.include?(d)}
    end
  else
    true
  end
end

#subClassArray<RDF::Vocabulary::Term>

Get the immediate subclasses of this class.

This iterates over terms defined in the vocabulary of this term, as well as the vocabularies imported by this vocabulary.



102
103
104
105
106
107
# File 'vendor/bundler/ruby/2.5.0/bundler/gems/rdf-reasoner-0705d0a3eca4/lib/rdf/reasoner/rdfs.rb', line 102

def subClass
  raise RDF::Reasoner::Error, "#{self} Can't entail subClass" unless class?
  subClass_cache[self] ||= ([self.vocab] + self.vocab.imported_from).map do |v|
    Array(v.properties).select {|p| p.class? && Array(p.subClassOf).include?(self)}
  end.flatten.compact
end