rdf-ldp 0.9.2 → 2.1.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 +5 -5
 - data/CHANGELOG.md +10 -0
 - data/CREDITS +1 -0
 - data/README.md +66 -10
 - data/UNLICENSE +1 -1
 - data/VERSION +1 -1
 - data/app/lamprey.rb +119 -40
 - data/bin/lamprey +15 -1
 - data/lib/rack/ldp.rb +23 -25
 - data/lib/rdf/ldp/container.rb +32 -22
 - data/lib/rdf/ldp/direct_container.rb +9 -7
 - data/lib/rdf/ldp/indirect_container.rb +8 -6
 - data/lib/rdf/ldp/interaction_model.rb +39 -29
 - data/lib/rdf/ldp/non_rdf_source.rb +10 -6
 - data/lib/rdf/ldp/rdf_source.rb +3 -3
 - data/lib/rdf/ldp/resource.rb +33 -31
 - data/lib/rdf/ldp/spec/container.rb +337 -0
 - data/lib/rdf/ldp/spec/direct_container.rb +245 -0
 - data/lib/rdf/ldp/spec/indirect_container.rb +152 -0
 - data/lib/rdf/ldp/spec/non_rdf_source.rb +138 -0
 - data/lib/rdf/ldp/spec/rdf_source.rb +370 -0
 - data/lib/rdf/ldp/spec/resource.rb +242 -0
 - data/lib/rdf/ldp/spec.rb +6 -0
 - data/lib/rdf/ldp/storage_adapters/file_storage_adapter.rb +4 -4
 - data/lib/rdf/ldp/version.rb +16 -3
 - data/lib/rdf/ldp.rb +4 -3
 - metadata +89 -55
 
| 
         @@ -0,0 +1,152 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rdf/ldp/spec/direct_container'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            shared_examples 'an IndirectContainer' do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it_behaves_like 'a DirectContainer'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              shared_context 'with a relation' do
         
     | 
| 
      
 7 
     | 
    
         
            +
                before do
         
     | 
| 
      
 8 
     | 
    
         
            +
                  subject.create(StringIO.new(graph.dump(:ntriples)),
         
     | 
| 
      
 9 
     | 
    
         
            +
                                 'application/n-triples')
         
     | 
| 
      
 10 
     | 
    
         
            +
                end
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                let(:graph) { RDF::Graph.new << inserted_content_statement }
         
     | 
| 
      
 13 
     | 
    
         
            +
                let(:relation_predicate) { RDF::Vocab::DC.creator }
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                let(:inserted_content_statement) do
         
     | 
| 
      
 16 
     | 
    
         
            +
                  RDF::Statement(uri,
         
     | 
| 
      
 17 
     | 
    
         
            +
                                 RDF::Vocab::LDP.insertedContentRelation,
         
     | 
| 
      
 18 
     | 
    
         
            +
                                 relation_predicate)
         
     | 
| 
      
 19 
     | 
    
         
            +
                end
         
     | 
| 
      
 20 
     | 
    
         
            +
              end
         
     | 
| 
      
 21 
     | 
    
         
            +
             
     | 
| 
      
 22 
     | 
    
         
            +
              describe '#inserted_content_relation' do
         
     | 
| 
      
 23 
     | 
    
         
            +
                it 'returns a uri' do
         
     | 
| 
      
 24 
     | 
    
         
            +
                  subject.create(StringIO.new, 'application/n-triples')
         
     | 
| 
      
 25 
     | 
    
         
            +
                  expect(subject.inserted_content_relation).to be_a RDF::URI
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                context 'with a relation' do
         
     | 
| 
      
 29 
     | 
    
         
            +
                  include_context 'with a relation'
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                  it 'gives the relation' do
         
     | 
| 
      
 32 
     | 
    
         
            +
                    expect(subject.inserted_content_relation).to eq relation_predicate
         
     | 
| 
      
 33 
     | 
    
         
            +
                  end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
                  it 'raises an error when more than one exists' do
         
     | 
| 
      
 36 
     | 
    
         
            +
                    new_statement = inserted_content_statement.clone
         
     | 
| 
      
 37 
     | 
    
         
            +
                    new_statement.object = RDF::Vocab::DC.relation
         
     | 
| 
      
 38 
     | 
    
         
            +
                    subject.graph << new_statement
         
     | 
| 
      
 39 
     | 
    
         
            +
                    expect { subject.inserted_content_relation }
         
     | 
| 
      
 40 
     | 
    
         
            +
                      .to raise_error RDF::LDP::NotAcceptable
         
     | 
| 
      
 41 
     | 
    
         
            +
                  end
         
     | 
| 
      
 42 
     | 
    
         
            +
                end
         
     | 
| 
      
 43 
     | 
    
         
            +
              end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
              describe '#add' do
         
     | 
| 
      
 46 
     | 
    
         
            +
                include_context 'with a relation'
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                subject { described_class.new(uri, repo) }
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                let(:repo) { RDF::Repository.new }
         
     | 
| 
      
 51 
     | 
    
         
            +
                let(:resource_uri) { RDF::URI('http://example.org/too-ticky') }
         
     | 
| 
      
 52 
     | 
    
         
            +
                let(:contained_resource) { RDF::LDP::RDFSource.new(resource_uri, repo) }
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                context 'when no derived URI is found' do
         
     | 
| 
      
 55 
     | 
    
         
            +
                  it 'raises NotAcceptable' do
         
     | 
| 
      
 56 
     | 
    
         
            +
                    expect { subject.add(contained_resource) }
         
     | 
| 
      
 57 
     | 
    
         
            +
                      .to raise_error RDF::LDP::NotAcceptable
         
     | 
| 
      
 58 
     | 
    
         
            +
                  end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                  it 'does not create the resource' do
         
     | 
| 
      
 61 
     | 
    
         
            +
                    begin; subject.add(contained_resource); rescue; end
         
     | 
| 
      
 62 
     | 
    
         
            +
                    expect(contained_resource).not_to exist
         
     | 
| 
      
 63 
     | 
    
         
            +
                  end
         
     | 
| 
      
 64 
     | 
    
         
            +
                end
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                context 'with expected predicate' do
         
     | 
| 
      
 67 
     | 
    
         
            +
                  before { contained_resource.graph << statement }
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  let(:target_uri) { contained_resource.to_uri / '#me' }
         
     | 
| 
      
 70 
     | 
    
         
            +
             
     | 
| 
      
 71 
     | 
    
         
            +
                  let(:statement) do
         
     | 
