Skip to content

Commit 18c1c86

Browse files
committed
Better support for non-distinguished variables.
1 parent 3265a69 commit 18c1c86

4 files changed

Lines changed: 62 additions & 9 deletions

File tree

lib/rdf/query.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,9 @@ def execute(queryable, solutions: Solution.new, graph_name: nil, name: nil, **op
359359
return @solutions if @solutions.empty?
360360

361361
if !pattern.optional?
362-
# We have no solutions for variables we should have solutions for:
363-
need_vars = pattern.variables.keys
362+
# We have no solutions for variables we should have solutions for
363+
# (excludes non-distinguished variables):
364+
need_vars = pattern.variables.select {|k,v| v.distinguished?}.keys
364365
@solutions.each do |solution|
365366
break if need_vars.empty?
366367
need_vars -= solution.bindings.keys

lib/rdf/query/variable.rb

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,12 @@ class Variable
6565
# the variable name
6666
# @param [RDF::Term] value
6767
# an optional variable value
68-
def initialize(name = nil, value = nil)
68+
# @param [Boolean] distinguished (true)
69+
# defaults to false, unless name looks like a bnode
70+
def initialize(name = nil, value = nil, distinguished: true)
6971
@name = (name || "g#{__id__.to_i.abs}").to_sym
7072
@value = value
73+
@distinguished = distinguished
7174
end
7275

7376
##
@@ -109,7 +112,7 @@ def unbound?
109112
#
110113
# @return [Boolean]
111114
def distinguished?
112-
@distinguished.nil? || @distinguished
115+
@distinguished
113116
end
114117

115118
##

spec/query_spec.rb

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -602,7 +602,27 @@
602602
its(:variables) {is_expected.to include(:g)}
603603
end
604604
end
605-
605+
606+
context "with non-distinguished variables" do
607+
before :each do
608+
@graph = RDF::Graph.new do |graph|
609+
graph << [EX.s1, EX.p, EX.o]
610+
graph << [EX.s2, EX.p, EX.o]
611+
graph << [EX.s2, EX.p2, EX.o2]
612+
end
613+
end
614+
615+
it "matches graphs with a bound non-distinguished variable" do
616+
query = RDF::Query.new do |query|
617+
query.pattern [:s, EX.p, EX.o]
618+
query.pattern [RDF::Query::Variable.new(:s2, distinguished: false), EX.p2, EX.o2]
619+
end
620+
expect(query.execute(@graph)).to have_result_set([{ s: EX.s1, s2: EX.s2 }, { s: EX.s2, s2: EX.s2 }])
621+
end
622+
623+
it "matches graphs with a unbound non-distinguished variable"
624+
end
625+
606626
context "with an optional pattern" do
607627
before :each do
608628
@graph = RDF::Graph.new do |graph|

spec/query_variable_spec.rb

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
require File.join(File.dirname(__FILE__), 'spec_helper')
22

33
describe RDF::Query::Variable do
4-
context ".new(:x)" do
4+
context ".new unbound" do
55
let(:var) {RDF::Query::Variable.new(:x)}
66
subject {var}
77

88
it "is named" do
9-
expect(subject.named?).to be_truthy
9+
expect(subject).to be_named
1010
expect(subject.name).to eq :x
1111
end
1212

@@ -35,6 +35,10 @@
3535
expect(subject).to_not be_distinguished
3636
end
3737

38+
it "can be created as non-distinguished" do
39+
expect(described_class.new(:x, distinguished: false)).not_to be_distinguished
40+
end
41+
3842
it "can be made distinguished" do
3943
subject.distinguished = true
4044
expect(subject).to be_distinguished
@@ -49,7 +53,6 @@
4953
expect(subject.to_sym).to eq :x
5054
end
5155

52-
5356
it "has no value" do
5457
expect(subject.value).to be_nil
5558
end
@@ -104,7 +107,33 @@
104107
end
105108
end
106109

107-
context ".new(:x, 123)" do
110+
context ".new non-distinguished" do
111+
subject {RDF::Query::Variable.new(:x, RDF::Literal(123))}
112+
113+
it "has a value" do
114+
expect(subject.value).to eq RDF::Literal(123)
115+
end
116+
117+
it "is bound" do
118+
expect(subject).not_to be_unbound
119+
expect(subject).to be_bound
120+
expect(subject.variables).to eq({x: subject})
121+
expect(subject.bindings).to eq({x: RDF::Literal(123)})
122+
end
123+
124+
it "matches only its value" do
125+
[nil, true, false, RDF::Literal(456)].each do |value|
126+
expect((subject === value)).to be_falsey
127+
end
128+
expect((subject === RDF::Literal(123))).to be_truthy
129+
end
130+
131+
it "has a string representation" do
132+
expect(subject.to_s).to eq "?x=123"
133+
end
134+
end
135+
136+
context ".new bound" do
108137
subject {RDF::Query::Variable.new(:x, RDF::Literal(123))}
109138

110139
it "has a value" do

0 commit comments

Comments
 (0)