dbd 0.0.5 → 0.0.6

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Guardfile +3 -2
  3. data/HISTORY.txt +5 -0
  4. data/dbd.gemspec +1 -1
  5. data/docs/stories/013_read_graph_from_CSV.txt +10 -0
  6. data/lib/dbd.rb +1 -1
  7. data/lib/dbd/fact.rb +23 -1
  8. data/lib/dbd/fact/id.rb +3 -3
  9. data/lib/dbd/fact/subject.rb +3 -3
  10. data/lib/dbd/graph.rb +25 -4
  11. data/lib/dbd/provenance_fact.rb +5 -8
  12. data/lib/dbd/provenance_resource.rb +21 -13
  13. data/lib/dbd/{rdf.rb → rdf_base.rb} +0 -0
  14. data/lib/dbd/resource.rb +25 -23
  15. data/lib/dbd/time_stamp.rb +13 -2
  16. data/lib/dbd/version.rb +1 -1
  17. data/spec/factories/fact.rb +23 -0
  18. data/spec/factories/fact/id.rb +14 -0
  19. data/spec/factories/fact/subject.rb +18 -0
  20. data/spec/factories/graph.rb +23 -0
  21. data/spec/factories/provenance_resource.rb +3 -3
  22. data/spec/factories/time_stamp.rb +12 -0
  23. data/spec/lib/dbd/fact/{collection_spec.rb → collection/collection_spec.rb} +0 -0
  24. data/spec/lib/dbd/fact/factory_spec.rb +82 -0
  25. data/spec/lib/dbd/fact/id/factory_spec.rb +20 -0
  26. data/spec/lib/dbd/fact/id/id_spec.rb +27 -0
  27. data/spec/lib/dbd/fact/methods_spec.rb +117 -0
  28. data/spec/lib/dbd/fact/new_spec.rb +91 -0
  29. data/spec/lib/dbd/fact/subject/factory_spec.rb +33 -0
  30. data/spec/lib/dbd/fact/subject/subject_spec.rb +27 -0
  31. data/spec/lib/dbd/graph/add_to_graph_spec.rb +139 -0
  32. data/spec/lib/dbd/graph/factory_spec.rb +33 -0
  33. data/spec/lib/dbd/graph/from_csv_spec.rb +29 -0
  34. data/spec/lib/dbd/{graph_spec.rb → graph/to_csv_spec.rb} +0 -120
  35. data/spec/lib/dbd/helpers/{ordered_set_collection_spec.rb → ordered_set_collection/ordered_set_collection_spec.rb} +0 -0
  36. data/spec/lib/dbd/helpers/{uuid_spec.rb → uuid/uuid_spec.rb} +0 -0
  37. data/spec/lib/dbd/performance_spec.rb +3 -1
  38. data/spec/lib/dbd/provenance_fact/factory_spec.rb +24 -0
  39. data/spec/lib/dbd/provenance_fact/methods_spec.rb +78 -0
  40. data/spec/lib/dbd/provenance_fact/new_spec.rb +51 -0
  41. data/spec/lib/dbd/{provenance_resource_spec.rb → provenance_resource/provenance_resource_spec.rb} +6 -10
  42. data/spec/lib/dbd/{rdf_base_spec.rb → rdf_base/rdf_base_spec.rb} +0 -0
  43. data/spec/lib/dbd/{resource_spec.rb → resource/collection_spec.rb} +8 -47
  44. data/spec/lib/dbd/resource/factory_spec.rb +14 -0
  45. data/spec/lib/dbd/resource/new_spec.rb +44 -0
  46. data/spec/lib/dbd/time_stamp/comparisons_spec.rb +64 -0
  47. data/spec/lib/dbd/time_stamp/factory_spec.rb +17 -0
  48. data/spec/lib/dbd/time_stamp/methods_spec.rb +37 -0
  49. data/spec/lib/dbd/time_stamp/new_spec.rb +38 -0
  50. metadata +66 -29
  51. data/spec/lib/dbd/fact/id_spec.rb +0 -19
  52. data/spec/lib/dbd/fact/subject_spec.rb +0 -19
  53. data/spec/lib/dbd/fact_spec.rb +0 -216
  54. data/spec/lib/dbd/provenance_fact_spec.rb +0 -120
  55. data/spec/lib/dbd/time_stamp_spec.rb +0 -115
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9ad1bee3c2518a24358318cfda3b6931321911a2
4
- data.tar.gz: 2b7ffc84e350ce65c526e8cfc2246713e02cd7a6
3
+ metadata.gz: cc144cf2ae12eb90508d2da68006a9cc5ac247dd
4
+ data.tar.gz: 7bac3b578951f4a3a610aa988d5f06c180095368
5
5
  SHA512:
