Class: RDF::Query::Pattern

Inherits:
Statement show all
Defined in:
lib/rdf/query/pattern.rb

Overview

An RDF query pattern.

Since:

  • 0.3.0

Instance Attribute Summary collapse

Attributes inherited from Statement

#context, #id, #object, #predicate, #subject

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Statement

#==, #===, #[], #[]=, #asserted?, #eql?, #has_blank_nodes?, #has_context?, #has_graph?, #has_object?, #has_predicate?, #has_subject?, #inferred?, #invalid?, #quoted?, #reified, #statement?, #to_hash, #to_quad, #to_triple, #valid?

Methods included from Value

#graph?, #inspect, #inspect!, #iri?, #literal?, #node?, #resource?, #statement?, #to_ntriples, #to_quad, #to_rdf, #type_error, #uri?

Constructor Details

#initialize(options = {}) ⇒ Pattern #initialize(subject, predicate, object, options = {}) ⇒ Pattern

Returns a new instance of Pattern.

Overloads:

  • #initialize(options = {}) ⇒ Pattern

    Parameters:

    • options (Hash{Symbol => Object}) (defaults to: {})

    Options Hash (options):

    • :subject (Variable, Resource) — default: nil
    • :predicate (Variable, URI) — default: nil
    • :object (Variable, Term) — default: nil
    • :context (Variable, Resource) — default: nil

      A context of nil matches any context, a context of false, matches only the default context.

    • :optional (Boolean) — default: false
  • #initialize(subject, predicate, object, options = {}) ⇒ Pattern

    Parameters:

    Options Hash (options):

    • :context (Variable, Resource) — default: nil
    • :optional (Boolean) — default: false

Since:

  • 0.3.0



35
36
37
# File 'lib/rdf/query/pattern.rb', line 35

def initialize(subject = nil, predicate = nil, object = nil, options = {})
  super
end

Instance Attribute Details

#costNumeric

The estimated cost of this pattern (for query optimization).

Returns:

  • (Numeric)

Since:

  • 0.3.0



59
60
61
# File 'lib/rdf/query/pattern.rb', line 59

def cost
  @cost
end

#optionsHash (readonly)

Any additional options for this pattern.

Returns:

  • (Hash)

Since:

  • 0.3.0



53
54
55
# File 'lib/rdf/query/pattern.rb', line 53

def options
  @options
end

Class Method Details

.from(pattern, options = {}) ⇒ Object

Since:

  • 0.2.2



8
9
10
11
12
13
14
15
16
# File 'lib/rdf/query/pattern.rb', line 8

def self.from(pattern, options = {})
  case pattern
    when Pattern then pattern
    when Array, Statement
      self.new(pattern[0], pattern[1], pattern[2], options.merge(:context => pattern[3]))
    when Hash    then self.new(options.merge(pattern))
    else raise ArgumentError, "expected RDF::Query::Pattern, RDF::Statement, Hash, or Array, but got #{pattern.inspect}"
  end
end

Instance Method Details

#binding_countInteger

Returns the number of bindings in this pattern.

Returns:

  • (Integer)

    (0..3)

Since:

  • 0.3.0



261
262
263
# File 'lib/rdf/query/pattern.rb', line 261

def binding_count
  bindings.size
end

#bindingsHash{Symbol => RDF::Term}

Returns all bindings in this pattern.

Returns:

Since:

  • 0.3.0



269
270
271
272
273
274
275
276
# File 'lib/rdf/query/pattern.rb', line 269

def bindings
  bindings = {}
  bindings.merge!(subject.bindings)   if subject.is_a?(Variable)
  bindings.merge!(predicate.bindings) if predicate.is_a?(Variable)
  bindings.merge!(object.bindings)    if object.is_a?(Variable)
  bindings.merge!(context.bindings)   if context.is_a?(Variable)
  bindings
end

#bindings?Boolean

Returns ‘true` if this pattern contains bindings.

Returns:

  • (Boolean)

    ‘true` or `false`

Since:

  • 0.3.0



253
254
255
# File 'lib/rdf/query/pattern.rb', line 253

def bindings?
  !bindings.empty?
end

#blank?Boolean

Returns ‘true` if this is a blank pattern, with all terms being `nil`.

Returns:

  • (Boolean)

    ‘true` or `false`

Since:

  • 0.3.0



66
67
68
# File 'lib/rdf/query/pattern.rb', line 66

def blank?
  subject.nil? && predicate.nil? && object.nil? && context.nil?
end

#bound?Boolean

Returns ‘true` if all variables in this pattern are bound.

Returns:

  • (Boolean)

    ‘true` or `false`

