module RDF::Enumerable

An RDF statement enumeration mixin.

Classes that include this module must implement an `#each` method that yields {RDF::Statement RDF statements}.

@example Checking whether any statements exist

enumerable.empty?

@example Checking how many statements exist

enumerable.count

@example Checking whether a specific statement exists

enumerable.has_statement?(RDF::Statement(subject, predicate, object))
enumerable.has_triple?([subject, predicate, object])
enumerable.has_quad?([subject, predicate, object, graph_name])

@example Checking whether a specific value exists

enumerable.has_subject?(RDF::URI("http://rubygems.org/gems/rdf"))
enumerable.has_predicate?(RDF::RDFS.label)
enumerable.has_object?(RDF::Literal("A Ruby library for working with Resource Description Framework (RDF) data.", language: :en))
enumerable.has_graph?(RDF::URI("http://ar.to/#self"))

@example Enumerating all statements

enumerable.each_statement do |statement|
  puts statement.inspect
end

@example Enumerating all statements in the form of triples

enumerable.each_triple do |subject, predicate, object|
  puts [subject, predicate, object].inspect
end

@example Enumerating all statements in the form of quads

enumerable.each_quad do |subject, predicate, object, graph_name|
  puts [subject, predicate, object, graph_name].inspect
end

@example Enumerating all terms

enumerable.each_subject   { |term| puts term.inspect }
enumerable.each_predicate { |term| puts term.inspect }
enumerable.each_object    { |term| puts term.inspect }
enumerable.each_term      { |term| puts term.inspect }

@example Obtaining all statements

enumerable.statements  #=> [RDF::Statement(subject1, predicate1, object1), ...]
enumerable.triples     #=> [[subject1, predicate1, object1], ...]
enumerable.quads       #=> [[subject1, predicate1, object1, graph_name1], ...]

@example Obtaining all unique values

enumerable.subjects(unique: true)    #=> [subject1, subject2, subject3, ...]
enumerable.predicates(unique: true)  #=> [predicate1, predicate2, predicate3, ...]
enumerable.objects(unique: true)     #=> [object1, object2, object3, ...]
enumerable.graph_names(unique: true) #=> [graph_name1, graph_name2, graph_name3, ...]

@see RDF::Graph @see RDF::Repository

Enumerators for different mixins. These are defined in a separate module, so that they are bound when used, allowing other mixins inheriting behavior to be included.

Public Instance Methods

dump(*args) click to toggle source

Returns a serialized string representation of `self`.

Before calling this method you may need to explicitly require a serialization extension for the specified format.

@example Serializing into N-Triples format

require 'rdf/ntriples'
ntriples = enumerable.dump(:ntriples)

@param [Array<Object>] args

if the last argument is a hash, it is passed as options to
{RDF::Writer.dump}.

@return [String] @see RDF::Writer.dump @raise [RDF::WriterError] if no writer found @since 0.2.0

# File lib/rdf/mixin/enumerable.rb, line 741
def dump(*args)
  options = args.last.is_a?(Hash) ? args.pop : {}
  writer = RDF::Writer.for(*args)
  raise RDF::WriterError, "No writer found using #{args.inspect}" unless writer
  writer.dump(self, nil, options)
end
each_graph() { |graph(graph_name: nil, data: self)| ... } click to toggle source

Iterates the given block for each RDF graph in `self`.

If no block was given, returns an enumerator.

The order in which graphs are yielded is undefined.

@overload #each_graph

@yield  [graph]
  each graph
@yieldparam  [RDF::Graph] graph
@yieldreturn [void] ignored
@return [void]

@overload #each_graph

@return [Enumerator<RDF::Graph>]

@see enum_graph @since 0.1.9

# File lib/rdf/mixin/enumerable.rb, line 659
def each_graph
  if block_given?
    yield RDF::Graph.new(graph_name: nil, data: self)
    # FIXME: brute force, repositories should override behavior
    if supports?(:graph_name)
      enum_statement.map(&:graph_name).uniq.compact.each do |graph_name|
        yield RDF::Graph.new(graph_name: graph_name, data: self)
      end
    end
  end
  enum_graph
