ld4l-ore_rdf 0.0.4

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