tripod 0.0.10 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +11 -5
- data/lib/tripod.rb +3 -0
- data/lib/tripod/attributes.rb +49 -57
- data/lib/tripod/components.rb +2 -0
- data/lib/tripod/errors.rb +1 -0
- data/lib/tripod/errors/field_not_present.rb +8 -0
- data/lib/tripod/fields.rb +4 -31
- data/lib/tripod/finders.rb +19 -12
- data/lib/tripod/persistence.rb +12 -0
- data/lib/tripod/predicates.rb +78 -0
- data/lib/tripod/repository.rb +20 -3
- data/lib/tripod/resource.rb +23 -24
- data/lib/tripod/serialization.rb +27 -0
- data/lib/tripod/sparql_client.rb +15 -4
- data/lib/tripod/version.rb +1 -1
- data/spec/app/models/person.rb +4 -0
- data/spec/tripod/attributes_spec.rb +79 -70
- data/spec/tripod/fields_spec.rb +15 -65
- data/spec/tripod/finders_spec.rb +14 -19
- data/spec/tripod/persistence_spec.rb +62 -58
- data/spec/tripod/predicates_spec.rb +82 -0
- data/spec/tripod/repository_spec.rb +53 -26
- data/spec/tripod/resource_spec.rb +20 -40
- data/spec/tripod/serialization_spec.rb +36 -0
- data/spec/tripod/state_spec.rb +2 -2
- data/tripod.gemspec +3 -2
- metadata +38 -20
data/spec/tripod/finders_spec.rb
CHANGED
@@ -18,8 +18,8 @@ describe Tripod::Finders do
|
|
18
18
|
stmt.object = RDF::URI.new('http://bill')
|
19
19
|
stmts << stmt
|
20
20
|
|
21
|
-
r = Person.new(@ric_uri
|
22
|
-
r.hydrate!(stmts)
|
21
|
+
r = Person.new(@ric_uri)
|
22
|
+
r.hydrate!(:graph => stmts)
|
23
23
|
r.save
|
24
24
|
r
|
25
25
|
end
|
@@ -32,8 +32,8 @@ describe Tripod::Finders do
|
|
32
32
|
stmt.predicate = RDF::URI.new('http://name')
|
33
33
|
stmt.object = "bill"
|
34
34
|
stmts << stmt
|
35
|
-
b = Person.new(@bill_uri
|
36
|
-
b.hydrate!(stmts)
|
35
|
+
b = Person.new(@bill_uri)
|
36
|
+
b.hydrate!(:graph => stmts)
|
37
37
|
b.save
|
38
38
|
b
|
39
39
|
end
|
@@ -41,38 +41,33 @@ describe Tripod::Finders do
|
|
41
41
|
describe '.find' do
|
42
42
|
|
43
43
|
context 'when record exists' do
|
44
|
-
|
45
|
-
it 'does not error' do
|
46
|
-
r = Person.find(ric.uri)
|
47
|
-
end
|
44
|
+
let(:person) { Person.find(ric.uri) }
|
48
45
|
|
49
46
|
it 'hydrates and return an object' do
|
50
|
-
|
51
|
-
|
52
|
-
r['http://knows'].should == [RDF::URI.new('http://bill')]
|
47
|
+
person.name.should == "ric"
|
48
|
+
person.knows.should == [RDF::URI('http://bill')]
|
53
49
|
end
|
54
50
|
|
55
51
|
it 'sets the graph on the instantiated object' do
|
56
|
-
|
57
|
-
|
58
|
-
r.graph_uri.should == RDF::URI("http://people")
|
52
|
+
person.graph_uri.should_not be_nil
|
53
|
+
person.graph_uri.should == RDF::URI("http://graph")
|
59
54
|
end
|
60
55
|
|
61
56
|
it "returns a non-new record" do
|
62
|
-
|
63
|
-
r.new_record?.should be_false
|
57
|
+
person.new_record?.should be_false
|
64
58
|
end
|
65
59
|
|
66
60
|
end
|
67
61
|
|
68
62
|
context 'when record does not exist' do
|
69
63
|
it 'raises not found' do
|
70
|
-
lambda { Person.find('http://
|
64
|
+
lambda { Person.find('http://nonexistent') }.should raise_error(Tripod::Errors::ResourceNotFound)
|
71
65
|
end
|
72
66
|
end
|
73
67
|
|
68
|
+
context 'with a given graph URI' do
|
74
69
|
|
75
|
-
|
70
|
+
end
|
76
71
|
end
|
77
72
|
|
78
73
|
describe '.where' do
|
@@ -90,7 +85,7 @@ describe Tripod::Finders do
|
|
90
85
|
res.last.should == bill
|
91
86
|
|
92
87
|
res.first.name.should == "ric"
|
93
|
-
res.first
|
88
|
+
res.first.knows.should == [RDF::URI.new("http://bill")]
|
94
89
|
end
|
95
90
|
|
96
91
|
it 'uses the uri and graph variables if supplied' do
|
@@ -4,14 +4,15 @@ describe Tripod::Persistence do
|
|
4
4
|
|
5
5
|
let(:unsaved_person) do
|
6
6
|
@unsaved_uri = @uri = 'http://uri'
|
7
|
-
@
|
7
|
+
@graph_uri = 'http://graph'
|
8
|
+
@graph1 = RDF::Graph.new(@graph_uri)
|
8
9
|
stmt = RDF::Statement.new
|
9
10
|
stmt.subject = RDF::URI.new(@uri)
|
10
11
|
stmt.predicate = RDF::URI.new('http://pred')
|
11
12
|
stmt.object = RDF::URI.new('http://obj')
|
12
13
|
@graph1 << stmt
|
13
14
|
p = Person.new(@uri, 'http://graph')
|
14
|
-
p.hydrate!(@graph1)
|
15
|
+
p.hydrate!(:graph => @graph1)
|
15
16
|
p
|
16
17
|
end
|
17
18
|
|
@@ -24,65 +25,38 @@ describe Tripod::Persistence do
|
|
24
25
|
stmt.object = RDF::URI.new('http://obj2')
|
25
26
|
@graph2 << stmt
|
26
27
|
p = Person.new(@uri2, 'http://graph')
|
27
|
-
p.hydrate!(@graph2)
|
28
|
+
p.hydrate!(:graph => @graph2)
|
28
29
|
p.save
|
29
30
|
p
|
30
31
|
end
|
31
32
|
|
32
33
|
|
33
|
-
describe "
|
34
|
+
describe ".save" do
|
35
|
+
it 'saves the contents to the db' do
|
36
|
+
unsaved_person.save.should be_true
|
34
37
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
context 'uri not set' do
|
47
|
-
it 'should not succeed' do
|
48
|
-
unsaved_person.uri = nil
|
49
|
-
unsaved_person.save.should be_false
|
50
|
-
unsaved_person.should_not be_valid
|
51
|
-
unsaved_person.errors.should_not be_empty
|
52
|
-
unsaved_person.errors[:uri].length.should ==1
|
53
|
-
unsaved_person.errors[:uri].should == ["can't be blank"]
|
54
|
-
end
|
38
|
+
# try reading the data back out.
|
39
|
+
p2 = Person.new(@uri)
|
40
|
+
p2.hydrate!
|
41
|
+
repo_statements = p2.repository.statements
|
42
|
+
repo_statements.count.should == 1
|
43
|
+
repo_statements.first.subject.should == RDF::URI.new(@uri)
|
44
|
+
repo_statements.first.predicate.should == RDF::URI.new('http://pred')
|
45
|
+
repo_statements.first.object.should == RDF::URI.new('http://obj')
|
55
46
|
end
|
56
47
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
unsaved_person.save.should be_true
|
61
|
-
|
62
|
-
# try reading the data back out.
|
63
|
-
p2 = Person.new(@uri)
|
64
|
-
p2.hydrate!
|
65
|
-
repo_statements = p2.repository.statements
|
66
|
-
repo_statements.count.should == 1
|
67
|
-
repo_statements.first.subject.should == RDF::URI.new(@uri)
|
68
|
-
repo_statements.first.predicate.should == RDF::URI.new('http://pred')
|
69
|
-
repo_statements.first.object.should == RDF::URI.new('http://obj')
|
70
|
-
end
|
71
|
-
|
72
|
-
it 'should leave other people untouched' do
|
73
|
-
# save the unsaved person
|
74
|
-
unsaved_person.save.should be_true
|
75
|
-
|
76
|
-
# read the saved person back out the db, and check he's untouched.
|
77
|
-
p2 = Person.new(saved_person.uri)
|
78
|
-
p2.hydrate!
|
79
|
-
p2.repository.dump(:ntriples).should == saved_person.repository.dump(:ntriples)
|
80
|
-
end
|
48
|
+
it 'should leave other people untouched' do
|
49
|
+
# save the unsaved person
|
50
|
+
unsaved_person.save.should be_true
|
81
51
|
|
52
|
+
# read the saved person back out the db, and check he's untouched.
|
53
|
+
p2 = Person.new(saved_person.uri)
|
54
|
+
p2.hydrate!
|
55
|
+
p2.repository.dump(:ntriples).should == saved_person.repository.dump(:ntriples)
|
82
56
|
end
|
83
57
|
end
|
84
58
|
|
85
|
-
describe "
|
59
|
+
describe ".destroy" do
|
86
60
|
|
87
61
|
it 'removes all triples from the db' do
|
88
62
|
saved_person.destroy.should be_true
|
@@ -95,42 +69,72 @@ describe Tripod::Persistence do
|
|
95
69
|
|
96
70
|
end
|
97
71
|
|
98
|
-
describe "
|
72
|
+
describe ".save!" do
|
99
73
|
it 'throws an exception if save fails' do
|
100
|
-
unsaved_person.
|
74
|
+
unsaved_person.stub(:graph_uri).and_return(nil) # force a failure
|
101
75
|
lambda {unsaved_person.save!}.should raise_error(Tripod::Errors::Validations)
|
102
76
|
end
|
103
77
|
end
|
104
78
|
|
79
|
+
describe '.update_attribute' do
|
80
|
+
let (:person) { Person.new('http://newperson') }
|
81
|
+
before { person.stub(:save) }
|
82
|
+
|
83
|
+
it 'should write the attribute' do
|
84
|
+
person.update_attribute(:name, 'Bob')
|
85
|
+
person.name.should == 'Bob'
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should save the record' do
|
89
|
+
person.should_receive(:save)
|
90
|
+
person.update_attribute(:name, 'Bob')
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '.update_attributes' do
|
95
|
+
let (:person) { Person.new('http://newperson') }
|
96
|
+
before { person.stub(:save) }
|
97
|
+
|
98
|
+
it 'should assign the attributes' do
|
99
|
+
person.update_attributes(:name => 'Bob')
|
100
|
+
person.name.should == 'Bob'
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should save the record' do
|
104
|
+
person.should_receive(:save)
|
105
|
+
person.update_attributes(:name => 'Bob')
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
105
109
|
describe "transactions" do
|
106
110
|
|
107
|
-
it "only
|
111
|
+
it "only saves on commit" do
|
108
112
|
|
109
113
|
transaction = Tripod::Persistence::Transaction.new
|
110
114
|
|
111
115
|
unsaved_person.save(transaction: transaction)
|
112
|
-
saved_person
|
116
|
+
saved_person.write_predicate('http://pred2', 'blah')
|
113
117
|
saved_person.save(transaction: transaction)
|
114
118
|
|
115
119
|
# nothing should have changed yet.
|
116
120
|
lambda {Person.find(unsaved_person.uri)}.should raise_error(Tripod::Errors::ResourceNotFound)
|
117
|
-
Person.find(saved_person.uri)
|
121
|
+
Person.find(saved_person.uri).read_predicate('http://pred2').first.to_s.should == RDF::URI.new('http://obj2').to_s
|
118
122
|
|
119
123
|
transaction.commit
|
120
124
|
|
121
125
|
# things should have changed now.
|
122
126
|
lambda {Person.find(unsaved_person.uri)}.should_not raise_error()
|
123
|
-
Person.find(saved_person.uri)
|
127
|
+
Person.find(saved_person.uri).read_predicate('http://pred2').first.should == 'blah'
|
124
128
|
|
125
129
|
end
|
126
130
|
|
127
131
|
it "silently ignore invalid saves" do
|
128
132
|
transaction = Tripod::Persistence::Transaction.new
|
129
133
|
|
130
|
-
unsaved_person.
|
134
|
+
unsaved_person.stub(:graph_uri).and_return(nil) # force a failure
|
131
135
|
unsaved_person.save(transaction: transaction).should be_false
|
132
136
|
|
133
|
-
saved_person
|
137
|
+
saved_person.write_predicate('http://pred2', 'blah')
|
134
138
|
saved_person.save(transaction: transaction).should be_true
|
135
139
|
|
136
140
|
transaction.commit
|
@@ -142,7 +146,7 @@ describe Tripod::Persistence do
|
|
142
146
|
lambda {Person.find(unsaved_person.uri)}.should raise_error(Tripod::Errors::ResourceNotFound)
|
143
147
|
|
144
148
|
# saved person SHOULD be updated
|
145
|
-
Person.find(saved_person.uri)
|
149
|
+
Person.find(saved_person.uri).read_predicate('http://pred2').first.should == 'blah'
|
146
150
|
end
|
147
151
|
|
148
152
|
it "can be aborted" do
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Tripod::Predicates do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@uri = 'http://ric'
|
7
|
+
@graph = RDF::Graph.new('http://graph')
|
8
|
+
|
9
|
+
stmt = RDF::Statement.new
|
10
|
+
stmt.subject = RDF::URI.new(@uri)
|
11
|
+
stmt.predicate = RDF::URI.new('http://blog')
|
12
|
+
stmt.object = RDF::URI.new('http://blog1')
|
13
|
+
@graph << stmt
|
14
|
+
|
15
|
+
stmt2 = RDF::Statement.new
|
16
|
+
stmt2.subject = RDF::URI.new(@uri)
|
17
|
+
stmt2.predicate = RDF::URI.new('http://blog')
|
18
|
+
stmt2.object = RDF::URI.new('http://blog2')
|
19
|
+
@graph << stmt2
|
20
|
+
|
21
|
+
stmt3 = RDF::Statement.new
|
22
|
+
stmt3.subject = RDF::URI.new(@uri)
|
23
|
+
stmt3.predicate = RDF::URI.new('http://name')
|
24
|
+
stmt3.object = "ric"
|
25
|
+
@graph << stmt3
|
26
|
+
end
|
27
|
+
|
28
|
+
let(:person) do
|
29
|
+
p = Person.new(@uri)
|
30
|
+
p.hydrate!(:graph => @graph)
|
31
|
+
p
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#read_predicate" do
|
35
|
+
it 'returns the values where the predicate matches' do
|
36
|
+
values = person.read_predicate('http://blog')
|
37
|
+
values.length.should == 2
|
38
|
+
values.first.should == RDF::URI('http://blog1')
|
39
|
+
values[1].should == RDF::URI('http://blog2')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#write_predicate' do
|
44
|
+
|
45
|
+
context 'single term passed' do
|
46
|
+
it 'replaces the values where the predicate matches' do
|
47
|
+
person.write_predicate('http://name', 'richard')
|
48
|
+
person.read_predicate('http://name').should == [RDF::Literal.new('richard')]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'multiple terms passed' do
|
53
|
+
it 'replaces the values where the predicate matches' do
|
54
|
+
person.write_predicate('http://name', ['richard', 'ric', 'ricardo'])
|
55
|
+
person.read_predicate('http://name').should == [RDF::Literal.new('richard'), RDF::Literal.new('ric'), RDF::Literal.new('ricardo')]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
describe '#remove_predicate' do
|
62
|
+
it 'remnoves the values where the predicate matches' do
|
63
|
+
person.remove_predicate('http://blog')
|
64
|
+
person.read_predicate('http://blog').should be_empty
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#append_to_predicate" do
|
69
|
+
it 'appends values to the existing values for the predicate' do
|
70
|
+
person.append_to_predicate('http://name', 'rico')
|
71
|
+
person.read_predicate('http://name').should == [RDF::Literal.new('ric'), RDF::Literal.new('rico')]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#predicates" do
|
76
|
+
it "returns a list of unique RDF::URIs for the predicates set on this resource" do
|
77
|
+
person.predicates.length.should == 2
|
78
|
+
person.predicates.should == [RDF::URI('http://blog'), RDF::URI('http://name')]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -4,51 +4,78 @@ describe Tripod::Repository do
|
|
4
4
|
|
5
5
|
describe "#hydrate" do
|
6
6
|
|
7
|
-
context 'no uri set' do
|
8
|
-
let(:person) do
|
9
|
-
Person.new
|
10
|
-
end
|
11
|
-
|
12
|
-
it 'rasies a UriNotSet error' do
|
13
|
-
lambda { person.hydrate! }.should raise_error(Tripod::Errors::UriNotSet)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
7
|
context 'uri set' do
|
18
8
|
|
19
9
|
before do
|
20
10
|
@uri = 'http://foobar'
|
21
|
-
@
|
22
|
-
@
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
11
|
+
@uri2 = 'http://bazbar'
|
12
|
+
@graph_uri = 'http://graph'
|
13
|
+
|
14
|
+
p1 = Person.new(@uri, @graph_uri)
|
15
|
+
p1.write_predicate('http://pred', RDF::URI.new('http://obj'))
|
16
|
+
p1.write_predicate('http://pred2', RDF::URI.new('http://obj2'))
|
17
|
+
p1.write_predicate('http://pred3', 'literal')
|
18
|
+
p1.save!
|
28
19
|
end
|
29
20
|
|
30
21
|
let(:person) do
|
31
|
-
Person.new(@uri)
|
22
|
+
Person.new(@uri, @graph_uri)
|
32
23
|
end
|
33
24
|
|
34
25
|
context 'no graph passed' do
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
26
|
+
|
27
|
+
context 'no predicate restrictions passed' do
|
28
|
+
|
29
|
+
it 'populates the repository with a graph of triples from the db' do
|
30
|
+
Tripod::SparqlClient::Query.should_receive(:describe).with("DESCRIBE <#{@uri}>").and_call_original
|
31
|
+
person.hydrate!
|
32
|
+
person.repository.should_not be_empty
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'single predicate restriction passed' do
|
38
|
+
it 'calls the right CONSTRUCT query' do
|
39
|
+
Tripod::SparqlClient::Query.should_receive(:construct).with("CONSTRUCT { <http://foobar> ?p ?o } WHERE { <http://foobar> ?p ?o . FILTER (?p = <http://pred>)}").and_call_original
|
40
|
+
person.hydrate!(:only => 'http://pred')
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'only populates the right predicates' do
|
44
|
+
person.hydrate!(:only => 'http://pred')
|
45
|
+
person.predicates.length.should ==1
|
46
|
+
person.predicates.should == [RDF::URI('http://pred')]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'multiple predicate restrictions passed' do
|
51
|
+
it 'calls the right CONSTRUCT query' do
|
52
|
+
Tripod::SparqlClient::Query.should_receive(:construct).with("CONSTRUCT { <http://foobar> ?p ?o } WHERE { <http://foobar> ?p ?o . FILTER (?p = <http://pred> || ?p = <http://anotherpred>)}").and_call_original
|
53
|
+
person.hydrate!(:only => ['http://pred', 'http://anotherpred'])
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'only populates the right predicates' do
|
57
|
+
person.hydrate!(:only => ['http://pred2', 'http://pred'])
|
58
|
+
person.predicates.length.should == 2
|
59
|
+
person.predicates.should == [RDF::URI('http://pred'), RDF::URI('http://pred2')]
|
60
|
+
end
|
39
61
|
end
|
40
62
|
end
|
41
63
|
|
42
64
|
context 'graph passed' do
|
43
65
|
it 'populates the repository with the graph of triples passed in, ingoring triples not about this resource' do
|
66
|
+
@graph = RDF::Graph.new
|
67
|
+
|
68
|
+
person.repository.statements.each do |s|
|
69
|
+
@graph << s
|
70
|
+
end
|
44
71
|
|
45
72
|
@graph << RDF::Statement.new( 'http://anotherresource', 'http://pred', 'http://obj')
|
46
|
-
@graph.statements.count.should ==2
|
73
|
+
@graph.statements.count.should ==2 # there'll already be a statement about type in the person.
|
47
74
|
|
48
|
-
person.hydrate!(@graph)
|
75
|
+
person.hydrate!(:graph => @graph)
|
49
76
|
person.repository.should_not be_empty
|
50
|
-
person.repository.statements.count.should == 1 # not the extra
|
51
|
-
person.repository.statements.first.should == @
|
77
|
+
person.repository.statements.count.should == 1 # not the extra ones
|
78
|
+
person.repository.statements.first.should == @graph.statements.first
|
52
79
|
end
|
53
80
|
end
|
54
81
|
|