end
each_object() { |value| ... } click to toggle source

Iterates the given block for each unique RDF object term.

If no block was given, returns an enumerator.

The order in which values are yielded is undefined.

@overload #each_object

@yield  [object]
  each object term
@yieldparam  [RDF::Term] object
@yieldreturn [void] ignored
@return [void]

@overload #each_object

@return [Enumerator<RDF::Term>]

@see enum_object

# File lib/rdf/mixin/enumerable.rb, line 475
def each_object # FIXME: deduplication
  if block_given?
    values = {}
    each_statement do |statement|
      value = statement.object
      unless value.nil? || values.include?(value)
        values[value] = true
        yield value
      end
    end
  end
  enum_object
end
each_predicate() { |value| ... } click to toggle source

Iterates the given block for each unique RDF predicate term.

If no block was given, returns an enumerator.

The order in which values are yielded is undefined.

@overload #each_predicate

@yield  [predicate]
  each predicate term
@yieldparam  [RDF::URI] predicate
@yieldreturn [void] ignored
@return [void]

@overload #each_predicate

@return [Enumerator<RDF::URI>]

@see enum_predicate

# File lib/rdf/mixin/enumerable.rb, line 409
def each_predicate
  if block_given?
    values = {}
    each_statement do |statement|
      value = statement.predicate
      unless value.nil? || values.include?(value.to_s)
        values[value.to_s] = true
        yield value
      end
    end
  end
  enum_predicate
end
each_quad() { |*to_quad| ... } click to toggle source

Iterates the given block for each RDF quad.

If no block was given, returns an enumerator.

The order in which quads are yielded is undefined.

@overload #each_quad

@yield  [subject, predicate, object, graph_name]
  each quad
@yieldparam [RDF::Resource] subject
@yieldparam [RDF::URI]      predicate
@yieldparam [RDF::Term]     object
@yieldparam [RDF::Resource] graph_name
@yieldreturn [void] ignored
@return [void]

@overload #each_quad

@return [Enumerator<Array(RDF::Resource, RDF::URI, RDF::Term, RDF::Resource)>]

@see enum_quad

# File lib/rdf/mixin/enumerable.rb, line 282
def each_quad
  if block_given?
    each_statement do |statement|
      yield *statement.to_quad
    end
  end
  enum_quad
end
each_statement(&block) click to toggle source

Iterates the given block for each RDF statement.

If no block was given, returns an enumerator.

The order in which statements are yielded is undefined.

@overload #each_statement

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

@overload #each_statement

@return [Enumerator<RDF::Statement>]

@see enum_statement

# File lib/rdf/mixin/enumerable.rb, line 156
def each_statement(&block)
  if block_given?
    # Invoke {#each} in the containing class:
    each(&block)
  end
  enum_statement
end
each_subject() { |value| ... } click to toggle source

Iterates the given block for each unique RDF subject term.

If no block was given, returns an enumerator.

The order in which values are yielded is undefined.

@overload #each_subject

@yield  [subject]
  each subject term
@yieldparam  [RDF::Resource] subject
@yieldreturn [void] ignored
@return [void]

@overload #each_subject

@return [Enumerator<RDF::Resource>]

@see enum_subject

# File lib/rdf/mixin/enumerable.rb, line 344
def each_subject
  if block_given?
    values = {}
    each_statement do |statement|
      value = statement.subject
      unless value.nil? || values.include?(value.to_s)
        values[value.to_s] = true
        yield value
      end
    end
  end
  enum_subject
end
each_term() { |value| ... } click to toggle source

Iterates the given block for each unique RDF term (subject, predicate, object, or graph_name).

If no block was given, returns an enumerator.

The order in which values are yielded is undefined.

@overload #each_term

@yield  [term]
  each term
@yieldparam  [RDF::Term] term
@yieldreturn [void] ignored
@return [void]

@overload #each_term

@return [Enumerator<RDF::Term>]

@since 2.0 @see enum_term

