amigo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|