ld4l-ore_rdf 0.0.4

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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +25 -0
  4. data/.travis.yml +12 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE.txt +14 -0
  7. data/README.md +171 -0
  8. data/Rakefile +2 -0
  9. data/ld4l-ore_rdf.gemspec +45 -0
  10. data/lib/ld4l/ore_rdf/configuration.rb +41 -0
  11. data/lib/ld4l/ore_rdf/models/aggregation.rb +50 -0
  12. data/lib/ld4l/ore_rdf/models/aggregation_resource.rb +98 -0
  13. data/lib/ld4l/ore_rdf/models/proxy_resource.rb +54 -0
  14. data/lib/ld4l/ore_rdf/services/aggregation/add_aggregated_resource.rb +49 -0
  15. data/lib/ld4l/ore_rdf/services/aggregation/add_aggregated_resources.rb +28 -0
  16. data/lib/ld4l/ore_rdf/services/aggregation/create.rb +39 -0
  17. data/lib/ld4l/ore_rdf/services/aggregation/destroy.rb +47 -0
  18. data/lib/ld4l/ore_rdf/services/aggregation/destroy_with_id.rb +22 -0
  19. data/lib/ld4l/ore_rdf/services/aggregation/find.rb +72 -0
  20. data/lib/ld4l/ore_rdf/services/aggregation/persist.rb +34 -0
  21. data/lib/ld4l/ore_rdf/services/aggregation/resume.rb +30 -0
  22. data/lib/ld4l/ore_rdf/services/proxy/create.rb +64 -0
  23. data/lib/ld4l/ore_rdf/services/proxy/find.rb +93 -0
  24. data/lib/ld4l/ore_rdf/version.rb +5 -0
  25. data/lib/ld4l/ore_rdf/vocab/co.rb +27 -0
  26. data/lib/ld4l/ore_rdf/vocab/dcterms.rb +6 -0
  27. data/lib/ld4l/ore_rdf/vocab/iana.rb +9 -0
  28. data/lib/ld4l/ore_rdf/vocab/ore.rb +16 -0
  29. data/lib/ld4l/ore_rdf.rb +76 -0
  30. data/spec/ld4l/ore_rdf/configuration_spec.rb +174 -0
  31. data/spec/ld4l/ore_rdf/models/aggregation_resource_spec.rb +830 -0
  32. data/spec/ld4l/ore_rdf/models/aggregation_spec.rb +9 -0
  33. data/spec/ld4l/ore_rdf/models/proxy_resource_spec.rb +690 -0
  34. data/spec/ld4l/ore_rdf/services/aggregation/add_aggregated_resource_spec.rb +36 -0
  35. data/spec/ld4l/ore_rdf/services/aggregation/add_aggregated_resources_spec.rb +78 -0
  36. data/spec/ld4l/ore_rdf/services/aggregation/create_spec.rb +62 -0
  37. data/spec/ld4l/ore_rdf/services/aggregation/destroy_spec.rb +169 -0
  38. data/spec/ld4l/ore_rdf/services/aggregation/find_spec.rb +198 -0
  39. data/spec/ld4l/ore_rdf/services/aggregation/persist_spec.rb +13 -0
  40. data/spec/ld4l/ore_rdf/services/aggregation/resume_spec.rb +46 -0
  41. data/spec/ld4l/ore_rdf/services/proxy/create_spec.rb +143 -0
  42. data/spec/ld4l/ore_rdf/services/proxy/find_spec.rb +138 -0
  43. data/spec/ld4l/ore_rdf_spec.rb +53 -0
  44. data/spec/spec_helper.rb +23 -0
  45. metadata +259 -0
