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