active-triples 0.11.0 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+ require 'spec_helper'
3
+
4
+ describe ActiveTriples::NodeConfig do
5
+ subject(:config) { described_class.new(term, predicate) }
6
+ let(:predicate) { RDF::URI(nil) }
7
+ let(:term) { :moomin }
8
+
9
+ it { is_expected.to have_attributes(predicate: predicate, term: term) }
10
+
11
+ describe '#[]' do
12
+ subject(:config) { described_class.new(term, predicate, some_opt: :moomin) }
13
+
14
+ it 'accesses arbitrary opts' do
15
+ expect(config[:some_opt]).to eq :moomin
16
+ end
17
+ end
18
+
19
+ describe '#cast' do
20
+ it 'defaults to true' do
21
+ expect { config.cast = false }
22
+ .to change { config.cast }
23
+ .from(true)
24
+ .to(false)
25
+ end
26
+
27
+ it 'is set with the initializer' do
28
+ expect(described_class.new(term, predicate, cast: false).cast).to be false
29
+ end
30
+ end
31
+
32
+ describe '#with_index' do
33
+ it 'yields an index configuration object' do
34
+ expect { |b| config.with_index(&b) }
35
+ .to yield_with_args(an_instance_of(described_class::IndexObject))
36
+ end
37
+
38
+ it 'accepts behavior settings' do
39
+ config.with_index do |index|
40
+ index.as :moomin, :snork
41
+ end
42
+
43
+ expect(config.behaviors).to contain_exactly :moomin, :snork
44
+ end
45
+
46
+ it 'accepts type settings' do
47
+ config.with_index do |index|
48
+ index.type :moomin
49
+ end
50
+
51
+ expect(config.type).to eq :moomin
52
+ end
53
+ end
54
+ end
@@ -4,7 +4,7 @@ require 'spec_helper'
4
4
  describe ActiveTriples::ParentStrategy do
5
5
  subject { described_class.new(rdf_source) }
6
6
  let(:rdf_source) { BasicPersistable.new }
7
-
7
+
8
8
  shared_context 'with a parent' do
9
9
  subject { rdf_source.persistence_strategy }
10
10
  let(:parent) { BasicPersistable.new }
@@ -50,7 +50,7 @@ describe ActiveTriples::ParentStrategy do
50
50
  rdf_source.insert(*statements)
51
51
  subject.persist!
52
52
  end
53
-
53
+
54
54
  let(:statements) do
55
55
  [RDF::Statement(subject.source.rdf_subject, RDF::Vocab::DC.title, 'moomin'),
56
56
  RDF::Statement(subject.parent, RDF::Vocab::DC.relation, subject.source.rdf_subject)]
@@ -58,7 +58,7 @@ describe ActiveTriples::ParentStrategy do
58
58
 
59
59
  it 'removes graph from the parent' do
60
60
  subject.destroy
61
-
61
+
62
62
  statements.each do |statement|
63
63
  expect(subject.parent.statements).not_to have_statement statement
64
64
  end
@@ -83,18 +83,18 @@ describe ActiveTriples::ParentStrategy do
83
83
 
84
84
  context 'with parent' do
85
85
  include_context 'with a parent'
86
-
86
+
87
87
  it 'gives the parent' do
88
88
  expect(subject.ancestors).to contain_exactly(parent)
89
89
  end
90
90
 
91
91
  context 'and nested parents' do
92
92
  let(:parents) do