# File lib/rdf/mixin/enumerable.rb, line 549
def each_term
  if block_given?
    values = {}
    each_statement do |statement|
      statement.to_quad.each do |value|
        unless value.nil? || values.include?(value.hash)
          values[value.hash] = true
          yield value
        end
      end
    end
  end
  enum_term
end
each_triple() { |*to_triple| ... } click to toggle source

Iterates the given block for each RDF triple.

If no block was given, returns an enumerator.

The order in which triples are yielded is undefined.

@overload #each_triple

@yield  [subject, predicate, object]
  each triple
@yieldparam  [RDF::Resource] subject
@yieldparam  [RDF::URI]      predicate
@yieldparam  [RDF::Term]     object
@yieldreturn [void] ignored
@return [void]

@overload #each_triple

@return [Enumerator<Array(RDF::Resource, RDF::URI, RDF::Term)>]

@see enum_triple

# File lib/rdf/mixin/enumerable.rb, line 220
def each_triple
  if block_given?
    each_statement do |statement|
      yield *statement.to_triple
    end
  end
  enum_triple
end
enum_for(method = :each, *args) click to toggle source

@private @param [Symbol, to_sym] method @return [Enumerator] @see Object#enum_for

# File lib/rdf/mixin/enumerable.rb, line 778
def enum_for(method = :each, *args)
  # Ensure that enumerators are, themselves, queryable
  this = self
  Enumerable::Enumerator.new do |yielder|
    this.send(method, *args) {|*y| yielder << (y.length > 1 ? y : y.first)}
  end
end
Also aliased as: to_enum
enum_graph() click to toggle source