| 
      
 72 
     | 
    
         
            +
                    RDF::Statement(contained_resource.to_uri,
         
     | 
| 
      
 73 
     | 
    
         
            +
                                   relation_predicate,
         
     | 
| 
      
 74 
     | 
    
         
            +
                                   target_uri)
         
     | 
| 
      
 75 
     | 
    
         
            +
                  end
         
     | 
| 
      
 76 
     | 
    
         
            +
             
     | 
| 
      
 77 
     | 
    
         
            +
                  it 'when membership resource does not exist raises NotAcceptable' do
         
     | 
| 
      
 78 
     | 
    
         
            +
                    new_resource = described_class.new(uri / 'new', repo)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    expect { new_resource.add(contained_resource) }
         
     | 
| 
      
 80 
     | 
    
         
            +
                      .to raise_error RDF::LDP::NotAcceptable
         
     | 
| 
      
 81 
     | 
    
         
            +
                  end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                  context 'when the container exists' do
         
     | 
| 
      
 84 
     | 
    
         
            +
                    it 'adds membership triple' do
         
     | 
| 
      
 85 
     | 
    
         
            +
                      subject.add(contained_resource)
         
     | 
| 
      
 86 
     | 
    
         
            +
                      expect(subject.graph.statements)
         
     | 
| 
      
 87 
     | 
    
         
            +
                        .to include RDF::Statement(subject.to_uri,
         
     | 
| 
      
 88 
     | 
    
         
            +
                                                   subject.membership_predicate,
         
     | 
| 
      
 89 
     | 
    
         
            +
                                                   target_uri)
         
     | 
| 
      
 90 
     | 
    
         
            +
                    end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                    it 'for multiple predicates raises NotAcceptable' do
         
     | 
| 
      
 93 
     | 
    
         
            +
                      new_statement = statement.clone
         
     | 
| 
      
 94 
     | 
    
         
            +
                      new_statement.object = contained_resource.to_uri / '#you'
         
     | 
| 
      
 95 
     | 
    
         
            +
                      contained_resource.graph << new_statement
         
     | 
| 
      
 96 
     | 
    
         
            +
                      expect { subject.add(contained_resource) }
         
     | 
| 
      
 97 
     | 
    
         
            +
                        .to raise_error RDF::LDP::NotAcceptable
         
     | 
| 
      
 98 
     | 
    
         
            +
                    end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                    it 'for an LDP-NR raises NotAcceptable' do
         
     | 
| 
      
 101 
     | 
    
         
            +
                      nr_resource = RDF::LDP::NonRDFSource.new(resource_uri, repo)
         
     | 
| 
      
 102 
     | 
    
         
            +
                      expect { subject.add(nr_resource) }
         
     | 
| 
      
 103 
     | 
    
         
            +
                        .to raise_error RDF::LDP::NotAcceptable
         
     | 
| 
      
 104 
     | 
    
         
            +
                    end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                    context 'with membership resource' do
         
     | 
| 
      
 107 
     | 
    
         
            +
                      before do
         
     | 
| 
      
 108 
     | 
    
         
            +
                        subject.graph
         
     | 
| 
      
 109 
     | 
    
         
            +
                               .delete([uri, RDF::Vocab::LDP.membershipResource, nil])
         
     | 
| 
      
 110 
     | 
    
         
            +
                        subject.graph << RDF::Statement(uri,
         
     | 
| 
      
 111 
     | 
    
         
            +
                                                        RDF::Vocab::LDP.membershipResource,
         
     | 
| 
      
 112 
     | 
    
         
            +
                                                        membership_resource)
         
     | 
| 
      
 113 
     | 
    
         
            +
                      end
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
                      let(:membership_resource) { uri }
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                      it 'raises error when resource does not exist' do
         
     | 
| 
      
 118 
     | 
    
         
            +
                        new_resource = described_class.new(uri / 'new', repo)
         
     | 
| 
      
 119 
     | 
    
         
            +
                        expect { new_resource.add(contained_resource) }
         
     | 
| 
      
 120 
     | 
    
         
            +
                          .to raise_error RDF::LDP::NotAcceptable
         
     | 
| 
      
 121 
     | 
    
         
            +
                      end
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                      context 'when the membership resource is not in the server' do
         
     | 
| 
      
 124 
     | 
    
         
            +
                        let(:membership_resource) { uri / '#me' }
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                        it 'adds membership triple to container' do
         
     | 
| 
      
 127 
     | 
    
         
            +
                          contained_resource.create(StringIO.new, 'application/n-triples')
         
     | 
| 
      
 128 
     | 
    
         
            +
                          subject.add(contained_resource)
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                          expect(subject.graph.statements)
         
     | 
| 
      
 131 
     | 
    
         
            +
                            .to include RDF::Statement(membership_resource,
         
     | 
| 
      
 132 
     | 
    
         
            +
                                                       subject.membership_predicate,
         
     | 
| 
      
 133 
     | 
    
         
            +
                                                       target_uri)
         
     | 
| 
      
 134 
     | 
    
         
            +
                        end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                        it 'removes membership triple to container' do
         
     | 
| 
      
 137 
     | 
    
         
            +
                          contained_resource.create(StringIO.new, 'application/n-triples')
         
     | 
| 
      
 138 
     | 
    
         
            +
             
     | 
| 
      
 139 
     | 
    
         
            +
                          subject.add(contained_resource)
         
     | 
| 
      
 140 
     | 
    
         
            +
                          subject.remove(contained_resource)
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
                          expect(subject.graph.statements)
         
     | 
| 
      
 143 
     | 
    
         
            +
                            .not_to include RDF::Statement(membership_resource,
         
     | 
| 
      
 144 
     | 
    
         
            +
                                                           subject.membership_predicate,
         
     | 
| 
      
 145 
     | 
    
         
            +
                                                           target_uri)
         
     | 
| 
      
 146 
     | 
    
         
            +
                        end
         
     | 
| 
      
 147 
     | 
    
         
            +
                      end
         
     | 
| 
      
 148 
     | 
    
         
            +
                    end
         
     | 
| 
      
 149 
     | 
    
         
            +
                  end
         
     | 
| 
      
 150 
     | 
    
         
            +
                end
         
     | 
| 
      
 151 
     | 
    
         
            +
              end
         
     | 
| 
      
 152 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,138 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rdf/ldp/spec/resource'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            shared_examples 'a NonRDFSource' do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it_behaves_like 'a Resource'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              subject { described_class.new(uri) }
         
     | 
| 
      
 7 
     | 
    
         
            +
              let(:uri) { RDF::URI 'http://example.org/moomin' }
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
              let(:contents) { StringIO.new('mummi') }
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              after { subject.destroy }
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              describe '#non_rdf_source?' do
         
     | 
