active-triples 0.10.2 → 0.11.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/CHANGES.md +17 -11
- data/README.md +72 -39
- data/lib/active_triples/configurable.rb +6 -1
- data/lib/active_triples/list.rb +1 -4
- data/lib/active_triples/nested_attributes.rb +10 -7
- data/lib/active_triples/persistable.rb +13 -0
- data/lib/active_triples/persistence_strategies/parent_strategy.rb +47 -34
- data/lib/active_triples/persistence_strategies/persistence_strategy.rb +14 -1
- data/lib/active_triples/properties.rb +19 -4
- data/lib/active_triples/property_builder.rb +4 -4
- data/lib/active_triples/rdf_source.rb +142 -189
- data/lib/active_triples/relation.rb +307 -156
- data/lib/active_triples/util/buffered_transaction.rb +126 -0
- data/lib/active_triples/util/extended_bounded_description.rb +75 -0
- data/lib/active_triples/version.rb +1 -1
- data/spec/active_triples/configurable_spec.rb +35 -7
- data/spec/active_triples/identifiable_spec.rb +19 -6
- data/spec/active_triples/list_spec.rb +15 -7
- data/spec/active_triples/nested_attributes_spec.rb +12 -10
- data/spec/active_triples/persistable_spec.rb +0 -4
- data/spec/active_triples/persistence_strategies/parent_strategy_spec.rb +57 -10
- data/spec/active_triples/rdf_source_spec.rb +137 -97
- data/spec/active_triples/relation_spec.rb +436 -132
- data/spec/active_triples/resource_spec.rb +8 -23
- data/spec/active_triples/util/buffered_transaction_spec.rb +187 -0
- data/spec/active_triples/util/extended_bounded_description_spec.rb +98 -0
- data/spec/integration/reciprocal_properties_spec.rb +10 -10
- data/spec/support/matchers.rb +13 -1
- metadata +7 -3
@@ -41,14 +41,12 @@ describe ActiveTriples::RDFSource do
|
|
41
41
|
it { is_expected.to be_queryable }
|
42
42
|
it { is_expected.to be_countable }
|
43
43
|
it { is_expected.to be_a_value }
|
44
|
-
# it { is_expected.to be_a_term }
|
45
|
-
# it { is_expected.to be_a_resource }
|
46
44
|
|
47
45
|
let(:enumerable) { source_class.new }
|
48
46
|
it_behaves_like 'an RDF::Enumerable'
|
49
47
|
|
50
48
|
let(:queryable) { enumerable }
|
51
|
-
|
49
|
+
it_behaves_like 'an RDF::Queryable'
|
52
50
|
|
53
51
|
let(:countable) { enumerable }
|
54
52
|
it_behaves_like 'an RDF::Countable'
|
@@ -152,7 +150,7 @@ describe ActiveTriples::RDFSource do
|
|
152
150
|
subject.creator = 'moomin'
|
153
151
|
expect(subject.attributes['creator']).to contain_exactly 'moomin'
|
154
152
|
end
|
155
|
-
|
153
|
+
|
156
154
|
it 'has unregistered properties' do
|
157
155
|
predicate = RDF::OWL.sameAs
|
158
156
|
subject << [subject, predicate, 'moomin']
|
@@ -174,16 +172,25 @@ describe ActiveTriples::RDFSource do
|
|
174
172
|
|
175
173
|
context 'with statements for other subjects' do
|
176
174
|
before do
|
177
|
-
subject <<
|
175
|
+
subject <<
|
176
|
+
RDF::Statement(RDF::URI('http://example.org/OTHER_SUBJECT'),
|
177
|
+
RDF::URI('http://example.org/ontology/OTHER_PRED'),
|
178
|
+
'OTHER_OBJECT')
|
178
179
|
end
|
179
180
|
|
180
|
-
it
|
181
|
+
it 'excludes values for statements not matching rdf_subject' do
|
181
182
|
expect(subject.attributes.keys).not_to include 'http://example.org/ontology/OTHER_PRED'
|
182
183
|
expect(subject.attributes.values).not_to include ['OTHER_OBJECT']
|
183
184
|
end
|
184
185
|
end
|
185
186
|
end
|
186
187
|
|
188
|
+
describe '#attributes=' do
|
189
|
+
it 'raises an error when not passed a hash' do
|
190
|
+
expect { subject.attributes = true }.to raise_error ArgumentError
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
187
194
|
describe '#fetch' do
|
188
195
|
it 'raises an error when it is a node' do
|
189
196
|
expect { subject.fetch }
|
@@ -195,7 +202,7 @@ describe ActiveTriples::RDFSource do
|
|
195
202
|
subject { source_class.new(uri) }
|
196
203
|
|
197
204
|
context 'with a bad link' do
|
198
|
-
before { stub_request(:get, uri).to_return(:
|
205
|
+
before { stub_request(:get, uri).to_return(status: 404) }
|
199
206
|
|
200
207
|
it 'raises an error if no block is given' do
|
201
208
|
expect { subject.fetch }.to raise_error IOError
|
@@ -208,8 +215,7 @@ describe ActiveTriples::RDFSource do
|
|
208
215
|
|
209
216
|
context 'with a working link' do
|
210
217
|
before do
|
211
|
-
stub_request(:get, uri).to_return(:
|
212
|
-
:body => graph.dump(:ttl))
|
218
|
+
stub_request(:get, uri).to_return(status: 200, body: graph.dump(:ttl))
|
213
219
|
end
|
214
220
|
|
215
221
|
let(:graph) { RDF::Graph.new << statement }
|
@@ -221,8 +227,8 @@ describe ActiveTriples::RDFSource do
|
|
221
227
|
it 'loads retrieved graph into its own' do
|
222
228
|
expect { subject.fetch }
|
223
229
|
.to change { subject.statements.to_a }
|
224
|
-
|
225
|
-
|
230
|
+
.from(a_collection_containing_exactly)
|
231
|
+
.to(a_collection_containing_exactly(statement))
|
226
232
|
end
|
227
233
|
|
228
234
|
it 'merges retrieved graph into its own' do
|
@@ -231,15 +237,18 @@ describe ActiveTriples::RDFSource do
|
|
231
237
|
|
232
238
|
expect { subject.fetch }
|
233
239
|
.to change { subject.statements.to_a }
|
234
|
-
|
235
|
-
|
240
|
+
.from(a_collection_containing_exactly(existing))
|
241
|
+
.to(a_collection_containing_exactly(statement, existing))
|
236
242
|
end
|
237
243
|
|
238
|
-
it
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
244
|
+
it 'passes extra arguments to RDF::Reader' do
|
245
|
+
mime = 'x-humans/as-they-are'
|
246
|
+
|
247
|
+
expect(RDF::Reader)
|
248
|
+
.to receive(:open).with(subject.rdf_subject,
|
249
|
+
base_uri: subject.rdf_subject,
|
250
|
+
headers: { Accept: mime })
|
251
|
+
subject.fetch(headers: { Accept: mime })
|
243
252
|
end
|
244
253
|
end
|
245
254
|
end
|
@@ -309,14 +318,14 @@ describe ActiveTriples::RDFSource do
|
|
309
318
|
context 'with no matching property' do
|
310
319
|
it 'is empty' do
|
311
320
|
expect(subject.get_values(:not_a_predicate))
|
312
|
-
.to be_a_relation_containing
|
321
|
+
.to be_a_relation_containing
|
313
322
|
end
|
314
323
|
end
|
315
324
|
|
316
325
|
context 'with an empty predicate' do
|
317
326
|
it 'is empty' do
|
318
327
|
expect(subject.get_values(RDF::URI('http://example.org/empty')))
|
319
|
-
.to be_a_relation_containing
|
328
|
+
.to be_a_relation_containing
|
320
329
|
end
|
321
330
|
end
|
322
331
|
|
@@ -348,24 +357,24 @@ describe ActiveTriples::RDFSource do
|
|
348
357
|
|
349
358
|
context 'when given an unregistered property name' do
|
350
359
|
it 'raises an error' do
|
351
|
-
expect { subject.set_value(:not_a_property, '') }.to raise_error do |
|
352
|
-
expect(
|
353
|
-
expect(
|
354
|
-
expect(
|
360
|
+
expect { subject.set_value(:not_a_property, '') }.to raise_error do |e|
|
361
|
+
expect(e).to be_a ActiveTriples::UndefinedPropertyError
|
362
|
+
expect(e.klass).to eq subject.class
|
363
|
+
expect(e.property).to eq :not_a_property
|
355
364
|
end
|
356
365
|
end
|
357
|
-
|
366
|
+
|
358
367
|
it 'is a no-op' do
|
359
368
|
subject << RDF::Statement(subject, RDF::Vocab::DC.title, 'Moomin')
|
360
369
|
expect { subject.set_value(:not_a_property, '') rescue nil }
|
361
370
|
.not_to change { subject.triples.to_a }
|
362
371
|
end
|
363
372
|
end
|
364
|
-
|
373
|
+
|
365
374
|
shared_examples 'setting values' do
|
366
375
|
include_context 'with properties'
|
367
376
|
after do
|
368
|
-
Object.send(:remove_const, 'SourceWithCreator') if
|
377
|
+
Object.send(:remove_const, 'SourceWithCreator') if
|
369
378
|
defined? SourceWithCreator
|
370
379
|
end
|
371
380
|
|
@@ -381,26 +390,26 @@ describe ActiveTriples::RDFSource do
|
|
381
390
|
it 'sets a value' do
|
382
391
|
expect { subject.set_value(predicate, value) }
|
383
392
|
.to change { subject.statements }
|
384
|
-
|
393
|
+
.to(a_collection_containing_exactly(*statements))
|
385
394
|
end
|
386
395
|
|
387
396
|
it 'sets a value with a property name' do
|
388
397
|
expect { subject.set_value(property_name, value) }
|
389
398
|
.to change { subject.statements }
|
390
|
-
|
399
|
+
.to(a_collection_containing_exactly(*statements))
|
391
400
|
end
|
392
401
|
|
393
402
|
it 'overwrites existing values' do
|
394
|
-
old_vals = ['old value',
|
395
|
-
RDF::Node.new,
|
396
|
-
RDF::Vocab::DC.type,
|
403
|
+
old_vals = ['old value',
|
404
|
+
RDF::Node.new,
|
405
|
+
RDF::Vocab::DC.type,
|
397
406
|
RDF::URI('----')]
|
398
407
|
|
399
408
|
subject.set_value(predicate, old_vals)
|
400
409
|
|
401
410
|
expect { subject.set_value(predicate, value) }
|
402
411
|
.to change { subject.statements }
|
403
|
-
|
412
|
+
.to(a_collection_containing_exactly(*statements))
|
404
413
|
end
|
405
414
|
|
406
415
|
it 'returns the set values in a Relation' do
|
@@ -408,7 +417,7 @@ describe ActiveTriples::RDFSource do
|
|
408
417
|
.to be_a_relation_containing(*Array.wrap(value))
|
409
418
|
end
|
410
419
|
end
|
411
|
-
|
420
|
+
|
412
421
|
context 'with string literal' do
|
413
422
|
include_examples 'setting values' do
|
414
423
|
let(:value) { 'moomin' }
|
@@ -417,7 +426,7 @@ describe ActiveTriples::RDFSource do
|
|
417
426
|
|
418
427
|
context 'with multiple values' do
|
419
428
|
include_examples 'setting values' do
|
420
|
-
let(:value) {
|
429
|
+
let(:value) { %w('moominpapa moominmama') }
|
421
430
|
end
|
422
431
|
end
|
423
432
|
|
@@ -454,11 +463,11 @@ describe ActiveTriples::RDFSource do
|
|
454
463
|
context 'with mixed values' do
|
455
464
|
include_examples 'setting values' do
|
456
465
|
let(:value) do
|
457
|
-
['moomin',
|
458
|
-
Date.today,
|
459
|
-
RDF::Node.new,
|
460
|
-
source_class.new,
|
461
|
-
source_class.new(uri),
|
466
|
+
['moomin',
|
467
|
+
Date.today,
|
468
|
+
RDF::Node.new,
|
469
|
+
source_class.new,
|
470
|
+
source_class.new(uri),
|
462
471
|
subject]
|
463
472
|
end
|
464
473
|
end
|
@@ -473,23 +482,23 @@ describe ActiveTriples::RDFSource do
|
|
473
482
|
person.set_value(RDF::Vocab::FOAF.publications, document)
|
474
483
|
|
475
484
|
expect(person.get_values(RDF::Vocab::FOAF.publications))
|
476
|
-
.to
|
485
|
+
.to be_a_relation_containing(document)
|
477
486
|
expect(document.get_values(RDF::Vocab::DC.creator))
|
478
|
-
.to
|
487
|
+
.to be_a_relation_containing(person)
|
479
488
|
end
|
480
489
|
|
481
490
|
it 'handles setting' do
|
482
|
-
document.set_value(RDF::Vocab::DC.creator, person)
|
483
|
-
person.set_value(RDF::Vocab::FOAF.knows, subject)
|
484
|
-
subject.set_value(RDF::Vocab::FOAF.publications, document)
|
485
|
-
subject.set_value(RDF::OWL.sameAs, subject)
|
491
|
+
document.set_value(RDF::Vocab::DC.creator, person)
|
492
|
+
person.set_value(RDF::Vocab::FOAF.knows, subject)
|
493
|
+
subject.set_value(RDF::Vocab::FOAF.publications, document)
|
494
|
+
subject.set_value(RDF::OWL.sameAs, subject)
|
486
495
|
|
487
496
|
expect(subject.get_values(RDF::Vocab::FOAF.publications))
|
488
|
-
.to
|
497
|
+
.to be_a_relation_containing(document)
|
489
498
|
expect(subject.get_values(RDF::OWL.sameAs))
|
490
|
-
.to
|
499
|
+
.to be_a_relation_containing(subject)
|
491
500
|
expect(document.get_values(RDF::Vocab::DC.creator))
|
492
|
-
.to
|
501
|
+
.to be_a_relation_containing(person)
|
493
502
|
end
|
494
503
|
|
495
504
|
it 'handles setting circularly' do
|
@@ -497,9 +506,9 @@ describe ActiveTriples::RDFSource do
|
|
497
506
|
person.set_value(RDF::Vocab::FOAF.knows, subject)
|
498
507
|
|
499
508
|
expect(document.get_values(RDF::Vocab::DC.creator))
|
500
|
-
.to
|
509
|
+
.to be_a_relation_containing(person, subject)
|
501
510
|
expect(person.get_values(RDF::Vocab::FOAF.knows))
|
502
|
-
.to
|
511
|
+
.to be_a_relation_containing subject
|
503
512
|
end
|
504
513
|
|
505
514
|
it 'handles setting circularly within ancestor list' do
|
@@ -508,36 +517,53 @@ describe ActiveTriples::RDFSource do
|
|
508
517
|
document.set_value(RDF::Vocab::DC.relation, person)
|
509
518
|
person.set_value(RDF::Vocab::DC.relation, person2)
|
510
519
|
person2.set_value(RDF::Vocab::DC.relation, document)
|
511
|
-
|
520
|
+
|
512
521
|
expect(person.get_values(RDF::Vocab::DC.relation))
|
513
|
-
.to
|
522
|
+
.to be_a_relation_containing person2
|
514
523
|
expect(person2.get_values(RDF::Vocab::DC.relation))
|
515
|
-
.to
|
524
|
+
.to be_a_relation_containing document
|
516
525
|
end
|
517
526
|
end
|
518
527
|
|
519
528
|
describe 'capturing child nodes' do
|
520
|
-
let(:other)
|
529
|
+
let(:other) { source_class.new }
|
530
|
+
let(:predicate) { RDF::OWL.sameAs }
|
521
531
|
|
522
532
|
it 'adds child node data to own graph' do
|
523
533
|
other << RDF::Statement(:s, RDF::URI('p'), 'o')
|
524
|
-
|
525
|
-
|
534
|
+
|
535
|
+
expect { subject.set_value(predicate, other) }
|
536
|
+
.to change { subject.statements.to_a }
|
537
|
+
.to include(*other.statements.to_a)
|
526
538
|
end
|
527
539
|
|
528
540
|
it 'does not change persistence strategy of added node' do
|
529
|
-
expect { subject.set_value(
|
541
|
+
expect { subject.set_value(predicate, other) }
|
530
542
|
.not_to change { other.persistence_strategy }
|
531
543
|
end
|
532
|
-
|
544
|
+
|
533
545
|
it 'does not capture a child node when it already persists to a parent' do
|
534
546
|
third = source_class.new
|
535
|
-
third.set_value(
|
536
|
-
|
537
|
-
child_other = third.get_values(
|
538
|
-
expect { subject.set_value(
|
547
|
+
third.set_value(predicate, other)
|
548
|
+
|
549
|
+
child_other = third.get_values(predicate).first
|
550
|
+
expect { subject.set_value(predicate, child_other) }
|
539
551
|
.not_to change { child_other.persistence_strategy.parent }
|
540
552
|
end
|
553
|
+
|
554
|
+
context 'when setting to a relation' do
|
555
|
+
it 'adds child node data to graph' do
|
556
|
+
other << RDF::Statement(other, RDF::URI('p'), 'o')
|
557
|
+
|
558
|
+
relation_source = source_class.new
|
559
|
+
relation_source.set_value(predicate, other)
|
560
|
+
relation = relation_source.get_values(predicate)
|
561
|
+
|
562
|
+
expect { subject.set_value(predicate, relation) }
|
563
|
+
.to change { subject.statements.to_a }
|
564
|
+
.to include(*other.statements.to_a)
|
565
|
+
end
|
566
|
+
end
|
541
567
|
end
|
542
568
|
end
|
543
569
|
|
@@ -578,8 +604,8 @@ describe ActiveTriples::RDFSource do
|
|
578
604
|
it 'adds error message' do
|
579
605
|
expect { subject.valid? }
|
580
606
|
.to change { subject.errors.messages }
|
581
|
-
|
582
|
-
|
607
|
+
.from({})
|
608
|
+
.to(base: ['The underlying graph must be valid'])
|
583
609
|
end
|
584
610
|
end
|
585
611
|
|
@@ -604,8 +630,8 @@ describe ActiveTriples::RDFSource do
|
|
604
630
|
it 'has errors' do
|
605
631
|
expect { subject.valid? }
|
606
632
|
.to change { subject.errors.messages }
|
607
|
-
|
608
|
-
|
633
|
+
.from({})
|
634
|
+
.to(title: ["can't be blank"])
|
609
635
|
end
|
610
636
|
end
|
611
637
|
|
@@ -622,45 +648,53 @@ describe ActiveTriples::RDFSource do
|
|
622
648
|
it 'has errors' do
|
623
649
|
expect { subject.valid? }
|
624
650
|
.to change { subject.errors.messages }
|
625
|
-
|
626
|
-
|
651
|
+
.from({})
|
652
|
+
.to(include(base: ['The underlying graph must be valid']))
|
627
653
|
end
|
628
654
|
end
|
629
655
|
end
|
630
656
|
end
|
631
657
|
end
|
632
658
|
|
633
|
-
describe
|
659
|
+
describe '.apply_schema' do
|
634
660
|
let(:dummy_source) { Class.new { include ActiveTriples::RDFSource } }
|
635
661
|
|
636
662
|
before do
|
637
663
|
class MyDataModel < ActiveTriples::Schema
|
638
|
-
property :test_title, :
|
664
|
+
property :test_title, predicate: RDF::Vocab::DC.title
|
639
665
|
end
|
640
666
|
end
|
641
667
|
|
642
|
-
after
|
643
|
-
|
644
|
-
|
645
|
-
it "should apply the schema" do
|
668
|
+
after { Object.send(:remove_const, 'MyDataModel') }
|
669
|
+
|
670
|
+
it 'should apply the schema' do
|
646
671
|
dummy_source.apply_schema MyDataModel
|
647
672
|
|
648
|
-
expect{dummy_source.new.test_title}.not_to raise_error
|
673
|
+
expect { dummy_source.new.test_title }.not_to raise_error
|
649
674
|
end
|
650
675
|
end
|
651
676
|
|
652
677
|
describe 'sources with properties with class_name defined' do
|
653
678
|
before(:context) do
|
654
679
|
class DummyChapter < ActiveTriples::Resource
|
655
|
-
|
656
|
-
|
657
|
-
|
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'
|
658
687
|
end
|
659
688
|
|
660
689
|
class DummyBook < ActiveTriples::Resource
|
661
|
-
|
662
|
-
|
663
|
-
|
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
|
664
698
|
end
|
665
699
|
end
|
666
700
|
|
@@ -673,11 +707,11 @@ describe ActiveTriples::RDFSource do
|
|
673
707
|
@book_title = 'Example Book.'
|
674
708
|
@chapter_title = 'Chapter 1'
|
675
709
|
ttl = "<#{@book_url}> a <http://www.example.com/type/Book>;
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
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}\" ."
|
681
715
|
book_graph = ::RDF::Graph.new.from_ttl ttl
|
682
716
|
r = ActiveTriples::Repositories.repositories[:default]
|
683
717
|
r << book_graph
|
@@ -688,7 +722,8 @@ describe ActiveTriples::RDFSource do
|
|
688
722
|
it 'populates DummyBook properly' do
|
689
723
|
expect(@book.rdf_subject.to_s).to eq @book_url
|
690
724
|
expect(@book).to be_a DummyBook
|
691
|
-
expect(@book.type)
|
725
|
+
expect(@book.type)
|
726
|
+
.to include(RDF::URI.new('http://www.example.com/type/Book'))
|
692
727
|
expect(@book.title.first).to eq @book_title
|
693
728
|
end
|
694
729
|
|
@@ -696,11 +731,11 @@ describe ActiveTriples::RDFSource do
|
|
696
731
|
chapter = @book.has_chapter.first
|
697
732
|
expect(chapter).to be_a DummyChapter
|
698
733
|
expect(chapter.title.first).to eq @chapter_title
|
699
|
-
expect(chapter.type)
|
734
|
+
expect(chapter.type)
|
735
|
+
.to include(RDF::URI.new('http://www.example.com/type/Chapter'))
|
700
736
|
end
|
701
737
|
end
|
702
738
|
|
703
|
-
|
704
739
|
context 'when loading models through properties' do
|
705
740
|
before(:context) do
|
706
741
|
r = RDF::Repository.new
|
@@ -720,20 +755,25 @@ describe ActiveTriples::RDFSource do
|
|
720
755
|
end
|
721
756
|
|
722
757
|
it 'populates DummyBook (resumed resource) properly' do
|
723
|
-
expect(@bk1.type.first)
|
724
|
-
|
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'
|
725
762
|
end
|
726
763
|
|
727
|
-
|
728
764
|
it 'populates DummyChapter (property resource) properly' do
|
729
765
|
ch1 = @bk1.has_chapter.first
|
730
|
-
expect(ch1.type.first)
|
731
|
-
|
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'
|
732
770
|
end
|
733
771
|
|
734
772
|
it 'populates DummyChapter (directly from repository) properly' do
|
735
|
-
expect(@ch1.type.first)
|
736
|
-
|
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'
|
737
777
|
end
|
738
778
|
|
739
779
|
it 'does not reload from repository twice' do
|