93
- [double('second', persistence_strategy: double('strategy2')),
93
+ [double('second', persistence_strategy: double('strategy2')),
94
94
  double('third', persistence_strategy: double('strategy3'))]
95
95
  end
96
96
  let(:last) { double('last', persistence_strategy: double('last_strategy')) }
97
-
97
+
98
98
  it 'gives all ancestors' do
99
99
  allow(parent.persistence_strategy)
100
100
  .to receive(:parent).and_return(parents.first)
@@ -102,7 +102,7 @@ describe ActiveTriples::ParentStrategy do
102
102
  .to receive(:parent).and_return(parents[1])
103
103
  allow(parents[1].persistence_strategy)
104
104
  .to receive(:parent).and_return(last)
105
-
105
+
106
106
  expect(subject.ancestors)
107
107
  .to contain_exactly(*(parents << parent << last))
108
108
  end
@@ -148,7 +148,19 @@ describe ActiveTriples::ParentStrategy do
148
148
  describe '#parent' do
149
149
  it { is_expected.to have_attributes(:parent => nil) }
150
150
 
151
- it 'requires its parent to be RDF::Mutable' do
151
+ context 'with a parent' do
152
+ include_context 'with a parent'
153
+ it { is_expected.to have_attributes(:parent => parent) }
154
+ end
155
+ end
156
+
157
+ describe '#parent=' do
158
+ it 'requires a non-nil value' do
159
+ expect { subject.parent = nil }
160
+ .to raise_error described_class::NilParentError
161
+ end
162
+
163
+ it 'requires the value to be RDF::Mutable' do
152
164
  expect { subject.parent = Object.new }
153
165
  .to raise_error described_class::UnmutableParentError
154
166
  end
@@ -159,11 +171,6 @@ describe ActiveTriples::ParentStrategy do
159
171
  expect { subject.parent = immutable }
160
172
  .to raise_error described_class::UnmutableParentError
161
173
  end
162
-
163
- context 'with a parent' do
164
- include_context 'with a parent'
165
- it { is_expected.to have_attributes(:parent => parent) }
166
- end
167
174
  end
168
175
 
169
176
  describe '#persist!' do
@@ -205,7 +212,7 @@ describe ActiveTriples::ParentStrategy do
205
212
  parent.persistence_strategy.parent = last
206
213
  rdf_source.reload
207
214
  end
208
-
215
+
209
216
  it 'writes to #parent graph when parent changes while child is live' do
210
217
  parent.insert(parent_st)
211
218
  parent.persist!
@@ -248,16 +255,16 @@ describe ActiveTriples::ParentStrategy::Ancestors do
248
255
  context 'with parents' do
249
256
  let(:parent) { BasicPersistable.new }
250
257
  let(:last) { BasicPersistable.new }
251
-
258
+
252
259
  before do
253
260
  parent.set_persistence_strategy(ActiveTriples::ParentStrategy)
254
261
  parent.persistence_strategy.parent = last
255
262
  rdf_source.set_persistence_strategy(ActiveTriples::ParentStrategy)
256
263
  rdf_source.persistence_strategy.parent = parent
257
264
  end
258
-
265
+
259
266
  it { expect(subject.each).to be_a Enumerator }
260
-
267
+
261
268
  it 'enumerates ancestors' do
262
269
  expect(subject.each).to contain_exactly(parent, last)
263
270
  end
@@ -17,6 +17,16 @@ describe ActiveTriples::Property do
17
17
  expect(subject.class_name).to eq "Test"
18
18
  end
19
19
 
20
+ it 'should hold a block' do
21
+ fake = Object.new
22
+ property = described_class.new(options) do
23
+ fake.configure
24
+ end
25
+
26
+ expect(fake).to receive(:configure)
27
+ property.config.call
28
+ end
29
+
20
30
  describe "#to_h" do
21
31
  it "should not return the property's name" do
22
32
  expect(subject.to_h).to eq (
@@ -18,8 +18,9 @@ describe ActiveTriples::RDFSource do
18
18
  end
19
19
 
20
20
  before { @enumerable = subject }
21
+
21
22
  let(:source_class) { Class.new { include ActiveTriples::RDFSource } }
22
- let(:uri) { RDF::URI('http://example.org/moomin') }
23
+ let(:uri) { RDF::URI('http://example.org/moomin') }
23
24
 
24
25
  subject { source_class.new }
25
26
 
@@ -107,6 +108,45 @@ describe ActiveTriples::RDFSource do
107
108
  end
108
109
  end
109
110
 
111
+ describe 'observers' do
112
+ let(:observer) { double('observer') }
113
+
114
+ before { subject.add_observer(observer) }
115
+
116
+ include_context 'with properties'
117
+
118
+ it 'notifies an observer of changes' do
119
+ expect(observer)
120
+ .to receive(:notify)
121
+ .with(:creator, a_collection_containing_exactly('moomin'))
122
+
123
+ subject.creator = 'moomin'
124
+ end
125
+
126
+ it 'notifies muliple observers of changes' do
127
+ other_observer = double('second observer')
128
+ values = ['moomin', 'snork']
129
+
130
+ expect(observer)
131
+ .to receive(:notify)
132
+ .with(:creator, a_collection_containing_exactly(*values))
133
+ expect(other_observer)
134
+ .to receive(:notify)
135
+ .with(:creator, a_collection_containing_exactly(*values))
136
+
137
+ subject.add_observer(other_observer)
138
+ subject.creator = values
139
+ end
140
+
141
+ it 'does not notify removed observers' do
142
+ expect(observer).not_to receive(:notify)
143
+
144
+ subject.delete_observer(observer)
145
+
146
+ subject.creator = 'moomin'
147
+ end
148
+ end
149
+
110
150
  describe '#==' do
111
151
  shared_examples 'Term equality' do
112
152
  it 'equals itself' do
@@ -172,9 +212,9 @@ describe ActiveTriples::RDFSource do
172
212
 
173
213
  context 'with statements for other subjects' do
174
214
  before do
175
- subject <<
215
+ subject <<
176
216
  RDF::Statement(RDF::URI('http://example.org/OTHER_SUBJECT'),
177
- RDF::URI('http://example.org/ontology/OTHER_PRED'),
217
+ RDF::URI('http://example.org/ontology/OTHER_PRED'),
178
218
  'OTHER_OBJECT')
179
219
  end
180
220
 
@@ -191,6 +231,16 @@ describe ActiveTriples::RDFSource do
191
231
  end
192
232
  end
193
233
 
234
+ describe '#default_labels' do
235
+ it 'prefers skos:prefLabel' do
236
+ expect(subject.default_labels.first).to eq RDF::Vocab::SKOS.prefLabel
237
+ end
238
+
239
+ it 'values are all valid predicates' do
240
+ subject.default_labels.each { |term| expect(term).to be_uri }
241
+ end
242
+ end
243
+
194
244
  describe '#fetch' do
195
245
  it 'raises an error when it is a node' do
196
246
  expect { subject.fetch }
@@ -271,6 +321,18 @@ describe ActiveTriples::RDFSource do
271
321
  end
272
322
  end
273
323
 
324
+ describe '#inspect' do
325
+ it 'includes bnode id' do
326
+ expect(subject.inspect).to include subject.to_base
327
+ end
328
+
329
+ it 'includes uri' do
330
+ subject.set_subject!('http://example.org/moomin')
331
+
332
+ expect(subject.inspect).to include subject.to_base
333
+ end
334
+ end
335
+
274
336
  describe '#rdf_subject' do
275
337
  its(:rdf_subject) { is_expected.to be_a_node }
276
338
 
@@ -373,6 +435,7 @@ describe ActiveTriples::RDFSource do
373
435
 
374
436
  shared_examples 'setting values' do
375
437
  include_context 'with properties'
438
+
376
439
  after do
377
440
  Object.send(:remove_const, 'SourceWithCreator') if
378
441
  defined? SourceWithCreator
@@ -473,6 +536,39 @@ describe ActiveTriples::RDFSource do
473
536
  end
474
537
  end
475
538
 
539
+ describe 'on child nodes' do
540
+ let(:parent) { source_class.new }
541
+ let(:subject) { source_class.new(uri, parent) }
542
+
543
+ include_examples 'setting values' do
544
+ let(:value) do
545
+ ['moomin',
546
+ Date.today,
547
+ RDF::Node.new,
548
+ source_class.new,
549
+ source_class.new(uri / 'new'),
550
+ subject]
551
+ end
552
+ end
553
+
554
+ it 'does not change parent' do
555
+ property = RDF::Vocab::DC.title
556
+
557
+ expect { subject.set_value(property, 'Comet in Moominland') }
558
+ .not_to change { parent.to_a }
559
+ end
560
+
561
+ it 'persists to parent' do
562
+ property = RDF::Vocab::DC.title
563
+
564
+ subject.set_value(property, 'Comet in Moominland')
565
+
566
+ expect { subject.persist! }
567
+ .to change { parent.to_a }
568
+ .to include RDF::Statement(subject, property, 'Comet in Moominland')
569
+ end
570
+ end
571
+
476
572
  context 'with reciprocal relations' do
477
573
  let(:document) { source_class.new }
478
574
  let(:person) { source_class.new }
@@ -550,15 +646,15 @@ describe ActiveTriples::RDFSource do
550
646
  expect { subject.set_value(predicate, child_other) }
551
647
  .not_to change { child_other.persistence_strategy.parent }
552
648
  end
553
-
649
+
554
650
  context 'when setting to a relation' do
555
651
  it 'adds child node data to graph' do
556
652
  other << RDF::Statement(other, RDF::URI('p'), 'o')
557
-
558
- relation_source = source_class.new
653
+
654
+ relation_source = source_class.new
559
655
  relation_source.set_value(predicate, other)
560
656
  relation = relation_source.get_values(predicate)
561
-
657
+
562
658
  expect { subject.set_value(predicate, relation) }
563
659
  .to change { subject.statements.to_a }
564
660
  .to include(*other.statements.to_a)
@@ -673,119 +769,4 @@ describe ActiveTriples::RDFSource do
673
769
  expect { dummy_source.new.test_title }.not_to raise_error
674
770
  end
675
771
  end
676
-
677
- describe 'sources with properties with class_name defined' do
678
- before(:context) do
679
- class DummyChapter < ActiveTriples::Resource
680
- ontology = RDF::URI('http://www.example.com/ontology')
681
- type = RDF::URI('http://www.example.com/type')
682
-
683
- configure repository: :default, type: type / 'Chapter'
684
-
685
- property :title, predicate: ontology / 'title'
686
- property :subtitle, predicate: ontology / 'subtitle'
687
- end
688
-
689
- class DummyBook < ActiveTriples::Resource
690
- ontology = RDF::URI('http://www.example.com/ontology')
691
- type = RDF::URI('http://www.example.com/type')
692
-
693
- configure repository: :default, type: type / 'Book'
694
-
695
- property :title, predicate: ontology / 'title'
696
- property :has_chapter, predicate: ontology / 'hasChapter',
697
- class_name: DummyChapter
698
- end
699
- end
700
-
701
- context 'when loading models from graph' do
702
- before(:context) do
703
- r = RDF::Repository.new
704
- ActiveTriples::Repositories.repositories[:default] = r
705
-
706
- @book_url = 'http://www.example.com/BOOK_URI'
707
- @book_title = 'Example Book.'
708
- @chapter_title = 'Chapter 1'
709
- ttl = "<#{@book_url}> a <http://www.example.com/type/Book>;
710
- <http://www.example.com/ontology/hasChapter> [
711
- a <http://www.example.com/type/Chapter>;
712
- <http://www.example.com/ontology/title> \"#{@chapter_title}\"
713
- ];
714
- <http://www.example.com/ontology/title> \"#{@book_title}\" ."
715
- book_graph = ::RDF::Graph.new.from_ttl ttl
716
- r = ActiveTriples::Repositories.repositories[:default]
717
- r << book_graph
718
-
719
- @book = DummyBook.new(RDF::URI.new(@book_url))
720
- end
721
-
722
- it 'populates DummyBook properly' do
723
- expect(@book.rdf_subject.to_s).to eq @book_url
724
- expect(@book).to be_a DummyBook
725
- expect(@book.type)
726
- .to include(RDF::URI.new('http://www.example.com/type/Book'))
727
- expect(@book.title.first).to eq @book_title
728
- end
729
-
730
- it 'populates DummyChapter properly' do
731
- chapter = @book.has_chapter.first
732
- expect(chapter).to be_a DummyChapter
733
- expect(chapter.title.first).to eq @chapter_title
734
- expect(chapter.type)
735
- .to include(RDF::URI.new('http://www.example.com/type/Chapter'))
736
- end
737
- end
738
-
739
- context 'when loading models through properties' do
740
- before(:context) do
741
- r = RDF::Repository.new
742
- ActiveTriples::Repositories.repositories[:default] = r
743
-
744
- bk1 = DummyBook.new('http://www.example.com/book1')
745
- bk1.title = 'Learning about Explicit Links in ActiveTriples'
746
-
747
- ch1 = DummyChapter.new('http://www.example.com/book1/chapter1')
748
- ch1.title = 'Defining a source with an Explicit Link'
749
- bk1.has_chapter = ch1
750
- ch1.persist!
751
- bk1.persist!
752
-
753
- @bk1 = DummyBook.new('http://www.example.com/book1')
754
- @ch1 = DummyChapter.new('http://www.example.com/book1/chapter1')
755
- end
756
-
757
- it 'populates DummyBook (resumed resource) properly' do
758
- expect(@bk1.type.first)
759
- .to eq RDF::URI('http://www.example.com/type/Book')
760
- expect(@bk1.title.first)
761
- .to eq 'Learning about Explicit Links in ActiveTriples'
762
- end
763
-
764
- it 'populates DummyChapter (property resource) properly' do
765
- ch1 = @bk1.has_chapter.first
766
- expect(ch1.type.first)
767
- .to eq RDF::URI('http://www.example.com/type/Chapter')
768
- expect(ch1.title.first)
769
- .to eq 'Defining a source with an Explicit Link'
770
- end
771
-
772
- it 'populates DummyChapter (directly from repository) properly' do
773
- expect(@ch1.type.first)
774
- .to eq RDF::URI('http://www.example.com/type/Chapter')
775
- expect(@ch1.title.first)
776
- .to eq 'Defining a source with an Explicit Link'
777
- end
778
-
779
- it 'does not reload from repository twice' do
780
- ch1 = @bk1.has_chapter.first
781
- expect(ch1.title.first).to eq 'Defining a source with an Explicit Link'
782
-
783
- @ch1.subtitle = 'Changed after original load'
784
- @ch1.persist!
785
- expect(@ch1.subtitle).to eq ['Changed after original load']
786
-
787
- expect(ch1.subtitle).to eq []
788
- end
789
- end
790
- end
791
772
  end