6
- metadata.gz: a2b09154cd4c1482f08d7233964343c9b02ac70293358e9928b6b46fe30f04650b1a118506ab0fe98d6ce8a46143563ac5f09a0e3233f5c3196ab95b26e97b81
7
- data.tar.gz: a25149c6e0288ce1cd9ae0f7f769fbcd067b5db6dfc52b8128cd4f6d53cfd31c1e607e62e2ef020735cef027447de56711f754bcfcf8cef55005d241ae7e2ca6
6
+ metadata.gz: 0e0f6fa90ad08943e62780b350a058e4d27286eb0396e3524222cd4d488ca81ac3764b58076bdb5331a91cd851fa710440a3e1b7060e81d2734c2f069f56a8ed
7
+ data.tar.gz: fb95d9bb0d1ecb5f13d297fa69ab01d661e460653d80333967583c46e843412ea46324fa025330d59f1dfcbf19c4dd5fa53a51099fe39db9d972a0e5339b1595
data/Guardfile CHANGED
@@ -1,8 +1,9 @@
1
1
  guard 'rspec' do
2
2
  watch(%r{^spec/.+_spec\.rb$})
3
3
  watch(%r{^spec/factories}) { "spec" }
4
- watch(%r{^lib/dbd/helpers}) { "spec" }
5
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
4
+ watch(%r{^lib/dbd/helpers}) { "spec" }
5
+ # watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}/" }
6
7
  watch('spec/spec_helper.rb') { "spec" }
7
8
  watch('lib/dbd.rb') { "spec" }
8
9
  end
@@ -27,3 +27,8 @@
27
27
  =====
28
28
 
29
29
  * use ruby_peter_v 0.0.8 which does not have max_with_nil
30
+
31
+ 0.0.6 (17 June 2013)
32
+ =====
33
+
34
+ * Fact.from_CSV reads from a CSV stream (file or stringIO)
@@ -26,5 +26,5 @@ Gem::Specification.new do |spec|
26
26
  spec.add_development_dependency 'yard'
27
27
  spec.add_runtime_dependency 'neography'
28
28
  spec.add_runtime_dependency 'rdf', '~> 1.0.6'
29
- spec.add_runtime_dependency 'ruby_peter_v', '>= 0.0.8'
29
+ spec.add_runtime_dependency 'ruby_peter_v', '>= 0.0.9'
30
30
  end
@@ -0,0 +1,10 @@
1
+ 013_read_graph_from_CSV
2
+
3
+ As a client
4
+ I can read a graph from a CSV file
5
+
6
+ * read a CSV file
7
+ * with some special characters
8
+ * with comma, new line and escape double quote
9
+ * without double quotes
10
+ * checks that each Fact has 6 valid fields
data/lib/dbd.rb CHANGED
@@ -10,5 +10,5 @@ require 'dbd/resource'
10
10
  require 'dbd/provenance_resource'
11
11
  require 'dbd/graph'
12
12
 
13
- require 'dbd/rdf'
13
+ require 'dbd/rdf_base'
14
14
  require 'dbd/repo'
@@ -123,8 +123,11 @@ module Dbd
123
123
  # @option options [#to_s] :object Required : the object for this Fact (required)
124
124
  # @option options [Subject] :provenance_subject (nil) Optional: the subject of the provenance(resource|fact)
125
125
  # @option options [Subject] :subject (nil) Optional: the subject for this Fact
126
+ # @option options [TimeStamp] :time_stamp (nil) Optional: the time_stamp for this Fact
127
+ # @option options [ID] :id Optional : set the id
126
128
  def initialize(options)
127
- @id = self.class.new_id
129
+ @id = options[:id] || self.class.new_id
130
+ @time_stamp = options[:time_stamp]
128
131
  @provenance_subject = options[:provenance_subject]
129
132
  @subject = options[:subject]
130
133
  @predicate = options[:predicate]
@@ -139,6 +142,16 @@ module Dbd
139
142
  self.class.attributes.map{ |attribute| self.send(attribute) }
140
143
  end
141
144
 
145
+ ##
146
+ # Constructs a Fact from a values array
147
+ # (e.g. pulled from a CSV row).
148
+ #
149
+ # @param [Array] values Required : the array with values, organized as in attributes
150
+ # @return [Fact] the constructed fact
151
+ def self.from_values(values)
152
+ new(Hash[[self.attributes, values].transpose])
153
+ end
154
+
142
155
  ##
