dbd 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +10 -0
  5. data/Gemfile +8 -0
  6. data/Guardfile +7 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +97 -0
  9. data/Rakefile +1 -0
  10. data/dbd.gemspec +30 -0
  11. data/docs/rationale.md +17 -0
  12. data/docs/stories/001_create_a_fact.txt +15 -0
  13. data/docs/stories/002_create_a_facts_collection.txt +14 -0
  14. data/docs/stories/003_create_a_fact_origin.txt +15 -0
  15. data/docs/stories/004_create_fact_origins_collection.txt +8 -0
  16. data/docs/stories/005_CSV_export_the_graph.txt +18 -0
  17. data/docs/stories/006_refactor_fact_origin_to_provenance_fact.txt +20 -0
  18. data/docs/stories/007_rename_property_to_predicate.txt +6 -0
  19. data/docs/stories/008_testing_different_ruby_versions.txt +7 -0
  20. data/docs/stories/009_build_and_store_resources_with_provenance.txt +38 -0
  21. data/docs/stories/010_provenance_fact_properties_from_provenance_ontology.txt +10 -0
  22. data/docs/test.rb +32 -0
  23. data/lib/dbd.rb +13 -0
  24. data/lib/dbd/errors.rb +11 -0
  25. data/lib/dbd/fact.rb +182 -0
  26. data/lib/dbd/fact/collection.rb +60 -0
  27. data/lib/dbd/fact/id.rb +19 -0
  28. data/lib/dbd/fact/subject.rb +21 -0
  29. data/lib/dbd/graph.rb +47 -0
  30. data/lib/dbd/helpers/ordered_set_collection.rb +86 -0
  31. data/lib/dbd/helpers/uuid.rb +33 -0
  32. data/lib/dbd/provenance_fact.rb +76 -0
  33. data/lib/dbd/provenance_resource.rb +54 -0
  34. data/lib/dbd/rdf.rb +9 -0
  35. data/lib/dbd/repo.rb +8 -0
  36. data/lib/dbd/repo/neo4j_repo.rb +4 -0
  37. data/lib/dbd/repo/neo4j_repo/base.rb +55 -0
  38. data/lib/dbd/resource.rb +117 -0
  39. data/lib/dbd/version.rb +3 -0
  40. data/spec/factories/fact.rb +76 -0
  41. data/spec/factories/provenance_fact.rb +34 -0
  42. data/spec/factories/provenance_resource.rb +16 -0
  43. data/spec/factories/resource.rb +17 -0
  44. data/spec/lib/dbd/fact/collection_spec.rb +236 -0
  45. data/spec/lib/dbd/fact/id_spec.rb +19 -0
  46. data/spec/lib/dbd/fact/subject_spec.rb +19 -0
  47. data/spec/lib/dbd/fact_spec.rb +217 -0
  48. data/spec/lib/dbd/graph_spec.rb +214 -0
  49. data/spec/lib/dbd/helpers/ordered_set_collection_spec.rb +88 -0
  50. data/spec/lib/dbd/helpers/uuid_spec.rb +15 -0
  51. data/spec/lib/dbd/provenance_fact_spec.rb +108 -0
  52. data/spec/lib/dbd/provenance_resource_spec.rb +77 -0
  53. data/spec/lib/dbd/rdf_base_spec.rb +39 -0
  54. data/spec/lib/dbd/repo/neo4j_repo/base_spec.rb +85 -0
  55. data/spec/lib/dbd/repo/neo4j_repo/performance_spec.rb +40 -0
  56. data/spec/lib/dbd/resource_spec.rb +166 -0
  57. data/spec/spec_helper.rb +19 -0
  58. metadata +272 -0
