ladder 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +4 -1
- data/.semver +5 -0
- data/Gemfile +1 -1
- data/README.md +11 -11
- data/Rakefile +1 -2
- data/ladder.gemspec +26 -23
- data/lib/ladder.rb +1 -1
- data/lib/ladder/file.rb +49 -40
- data/lib/ladder/resource.rb +204 -60
- data/lib/ladder/resource/dynamic.rb +134 -83
- data/lib/ladder/resource/serializable.rb +56 -43
- data/lib/ladder/searchable.rb +14 -12
- data/lib/ladder/searchable/background.rb +40 -31
- data/lib/ladder/searchable/file.rb +33 -26
- data/lib/ladder/searchable/resource.rb +26 -15
- data/lib/ladder/version.rb +2 -2
- data/spec/ladder/file_spec.rb +9 -7
- data/spec/ladder/resource/dynamic_spec.rb +13 -143
- data/spec/ladder/resource_spec.rb +47 -226
- data/spec/ladder/searchable/background_spec.rb +37 -42
- data/spec/ladder/searchable/file_spec.rb +8 -5
- data/spec/ladder/searchable/resource_spec.rb +30 -38
- data/spec/shared/file.rb +9 -9
- data/spec/shared/graph.jsonld +31 -0
- data/spec/shared/resource.rb +397 -14
- data/spec/shared/searchable/file.rb +2 -4
- data/spec/shared/searchable/resource.rb +137 -145
- data/spec/spec_helper.rb +3 -2
- metadata +49 -4
@@ -1,30 +1,37 @@
|
|
1
|
-
module Ladder
|
2
|
-
|
1
|
+
module Ladder
|
2
|
+
module Searchable
|
3
|
+
module File
|
4
|
+
extend ActiveSupport::Concern
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
6
|
+
included do
|
7
|
+
# Index binary content using Elasticsearch mapper attachment plugin
|
8
|
+
# https://github.com/elasticsearch/elasticsearch-mapper-attachments
|
9
|
+
mapping _source: { enabled: false } do
|
10
|
+
indexes :file, type: 'attachment', fields: {
|
11
|
+
file: { store: true },
|
12
|
+
title: { store: true },
|
13
|
+
date: { store: true },
|
14
|
+
author: { store: true },
|
15
|
+
keywords: { store: true },
|
16
|
+
content_type: { store: true },
|
17
|
+
content_length: { store: true },
|
18
|
+
language: { store: true }
|
19
|
+
}
|
20
|
+
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
# Explicitly set mapping definition on index
|
23
|
+
__elasticsearch__.create_index!
|
24
|
+
end
|
23
25
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
26
|
+
##
|
27
|
+
# Serialize a Base64-encoded version of data for indexing
|
28
|
+
#
|
29
|
+
# @see Elasticsearch::Model::Serializing#as_indexed_json
|
30
|
+
#
|
31
|
+
# @return [Hash] a serialized version of the file
|
32
|
+
def as_indexed_json(*)
|
33
|
+
{ file: Base64.encode64(data) }
|
34
|
+
end
|
35
|
+
end
|
28
36
|
end
|
29
|
-
|
30
|
-
end
|
37
|
+
end
|
@@ -1,19 +1,30 @@
|
|
1
|
-
module Ladder
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
respond_to?(:serialized_json) ? serialized_json : as_json(except: [:id, :_id])
|
6
|
-
end
|
1
|
+
module Ladder
|
2
|
+
module Searchable
|
3
|
+
module Resource
|
4
|
+
extend ActiveSupport::Concern
|
7
5
|
|
8
|
-
|
6
|
+
##
|
7
|
+
# Serialize the resource as JSON for indexing
|
8
|
+
#
|
9
|
+
# @see Elasticsearch::Model::Serializing#as_indexed_json
|
10
|
+
#
|
11
|
+
# @return [Hash] a serialized version of the resource
|
12
|
+
def as_indexed_json(*)
|
13
|
+
respond_to?(:serialized_json) ? serialized_json : as_json(except: [:id, :_id])
|
14
|
+
end
|
9
15
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
16
|
+
module ClassMethods
|
17
|
+
##
|
18
|
+
# Specify type of serialization to use for indexing;
|
19
|
+
# if a block is provided, it is expected to return a Hash
|
20
|
+
# that will be used in lieu of {#as_indexed_json} for
|
21
|
+
# serializing the resource in the index
|
22
|
+
#
|
23
|
+
# @return [void]
|
24
|
+
def index_for_search(&block)
|
25
|
+
define_method(:serialized_json, block) if block_given?
|
26
|
+
end
|
27
|
+
end
|
15
28
|
end
|
16
|
-
|
17
29
|
end
|
18
|
-
|
19
|
-
end
|
30
|
+
end
|
data/lib/ladder/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Ladder
|
2
|
-
VERSION =
|
3
|
-
end
|
2
|
+
VERSION = '0.3.2'
|
3
|
+
end
|
data/spec/ladder/file_spec.rb
CHANGED
@@ -15,7 +15,7 @@ describe Ladder::File do
|
|
15
15
|
|
16
16
|
after do
|
17
17
|
Object.send(:remove_const, :LADDER_BASE_URI) if Object
|
18
|
-
Object.send(:remove_const,
|
18
|
+
Object.send(:remove_const, 'Datastream') if Object
|
19
19
|
end
|
20
20
|
|
21
21
|
shared_context 'with relations' do
|
@@ -42,7 +42,7 @@ describe Ladder::File do
|
|
42
42
|
|
43
43
|
context 'with one-sided has-many' do
|
44
44
|
it 'should have a relation' do
|
45
|
-
expect(thing.relations['files'].relation).to eq
|
45
|
+
expect(thing.relations['files'].relation).to eq Mongoid::Relations::Referenced::ManyToMany
|
46
46
|
expect(thing.files.to_a).to include subject
|
47
47
|
end
|
48
48
|
|
@@ -59,7 +59,6 @@ describe Ladder::File do
|
|
59
59
|
expect(subject.class.properties).to be_empty
|
60
60
|
end
|
61
61
|
end
|
62
|
-
|
63
62
|
end
|
64
63
|
|
65
64
|
context 'with data from file' do
|
@@ -73,8 +72,12 @@ describe Ladder::File do
|
|
73
72
|
end
|
74
73
|
|
75
74
|
context 'with data from string after creation' do
|
76
|
-
data =
|
77
|
-
|
75
|
+
data = 'And so Moomintroll was helplessly thrown out into a strange and dangerous world and dropped
|
76
|
+
up to his ears in the first snowdrift of his experience. It felt unpleasantly prickly to his
|
77
|
+
velvet skin, but at the same time his nose caught a new smell. It was a more serious smell
|
78
|
+
than any he had met before, and slightly frightening. But it made him wide awake and greatly
|
79
|
+
interested.'
|
80
|
+
|
78
81
|
let(:subject) { Datastream.new }
|
79
82
|
let(:source) { data } # UTF-8 (string)
|
80
83
|
|
@@ -85,5 +88,4 @@ describe Ladder::File do
|
|
85
88
|
include_context 'with relations'
|
86
89
|
it_behaves_like 'a File'
|
87
90
|
end
|
88
|
-
|
89
|
-
end
|
91
|
+
end
|
@@ -10,12 +10,17 @@ describe Ladder::Resource::Dynamic do
|
|
10
10
|
|
11
11
|
class Thing
|
12
12
|
include Ladder::Resource::Dynamic
|
13
|
+
configure type: RDF::DC.BibliographicResource
|
14
|
+
|
15
|
+
field :alt
|
16
|
+
property :alt, predicate: RDF::DC.alternative # non-localized literal
|
17
|
+
property :title, predicate: RDF::DC.title # localized literal
|
13
18
|
end
|
14
19
|
end
|
15
20
|
|
16
21
|
after do
|
17
22
|
Object.send(:remove_const, :LADDER_BASE_URI) if Object
|
18
|
-
Object.send(:remove_const,
|
23
|
+
Object.send(:remove_const, 'Thing') if Object
|
19
24
|
end
|
20
25
|
|
21
26
|
context 'with data' do
|
@@ -23,155 +28,20 @@ describe Ladder::Resource::Dynamic do
|
|
23
28
|
|
24
29
|
before do
|
25
30
|
# non-localized literal
|
26
|
-
subject.class.field :alt
|
27
|
-
subject.class.property :alt, predicate: RDF::DC.alternative
|
28
31
|
subject.alt = 'Mumintrollet pa kometjakt'
|
29
32
|
|
30
33
|
# localized literal
|
31
|
-
subject.class.property :title, predicate: RDF::DC.title
|
32
34
|
subject.title = 'Comet in Moominland'
|
33
35
|
end
|
34
36
|
|
35
37
|
it_behaves_like 'a Resource'
|
36
|
-
|
37
|
-
|
38
|
-
context 'with undefined property' do
|
39
|
-
before do
|
40
|
-
subject.property :description, predicate: RDF::DC.description
|
41
|
-
subject.description = "Second in Tove Jansson's series of Moomin books"
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'should create a context' do
|
45
|
-
expect(subject._context).to eq({description: RDF::DC.description.to_uri.to_s})
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'should build an accessor' do
|
49
|
-
expect(subject.description).to eq "Second in Tove Jansson's series of Moomin books"
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
context 'with conflicting property' do
|
54
|
-
before do
|
55
|
-
subject.property :title, predicate: RDF::DC11.title
|
56
|
-
subject.dc11_title = "Kometjakten"
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'should create a context' do
|
60
|
-
expect(subject._context).to eq({dc11_title: RDF::DC11.title.to_uri.to_s})
|
61
|
-
end
|
62
|
-
|
63
|
-
it 'should build an accessor' do
|
64
|
-
expect(subject.dc11_title).to eq "Kometjakten"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
describe '#update_resource' do
|
70
|
-
before do
|
71
|
-
# undefined property
|
72
|
-
subject.property :description, predicate: RDF::DC.description
|
73
|
-
subject.description = "Second in Tove Jansson's series of Moomin books"
|
74
|
-
|
75
|
-
# conflicting property
|
76
|
-
subject.property :title, predicate: RDF::DC11.title
|
77
|
-
subject.dc11_title = "Kometjakten"
|
78
|
-
|
79
|
-
# defined field
|
80
|
-
subject << RDF::Statement(nil, RDF::DC.title, 'Kometen kommer')
|
81
|
-
|
82
|
-
# conflicting property
|
83
|
-
subject << RDF::Statement(nil, RDF::DC.alternative, "Kometjakten")
|
84
|
-
|
85
|
-
# URI value
|
86
|
-
subject << RDF::Statement(nil, RDF::DC.identifier, RDF::URI('http://some.uri'))
|
87
|
-
|
88
|
-
subject.update_resource
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'should have updated values' do
|
92
|
-
expect(subject.resource.statements.count).to eq 5
|
93
|
-
expect(subject.resource.query(predicate: RDF::DC.description, object: "Second in Tove Jansson's series of Moomin books").count).to eq 1
|
94
|
-
expect(subject.resource.query(predicate: RDF::DC11.title, object: "Kometjakten").count).to eq 1
|
95
|
-
expect(subject.resource.query(predicate: RDF::DC.title, object: RDF::Literal.new('Kometen kommer', language: :en)).count).to eq 1
|
96
|
-
expect(subject.resource.query(predicate: RDF::DC.alternative, object: "Kometjakten").count).to eq 1
|
97
|
-
expect(subject.resource.query(predicate: RDF::DC.identifier, object: RDF::URI('http://some.uri')).count).to eq 1
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
describe '#<<' do
|
102
|
-
context 'with defined field' do
|
103
|
-
before do
|
104
|
-
subject << RDF::Statement(nil, RDF::DC.title, 'Kometen kommer')
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'should not create a context' do
|
108
|
-
expect(subject._context).to be nil
|
109
|
-
end
|
110
|
-
|
111
|
-
it 'should update existing values' do
|
112
|
-
expect(subject.title).to eq 'Kometen kommer'
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
context 'with undefined field' do
|
117
|
-
before do
|
118
|
-
subject << RDF::Statement(nil, RDF::DC.description, "Second in Tove Jansson's series of Moomin books")
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'should create a context' do
|
122
|
-
expect(subject._context).to eq({ description: RDF::DC.description.to_uri.to_s })
|
123
|
-
end
|
124
|
-
|
125
|
-
it 'should build an accessor' do
|
126
|
-
expect(subject.description).to eq "Second in Tove Jansson's series of Moomin books"
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
context 'with conflicting property' do
|
131
|
-
before do
|
132
|
-
subject << RDF::Statement(nil, RDF::DC11.title, "Kometjakten")
|
133
|
-
end
|
134
|
-
|
135
|
-
it 'should create a context' do
|
136
|
-
expect(subject._context).to eq({ dc11_title: RDF::DC11.title.to_uri.to_s })
|
137
|
-
end
|
138
|
-
|
139
|
-
it 'should build an accessor' do
|
140
|
-
expect(subject.dc11_title).to eq "Kometjakten"
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
context 'with a URI value' do
|
145
|
-
before do
|
146
|
-
subject << RDF::Statement(nil, RDF::DC.identifier, RDF::URI('http://some.uri'))
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'should store the URI as a string' do
|
150
|
-
expect(subject.identifier).to eq 'http://some.uri'
|
151
|
-
end
|
38
|
+
it_behaves_like 'a Dynamic Resource'
|
39
|
+
end
|
152
40
|
|
153
|
-
|
154
|
-
|
155
|
-
query = subject.resource.query(subject: subject.rdf_subject, predicate: RDF::DC.identifier)
|
156
|
-
expect(query.first_object).to be_a_kind_of RDF::URI
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
describe '#resource_class' do
|
162
|
-
before do
|
163
|
-
subject.property :description, predicate: RDF::DC.description
|
164
|
-
end
|
41
|
+
context 'from JSON-LD' do
|
42
|
+
let(:subject) { Thing.new_from_graph(RDF::Graph.load './spec/shared/graph.jsonld') }
|
165
43
|
|
166
|
-
|
167
|
-
|
168
|
-
end
|
169
|
-
|
170
|
-
it 'should not modify the global class properties' do
|
171
|
-
expect(subject.class.resource_class.properties.keys).to_not include 'description'
|
172
|
-
expect(subject.class.resource_class.properties).to eq subject.class.new.class.resource_class.properties
|
173
|
-
end
|
174
|
-
end
|
44
|
+
it_behaves_like 'a Resource'
|
45
|
+
it_behaves_like 'a Dynamic Resource'
|
175
46
|
end
|
176
|
-
|
177
|
-
end
|
47
|
+
end
|
@@ -10,266 +10,63 @@ describe Ladder::Resource do
|
|
10
10
|
|
11
11
|
class Thing
|
12
12
|
include Ladder::Resource
|
13
|
+
configure type: RDF::DC.BibliographicResource
|
14
|
+
|
15
|
+
field :alt
|
16
|
+
property :alt, predicate: RDF::DC.alternative # non-localized literal
|
17
|
+
property :title, predicate: RDF::DC.title # localized literal
|
18
|
+
property :identifier, predicate: RDF::DC.identifier
|
13
19
|
end
|
14
20
|
end
|
15
21
|
|
16
22
|
after do
|
17
23
|
Object.send(:remove_const, :LADDER_BASE_URI) if Object
|
18
|
-
Object.send(:remove_const,
|
19
|
-
end
|
20
|
-
|
21
|
-
shared_context 'with data' do
|
22
|
-
before do
|
23
|
-
subject.class.configure type: RDF::DC.BibliographicResource
|
24
|
-
|
25
|
-
# non-localized literal
|
26
|
-
subject.class.field :alt
|
27
|
-
subject.class.property :alt, predicate: RDF::DC.alternative
|
28
|
-
subject.alt = 'Mumintrollet pa kometjakt'
|
29
|
-
|
30
|
-
# localized literal
|
31
|
-
subject.class.property :title, predicate: RDF::DC.title
|
32
|
-
subject.title = 'Comet in Moominland'
|
33
|
-
end
|
24
|
+
Object.send(:remove_const, 'Thing') if Object
|
34
25
|
end
|
35
26
|
|
36
27
|
shared_context 'with relations' do
|
37
28
|
let(:person) { Person.new }
|
38
29
|
let(:concept) { Concept.new }
|
39
30
|
let(:part) { Part.new }
|
40
|
-
|
31
|
+
|
41
32
|
before do
|
42
33
|
class Person
|
43
34
|
include Ladder::Resource
|
35
|
+
configure type: RDF::DC.AgentClass
|
36
|
+
|
37
|
+
property :things, predicate: RDF::DC.relation, class_name: 'Thing'
|
44
38
|
end
|
45
39
|
|
46
40
|
class Concept
|
47
41
|
include Ladder::Resource
|
42
|
+
configure type: RDF::SKOS.Concept
|
48
43
|
end
|
49
44
|
|
50
45
|
class Part
|
51
46
|
include Ladder::Resource
|
52
|
-
|
47
|
+
configure type: RDF::DC.PhysicalResource
|
53
48
|
|
54
|
-
|
55
|
-
|
56
|
-
|
49
|
+
embedded_in :thing
|
50
|
+
property :thing, predicate: RDF::DC.relation, class_name: 'Thing'
|
51
|
+
end
|
57
52
|
|
58
53
|
# many-to-many
|
59
|
-
|
60
|
-
subject.class.property :people, predicate: RDF::DC.creator, class_name: 'Person'
|
61
|
-
subject.people << person
|
54
|
+
Thing.property :people, predicate: RDF::DC.creator, class_name: 'Person'
|
62
55
|
|
63
56
|
# one-sided has-many
|
64
|
-
|
65
|
-
|
66
|
-
subject.concepts << concept
|
57
|
+
Thing.has_and_belongs_to_many :concepts, inverse_of: nil, autosave: true
|
58
|
+
Thing.property :concepts, predicate: RDF::DC.subject, class_name: 'Concept'
|
67
59
|
|
68
60
|
# embedded one
|
69
|
-
|
70
|
-
|
71
|
-
subject.class.embeds_one :part, cascade_callbacks: true
|
72
|
-
subject.class.property :part, predicate: RDF::DC.hasPart, class_name: 'Part'
|
73
|
-
subject.part = part
|
74
|
-
subject.save
|
61
|
+
Thing.embeds_one :part, cascade_callbacks: true
|
62
|
+
Thing.property :part, predicate: RDF::DC.hasPart, class_name: 'Part'
|
75
63
|
end
|
76
64
|
|
77
65
|
after do
|
78
|
-
Object.send(:remove_const,
|
66
|
+
Object.send(:remove_const, 'Person') if Object
|
79
67
|
Object.send(:remove_const, 'Concept') if Object
|
80
68
|
Object.send(:remove_const, 'Part') if Object
|
81
69
|
end
|
82
|
-
|
83
|
-
it 'should have relations' do
|
84
|
-
expect(subject.people.to_a).to include person
|
85
|
-
expect(subject.concepts.to_a).to include concept
|
86
|
-
expect(subject.part).to eq part
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'should have inverse relations' do
|
90
|
-
expect(person.things.to_a).to include subject
|
91
|
-
expect(concept.relations).to be_empty
|
92
|
-
expect(part.thing).to eq subject
|
93
|
-
end
|
94
|
-
|
95
|
-
context 'with many-to-many' do
|
96
|
-
it 'should have a relation' do
|
97
|
-
expect(subject.relations['people'].relation).to eq (Mongoid::Relations::Referenced::ManyToMany)
|
98
|
-
expect(subject.people.to_a).to include person
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'should have an inverse relation' do
|
102
|
-
expect(person.relations['things'].relation).to eq (Mongoid::Relations::Referenced::ManyToMany)
|
103
|
-
expect(person.things.to_a).to include subject
|
104
|
-
end
|
105
|
-
|
106
|
-
it 'should have a valid predicate' do
|
107
|
-
expect(subject.class.properties['people'].predicate).to eq RDF::DC.creator
|
108
|
-
end
|
109
|
-
|
110
|
-
it 'should have a valid inverse predicate' do
|
111
|
-
expect(person.class.properties['things'].predicate).to eq RDF::DC.relation
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
context 'with one-sided has-many' do
|
116
|
-
it 'should have a relation' do
|
117
|
-
expect(subject.relations['concepts'].relation).to eq (Mongoid::Relations::Referenced::ManyToMany)
|
118
|
-
expect(subject.concepts.to_a).to include concept
|
119
|
-
end
|
120
|
-
|
121
|
-
it 'should not have an inverse relation' do
|
122
|
-
expect(subject.relations['concepts'].inverse_of).to be nil
|
123
|
-
expect(concept.relations).to be_empty
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'should have a valid predicate' do
|
127
|
-
expect(subject.class.properties['concepts'].predicate).to eq RDF::DC.subject
|
128
|
-
end
|
129
|
-
|
130
|
-
it 'should not have an inverse predicate' do
|
131
|
-
expect(concept.class.properties).to be_empty
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
context 'with embedded-one' do
|
136
|
-
it 'should have a relation' do
|
137
|
-
expect(subject.relations['part'].relation).to eq (Mongoid::Relations::Embedded::One)
|
138
|
-
expect(subject.part).to eq part
|
139
|
-
end
|
140
|
-
|
141
|
-
it 'should have an inverse relation' do
|
142
|
-
expect(part.relations['thing'].relation).to eq (Mongoid::Relations::Embedded::In)
|
143
|
-
expect(part.thing).to eq subject
|
144
|
-
end
|
145
|
-
|
146
|
-
it 'should have a valid predicate' do
|
147
|
-
expect(subject.class.properties['part'].predicate).to eq RDF::DC.hasPart
|
148
|
-
end
|
149
|
-
|
150
|
-
it 'should have a valid inverse predicate' do
|
151
|
-
expect(part.class.properties['thing'].predicate).to eq RDF::DC.relation
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
context '#update_resource with related' do
|
156
|
-
# TODO add tests for autosaved relations
|
157
|
-
before do
|
158
|
-
subject.update_resource(related: true)
|
159
|
-
end
|
160
|
-
|
161
|
-
it 'should have a literal object' do
|
162
|
-
query = subject.resource.query(subject: subject.rdf_subject, predicate: RDF::DC.title)
|
163
|
-
expect(query.first_object.to_s).to eq 'Comet in Moominland'
|
164
|
-
end
|
165
|
-
|
166
|
-
it 'should have an embedded object' do
|
167
|
-
query = subject.resource.query(subject: subject.rdf_subject, predicate: RDF::DC.hasPart)
|
168
|
-
expect(query.count).to eq 1
|
169
|
-
expect(query.first_object).to eq part.rdf_subject
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'should have an embedded object relation' do
|
173
|
-
query = subject.resource.query(subject: part.rdf_subject, predicate: RDF::DC.relation)
|
174
|
-
expect(query.count).to eq 1
|
175
|
-
expect(query.first_object).to eq subject.rdf_subject
|
176
|
-
end
|
177
|
-
|
178
|
-
it 'should have related objects' do
|
179
|
-
# many-to-many
|
180
|
-
query_creator = subject.resource.query(subject: subject.rdf_subject, predicate: RDF::DC.creator)
|
181
|
-
expect(query_creator.count).to eq 1
|
182
|
-
expect(query_creator.first_object).to eq person.rdf_subject
|
183
|
-
|
184
|
-
# one-sided has-many
|
185
|
-
query_subject = subject.resource.query(subject: subject.rdf_subject, predicate: RDF::DC.subject)
|
186
|
-
expect(query_subject.count).to eq 1
|
187
|
-
expect(query_subject.first_object).to eq concept.rdf_subject
|
188
|
-
|
189
|
-
# embedded-one
|
190
|
-
query_part = subject.resource.query(subject: subject.rdf_subject, predicate: RDF::DC.hasPart)
|
191
|
-
expect(query_part.count).to eq 1
|
192
|
-
expect(query_part.first_object).to eq part.rdf_subject
|
193
|
-
end
|
194
|
-
|
195
|
-
it 'should have related object relations' do
|
196
|
-
# many-to-many
|
197
|
-
query = person.resource.query(subject: person.rdf_subject, predicate: RDF::DC.relation)
|
198
|
-
expect(query.count).to eq 1
|
199
|
-
expect(query.first_object).to eq subject.rdf_subject
|
200
|
-
|
201
|
-
# one-sided has-many
|
202
|
-
expect(concept.resource.query(object: subject.rdf_subject)).to be_empty
|
203
|
-
|
204
|
-
# embedded-one
|
205
|
-
query = part.resource.query(subject: part.rdf_subject, predicate: RDF::DC.relation)
|
206
|
-
expect(query.count).to eq 1
|
207
|
-
expect(query.first_object).to eq subject.rdf_subject
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
context '#update_resource with related and then without related' do
|
212
|
-
# TODO add tests for autosaved relations
|
213
|
-
before do
|
214
|
-
subject.update_resource(related: true)
|
215
|
-
subject.update_resource # implicit false
|
216
|
-
end
|
217
|
-
|
218
|
-
it 'should not have related objects' do
|
219
|
-
expect(subject.resource.query(subject: person.rdf_subject)).to be_empty
|
220
|
-
expect(subject.resource.query(subject: concept.rdf_subject)).to be_empty
|
221
|
-
end
|
222
|
-
|
223
|
-
it 'should have embedded object relations' do
|
224
|
-
query = subject.resource.query(subject: part.rdf_subject, predicate: RDF::DC.relation)
|
225
|
-
expect(query.count).to eq 1
|
226
|
-
expect(query.first_object).to eq subject.rdf_subject
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'should have related object relations' do
|
230
|
-
# many-to-many
|
231
|
-
query = person.resource.query(subject: person.rdf_subject, predicate: RDF::DC.relation)
|
232
|
-
expect(query.count).to eq 1
|
233
|
-
expect(query.first_object).to eq subject.rdf_subject
|
234
|
-
|
235
|
-
# one-sided has-many
|
236
|
-
expect(concept.resource.query(object: subject.rdf_subject)).to be_empty
|
237
|
-
|
238
|
-
# embedded-one
|
239
|
-
query = part.resource.query(subject: part.rdf_subject, predicate: RDF::DC.relation)
|
240
|
-
expect(query.count).to eq 1
|
241
|
-
expect(query.first_object).to eq subject.rdf_subject
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
context 'serializable' do
|
246
|
-
# TODO: contexts with relations and without
|
247
|
-
# expect(subject.as_jsonld(related: true)).to eq subject.as_jsonld
|
248
|
-
# expect(subject.as_qname(related: true)).to eq subject.as_qname
|
249
|
-
# expect(subject.as_framed_jsonld).to eq subject.as_jsonld
|
250
|
-
|
251
|
-
describe '#as_jsonld related: true' do
|
252
|
-
it 'should output a valid jsonld representation of itself and related' do
|
253
|
-
graph = RDF::Graph.new << JSON::LD::API.toRdf(subject.as_jsonld related: true)
|
254
|
-
expect(subject.update_resource(related: true).to_hash).to eq graph.to_hash
|
255
|
-
end
|
256
|
-
end
|
257
|
-
|
258
|
-
describe '#as_qname related: true' do
|
259
|
-
it 'should output a valid qname representation of itself and related' do
|
260
|
-
# TODO
|
261
|
-
end
|
262
|
-
end
|
263
|
-
|
264
|
-
describe '#as_framed_jsonld' do
|
265
|
-
it 'should output a valid framed jsonld representation of itself and related' do
|
266
|
-
framed_graph = RDF::Graph.new << JSON::LD::API.toRdf(subject.as_framed_jsonld)
|
267
|
-
related_graph = RDF::Graph.new << JSON::LD::API.toRdf(subject.as_jsonld related: true)
|
268
|
-
expect(framed_graph.to_hash).to eq related_graph.to_hash
|
269
|
-
end
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
70
|
end
|
274
71
|
|
275
72
|
context 'with data' do
|
@@ -286,7 +83,31 @@ describe Ladder::Resource do
|
|
286
83
|
include_context 'with data'
|
287
84
|
include_context 'with relations'
|
288
85
|
|
86
|
+
before do
|
87
|
+
subject.people << person # many-to-many
|
88
|
+
subject.concepts << concept # one-sided has-many
|
89
|
+
subject.part = part # embedded one
|
90
|
+
subject.save
|
91
|
+
end
|
92
|
+
|
289
93
|
it_behaves_like 'a Resource'
|
94
|
+
it_behaves_like 'a Resource with relations'
|
290
95
|
end
|
291
96
|
|
292
|
-
|
97
|
+
context 'from JSON-LD' do
|
98
|
+
let(:subject) { Thing.new_from_graph(RDF::Graph.load './spec/shared/graph.jsonld') }
|
99
|
+
|
100
|
+
include_context 'with relations'
|
101
|
+
|
102
|
+
let(:person) { subject.people.first }
|
103
|
+
let(:concept) { subject.concepts.first }
|
104
|
+
let(:part) { subject.part }
|
105
|
+
|
106
|
+
before do
|
107
|
+
subject.save
|
108
|
+
end
|
109
|
+
|
110
|
+
it_behaves_like 'a Resource'
|
111
|
+
it_behaves_like 'a Resource with relations'
|
112
|
+
end
|
113
|
+
end
|