| 
      
 14 
     | 
    
         
            +
                it { is_expected.to be_non_rdf_source }
         
     | 
| 
      
 15 
     | 
    
         
            +
              end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              describe '#create' do
         
     | 
| 
      
 18 
     | 
    
         
            +
                it 'writes the input to body' do
         
     | 
| 
      
 19 
     | 
    
         
            +
                  subject.create(contents, 'text/plain')
         
     | 
| 
      
 20 
     | 
    
         
            +
                  contents.rewind
         
     | 
| 
      
 21 
     | 
    
         
            +
                  expect(subject.to_response.each.to_a).to eq contents.each.to_a
         
     | 
| 
      
 22 
     | 
    
         
            +
                end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                it 'sets #content_type' do
         
     | 
| 
      
 25 
     | 
    
         
            +
                  expect { subject.create(StringIO.new(''), 'text/plain') }
         
     | 
| 
      
 26 
     | 
    
         
            +
                    .to change { subject.content_type }.to('text/plain')
         
     | 
| 
      
 27 
     | 
    
         
            +
                end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                it 'persists to resource' do
         
     | 
| 
      
 30 
     | 
    
         
            +
                  repo = RDF::Repository.new
         
     | 
| 
      
 31 
     | 
    
         
            +
                  saved = described_class.new(uri, repo)
         
     | 
| 
      
 32 
     | 
    
         
            +
             
     | 
| 
      
 33 
     | 
    
         
            +
                  saved.create(contents, 'text/plain')
         
     | 
| 
      
 34 
     | 
    
         
            +
                  contents.rewind
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  loaded = RDF::LDP::Resource.find(uri, repo)
         
     | 
| 
      
 37 
     | 
    
         
            +
                  expect(loaded.to_response.each.to_a).to eq contents.each.to_a
         
     | 
| 
      
 38 
     | 
    
         
            +
                end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                it 'creates an LDP::RDFSource' do
         
     | 
| 
      
 41 
     | 
    
         
            +
                  repo = RDF::Repository.new
         
     | 
| 
      
 42 
     | 
    
         
            +
                  saved = described_class.new(uri, repo)
         
     | 
| 
      
 43 
     | 
    
         
            +
                  description = RDF::LDP::RDFSource.new(subject.description_uri, repo)
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                  expect { saved.create(contents, 'text/plain') }
         
     | 
| 
      
 46 
     | 
    
         
            +
                    .to change { description.exists? }.from(false).to(true)
         
     | 
| 
      
 47 
     | 
    
         
            +
                end
         
     | 
| 
      
 48 
     | 
    
         
            +
              end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
              describe '#update' do
         
     | 
| 
      
 51 
     | 
    
         
            +
                before { subject.create(contents, 'text/plain') }
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                it 'writes the input to body' do
         
     | 
| 
      
 54 
     | 
    
         
            +
                  new_contents = StringIO.new('snorkmaiden')
         
     | 
| 
      
 55 
     | 
    
         
            +
                  expect { subject.update(new_contents, 'text/plain') }
         
     | 
| 
      
 56 
     | 
    
         
            +
                    .to change { subject.to_response.to_a }
         
     | 
| 
      
 57 
     | 
    
         
            +
                    .from(a_collection_containing_exactly('mummi'))
         
     | 
| 
      
 58 
     | 
    
         
            +
                    .to(a_collection_containing_exactly('snorkmaiden'))
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
             
     | 
| 
      
 61 
     | 
    
         
            +
                it 'updates #content_type' do
         
     | 
| 
      
 62 
     | 
    
         
            +
                  expect { subject.update(contents, 'text/prs.moomin') }
         
     | 
| 
      
 63 
     | 
    
         
            +
                    .to change { subject.content_type }
         
     | 
| 
      
 64 
     | 
    
         
            +
                    .from('text/plain').to('text/prs.moomin')
         
     | 
| 
      
 65 
     | 
    
         
            +
                end
         
     | 
| 
      
 66 
     | 
    
         
            +
              end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
              describe '#description' do
         
     | 
| 
      
 69 
     | 
    
         
            +
                it 'is not found' do
         
     | 
| 
      
 70 
     | 
    
         
            +
                  expect { subject.description }.to raise_error RDF::LDP::NotFound
         
     | 
| 
      
 71 
     | 
    
         
            +
                end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                context 'when it exists' do
         
     | 
| 
      
 74 
     | 
    
         
            +
                  before { subject.create(StringIO.new(''), 'text/plain') }
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                  it 'is an RDFSource' do
         
     | 
| 
      
 77 
     | 
    
         
            +
                    expect(subject.description).to be_rdf_source
         
     | 
| 
      
 78 
     | 
    
         
            +
                  end
         
     | 
| 
      
 79 
     | 
    
         
            +
             
     | 
| 
      
 80 
     | 
    
         
            +
                  it 'is the description uri' do
         
     | 
| 
      
 81 
     | 
    
         
            +
                    expect(subject.description.to_uri).to eq subject.description_uri
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
                end
         
     | 
| 
      
 84 
     | 
    
         
            +
              end
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
              describe '#description_uri' do
         
     | 
| 
      
 87 
     | 
    
         
            +
                it 'is a uri' do
         
     | 
| 
      
 88 
     | 
    
         
            +
                  expect(subject.description_uri).to be_a RDF::URI
         
     | 
| 
      
 89 
     | 
    
         
            +
                end
         
     | 
| 
      
 90 
     | 
    
         
            +
              end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
              describe '#storage' do
         
     | 
| 
      
 93 
     | 
    
         
            +
                it 'sets a default storage adapter' do
         
     | 
| 
      
 94 
     | 
    
         
            +
                  expect(subject.storage).to be_a RDF::LDP::NonRDFSource::FileStorageAdapter
         
     | 
| 
      
 95 
     | 
    
         
            +
                end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
                it 'explicitly sets a storage adapter' do
         
     | 
| 
      
 98 
     | 
    
         
            +
                  class DummyAdapter < RDF::LDP::NonRDFSource::FileStorageAdapter
         
     | 
| 
      
 99 
     | 
    
         
            +
                  end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                  dummy_subject = described_class.new(uri, nil, DummyAdapter)
         
     | 
| 
      
 102 
     | 
    
         
            +
                  expect(dummy_subject.storage).to be_a DummyAdapter
         
     | 
| 
      
 103 
     | 
    
         
            +
                end
         
     | 
| 
      
 104 
     | 
    
         
            +
              end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
              describe '#to_response' do
         
     | 
| 
      
 107 
     | 
    
         
            +
                it 'gives an empty response if it is new' do
         
     | 
