amigo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.rdoc +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +20 -0
- data/Rakefile +5 -0
- data/lib/amigo.rb +4 -0
- data/lib/amigo/core_ext.rb +1 -0
- data/lib/amigo/core_ext/object.rb +21 -0
- data/lib/amigo/initial_result.rb +31 -0
- data/lib/amigo/join_result.rb +27 -0
- data/lib/amigo/select.rb +55 -0
- data/lib/amigo/solution.rb +44 -0
- data/lib/amigo/store.rb +44 -0
- data/lib/amigo/term.rb +44 -0
- data/lib/amigo/triple.rb +45 -0
- data/lib/amigo/uri.rb +38 -0
- data/lib/amigo/variable.rb +45 -0
- data/lib/amigo/variables.rb +56 -0
- data/lib/amigo/version.rb +5 -0
- data/lib/amigo/where.rb +78 -0
- data/spec/amigo/select/execute_spec.rb +184 -0
- data/spec/amigo/select/immutable_spec.rb +15 -0
- data/spec/amigo/select/to_sparql_spec.rb +35 -0
- data/spec/amigo/select/to_sql_spec.rb +38 -0
- data/spec/amigo/store/to_ntriples_spec.rb +17 -0
- data/spec/amigo/term/to_sparql_spec.rb +35 -0
- data/spec/amigo/triple/immutable_spec.rb +15 -0
- data/spec/amigo/triple/inspect_spec.rb +23 -0
- data/spec/amigo/triple/to_ntriple_spec.rb +35 -0
- data/spec/amigo/uri/to_ntriple_spec.rb +34 -0
- data/spec/amigo/uri/to_sparql_spec.rb +34 -0
- data/spec/amigo/variable/to_sparql_spec.rb +35 -0
- data/spec/amigo/variables/immutable_spec.rb +15 -0
- data/spec/amigo/variables/include_spec.rb +38 -0
- data/spec/amigo/variables/to_sparql_spec.rb +36 -0
- data/spec/amigo/where/to_sparql_spec.rb +36 -0
- data/spec/spec.opts +2 -0
- data/spec/spec_helper.rb +2 -0
- data/tasks/spec.rb +6 -0
- metadata +144 -0
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'hamster/immutable'
|
2
|
+
require 'hamster/list'
|
3
|
+
|
4
|
+
module Amigo
|
5
|
+
|
6
|
+
class Variables
|
7
|
+
|
8
|
+
include Hamster::Immutable
|
9
|
+
|
10
|
+
module ALL
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
def include?(name)
|
15
|
+
true
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_sparql
|
19
|
+
"*"
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.new(*names)
|
27
|
+
return ALL if names.include?(:*)
|
28
|
+
super(names)
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(names)
|
32
|
+
@names = Hamster.list(*names)
|
33
|
+
end
|
34
|
+
|
35
|
+
def include?(name)
|
36
|
+
@names.include?(name)
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_sparql
|
40
|
+
@names.map { |name| "?#{name}" }.join(" ")
|
41
|
+
end
|
42
|
+
|
43
|
+
def eql?(other)
|
44
|
+
return true if other.equal?(self)
|
45
|
+
other.class.equal?(self.class) &&
|
46
|
+
@names.eql?(other.instance_variable_get(:@names))
|
47
|
+
end
|
48
|
+
alias_method :==, :eql?
|
49
|
+
|
50
|
+
def hash
|
51
|
+
@names.hash
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/amigo/where.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'hamster/immutable'
|
2
|
+
require 'hamster/list'
|
3
|
+
require 'hamster/hash'
|
4
|
+
require 'hamster/set'
|
5
|
+
|
6
|
+
require 'amigo/variable'
|
7
|
+
require 'amigo/term'
|
8
|
+
|
9
|
+
module Amigo
|
10
|
+
|
11
|
+
class Where
|
12
|
+
|
13
|
+
include Hamster::Immutable
|
14
|
+
|
15
|
+
def initialize(subject, predicate, object)
|
16
|
+
@components = Hamster.list(
|
17
|
+
component(:subject, subject),
|
18
|
+
component(:predicate, predicate),
|
19
|
+
component(:object, object)
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
def ask(statements)
|
24
|
+
statements.any? { |statement| select?(statement) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def select(statements)
|
28
|
+
statements.reduce(Hamster.set) do |result, statement|
|
29
|
+
next result unless select?(statement)
|
30
|
+
result.add(bind(statement, Hamster.hash))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def join(statements, rows)
|
35
|
+
rows.reduce(Hamster.set) do |result, row|
|
36
|
+
statements.reduce(result) do |result, statement|
|
37
|
+
next result unless join?(statement, row)
|
38
|
+
result.add(bind(statement, row))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def select?(statement)
|
44
|
+
@components.all? { |component| component.select?(statement) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def join?(statement, row)
|
48
|
+
select?(statement) && @components.all? { |component| component.join?(statement, row) }
|
49
|
+
end
|
50
|
+
|
51
|
+
def bind(statement, row)
|
52
|
+
@components.reduce(row) { |row, component| component.bind(statement, row) }
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_sparql
|
56
|
+
"#{@components.map(&:to_sparql).join(" ")} ."
|
57
|
+
end
|
58
|
+
|
59
|
+
def eql?(other)
|
60
|
+
return true if other.equal?(self)
|
61
|
+
other.class.equal?(self.class) &&
|
62
|
+
@components.eql?(other.instance_variable_get(:@components))
|
63
|
+
end
|
64
|
+
alias_method :==, :eql?
|
65
|
+
|
66
|
+
def hash
|
67
|
+
@components.hash
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def component(component, value)
|
73
|
+
(Symbol === value ? Variable : Term).new(component, value)
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'hamster/set'
|
4
|
+
require 'hamster/hash'
|
5
|
+
|
6
|
+
require 'amigo/uri'
|
7
|
+
require 'amigo/triple'
|
8
|
+
require 'amigo/select'
|
9
|
+
|
10
|
+
module Amigo
|
11
|
+
|
12
|
+
describe Select do
|
13
|
+
|
14
|
+
describe "#execute" do
|
15
|
+
|
16
|
+
describe "with no where clauses" do
|
17
|
+
|
18
|
+
before do
|
19
|
+
@result = Select.new(:title).
|
20
|
+
execute(Hamster.set(Triple.new(URI.parse(URI.parse("ex_book:book1")), URI.parse(URI.parse("dc:title")), "SPARQL Tutorial")))
|
21
|
+
end
|
22
|
+
|
23
|
+
it "the result has a single solution" do
|
24
|
+
@result.size.should == 1
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "the solution" do
|
28
|
+
|
29
|
+
before do
|
30
|
+
@solution = @result.first
|
31
|
+
end
|
32
|
+
|
33
|
+
it "binds no variables" do
|
34
|
+
@solution.include?(:title).should == false
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "when matching URIs" do
|
42
|
+
|
43
|
+
before do
|
44
|
+
@result = Select.new(:title).
|
45
|
+
where(URI.parse("ex_book:book1"), URI.parse("dc:title"), :title).
|
46
|
+
execute(Hamster.set(Triple.new(URI.parse("ex_book:book1"), URI.parse("dc:title"), "SPARQL Tutorial")))
|
47
|
+
end
|
48
|
+
|
49
|
+
it "returns the correct number of solutions" do
|
50
|
+
@result.size.should == 1
|
51
|
+
end
|
52
|
+
|
53
|
+
describe "each solution" do
|
54
|
+
|
55
|
+
before do
|
56
|
+
@solution = @result.first
|
57
|
+
end
|
58
|
+
|
59
|
+
it "correctly bind the selected variables" do
|
60
|
+
@solution[:title].should == "SPARQL Tutorial"
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "when matching literals" do
|
68
|
+
|
69
|
+
before do
|
70
|
+
@result = Select.new(:v).
|
71
|
+
where(:v, :p, 42).
|
72
|
+
execute(Hamster.set(Triple.new(URI.parse("ns:y"), URI.parse("ns:p"), 42)))
|
73
|
+
end
|
74
|
+
|
75
|
+
it "returns the correct number of solutions" do
|
76
|
+
@result.size.should == 1
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "each solution" do
|
80
|
+
|
81
|
+
before do
|
82
|
+
@solution = @result.first
|
83
|
+
end
|
84
|
+
|
85
|
+
it "correctly bind the the selected variables" do
|
86
|
+
@solution[:v].should == URI.parse("ns:y")
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
describe "with unselected variables" do
|
94
|
+
|
95
|
+
before do
|
96
|
+
@result = Select.new(:title).
|
97
|
+
where(:x, :y, :title).
|
98
|
+
execute(Hamster.set(Triple.new(URI.parse("ex_book:book1"), URI.parse("dc:title"), "SPARQL Tutorial")))
|
99
|
+
end
|
100
|
+
|
101
|
+
it "returns the correct number of solutions" do
|
102
|
+
@result.size.should == 1
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "each solution" do
|
106
|
+
|
107
|
+
before do
|
108
|
+
@solution = @result.first
|
109
|
+
end
|
110
|
+
|
111
|
+
it "correctly bind the the selected variables" do
|
112
|
+
@solution[:title].should == "SPARQL Tutorial"
|
113
|
+
end
|
114
|
+
|
115
|
+
it "do not bind any non-selected variables" do
|
116
|
+
@solution.include?(:x).should == false
|
117
|
+
@solution.include?(:y).should == false
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
describe "with joins" do
|
125
|
+
|
126
|
+
before do
|
127
|
+
@result = Select.new(:name, :mbox).
|
128
|
+
where(:x, URI.parse("foaf:name"), :name).
|
129
|
+
where(:x, URI.parse("foaf:mbox"), :mbox).
|
130
|
+
execute(Hamster.set(
|
131
|
+
Triple.new("a", URI.parse("foaf:name"), "Johnny Lee Outlaw"),
|
132
|
+
Triple.new("a", URI.parse("foaf:mbox"), URI.parse("mailto:jlow@example.com")),
|
133
|
+
Triple.new("b", URI.parse("foaf:name"), "Peter Goodguy"),
|
134
|
+
Triple.new("b", URI.parse("foaf:mbox"), URI.parse("mailto:peter@example.com")),
|
135
|
+
Triple.new("c", URI.parse("foaf:mbox"), URI.parse("mailto:carol@example.com"))
|
136
|
+
)).
|
137
|
+
sort_by(&:name)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "returns the correct number of solutions" do
|
141
|
+
@result.size == 2
|
142
|
+
end
|
143
|
+
|
144
|
+
describe "each solution" do
|
145
|
+
|
146
|
+
before do
|
147
|
+
@solution = @result.first
|
148
|
+
end
|
149
|
+
|
150
|
+
it "correctly bind the selected variables" do
|
151
|
+
@solution[:name].should == "Johnny Lee Outlaw"
|
152
|
+
@solution[:mbox].should == URI.parse("mailto:jlow@example.com")
|
153
|
+
end
|
154
|
+
|
155
|
+
it "does not bind any un-selected variables" do
|
156
|
+
@solution.include?(:x).should == false
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "each solution" do
|
162
|
+
|
163
|
+
before do
|
164
|
+
@solution = @result.last
|
165
|
+
end
|
166
|
+
|
167
|
+
it "correctly bind the selected variables" do
|
168
|
+
@solution[:name].should == "Peter Goodguy"
|
169
|
+
@solution[:mbox].should == URI.parse("mailto:peter@example.com")
|
170
|
+
end
|
171
|
+
|
172
|
+
it "does not bind any un-selected variables" do
|
173
|
+
@solution.include?(:x).should == false
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'amigo/select'
|
4
|
+
|
5
|
+
module Amigo
|
6
|
+
|
7
|
+
describe Select do
|
8
|
+
|
9
|
+
describe "#to_sparql" do
|
10
|
+
|
11
|
+
[
|
12
|
+
[Select.new(:*), "SELECT * WHERE {}"],
|
13
|
+
[Select.new(:*).where(:a, :b, :c), "SELECT * WHERE {?a ?b ?c .}"],
|
14
|
+
[Select.new(:a, :b, :c).where(:a, :b, :c), "SELECT ?a ?b ?c WHERE {?a ?b ?c .}"],
|
15
|
+
[Select.new(:a, :c).where(:a, :b, :c), "SELECT ?a ?c WHERE {?a ?b ?c .}"],
|
16
|
+
[Select.new(:*).where(:a, "bee", :c), "SELECT * WHERE {?a \"bee\" ?c .}"],
|
17
|
+
[Select.new(:a, :c).where(:a, "bee", :c), "SELECT ?a ?c WHERE {?a \"bee\" ?c .}"],
|
18
|
+
[Select.new(:*).where(:a, "bee", :c).where("dee", :e, "eff"), "SELECT * WHERE {?a \"bee\" ?c . \"dee\" ?e \"eff\" .}"],
|
19
|
+
].each do |select, sparql|
|
20
|
+
|
21
|
+
describe "given #{select.inspect}" do
|
22
|
+
|
23
|
+
it "returns #{sparql.inspect}" do
|
24
|
+
select.to_sparql.should == sparql
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'amigo/select'
|
4
|
+
|
5
|
+
module Amigo
|
6
|
+
|
7
|
+
describe Select do
|
8
|
+
|
9
|
+
describe "#to_sql" do
|
10
|
+
|
11
|
+
[
|
12
|
+
[Select.new(:*), "SELECT * FROM triples LIMIT 0"],
|
13
|
+
[Select.new(:*).where(:x, :y, :z), "SELECT subject x, predicate y, object z FROM triples"],
|
14
|
+
[Select.new(:x, :y, :z).where(:x, :y, :z), "SELECT subject x, predicate y, object z FROM triples"],
|
15
|
+
[Select.new(:x, :z).where(:x, :y, :z), "SELECT subject x, object z FROM triples"],
|
16
|
+
[Select.new(:*).where(:x, "bee", :z), "SELECT subject x, object z, FROM triples WHERE triples.predicate = 'bee'"],
|
17
|
+
[Select.new(:x, :z).where(:x, "bee", :z), "SELECT subject x, object z FROM triples WHERE triples.predicate = 'bee'"],
|
18
|
+
[Select.new(:*).where(:x, "bee", :z).where("dee", :y, "eff"), "SELECT a.subject x, a.object z, b.predicate y FROM triples a CROSS JOIN triples b WHERE a.predicate = 'bee' AND b.subject = 'dee' AND b.object = 'eff'"],
|
19
|
+
[Select.new(:x, :y).where(:x, "bee", :z).where(:z, :y, "see"), "SELECT a.subject x, b.predicate y FROM triples a JOIN triples b ON (a.object = b.subject) WHERE a.predicate = 'bee' AND b.object = 'see'"],
|
20
|
+
].each do |select, sql|
|
21
|
+
|
22
|
+
describe "given #{select.inspect}" do
|
23
|
+
|
24
|
+
it "returns #{sql.inspect}" do
|
25
|
+
pending {
|
26
|
+
select.to_sql.should == sql
|
27
|
+
}
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'amigo/term'
|
4
|
+
|
5
|
+
module Amigo
|
6
|
+
|
7
|
+
describe Term do
|
8
|
+
|
9
|
+
describe "#to_sparql" do
|
10
|
+
|
11
|
+
[
|
12
|
+
[:subject, "a", "\"a\""],
|
13
|
+
[:predicate, "x", "\"x\""],
|
14
|
+
[:object, "flibble", "\"flibble\""]
|
15
|
+
].each do |component, value, sparql|
|
16
|
+
|
17
|
+
describe "given #{name.inspect}" do
|
18
|
+
|
19
|
+
before do
|
20
|
+
@term = Term.new(component, value)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "returns #{sparql.inspect}" do
|
24
|
+
@term.to_sparql.should == sparql
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|