dbd 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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