| 
      
 108 
     | 
    
         
            +
                  expect(subject.to_response.to_a).to eq []
         
     | 
| 
      
 109 
     | 
    
         
            +
                end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                it 'does not create a non-existant file' do
         
     | 
| 
      
 112 
     | 
    
         
            +
                  subject.to_response
         
     | 
| 
      
 113 
     | 
    
         
            +
                  expect(subject.storage.send(:file_exists?)).to be false
         
     | 
| 
      
 114 
     | 
    
         
            +
                end
         
     | 
| 
      
 115 
     | 
    
         
            +
              end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
              describe '#destroy' do
         
     | 
| 
      
 118 
     | 
    
         
            +
                before { subject.create(contents, 'text/plain') }
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                it 'deletes the content' do
         
     | 
| 
      
 121 
     | 
    
         
            +
                  expect { subject.destroy }
         
     | 
| 
      
 122 
     | 
    
         
            +
                    .to change { subject.to_response.to_a }
         
     | 
| 
      
 123 
     | 
    
         
            +
                    .from(a_collection_containing_exactly('mummi')).to([])
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                it 'marks resource as destroyed' do
         
     | 
| 
      
 127 
     | 
    
         
            +
                  expect { subject.destroy }
         
     | 
| 
      
 128 
     | 
    
         
            +
                    .to change { subject.destroyed? }.from(false).to(true)
         
     | 
| 
      
 129 
     | 
    
         
            +
                end
         
     | 
| 
      
 130 
     | 
    
         
            +
              end
         
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
              describe '#content_type' do
         
     | 
| 
      
 133 
     | 
    
         
            +
                it 'sets and gets a content_type' do
         
     | 
| 
      
 134 
     | 
    
         
            +
                  expect { subject.content_type = 'text/plain' }
         
     | 
| 
      
 135 
     | 
    
         
            +
                    .to change { subject.content_type }.to('text/plain')
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
              end
         
     | 
| 
      
 138 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,370 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'rdf/ldp/spec/resource'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            shared_examples 'an RDFSource' do
         
     | 
| 
      
 4 
     | 
    
         
            +
              it_behaves_like 'a Resource'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
              let(:uri) { RDF::URI('http://ex.org/moomin') }
         
     | 
| 
      
 7 
     | 
    
         
            +
              subject { described_class.new('http://ex.org/moomin') }
         
     | 
| 
      
 8 
     | 
    
         
            +
              it { is_expected.to be_rdf_source }
         
     | 
| 
      
 9 
     | 
    
         
            +
              it { is_expected.not_to be_non_rdf_source }
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
              describe '#parse_graph' do
         
     | 
| 
      
 12 
     | 
    
         
            +
                it 'raises UnsupportedMediaType if no reader found' do
         
     | 
| 
      
 13 
     | 
    
         
            +
                  expect { subject.send(:parse_graph, StringIO.new('graph'), 'text/fake') }
         
     | 
| 
      
 14 
     | 
    
         
            +
                    .to raise_error RDF::LDP::UnsupportedMediaType
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                it 'raises BadRequest if graph cannot be parsed' do
         
     | 
| 
      
 18 
     | 
    
         
            +
                  expect do
         
     | 
| 
      
 19 
     | 
    
         
            +
                    subject.send(:parse_graph,
         
     | 
| 
      
 20 
     | 
    
         
            +
                                 StringIO.new('graph'),
         
     | 
| 
      
 21 
     | 
    
         
            +
                                 'application/n-triples')
         
     | 
| 
      
 22 
     | 
    
         
            +
                  end.to raise_error RDF::LDP::BadRequest
         
     | 
| 
      
 23 
     | 
    
         
            +
                end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                describe 'parsing the graph' do
         
     | 
| 
      
 26 
     | 
    
         
            +
                  let(:graph) { RDF::Repository.new }
         
     | 
| 
      
 27 
     | 
    
         
            +
             
     | 
| 
      
 28 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 29 
     | 
    
         
            +
                    graph << RDF::Statement(RDF::URI('http://ex.org/moomin'),
         
     | 
| 
      
 30 
     | 
    
         
            +
                                            RDF.type,
         
     | 
| 
      
 31 
     | 
    
         
            +
                                            RDF::Vocab::FOAF.Person,
         
     | 
| 
      
 32 
     | 
    
         
            +
                                            graph_name: subject.subject_uri)
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    10.times do
         
     | 
| 
      
 35 
     | 
    
         
            +
                      graph << RDF::Statement(RDF::Node.new,
         
     | 
| 
      
 36 
     | 
    
         
            +
                                              RDF::Vocab::DC.creator,
         
     | 
| 
      
 37 
     | 
    
         
            +
                                              RDF::Node.new,
         
     | 
| 
      
 38 
     | 
    
         
            +
                                              graph_name: subject.subject_uri)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    end
         
     | 
| 
      
 40 
     | 
    
         
            +
                  end
         
     | 
| 
      
 41 
     | 
    
         
            +
             
     | 
| 
      
 42 
     | 
    
         
            +
                  it 'parses turtle' do
         
     | 
| 
      
 43 
     | 
    
         
            +
                    expect(subject.send(:parse_graph,
         
     | 
| 
      
 44 
     | 
    
         
            +
                                        StringIO.new(graph.dump(:ttl)),
         
     | 
| 
      
 45 
     | 
    
         
            +
                                        'text/turtle'))
         
     | 
| 
      
 46 
     | 
    
         
            +
                      .to be_isomorphic_with graph
         
     | 
| 
      
 47 
     | 
    
         
            +
                  end
         
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
                  it 'parses ntriples' do
         
     | 
| 
      
 50 
     | 
    
         
            +
                    expect(subject.send(:parse_graph,
         
     | 
| 
      
 51 
     | 
    
         
            +
                                        StringIO.new(graph.dump(:ntriples)),
         
     | 
| 
      
 52 
     | 
    
         
            +
                                        'application/n-triples'))
         
     | 
| 
      
 53 
     | 
    
         
            +
                      .to be_isomorphic_with graph
         
     | 
| 
      
 54 
     | 
    
         
            +
                  end
         
     | 
| 
      
 55 
     | 
    
         
            +
                end
         
     | 
| 
      
 56 
     | 
    
         
            +
              end
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              describe '#etag' do
         
     | 
| 
      
 59 
     | 
    
         
            +
                before do
         
     | 
| 
      
 60 
     | 
    
         
            +
                  subject.graph << statement
         
     | 
| 
      
 61 
     | 
    
         
            +
                  other.graph << statement
         
     | 
| 
      
 62 
     | 
    
         
            +
                end
         
     | 
