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,214 @@
1
+ require 'spec_helper'
2
+
3
+ module Dbd
4
+ describe Graph do
5
+
6
+ def new_subject
7
+ Fact.new_subject
8
+ end
9
+
10
+ let(:data_fact) { Factories::Fact.data_fact(new_subject, new_subject) }
11
+ let(:fact_no_subject) { Factories::Fact.data_fact(new_subject, nil) }
12
+ let(:fact_no_provenance) { Factories::Fact.data_fact(nil, new_subject) }
13
+
14
+ let(:provenance_facts) { Factories::Fact::Collection.provenance_facts(new_subject) }
15
+ let(:provenance_fact_1) { provenance_facts.first }
16
+ let(:fact_2_3) { Factories::Fact::Collection.fact_2_3(provenance_fact_1.subject) }
17
+
18
+ let(:subject_regexp) { Fact::Subject.regexp }
19
+ let(:id_regexp) { Fact::ID.regexp }
20
+
21
+ describe "create a graph" do
22
+ it "does not fail" do
23
+ described_class.new # should_not raise_error
24
+ end
25
+ end
26
+
27
+ describe "<< " do
28
+ describe "a Fact" do
29
+ it "a data_fact does not fail" do
30
+ subject << data_fact
31
+ end
32
+
33
+ it "a provenance_fact does not fail" do
34
+ subject << provenance_fact_1
35
+ end
36
+
37
+ it "two facts does not fail" do
38
+ subject << provenance_fact_1
39
+ subject << data_fact
40
+ end
41
+
42
+ it "fact with missing subject raises FactError" do
43
+ lambda { subject << fact_no_subject } . should raise_error FactError
44
+ end
45
+
46
+ it "fact with missing provenance raises FactError" do
47
+ lambda { subject << fact_no_provenance } . should raise_error FactError
48
+ end
49
+ end
50
+
51
+ describe "sets the time_stamp and adds 2 nanoseconds if needed" do
52
+ it "sets the time_stamp" do
53
+ data_fact.time_stamp.should be_nil # assert pre condition
54
+ subject << data_fact
55
+ subject.first.time_stamp.should be_a(Time)
56
+ end
57
+
58
+ it "sets a slightly higher time_stamp if smaller or equal then newest_time_stamp" do
59
+ subject
60
+ subject.newest_time_stamp
61
+ far_future = Time.new(2200,1,1,12,0,0).utc
62
+ subject.stub(:newest_time_stamp).and_return(far_future)
63
+ subject << data_fact
64
+ subject.first.time_stamp.should > far_future
65
+ subject.first.time_stamp.should < far_future + 0.000_000_005
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "#to_CSV with only provenance_facts" do
71
+ before do
72
+ provenance_facts.each_with_index do |provenance_fact, index|
73
+ subject << provenance_fact
74
+ end
75
+ end
76
+
77
+ it "returns a string" do
78
+ subject.to_CSV.should be_a(String)
79
+ end
80
+
81
+ it "returns a string in UTF-8 encoding" do
82
+ subject.to_CSV.encoding.should == Encoding::UTF_8
83
+ end
84
+
85
+ it "returns a string with comma's" do
86
+ subject.to_CSV.should match(/\A"[^",]+","[^",]+","[^",]*","[^",]+"/)
87
+ end
88
+
89
+ describe "with a single provenance_fact collection" do
90
+ it "has three logical lines (but one with embedded newline)" do
91
+ subject.to_CSV.lines.count.should == 4
92
+ end
93
+
94
+ it "ends with a newline" do
95
+ subject.to_CSV.lines.to_a.last[-1].should == "\n"
96
+ end
97
+ end
98
+
99
+ describe "has all attributes of the provenance_fact_collection" do
100
+
101
+ let(:first_line) do
102
+ subject.to_CSV.lines.to_a.first.chomp
103
+ end
104
+
105
+ it "has id (a Fact::ID) as first value" do
106
+ first_line.split(',')[0].gsub(/"/, '').should match(id_regexp)
107
+ end
108
+
109
+ it "has time_stamp as second value" do
110
+ first_line.split(',')[1].should match(/"\d{4}-\d\d-\d\d \d\d:\d\d:\d\d UTC"/)
111
+ end
112
+
113
+ it "has an empty third value (signature of a provenance_fact)" do
114
+ first_line.split(',')[2].should == "\"\""
115
+ end
116
+
117
+ it "has subject as 4th value" do
118
+ first_line.split(',')[3].gsub(/"/, '').should match(subject_regexp)
119
+ end
120
+
121
+ it "has data_predicate as 5th value" do
122
+ first_line.split(',')[4].should == '"https://data.vandenabeele.com/ontologies/provenance#context"'
123
+ end
124
+
125
+ it "has object as 6th value" do
126
+ first_line.split(',')[5].should == '"public"'
127
+ end
128
+ end
129
+
130
+ describe "handles comma, double quote and newline correctly" do
131
+ it "has original_source with special characters and double quote escaped" do
132
+ subject.to_CSV.should match(/"this has a comma , a newline \n and a double quote """/)
133
+ end
134
+ end
135
+ end
136
+
137
+ describe "#to_CSV with only facts" do
138
+ before do
139
+ fact_2_3.each_with_index do |fact, index|
140
+ subject << fact
141
+ end
142
+ end
143
+
144
+ it "returns a string" do
145
+ subject.to_CSV.should be_a(String)
146
+ end
147
+
148
+ it "returns a string in UTF-8 encoding" do
149
+ subject.to_CSV.encoding.should == Encoding::UTF_8
150
+ end
151
+
152
+ it "returns a string with comma's" do
153
+ subject.to_CSV.should match(/\A"[^",]+","[^",]+","[^",]+"/)
154
+ end
155
+
156
+ describe "with a single fact collection" do
157
+ it "has two lines" do
158
+ subject.to_CSV.lines.count.should == 2
159
+ end
160
+
161
+ it "ends with a newline" do
162
+ subject.to_CSV.lines.to_a.last[-1].should == "\n"
163
+ end
164
+ end
165
+
166
+ describe "has all attributes of the fact_collection" do
167
+
168
+ let(:first_line) do
169
+ subject.to_CSV.lines.to_a.first.chomp
170
+ end
171
+
172
+ it "has id (a Fact::ID) as first value" do
173
+ first_line.split(',')[0].gsub(/"/, '').should match(id_regexp)
174
+ end
175
+
176
+ it "has time_stamp as second value" do
177
+ first_line.split(',')[1].should match(/"\d{4}-\d\d-\d\d \d\d:\d\d:\d\d UTC"/)
178
+ end
179
+
180
+ it "has provenance_fact_1.subject as third value" do
181
+ first_line.split(',')[2].should == "\"#{provenance_fact_1.subject.to_s}\""
182
+ end
183
+
184
+ it "has subject as 4th value" do
185
+ first_line.split(',')[3].gsub(/"/, '').should match(subject_regexp)
186
+ end
187
+
188
+ it "has data_predicate as 5th value" do
189
+ first_line.split(',')[4].should == '"http://example.org/test/name"'
190
+ end
191
+
192
+ it "has object as 6th value" do
193
+ first_line.split(',')[5].should == '"Mandela"'
194
+ end
195
+ end
196
+ end
197
+
198
+ describe "#to_CSV with provenance_facts and facts" do
199
+
200
+ before do
201
+ provenance_facts.each do |provenance_fact|
202
+ subject << provenance_fact
203
+ end
204
+ fact_2_3.each do |fact|
205
+ subject << fact
206
+ end
207
+ end
208
+
209
+ it "has six lines" do
210
+ subject.to_CSV.lines.count.should == 6
211
+ end
212
+ end
213
+ end
214
+ end
@@ -0,0 +1,88 @@
1
+ require 'spec_helper'
2
+
3
+ module Dbd
4
+ module Helpers
5
+ describe OrderedSetCollection do
6
+
7
+ let(:element_1) {:element_1}
8
+ let(:element_2) {:element_2}
9
+ let(:subject) do
10
+ o = Object.new
11
+ o.extend(described_class)
12
+ o.send(:initialize)
13
+ o
14
+ end
15
+
16
+ describe "create an elements collection" do
17
+ it "the collection is not an array" do
18
+ # do not derive from Ruby standard classes
19
+ subject.should_not be_a(Array)
20
+ end
21
+ end
22
+
23
+ describe "accessor functions" do
24
+ it "the collection has Enumerable methods" do
25
+ subject.map #should_not raise_exception
26
+ subject.first #should_not raise_exception
27
+ end
28
+
29
+ it "<< adds the element" do
30
+ subject << element_1
31
+ subject.count.should == 1
32
+ end
33
+
34
+ it "returns self to allow chaining" do
35
+ (subject << element_1).should == subject
36
+ end
37
+
38
+ it "other functions (e.g. pop) do not work" do
39
+ lambda {subject.pop} . should raise_exception NoMethodError
40
+ end
41
+
42
+ describe "add_and_return_index returns the index of the inserted element" do
43
+
44
+ let(:internal_collection) do
45
+ subject.instance_variable_get("@internal_collection")
46
+ end
47
+
48
+ let(:index) do
49
+ described_class.add_and_return_index(element_1, internal_collection)
50
+ end
51
+
52
+ before(:each) { index }
53
+
54
+ it "works for 1 element" do
55
+ index.should == 0
56
+ end
57
+
58
+ it "works for 2 elements" do
59
+ index_2 = described_class.add_and_return_index(element_2, internal_collection)
60
+ index_2.should == 1
61
+ end
62
+ end
63
+
64
+ describe "last" do
65
+ it "returns the last element" do
66
+ subject << element_1
67
+ subject << element_2
68
+ subject.last.should == element_2
69
+ end
70
+ end
71
+
72
+ describe "size" do
73
+ it "returns the last element" do
74
+ subject << element_1
75
+ subject << element_2
76
+ subject.size.should == 2
77
+ end
78
+ end
79
+ end
80
+
81
+ describe "on empty collection" do
82
+ it "#last returns nil" do
83
+ subject.last.should be_nil
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ module Dbd
4
+ module Helpers
5
+ describe UUID do
6
+ it ".regex" do
7
+ '12345678-abcd-4567-89ab-0123456789ab'.should match(UUID.regexp)
8
+ end
9
+
10
+ it ".new creates a new random UUID" do
11
+ described_class.new.to_s.should match(UUID.regexp)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ module Dbd
4
+ describe ProvenanceFact do
5
+
6
+ let(:subject) { described_class.new_subject }
7
+ let(:id_class) { described_class.new_id.class }
8
+
9
+ let(:provenance_fact_1) do
10
+ Factories::ProvenanceFact.context(subject)
11
+ end
12
+
13
+ let(:provenance_fact_2) do
14
+ Factories::ProvenanceFact.created_by(subject)
15
+ end
16
+
17
+ describe "#new" do
18
+ it "has a unique id (new_id.class)" do
19
+ provenance_fact_1.id.should be_a(id_class)
20
+ end
21
+
22
+ it "two provenance_facts have different id" do
23
+ provenance_fact_1.id.should_not == provenance_fact_2.id
24
+ end
25
+
26
+ it "has nil provenance_subject" do
27
+ provenance_fact_1.provenance_subject.should be_nil
28
+ end
29
+
30
+ it "has correct subject" do
31
+ provenance_fact_1.subject.should == subject
32
+ end
33
+
34
+ it "has correct predicate" do
35
+ provenance_fact_1.predicate.should == "https://data.vandenabeele.com/ontologies/provenance#context"
36
+ end
37
+
38
+ it "has correct object" do
39
+ provenance_fact_1.object.should == "public"
40
+ end
41
+
42
+ it "raises an ProvenanceError when provenance_subject is present in options hash" do
43
+ lambda { described_class.new(
44
+ provenance_subject: described_class.new_subject,
45
+ predicate: "test",
46
+ object: "test") } .
47
+ should raise_error ProvenanceError
48
+ end
49
+ end
50
+
51
+ describe "valid?" do
52
+ it "the factory isi valid?" do
53
+ provenance_fact_1.should be_valid
54
+ end
55
+
56
+ it "with ! provenance_subject is not valid?" do
57
+ provenance_fact_1.stub(:provenance_subject).and_return(subject)
58
+ provenance_fact_1.should_not be_valid
59
+ end
60
+
61
+ it "without subject is not valid?" do
62
+ provenance_fact_1.stub(:subject).and_return(nil)
63
+ provenance_fact_1.should_not be_valid
64
+ end
65
+ end
66
+
67
+ describe "#dup_with_subject" do
68
+
69
+ let (:new_fact) do
70
+ provenance_fact_1.dup_with_subject(subject)
71
+ end
72
+
73
+ it "is a different instance" do
74
+ new_fact.should_not be_equal(provenance_fact_1)
75
+ end
76
+
77
+ it "is from the same class" do
78
+ new_fact.should be_a(provenance_fact_1.class)
79
+ end
80
+ end
81
+
82
+ describe "update_used_provenance_subjects" do
83
+ it "does nothing for a provenance_fact" do
84
+ h = {}
85
+ provenance_fact_1.update_used_provenance_subjects(h)
86
+ h.should be_empty
87
+ end
88
+ end
89
+
90
+ describe "Factories do not fail" do
91
+ it "Factories::ProvenanceFact.context is OK" do
92
+ Factories::ProvenanceFact.context.should_not be_nil
93
+ end
94
+
95
+ it "Factories::ProvenanceFact.created_by is OK" do
96
+ Factories::ProvenanceFact.created_by.should_not be_nil
97
+ end
98
+
99
+ it "Factories::ProvenanceFact.original_source is OK" do
100
+ Factories::ProvenanceFact.original_source.should_not be_nil
101
+ end
102
+
103
+ it "Factories::ProvenanceFact.new_subject is OK" do
104
+ Factories::ProvenanceFact.new_subject.should be_a(ProvenanceFact.new_subject.class)
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ module Dbd
4
+ describe ProvenanceResource do
5
+
6
+ let(:provenance_resource) { described_class.new }
7
+ let(:provenance_resource_subject) { provenance_resource.subject }
8
+
9
+ describe ".new" do
10
+ describe "without a subject argument" do
11
+ it "has created a new subject" do
12
+ provenance_resource.subject.should be_a(described_class.new_subject.class)
13
+ end
14
+ end
15
+
16
+ describe "with a subject argument" do
17
+ it "has stored the resource_subject" do
18
+ described_class.new(subject: provenance_resource_subject).subject.should == provenance_resource_subject
19
+ end
20
+ end
21
+
22
+ describe "with a provenance_subject argument" do
23
+ it "raises an ProvenanceError" do
24
+ lambda { described_class.new(provenance_subject: provenance_resource_subject) } .
25
+ should raise_error ProvenanceError
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "provenance_subject" do
31
+ it "raises NoMethodError when called" do
32
+ lambda { provenance_resource.provenance_subject } . should raise_error NoMethodError
33
+ end
34
+ end
35
+
36
+ describe "Factories::Resource" do
37
+ it ".provenance_resource works" do
38
+ Factories::ProvenanceResource.provenance_resource
39
+ end
40
+ end
41
+
42
+ describe "the collection" do
43
+
44
+ let(:provenance_fact_context) { Factories::ProvenanceFact.context }
45
+ let(:provenance_fact_context_with_incorrect_subject) { Factories::ProvenanceFact.context(Factories::ProvenanceFact.new_subject) }
46
+ let(:provenance_fact_context_with_correct_subject) { Factories::ProvenanceFact.context(provenance_resource_subject) }
47
+ let(:fact_1) { Factories::Fact.fact_1(provenance_resource_subject) }
48
+
49
+ describe "data facts" do
50
+ it "with correct subject" do
51
+ provenance_resource << provenance_fact_context_with_correct_subject
52
+ provenance_resource.first.subject.should == provenance_resource_subject
53
+ end
54
+
55
+ it "with incorrect subject it raise SubjectError" do
56
+ lambda { provenance_resource << provenance_fact_context_with_incorrect_subject } .
57
+ should raise_error SubjectError
58
+ end
59
+
60
+ it "with nil subject" do
61
+ provenance_resource << provenance_fact_context
62
+ provenance_resource.first.subject.should == provenance_resource_subject
63
+ end
64
+
65
+ it "with nil (=correct) provenance_subject" do
66
+ provenance_resource << provenance_fact_context
67
+ provenance_resource.first.provenance_subject.should be_nil
68
+ end
69
+
70
+ it "with incorrect provenance_subjecti ProvenanceError" do
71
+ lambda { provenance_resource << fact_1 } .
72
+ should raise_error ProvenanceError
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end