Skip to content

Commit 1174a16

Browse files
committed
Have solution iterators also return enumerators.
1 parent aadee9e commit 1174a16

4 files changed

Lines changed: 276 additions & 82 deletions

File tree

lib/rdf/query/solution.rb

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ class RDF::Query
2222
#
2323
class Solution
2424
# Undefine all superfluous instance methods:
25+
alias_method :__send, :send
2526
undef_method(*instance_methods.
2627
map(&:to_s).
2728
select {|m| m.match?(/^\w+$/)}.
@@ -57,29 +58,59 @@ def initialize(bindings = {}, &block)
5758
# @yieldparam [RDF::Term] value
5859
# @return [Enumerator]
5960
def each_binding(&block)
60-
@bindings.each(&block)
61+
@bindings.each(&block) if block_given?
62+
enum_binding
6163
end
6264
alias_method :each, :each_binding
6365

66+
##
67+
# Returns an enumerator for {#each_binding}.
68+
#
69+
# @return [Enumerator<RDF::Resource>]
70+
# @see #each_subject
71+
def enum_binding
72+
enum_for(:each_binding)
73+
end
74+
6475
##
6576
# Enumerates over every variable name in this solution.
6677
#
6778
# @yield [name]
6879
# @yieldparam [Symbol] name
6980
# @return [Enumerator]
7081
def each_name(&block)
71-
@bindings.each_key(&block)
82+
@bindings.each_key(&block) if block_given?
83+
enum_name
7284
end
7385
alias_method :each_key, :each_name
7486

87+
##
88+
# Returns an enumerator for {#each_name}.
89+
#
90+
# @return [Enumerator<RDF::Resource>]
91+
# @see #each_subject
92+
def enum_name
93+
enum_for(:each_name)
94+
end
95+
7596
##
7697
# Enumerates over every variable value in this solution.
7798
#
7899
# @yield [value]
79100
# @yieldparam [RDF::Term] value
80101
# @return [Enumerator]
81102
def each_value(&block)
82-
@bindings.each_value(&block)
103+
@bindings.each_value(&block) if block_given?
104+
enum_value
105+
end
106+
107+
##
108+
# Returns an enumerator for {#each_value}.
109+
#
110+
# @return [Enumerator<RDF::Resource>]
111+
# @see #each_subject
112+
def enum_value
113+
enum_for(:each_value)
83114
end
84115

85116
##
@@ -101,9 +132,21 @@ def has_variables?(variables)
101132
# @yieldparam [Variable]
102133
# @return [Enumerator]
103134
def each_variable
104-
@bindings.each do |name, value|
105-
yield Variable.new(name, value)
135+
if block_given?
136+
@bindings.each do |name, value|
137+
yield Variable.new(name, value)
138+
end
106139
end
140+
enum_variable
141+
end
142+
143+
##
144+
# Returns an enumerator for {#each_variable}.
145+
#
146+
# @return [Enumerator<RDF::Resource>]
147+
# @see #each_subject
148+
def enum_variable
149+
enum_for(:each_variable)
107150
end
108151

109152
##
@@ -282,5 +325,19 @@ def method_missing(name, *args, &block)
282325
def respond_to_missing?(name, include_private = false)
283326
@bindings.has_key?(name.to_sym) || super
284327
end
328+
329+
##
330+
# @private
331+
# @param [Symbol, #to_sym] method
332+
# @return [Enumerator]
333+
# @see Object#enum_for
334+
def enum_for(method = :each)
335+
# Ensure that enumerators are, themselves, queryable
336+
this = self
337+
Enumerator.new do |yielder|
338+
this.__send(method) {|*y| yielder << (y.length > 1 ? y : y.first)}
339+
end
340+
end
341+
alias_method :to_enum, :enum_for
285342
end # Solution
286343
end # RDF::Query

lib/rdf/query/variable.rb

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,25 @@ class Variable
6565
# the variable name
6666
# @param [RDF::Term] value
6767
# an optional variable value
68-
# @param [Boolean] distinguished (true)
69-
# defaults to false, unless name looks like a bnode
70-
def initialize(name = nil, value = nil, distinguished: true, existential: false)
71-
@name = (name || "g#{__id__.to_i.abs}").to_sym
68+
# @param [Boolean] distinguished (true) Also interpreted by leading '??' or '$$' in name.
69+
# @param [Boolean] existential (true) Also interpreted by leading '$' in name
70+
def initialize(name = nil, value = nil, distinguished: nil, existential: nil)
71+
name = (name || "g#{__id__.to_i.abs}").to_s
72+
if name.start_with?('??')
73+
name, dis, ex = name[2..-1], false, false
74+
elsif name.start_with?('?')
75+
name, dis, ex = name[1..-1], true, false
76+
elsif name.start_with?('$$')
77+
name, dis, ex = name[2..-1], false, true
78+
elsif name.start_with?('$')
79+
name, dis, ex = name[1..-1], true, true
80+
else
81+
dis, ex = true, false
82+
end
83+
@name = name.to_sym
7284
@value = value
73-
@distinguished = distinguished
74-
@existential = existential
85+
@distinguished = distinguished.nil? ? dis : distinguished
86+
@existential = existential.nil? ? ex : existential
7587
end
7688

7789
##

0 commit comments

Comments
 (0)