| 
      
 63 
     | 
    
         
            +
             
     | 
| 
      
 64 
     | 
    
         
            +
                let(:other) { described_class.new(RDF::URI('http://ex.org/blah')) }
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
                let(:statement) do
         
     | 
| 
      
 67 
     | 
    
         
            +
                  RDF::Statement(RDF::URI('http://ex.org/m'),
         
     | 
| 
      
 68 
     | 
    
         
            +
                                 RDF::Vocab::DC.title,
         
     | 
| 
      
 69 
     | 
    
         
            +
                                 'moomin')
         
     | 
| 
      
 70 
     | 
    
         
            +
                end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                it 'is the same for equal graphs' do
         
     | 
| 
      
 73 
     | 
    
         
            +
                  expect(subject.etag).to eq other.etag
         
     | 
| 
      
 74 
     | 
    
         
            +
                end
         
     | 
| 
      
 75 
     | 
    
         
            +
             
     | 
| 
      
 76 
     | 
    
         
            +
                xit 'is different for different graphs' do
         
     | 
| 
      
 77 
     | 
    
         
            +
                  subject.graph <<
         
     | 
| 
      
 78 
     | 
    
         
            +
                    RDF::Statement(RDF::Node.new, RDF::Vocab::DC.title, 'mymble')
         
     | 
| 
      
 79 
     | 
    
         
            +
                  expect(subject.etag).not_to eq other.etag
         
     | 
| 
      
 80 
     | 
    
         
            +
                end
         
     | 
| 
      
 81 
     | 
    
         
            +
              end
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              describe '#create' do
         
     | 
| 
      
 84 
     | 
    
         
            +
                let(:subject) { described_class.new(RDF::URI('http://ex.org/m')) }
         
     | 
| 
      
 85 
     | 
    
         
            +
                let(:graph) { RDF::Graph.new }
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                it 'does not create when graph fails to parse' do
         
     | 
| 
      
 88 
     | 
    
         
            +
                  begin
         
     | 
| 
      
 89 
     | 
    
         
            +
                    subject.create(StringIO.new(graph.dump(:ttl)), 'text/moomin')
         
     | 
| 
      
 90 
     | 
    
         
            +
                  rescue; end
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                  expect(subject).not_to exist
         
     | 
| 
      
 93 
     | 
    
         
            +
                end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                it 'returns itself' do
         
     | 
| 
      
 96 
     | 
    
         
            +
                  expect(subject.create(StringIO.new(graph.dump(:ttl)), 'text/turtle'))
         
     | 
| 
      
 97 
     | 
    
         
            +
                    .to eq subject
         
     | 
| 
      
 98 
     | 
    
         
            +
                end
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
                it 'yields a transaction' do
         
     | 
| 
      
 101 
     | 
    
         
            +
                  expect do |b|
         
     | 
| 
      
 102 
     | 
    
         
            +
                    subject.create(StringIO.new(graph.dump(:ttl)), 'text/turtle', &b)
         
     | 
| 
      
 103 
     | 
    
         
            +
                  end.to yield_with_args(be_kind_of(RDF::Transaction))
         
     | 
| 
      
 104 
     | 
    
         
            +
                end
         
     | 
| 
      
 105 
     | 
    
         
            +
             
     | 
| 
      
 106 
     | 
    
         
            +
                it 'interprets NULL URI as this resource' do
         
     | 
| 
      
 107 
     | 
    
         
            +
                  graph << RDF::Statement(RDF::URI.new, RDF::Vocab::DC.title, 'moomin')
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                  created =
         
     | 
| 
      
 110 
     | 
    
         
            +
                    subject.create(StringIO.new(graph.dump(:ttl)), 'text/turtle').graph
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                  expect(created)
         
     | 
| 
      
 113 
     | 
    
         
            +
                    .to have_statement RDF::Statement(subject.subject_uri,
         
     | 
| 
      
 114 
     | 
    
         
            +
                                                      RDF::Vocab::DC.title,
         
     | 
| 
      
 115 
     | 
    
         
            +
                                                      'moomin')
         
     | 
| 
      
 116 
     | 
    
         
            +
                end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                it 'interprets Relative URIs as this based on this resource' do
         
     | 
| 
      
 119 
     | 
    
         
            +
                  graph << RDF::Statement(subject.subject_uri,
         
     | 
| 
      
 120 
     | 
    
         
            +
                                          RDF::Vocab::DC.isPartOf,
         
     | 
| 
      
 121 
     | 
    
         
            +
                                          RDF::URI('#moomin'))
         
     | 
| 
      
 122 
     | 
    
         
            +
             
     | 
| 
      
 123 
     | 
    
         
            +
                  created =
         
     | 
| 
      
 124 
     | 
    
         
            +
                    subject.create(StringIO.new(graph.dump(:ttl)), 'text/turtle').graph
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                  expect(created)
         
     | 
| 
      
 127 
     | 
    
         
            +
                    .to have_statement RDF::Statement(subject.subject_uri,
         
     | 
| 
      
 128 
     | 
    
         
            +
                                                      RDF::Vocab::DC.isPartOf,
         
     | 
| 
      
 129 
     | 
    
         
            +
                                                      subject.subject_uri / '#moomin')
         
     | 
| 
      
 130 
     | 
    
         
            +
                end
         
     | 
| 
      
 131 
     | 
    
         
            +
              end
         
     | 
| 
      
 132 
     | 
    
         
            +
             
     | 
| 
      
 133 
     | 
    
         
            +
              describe '#update' do
         
     | 
| 
      
 134 
     | 
    
         
            +
                let(:statement) do
         
     | 
| 
      
 135 
     | 
    
         
            +
                  RDF::Statement(subject.subject_uri, RDF::Vocab::DC.title, 'moomin')
         
     | 
| 
      
 136 
     | 
    
         
            +
                end
         
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
                let(:graph) { RDF::Graph.new << statement }
         
     | 
| 
      
 139 
     | 
    
         
            +
                let(:content_type) { 'text/turtle' }
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                shared_examples 'updating rdf_sources' do
         
     | 
| 
      
 142 
     | 
    
         
            +
                  it 'changes the response' do
         
     | 
| 
      
 143 
     | 
    
         
            +
                    expect { subject.update(StringIO.new(graph.dump(:ttl)), content_type) }
         
     | 
| 
      
 144 
     | 
    
         
            +
                      .to change { subject.to_response }
         
     | 
| 
      
 145 
     | 
    
         
            +
                  end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
                  it 'changes etag' do
         
     | 
| 
      
 148 
     | 
    
         
            +
                    expect { subject.update(StringIO.new(graph.dump(:ttl)), content_type) }
         
     | 
