-
Notifications
You must be signed in to change notification settings - Fork 14
/
evaluatable.rb
82 lines (78 loc) · 2.48 KB
/
evaluatable.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
module SPARQL; module Algebra
##
# Mixin for Algebra::Operator sub-classes that evaluate bindings to return a result
#
# @abstract
module Evaluatable
##
# Evaluates this operator using the given variable `bindings`.
#
# @param [RDF::Query::Solution] bindings
# a query solution containing zero or more variable bindings
# @param [Hash{Symbol => Object}] options ({})
# options passed from query
# @return [RDF::Term]
# @abstract
def evaluate(bindings, **options)
args = operands.map { |operand| operand.evaluate(bindings, **options.merge(depth: options[:depth].to_i + 1)) }
options[:memoize] ? memoize(*args, **options) : apply(*args, **options)
end
##
# @param [Array<RDF::Term>] operands
# evaluated operands
# @return [RDF::Term] the memoized result
def memoize(*operands, **options)
@cache ||= RDF::Util::Cache.new(options[:memoize].is_a?(Integer) ? options[:memoize] : -1)
@cache[operands] ||= apply(*operands, **options)
end
##
# @param [Array<RDF::Term>] operands
# evaluated operands
# @return [RDF::Term]
# @abstract
def apply(*operands, **options)
raise NotImplementedError, "#{self.class}#apply(#{operands.map(&:class).join(', ')})"
end
##
# Replace operators which are variables with the result of the block
# descending into operators which are also evaluatable
#
# @yield var
# @yieldparam [RDF::Query::Variable] var
# @yieldreturn [RDF::Query::Variable, SPARQL::Algebra::Evaluatable]
# @return [SPARQL::Algebra::Evaluatable] self
def replace_vars!(&block)
@operands.map! do |op|
case
when op.is_a?(RDF::Query::Variable)
yield op
when op.respond_to?(:replace_vars!)
op.replace_vars!(&block)
else
op
end
end
self
end
##
# Recursively re-map operators to replace aggregates with temporary variables returned from the block
#
# @yield agg
# @yieldparam [SPARQL::Algebra::Aggregate] agg
# @yieldreturn [RDF::Query::Variable]
# @return [SPARQL::Algebra::Evaluatable, RDF::Query::Variable] self
def replace_aggregate!(&block)
@operands.map! do |op|
case
when op.aggregate?
yield op
when op.respond_to?(:replace_aggregate!)
op.replace_aggregate!(&block)
else
op
end
end
self
end
end # Evaluatable
end; end # SPARQL::Algebra