Since:

  • 0.3.0



282
283
284
# File 'lib/rdf/query/pattern.rb', line 282

def bound?
  !variables.empty? && variables.values.all?(&:bound?)
end

#bound_variablesHash{Symbol => Variable}

Returns all bound variables in this pattern.

Returns:

Since:

  • 0.3.0



290
291
292
# File 'lib/rdf/query/pattern.rb', line 290

def bound_variables
  variables.reject { |name, variable| variable.unbound? }
end

#constant?Boolean

Returns ‘true` if this is a constant pattern, with all terms being either URIs, blank nodes, or literals.

A constant pattern is structurally and functionally equivalent to an RDF statement.

Returns:

  • (Boolean)

    ‘true` or `false`

Since:

  • 0.3.0



79
80
81
# File 'lib/rdf/query/pattern.rb', line 79

def constant?
  !(variable?)
end

#execute(queryable, bindings = {}) {|statement| ... } ⇒ Enumerator

Executes this query pattern on the given ‘queryable` object.

Values are matched using using Queryable#query_pattern.

If the optional ‘bindings` are given, variables will be substituted with their values when executing the query.

To match triples only in the default context, set context to ‘false’.

Examples:

Pattern.new(:s, :p, :o).execute(RDF::Repository.load('data.nt'))

Parameters:

  • queryable (RDF::Queryable)

    the graph or repository to query

  • bindings (Hash{Symbol => RDF::Term}) (defaults to: {})

    optional variable bindings to use

Yields:

  • (statement)

    each matching statement

Yield Parameters:

  • statement (RDF::Statement)

    an RDF statement matching this pattern

Returns:

  • (Enumerator)

    an enumerator yielding matching statements

See Also:

Since:

  • 0.3.0



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/rdf/query/pattern.rb', line 144

def execute(queryable, bindings = {}, &block)
  query = {
    :subject   => subject.is_a?(Variable)   && bindings[subject.to_sym]   ? bindings[subject.to_sym]   : subject,
    :predicate => predicate.is_a?(Variable) && bindings[predicate.to_sym] ? bindings[predicate.to_sym] : predicate,
    :object    => object.is_a?(Variable)    && bindings[object.to_sym]    ? bindings[object.to_sym]    : object,
    :context   => context.is_a?(Variable)   && bindings[context.to_sym]   ? bindings[context.to_sym]   : context,
  }.delete_if{|k,v| v.nil?}

  # Do all the variable terms refer to distinct variables?
  variables = self.variables
  if variable_count == variables.size
    # If so, we can just let the repository implementation handle
    # everything and yield matching statements directly:
    queryable.query(query, &block)

  # No, some terms actually refer to the same variable...
  else
    # Figure out which terms refer to the same variable:
    terms = variables.each_key.find do |name|
      terms = variable_terms(name)
      break terms if terms.size > 1
    end
    queryable.query(query) do |statement|
      # Only yield those matching statements where the variable
      # constraint is also satisfied:
      # FIXME: `Array#uniq` uses `#eql?` and `#hash`, not `#==`
      if matches = terms.map { |term| statement.send(term) }.uniq.size.equal?(1)
        block.call(statement)
      end
    end
  end
end

#has_variables?Boolean Also known as: variables?

Returns ‘true` if this pattern contains any variables.

Returns:

  • (Boolean)

    ‘true` or `false`

Since:

  • 0.3.0



98
99
100
101
102
103
# File 'lib/rdf/query/pattern.rb', line 98

def has_variables?
  subject.is_a?(Variable) ||
    predicate.is_a?(Variable) ||
    object.is_a?(Variable) ||
    context.is_a?(Variable)
end

#initialize!Object

Since:

  • 0.3.0



41
42
43
44
45
46
47
# File 'lib/rdf/query/pattern.rb', line 41

def initialize!
  @context   = Variable.new(@context)   if @context.is_a?(Symbol)
  @subject   = Variable.new(@subject)   if @subject.is_a?(Symbol)
  @predicate = Variable.new(@predicate) if @predicate.is_a?(Symbol)
  @object    = Variable.new(@object)    if @object.is_a?(Symbol)
  super
end

#optional?Boolean

Returns ‘true` if this is an optional pattern.

Examples:

Pattern.new(:s, :p, :o).optional?                     #=> false
Pattern.new(:s, :p, :o, :optional => true).optional?  #=> true

Returns:

  • (Boolean)

    ‘true` or `false`

Since:

  • 0.3.0



115
116
117
# File 'lib/rdf/query/pattern.rb', line 115

def optional?
  !!options[:optional]
end