Returns an enumerator for {RDF::Enumerable#each_graph}.

@return [Enumerator<RDF::Graph>] @see each_graph @since 0.1.9

# File lib/rdf/mixin/enumerable.rb, line 678
def enum_graph
  enum_for(:each_graph)
end
Also aliased as: enum_graphs
enum_graphs()
Alias for: enum_graph
enum_object() click to toggle source

Returns an enumerator for {RDF::Enumerable#each_object}.

@return [Enumerator<RDF::Term>] @see each_object

# File lib/rdf/mixin/enumerable.rb, line 494
def enum_object
  enum_for(:each_object)
end
Also aliased as: enum_objects
enum_objects()
Alias for: enum_object
enum_predicate() click to toggle source

Returns an enumerator for {RDF::Enumerable#each_predicate}.

@return [Enumerator<RDF::URI>] @see each_predicate

# File lib/rdf/mixin/enumerable.rb, line 428
def enum_predicate
  enum_for(:each_predicate)
end
Also aliased as: enum_predicates
enum_predicates()
Alias for: enum_predicate
enum_quad() click to toggle source

Returns an enumerator for {RDF::Enumerable#each_quad}.

@return [Enumerator<Array(RDF::Resource, RDF::URI, RDF::Term, RDF::Resource)>] @see each_quad

# File lib/rdf/mixin/enumerable.rb, line 296
def enum_quad
  Countable::Enumerator.new do |yielder|
    each_quad {|s, p, o, c| yielder << [s, p, o, c]}
  end
end
Also aliased as: enum_quads
enum_quads()
Alias for: enum_quad
enum_statement() click to toggle source

Returns an enumerator for {RDF::Enumerable#each_statement}. FIXME: #enum_for doesn't seem to be working properly in JRuby 1.7, so specs are marked pending

@return [Enumerator<RDF::Statement>] @see each_statement

# File lib/rdf/mixin/enumerable.rb, line 171
def enum_statement
  # Ensure that statements are queryable, countable and enumerable
  this = self
  Queryable::Enumerator.new do |yielder|
    this.send(:each_statement) {|y| yielder << y}
  end
end
Also aliased as: enum_statements
enum_statements()
Alias for: enum_statement
enum_subject() click to toggle source

Returns an enumerator for {RDF::Enumerable#each_subject}.

@return [Enumerator<RDF::Resource>] @see each_subject

# File lib/rdf/mixin/enumerable.rb, line 363
def enum_subject
  enum_for(:each_subject)
end
Also aliased as: enum_subjects
enum_subjects()
Alias for: enum_subject
enum_term() click to toggle source

Returns an enumerator for {RDF::Enumerable#each_term}.

@return [Enumerator<RDF::Term>] @see each_term @since 2.0

# File lib/rdf/mixin/enumerable.rb, line 570
def enum_term
  enum_for(:each_term)
end
Also aliased as: enum_terms
enum_terms()
Alias for: enum_term
enum_triple() click to toggle source

Returns an enumerator for {RDF::Enumerable#each_triple}.

@return [Enumerator<Array(RDF::Resource, RDF::URI, RDF::Term)>] @see each_triple

# File lib/rdf/mixin/enumerable.rb, line 234
def enum_triple
  Countable::Enumerator.new do |yielder|
    each_triple {|s, p, o| yielder << [s, p, o]}
  end
end
Also aliased as: enum_triples
enum_triples()
Alias for: enum_triple
graph_names(unique: true) click to toggle source

Returns all unique RDF graph names, other than the default graph.

@param unique (true) @return [Array<RDF::Resource>] @see each_graph @see enum_graph @since 2.0

# File lib/rdf/mixin/enumerable.rb, line 583
def graph_names(unique: true)
  unless unique
    enum_statement.map(&:graph_name).compact # TODO: optimize
  else
    enum_graph.map(&:graph_name).compact
  end
end
has_graph?(graph_name) click to toggle source

Returns `true` if `self` contains the given RDF graph_name.

@param [RDF::Resource, false] graph_name

Use value `false` to query for the default graph_name

@return [Boolean]

# File lib/rdf/mixin/enumerable.rb, line 597
def has_graph?(graph_name)
  enum_statement.any? {|s| s.graph_name == graph_name}
end
has_object?(value) click to toggle source

Returns `true` if `self` contains the given RDF object term.

@param [RDF::Term] value @return [Boolean]

# File lib/rdf/mixin/enumerable.rb, line 453
def has_object?(value)
  enum_object.include?(value)
end
has_predicate?(value) click to toggle source

Returns `true` if `self` contains the given RDF predicate term.

@param [RDF::URI] value @return [Boolean]

# File lib/rdf/mixin/enumerable.rb, line 388
def has_predicate?(value)
  enum_predicate.include?(value)
end
has_quad?(quad) click to toggle source

Returns `true` if `self` contains the given RDF quad.

@param [Array(RDF::Resource, RDF::URI, RDF::Term, RDF::Resource)] quad @return [Boolean]

# File lib/rdf/mixin/enumerable.rb, line 257
def has_quad?(quad)
  quads.include?(quad)
end
has_statement?(statement) click to toggle source

Returns `true` if `self` contains the given RDF statement.

@param [RDF::Statement] statement @return [Boolean]

# File lib/rdf/mixin/enumerable.rb, line 133
def has_statement?(statement)
  !enum_statement.find { |s| s.eql?(statement) }.nil?
end
Also aliased as: include?
has_subject?(value) click to toggle source

Returns `true` if `self` contains the given RDF subject term.

@param [RDF::Resource] value @return [Boolean]

# File lib/rdf/mixin/enumerable.rb, line 323
def has_subject?(value)
  enum_subject.include?(value)
end
has_term?(value) click to toggle source

Returns `true` if `self` contains the given RDF subject term.

@param [RDF::Resource] value @return [Boolean] @since 2.0

# File lib/rdf/mixin/enumerable.rb, line 527
def has_term?(value)
  enum_term.include?(value)
end
has_triple?(triple) click to toggle source

Returns `true` if `self` contains the given RDF triple.

@param [Array(RDF::Resource, RDF::URI, RDF::Term)] triple @return [Boolean]

# File lib/rdf/mixin/enumerable.rb, line 196
def has_triple?(triple)
  triples.include?(triple)
end
include?(statement)
Alias for: has_statement?
invalid?() click to toggle source

Returns `true` if value is not valid

@return [Boolean] `true` or `false` @raise [NotImplementedError] unless enumerable supports validation @since 0.2.1

# File lib/rdf/mixin/enumerable.rb, line 102
def invalid?
  !valid?
end
method_missing(meth, *args) click to toggle source

@overload to_writer

Implements #to_writer for each available instance of {RDF::Writer},
based on the writer symbol.

@return [String]
@see {RDF::Writer.sym}
Calls superclass method
# File lib/rdf/mixin/enumerable.rb, line 755
def method_missing(meth, *args)
  writer = RDF::Writer.for(meth.to_s[3..-1].to_sym) if meth.to_s[0,3] == "to_"
  if writer
    writer.buffer(standard_prefixes: true) {|w| w << self}
  else
    super
  end
end
objects(unique: true) click to toggle source

Returns all unique RDF object terms.

@param unique (true) @return [Array<RDF::Term>] @see each_object @see enum_object

# File lib/rdf/mixin/enumerable.rb, line 440
def objects(unique: true)
  unless unique
    enum_statement.map(&:object) # TODO: optimize
  else
    Array(enum_object)
  end
end
predicates(unique: true) click to toggle source

Returns all unique RDF predicate terms.

@param unique (true) @return [Array<RDF::URI>] @see each_predicate @see enum_predicate

# File lib/rdf/mixin/enumerable.rb, line 375
def predicates(unique: true)
  unless unique
    enum_statement.map(&:predicate) # TODO: optimize
  else
    Array(enum_predicate)
  end
end
project_graph(graph_name) { |statement| ... } click to toggle source

Limits statements to be from a specific graph.

If no block was given, returns an enumerator.

The order in which statements are yielded is undefined.

@overload #project_graph(graph_name)

@param [RDF::Resource, nil] graph_name
  The name of the graph from which statements are taken.
  Use `nil` for the default graph.
@yield  [statement]
  each statement
@yieldparam  [RDF::Statement] statement
@yieldreturn [void] ignored
@return [void]

@overload #project_graph(graph_name)

@param [RDF::Resource, false] graph_name
  The name of the graph from which statements are taken.
  Use `false` for the default graph.
@return [Enumerable]

@see each_statement @since 3.0

# File lib/rdf/mixin/enumerable.rb, line 626
def project_graph(graph_name)
  if block_given?
    self.each do |statement|
      yield statement if statement.graph_name == graph_name
    end
  else
    # Ensure that statements are queryable, countable and enumerable
    this = self
    Queryable::Enumerator.new do |yielder|
      this.send(:project_graph, graph_name) {|y| yielder << y}
    end
  end
end
quads(options = {}) click to toggle source

Returns all RDF quads.

@param [Hash{Symbol => Boolean}] options @return [Array<Array(RDF::Resource, RDF::URI, RDF::Term, RDF::Resource)>] @see each_quad @see enum_quad

# File lib/rdf/mixin/enumerable.rb, line 248
def quads(options = {})
  enum_statement.map(&:to_quad) # TODO: optimize
end
respond_to_missing?(name, include_private = false) click to toggle source

@note this instantiates an writer; it could probably be done more

efficiently by refactoring `RDF::Reader` and/or `RDF::Format` to expose
a list of valid format symbols.
Calls superclass method
# File lib/rdf/mixin/enumerable.rb, line 768
def respond_to_missing?(name, include_private = false)
  return RDF::Writer.for(name.to_s[3..-1].to_sym) if name.to_s[0,3] == 'to_'
  super
end
statements(options = {}) click to toggle source

Returns all RDF statements.

@param [Hash{Symbol => Boolean}] options @return [Array<RDF::Statement>] @see each_statement @see enum_statement

# File lib/rdf/mixin/enumerable.rb, line 124
def statements(options = {})
  Array(enum_statement)
end
subjects(unique: true) click to toggle source

Returns all unique RDF subject terms.

@param unique (true) @return [Array<RDF::Resource>] @see each_subject @see enum_subject

# File lib/rdf/mixin/enumerable.rb, line 310
def subjects(unique: true)
  unless unique
    enum_statement.map(&:subject) # TODO: optimize
  else
    Array(enum_subject)
  end
end
supports?(feature) click to toggle source

Returns `true` if this enumerable supports the given `feature`.

Supported features include:

* `:graph_name` supports statements with a graph_name, allowing multiple named graphs
* `:inference` supports RDFS inferrence of queryable contents.
* `:literal_equality' preserves [term-equality](https://www.w3.org/TR/rdf11-concepts/#dfn-literal-term-equality) for literals. Literals are equal only if their lexical values and datatypes are equal, character by character. Literals may be "inlined" to value-space for efficiency only if `:literal_equality` is `false`.
* `:validity` allows a concrete Enumerable implementation to indicate that it does or does not support valididty checking. By default implementations are assumed to support validity checking.
* `:skolemize` supports [Skolemization](https://www.w3.org/wiki/BnodeSkolemization) of an `Enumerable`. Implementations supporting this feature must implement a `#skolemize` method, taking a base URI used for minting URIs for BNodes as stable identifiers and a `#deskolemize` method, also taking a base URI used for turning URIs having that prefix back into the same BNodes which were originally skolemized.

@param [Symbol, to_sym] feature @return [Boolean] @since 0.3.5

# File lib/rdf/mixin/enumerable.rb, line 78
def supports?(feature)
  feature == :validity || feature == :literal_equality
end
terms(unique: true) click to toggle source

Returns all unique RDF terms (subjects, predicates, objects, and #graph_names).

@example finding all Blank Nodes used within an enumerable

enumberable.terms.select(&:node?)

@param unique (true) @return [Array<RDF::Resource>] @since 2.0 @see each_resource @see enum_resource

# File lib/rdf/mixin/enumerable.rb, line 510
def terms(unique: true)
  unless unique
    enum_statement.
      map(&:to_quad).
      flatten.
      compact
  else
    Array(enum_term)
  end
end
to_a() click to toggle source

Returns all RDF statements in `self` as an array.

Mixes in `RDF::Enumerable` into the returned object.

@return [Array] @since 0.2.0

Calls superclass method
# File lib/rdf/mixin/enumerable.rb, line 690
def to_a
  super.extend(RDF::Enumerable)
end
to_enum(method = :each, *args)
Alias for: enum_for
to_hash() click to toggle source

Returns all RDF object terms indexed by their subject and predicate terms.

The return value is a `Hash` instance that has the structure: `{subject => {predicate => [*objects]}}`.

@return [Hash]

# File lib/rdf/mixin/enumerable.rb, line 714
def to_hash
  result = {}
  each_statement do |statement|
    result[statement.subject] ||= {}
    values = (result[statement.subject][statement.predicate] ||= [])
    values << statement.object unless values.include?(statement.object)
  end
  result
end
to_set() click to toggle source

Returns all RDF statements in `self` as a set.

Mixes in `RDF::Enumerable` into the returned object.

@return [Set] @since 0.2.0

Calls superclass method
# File lib/rdf/mixin/enumerable.rb, line 701
def to_set
  require 'set' unless defined?(::Set)
  super.extend(RDF::Enumerable)
end
triples(options = {}) click to toggle source

Returns all RDF triples.

@param [Hash{Symbol => Boolean}] options @return [Array<Array(RDF::Resource, RDF::URI, RDF::Term)>] @see each_triple @see enum_triple

# File lib/rdf/mixin/enumerable.rb, line 187
def triples(options = {})
  enum_statement.map(&:to_triple) # TODO: optimize
end
valid?() click to toggle source

Returns `true` if all statements are valid

@return [Boolean] `true` or `false` @raise [NotImplementedError] unless enumerable supports validation @since 0.3.11

# File lib/rdf/mixin/enumerable.rb, line 88
def valid?
  raise NotImplementedError, "#{self.class} does not support validation" unless supports?(:validity)
  each_statement do |s|
    return false if s.invalid?
  end
  true
end
validate()
Alias for: validate!
validate!() click to toggle source

Default validate! implementation, overridden in concrete classes @return [RDF::Enumerable] `self` @raise [ArgumentError] if the value is invalid @since 0.3.9

# File lib/rdf/mixin/enumerable.rb, line 111
def validate!
  raise ArgumentError if supports?(:validity) && invalid?
  self
end
Also aliased as: validate