@@ -0,0 +1,93 @@
1
+ module LD4L
2
+ module OreRDF
3
+ class FindProxies
4
+
5
+ ##
6
+ # Find proxies matching the specified criteria.
7
+ #
8
+ # @param [Hash] options the options to use to find proxies
9
+ # @option options [String, RDF::URI, LD4L::OreRDF::AggregationResource] :aggregation - limit proxies found to this aggregation (required)
10
+ # @option options [Hash<Object,Object>] :criteria for finding proxies (ex. RDF::DC.proxy_in=>RDF::URI('http://example.org/ag123')) (default - nil for all proxies in the aggregation)
11
+ # @option options [Hash<Symbol><Object>] :properties to return with the proxy uri (ex. :proxy_for=>RDFVocabularies::ORE.proxyFor) (default - nil aggregation uri only)
12
+ # @option options [Symbol] :repository to search (default - :default)
13
+ # @option options [TrueClass,FalseClass] :resume if true, find and resume; otherwise, find only (default - false)
14
+ #
15
+ # @returns [Array<RDF::URI>,Hash<RDF::URI,LD4L::OreRDF::Proxy,Hash<RDF::URI,Hash<Object,Object>]
16
+ # if resume==false, returns URIs of matching proxy resources + specified properties' values;
17
+ # otherwise, returns resumed instances of matching proxies
18
+ #
19
+ # @example Search for all proxies in aggregation
20
+ # all_proxies = LD4L::OreRDF.FindProxies('http://example.org/aggregations/ag123')
21
+ #
22
+ # @example Search for all proxies in aggregation
23
+ # all_proxies = LD4L::OreRDF.FindProxies(RDF::URI('http://example.org/aggregations/ag123'))
24
+ #
25
+ # @example Search for all proxies in aggregation
26
+ # aggregation_resource = LD4L::OreRDF::AggregationResource.new('http://example.org/aggregations/ag123'))
27
+ # all_proxies = LD4L::OreRDF.FindProxies(aggregation_resource)
28
+ #
29
+ def self.call( options={} )
30
+ aggregation = options[:aggregation] || nil
31
+ raise ArgumentError, 'aggregation must be one of string uri, RDF::URI, LD4L::OreRDF::AggregationResource' unless
32
+ !aggregation.nil? && ( aggregation.kind_of?(String) ||
33
+ aggregation.kind_of?(RDF::URI) ||
34
+ aggregation.kind_of?(LD4L::OreRDF::AggregationResource) )
35
+ aggregation = RDF::URI(aggregation) if aggregation.kind_of?(String)
36
+ aggregation = aggregation.rdf_subject if aggregation.kind_of?(LD4L::OreRDF::AggregationResource)
37
+ # aggregation = aggregation.to_s if aggregation.kind_of?(RDF::URI)
38
+ # aggregation = aggregation.rdf_subject.to_s if aggregation.kind_of?(LD4L::OreRDF::AggregationResource)
39
+
40
+ repository = options[:repository] || :default
41
+ raise ArgumentError, 'repository must be a symbol' unless repository.kind_of?(Symbol)
42
+ raise ArgumentError, 'repository must be a registered repository' unless
43
+ ActiveTriples::Repositories.repositories.has_key?(repository)
44
+
45
+ resume = options[:resume] || false
46
+ raise ArgumentError, 'resume must be true or false' unless
47
+ resume.kind_of?(TrueClass) || resume.kind_of?(FalseClass)
48
+
49
+ criteria = options[:criteria] || nil
50
+ raise ArgumentError, 'criteria must be a hash of attribute-value pairs for searching for proxies' unless
51
+ criteria.nil? || criteria.kind_of?(Hash)
52
+ criteria = criteria ? criteria.dup : {}
53
+ criteria[RDF.type] = RDFVocabularies::ORE.Proxy
54
+ criteria[RDFVocabularies::ORE.proxyIn] = aggregation
55
+
56
+ # properties are ignored when resume==true because all properties are returned as part of the resumed proxies
57
+ properties = options[:properties] || nil
58
+ raise ArgumentError, 'properties must be an array of predicates' unless
59
+ properties.nil? || properties.kind_of?(Hash) || resume
60
+ properties.each_key { |k| criteria[properties[k]] = k unless criteria.has_key?(properties[k]) } unless
61
+ properties.nil? || resume
62
+ process_properties = properties.nil? || resume ? false : true
63
+
64
+
65
+ graph = ActiveTriples::Repositories.repositories[repository]
66
+ query = RDF::Query.new({ :proxy => criteria })
67
+
68
+ process_properties || resume ? proxies = {} : proxies = []
69
+ results = query.execute(graph)
70
+ results.each do |r|
71
+ h = r.to_hash
72
+ uri = h[:proxy]
73
+ if resume
74
+ # if resume, return Hash of proxy uri => resumed proxy for each found
75
+ proxies[uri] = LD4L::OreRDF::ProxyResource.new(uri)
76
+ elsif process_properties
77
+ # if properties, return Hash of proxy uri => Hash of property => value for each found
78
+ properties = h
79
+ properties.delete(:proxy)
80
+ proxies[uri] = properties
81
+ else
82
+ # if no properties && not resumed, return array of proxy uris
83
+ proxies << uri
84
+ end
85
+ end
86
+
87
+ proxies
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+
@@ -0,0 +1,5 @@
1
+ module LD4L
2
+ module OreRDF
3
+ VERSION = "0.0.4"
4
+ end
5
+ end
@@ -0,0 +1,27 @@
1
+ require 'rdf'
2
+ module RDFVocabularies
3
+ class CO < RDF::Vocabulary("http://purl.org/co#")
4
+
5
+ # Class definitions
6
+ term :Set # used for unordered lists
7
+ term :List # used for ordered lists
8
+ term :Element # used for items in an unordered list
9
+ term :ListItem # used for items in an ordered list
10
+
11
+ # Property definitions for CO.Set and CO.List
12
+ property :size # xsd:nonNegativeInteger -- count of all Elements/ListItems in this list
13
+ property :item # URI of each ListItem in this List
14
+
15
+ # Property definitions for CO.List
16
+ property :firstItem # URI to first ListItem in an ordered list
17
+ property :lastItem # URI to last ListItem in an ordered list
18
+
19
+ # Property definitions for CO.Element and CO.ListItem
20
+ property :itemContent # URI to any content
21
+
22
+ # Property definitions for CO.ListItem
23
+ property :index # xsd:positiveInteger -- index of each ListItem starting at 1 counting up
24
+ property :nextItem # URI to a ListItem
25
+ property :previousItem # URI to a ListItem
26
+ end
27
+ end
@@ -0,0 +1,6 @@
1
+ require 'rdf'
2
+ module RDFVocabularies
3
+ class DCTERMS < RDF::Vocabulary("http://purl.org/dc/terms/")
4
+ property :format
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ # require 'rdf'
2
+ module RDFVocabularies
3
+ class IANA < RDF::Vocabulary("http://www.iana.org/assignments/relation/")
4
+ property :first # URI of first item - An IRI that refers to the furthest preceding resource in a series of resources.
5
+ property :last # URI of last item - An IRI that refers to the furthest following resource in a series of resources.
6
+ property :next # URI of next item - Indicates that the link's context is a part of a series, and that the next in the series is the link target.
7
+ property :prev # URI of previous item - Indicates that the link's context is a part of a series, and that the previous in the series is the link target.
8
+ end
9
+ end
@@ -0,0 +1,16 @@
1
+ require 'rdf'
2
+ module RDFVocabularies
3
+ class ORE < RDF::Vocabulary("http://www.openarchives.org/ore/terms/")
4
+
5
+ # Class definitions
6
+ term :Aggregation
7
+ term :Proxy
8
+
9
+ # Property definitions ORE.Aggregation
10
+ property :aggregates # URI of each list item in this Aggregation
11
+
12
+ # Property definitions for ORE.Proxy
13
+ property :proxyFor # URI of list item
14
+ property :proxyIn # URI of aggregating list
15
+ end
16
+ end
@@ -0,0 +1,76 @@
1
+ require 'rdf'
2
+ require 'active_triples'
3
+ require 'active_triples/local_name'
4
+ require 'linkeddata'
5
+ require 'doubly_linked_list'
6
+ require 'ld4l/foaf_rdf'
7
+ require 'ld4l/ore_rdf/version'
8
+ require 'ld4l/ore_rdf/vocab/ore'
9
+ require 'ld4l/ore_rdf/vocab/iana'
10
+ require 'ld4l/ore_rdf/vocab/dcterms'
11
+
12
+ module LD4L
13
+ module OreRDF
14
+
15
+ # Methods for configuring the GEM
16
+ class << self
17
+ attr_accessor :configuration
18
+ end
19
+
20
+ def self.configuration
21
+ @configuration ||= Configuration.new
22
+ end
23
+
24
+ def self.reset
25
+ @configuration = Configuration.new
26
+ end
27
+
28
+ def self.configure
29
+ yield(configuration)
30
+ end
31
+
32
+
33
+ # RDF vocabularies
34
+ autoload :DCTERMS, 'ld4l/ore_rdf/vocab/dcterms'
35
+ autoload :IANA, 'ld4l/ore_rdf/vocab/iana'
36
+ autoload :ORE, 'ld4l/ore_rdf/vocab/ore'
37
+
38
+
39
+ # autoload classes
40
+ autoload :Configuration, 'ld4l/ore_rdf/configuration'
41
+
42
+ # autoload model classes
43
+ autoload :Aggregation, 'ld4l/ore_rdf/models/aggregation'
44
+ autoload :AggregationResource, 'ld4l/ore_rdf/models/aggregation_resource'
45
+ autoload :ProxyResource, 'ld4l/ore_rdf/models/proxy_resource'
46
+
47
+ # autoload service classes
48
+ autoload :CreateAggregation, 'ld4l/ore_rdf/services/aggregation/create'
49
+ autoload :PersistAggregation, 'ld4l/ore_rdf/services/aggregation/persist'
50
+ autoload :ResumeAggregation, 'ld4l/ore_rdf/services/aggregation/resume'
51
+ autoload :DestroyAggregation, 'ld4l/ore_rdf/services/aggregation/destroy'
52
+ autoload :FindAggregations, 'ld4l/ore_rdf/services/aggregation/find'
53
+ autoload :AddAggregatedResource, 'ld4l/ore_rdf/services/aggregation/add_aggregated_resource'
54
+ autoload :AddAggregatedResources, 'ld4l/ore_rdf/services/aggregation/add_aggregated_resources'
55
+
56
+ autoload :CreateProxy, 'ld4l/ore_rdf/services/proxy/create'
57
+ autoload :FindProxies, 'ld4l/ore_rdf/services/proxy/find'
58
+
59
+ def self.class_from_string(class_name, container_class=Kernel)
60
+ container_class = container_class.name if container_class.is_a? Module
61
+ container_parts = container_class.split('::')
62
+ (container_parts + class_name.split('::')).flatten.inject(Kernel) do |mod, class_name|
63
+ if mod == Kernel
64
+ Object.const_get(class_name)
65
+ elsif mod.const_defined? class_name.to_sym
66
+ mod.const_get(class_name)
67
+ else
68
+ container_parts.pop
69
+ class_from_string(class_name, container_parts.join('::'))
70
+ end
71
+ end
72
+ end
73
+
74
+ end
75
+ end
76
+
@@ -0,0 +1,174 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'LD4L::OreRDF' do
4
+
5
+ describe '#configuration' do
6
+ describe "base_uri" do
7
+ context "when base_uri is not configured" do
8
+ before do
9
+ class DummyAggregation < LD4L::OreRDF::AggregationResource
10
+ configure :type => RDFVocabularies::ORE.Aggregation, :base_uri => LD4L::OreRDF.configuration.base_uri, :repository => :default
11
+ end
12
+ end
13
+ after do
14
+ Object.send(:remove_const, "DummyAggregation") if Object
15
+ end
16
+ it "should generate an Aggregation URI using the default base_uri" do
17
+ expect(DummyAggregation.new('1').rdf_subject.to_s).to eq "http://localhost/1"
18
+ end
19
+ end
20
+
21
+ context "when uri ends with slash" do
22
+ before do
23
+ LD4L::OreRDF.configure do |config|
24
+ config.base_uri = "http://localhost/test_slash/"
25
+ end
26
+ class DummyAggregation < LD4L::OreRDF::AggregationResource
27
+ configure :type => RDFVocabularies::ORE.Aggregation, :base_uri => LD4L::OreRDF.configuration.base_uri, :repository => :default
28
+ end
29
+ end
30
+ after do
31
+ Object.send(:remove_const, "DummyAggregation") if Object
32
+ LD4L::OreRDF.reset
33
+ end
34
+
35
+ it "should generate an Aggregation URI using the configured base_uri" do
36
+ expect(DummyAggregation.new('1').rdf_subject.to_s).to eq "http://localhost/test_slash/1"
37
+ end
38
+ end
39
+
40
+ context "when uri does not end with slash" do
41
+ before do
42
+ LD4L::OreRDF.configure do |config|
43
+ config.base_uri = "http://localhost/test_no_slash"
44
+ end
45
+ class DummyAggregation < LD4L::OreRDF::AggregationResource
46
+ configure :type => RDFVocabularies::ORE.Aggregation, :base_uri => LD4L::OreRDF.configuration.base_uri, :repository => :default
47
+ end
48
+ end
49
+ after do
50
+ Object.send(:remove_const, "DummyAggregation") if Object
51
+ LD4L::OreRDF.reset
52
+ end
53
+
54
+ it "should generate an Aggregation URI using the configured base_uri" do
55
+ expect(DummyAggregation.new('1').rdf_subject.to_s).to eq "http://localhost/test_no_slash/1"
56
+ end
57
+ end
58
+
59
+ it "should return value of configured base_uri" do
60
+ LD4L::OreRDF.configure do |config|
61
+ config.base_uri = "http://localhost/test_config/"
62
+ end
63
+ expect(LD4L::OreRDF.configuration.base_uri).to eq "http://localhost/test_config/"
64
+ end
65
+
66
+ it "should return default base_uri when base_uri is reset" do
67
+ LD4L::OreRDF.configure do |config|
68
+ config.base_uri = "http://localhost/test_config/"
69
+ end
70
+ expect(LD4L::OreRDF.configuration.base_uri).to eq "http://localhost/test_config/"
71
+ LD4L::OreRDF.configuration.reset_base_uri
72
+ expect(LD4L::OreRDF.configuration.base_uri).to eq "http://localhost/"
73
+ end
74
+
75
+ it "should return default base_uri when all configs are reset" do
76
+ LD4L::OreRDF.configure do |config|
77
+ config.base_uri = "http://localhost/test_config/"
78
+ end
79
+ expect(LD4L::OreRDF.configuration.base_uri).to eq "http://localhost/test_config/"
80
+ LD4L::OreRDF.reset
81
+ expect(LD4L::OreRDF.configuration.base_uri).to eq "http://localhost/"
82
+ end
83
+ end
84
+
85
+ describe "localname_minter" do
86
+ context "when minter is nil" do
87
+ before do
88
+ class DummyAggregation < LD4L::OreRDF::AggregationResource
89
+ configure :type => RDFVocabularies::ORE.Aggregation, :base_uri => LD4L::OreRDF.configuration.base_uri, :repository => :default
90
+ end
91
+ end
92
+ after do
93
+ Object.send(:remove_const, "DummyAggregation") if Object
94
+ end
95
+ it "should use default minter in minter gem" do
96
+ localname = ActiveTriples::LocalName::Minter.generate_local_name(
97
+ LD4L::OreRDF::AggregationResource, 10, {:prefix=>'default_'},
98
+ LD4L::OreRDF.configuration.localname_minter )
99
+ expect(localname).to be_kind_of String
100
+ expect(localname.size).to eq 44
101
+ expect(localname).to match /default_[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}/
102
+ end
103
+ end
104
+
105
+ context "when minter is configured" do
106
+ before do
107
+ LD4L::OreRDF.configure do |config|
108
+ config.localname_minter = lambda { |prefix=""| prefix+'_configured_'+SecureRandom.uuid }
109
+ end
110
+ class DummyAggregation < LD4L::OreRDF::AggregationResource
111
+ configure :type => RDFVocabularies::ORE.Aggregation, :base_uri => LD4L::OreRDF.configuration.base_uri, :repository => :default
112
+ end
113
+ end
114
+ after do
115
+ Object.send(:remove_const, "DummyAggregation") if Object
116
+ LD4L::OreRDF.reset
117
+ end
118
+
119
+ it "should generate an Aggregation URI using the configured localname_minter" do
120
+ localname = ActiveTriples::LocalName::Minter.generate_local_name(
121
+ LD4L::OreRDF::AggregationResource, 10,
122
+ LD4L::OreRDF::AggregationResource.localname_prefix,
123
+ &LD4L::OreRDF.configuration.localname_minter )
124
+ expect(localname).to be_kind_of String
125
+ expect(localname.size).to eq 50
126
+ expect(localname).to match /ag_configured_[a-zA-Z0-9]{8}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{4}-[a-zA-Z0-9]{12}/
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+
133
+ describe "LD4L::OreRDF::Configuration" do
134
+ describe "#base_uri" do
135
+ it "should default to localhost" do
136
+ expect(LD4L::OreRDF::Configuration.new.base_uri).to eq "http://localhost/"
137
+ end
138
+
139
+ it "should be settable" do
140
+ config = LD4L::OreRDF::Configuration.new
141
+ config.base_uri = "http://localhost/test"
142
+ expect(config.base_uri).to eq "http://localhost/test"
143
+ end
144
+
145
+ it "should be re-settable" do
146
+ config = LD4L::OreRDF::Configuration.new
147
+ config.base_uri = "http://localhost/test/again"
148
+ expect(config.base_uri).to eq "http://localhost/test/again"
149
+ config.reset_base_uri
150
+ expect(config.base_uri).to eq "http://localhost/"
151
+ end
152
+ end
153
+
154
+ describe "#localname_minter" do
155
+ it "should default to nil" do
156
+ expect(LD4L::OreRDF::Configuration.new.localname_minter).to eq nil
157
+ end
158
+
159
+ it "should be settable" do
160
+ config = LD4L::OreRDF::Configuration.new
161
+ config.localname_minter = lambda { |prefix=""| prefix+'_configured_'+SecureRandom.uuid }
162
+ expect(config.localname_minter).to be_kind_of Proc
163
+ end
164
+
165
+ it "should be re-settable" do
166
+ config = LD4L::OreRDF::Configuration.new
167
+ config.localname_minter = lambda { |prefix=""| prefix+'_configured_'+SecureRandom.uuid }
168
+ expect(config.localname_minter).to be_kind_of Proc
169
+ config.reset_localname_minter
170
+ expect(config.localname_minter).to eq nil
171
+ end
172
+ end
173
+ end
174
+ end
@@ -0,0 +1,830 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'LD4L::OreRDF::AggregationResource' do
4
+
5
+ subject { LD4L::OreRDF::AggregationResource.new } # new virtual collection without a subject
6
+
7
+ describe '#rdf_subject' do
8
+ it "should be a blank node if we haven't set it" do
9
+ expect(subject.rdf_subject.node?).to be true
10
+ end
11
+
12
+ it "should be settable when it has not been set yet" do
13
+ subject.set_subject! RDF::URI('http://example.org/moomin')
14
+ expect(subject.rdf_subject).to eq RDF::URI('http://example.org/moomin')
15
+ end
16
+
17
+ it "should append to base URI when setting to non-URI subject" do
18
+ subject.set_subject! '123'
19
+ expect(subject.rdf_subject).to eq RDF::URI("#{LD4L::OreRDF::AggregationResource.base_uri}123")
20
+ end
21
+
22
+ describe 'when changing subject' do
23
+ before do
24
+ subject << RDF::Statement.new(subject.rdf_subject, RDF::DC.title, RDF::Literal('Comet in Moominland'))
25
+ subject << RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.isPartOf, subject.rdf_subject)
26
+ subject << RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.relation, 'http://example.org/moomin_land')
27
+ subject.set_subject! RDF::URI('http://example.org/moomin')
28
+ end
29
+
30
+ it 'should update graph subjects' do
31
+ expect(subject.has_statement?(RDF::Statement.new(subject.rdf_subject, RDF::DC.title, RDF::Literal('Comet in Moominland')))).to be true
32
+ end
33
+
34
+ it 'should update graph objects' do
35
+ expect(subject.has_statement?(RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.isPartOf, subject.rdf_subject))).to be true
36
+ end
37
+
38
+ it 'should leave other uris alone' do
39
+ expect(subject.has_statement?(RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.relation, 'http://example.org/moomin_land'))).to be true
40
+ end
41
+ end
42
+
43
+ describe 'created with URI subject' do
44
+ before do
45
+ subject.set_subject! RDF::URI('http://example.org/moomin')
46
+ end
47
+
48
+ it 'should not be settable' do
49
+ expect{ subject.set_subject! RDF::URI('http://example.org/moomin2') }.to raise_error
50
+ end
51
+ end
52
+ end
53
+
54
+
55
+ # -------------------------------------------------
56
+ # START -- Test attributes specific to this model
57
+ # -------------------------------------------------
58
+
59
+ describe 'type' do
60
+ it "should be an ORE.Aggregation" do
61
+ expect(subject.type.first.value).to eq RDFVocabularies::ORE.Aggregation.value
62
+ end
63
+ end
64
+
65
+ describe 'title' do
66
+ it "should be empty array if we haven't set it" do
67
+ expect(subject.title).to match_array([])
68
+ end
69
+
70
+ it "should be settable" do
71
+ subject.title = "Test Title"
72
+ expect(subject.title).to eq ["Test Title"]
73
+ end
74
+
75
+ it "should be changeable" do
76
+ subject.title = "Test Title"
77
+ subject.title = "New Title"
78
+ expect(subject.title).to eq ["New Title"]
79
+ end
80
+ end
81
+
82
+ describe 'description' do
83
+ it "should be empty array if we haven't set it" do
84
+ expect(subject.description).to match_array([])
85
+ end
86
+
87
+ it "should be settable" do
88
+ subject.description = "Test Description"
89
+ expect(subject.description).to eq ["Test Description"]
90
+ end
91
+
92
+ it "should be changeable" do
93
+ subject.description = "Test Description"
94
+ subject.description = "New Description"
95
+ expect(subject.description).to eq ["New Description"]
96
+ end
97
+ end
98
+
99
+ describe 'owner' do
100
+ it "should be empty array if we haven't set it" do
101
+ expect(subject.owner).to match_array([])
102
+ end
103
+
104
+ it "should be settable" do
105
+ a_person = LD4L::FoafRDF::Person.new('1')
106
+ subject.owner = a_person
107
+ expect(subject.owner.first.rdf_subject).to eq a_person.rdf_subject
108
+ end
109
+
110
+ it "should be changeable" do
111
+ orig_person = LD4L::FoafRDF::Person.new('1')
112
+ new_person = LD4L::FoafRDF::Person.new('2')
113
+ subject.owner = orig_person
114
+ subject.owner = new_person
115
+ expect(subject.owner.first.rdf_subject).to eq new_person.rdf_subject
116
+ end
117
+ end
118
+
119
+ describe 'aggregates' do
120
+ it "should be empty array if we haven't set it" do
121
+ expect(subject.aggregates).to match_array([])
122
+ end
123
+
124
+ it "should be set to a URI producing an ActiveTriple::Resource" do
125
+ subject.aggregates = RDF::URI("http://example.org/individual/b1")
126
+ expect(subject.aggregates.first).to be_a ActiveTriples::Resource
127
+ end
128
+
129
+ it "should be settable" do
130
+ subject.aggregates = RDF::URI("http://example.org/individual/b1")
131
+ expect(subject.aggregates.first.rdf_subject).to eq RDF::URI("http://example.org/individual/b1")
132
+ ['id']
133
+ end
134
+
135
+ it "should be settable to multiple values" do
136
+ bib1 = RDF::URI("http://example.org/individual/b1")
137
+ bib2 = RDF::URI("http://example.org/individual/b2")
138
+ bib3 = RDF::URI("http://example.org/individual/b3")
139
+ subject.aggregates = bib1
140
+ subject.aggregates << bib2
141
+ subject.aggregates << bib3
142
+ expect(subject.aggregates[0].rdf_subject).to eq bib1
143
+ expect(subject.aggregates[1].rdf_subject).to eq bib2
144
+ expect(subject.aggregates[2].rdf_subject).to eq bib3
145
+ end
146
+
147
+ it "should be changeable" do
148
+ orig_bib = RDF::URI("http://example.org/individual/b1")
149
+ new_bib = RDF::URI("http://example.org/individual/b1_NEW")
150
+ subject.aggregates = orig_bib
151
+ subject.aggregates = new_bib
152
+ expect(subject.aggregates.first.rdf_subject).to eq new_bib
153
+ end
154
+
155
+ it "should be changeable for multiple values" do
156
+ orig_bib1 = RDF::URI("http://example.org/individual/b1")
157
+ orig_bib2 = RDF::URI("http://example.org/individual/b2")
158
+ orig_bib3 = RDF::URI("http://example.org/individual/b3")
159
+
160
+ new_bib1 = RDF::URI("http://example.org/individual/b1_NEW")
161
+ new_bib2 = RDF::URI("http://example.org/individual/b2_NEW")
162
+ new_bib3 = RDF::URI("http://example.org/individual/b3_NEW")
163
+
164
+ subject.aggregates = orig_bib1
165
+ subject.aggregates << orig_bib2
166
+ subject.aggregates << orig_bib3
167
+
168
+ aggregates = subject.aggregates.dup
169
+ aggregates[0] = new_bib1
170
+ # aggregates[1] = new_bib2
171
+ aggregates[2] = new_bib3
172
+ subject.aggregates = aggregates
173
+
174
+ expect(subject.aggregates[0].rdf_subject).to eq new_bib1
175
+ # expect(subject.aggregates[1].rdf_subject).to eq new_bib2
176
+ expect(subject.aggregates[1].rdf_subject).to eq orig_bib2
177
+ expect(subject.aggregates[2].rdf_subject).to eq new_bib3
178
+ end
179
+
180
+ it "should be directly changeable for multiple values" do
181
+ orig_bib1 = RDF::URI("http://example.org/individual/b1")
182
+ orig_bib2 = RDF::URI("http://example.org/individual/b2")
183
+ orig_bib3 = RDF::URI("http://example.org/individual/b3")
184
+
185
+ new_bib1 = RDF::URI("http://example.org/individual/b1_NEW")
186
+ new_bib2 = RDF::URI("http://example.org/individual/b2_NEW")
187
+ new_bib3 = RDF::URI("http://example.org/individual/b3_NEW")
188
+
189
+ subject.aggregates = orig_bib1
190
+ subject.aggregates << orig_bib2
191
+ subject.aggregates << orig_bib3
192
+
193
+ subject.aggregates[0] = new_bib1
194
+ # subject.aggregates[1] = new_bib2
195
+ subject.aggregates[2] = new_bib3
196
+
197
+ expect(subject.aggregates[0].rdf_subject).to eq new_bib1
198
+ # expect(subject.aggregates[1].rdf_subject).to eq new_bib2
199
+ expect(subject.aggregates[1].rdf_subject).to eq orig_bib2
200
+ expect(subject.aggregates[2].rdf_subject).to eq new_bib3
201
+ end
202
+ end
203
+
204
+ # -----------------------------------------------
205
+ # END -- Test attributes specific to this model
206
+ # -----------------------------------------------
207
+
208
+
209
+ # -----------------------------------------------------
210
+ # START -- Test helper methods specific to this model
211
+ # -----------------------------------------------------
212
+
213
+
214
+ ########### NEED TO MOVE TO SERVICE OBJECT ####################
215
+
216
+
217
+ describe "#get_items_content" do
218
+ context "when collection has 0 items" do
219
+ before do
220
+ subject.aggregates = []
221
+ end
222
+ it "should return empty array when no items exist" do
223
+ subject.aggregates = []
224
+ content_array = subject.get_items_content
225
+ expect(content_array).to eq []
226
+ end
227
+ end
228
+
229
+ context "when collection has items" do
230
+ xit "should return array" do
231
+
232
+
233
+ ### TODO need to update add_items_with_content to use new service
234
+
235
+
236
+ # subject.add_items_with_content([RDF::URI("http://example.org/individual/b1"),
237
+ # RDF::URI("http://example.org/individual/b2"),
238
+ # RDF::URI("http://example.org/individual/b3")])
239
+
240
+
241
+
242
+
243
+ content_array = subject.get_items_content
244
+ expect(content_array).to be_a(Array)
245
+ end
246
+ end
247
+
248
+ context "when start and limit are not specified" do
249
+ xit "should return array of all content aggregated by subject" do
250
+
251
+
252
+ ### TODO need to update add_items_with_content to use new service
253
+
254
+
255
+ # subject.add_items_with_content([RDF::URI("http://example.org/individual/b1"),
256
+ # RDF::URI("http://example.org/individual/b2"),
257
+ # RDF::URI("http://example.org/individual/b3")])
258
+
259
+
260
+
261
+
262
+ content_array = subject.get_items_content
263
+ expect(content_array).to include ActiveTriples::Resource.new(RDF::URI("http://example.org/individual/b1"))
264
+ expect(content_array).to include ActiveTriples::Resource.new(RDF::URI("http://example.org/individual/b2"))
265
+ expect(content_array).to include ActiveTriples::Resource.new(RDF::URI("http://example.org/individual/b3"))
266
+ end
267
+
268
+ xit "should not return any content not aggregated by subject" do
269
+ vc = LD4L::OreRDF::AggregationResource.new('999')
270
+
271
+
272
+ ### TODO need to update add_items_with_content to use new service
273
+
274
+
275
+ # vc.add_item_with_content(RDF::URI("http://example.org/individual/b999"))
276
+ #
277
+ # subject.add_items_with_content([RDF::URI("http://example.org/individual/b1"),
278
+ # RDF::URI("http://example.org/individual/b2"),
279
+ # RDF::URI("http://example.org/individual/b3")])
280
+
281
+
282
+
283
+ content_array = subject.get_items_content
284
+ expect(content_array).to include ActiveTriples::Resource.new(RDF::URI("http://example.org/individual/b1"))
285
+ expect(content_array).to include ActiveTriples::Resource.new(RDF::URI("http://example.org/individual/b2"))
286
+ expect(content_array).to include ActiveTriples::Resource.new(RDF::URI("http://example.org/individual/b3"))
287
+ expect(content_array.size).to eq 3
288
+ end
289
+ end
290
+
291
+ context "when limit is specified" do
292
+ xit "should return array of content with max size=limit" do
293
+ pending "this needs to be implemented"
294
+ end
295
+ end
296
+
297
+ context "when start is specified" do
298
+ xit "should return array of content_beginning with item at position=start" do
299
+ # TODO: What does _start_ mean in ActiveTriples? Does it support this kind of query?
300
+ pending "this needs to be implemented"
301
+ end
302
+ end
303
+
304
+ context "when start and limit are specified" do
305
+ xit "should return an array of content with max size=limit beginning with item at position=start" do
306
+ pending "this needs to be implemented"
307
+ end
308
+ end
309
+ end
310
+
311
+ describe "#get_items" do
312
+ context "when collection has 0 items" do
313
+ before do
314
+ subject.aggregates = []
315
+ end
316
+
317
+ it "should return empty array when no items exist" do
318
+ vci_array = subject.get_items
319
+ expect(vci_array).to eq []
320
+ end
321
+ end
322
+
323
+ context "when collection has items" do
324
+ before do
325
+
326
+
327
+ ### TODO need to update add_items_with_content to use new service
328
+
329
+
330
+ # subject.add_items_with_content([RDF::URI("http://example.org/individual/b1"),
331
+ # RDF::URI("http://example.org/individual/b2"),
332
+ # RDF::URI("http://example.org/individual/b3")])
333
+ end
334
+
335
+ xit "should return array" do
336
+ vci_array = subject.get_items
337
+ expect(vci_array).to be_a(Array)
338
+ end
339
+
340
+ xit "should return array of LD4L::OreRDF::ProxyResource instances" do
341
+ vci_array = subject.get_items
342
+ vci_array.each do |vci|
343
+ expect(vci).to be_a(LD4L::OreRDF::ProxyResource)
344
+ end
345
+ end
346
+ end
347
+
348
+ context "when start and limit are not specified" do
349
+ context "and objects not persisted" do
350
+ xit "should return empty array" do
351
+
352
+
353
+ ### TODO need to update add_items_with_content to use new service
354
+
355
+
356
+ # subject.add_items_with_content([RDF::URI("http://example.org/individual/b1"),
357
+ # RDF::URI("http://example.org/individual/b2"),
358
+ # RDF::URI("http://example.org/individual/b3")])
359
+ vci_array = subject.get_items
360
+ expect(vci_array.size).to eq(0)
361
+ end
362
+ end
363
+
364
+ context "and objects are persisted" do
365
+ xit "should return array of all LD4L::OreRDF::ProxyResource instances for content aggregated by subject" do
366
+
367
+
368
+ ### TODO need to update add_items_with_content to use new service
369
+
370
+
371
+ # vci_array = subject.add_items_with_content([RDF::URI("http://example.org/individual/b1"),
372
+ # RDF::URI("http://example.org/individual/b2"),
373
+ # RDF::URI("http://example.org/individual/b3")])
374
+ subject.persist!
375
+ vci_array.each { |vci| vci.persist! }
376
+
377
+ vci_array = subject.get_items
378
+ vci_array.each do |vci|
379
+ expect(vci).to be_a(LD4L::OreRDF::ProxyResource)
380
+ expect(vci.proxy_in.first).to eq subject
381
+ end
382
+ results = []
383
+ vci_array.each { |vci| results << vci.proxy_for.first }
384
+ expect(results).to include ActiveTriples::Resource.new(RDF::URI("http://example.org/individual/b1"))
385
+ expect(results).to include ActiveTriples::Resource.new(RDF::URI("http://example.org/individual/b2"))
386
+ expect(results).to include ActiveTriples::Resource.new(RDF::URI("http://example.org/individual/b3"))
387
+ expect(vci_array.size).to eq(3)
388
+ end
389
+
390
+ xit "should not return any LD4L::OreRDF::ProxyResource instances for content not aggregated by subject" do
391
+ pending "this needs to be implemented"
392
+ end
393
+ end
394
+ end
395
+
396
+ context "when limit is specified" do
397
+ xit "should return array of LD4L::OreRDF::ProxyResource instances with max size=limit" do
398
+ pending "this needs to be implemented"
399
+ end
400
+ end
401
+
402
+ context "when start is specified" do
403
+ xit "should return array of LD4L::OreRDF::ProxyResource instances_beginning with item at position=start" do
404
+ # TODO: What does _start_ mean in ActiveTriples? Does it support this kind of query?
405
+ pending "this needs to be implemented"
406
+ end
407
+ end
408
+
409
+ context "when start and limit are specified" do
410
+ xit "should return an array of LD4L::OreRDF::ProxyResource instances with max size=limit beginning with item at position=start" do
411
+ pending "this needs to be implemented"
412
+ end
413
+ end
414
+ end
415
+
416
+ describe "#find_item_with_content" do
417
+ skip "this needs to be implemented"
418
+ end
419
+
420
+ describe "#get_item_content_at" do
421
+ skip "this needs to be implemented"
422
+ end
423
+
424
+ describe "#get_item_at" do
425
+ skip "this needs to be implemented"
426
+ end
427
+
428
+ describe "#has_item_at?" do
429
+ skip "this needs to be implemented"
430
+ end
431
+
432
+ describe "#has_item_content?" do
433
+ skip "this needs to be implemented"
434
+ end
435
+
436
+ describe "#remove_item_with_content" do
437
+ skip "this needs to be implemented"
438
+ end
439
+
440
+ describe "#is_ordered?" do
441
+ skip "this needs to be implemented"
442
+ end
443
+
444
+ # ---------------------------------------------------
445
+ # END -- Test helper methods specific to this model
446
+ # ---------------------------------------------------
447
+
448
+
449
+ describe "#persisted?" do
450
+ context 'with a repository' do
451
+ before do
452
+ # Create inmemory repository
453
+ repository = RDF::Repository.new
454
+ allow(subject).to receive(:repository).and_return(repository)
455
+ end
456
+
457
+ context "when the object is new" do
458
+ it "should return false" do
459
+ expect(subject).not_to be_persisted
460
+ end
461
+ end
462
+
463
+ context "when it is saved" do
464
+ before do
465
+ subject.title = "bla"
466
+ subject.persist!
467
+ end
468
+
469
+ it "should return true" do
470
+ expect(subject).to be_persisted
471
+ end
472
+
473
+ context "and then modified" do
474
+ before do
475
+ subject.title = "newbla"
476
+ end
477
+
478
+ it "should return true" do
479
+ expect(subject).to be_persisted
480
+ end
481
+ end
482
+ context "and then reloaded" do
483
+ before do
484
+ subject.reload
485
+ end
486
+
487
+ it "should reset the title" do
488
+ expect(subject.title).to eq ["bla"]
489
+ end
490
+
491
+ it "should be persisted" do
492
+ expect(subject).to be_persisted
493
+ end
494
+ end
495
+ end
496
+ end
497
+ end
498
+
499
+ describe "#persist!" do
500
+ context "when the repository is set" do
501
+ context "and the item is not a blank node" do
502
+
503
+ subject {LD4L::OreRDF::AggregationResource.new("123")}
504
+
505
+ before do
506
+ # Create inmemory repository
507
+ @repo = RDF::Repository.new
508
+ allow(subject.class).to receive(:repository).and_return(nil)
509
+ allow(subject).to receive(:repository).and_return(@repo)
510
+ subject.title = "bla"
511
+ subject.persist!
512
+ end
513
+
514
+ it "should persist to the repository" do
515
+ expect(@repo.statements.first).to eq subject.statements.first
516
+ end
517
+
518
+ it "should delete from the repository" do
519
+ subject.reload
520
+ expect(subject.title).to eq ["bla"]
521
+ subject.title = []
522
+ expect(subject.title).to eq []
523
+ subject.persist!
524
+ subject.reload
525
+ expect(subject.title).to eq []
526
+ expect(@repo.statements.to_a.length).to eq 1 # Only the type statement
527
+ end
528
+ end
529
+ end
530
+ end
531
+
532
+ describe '#destroy!' do
533
+ before do
534
+ subject << RDF::Statement(RDF::DC.LicenseDocument, RDF::DC.title, 'LICENSE')
535
+ end
536
+
537
+ subject { LD4L::FoafRDF::Person.new('456')}
538
+
539
+ it 'should return true' do
540
+ expect(subject.destroy!).to be true
541
+ expect(subject.destroy).to be true
542
+ end
543
+
544
+ it 'should delete the graph' do
545
+ subject.destroy
546
+ expect(subject).to be_empty
547
+ end
548
+
549
+ context 'with a parent' do
550
+ before do
551
+ parent.owner = subject
552
+ end
553
+
554
+ let(:parent) do
555
+ LD4L::OreRDF::AggregationResource.new('123')
556
+ end
557
+
558
+ it 'should empty the graph and remove it from the parent' do
559
+ subject.destroy
560
+ expect(parent.owner).to be_empty
561
+ end
562
+
563
+ it 'should remove its whole graph from the parent' do
564
+ subject.destroy
565
+ subject.each_statement do |s|
566
+ expect(parent.statements).not_to include s
567
+ end
568
+ end
569
+ end
570
+ end
571
+
572
+ describe 'attributes' do
573
+ before do
574
+ subject.owner = owner
575
+ subject.title = 'My Title'
576
+ end
577
+
578
+ subject {LD4L::OreRDF::AggregationResource.new("123")}
579
+
580
+ let(:owner) { LD4L::FoafRDF::Person.new('456') }
581
+
582
+ it 'should return an attributes hash' do
583
+ expect(subject.attributes).to be_a Hash
584
+ end
585
+
586
+ it 'should contain data' do
587
+ expect(subject.attributes['title']).to eq ['My Title']
588
+ end
589
+
590
+ it 'should contain child objects' do
591
+ expect(subject.attributes['owner']).to eq [owner]
592
+ end
593
+
594
+ context 'with unmodeled data' do
595
+ before do
596
+ subject << RDF::Statement(subject.rdf_subject, RDF::DC.contributor, 'Tove Jansson')
597
+ subject << RDF::Statement(subject.rdf_subject, RDF::DC.relation, RDF::URI('http://example.org/moomi'))
598
+ node = RDF::Node.new
599
+ subject << RDF::Statement(RDF::URI('http://example.org/moomi'), RDF::DC.relation, node)
600
+ subject << RDF::Statement(node, RDF::DC.title, 'bnode')
601
+ end
602
+
603
+ it 'should include data with URIs as attribute names' do
604
+ expect(subject.attributes[RDF::DC.contributor.to_s]).to eq ['Tove Jansson']
605
+ end
606
+
607
+ it 'should return generic Resources' do
608
+ expect(subject.attributes[RDF::DC.relation.to_s].first).to be_a ActiveTriples::Resource
609
+ end
610
+
611
+ it 'should build deep data for Resources' do
612
+ expect(subject.attributes[RDF::DC.relation.to_s].first.get_values(RDF::DC.relation).
613
+ first.get_values(RDF::DC.title)).to eq ['bnode']
614
+ end
615
+
616
+ it 'should include deep data in serializable_hash' do
617
+ expect(subject.serializable_hash[RDF::DC.relation.to_s].first.get_values(RDF::DC.relation).
618
+ first.get_values(RDF::DC.title)).to eq ['bnode']
619
+ end
620
+ end
621
+
622
+ describe 'attribute_serialization' do
623
+ describe '#to_json' do
624
+ it 'should return a string with correct objects' do
625
+ json_hash = JSON.parse(subject.to_json)
626
+ expect(json_hash['owner'].first['id']).to eq owner.rdf_subject.to_s
627
+ end
628
+ end
629
+ end
630
+ end
631
+
632
+ describe 'property methods' do
633
+ it 'should set and get properties' do
634
+ subject.title = 'Comet in Moominland'
635
+ expect(subject.title).to eq ['Comet in Moominland']
636
+ end
637
+ end
638
+
639
+ describe 'child nodes' do
640
+ it 'should return an object of the correct class when the value is built from the base URI' do
641
+ subject.owner = LD4L::FoafRDF::Person.new('456')
642
+ expect(subject.owner.first).to be_kind_of LD4L::FoafRDF::Person
643
+ end
644
+
645
+ it 'should return an object with the correct URI created with a URI' do
646
+ subject.owner = LD4L::FoafRDF::Person.new("http://vivo.cornell.edu/individual/JohnSmith")
647
+ expect(subject.owner.first.rdf_subject).to eq RDF::URI("http://vivo.cornell.edu/individual/JohnSmith")
648
+ end
649
+
650
+ it 'should return an object of the correct class when the value is a bnode' do
651
+ subject.owner = LD4L::FoafRDF::Person.new
652
+ expect(subject.owner.first).to be_kind_of LD4L::FoafRDF::Person
653
+ end
654
+ end
655
+
656
+ describe '#set_value' do
657
+ it 'should set a value in the graph' do
658
+ subject.set_value(RDF::DC.title, 'Comet in Moominland')
659
+ subject.query(:subject => subject.rdf_subject, :predicate => RDF::DC.title).each_statement do |s|
660
+ expect(s.object.to_s).to eq 'Comet in Moominland'
661
+ end
662
+ end
663
+
664
+ it 'should set a value in the when given a registered property symbol' do
665
+ subject.set_value(:title, 'Comet in Moominland')
666
+ expect(subject.title).to eq ['Comet in Moominland']
667
+ end
668
+
669
+ it "raise an error if the value is not a URI, Node, Literal, RdfResource, or string" do
670
+ expect{subject.set_value(RDF::DC.title, Object.new)}.to raise_error
671
+ end
672
+
673
+ it "should be able to accept a subject" do
674
+ expect{subject.set_value(RDF::URI("http://opaquenamespace.org/jokes"), RDF::DC.title, 'Comet in Moominland')}.not_to raise_error
675
+ expect(subject.query(:subject => RDF::URI("http://opaquenamespace.org/jokes"), :predicate => RDF::DC.title).statements.to_a.length).to eq 1
676
+ end
677
+ end
678
+ describe '#get_values' do
679
+ before do
680
+ subject.title = ['Comet in Moominland', "Finn Family Moomintroll"]
681
+ end
682
+
683
+ it 'should return values for a predicate uri' do
684
+ expect(subject.get_values(RDF::DC.title)).to eq ['Comet in Moominland', 'Finn Family Moomintroll']
685
+ end
686
+
687
+ it 'should return values for a registered predicate symbol' do
688
+ expect(subject.get_values(:title)).to eq ['Comet in Moominland', 'Finn Family Moomintroll']
689
+ end
690
+
691
+ it "should return values for other subjects if asked" do
692
+ expect(subject.get_values(RDF::URI("http://opaquenamespace.org/jokes"),:title)).to eq []
693
+ subject.set_value(RDF::URI("http://opaquenamespace.org/jokes"), RDF::DC.title, 'Comet in Moominland')
694
+ expect(subject.get_values(RDF::URI("http://opaquenamespace.org/jokes"),:title)).to eq ["Comet in Moominland"]
695
+ end
696
+ end
697
+
698
+ describe '#type' do
699
+ it 'should return the type configured on the parent class' do
700
+ expect(subject.type).to eq [LD4L::OreRDF::AggregationResource.type]
701
+ end
702
+
703
+ it 'should set the type' do
704
+ subject.type = RDF::URI('http://example.org/AnotherClass')
705
+ expect(subject.type).to eq [RDF::URI('http://example.org/AnotherClass')]
706
+ end
707
+
708
+ it 'should be the type in the graph' do
709
+ subject.query(:subject => subject.rdf_subject, :predicate => RDF.type).statements do |s|
710
+ expect(s.object).to eq RDF::URI('http://example.org/AnotherClass')
711
+ end
712
+ end
713
+ end
714
+
715
+ describe '#rdf_label' do
716
+ it 'should return an array of label values' do
717
+ expect(subject.rdf_label).to be_kind_of Array
718
+ end
719
+
720
+ it 'should return the default label values' do
721
+ subject.title = 'Comet in Moominland'
722
+ expect(subject.rdf_label).to eq ['Comet in Moominland']
723
+ end
724
+
725
+ it 'should prioritize configured label values' do
726
+ custom_label = RDF::URI('http://example.org/custom_label')
727
+ subject.class.configure :rdf_label => custom_label
728
+ subject << RDF::Statement(subject.rdf_subject, custom_label, RDF::Literal('New Label'))
729
+ subject.title = 'Comet in Moominland'
730
+ expect(subject.rdf_label).to eq ['New Label']
731
+ end
732
+ end
733
+
734
+ describe '#solrize' do
735
+ it 'should return a label for bnodes' do
736
+ expect(subject.solrize).to eq subject.rdf_label
737
+ end
738
+
739
+ it 'should return a string of the resource uri' do
740
+ subject.set_subject! 'http://example.org/moomin'
741
+ expect(subject.solrize).to eq 'http://example.org/moomin'
742
+ end
743
+ end
744
+
745
+ describe 'editing the graph' do
746
+ it 'should write properties when statements are added' do
747
+ subject << RDF::Statement.new(subject.rdf_subject, RDF::DC.title, 'Comet in Moominland')
748
+ expect(subject.title).to include 'Comet in Moominland'
749
+ end
750
+
751
+ it 'should delete properties when statements are removed' do
752
+ subject << RDF::Statement.new(subject.rdf_subject, RDF::DC.title, 'Comet in Moominland')
753
+ subject.delete RDF::Statement.new(subject.rdf_subject, RDF::DC.title, 'Comet in Moominland')
754
+ expect(subject.title).to eq []
755
+ end
756
+ end
757
+
758
+ describe 'big complex graphs' do
759
+ before do
760
+ class DummyPerson < ActiveTriples::Resource
761
+ configure :type => RDF::URI('http://example.org/Person')
762
+ property :foafname, :predicate => RDF::FOAF.name
763
+ property :publications, :predicate => RDF::FOAF.publications, :class_name => 'DummyDocument'
764
+ property :knows, :predicate => RDF::FOAF.knows, :class_name => DummyPerson
765
+ end
766
+
767
+ class DummyDocument < ActiveTriples::Resource
768
+ configure :type => RDF::URI('http://example.org/Document')
769
+ property :title, :predicate => RDF::DC.title
770
+ property :creator, :predicate => RDF::DC.creator, :class_name => 'DummyPerson'
771
+ end
772
+
773
+ LD4L::OreRDF::AggregationResource.property :item, :predicate => RDF::DC.relation, :class_name => DummyDocument
774
+ end
775
+
776
+ subject { LD4L::OreRDF::AggregationResource.new }
777
+
778
+ let (:document1) do
779
+ d = DummyDocument.new
780
+ d.title = 'Document One'
781
+ d
782
+ end
783
+
784
+ let (:document2) do
785
+ d = DummyDocument.new
786
+ d.title = 'Document Two'
787
+ d
788
+ end
789
+
790
+ let (:person1) do
791
+ p = DummyPerson.new
792
+ p.foafname = 'Alice'
793
+ p
794
+ end
795
+
796
+ let (:person2) do
797
+ p = DummyPerson.new
798
+ p.foafname = 'Bob'
799
+ p
800
+ end
801
+
802
+ let (:data) { <<END
803
+ _:1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/SomeClass> .
804
+ _:1 <http://purl.org/dc/terms/relation> _:2 .
805
+ _:2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Document> .
806
+ _:2 <http://purl.org/dc/terms/title> "Document One" .
807
+ _:2 <http://purl.org/dc/terms/creator> _:3 .
808
+ _:2 <http://purl.org/dc/terms/creator> _:4 .
809
+ _:4 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Person> .
810
+ _:4 <http://xmlns.com/foaf/0.1/name> "Bob" .
811
+ _:3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Person> .
812
+ _:3 <http://xmlns.com/foaf/0.1/name> "Alice" .
813
+ _:3 <http://xmlns.com/foaf/0.1/knows> _:4 ."
814
+ END
815
+ }
816
+
817
+ after do
818
+ Object.send(:remove_const, "DummyDocument")
819
+ Object.send(:remove_const, "DummyPerson")
820
+ end
821
+
822
+ it 'should allow access to deep nodes' do
823
+ document1.creator = [person1, person2]
824
+ document2.creator = person1
825
+ person1.knows = person2
826
+ subject.item = [document1]
827
+ expect(subject.item.first.creator.first.knows.first.foafname).to eq ['Bob']
828
+ end
829
+ end
830
+ end