| 
      
 149 
     | 
    
         
            +
                      .to change { subject.etag }
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  it 'yields a transaction' do
         
     | 
| 
      
 153 
     | 
    
         
            +
                    expect do |b|
         
     | 
| 
      
 154 
     | 
    
         
            +
                      subject.update(StringIO.new(graph.dump(:ttl)), content_type, &b)
         
     | 
| 
      
 155 
     | 
    
         
            +
                    end.to yield_with_args(be_kind_of(RDF::Transaction))
         
     | 
| 
      
 156 
     | 
    
         
            +
                  end
         
     | 
| 
      
 157 
     | 
    
         
            +
             
     | 
| 
      
 158 
     | 
    
         
            +
                  context 'with bad media type' do
         
     | 
| 
      
 159 
     | 
    
         
            +
                    it 'raises UnsupportedMediaType' do
         
     | 
| 
      
 160 
     | 
    
         
            +
                      graph_io = StringIO.new(graph.dump(:ttl))
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
                      expect { subject.update(graph_io, 'text/moomin') }
         
     | 
| 
      
 163 
     | 
    
         
            +
                        .to raise_error RDF::LDP::UnsupportedMediaType
         
     | 
| 
      
 164 
     | 
    
         
            +
                    end
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                    it 'does not update #last_modified' do
         
     | 
| 
      
 167 
     | 
    
         
            +
                      modified = subject.last_modified
         
     | 
| 
      
 168 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 169 
     | 
    
         
            +
                        subject.update(StringIO.new(graph.dump(:ttl)), 'text/moomin')
         
     | 
| 
      
 170 
     | 
    
         
            +
                      rescue; end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                      expect(subject.last_modified).to eq modified
         
     | 
| 
      
 173 
     | 
    
         
            +
                    end
         
     | 
| 
      
 174 
     | 
    
         
            +
                  end
         
     | 
| 
      
 175 
     | 
    
         
            +
                end
         
     | 
| 
      
 176 
     | 
    
         
            +
             
     | 
| 
      
 177 
     | 
    
         
            +
                include_examples 'updating rdf_sources'
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                context 'when it exists' do
         
     | 
| 
      
 180 
     | 
    
         
            +
                  before { subject.create(StringIO.new, 'application/n-triples') }
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                  include_examples 'updating rdf_sources'
         
     | 
| 
      
 183 
     | 
    
         
            +
                end
         
     | 
| 
      
 184 
     | 
    
         
            +
              end
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
              describe '#patch' do
         
     | 
| 
      
 187 
     | 
    
         
            +
                it 'raises UnsupportedMediaType when no media type is given' do
         
     | 
| 
      
 188 
     | 
    
         
            +
                  expect { subject.request(:patch, 200, {}, {}) }
         
     | 
| 
      
 189 
     | 
    
         
            +
                    .to raise_error RDF::LDP::UnsupportedMediaType
         
     | 
| 
      
 190 
     | 
    
         
            +
                end
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                it 'gives PreconditionFailed when trying to update with wrong Etag' do
         
     | 
| 
      
 193 
     | 
    
         
            +
                  env = { 'HTTP_IF_MATCH' => 'not an Etag' }
         
     | 
| 
      
 194 
     | 
    
         
            +
                  expect { subject.request(:PATCH, 200, { 'abc' => 'def' }, env) }
         
     | 
| 
      
 195 
     | 
    
         
            +
                    .to raise_error RDF::LDP::PreconditionFailed
         
     | 
| 
      
 196 
     | 
    
         
            +
                end
         
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
                context 'ldpatch' do
         
     | 
| 
      
 199 
     | 
    
         
            +
                  it 'raises BadRequest when invalid document' do
         
     | 
| 
      
 200 
     | 
    
         
            +
                    env = { 'CONTENT_TYPE' => 'text/ldpatch',
         
     | 
| 
      
 201 
     | 
    
         
            +
                            'rack.input'   => StringIO.new('---invalid---') }
         
     | 
| 
      
 202 
     | 
    
         
            +
                    expect { subject.request(:patch, 200, {}, env) }
         
     | 
| 
      
 203 
     | 
    
         
            +
                      .to raise_error RDF::LDP::BadRequest
         
     | 
| 
      
 204 
     | 
    
         
            +
                  end
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
      
 206 
     | 
    
         
            +
                  it 'handles patch' do
         
     | 
| 
      
 207 
     | 
    
         
            +
                    statement =
         
     | 
| 
      
 208 
     | 
    
         
            +
                      RDF::Statement(subject.subject_uri, RDF::Vocab::FOAF.name, 'Moomin')
         
     | 
| 
      
 209 
     | 
    
         
            +
                    patch = '@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .' \
         
     | 
| 
      
 210 
     | 
    
         
            +
                            "\n\nAdd { #{statement.subject.to_base} " \
         
     | 
| 
      
 211 
     | 
    
         
            +
                            "#{statement.predicate.to_base} #{statement.object.to_base} } ."
         
     | 
| 
      
 212 
     | 
    
         
            +
                    env = { 'CONTENT_TYPE' => 'text/ldpatch',
         
     | 
| 
      
 213 
     | 
    
         
            +
                            'rack.input'   => StringIO.new(patch) }
         
     | 
| 
      
 214 
     | 
    
         
            +
             
     | 
| 
      
 215 
     | 
    
         
            +
                    expect { subject.request(:patch, 200, {}, env) }
         
     | 
| 
      
 216 
     | 
    
         
            +
                      .to change { subject.graph.statements.to_a }
         
     | 
| 
      
 217 
     | 
    
         
            +
                      .to(contain_exactly(statement))
         
     | 
| 
      
 218 
     | 
    
         
            +
                  end
         
     | 
| 
      
 219 
     | 
    
         
            +
                end
         
     | 
| 
      
 220 
     | 
    
         
            +
             
     | 
| 
      
 221 
     | 
    
         
            +
                context 'sparql update' do
         
     | 
| 
      
 222 
     | 
    
         
            +
                  it 'raises BadRequest when invalid document' do
         
     | 
| 
      
 223 
     | 
    
         
            +
                    env = { 'CONTENT_TYPE' => 'application/sparql-update',
         
     | 
| 
      
 224 
     | 
    
         
            +
                            'rack.input'   => StringIO.new('---invalid---') }
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                    expect { subject.request(:patch, 200, {}, env) }
         
     | 
| 
      
 227 
     | 
    
         
            +
                      .to raise_error RDF::LDP::BadRequest
         
     | 
| 
      
 228 
     | 
    
         
            +
                  end
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                  it 'runs sparql update' do
         
     | 