#solution(statement) ⇒ RDF::Query::Solution

Returns a query solution constructed by binding any variables in this pattern with the corresponding terms in the given ‘statement`.

Examples:

pattern.solution(statement)

Parameters:

Returns:

Since:

  • 0.3.0



188
189
190
191
192
193
194
195
# File 'lib/rdf/query/pattern.rb', line 188

def solution(statement)
  RDF::Query::Solution.new do |solution|
    solution[subject.to_sym]   = statement.subject   if subject.is_a?(Variable)
    solution[predicate.to_sym] = statement.predicate if predicate.is_a?(Variable)
    solution[object.to_sym]    = statement.object    if object.is_a?(Variable)
    solution[context.to_sym]   = statement.context   if context.is_a?(Variable)
  end
end

#to_sString

Returns a string representation of this pattern.

Returns:

  • (String)

Since:

  • 0.3.0



314
315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/rdf/query/pattern.rb', line 314

def to_s
  StringIO.open do |buffer| # FIXME in RDF::Statement
    buffer << 'OPTIONAL ' if optional?
    buffer << [subject, predicate, object].map do |r|
      r.is_a?(RDF::Query::Variable) ? r.to_s : RDF::NTriples.serialize(r)
    end.join(" ")
    buffer << case context
      when nil, false then " ."
      when Variable then " #{context.to_s} ."
      else " #{RDF::NTriples.serialize(context)} ."
    end
    buffer.string
  end
end

#unbound?Boolean

Returns ‘true` if all variables in this pattern are unbound.

Returns:

  • (Boolean)

    ‘true` or `false`

Since:

  • 0.3.0



298
299
300
# File 'lib/rdf/query/pattern.rb', line 298

def unbound?
  !variables.empty? && variables.values.all?(&:unbound?)
end

#unbound_variablesHash{Symbol => Variable}

Returns all unbound variables in this pattern.

Returns:

Since:

  • 0.3.0



306
307
308
# File 'lib/rdf/query/pattern.rb', line 306

def unbound_variables
  variables.reject { |name, variable| variable.bound? }
end

#variable?Boolean

Returns ‘true` if this is a variable pattern, with any term being `nil` or a variable.

Returns:

  • (Boolean)

    ‘true` or `false`

Since:

  • 0.3.0



89
90
91
# File 'lib/rdf/query/pattern.rb', line 89

def variable?
  subject.nil? || predicate.nil? || object.nil? || context.nil? || has_variables?
end

#variable_countInteger Also known as: cardinality, arity

Returns the number of variables in this pattern.

Note: this does not count distinct variables, and will therefore e.g. return 3 even if two terms are actually the same variable.

Returns:

  • (Integer)

    (0..3)

Since:

  • 0.3.0



223
224
225
226
227
228
229
230
# File 'lib/rdf/query/pattern.rb', line 223

def variable_count
  count = 0
  count += 1 if subject.is_a?(Variable)
  count += 1 if predicate.is_a?(Variable)
  count += 1 if object.is_a?(Variable)
  count += 1 if context.is_a?(Variable)
  count
end

#variable_terms(name = nil) ⇒ Array<Symbol>

Returns the variable terms in this pattern.

Examples:

Pattern.new(RDF::Node.new, :p, 123).variable_terms    #=> [:predicate]

Parameters:

  • name (Symbol, #to_sym) (defaults to: nil)

    an optional variable name

Returns:

  • (Array<Symbol>)

Since:

  • 0.3.0



207
208
209
210
211
212
213
214
# File 'lib/rdf/query/pattern.rb', line 207

def variable_terms(name = nil)
  terms = []
  terms << :subject   if subject.is_a?(Variable)   && (!name || name.eql?(subject.name))
  terms << :predicate if predicate.is_a?(Variable) && (!name || name.eql?(predicate.name))
  terms << :object    if object.is_a?(Variable)    && (!name || name.eql?(object.name))
  terms << :context   if context.is_a?(Variable)   && (!name || name.eql?(context.name))
  terms
end

#variablesHash{Symbol => Variable}

Returns all variables in this pattern.

Note: this returns a hash containing distinct variables only.

Returns:

Since:

  • 0.3.0



240
241
242
243
244
245
246
247
# File 'lib/rdf/query/pattern.rb', line 240

def variables
  variables = {}
  variables.merge!(subject.variables)   if subject.is_a?(Variable)
  variables.merge!(predicate.variables) if predicate.is_a?(Variable)
  variables.merge!(object.variables)    if object.is_a?(Variable)
  variables.merge!(context.variables)   if context.is_a?(Variable)
  variables
end