143
156
  # @return [String] a short string representation of a Fact
144
157
  def short
@@ -190,6 +203,15 @@ module Dbd
190
203
  "Provenance subject is missing" unless provenance_subject
191
204
  end
192
205
 
206
+ ##
207
+ # Confirms this is not a ProvenanceFact
208
+ #
209
+ # Needed for validations that depend on different behavior for
210
+ # a provenance_fact (mainly, no provenance_subject).
211
+ def provenance_fact?
212
+ false
213
+ end
214
+
193
215
  private
194
216
 
195
217
  def provenance_subject_short
@@ -2,12 +2,12 @@ module Dbd
2
2
  class Fact
3
3
  class ID
4
4
 
5
- def initialize
6
- @uuid = Helpers::UUID.new
5
+ def initialize(options = {})
6
+ @uuid = options[:uuid] || Helpers::UUID.new.to_s
7
7
  end
8
8
 
9
9
  def to_s
10
- @uuid.to_s
10
+ @uuid
11
11
  end
12
12
 
13
13
  def self.regexp
@@ -4,12 +4,12 @@ module Dbd
4
4
  class Fact
5
5
  class Subject
6
6
 
7
- def initialize
8
- @uuid = Helpers::UUID.new
7
+ def initialize(options = {})
8
+ @uuid = options[:uuid] || Helpers::UUID.new.to_s
9
9
  end
10
10
 
11
11
  def to_s
12
- @uuid.to_s
12
+ @uuid
13
13
  end
14
14
 
15
15
  def self.regexp
@@ -5,19 +5,26 @@ module Dbd
5
5
  ##
6
6
  # The Graph stores the Facts and ProvenanceFacts in an in-memory
7
7
  # collection structure.
8
+ #
9
+ # On the other hand, it acts as an "interface" that can be
10
+ # re-implemented by other persistence mechanisms (duck typing).
8
11
  class Graph
9
12
 
10
13
  include Fact::Collection
11
14
 
12
15
  ##
13
- # Add a Fact or Resource or any set recursively.
16
+ # Add a Fact, Resource or other recursive collection of facts.
14
17
  #
15
- # This will add a time_stamp to the Facts.
16
- def <<(recursive_fact_collection)
17
- recursive_fact_collection.each_recursively do |fact|
18
+ # Side effect: this will set the time_stamp of the facts.
19
+ #
20
+ # @param [#time_stamp, #time_stamp=, #each] fact_collection a recursive collection of facts
21
+ # @return [Graph] self
22
+ def <<(fact_collection)
23
+ fact_collection.each_recursively do |fact|
18
24
  enforce_strictly_monotonic_time(fact)
19
25
  super(fact)
20
26
  end
27
+ self
21
28
  end
22
29
 
23
30
  ##
@@ -32,6 +39,20 @@ module Dbd
32
39
  end.encode("utf-8")
33
40
  end
34
41
 
42
+ ##
43
+ # Import a graph from a CSV string.
44
+ #
45
+ # @param [String] csv a string that contains the CSV serialization
46
+ # @return [Graph] the imported graph
47
+ def self.from_CSV(csv)
48
+ Graph.new.tap do |graph|
49
+ CSV.new(csv).each do |row|
50
+ # TODO validate the input formats (e.g. invalid uuid codes)
51
+ graph << Fact.from_values(row)
52
+ end
53
+ end
54
+ end
55
+
35
56
  private
36
57
 
37
58
  ##
@@ -53,15 +53,12 @@ module Dbd
53
53
  end
54
54
 
55
55
  ##
56
- # Builds duplicate with the subject set.
56
+ # Confirms this is a ProvenanceFact
57
57
  #
58
- # @param [Subject] subject_arg
59
- # @return [ProvenanceFact] the duplicate fact
60
- def dup_with_subject(subject_arg)
61
- self.class.new(
62
- subject: subject_arg, # from arg
63
- predicate: predicate,
64
- object: object)
58
+ # Needed for validations that depend on different behavior for
59
+ # a provenance_fact (mainly, no provenance_subject).
60
+ def provenance_fact?
61
+ true
65
62
  end
66
63
 
67
64
  private
@@ -1,7 +1,9 @@
1
1
  module Dbd
2
2
  ##
3
3
  # A ProvenanceResource is derived from a Resource, specifically
4
- # for a Provenance (does not have and does need a provenance_subject)
4
+ # for a Provenance.
5
+ #
6
+ # The main difference is that it does not have a provenance_subject.
5
7
  class ProvenanceResource < Resource
