module RDF::Queryable

Override RDF::Queryable to execute against SPARQL::Algebra::Query elements as well as RDF::Query and RDF::Pattern

Extensions for `RDF::Queryable`

Public Instance Methods

concise_bounded_description(*terms, **options) { |statement| ... } click to toggle source

Concise Bounded Description

Given a particular node (the starting node) in a particular RDF graph (the source graph), a subgraph of that particular graph, taken to comprise a concise bounded description of the resource denoted by the starting node, can be identified as follows:

1. Include in the subgraph all statements in the source graph where the subject of the statement is the
   starting node;
2. Recursively, for all statements identified in the subgraph thus far having a blank node object,
   include in the subgraph all statements in the source graph where the subject of the statement is the
   blank node in question and which are not already included in the subgraph.
3. Recursively, for all statements included in the subgraph thus far, for all reifications of each
   statement in the source graph, include the concise bounded description beginning from the
   rdf:Statement node of each reification. (we skip this step)

This results in a subgraph where the object nodes are either URI references, literals, or blank nodes not serving as the subject of any statement in the graph.

Used to implement the SPARQL `DESCRIBE` operator.

@overload concise_bounded_description(*terms, **options, &block)

@param [Array<RDF::Term>] terms
  List of terms to include in the results.
@param [Hash{Symbol => Object}] options
@option options [Boolean] :non_subjects (false)
  If `term` is not a `subject` within `self`
  then add all `subject`s referencing the term as a `predicate` or `object`.
@option options [RDF::Graph] graph
  Graph containing statements already considered.

@yield [statement] @yieldparam [RDF::Statement] statement @yieldreturn [void] ignored @return [RDF::Graph]

@see www.w3.org/Submission/CBD/

# File lib/sparql/extensions.rb, line 43
def concise_bounded_description(*terms, **options, &block)
  graph = options[:graph] || RDF::Graph.new

  if options[:non_subjects]
    query_terms = terms.dup

    # Find terms not in self as a subject and recurse with their subjects
    terms.reject {|term| self.first({subject: term})}.each do |term|
      self.query({predicate: term}) do |statement|
        query_terms << statement.subject
      end

      self.query({object: term}) do |statement|
        query_terms << statement.subject
      end
    end
    
    terms = query_terms.uniq
  end

  # Don't consider term if already in graph
  terms.reject {|term| graph.first({subject: term})}.each do |term|
    # Find statements from queryiable with term as a subject
    self.query({subject: term}) do |statement|
      yield(statement) if block_given?
      graph << statement
      
      # Include reifications of this statement
      RDF::Query.new({
        s: {
          RDF.type => RDF["Statement"],
          RDF.subject => statement.subject,
          RDF.predicate => statement.predicate,
          RDF.object => statement.object,
        }
      }, **{}).execute(self).each do |solution|
        # Recurse to include this subject
        recurse_opts = options.merge(non_subjects: false, graph: graph)
        self.concise_bounded_description(solution[:s], **recurse_opts, &block)
      end

      # Recurse if object is a BNode and it is not already in subjects
      if statement.object.node?
        recurse_opts = options.merge(non_subjects: false, graph: graph)
        self.concise_bounded_description(statement.object, **recurse_opts, &block)
      end
    end
  end
  
  graph
end
query(pattern, **options, &block) click to toggle source

Queries `self` for RDF statements matching the given `pattern`.

Monkey patch to RDF::Queryable#query to execute a {SPARQL::Algebra::Operator} in addition to an {RDF::Query} object.

@example

queryable.query([nil, RDF::DOAP.developer, nil])
queryable.query({predicate: RDF::DOAP.developer})

op = SPARQL::Algebra::Expression.parse(%q((bgp (triple ?a doap:developer ?b))))
queryable.query(op)

@param [RDF::Query, RDF::Statement, Array(RDF::Term), Hash, SPARQL::Operator] pattern @yield [statement]

each matching statement

@yieldparam [RDF::Statement] statement @yieldreturn [void] ignored @return [Enumerator] @see RDF::Queryable#query_pattern

# File lib/sparql/algebra/extensions.rb, line 323
def query(pattern, **options, &block)
  raise TypeError, "#{self} is not queryable" if respond_to?(:queryable?) && !queryable?

  if pattern.is_a?(SPARQL::Algebra::Operator) && pattern.respond_to?(:execute)
    before_query(pattern) if respond_to?(:before_query)
    solutions = if method(:query_execute).arity == 1
      query_execute(pattern, &block)
    else
      query_execute(pattern, **options, &block)
    end
    after_query(pattern) if respond_to?(:after_query)

    if !pattern.respond_to?(:query_yeilds_solutions?) || pattern.query_yields_solutions?
      # Just return solutions
      solutions
    else
      # Return an enumerator
      enum_for(:query, pattern, **options)
    end
  else
    query_without_sparql(pattern, **options, &block)
  end
end
Also aliased as: query_without_sparql
query_without_sparql(pattern, **options, &block)
Alias for: query