| 
      
 231 
     | 
    
         
            +
                    update = "INSERT DATA { #{subject.subject_uri.to_base} "\
         
     | 
| 
      
 232 
     | 
    
         
            +
                             "#{RDF::Vocab::DC.title.to_base} 'moomin' . }"
         
     | 
| 
      
 233 
     | 
    
         
            +
             
     | 
| 
      
 234 
     | 
    
         
            +
                    env = { 'CONTENT_TYPE' => 'application/sparql-update',
         
     | 
| 
      
 235 
     | 
    
         
            +
                            'rack.input'   => StringIO.new(update) }
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                    expect { subject.request(:patch, 200, {}, env) }
         
     | 
| 
      
 238 
     | 
    
         
            +
                      .to change { subject.graph.count }.from(0).to(1)
         
     | 
| 
      
 239 
     | 
    
         
            +
                  end
         
     | 
| 
      
 240 
     | 
    
         
            +
                end
         
     | 
| 
      
 241 
     | 
    
         
            +
              end
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
              describe '#graph' do
         
     | 
| 
      
 244 
     | 
    
         
            +
                it 'has a graph' do
         
     | 
| 
      
 245 
     | 
    
         
            +
                  expect(subject.graph).to be_a RDF::Enumerable
         
     | 
| 
      
 246 
     | 
    
         
            +
                end
         
     | 
| 
      
 247 
     | 
    
         
            +
              end
         
     | 
| 
      
 248 
     | 
    
         
            +
             
     | 
| 
      
 249 
     | 
    
         
            +
              describe '#subject_uri' do
         
     | 
| 
      
 250 
     | 
    
         
            +
                let(:uri) { RDF::URI('http://ex.org/moomin') }
         
     | 
| 
      
 251 
     | 
    
         
            +
             
     | 
| 
      
 252 
     | 
    
         
            +
                it 'has a uri getter' do
         
     | 
| 
      
 253 
     | 
    
         
            +
                  expect(subject.subject_uri).to eq uri
         
     | 
| 
      
 254 
     | 
    
         
            +
                end
         
     | 
| 
      
 255 
     | 
    
         
            +
             
     | 
| 
      
 256 
     | 
    
         
            +
                it 'aliases to #to_uri' do
         
     | 
| 
      
 257 
     | 
    
         
            +
                  expect(subject.to_uri).to eq uri
         
     | 
| 
      
 258 
     | 
    
         
            +
                end
         
     | 
| 
      
 259 
     | 
    
         
            +
              end
         
     | 
| 
      
 260 
     | 
    
         
            +
             
     | 
| 
      
 261 
     | 
    
         
            +
              describe '#to_response' do
         
     | 
| 
      
 262 
     | 
    
         
            +
                it 'gives the graph minus context' do
         
     | 
| 
      
 263 
     | 
    
         
            +
                  expect(subject.to_response.graph_name).to eq nil
         
     | 
| 
      
 264 
     | 
    
         
            +
                end
         
     | 
| 
      
 265 
     | 
    
         
            +
              end
         
     | 
| 
      
 266 
     | 
    
         
            +
             
     | 
| 
      
 267 
     | 
    
         
            +
              describe '#request' do
         
     | 
| 
      
 268 
     | 
    
         
            +
                context 'with :GET' do
         
     | 
| 
      
 269 
     | 
    
         
            +
                  it 'gives the subject' do
         
     | 
| 
      
 270 
     | 
    
         
            +
                    expect(subject.request(:GET, 200, { 'abc' => 'def' }, {}))
         
     | 
| 
      
 271 
     | 
    
         
            +
                      .to contain_exactly(200, a_hash_including('abc' => 'def'), subject)
         
     | 
| 
      
 272 
     | 
    
         
            +
                  end
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
                  it 'does not call the graph' do
         
     | 
| 
      
 275 
     | 
    
         
            +
                    expect(subject).not_to receive(:graph)
         
     | 
| 
      
 276 
     | 
    
         
            +
                    subject.request(:GET, 200, { 'abc' => 'def' }, {})
         
     | 
| 
      
 277 
     | 
    
         
            +
                  end
         
     | 
| 
      
 278 
     | 
    
         
            +
             
     | 
| 
      
 279 
     | 
    
         
            +
                  it 'returns 410 GONE when destroyed' do
         
     | 
| 
      
 280 
     | 
    
         
            +
                    allow(subject).to receive(:destroyed?).and_return true
         
     | 
| 
      
 281 
     | 
    
         
            +
                    expect { subject.request(:GET, 200, { 'abc' => 'def' }, {}) }
         
     | 
| 
      
 282 
     | 
    
         
            +
                      .to raise_error RDF::LDP::Gone
         
     | 
| 
      
 283 
     | 
    
         
            +
                  end
         
     | 
| 
      
 284 
     | 
    
         
            +
                end
         
     | 
| 
      
 285 
     | 
    
         
            +
             
     | 
| 
      
 286 
     | 
    
         
            +
                context 'with :DELETE' do
         
     | 
| 
      
 287 
     | 
    
         
            +
                  before { subject.create(StringIO.new, 'application/n-triples') }
         
     | 
| 
      
 288 
     | 
    
         
            +
             
     | 
| 
      
 289 
     | 
    
         
            +
                  it 'returns 204' do
         
     | 
| 
      
 290 
     | 
    
         
            +
                    expect(subject.request(:DELETE, 200, {}, {}).first).to eq 204
         
     | 
| 
      
 291 
     | 
    
         
            +
                  end
         
     | 
| 
      
 292 
     | 
    
         
            +
             
     | 
| 
      
 293 
     | 
    
         
            +
                  it 'returns an empty body' do
         
     | 
| 
      
 294 
     | 
    
         
            +
                    expect(subject.request(:DELETE, 200, {}, {}).last)
         
     | 
| 
      
 295 
     | 
    
         
            +
                      .to be_empty
         
     | 
| 
      
 296 
     | 
    
         
            +
                  end
         
     | 
| 
      
 297 
     | 
    
         
            +
             
     | 
| 
      
 298 
     | 
    
         
            +
                  it 'marks resource as destroyed' do
         
     | 
| 
      
 299 
     | 
    
         
            +
                    expect { subject.request(:DELETE, 200, {}, {}) }
         
     | 
| 
      
 300 
     | 
    
         
            +
                      .to change { subject.destroyed? }.from(false).to(true)
         
     | 
| 
      
 301 
     | 
    
         
            +
                  end
         
     | 
| 
      
 302 
     | 
    
         
            +
                end
         
     | 
| 
      
 303 
     | 
    
         
            +
             
     | 