6
8
 
7
9
  ##
@@ -17,38 +19,44 @@ module Dbd
17
19
  end
18
20
 
19
21
  ##
20
- # Add a ProvenanceFact.
22
+ # Add a ProvenanceFact (strictly only a ProvenanceFact).
21
23
  #
24
+ # Side effect on subject:
22
25
  # * if it has no subject, the subject is set in a duplicate provenance_fact
23
26
  # * if is has the same subject as the resource, added unchanged.
24
27
  # * if it has a different subject, a SubjectError is raised.
25
28
  def <<(provenance_fact)
26
- # TODO: check the type of the provenance_fact (ProvenanceFact)
27
29
  super
28
30
  end
29
31
 
30
32
  private
31
33
 
32
- ##
33
34
  # Should not be called in ProvenanceResource subclass.
34
35
  def provenance_subject
35
- raise RuntimeError, "provenance_subject should not be called in ProvenanceResource."
36
+ raise NoMethodError, "provenance_subject should not be called in ProvenanceResource."
36
37
  end
37
38
 
38
- ##
39
- # Validate that provenance_subject is not set here.
39
+ def set_provenance_subject(options)
40
+ raise ArgumentError, "provenance_subject must not be in the options" if options[:provenance_subject]
41
+ end
42
+
43
+ # Validate that provenance_subject is not present here.
44
+ # This should never raise as the setter was blocked above.
40
45
  def validate_provenance_subject
41
46
  raise ProvenanceError if @provenance_subject
42
47
  end
43
48
 
44
49
  ##
45
- # Check provenance_subject, which should be nil here
50
+ # Assert _only_ ProvenanceFacts here
51
+ def assert_fact_provenance_fact(fact)
52
+ raise ArgumentError, "Trying to add a non-ProvenanceFact to a ProvenanceResource." unless fact.provenance_fact?
53
+ end
54
+
55
+ ##
56
+ # A noop for ProvenanceResource.
46
57
  # @param [ProvenanceFact] provenance_fact
47
- def set_provenance!(provenance_fact)
48
- if provenance_fact.provenance_subject
49
- raise ProvenanceError,
50
- "trying to set provenance_subject to#{provenance_fact.provenance_subject}"
51
- end
58
+ def set_fact_provenance!(provenance_fact)
59
+ # Do nothing
52
60
  end
53
61
 
54
62
  end
File without changes
@@ -2,12 +2,12 @@ require 'dbd/helpers/ordered_set_collection'
2
2
 
3
3
  module Dbd
4
4
  ##
5
- # A Resource is a collection of facts that have the same subject.
5
+ # A Resource is a collection of Facts that have the same subject.
6
6
  #
7
7
  # In the real-world this is a mainly an "instance" about which all
8
8
  # facts are giving information (e.g. a conference, a person, a
9
9
  # bicycle, ...). More generally this can also be used to describe
10
- # classes and other concepts in the software system.
10
+ # classes and other concepts in the system.
11
11
  #
12
12
  # A new (random) subject is generated for a resource. In Dbd,
13
13
  # a subject is a random uuid (like a oid), not a meaningful URI
@@ -25,15 +25,7 @@ module Dbd
25
25
 
26
26
  include Helpers::OrderedSetCollection
27
27
 
28
- attr_reader :subject
29
-
30
- ##
31
- # Getter for provenance_subject.
32
- #
33
- # Will be overridden in the ProvenanceResource subclass.
34
- def provenance_subject
35
- @provenance_subject
36
- end
28
+ attr_reader :subject, :provenance_subject
37
29
 
38
30
  ##
39
31
  # @return [Fact::Subject] a new (random) Resource subject
@@ -51,19 +43,20 @@ module Dbd
51
43
  #
52
44
  # The provenance_subject argument is required. This will typically be
53
45
  # taken from an earlier created ProvenanceResource.
46
+ #
54
47
  # @param [Hash{Symbol => Object}] options
55
48
  # @option options [Fact::Subject] :provenance_subject (required) the subject of the provenance resource for this resource
56
49
  # @option options [Fact::Subject] :subject (new_subject) Optional: the subject for the resource
57
50
  def initialize(options)
58
- @subject = options[:subject] || self.class.new_subject
59
- @provenance_subject = options[:provenance_subject]
60
- validate_provenance_subject
51
+ set_subject(options)
52
+ set_provenance_subject(options)
61
53
  super()
62
54
  end
63
55
 
64
56
  ##
