diff --git a/README.md b/README.md index 0e25169b..0683227e 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ This is a [Ruby][] implementation of a [SPARQL][] client for [RDF.rb][]. * [Ruby](http://ruby-lang.org/) (>= 2.2.2) * [RDF.rb](http://rubygems.org/gems/rdf) (~> 3.0) -* [Net::HTTP::Persistent](http://rubygems.org/gems/net-http-persistent) (>= 1.4) +* [Net::HTTP::Persistent](http://rubygems.org/gems/net-http-persistent) (~> 3.0) * Soft dependency on [SPARQL](http://rubygems.org/gems/sparql) (~> 3.0) -* Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.7) +* Soft dependency on [Nokogiri](http://rubygems.org/gems/nokogiri) (>= 1.8) ## Installation diff --git a/lib/sparql/client.rb b/lib/sparql/client.rb index 5c329784..693a0a26 100644 --- a/lib/sparql/client.rb +++ b/lib/sparql/client.rb @@ -95,6 +95,9 @@ def initialize(url, options = {}, &block) @url, @options = RDF::URI.new(url.to_s), options.dup @headers = @options.delete(:headers) || {} @http = http_klass(@url.scheme) + + # Close the http connection when object is deallocated + ObjectSpace.define_finalizer(self, proc {@http.shutdown if @http.respond_to?(:shutdown)}) end if block_given? @@ -105,6 +108,16 @@ def initialize(url, options = {}, &block) end end + ## + # Closes a client instance by finishing the connection. + # The client is unavailable for any further data operations; an IOError is raised if such an attempt is made. I/O streams are automatically closed when they are claimed by the garbage collector. + # @return [void] `self` + def close + @http.shutdown if @http + @http = nil + self + end + ## # Executes a boolean `ASK` query. # @@ -288,6 +301,7 @@ def nodes # @option options [String] :content_type # @option options [Hash] :headers # @return [Array] + # @raise [IOError] if connection is closed # @see http://www.w3.org/TR/sparql11-protocol/#query-operation def query(query, options = {}) @op = :query @@ -315,6 +329,7 @@ def query(query, options = {}) # @option options [String] :content_type # @option options [Hash] :headers # @return [void] `self` + # @raise [IOError] if connection is closed # @see http://www.w3.org/TR/sparql11-protocol/#update-operation def update(query, options = {}) @op = :update @@ -338,6 +353,7 @@ def update(query, options = {}) # @option options [String] :content_type # @option options [Hash] :headers # @return [String] + # @raise [IOError] if connection is closed def response(query, options = {}) headers = options[:headers] || {} headers['Accept'] = options[:content_type] if options[:content_type] @@ -658,11 +674,7 @@ def http_klass(scheme) value = ENV['https_proxy'] proxy_url = URI.parse(value) unless value.nil? || value.empty? end - klass = if Net::HTTP::Persistent::VERSION >= '3.0' - Net::HTTP::Persistent.new(name: self.class.to_s, proxy: proxy_url) - else - Net::HTTP::Persistent.new(self.class.to_s, proxy_url) - end + klass = Net::HTTP::Persistent.new(name: self.class.to_s, proxy: proxy_url) klass.keep_alive = @options[:keep_alive] || 120 klass.read_timeout = @options[:read_timeout] || 60 klass @@ -676,6 +688,7 @@ def http_klass(scheme) # @yield [response] # @yieldparam [Net::HTTPResponse] response # @return [Net::HTTPResponse] + # @raise [IOError] if connection is closed # @see http://www.w3.org/TR/sparql11-protocol/#query-operation def request(query, headers = {}, &block) # Make sure an appropriate Accept header is present @@ -693,6 +706,7 @@ def request(query, headers = {}, &block) pre_http_hook(request) if respond_to?(:pre_http_hook) + raise IOError, "Client has been closed" unless @http response = @http.request(::URI.parse(url.to_s), request) post_http_hook(response) if respond_to?(:post_http_hook) diff --git a/sparql-client.gemspec b/sparql-client.gemspec index 5e7b657c..737f9d0b 100755 --- a/sparql-client.gemspec +++ b/sparql-client.gemspec @@ -25,7 +25,7 @@ Gem::Specification.new do |gem| gem.required_ruby_version = '>= 2.2.2' gem.requirements = [] gem.add_runtime_dependency 'rdf', '~> 3.0' - gem.add_runtime_dependency 'net-http-persistent', '>= 2.9', '< 4' + gem.add_runtime_dependency 'net-http-persistent', '~> 3.0' gem.add_development_dependency 'rdf-spec', '~> 3.0' gem.add_development_dependency 'sparql', '~> 3.0' gem.add_development_dependency 'rspec', '~> 3.7' diff --git a/spec/client_spec.rb b/spec/client_spec.rb index 001846e8..0fe1c708 100644 --- a/spec/client_spec.rb +++ b/spec/client_spec.rb @@ -55,65 +55,65 @@ def response(header) end end - it "should handle successful response with plain header" do + it "handles successful response with plain header" do expect(subject).to receive(:request).and_yield response('text/plain') expect(RDF::Reader).to receive(:for).with(:content_type => 'text/plain').and_call_original subject.query(query) end - it "should handle successful response with boolean header" do + it "handles successful response with boolean header" do expect(subject).to receive(:request).and_yield response(SPARQL::Client::RESULT_BOOL) expect(subject.query(query)).to be_falsey end - it "should handle successful response with JSON header" do + it "handles successful response with JSON header" do expect(subject).to receive(:request).and_yield response(SPARQL::Client::RESULT_JSON) expect(subject.class).to receive(:parse_json_bindings) subject.query(query) end - it "should handle successful response with XML header" do + it "handles successful response with XML header" do expect(subject).to receive(:request).and_yield response(SPARQL::Client::RESULT_XML) expect(subject.class).to receive(:parse_xml_bindings) subject.query(query) end - it "should handle successful response with CSV header" do + it "handles successful response with CSV header" do expect(subject).to receive(:request).and_yield response(SPARQL::Client::RESULT_CSV) expect(subject.class).to receive(:parse_csv_bindings) subject.query(query) end - it "should handle successful response with TSV header" do + it "handles successful response with TSV header" do expect(subject).to receive(:request).and_yield response(SPARQL::Client::RESULT_TSV) expect(subject.class).to receive(:parse_tsv_bindings) subject.query(query) end - it "should handle successful response with overridden XML header" do + it "handles successful response with overridden XML header" do expect(subject).to receive(:request).and_yield response(SPARQL::Client::RESULT_XML) expect(subject.class).to receive(:parse_json_bindings) subject.query(query, :content_type => SPARQL::Client::RESULT_JSON) end - it "should handle successful response with no content type" do + it "handles successful response with no content type" do expect(subject).to receive(:request).and_yield response(nil) expect { subject.query(query) }.not_to raise_error end - it "should handle successful response with overridden plain header" do + it "handles successful response with overridden plain header" do expect(subject).to receive(:request).and_yield response('text/plain') expect(RDF::Reader).to receive(:for).with(:content_type => 'text/turtle').and_call_original subject.query(query, :content_type => 'text/turtle') end - it "should handle successful response with custom headers" do + it "handles successful response with custom headers" do expect(subject).to receive(:request).with(anything, "Authorization" => "Basic XXX=="). and_yield response('text/plain') subject.query(query, :headers => {"Authorization" => "Basic XXX=="}) end - it "should handle successful response with initial custom headers" do + it "handles successful response with initial custom headers" do options = {:headers => {"Authorization" => "Basic XXX=="}, :method => :get} client = SPARQL::Client.new('http://data.linkedmdb.org/sparql', options) client.instance_variable_set :@http, double(:request => response('text/plain')) @@ -121,7 +121,7 @@ def response(header) client.query(query) end - it "should enable overriding the http method" do + it "enables overriding the http method" do stub_request(:get, "http://data.linkedmdb.org/sparql?query=DESCRIBE%20?kb%20WHERE%20%7B%20?kb%20%3Chttp://data.linkedmdb.org/resource/movie/actor_name%3E%20%22Kevin%20Bacon%22%20.%20%7D"). to_return(:status => 200, :body => "", :headers => { 'Content-Type' => 'application/n-triples'}) allow(subject).to receive(:request_method).with(query).and_return(:get) @@ -129,7 +129,7 @@ def response(header) subject.query(query) end - it "should support international characters in response body" do + it "supports international characters in response body" do client = SPARQL::Client.new('http://dbpedia.org/sparql') json = { :results => { @@ -145,6 +145,11 @@ def response(header) expect(result[:name].to_s).to eq "東京" end + it "generates IOError when querying closed client" do + subject.close + expect{ subject.query(ask_query) }.to raise_error IOError + end + context "Redirects" do before do WebMock.stub_request(:any, 'http://data.linkedmdb.org/sparql'). @@ -167,7 +172,7 @@ def response(header) end context "Accept Header" do - it "should use application/sparql-results+json for ASK" do + it "uses application/sparql-results+json for ASK" do WebMock.stub_request(:any, 'http://data.linkedmdb.org/sparql'). to_return(:body => '{}', :status => 200, :headers => { 'Content-Type' => 'application/sparql-results+json'}) subject.query(ask_query) @@ -175,7 +180,7 @@ def response(header) with(:headers => {'Accept'=>'application/sparql-results+json, application/sparql-results+xml, text/boolean, text/tab-separated-values;q=0.8, text/csv;q=0.2, */*;q=0.1'}) end - it "should use application/n-triples for CONSTRUCT" do + it "uses application/n-triples for CONSTRUCT" do WebMock.stub_request(:any, 'http://data.linkedmdb.org/sparql'). to_return(:body => '', :status => 200, :headers => { 'Content-Type' => 'application/n-triples'}) subject.query(construct_query) @@ -183,7 +188,7 @@ def response(header) with(:headers => {'Accept'=>'application/n-triples, text/plain, */*;q=0.1'}) end - it "should use application/n-triples for DESCRIBE" do + it "uses application/n-triples for DESCRIBE" do WebMock.stub_request(:any, 'http://data.linkedmdb.org/sparql'). to_return(:body => '', :status => 200, :headers => { 'Content-Type' => 'application/n-triples'}) subject.query(describe_query) @@ -191,7 +196,7 @@ def response(header) with(:headers => {'Accept'=>'application/n-triples, text/plain, */*;q=0.1'}) end - it "should use application/sparql-results+json for SELECT" do + it "uses application/sparql-results+json for SELECT" do WebMock.stub_request(:any, 'http://data.linkedmdb.org/sparql'). to_return(:body => '{}', :status => 200, :headers => { 'Content-Type' => 'application/sparql-results+json'}) subject.query(select_query) @@ -201,21 +206,21 @@ def response(header) end context "Alternative Endpoint" do - it "should use the default endpoint if no alternative endpoint is provided" do + it "uses the default endpoint if no alternative endpoint is provided" do WebMock.stub_request(:any, 'http://data.linkedmdb.org/sparql'). to_return(:body => '', :status => 200) subject.update(update_query) expect(WebMock).to have_requested(:post, "http://data.linkedmdb.org/sparql") end - it "should use the alternative endpoint if provided" do + it "uses the alternative endpoint if provided" do WebMock.stub_request(:any, 'http://data.linkedmdb.org/alternative'). to_return(:body => '', :status => 200) subject.update(update_query, { endpoint: "http://data.linkedmdb.org/alternative" }) expect(WebMock).to have_requested(:post, "http://data.linkedmdb.org/alternative") end - it "should not use the alternative endpoint for a select query" do + it "does not use the alternative endpoint for a select query" do WebMock.stub_request(:any, 'http://data.linkedmdb.org/sparql'). to_return(:body => '', :status => 200) WebMock.stub_request(:any, 'http://data.linkedmdb.org/alternative'). @@ -253,7 +258,7 @@ def response(header) let(:graph) {RDF::Graph.new << RDF::Statement(RDF::URI('http://example/s'), RDF::URI('http://example/p'), "o")} subject {SPARQL::Client.new(repo)} - it "should query repository" do + it "queries repository" do expect(SPARQL).to receive(:execute).with(query, repo, {}) subject.query(query) end @@ -301,7 +306,7 @@ def response(header) end context "when parsing XML" do - it "should parse binding results correctly" do + it "parses binding results correctly" do xml = File.read("spec/fixtures/results.xml") nodes = {} solutions = SPARQL::Client::parse_xml_bindings(xml, nodes) @@ -317,19 +322,19 @@ def response(header) expect(solutions[0]["x"]).to eq nodes["r2"] end - it "should parse boolean true results correctly" do + it "parses boolean true results correctly" do xml = File.read("spec/fixtures/bool_true.xml") expect(SPARQL::Client::parse_xml_bindings(xml)).to eq true end - it "should parse boolean false results correctly" do + it "parses boolean false results correctly" do xml = File.read("spec/fixtures/bool_false.xml") expect(SPARQL::Client::parse_xml_bindings(xml)).to eq false end end context "when parsing JSON" do - it "should parse binding results correctly" do + it "parses binding results correctly" do xml = File.read("spec/fixtures/results.json") nodes = {} solutions = SPARQL::Client::parse_json_bindings(xml, nodes) @@ -345,19 +350,19 @@ def response(header) expect(solutions[0]["x"]).to eq nodes["r2"] end - it "should parse boolean true results correctly" do + it "parses boolean true results correctly" do json = '{"boolean": true}' expect(SPARQL::Client::parse_json_bindings(json)).to eq true end - it "should parse boolean true results correctly" do + it "parses boolean true results correctly" do json = '{"boolean": false}' expect(SPARQL::Client::parse_json_bindings(json)).to eq false end end context "when parsing CSV" do - it "should parse binding results correctly" do + it "parses binding results correctly" do csv = File.read("spec/fixtures/results.csv") nodes = {} solutions = SPARQL::Client::parse_csv_bindings(csv, nodes) @@ -373,7 +378,7 @@ def response(header) end context "when parsing TSV" do - it "should parse binding results correctly" do + it "parses binding results correctly" do tsv = File.read("spec/fixtures/results.tsv") nodes = {} solutions = SPARQL::Client::parse_tsv_bindings(tsv, nodes) diff --git a/spec/query_spec.rb b/spec/query_spec.rb index c2da28fc..b77351d2 100644 --- a/spec/query_spec.rb +++ b/spec/query_spec.rb @@ -4,19 +4,19 @@ subject {SPARQL::Client::Query} context "when building queries" do - it "should support ASK queries" do + it "supports ASK queries" do expect(subject).to respond_to(:ask) end - it "should support SELECT queries" do + it "supports SELECT queries" do expect(subject).to respond_to(:select) end - it "should support DESCRIBE queries" do + it "supports DESCRIBE queries" do expect(subject).to respond_to(:describe) end - it "should support CONSTRUCT queries" do + it "supports CONSTRUCT queries" do expect(subject).to respond_to(:construct) end end @@ -84,38 +84,38 @@ end context "when building SELECT queries" do - it "should support basic graph patterns" do + it "supports basic graph patterns" do expect(subject.select.where([:s, :p, :o]).to_s).to eq "SELECT * WHERE { ?s ?p ?o . }" end - it "should support projection" do + it "supports projection" do expect(subject.select(:s).where([:s, :p, :o]).to_s).to eq "SELECT ?s WHERE { ?s ?p ?o . }" expect(subject.select(:s, :p).where([:s, :p, :o]).to_s).to eq "SELECT ?s ?p WHERE { ?s ?p ?o . }" expect(subject.select(:s, :p, :o).where([:s, :p, :o]).to_s).to eq "SELECT ?s ?p ?o WHERE { ?s ?p ?o . }" end - it "should support FROM" do + it "supports FROM" do uri = "http://example.org/dft.ttl" expect(subject.select.from(RDF::URI.new(uri)).where([:s, :p, :o]).to_s).to eq "SELECT * FROM <#{uri}> WHERE { ?s ?p ?o . }" end - it "should support DISTINCT" do + it "supports DISTINCT" do expect(subject.select(:s, :distinct => true).where([:s, :p, :o]).to_s).to eq "SELECT DISTINCT ?s WHERE { ?s ?p ?o . }" expect(subject.select(:s).distinct.where([:s, :p, :o]).to_s).to eq "SELECT DISTINCT ?s WHERE { ?s ?p ?o . }" expect(subject.select.distinct.where([:s, :p, :o]).to_s).to eq "SELECT DISTINCT * WHERE { ?s ?p ?o . }" end - it "should support REDUCED" do + it "supports REDUCED" do expect(subject.select(:s, :reduced => true).where([:s, :p, :o]).to_s).to eq "SELECT REDUCED ?s WHERE { ?s ?p ?o . }" expect(subject.select(:s).reduced.where([:s, :p, :o]).to_s).to eq "SELECT REDUCED ?s WHERE { ?s ?p ?o . }" end - it "should support GRAPH" do + it "supports GRAPH" do expect(subject.select.graph(:g).where([:s, :p, :o]).to_s).to eq "SELECT * WHERE { GRAPH ?g { ?s ?p ?o . } }" expect(subject.select.graph('http://example.org/').where([:s, :p, :o]).to_s).to eq "SELECT * WHERE { GRAPH { ?s ?p ?o . } }" end - it "should support COUNT" do + it "supports COUNT" do expect(subject.select(:count => { :s => :c }).where([:s, :p, :o]).to_s).to eq "SELECT ( COUNT(?s) AS ?c ) WHERE { ?s ?p ?o . }" expect(subject.select(:count => { :s => :c }, :distinct => true).where([:s, :p, :o]).to_s).to eq "SELECT ( COUNT(DISTINCT ?s) AS ?c ) WHERE { ?s ?p ?o . }" expect(subject.select(:count => { :s => '?c' }).where([:s, :p, :o]).to_s).to eq "SELECT ( COUNT(?s) AS ?c ) WHERE { ?s ?p ?o . }" @@ -123,7 +123,7 @@ expect(subject.select(:o, :count => { :s => :c }).where([:s, :p, :o]).to_s).to eq "SELECT ?o ( COUNT(?s) AS ?c ) WHERE { ?s ?p ?o . }" end - it "should support VALUES" do + it "supports VALUES" do expect(subject.select(:s).where([:s, :p, :o]).values(:o, "Object").to_s).to eq 'SELECT ?s WHERE { ?s ?p ?o . VALUES (?o) { ( "Object" ) } }' expect(subject.select(:s).where([:s, :p, :o]).values(:o, "1", "2").to_s).to eq 'SELECT ?s WHERE { ?s ?p ?o . VALUES (?o) { ( "1" ) ( "2" ) } }' expect(subject.select(:s).where([:s, :p, :o]).values([:o, :p], ["Object", "Predicate"]).to_s).to eq 'SELECT ?s WHERE { ?s ?p ?o . VALUES (?o ?p) { ( "Object" "Predicate" ) } }' @@ -131,12 +131,12 @@ expect(subject.select(:s).where([:s, :p, :o]).values([:o, :p], [nil, "2"], ["3", nil]).to_s).to eq 'SELECT ?s WHERE { ?s ?p ?o . VALUES (?o ?p) { ( UNDEF "2" ) ( "3" UNDEF ) } }' end - it "should support GROUP BY" do + it "supports GROUP BY" do expect(subject.select(:s).where([:s, :p, :o]).group_by(:s).to_s).to eq "SELECT ?s WHERE { ?s ?p ?o . } GROUP BY ?s" expect(subject.select(:s).where([:s, :p, :o]).group_by('?s').to_s).to eq "SELECT ?s WHERE { ?s ?p ?o . } GROUP BY ?s" end - it "should support ORDER BY" do + it "supports ORDER BY" do expect(subject.select.where([:s, :p, :o]).order_by(:o).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o" expect(subject.select.where([:s, :p, :o]).order_by(:o, :p).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o ?p" expect(subject.select.where([:s, :p, :o]).order_by('?o').to_s).to eq "SELECT * WHERE { ?s ?p ?o . } ORDER BY ?o" @@ -157,54 +157,54 @@ expect { subject.select.where([:s, :p, :o]).order_by(42 => :asc).to_s }.to raise_error(ArgumentError) end - it "should support ORDER BY ASC" do + it "supports ORDER BY ASC" do expect(subject.select.where([:s, :p, :o]).order.asc(:o).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } ORDER BY ASC(?o)" expect(subject.select.where([:s, :p, :o]).asc(:o).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } ORDER BY ASC(?o)" expect { subject.select.where([:s, :p, :o]).order.asc(:o, :p).to_s }.to raise_error(ArgumentError) end - it "should support ORDER BY DESC" do + it "supports ORDER BY DESC" do expect(subject.select.where([:s, :p, :o]).order.desc(:o).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } ORDER BY DESC(?o)" expect(subject.select.where([:s, :p, :o]).desc(:o).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } ORDER BY DESC(?o)" expect { subject.select.where([:s, :p, :o]).order.desc(:o, :p).to_s }.to raise_error(ArgumentError) end - it "should support OFFSET" do + it "supports OFFSET" do expect(subject.select.where([:s, :p, :o]).offset(100).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } OFFSET 100" end - it "should support LIMIT" do + it "supports LIMIT" do expect(subject.select.where([:s, :p, :o]).limit(10).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } LIMIT 10" end - it "should support OFFSET with LIMIT" do + it "supports OFFSET with LIMIT" do expect(subject.select.where([:s, :p, :o]).offset(100).limit(10).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } OFFSET 100 LIMIT 10" expect(subject.select.where([:s, :p, :o]).slice(100, 10).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } OFFSET 100 LIMIT 10" end - it "should support PREFIX" do + it "supports PREFIX" do prefixes = ["dc: ", "foaf: "] expect(subject.select.prefix(prefixes[0]).prefix(prefixes[1]).where([:s, :p, :o]).to_s).to eq "PREFIX #{prefixes[0]} PREFIX #{prefixes[1]} SELECT * WHERE { ?s ?p ?o . }" end - it "should support OPTIONAL" do + it "supports OPTIONAL" do expect(subject.select.where([:s, :p, :o]).optional([:s, RDF.type, :o], [:s, RDF::URI("http://purl.org/dc/terms/abstract"), :o]).to_s).to eq "SELECT * WHERE { ?s ?p ?o . OPTIONAL { ?s a ?o . ?s ?o . } }" end - it "should support OPTIONAL with filter in block" do + it "supports OPTIONAL with filter in block" do expect(subject.select.where([:s, :p, :o]).optional([:s, RDF.value, :o]) {filter("langmatches(lang(?o), 'en')")}.to_s).to eq "SELECT * WHERE { ?s ?p ?o . OPTIONAL { ?s ?o . FILTER(langmatches(lang(?o), 'en')) . } }" end - it "should support multiple OPTIONALs" do + it "supports multiple OPTIONALs" do expect(subject.select.where([:s, :p, :o]).optional([:s, RDF.type, :o]).optional([:s, RDF::URI("http://purl.org/dc/terms/abstract"), :o]).to_s).to eq "SELECT * WHERE { ?s ?p ?o . OPTIONAL { ?s a ?o . } OPTIONAL { ?s ?o . } }" end - it "should support subqueries" do + it "supports subqueries" do subquery = subject.select.where([:s, :p, :o]) expect(subject.select.where(subquery).where([:s, :p, :o]).to_s).to eq "SELECT * WHERE { { SELECT * WHERE { ?s ?p ?o . } } . ?s ?p ?o . }" end - it "should support subqueries using block" do + it "supports subqueries using block" do expect(subject.select.where([:s, :p, :o]) {select.where([:s, :p, :o])}.to_s).to eq "SELECT * WHERE { { SELECT * WHERE { ?s ?p ?o . } } . ?s ?p ?o . }" end @@ -213,40 +213,40 @@ end context "with property paths" do - it "should support the InversePath expression" do + it "supports the InversePath expression" do expect(subject.select.where([:s, ["^",RDF::RDFS.subClassOf], :o]).to_s).to eq "SELECT * WHERE { ?s ^<#{RDF::RDFS.subClassOf}> ?o . }" end - it "should support the SequencePath expression" do + it "supports the SequencePath expression" do expect(subject.select.where([:s, [RDF.type,"/",RDF::RDFS.subClassOf], :o]).to_s).to eq "SELECT * WHERE { ?s a/<#{RDF::RDFS.subClassOf}> ?o . }" end - it "should support the AlternativePath expression" do + it "supports the AlternativePath expression" do expect(subject.select.where([:s, [RDF.type,"|",RDF::RDFS.subClassOf], :o]).to_s).to eq "SELECT * WHERE { ?s a|<#{RDF::RDFS.subClassOf}> ?o . }" end - it "should support the ZeroOrMore expression" do + it "supports the ZeroOrMore expression" do expect(subject.select.where([:s, [RDF::RDFS.subClassOf,"*"], :o]).to_s).to eq "SELECT * WHERE { ?s <#{RDF::RDFS.subClassOf}>* ?o . }" end - it "should support the OneOrMore expression" do + it "supports the OneOrMore expression" do expect(subject.select.where([:s, [RDF::RDFS.subClassOf,"+"], :o]).to_s).to eq "SELECT * WHERE { ?s <#{RDF::RDFS.subClassOf}>+ ?o . }" end - it "should support the ZeroOrOne expression" do + it "supports the ZeroOrOne expression" do expect(subject.select.where([:s, [RDF::RDFS.subClassOf,"?"], :o]).to_s).to eq "SELECT * WHERE { ?s <#{RDF::RDFS.subClassOf}>? ?o . }" end - it "should support the NegatedPropertySet expression" do + it "supports the NegatedPropertySet expression" do expect(subject.select.where([:s, ["!",[RDF::RDFS.subClassOf,"|",RDF.type]], :o]).to_s).to eq "SELECT * WHERE { ?s !(<#{RDF::RDFS.subClassOf}>|a) ?o . }" end end context "with unions" do - it "should support pattern arguments" do + it "supports pattern arguments" do expect(subject.select.where([:s, :p, :o]).union([:s, :p, :o]).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } UNION { ?s ?p ?o . }" end - it "should support query arguments" do + it "supports query arguments" do subquery = subject.select.where([:s, :p, :o]) expect(subject.select.where([:s, :p, :o]).union(subquery).to_s).to eq "SELECT * WHERE { ?s ?p ?o . } UNION { ?s ?p ?o . }" end - it "should support block" do + it "supports block" do expect(subject.select.where([:s, :p, :o]).union {|q| q.where([:s, :p, :o])}.to_s).to eq "SELECT * WHERE { ?s ?p ?o . } UNION { ?s ?p ?o . }" end @@ -261,16 +261,16 @@ end context "with minus" do - it "should support pattern arguments" do + it "supports pattern arguments" do expect(subject.select.where([:s, :p, :o]).minus([:s, :p, :o]).to_s).to eq "SELECT * WHERE { ?s ?p ?o . MINUS { ?s ?p ?o . } }" end - it "should support query arguments" do + it "supports query arguments" do subquery = subject.select.where([:s, :p, :o]) expect(subject.select.where([:s, :p, :o]).minus(subquery).to_s).to eq "SELECT * WHERE { ?s ?p ?o . MINUS { ?s ?p ?o . } }" end - it "should support block" do + it "supports block" do expect(subject.select.where([:s, :p, :o]).minus {|q| q.where([:s, :p, :o])}.to_s).to eq "SELECT * WHERE { ?s ?p ?o . MINUS { ?s ?p ?o . } }" end @@ -286,17 +286,17 @@ end context "when building DESCRIBE queries" do - it "should support basic graph patterns" do + it "supports basic graph patterns" do expect(subject.describe.where([:s, :p, :o]).to_s).to eq "DESCRIBE * WHERE { ?s ?p ?o . }" end - it "should support projection" do + it "supports projection" do expect(subject.describe(:s).where([:s, :p, :o]).to_s).to eq "DESCRIBE ?s WHERE { ?s ?p ?o . }" expect(subject.describe(:s, :p).where([:s, :p, :o]).to_s).to eq "DESCRIBE ?s ?p WHERE { ?s ?p ?o . }" expect(subject.describe(:s, :p, :o).where([:s, :p, :o]).to_s).to eq "DESCRIBE ?s ?p ?o WHERE { ?s ?p ?o . }" end - it "should support RDF::URI arguments" do + it "supports RDF::URI arguments" do uris = ['http://www.bbc.co.uk/programmes/b007stmh#programme', 'http://www.bbc.co.uk/programmes/b00lg2xb#programme'] expect(subject.describe(RDF::URI.new(uris[0]),RDF::URI.new(uris[1])).to_s).to eq "DESCRIBE <#{uris[0]}> <#{uris[1]}>" end @@ -307,7 +307,7 @@ end context "when building CONSTRUCT queries" do - it "should support basic graph patterns" do + it "supports basic graph patterns" do expect(subject.construct([:s, :p, :o]).where([:s, :p, :o]).to_s).to eq "CONSTRUCT { ?s ?p ?o . } WHERE { ?s ?p ?o . }" end diff --git a/spec/repository_spec.rb b/spec/repository_spec.rb index 5c706572..ff42ad26 100644 --- a/spec/repository_spec.rb +++ b/spec/repository_spec.rb @@ -20,6 +20,6 @@ @base_repo.insert(*@statements) end - its(:count) {should == @statements.size} + its(:count) {is_expected.to eql @statements.size} end end diff --git a/spec/update_spec.rb b/spec/update_spec.rb index 44f9e2ce..b1df03b4 100644 --- a/spec/update_spec.rb +++ b/spec/update_spec.rb @@ -4,51 +4,51 @@ subject {SPARQL::Client::Update} context "when building queries" do - it "should support INSERT DATA operations" do + it "supports INSERT DATA operations" do expect(subject).to respond_to(:insert_data) end - it "should support DELETE DATA operations" do + it "supports DELETE DATA operations" do expect(subject).to respond_to(:delete_data) end - it "should support DELETE/INSERT operations", pending: true do + it "supports DELETE/INSERT operations", pending: true do expect(subject).to respond_to(:what) expect(subject).to respond_to(:delete) expect(subject).to respond_to(:insert) end - it "should support LOAD operations" do + it "supports LOAD operations" do expect(subject).to respond_to(:load) end - it "should support CLEAR operations" do + it "supports CLEAR operations" do expect(subject).to respond_to(:clear) end - it "should support CREATE operations" do + it "supports CREATE operations" do expect(subject).to respond_to(:create) end - it "should support DROP operations" do + it "supports DROP operations" do expect(subject).to respond_to(:drop) end - it "should support COPY operations", pending: true do + it "supports COPY operations", pending: true do expect(subject).to respond_to(:copy) # TODO end - it "should support MOVE operations", pending: true do + it "supports MOVE operations", pending: true do expect(subject).to respond_to(:move) # TODO end - it "should support ADD operations", pending: true do + it "supports ADD operations", pending: true do expect(subject).to respond_to(:add) # TODO end end context "when building INSERT DATA queries" do - it "should support empty input" do + it "supports empty input" do expect(subject.insert_data(RDF::Graph.new).to_s).to eq "INSERT DATA {\n}\n" end @@ -56,14 +56,14 @@ expect(subject.insert_data(RDF::Graph.new)).not_to be_expects_statements end - it "should support non-empty input" do + it "supports non-empty input" do data = RDF::Graph.new do |graph| graph << [RDF::URI('http://example.org/jhacker'), RDF::URI("http://xmlns.com/foaf/0.1/name"), "J. Random Hacker"] end expect(subject.insert_data(data).to_s).to eq "INSERT DATA {\n \"J. Random Hacker\" .\n}\n" end - it "should support the GRAPH modifier" do + it "supports the GRAPH modifier" do [subject.insert_data(RDF::Graph.new, :graph => 'http://example.org/'), subject.insert_data(RDF::Graph.new).graph('http://example.org/')].each do |example| expect(example.to_s).to eq "INSERT DATA { GRAPH {\n}}\n" @@ -72,7 +72,7 @@ end context "when building DELETE DATA queries" do - it "should support empty input" do + it "supports empty input" do expect(subject.delete_data(RDF::Graph.new).to_s).to eq "DELETE DATA {\n}\n" end @@ -80,14 +80,14 @@ expect(subject.delete_data(RDF::Graph.new)).to be_expects_statements end - it "should support non-empty input" do + it "supports non-empty input" do data = RDF::Graph.new do |graph| graph << [RDF::URI('http://example.org/jhacker'), RDF::URI("http://xmlns.com/foaf/0.1/name"), "J. Random Hacker"] end expect(subject.delete_data(data).to_s).to eq "DELETE DATA {\n \"J. Random Hacker\" .\n}\n" end - it "should support the GRAPH modifier" do + it "supports the GRAPH modifier" do [subject.delete_data(RDF::Graph.new, :graph => 'http://example.org/'), subject.delete_data(RDF::Graph.new).graph('http://example.org/')].each do |example| expect(example.to_s).to eq "DELETE DATA { GRAPH {\n}}\n" @@ -102,7 +102,7 @@ context "when building LOAD queries" do let(:from_url) {'http://example.org/data.rdf'} - it "should require a source URI" do + it "requires a source URI" do expect(subject.load(from_url).to_s).to eq "LOAD <#{from_url}>" end @@ -110,14 +110,14 @@ expect(subject.load(from_url)).to be_expects_statements end - it "should support the SILENT modifier" do + it "supports the SILENT modifier" do [subject.load(from_url).silent, subject.load(from_url, :silent => true)].each do |example| expect(example.to_s).to eq "LOAD SILENT <#{from_url}>" end end - it "should support the INTO GRAPH modifier" do + it "supports the INTO GRAPH modifier" do [subject.load(from_url).into(from_url), subject.load(from_url, :into => from_url)].each do |example| expect(example.to_s).to eq "LOAD <#{from_url}> INTO GRAPH <#{from_url}>" @@ -126,7 +126,7 @@ end context "when building CLEAR queries" do - it "should support the CLEAR GRAPH operation" do + it "supports the CLEAR GRAPH operation" do graph_uri = 'http://example.org/' [subject.clear.graph(graph_uri), subject.clear(:graph, graph_uri)].each do |example| @@ -134,19 +134,19 @@ end end - it "should support the CLEAR DEFAULT operation" do + it "supports the CLEAR DEFAULT operation" do [subject.clear.default, subject.clear(:default)].each do |example| expect(example.to_s).to eq "CLEAR DEFAULT" end end - it "should support the CLEAR NAMED operation" do + it "supports the CLEAR NAMED operation" do [subject.clear.named, subject.clear(:named)].each do |example| expect(example.to_s).to eq "CLEAR NAMED" end end - it "should support the CLEAR ALL operation" do + it "supports the CLEAR ALL operation" do [subject.clear.all, subject.clear(:all)].each do |example| expect(example.to_s).to eq "CLEAR ALL" end @@ -156,7 +156,7 @@ expect(subject.clear.all).not_to be_expects_statements end - it "should support the SILENT modifier" do + it "supports the SILENT modifier" do [subject.clear(:all).silent, subject.clear(:all, :silent => true)].each do |example| expect(example.to_s).to eq "CLEAR SILENT ALL" @@ -167,11 +167,11 @@ context "when building CREATE queries" do let(:graph_uri) {'http://example.org/'} - it "should require a graph URI" do + it "requires a graph URI" do expect(subject.create(graph_uri).to_s).to eq "CREATE GRAPH <#{graph_uri}>" end - it "should support the SILENT modifier" do + it "supports the SILENT modifier" do [subject.create(graph_uri).silent, subject.create(graph_uri, :silent => true)].each do |example| expect(example.to_s).to eq "CREATE SILENT GRAPH <#{graph_uri}>" @@ -184,7 +184,7 @@ end context "when building DROP queries" do - it "should support the DROP GRAPH operation" do + it "supports the DROP GRAPH operation" do graph_uri = 'http://example.org/' [subject.drop.graph(graph_uri), subject.drop(:graph, graph_uri)].each do |example| @@ -192,19 +192,19 @@ end end - it "should support the DROP DEFAULT operation" do + it "supports the DROP DEFAULT operation" do [subject.drop.default, subject.drop(:default)].each do |example| expect(example.to_s).to eq "DROP DEFAULT" end end - it "should support the DROP NAMED operation" do + it "supports the DROP NAMED operation" do [subject.drop.named, subject.drop(:named)].each do |example| expect(example.to_s).to eq "DROP NAMED" end end - it "should support the DROP ALL operation" do + it "supports the DROP ALL operation" do [subject.drop.all, subject.drop(:all)].each do |example| expect(example.to_s).to eq "DROP ALL" end @@ -214,7 +214,7 @@ expect(subject.drop.all).not_to be_expects_statements end - it "should support the SILENT modifier" do + it "supports the SILENT modifier" do [subject.drop(:all).silent, subject.drop(:all, :silent => true)].each do |example| expect(example.to_s).to eq "DROP SILENT ALL"