dbd 0.0.1

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.
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