65
- # Add a fact.
57
+ # Add a Fact (strictly not a ProvenanceFact)
66
58
  #
59
+ # Side effects on subject and provenance_subject:
67
60
  # * if it has no subject, the subject is set (this modifies the fact !)
68
61
  # * if is has the same subject as the resource, added unchanged.
69
62
  # * if it has a different subject, a SubjectError is raised.
@@ -71,25 +64,34 @@ module Dbd
71
64
  # * if is has the same provenance_subject as the resource, added unchanged.
72
65
  # * if it has a different provenance_subject, a ProvenanceError is raised.
73
66
  def <<(fact)
74
- # TODO: check the type of the fact (Fact)
75
- set_subject!(fact)
76
- set_provenance!(fact)
67
+ assert_fact_provenance_fact(fact)
68
+ set_fact_subject!(fact)
69
+ set_fact_provenance!(fact)
77
70
  super(fact)
78
71
  end
79
72
 
80
73
  private
81
74
 
82
- def set_subject!(fact)
75
+ def set_subject(options)
76
+ @subject = options[:subject] || self.class.new_subject
77
+ end
78
+
79
+ def set_provenance_subject(options)
80
+ @provenance_subject = options[:provenance_subject]
81
+ raise ProvenanceError, "provenance_subject cannot be nil" if @provenance_subject.nil?
82
+ end
83
+
84
+ def set_fact_subject!(fact)
83
85
  fact.subject = subject
84
86
  end
85
87
 
86
- # this will be overriden in the ProvenanceResource sub_class
87
- def set_provenance!(fact)
88
+ def set_fact_provenance!(fact)
88
89
  fact.provenance_subject = provenance_subject
89
90
  end
90
91
 
91
- def validate_provenance_subject
92
- raise ProvenanceError if @provenance_subject.nil?
92
+ # Assert _no_ ProvenanceFacts here
93
+ def assert_fact_provenance_fact(fact)
94
+ raise ArgumentError, "Trying to add a ProvenanceFact to a Resource." if fact.provenance_fact?
93
95
  end
94
96
 
95
97
  end
@@ -66,12 +66,23 @@ module Dbd
66
66
  Rational("#{1+rand(999)}/1_000_000_000")
67
67
  end
68
68
 
69
+ def self.time_format
70
+ '%F %T.%N %Z'
71
+ end
72
+
69
73
  public
70
74
 
71
75
  ##
72
- # to a nanosecond granularity and in UTC
76
+ # with a nanosecond granularity and in UTC
73
77
  def to_s
74
- @time.strftime('%F %T.%N %Z')
78
+ @time.strftime(self.class.time_format)
79
+ end
80
+
81
+ ##
82
+ # with a nanosecond granularity and in UTC
83
+ def self.from_s(time_string)
84
+ date_time = DateTime.strptime(time_string, time_format)
85
+ TimeStamp.new(time: date_time.to_time.utc)
75
86
  end
76
87
 
77
88
  def >(other)
@@ -1,3 +1,3 @@
1
1
  module Dbd
2
- VERSION = "0.0.5"
2
+ VERSION = "0.0.6"
3
3
  end
@@ -16,6 +16,20 @@ module Factories
16
16
  object: "Gandhi")
17
17
  end
18
18
 
19
+ def self.fact_with_forced_id(forced_id)
20
+ factory_for.new(
21
+ id: forced_id,
22
+ predicate: "http://example.org/test/name",
23
+ object: "Gandhi")
24
+ end
25
+
26
+ def self.fact_with_time_stamp(time_stamp)
27
+ factory_for.new(
28
+ time_stamp: time_stamp,
29
+ predicate: "http://example.org/test/name",
30
+ object: "Gandhi")
31
+ end
32
+
19
33
  def self.fact_2_with_subject(provenance_subject = nil)
20
34
  factory_for.new(
21
35
  provenance_subject: provenance_subject,
@@ -56,6 +70,15 @@ module Factories
56
70
  object: "A long story\nreally.")
57
71
  end
58
72
 
73
+ def self.full_fact
74
+ fixed_id = Factories::Fact::ID.fixed_id
75
+ fact_with_forced_id(fixed_id).tap do |fact|
76
+ fact.time_stamp = Factories::TimeStamp.fixed_time_stamp
77
+ fact.subject = Factories::Fact::Subject.fixed_subject
78
+ fact.provenance_subject = Factories::Fact::Subject.fixed_provenance_subject
79
+ end
80
+ end
81
+
59
82
  module Collection
60
83
 
61
84
  def self.factory_for_instance