| 
      
 304 
     | 
    
         
            +
                context 'with :PUT',
         
     | 
| 
      
 305 
     | 
    
         
            +
                        if: described_class.private_method_defined?(:put) do
         
     | 
| 
      
 306 
     | 
    
         
            +
                  let(:graph) { RDF::Graph.new }
         
     | 
| 
      
 307 
     | 
    
         
            +
                  let(:env) do
         
     | 
| 
      
 308 
     | 
    
         
            +
                    { 'rack.input' => StringIO.new(graph.dump(:ntriples)),
         
     | 
| 
      
 309 
     | 
    
         
            +
                      'CONTENT_TYPE' => 'application/n-triples' }
         
     | 
| 
      
 310 
     | 
    
         
            +
                  end
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
                  it 'creates the resource' do
         
     | 
| 
      
 313 
     | 
    
         
            +
                    expect { subject.request(:PUT, 200, { 'abc' => 'def' }, env) }
         
     | 
| 
      
 314 
     | 
    
         
            +
                      .to change { subject.exists? }.from(false).to(true)
         
     | 
| 
      
 315 
     | 
    
         
            +
                  end
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
                  it 'responds 201' do
         
     | 
| 
      
 318 
     | 
    
         
            +
                    expect(subject.request(:PUT, 200, { 'abc' => 'def' }, env).first)
         
     | 
| 
      
 319 
     | 
    
         
            +
                      .to eq 201
         
     | 
| 
      
 320 
     | 
    
         
            +
                  end
         
     | 
| 
      
 321 
     | 
    
         
            +
             
     | 
| 
      
 322 
     | 
    
         
            +
                  it 'returns the etag' do
         
     | 
| 
      
 323 
     | 
    
         
            +
                    expect(subject.request(:PUT, 200, { 'abc' => 'def' }, env)[1]['ETag'])
         
     | 
| 
      
 324 
     | 
    
         
            +
                      .to eq subject.etag
         
     | 
| 
      
 325 
     | 
    
         
            +
                  end
         
     | 
| 
      
 326 
     | 
    
         
            +
             
     | 
| 
      
 327 
     | 
    
         
            +
                  context 'when subject exists' do
         
     | 
| 
      
 328 
     | 
    
         
            +
                    before { subject.create(StringIO.new, 'application/n-triples') }
         
     | 
| 
      
 329 
     | 
    
         
            +
             
     | 
| 
      
 330 
     | 
    
         
            +
                    it 'responds 200' do
         
     | 
| 
      
 331 
     | 
    
         
            +
                      expect(subject.request(:PUT, 200, { 'abc' => 'def' }, env))
         
     | 
| 
      
 332 
     | 
    
         
            +
                        .to contain_exactly(200, a_hash_including('abc' => 'def'), subject)
         
     | 
| 
      
 333 
     | 
    
         
            +
                    end
         
     | 
| 
      
 334 
     | 
    
         
            +
             
     | 
| 
      
 335 
     | 
    
         
            +
                    it 'replaces the graph with the input' do
         
     | 
| 
      
 336 
     | 
    
         
            +
                      graph <<
         
     | 
| 
      
 337 
     | 
    
         
            +
                        RDF::Statement(subject.subject_uri, RDF::Vocab::DC.title, 'moomin')
         
     | 
| 
      
 338 
     | 
    
         
            +
                      expect { subject.request(:PUT, 200, { 'abc' => 'def' }, env) }
         
     | 
| 
      
 339 
     | 
    
         
            +
                        .to change { subject.graph.statements.count }.to(1)
         
     | 
| 
      
 340 
     | 
    
         
            +
                    end
         
     | 
| 
      
 341 
     | 
    
         
            +
             
     | 
| 
      
 342 
     | 
    
         
            +
                    it 'updates the etag' do
         
     | 
| 
      
 343 
     | 
    
         
            +
                      graph <<
         
     | 
| 
      
 344 
     | 
    
         
            +
                        RDF::Statement(subject.subject_uri, RDF::Vocab::DC.title, 'moomin')
         
     | 
| 
      
 345 
     | 
    
         
            +
                      expect { subject.request(:PUT, 200, { 'abc' => 'def' }, env) }
         
     | 
| 
      
 346 
     | 
    
         
            +
                        .to change { subject.etag }
         
     | 
| 
      
 347 
     | 
    
         
            +
                    end
         
     | 
| 
      
 348 
     | 
    
         
            +
             
     | 
| 
      
 349 
     | 
    
         
            +
                    it 'returns the etag' do
         
     | 
| 
      
 350 
     | 
    
         
            +
                      expect(subject.request(:PUT, 200, { 'abc' => 'def' }, env)[1]['ETag'])
         
     | 
| 
      
 351 
     | 
    
         
            +
                        .to eq subject.etag
         
     | 
| 
      
 352 
     | 
    
         
            +
                    end
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
                    it 'gives PreconditionFailed when trying to update with wrong Etag' do
         
     | 
| 
      
 355 
     | 
    
         
            +
                      env['HTTP_IF_MATCH'] = 'not an Etag'
         
     | 
| 
      
 356 
     | 
    
         
            +
                      expect { subject.request(:PUT, 200, { 'abc' => 'def' }, env) }
         
     | 
| 
      
 357 
     | 
    
         
            +
                        .to raise_error RDF::LDP::PreconditionFailed
         
     | 
| 
      
 358 
     | 
    
         
            +
                    end
         
     | 
| 
      
 359 
     | 
    
         
            +
             
     | 
| 
      
 360 
     | 
    
         
            +
                    it 'succeeds when giving correct Etag' do
         
     | 
| 
      
 361 
     | 
    
         
            +
                      graph <<
         
     | 
| 
      
 362 
     | 
    
         
            +
                        RDF::Statement(subject.subject_uri, RDF::Vocab::DC.title, 'moomin')
         
     | 
| 
      
 363 
     | 
    
         
            +
                      env['HTTP_IF_MATCH'] = subject.etag
         
     | 
| 
      
 364 
     | 
    
         
            +
                      expect { subject.request(:PUT, 200, { 'abc' => 'def' }, env) }
         
     | 
| 
      
 365 
     | 
    
         
            +
                        .to change { subject.graph.statements.count }
         
     | 
| 
      
 366 
     | 
    
         
            +
                    end
         
     | 
| 
      
 367 
     | 
    
         
            +
                  end
         
     | 
| 
      
 368 
     | 
    
         
            +
                end
         
     | 
| 
      
 369 
     | 
    
         
            +
              end
         
     | 
| 
      
 370 
     | 
    
         
            +
            end
         
     |