@@ -0,0 +1,16 @@
1
+ module Factories
2
+ module ProvenanceResource
3
+
4
+ def self.factory_for
5
+ ::Dbd::ProvenanceResource
6
+ end
7
+
8
+ def self.provenance_resource
9
+ factory_for.new.tap do |resource|
10
+ resource << Factories::ProvenanceFact.context
11
+ resource << Factories::ProvenanceFact.created_by
12
+ end
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,17 @@
1
+ module Factories
2
+ module Resource
3
+
4
+ def self.factory_for
5
+ ::Dbd::Resource
6
+ end
7
+
8
+ def self.facts_resource(provenance_subject)
9
+ subject = Fact.new_subject
10
+ factory_for.new(subject: subject, provenance_subject: provenance_subject).tap do |resource|
11
+ resource << Factories::Fact.data_fact(provenance_subject, subject)
12
+ resource << Factories::Fact.data_fact_EU(provenance_subject, subject)
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,236 @@
1
+ require 'spec_helper'
2
+
3
+ module Dbd
4
+ class Fact
5
+ describe Collection do
6
+
7
+ let(:provenance_subject_1) { ProvenanceFact.new_subject }
8
+ let(:provenance_subject_2) { ProvenanceFact.new_subject }
9
+
10
+ let(:provenance_fact_context) { Factories::ProvenanceFact.context(provenance_subject_1) }
11
+ let(:provenance_fact_created_by) { Factories::ProvenanceFact.created_by(provenance_subject_1) }
12
+ let(:provenance_fact_original_source) { Factories::ProvenanceFact.original_source(provenance_subject_2) }
13
+
14
+ let(:fact_1) { Factories::Fact.fact_1(provenance_subject_1) }
15
+ let(:fact_2_with_subject) { Factories::Fact.fact_2_with_subject(provenance_subject_1) }
16
+ let(:fact_3_with_subject) { Factories::Fact.fact_3_with_subject(provenance_subject_1) }
17
+
18
+ let(:fact_2_3) { Factories::Fact::Collection.fact_2_3(provenance_subject_1) }
19
+ let(:provenance_facts) { Factories::Fact::Collection.provenance_facts(provenance_subject_1) }
20
+
21
+ let(:subject) do
22
+ Object.new.tap do |object_with_Fact_Collection|
23
+ object_with_Fact_Collection.extend(described_class)
24
+ object_with_Fact_Collection.send(:initialize)
25
+ end
26
+ end
27
+
28
+ describe ".new : " do
29
+ it "the collection is not an array" do
30
+ subject.should_not be_a(Array)
31
+ end
32
+
33
+ it "the collection has Enumerable methods" do
34
+ subject.map #should_not raise_exception
35
+ end
36
+ end
37
+
38
+ describe ".methods : " do
39
+
40
+ describe "#<< : " do
41
+ it "adding a fact works" do
42
+ subject << fact_2_with_subject
43
+ subject.size.should == 1
44
+ end
45
+
46
+ it "adding a provenance_fact works" do
47
+ subject << provenance_fact_context
48
+ subject.size.should == 1
49
+ end
50
+
51
+ it "returns self to allow chaining" do
52
+ (subject << provenance_fact_context).should == subject
53
+ end
54
+ end
55
+
56
+ it "#first should be a Fact" do
57
+ subject << fact_2_with_subject
58
+ subject.first.should be_a(Fact)
59
+ end
60
+
61
+ it "other functions (e.g. []) do not work" do
62
+ subject << fact_2_with_subject
63
+ lambda { subject[0] } . should raise_exception NoMethodError
64
+ end
65
+
66
+ it "#<< returns self, so chaining is possible" do
67
+ (subject << fact_2_with_subject).should == subject
68
+ end
69
+ end
70
+
71
+ describe "adding a fact with a ref to a provenance_fact" do
72
+
73
+ it "fact_2_with_subject has a provenance_subject that refers to context and created_by" do
74
+ subject << provenance_fact_context
75
+ subject << provenance_fact_created_by
76
+ subject << fact_2_with_subject
77
+ ps = fact_1.provenance_subject
78
+ subject.by_subject(ps).should == [provenance_fact_context, provenance_fact_created_by]
79
+ end
80
+ end
81
+
82
+ describe "newest_time_stamp" do
83
+ it "returns nil for empty collection" do
84
+ subject.newest_time_stamp.should be_nil
85
+ end
86
+
87
+ it "returns a time_stamp" do
88
+ subject << fact_2_with_subject
89
+ subject.newest_time_stamp.should be_a(fact_2_with_subject.time_stamp.class)
90
+ end
91
+
92
+ it "returns the newest time_stamp" do
93
+ subject << fact_2_with_subject
94
+ subject << fact_3_with_subject
95
+ subject.newest_time_stamp.should == fact_3_with_subject.time_stamp
96
+ end
97
+ end
98
+
99
+ describe "validate that only 'newer' elements are added" do
100
+ before(:each) do
101
+ fact_2_with_subject.stub(:time_stamp).and_return(Time.new(2013,05,9,12,0,0))
102
+ fact_3_with_subject.stub(:time_stamp).and_return(Time.new(2013,05,9,12,0,1))
103
+ end
104
+
105
+ it "adding an element with a newer time_stamp succeeds" do
106
+ subject << fact_2_with_subject
107
+ subject << fact_3_with_subject
108
+ end
109
+
110
+ it "adding an element with an older time_stamp fails" do
111
+ fact_2_with_subject # will be older then fact_3_with_subject
112
+ subject << fact_3_with_subject
113
+ lambda { subject << fact_2_with_subject } . should raise_error OutOfOrderError
114
+ end
115
+
116
+ it "adding an element with an equal time_stamp fails" do
117
+ subject << fact_2_with_subject
118
+ lambda { subject << fact_2_with_subject } . should raise_error OutOfOrderError
119
+ end
120
+ end
121
+
122
+ describe "oldest_time_stamp" do
123
+ it "returns nil for empty collection" do
124
+ subject.oldest_time_stamp.should be_nil
125
+ end
126
+
127
+ it "returns a time_stamp" do
128
+ subject << fact_2_with_subject
129
+ subject.oldest_time_stamp.should be_a(fact_2_with_subject.time_stamp.class)
130
+ end
131
+
132
+ it "returns the oldest time_stamp" do
133
+ subject << fact_2_with_subject
134
+ subject << fact_3_with_subject
135
+ subject.oldest_time_stamp.should == fact_2_with_subject.time_stamp
136
+ end
137
+ end
138
+
139
+ describe "provenance_facts must all come before first use by a fact" do
140
+ it "adding a provenance_fact, depending fact, another provenance_fact with same subject fail" do
141
+ subject << provenance_fact_context
142
+ subject << fact_2_with_subject
143
+ lambda { subject << provenance_fact_created_by } . should raise_error OutOfOrderError
144
+ end
145
+
146
+ # testing private functionality (kept temporarily as documentation)
147
+ # A hash with all the provenance_subjects that are used by at least one fact.
148
+ # Needed for the validation that no provenance_fact may be added that is
149
+ # referred from a fact that is already in the fact stream.
150
+ describe "used_provenance_subjects" do
151
+ # testing an internal variable ...
152
+
153
+ let(:used_provenance_subjects) do
154
+ subject.instance_variable_get(:@used_provenance_subjects)
155
+ end
156
+
157
+ it "is empty initially" do
158
+ used_provenance_subjects.should be_empty
159
+ end
160
+
161
+ it "adding a provenance_fact alone does not create an entry" do
162
+ subject << provenance_fact_context
163
+ used_provenance_subjects.should be_empty
164
+ end
165
+
166
+ it "adding a provenance_fact and a depending fact create an entry" do
167
+ subject << provenance_fact_context
168
+ subject << fact_2_with_subject
169
+ used_provenance_subjects[provenance_subject_1].should == true
170
+ end
171
+ end
172
+ end
173
+
174
+ describe "validate that facts are valid? when loading in the Fact::Collection" do
175
+ it "succeeds with a fact from factory" do
176
+ subject << fact_2_with_subject # should_not raise_error
177
+ end
178
+
179
+ it "raises FactError when fact.valid? is false" do
180
+ provenance_fact_context.stub(:valid?).and_return(false)
181
+ lambda { subject << provenance_fact_context } . should raise_error FactError
182
+ end
183
+ end
184
+
185
+ describe "by_subject : " do
186
+ it "finds entries for a given subject" do
187
+ subject << provenance_fact_context
188
+ subject << provenance_fact_created_by
189
+ subject << provenance_fact_original_source
190
+ provenance_fact_context.subject.should == provenance_subject_1 # assert test set-up
191
+ provenance_fact_created_by.subject.should == provenance_subject_1 # assert test set-up
192
+ provenance_fact_original_source.subject.should == provenance_subject_2 # assert test set-up
193
+ subject.by_subject(provenance_subject_1).first.should == provenance_fact_context
194
+ subject.by_subject(provenance_subject_1).last.should == provenance_fact_created_by
195
+ subject.by_subject(provenance_subject_2).single.should == provenance_fact_original_source
196
+ end
197
+ end
198
+
199
+ describe "Factories::Fact::Collection" do
200
+ describe ".fact_2_3" do
201
+ it "has the given provenance_subject with explicit subject arg" do
202
+ fact_2_3.each do |fact|
203
+ fact.provenance_subject.should == provenance_subject_1
204
+ end
205
+ end
206
+ end
207
+
208
+ describe ".provenance_facts" do
209
+ it "has a context" do
210
+ provenance_facts.select do |provenance_fact|
211
+ provenance_fact.predicate == "https://data.vandenabeele.com/ontologies/provenance#context"
212
+ end.size.should == 1
213
+ end
214
+
215
+ it "has a created_by" do
216
+ provenance_facts.select do |provenance_fact|
217
+ provenance_fact.predicate == "https://data.vandenabeele.com/ontologies/provenance#created_by"
218
+ end.size.should == 1
219
+ end
220
+
221
+ it "has an original_source" do
222
+ provenance_facts.select do |provenance_fact|
223
+ provenance_fact.predicate == "https://data.vandenabeele.com/ontologies/provenance#original_source"
224
+ end.size.should == 1
225
+ end
226
+
227
+ it "has the given subjects with explicit subject arg" do
228
+ provenance_facts.each do |provenance_fact|
229
+ provenance_fact.subject.should == provenance_subject_1
230
+ end
231
+ end
232
+ end
233
+ end
234
+ end
235
+ end
236
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module Dbd
4
+ class Fact
5
+ describe ID do
6
+ it ".new creates an ID" do
7
+ subject.should be_a(described_class)
8
+ end
9
+
10
+ it "#to_s is a UUID string" do
11
+ subject.to_s.should match(Helpers::UUID.regexp)
12
+ end
13
+
14
+ it ".regexp has a regexp for the to_s" do
15
+ described_class.regexp.should == Helpers::UUID.regexp
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module Dbd
4
+ class Fact
5
+ describe Subject do
6
+ it ".new creates a Subject" do
7
+ subject.should be_a(described_class)
8
+ end
9
+
10
+ it "#to_s is a UUID string" do
11
+ subject.to_s.should match(Helpers::UUID.regexp)
12
+ end
13
+
14
+ it ".regexp has a regexp for the to_s" do
15
+ described_class.regexp.should == Helpers::UUID.regexp
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,217 @@
1
+ require 'spec_helper'
2
+
3
+ module Dbd
4
+ describe Fact do
5
+ let(:provenance_subject) { ProvenanceFact.new_subject }
6
+ let(:subject) { described_class.new_subject }
7
+ let(:data_predicate) { "http://example.org/test/name" }
8
+ let(:string_object_1) { "Gandhi" }
9
+ let(:string_object_2) { "Mandela" }
10
+ let(:id_class) { Fact::ID }
11
+ let(:subject_class) { Fact::Subject }
12
+ let(:fact_1) { Factories::Fact.fact_1(provenance_subject) }
13
+ let(:fact_2_with_subject) { Factories::Fact.fact_2_with_subject(provenance_subject) }
14
+
15
+ describe ".new_subject" do
16
+ it "creates a new (random) subject" do
17
+ described_class.new_subject.should be_a(subject_class)
18
+ end
19
+
20
+ it "creating a second one is different" do
21
+ subject_1 = described_class.new_subject
22
+ subject_2 = described_class.new_subject
23
+ subject_1.should_not == subject_2
24
+ end
25
+ end
26
+
27
+ describe "create a fact" do
28
+ it "has a unique id (id_class)" do
29
+ fact_1.id.should be_a(id_class)
30
+ end
31
+
32
+ it "two facts have different id" do
33
+ fact_1.id.should_not == fact_2_with_subject.id
34
+ end
35
+
36
+ it "new sets the provenance_subject" do
37
+ fact_1.provenance_subject.should == provenance_subject
38
+ end
39
+
40
+ it "new sets the subject" do
41
+ fact_2_with_subject.subject.should be_a(subject_class)
42
+ end
43
+
44
+ it "a nil predicate raises PredicateError" do
45
+ lambda do
46
+ described_class.new(
47
+ predicate: nil,
48
+ object: string_object_1)
49
+ end . should raise_error PredicateError
50
+ end
51
+
52
+ it "a nil object raises ObjectError" do
53
+ lambda do
54
+ described_class.new(
55
+ predicate: data_predicate,
56
+ object: nil)
57
+ end . should raise_error ObjectError
58
+ end
59
+ end
60
+
61
+ describe "time_stamp" do
62
+ it "can be set after creation" do
63
+ fact_1.time_stamp = Time.now
64
+ end
65
+
66
+ it "can be read back" do
67
+ time_now = Time.now
68
+ fact_1.time_stamp = time_now
69
+ fact_1.time_stamp.should == time_now
70
+ end
71
+
72
+ it "sees a difference of 2 nanoseconds" do
73
+ time_now = Time.now
74
+ fact_1.time_stamp = time_now + 0.000_000_002
75
+ fact_1.time_stamp.should > time_now
76
+ end
77
+
78
+ it "raise a RuntimeError if trying to write it 2 times" do
79
+ time_now = Time.now
80
+ fact_1.time_stamp = time_now
81
+ lambda { fact_1.time_stamp = time_now } . should raise_error RuntimeError
82
+ end
83
+ end
84
+
85
+ describe "valid?" do
86
+ it "the factory is valid?" do
87
+ fact_2_with_subject.should be_valid
88
+ end
89
+
90
+ it "without provenance_subject is not valid?" do
91
+ fact_2_with_subject.stub(:provenance_subject).and_return(nil)
92
+ fact_2_with_subject.should_not be_valid
93
+ end
94
+
95
+ it "without subject is not valid?" do
96
+ fact_2_with_subject.stub(:subject).and_return(nil)
97
+ fact_2_with_subject.should_not be_valid
98
+ end
99
+ end
100
+
101
+ describe "create fact_1" do
102
+ describe "with a string object type" do
103
+ it "new sets the predicate" do
104
+ fact_1.predicate.should == data_predicate
105
+ end
106
+
107
+ it "new sets the object" do
108
+ fact_1.object.should == string_object_1
109
+ end
110
+ end
111
+ end
112
+
113
+ describe "attributes and values" do
114
+ it "there are 6 attributes" do
115
+ described_class.attributes.size.should == 6
116
+ end
117
+
118
+ it "first attribute is :id" do
119
+ described_class.attributes.first.should == :id
120
+ end
121
+
122
+ it "there are 6 values" do
123
+ fact_1.values.size.should == 6
124
+ end
125
+ end
126
+
127
+ describe "#dup_with_subject" do
128
+
129
+ let (:new_fact) do
130
+ fact_1.dup_with_subject(subject)
131
+ end
132
+
133
+ it "is a different instance" do
134
+ new_fact.should_not be_equal(fact_1)
135
+ end
136
+
137
+ it "is from the same class" do
138
+ new_fact.should be_a(fact_1.class)
139
+ end
140
+
141
+ it "has copied over the other attributes except :id, :time_stamp" do
142
+ (fact_1.class.attributes - [:id, :time_stamp, :subject]).each do |attr|
143
+ new_fact.send(attr).should == fact_1.send(attr)
144
+ end
145
+ end
146
+
147
+ it "has set the subject to the Resource subject" do
148
+ fact_1.subject.should_not == new_fact.subject # double check
149
+ new_fact.subject.should == subject
150
+ end
151
+ end
152
+
153
+ describe "update_used_provenance_subjects" do
154
+ it "sets the value for provenance_subject to true for a fact" do
155
+ h = {}
156
+ fact_1.update_used_provenance_subjects(h)
157
+ h[fact_1.provenance_subject].should == true
158
+ end
159
+ end
160
+
161
+ describe "factory works" do
162
+ it "with explicit provenance_subject" do
163
+ fact_2_with_subject.provenance_subject.should be_a(provenance_subject.class)
164
+ fact_2_with_subject.subject.should be_a(subject.class)
165
+ fact_2_with_subject.predicate.should be_a(data_predicate.class)
166
+ fact_2_with_subject.object.should be_a(string_object_1.class)
167
+ end
168
+
169
+ it "without explicit provenance_subject" do
170
+ Factories::Fact.fact_1.provenance_subject.should be_nil
171
+ end
172
+
173
+ it "fact_2_with_subject should not raise_error" do
174
+ Factories::Fact.fact_2_with_subject
175
+ end
176
+
177
+ it "fact_3_with_subject should not raise_error" do
178
+ Factories::Fact.fact_3_with_subject
179
+ end
180
+
181
+ describe "data_fact" do
182
+ describe "without arguments" do
183
+ it "has empty provenance_subject" do
184
+ Factories::Fact.data_fact.provenance_subject.should be_nil
185
+ end
186
+
187
+ it "has empty subject" do
188
+ Factories::Fact.data_fact.subject.should be_nil
189
+ end
190
+ end
191
+
192
+ describe "with provenance_subject" do
193
+ it "has provenance_subject" do
194
+ Factories::Fact.data_fact(provenance_subject).
195
+ provenance_subject.should == provenance_subject
196
+ end
197
+
198
+ it "has empty subject" do
199
+ Factories::Fact.data_fact(provenance_subject).subject.should be_nil
200
+ end
201
+ end
202
+
203
+ describe "with provenance_subject and subject" do
204
+ it "has provenance_subject" do
205
+ Factories::Fact.data_fact(provenance_subject, subject).
206
+ provenance_subject.should == provenance_subject
207
+ end
208
+
209
+ it "has subject" do
210
+ Factories::Fact.data_fact(provenance_subject, subject).
211
+ subject.should == subject
212
+ end
213
+ end
214
+ end
215
+ end
216
+ end
217
+ end