sparql-client 0.0.1 → 0.0.2
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.
- data/README +40 -16
- data/VERSION +1 -1
- data/lib/sparql.rb +3 -1
- data/lib/sparql/client.rb +60 -9
- data/lib/sparql/client/query.rb +267 -0
- data/lib/sparql/client/repository.rb +170 -0
- data/lib/sparql/{version.rb → client/version.rb} +1 -1
- metadata +10 -8
    
        data/README
    CHANGED
    
    | @@ -8,43 +8,62 @@ This is a pure-Ruby implementation of a [SPARQL][] client for [RDF.rb][]. | |
| 8 8 | 
             
            Features
         | 
| 9 9 | 
             
            --------
         | 
| 10 10 |  | 
| 11 | 
            -
            *  | 
| 11 | 
            +
            * Executes queries against any SPARQL 1.0-compatible endpoints over HTTP.
         | 
| 12 | 
            +
            * Provides a query builder [DSL][] for `ASK`, `SELECT`, `DESCRIBE` and
         | 
| 13 | 
            +
              `CONSTRUCT` queries.
         | 
| 14 | 
            +
            * Supports tuple result sets in both XML and JSON formats, with JSON being
         | 
| 15 | 
            +
              the preferred default for content negotiation purposes.
         | 
| 16 | 
            +
            * Supports graph results in any RDF serialization format understood by RDF.rb.
         | 
| 17 | 
            +
            * Returns results using the [RDF.rb object model][RDF.rb model].
         | 
| 18 | 
            +
            * Supports accessing endpoints as read-only [`RDF::Repository`][RDF::Repository]
         | 
| 19 | 
            +
              instances.
         | 
| 12 20 |  | 
| 13 21 | 
             
            Examples
         | 
| 14 22 | 
             
            --------
         | 
| 15 23 |  | 
| 16 24 | 
             
                require 'sparql/client'
         | 
| 17 25 |  | 
| 18 | 
            -
                sparql = SPARQL::Client.new( | 
| 26 | 
            +
                sparql = SPARQL::Client.new("http://dbpedia.org/sparql")
         | 
| 19 27 |  | 
| 20 | 
            -
            ### Executing a boolean query
         | 
| 28 | 
            +
            ### Executing a boolean query and outputting the result
         | 
| 21 29 |  | 
| 22 | 
            -
                 | 
| 30 | 
            +
                # ASK WHERE { ?s ?p ?o }
         | 
| 31 | 
            +
                result = sparql.ask.whether([:s, :p, :o]).true?
         | 
| 23 32 |  | 
| 24 33 | 
             
                puts result.inspect   #=> true or false
         | 
| 25 34 |  | 
| 26 | 
            -
            ### Executing a tuple query
         | 
| 35 | 
            +
            ### Executing a tuple query and iterating over the returned solutions
         | 
| 27 36 |  | 
| 28 | 
            -
                 | 
| 37 | 
            +
                # SELECT * WHERE { ?s ?p ?o } OFFSET 100 LIMIT 10
         | 
| 38 | 
            +
                query = sparql.select.where([:s, :p, :o]).offset(100).limit(10)
         | 
| 29 39 |  | 
| 30 | 
            -
                 | 
| 31 | 
            -
                  puts  | 
| 40 | 
            +
                query.each_solution do |solution|
         | 
| 41 | 
            +
                  puts solution.inspect
         | 
| 32 42 | 
             
                end
         | 
| 33 43 |  | 
| 34 | 
            -
            ### Executing a graph query
         | 
| 44 | 
            +
            ### Executing a graph query and iterating over the returned statements
         | 
| 35 45 |  | 
| 36 | 
            -
                 | 
| 46 | 
            +
                # CONSTRUCT { ?s ?p ?o } WHERE { ?s ?p ?o } LIMIT 10
         | 
| 47 | 
            +
                query = sparql.construct([:s, :p, :o]).where([:s, :p, :o]).limit(10)
         | 
| 37 48 |  | 
| 38 | 
            -
                 | 
| 49 | 
            +
                query.each_statement do |statement|
         | 
| 39 50 | 
             
                  puts statement.inspect
         | 
| 40 51 | 
             
                end
         | 
| 41 52 |  | 
| 53 | 
            +
            ### Executing an arbitrary textual SPARQL query string
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                result = sparql.query("ASK WHERE { ?s ?p ?o }")
         | 
| 56 | 
            +
                
         | 
| 57 | 
            +
                puts result.inspect   #=> true or false
         | 
| 58 | 
            +
             | 
| 42 59 | 
             
            Documentation
         | 
| 43 60 | 
             
            -------------
         | 
| 44 61 |  | 
| 45 | 
            -
            <http://sparql.rubyforge.org/>
         | 
| 62 | 
            +
            <http://sparql.rubyforge.org/client/>
         | 
| 46 63 |  | 
| 47 64 | 
             
            * {SPARQL::Client}
         | 
| 65 | 
            +
              * {SPARQL::Client::Query}
         | 
| 66 | 
            +
              * {SPARQL::Client::Repository}
         | 
| 48 67 |  | 
| 49 68 | 
             
            Dependencies
         | 
| 50 69 | 
             
            ------------
         | 
| @@ -75,7 +94,7 @@ as follows: | |
| 75 94 | 
             
            Resources
         | 
| 76 95 | 
             
            ---------
         | 
| 77 96 |  | 
| 78 | 
            -
            * <http://sparql.rubyforge.org/>
         | 
| 97 | 
            +
            * <http://sparql.rubyforge.org/client/>
         | 
| 79 98 | 
             
            * <http://github.com/bendiken/sparql-client>
         | 
| 80 99 | 
             
            * <http://rubygems.org/gems/sparql-client>
         | 
| 81 100 | 
             
            * <http://rubyforge.org/projects/sparql/>
         | 
| @@ -94,6 +113,11 @@ License | |
| 94 113 | 
             
            `SPARQL::Client` is free and unencumbered public domain software. For more
         | 
| 95 114 | 
             
            information, see <http://unlicense.org/> or the accompanying UNLICENSE file.
         | 
| 96 115 |  | 
| 97 | 
            -
            [RDF]: | 
| 98 | 
            -
            [SPARQL]: | 
| 99 | 
            -
            [ | 
| 116 | 
            +
            [RDF]:             http://www.w3.org/RDF/
         | 
| 117 | 
            +
            [SPARQL]:          http://en.wikipedia.org/wiki/SPARQL
         | 
| 118 | 
            +
            [SPARQL JSON]:     http://www.w3.org/TR/rdf-sparql-json-res/
         | 
| 119 | 
            +
            [RDF.rb]:          http://rdf.rubyforge.org/
         | 
| 120 | 
            +
            [RDF.rb model]:    http://blog.datagraph.org/2010/03/rdf-for-ruby
         | 
| 121 | 
            +
            [RDF::Repository]: http://rdf.rubyforge.org/RDF/Repository.html
         | 
| 122 | 
            +
            [DSL]:             http://en.wikipedia.org/wiki/Domain-specific_language
         | 
| 123 | 
            +
                               "domain-specific language"
         | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0.0. | 
| 1 | 
            +
            0.0.2
         | 
    
        data/lib/sparql.rb
    CHANGED
    
    
    
        data/lib/sparql/client.rb
    CHANGED
    
    | @@ -1,12 +1,19 @@ | |
| 1 1 | 
             
            require 'net/http'
         | 
| 2 2 | 
             
            require 'rdf'
         | 
| 3 3 | 
             
            require 'rdf/ntriples'
         | 
| 4 | 
            -
            require 'sparql/version'
         | 
| 5 4 |  | 
| 6 5 | 
             
            module SPARQL
         | 
| 7 6 | 
             
              ##
         | 
| 8 7 | 
             
              # A SPARQL client for RDF.rb.
         | 
| 9 8 | 
             
              class Client
         | 
| 9 | 
            +
                autoload :Query,      'sparql/client/query'
         | 
| 10 | 
            +
                autoload :Repository, 'sparql/client/repository'
         | 
| 11 | 
            +
                autoload :VERSION,    'sparql/client/version'
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                class ClientError < StandardError; end
         | 
| 14 | 
            +
                class MalformedQuery < ClientError; end
         | 
| 15 | 
            +
                class ServerError < StandardError; end
         | 
| 16 | 
            +
             | 
| 10 17 | 
             
                RESULT_BOOL = 'text/boolean'.freeze # Sesame-specific
         | 
| 11 18 | 
             
                RESULT_JSON = 'application/sparql-results+json'.freeze
         | 
| 12 19 | 
             
                RESULT_XML  = 'application/sparql-results+xml'.freeze
         | 
| @@ -21,7 +28,7 @@ module SPARQL | |
| 21 28 | 
             
                # @param  [Hash{Symbol => Object}] options
         | 
| 22 29 | 
             
                def initialize(url, options = {}, &block)
         | 
| 23 30 | 
             
                  @url, @options = RDF::URI.new(url.to_s), options
         | 
| 24 | 
            -
                  @headers = {'Accept' => "#{ | 
| 31 | 
            +
                  @headers = {'Accept' => "#{RESULT_JSON}, #{RESULT_XML}, text/plain"}
         | 
| 25 32 |  | 
| 26 33 | 
             
                  if block_given?
         | 
| 27 34 | 
             
                    case block.arity
         | 
| @@ -31,19 +38,63 @@ module SPARQL | |
| 31 38 | 
             
                  end
         | 
| 32 39 | 
             
                end
         | 
| 33 40 |  | 
| 41 | 
            +
                ##
         | 
| 42 | 
            +
                # Executes a boolean `ASK` query.
         | 
| 43 | 
            +
                #
         | 
| 44 | 
            +
                # @return [Query]
         | 
| 45 | 
            +
                def ask(*args)
         | 
| 46 | 
            +
                  client = self
         | 
| 47 | 
            +
                  result = Query.ask(*args)
         | 
| 48 | 
            +
                  (class << result; self; end).send(:define_method, :execute) do
         | 
| 49 | 
            +
                    client.query(self)
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
                  result
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                ##
         | 
| 55 | 
            +
                # Executes a tuple `SELECT` query.
         | 
| 56 | 
            +
                #
         | 
| 57 | 
            +
                # @param  [Array<Symbol>] variables
         | 
| 58 | 
            +
                # @return [Query]
         | 
| 59 | 
            +
                def select(*args)
         | 
| 60 | 
            +
                  client = self
         | 
| 61 | 
            +
                  result = Query.select(*args)
         | 
| 62 | 
            +
                  (class << result; self; end).send(:define_method, :execute) do
         | 
| 63 | 
            +
                    client.query(self)
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
                  result
         | 
| 66 | 
            +
                end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                ##
         | 
| 69 | 
            +
                # Executes a graph `CONSTRUCT` query.
         | 
| 70 | 
            +
                #
         | 
| 71 | 
            +
                # @param  [Array<Symbol>] pattern
         | 
| 72 | 
            +
                # @return [Query]
         | 
| 73 | 
            +
                def construct(*args)
         | 
| 74 | 
            +
                  client = self
         | 
| 75 | 
            +
                  result = Query.construct(*args)
         | 
| 76 | 
            +
                  (class << result; self; end).send(:define_method, :execute) do
         | 
| 77 | 
            +
                    client.query(self)
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
                  result
         | 
| 80 | 
            +
                end
         | 
| 81 | 
            +
             | 
| 34 82 | 
             
                ##
         | 
| 35 83 | 
             
                # Executes a SPARQL query.
         | 
| 36 84 | 
             
                #
         | 
| 37 85 | 
             
                # @param  [String, #to_s]          url
         | 
| 38 86 | 
             
                # @param  [Hash{Symbol => Object}] options
         | 
| 87 | 
            +
                # @return [Array<RDF::Query::Solution>]
         | 
| 39 88 | 
             
                def query(query, options = {})
         | 
| 40 | 
            -
                  get(query | 
| 89 | 
            +
                  get(query) do |response|
         | 
| 41 90 | 
             
                    case response
         | 
| 42 | 
            -
                      when Net:: | 
| 43 | 
            -
                         | 
| 44 | 
            -
                      when Net:: | 
| 45 | 
            -
                         | 
| 46 | 
            -
                      when Net:: | 
| 91 | 
            +
                      when Net::HTTPBadRequest  # 400 Bad Request
         | 
| 92 | 
            +
                        raise MalformedQuery.new(response.body)
         | 
| 93 | 
            +
                      when Net::HTTPClientError # 4xx
         | 
| 94 | 
            +
                        raise ClientError.new(response.body)
         | 
| 95 | 
            +
                      when Net::HTTPServerError # 5xx
         | 
| 96 | 
            +
                        raise ServerError.new(response.body)
         | 
| 97 | 
            +
                      when Net::HTTPSuccess     # 2xx
         | 
| 47 98 | 
             
                        parse_response(response)
         | 
| 48 99 | 
             
                    end
         | 
| 49 100 | 
             
                  end
         | 
| @@ -79,7 +130,7 @@ module SPARQL | |
| 79 130 | 
             
                    when json['results']
         | 
| 80 131 | 
             
                      json['results']['bindings'].map do |row|
         | 
| 81 132 | 
             
                        row = row.inject({}) do |cols, (name, value)|
         | 
| 82 | 
            -
                          cols.merge(name => parse_json_value(value))
         | 
| 133 | 
            +
                          cols.merge(name.to_sym => parse_json_value(value))
         | 
| 83 134 | 
             
                        end
         | 
| 84 135 | 
             
                        RDF::Query::Solution.new(row)
         | 
| 85 136 | 
             
                      end
         | 
| @@ -0,0 +1,267 @@ | |
| 1 | 
            +
            module SPARQL; class Client
         | 
| 2 | 
            +
              ##
         | 
| 3 | 
            +
              # A SPARQL query builder.
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              # @example Iterating over all found solutions
         | 
| 6 | 
            +
              #   query.each_solution { |solution| puts solution.inspect }
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              class Query < RDF::Query
         | 
| 9 | 
            +
                ##
         | 
| 10 | 
            +
                # @return [Symbol]
         | 
| 11 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#QueryForms
         | 
| 12 | 
            +
                attr_reader :form
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                ##
         | 
| 15 | 
            +
                # @return [Hash{Symbol => Object}]
         | 
| 16 | 
            +
                attr_reader :options
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                ##
         | 
| 19 | 
            +
                # Creates a boolean `ASK` query.
         | 
| 20 | 
            +
                #
         | 
| 21 | 
            +
                # @param  [Hash{Symbol => Object}] options
         | 
| 22 | 
            +
                # @return [Query]
         | 
| 23 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#ask
         | 
| 24 | 
            +
                def self.ask(options = {})
         | 
| 25 | 
            +
                  self.new(:ask, options)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                ##
         | 
| 29 | 
            +
                # Creates a tuple `SELECT` query.
         | 
| 30 | 
            +
                #
         | 
| 31 | 
            +
                # @param  [Array<Symbol>]          variables
         | 
| 32 | 
            +
                # @param  [Hash{Symbol => Object}] options
         | 
| 33 | 
            +
                # @return [Query]
         | 
| 34 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#select
         | 
| 35 | 
            +
                def self.select(*variables)
         | 
| 36 | 
            +
                  options = variables.last.is_a?(Hash) ? variables.pop : {}
         | 
| 37 | 
            +
                  self.new(:select, options).select(*variables) # FIXME
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                ##
         | 
| 41 | 
            +
                # Creates a graph `CONSTRUCT` query.
         | 
| 42 | 
            +
                #
         | 
| 43 | 
            +
                # @param  [Array<RDF::Query::Pattern, Array>] patterns
         | 
| 44 | 
            +
                # @param  [Hash{Symbol => Object}]            options
         | 
| 45 | 
            +
                # @return [Query]
         | 
| 46 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#construct
         | 
| 47 | 
            +
                def self.construct(*patterns)
         | 
| 48 | 
            +
                  options = patterns.last.is_a?(Hash) ? patterns.pop : {}
         | 
| 49 | 
            +
                  self.new(:construct, options).construct(*patterns) # FIXME
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                ##
         | 
| 53 | 
            +
                # @param  [Symbol, #to_s]          form
         | 
| 54 | 
            +
                # @param  [Hash{Symbol => Object}] options
         | 
| 55 | 
            +
                # @yield  [query]
         | 
| 56 | 
            +
                # @yieldparam [Query]
         | 
| 57 | 
            +
                def initialize(form = :ask, options = {}, &block)
         | 
| 58 | 
            +
                  @form = form.respond_to?(:to_sym) ? form.to_sym : form.to_s.to_sym
         | 
| 59 | 
            +
                  super(options.dup, &block)
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                ##
         | 
| 63 | 
            +
                # @return [Query]
         | 
| 64 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#ask
         | 
| 65 | 
            +
                def ask
         | 
| 66 | 
            +
                  @form = :ask
         | 
| 67 | 
            +
                  self
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                ##
         | 
| 71 | 
            +
                # @param  [Array<Symbol>] variables
         | 
| 72 | 
            +
                # @param  [Hash{Symbol => Object}] options
         | 
| 73 | 
            +
                # @return [Query]
         | 
| 74 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#select
         | 
| 75 | 
            +
                def select(*variables)
         | 
| 76 | 
            +
                  @form = :select
         | 
| 77 | 
            +
                  options = variables.last.is_a?(Hash) ? variables.pop : {}
         | 
| 78 | 
            +
                  @variables = variables.inject({}) do |vars, var|
         | 
| 79 | 
            +
                    vars.merge(var.to_sym => RDF::Query::Variable.new(var))
         | 
| 80 | 
            +
                  end
         | 
| 81 | 
            +
                  self
         | 
| 82 | 
            +
                end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                ##
         | 
| 85 | 
            +
                # @param  [Array<RDF::Query::Pattern, Array>] patterns
         | 
| 86 | 
            +
                # @return [Query]
         | 
| 87 | 
            +
                def construct(*patterns)
         | 
| 88 | 
            +
                  options[:template] = patterns.map do |pattern|
         | 
| 89 | 
            +
                    case pattern
         | 
| 90 | 
            +
                      when RDF::Query::Pattern then pattern
         | 
| 91 | 
            +
                      else RDF::Query::Pattern.new(*pattern.to_a)
         | 
| 92 | 
            +
                    end
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
                  self
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                ##
         | 
| 98 | 
            +
                # @param  [Array<RDF::Query::Pattern, Array>] patterns
         | 
| 99 | 
            +
                # @return [Query]
         | 
| 100 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#GraphPattern
         | 
| 101 | 
            +
                def where(*patterns)
         | 
| 102 | 
            +
                  @patterns += patterns.map do |pattern|
         | 
| 103 | 
            +
                    case pattern
         | 
| 104 | 
            +
                      when RDF::Query::Pattern then pattern
         | 
| 105 | 
            +
                      else RDF::Query::Pattern.new(*pattern.to_a)
         | 
| 106 | 
            +
                    end
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
                  self
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                alias_method :whether, :where
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                ##
         | 
| 114 | 
            +
                # @param  [Array<Symbol>] variables
         | 
| 115 | 
            +
                # @return [Query]
         | 
| 116 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#modOrderBy
         | 
| 117 | 
            +
                def order(*variables)
         | 
| 118 | 
            +
                  options[:order_by] = variables
         | 
| 119 | 
            +
                  self
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                alias_method :order_by, :order
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                ##
         | 
| 125 | 
            +
                # @return [Query]
         | 
| 126 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#modDistinct
         | 
| 127 | 
            +
                def distinct(state = true)
         | 
| 128 | 
            +
                  options[:distinct] = state
         | 
| 129 | 
            +
                  self
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                ##
         | 
| 133 | 
            +
                # @return [Query]
         | 
| 134 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#modReduced
         | 
| 135 | 
            +
                def reduced(state = true)
         | 
| 136 | 
            +
                  options[:reduced] = state
         | 
| 137 | 
            +
                  self
         | 
| 138 | 
            +
                end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                ##
         | 
| 141 | 
            +
                # @param  [Integer, #to_i] start
         | 
| 142 | 
            +
                # @return [Query]
         | 
| 143 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#modOffset
         | 
| 144 | 
            +
                def offset(start)
         | 
| 145 | 
            +
                  slice(start, nil)
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
             | 
| 148 | 
            +
                ##
         | 
| 149 | 
            +
                # @param  [Integer, #to_i] length
         | 
| 150 | 
            +
                # @return [Query]
         | 
| 151 | 
            +
                # @see    http://www.w3.org/TR/rdf-sparql-query/#modResultLimit
         | 
| 152 | 
            +
                def limit(length)
         | 
| 153 | 
            +
                  slice(nil, length)
         | 
| 154 | 
            +
                end
         | 
| 155 | 
            +
             | 
| 156 | 
            +
                ##
         | 
| 157 | 
            +
                # @param  [Integer, #to_i] start
         | 
| 158 | 
            +
                # @param  [Integer, #to_i] length
         | 
| 159 | 
            +
                # @return [Query]
         | 
| 160 | 
            +
                def slice(start, length)
         | 
| 161 | 
            +
                  options[:offset] = start.to_i if start
         | 
| 162 | 
            +
                  options[:limit] = length.to_i if length
         | 
| 163 | 
            +
                  self
         | 
| 164 | 
            +
                end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                ##
         | 
| 167 | 
            +
                # @private
         | 
| 168 | 
            +
                def filter(string)
         | 
| 169 | 
            +
                  (options[:filters] ||= []) << string
         | 
| 170 | 
            +
                  self
         | 
| 171 | 
            +
                end
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                ##
         | 
| 174 | 
            +
                # @return [Boolean]
         | 
| 175 | 
            +
                def true?
         | 
| 176 | 
            +
                  case result
         | 
| 177 | 
            +
                    when TrueClass, FalseClass then result
         | 
| 178 | 
            +
                    when Enumerable then !result.empty?
         | 
| 179 | 
            +
                    else false
         | 
| 180 | 
            +
                  end
         | 
| 181 | 
            +
                end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                ##
         | 
| 184 | 
            +
                # @return [Boolean]
         | 
| 185 | 
            +
                def false?
         | 
| 186 | 
            +
                  !true?
         | 
| 187 | 
            +
                end
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                ##
         | 
| 190 | 
            +
                # @return [Enumerable<RDF::Query::Solution>]
         | 
| 191 | 
            +
                def solutions
         | 
| 192 | 
            +
                  result
         | 
| 193 | 
            +
                end
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                ##
         | 
| 196 | 
            +
                # @yield  [statement]
         | 
| 197 | 
            +
                # @yieldparam [RDF::Statement]
         | 
| 198 | 
            +
                # @return [Enumerator]
         | 
| 199 | 
            +
                def each_statement(&block)
         | 
| 200 | 
            +
                  result.each_statement(&block)
         | 
| 201 | 
            +
                end
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                ##
         | 
| 204 | 
            +
                # @return [Object]
         | 
| 205 | 
            +
                def result
         | 
| 206 | 
            +
                  @result ||= execute
         | 
| 207 | 
            +
                end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                ##
         | 
| 210 | 
            +
                # @return [Object]
         | 
| 211 | 
            +
                def execute
         | 
| 212 | 
            +
                  raise NotImplementedError
         | 
| 213 | 
            +
                end
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                ##
         | 
| 216 | 
            +
                # Returns the string representation of this query.
         | 
| 217 | 
            +
                #
         | 
| 218 | 
            +
                # @return [String]
         | 
| 219 | 
            +
                def to_s
         | 
| 220 | 
            +
                  buffer = [form.to_s.upcase]
         | 
| 221 | 
            +
                  case form
         | 
| 222 | 
            +
                    when :select
         | 
| 223 | 
            +
                      buffer << 'DISTINCT' if options[:distinct]
         | 
| 224 | 
            +
                      buffer << 'REDUCED'  if options[:reduced]
         | 
| 225 | 
            +
                      buffer << (variables.empty? ? '*' : variables.values.map(&:to_s).join(' '))
         | 
| 226 | 
            +
                    when :construct
         | 
| 227 | 
            +
                      buffer << '{'
         | 
| 228 | 
            +
                      buffer += options[:template].map(&:to_s)
         | 
| 229 | 
            +
                      buffer << '}'
         | 
| 230 | 
            +
                  end
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                  buffer << 'WHERE {'
         | 
| 233 | 
            +
                  buffer += patterns.map(&:to_s)
         | 
| 234 | 
            +
                  if options[:filters]
         | 
| 235 | 
            +
                    buffer += options[:filters].map { |filter| "FILTER(#{filter})" }
         | 
| 236 | 
            +
                  end
         | 
| 237 | 
            +
                  buffer << '}'
         | 
| 238 | 
            +
             | 
| 239 | 
            +
                  if options[:order_by]
         | 
| 240 | 
            +
                    buffer << 'ORDER BY'
         | 
| 241 | 
            +
                    buffer += options[:order_by].map { |var| "?#{var}" }
         | 
| 242 | 
            +
                  end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                  buffer << "OFFSET #{options[:offset]}" if options[:offset]
         | 
| 245 | 
            +
                  buffer << "LIMIT #{options[:limit]}"   if options[:limit]
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                  buffer.join(' ')
         | 
| 248 | 
            +
                end
         | 
| 249 | 
            +
             | 
| 250 | 
            +
                ##
         | 
| 251 | 
            +
                # Outputs a developer-friendly representation of this query to `stderr`.
         | 
| 252 | 
            +
                #
         | 
| 253 | 
            +
                # @return [void]
         | 
| 254 | 
            +
                def inspect!
         | 
| 255 | 
            +
                  warn(inspect)
         | 
| 256 | 
            +
                  self
         | 
| 257 | 
            +
                end
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                ##
         | 
| 260 | 
            +
                # Returns a developer-friendly representation of this query.
         | 
| 261 | 
            +
                #
         | 
| 262 | 
            +
                # @return [String]
         | 
| 263 | 
            +
                def inspect
         | 
| 264 | 
            +
                  sprintf("#<%s:%#0x(%s)>", self.class.name, __id__, to_s)
         | 
| 265 | 
            +
                end
         | 
| 266 | 
            +
              end
         | 
| 267 | 
            +
            end; end
         | 
| @@ -0,0 +1,170 @@ | |
| 1 | 
            +
            module SPARQL; class Client
         | 
| 2 | 
            +
              ##
         | 
| 3 | 
            +
              # A read-only repository view of a SPARQL endpoint.
         | 
| 4 | 
            +
              #
         | 
| 5 | 
            +
              # @see RDF::Repository
         | 
| 6 | 
            +
              class Repository < ::RDF::Repository
         | 
| 7 | 
            +
                # @return [SPARQL::Client]
         | 
| 8 | 
            +
                attr_reader :client
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                ##
         | 
| 11 | 
            +
                # @param  [String, #to_s]          endpoint
         | 
| 12 | 
            +
                # @param  [Hash{Symbol => Object}] options
         | 
| 13 | 
            +
                def initialize(endpoint, options = {})
         | 
| 14 | 
            +
                  @options = options.dup
         | 
| 15 | 
            +
                  @client  = SPARQL::Client.new(endpoint, options)
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                ##
         | 
| 19 | 
            +
                # Enumerates each RDF statement in this repository.
         | 
| 20 | 
            +
                #
         | 
| 21 | 
            +
                # @yield  [statement]
         | 
| 22 | 
            +
                # @yieldparam [RDF::Statement] statement
         | 
| 23 | 
            +
                # @return [Enumerator]
         | 
| 24 | 
            +
                # @see    RDF::Repository#each
         | 
| 25 | 
            +
                def each(&block)
         | 
| 26 | 
            +
                  unless block_given?
         | 
| 27 | 
            +
                    require 'enumerator' unless defined?(::Enumerable::Enumerator)
         | 
| 28 | 
            +
                    ::Enumerable::Enumerator.new(self, :each)
         | 
| 29 | 
            +
                  else
         | 
| 30 | 
            +
                    client.construct([:s, :p, :o]).where([:s, :p, :o]).each_statement(&block)
         | 
| 31 | 
            +
                  end
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                ##
         | 
| 35 | 
            +
                # Returns `true` if this repository contains the given subject.
         | 
| 36 | 
            +
                #
         | 
| 37 | 
            +
                # @param  [RDF::Resource]
         | 
| 38 | 
            +
                # @return [Boolean]
         | 
| 39 | 
            +
                # @see    RDF::Repository#has_subject?
         | 
| 40 | 
            +
                def has_subject?(subject)
         | 
| 41 | 
            +
                  client.ask.whether([subject, :p, :o]).true?
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                ##
         | 
| 45 | 
            +
                # Returns `true` if this repository contains the given predicate.
         | 
| 46 | 
            +
                #
         | 
| 47 | 
            +
                # @param  [RDF::URI]
         | 
| 48 | 
            +
                # @return [Boolean]
         | 
| 49 | 
            +
                # @see    RDF::Repository#has_predicate?
         | 
| 50 | 
            +
                def has_predicate?(predicate)
         | 
| 51 | 
            +
                  client.ask.whether([:s, predicate, :o]).true?
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                ##
         | 
| 55 | 
            +
                # Returns `true` if this repository contains the given object.
         | 
| 56 | 
            +
                #
         | 
| 57 | 
            +
                # @param  [RDF::Value]
         | 
| 58 | 
            +
                # @return [Boolean]
         | 
| 59 | 
            +
                # @see    RDF::Repository#has_object?
         | 
| 60 | 
            +
                def has_object?(object)
         | 
| 61 | 
            +
                  client.ask.whether([:s, :p, object]).true?
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                ##
         | 
| 65 | 
            +
                # Iterates over each subject in this repository.
         | 
| 66 | 
            +
                #
         | 
| 67 | 
            +
                # @yield  [subject]
         | 
| 68 | 
            +
                # @yieldparam [RDF::Resource] subject
         | 
| 69 | 
            +
                # @return [Enumerator]
         | 
| 70 | 
            +
                # @see    RDF::Repository#each_subject?
         | 
| 71 | 
            +
                def each_subject(&block)
         | 
| 72 | 
            +
                  unless block_given?
         | 
| 73 | 
            +
                    require 'enumerator' unless defined?(::Enumerable::Enumerator)
         | 
| 74 | 
            +
                    ::Enumerable::Enumerator.new(self, :each_subject)
         | 
| 75 | 
            +
                  else
         | 
| 76 | 
            +
                    client.select(:s, :distinct => true).where([:s, :p, :o]).each { |solution| block.call(solution[:s]) }
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
                end
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                ##
         | 
| 81 | 
            +
                # Iterates over each predicate in this repository.
         | 
| 82 | 
            +
                #
         | 
| 83 | 
            +
                # @yield  [predicate]
         | 
| 84 | 
            +
                # @yieldparam [RDF::URI] predicate
         | 
| 85 | 
            +
                # @return [Enumerator]
         | 
| 86 | 
            +
                # @see    RDF::Repository#each_predicate?
         | 
| 87 | 
            +
                def each_predicate(&block)
         | 
| 88 | 
            +
                  unless block_given?
         | 
| 89 | 
            +
                    require 'enumerator' unless defined?(::Enumerable::Enumerator)
         | 
| 90 | 
            +
                    ::Enumerable::Enumerator.new(self, :each_predicate)
         | 
| 91 | 
            +
                  else
         | 
| 92 | 
            +
                    client.select(:p, :distinct => true).where([:s, :p, :o]).each { |solution| block.call(solution[:p]) }
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
                end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
                ##
         | 
| 97 | 
            +
                # Iterates over each object in this repository.
         | 
| 98 | 
            +
                #
         | 
| 99 | 
            +
                # @yield  [object]
         | 
| 100 | 
            +
                # @yieldparam [RDF::Value] object
         | 
| 101 | 
            +
                # @return [Enumerator]
         | 
| 102 | 
            +
                # @see    RDF::Repository#each_object?
         | 
| 103 | 
            +
                def each_object(&block)
         | 
| 104 | 
            +
                  unless block_given?
         | 
| 105 | 
            +
                    require 'enumerator' unless defined?(::Enumerable::Enumerator)
         | 
| 106 | 
            +
                    ::Enumerable::Enumerator.new(self, :each_object)
         | 
| 107 | 
            +
                  else
         | 
| 108 | 
            +
                    client.select(:o, :distinct => true).where([:s, :p, :o]).each { |solution| block.call(solution[:o]) }
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                ##
         | 
| 113 | 
            +
                # Returns `true` if this repository contains the given `triple`.
         | 
| 114 | 
            +
                #
         | 
| 115 | 
            +
                # @param  [Array<RDF::Resource, RDF::URI, RDF::Value>] triple
         | 
| 116 | 
            +
                # @return [Boolean]
         | 
| 117 | 
            +
                # @see    RDF::Repository#has_triple?
         | 
| 118 | 
            +
                def has_triple?(triple)
         | 
| 119 | 
            +
                  client.ask.whether(triple.to_a[0...3]).true?
         | 
| 120 | 
            +
                end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                ##
         | 
| 123 | 
            +
                # Returns `true` if this repository contains the given `statement`.
         | 
| 124 | 
            +
                #
         | 
| 125 | 
            +
                # @param  [RDF::Statement] statement
         | 
| 126 | 
            +
                # @return [Boolean]
         | 
| 127 | 
            +
                # @see    RDF::Repository#has_statement?
         | 
| 128 | 
            +
                def has_statement?(statement)
         | 
| 129 | 
            +
                  has_triple?(statement.to_triple)
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
                ##
         | 
| 133 | 
            +
                # Returns the number of statements in this repository.
         | 
| 134 | 
            +
                #
         | 
| 135 | 
            +
                # @return [Integer]
         | 
| 136 | 
            +
                # @see    RDF::Repository#count?
         | 
| 137 | 
            +
                def count
         | 
| 138 | 
            +
                  begin
         | 
| 139 | 
            +
                    binding = client.query("SELECT COUNT(*) WHERE { ?s ?p ?o }").first.to_hash
         | 
| 140 | 
            +
                    binding[binding.keys.first].value.to_i
         | 
| 141 | 
            +
                  rescue SPARQL::Client::MalformedQuery => e
         | 
| 142 | 
            +
                    # SPARQL 1.0 does not include support for aggregate functions:
         | 
| 143 | 
            +
                    count = 0
         | 
| 144 | 
            +
                    each_statement { count += 1 } # TODO: optimize this
         | 
| 145 | 
            +
                    count
         | 
| 146 | 
            +
                  end
         | 
| 147 | 
            +
                end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
                alias_method :size,   :count
         | 
| 150 | 
            +
                alias_method :length, :count
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                ##
         | 
| 153 | 
            +
                # Returns `true` if this repository contains no statements.
         | 
| 154 | 
            +
                #
         | 
| 155 | 
            +
                # @return [Boolean]
         | 
| 156 | 
            +
                # @see    RDF::Repository#empty?
         | 
| 157 | 
            +
                def empty?
         | 
| 158 | 
            +
                  client.ask.whether([:s, :p, :o]).false?
         | 
| 159 | 
            +
                end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                ##
         | 
| 162 | 
            +
                # Returns `false` to indicate that this is a read-only repository.
         | 
| 163 | 
            +
                #
         | 
| 164 | 
            +
                # @return [Boolean]
         | 
| 165 | 
            +
                # @see    RDF::Mutable#mutable?
         | 
| 166 | 
            +
                def writable?
         | 
| 167 | 
            +
                  false
         | 
| 168 | 
            +
                end
         | 
| 169 | 
            +
              end
         | 
| 170 | 
            +
            end; end
         | 
    
        metadata
    CHANGED
    
    | @@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version | |
| 5 5 | 
             
              segments: 
         | 
| 6 6 | 
             
              - 0
         | 
| 7 7 | 
             
              - 0
         | 
| 8 | 
            -
              -  | 
| 9 | 
            -
              version: 0.0. | 
| 8 | 
            +
              - 2
         | 
| 9 | 
            +
              version: 0.0.2
         | 
| 10 10 | 
             
            platform: ruby
         | 
| 11 11 | 
             
            authors: 
         | 
| 12 12 | 
             
            - Arto Bendiken
         | 
| @@ -15,7 +15,7 @@ autorequire: | |
| 15 15 | 
             
            bindir: bin
         | 
| 16 16 | 
             
            cert_chain: []
         | 
| 17 17 |  | 
| 18 | 
            -
            date: 2010-04- | 
| 18 | 
            +
            date: 2010-04-12 00:00:00 +02:00
         | 
| 19 19 | 
             
            default_executable: 
         | 
| 20 20 | 
             
            dependencies: 
         | 
| 21 21 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -28,8 +28,8 @@ dependencies: | |
| 28 28 | 
             
                    segments: 
         | 
| 29 29 | 
             
                    - 0
         | 
| 30 30 | 
             
                    - 1
         | 
| 31 | 
            -
                    -  | 
| 32 | 
            -
                    version: 0.1. | 
| 31 | 
            +
                    - 6
         | 
| 32 | 
            +
                    version: 0.1.6
         | 
| 33 33 | 
             
              type: :development
         | 
| 34 34 | 
             
              version_requirements: *id001
         | 
| 35 35 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -70,8 +70,8 @@ dependencies: | |
| 70 70 | 
             
                    segments: 
         | 
| 71 71 | 
             
                    - 0
         | 
| 72 72 | 
             
                    - 1
         | 
| 73 | 
            -
                    -  | 
| 74 | 
            -
                    version: 0.1. | 
| 73 | 
            +
                    - 6
         | 
| 74 | 
            +
                    version: 0.1.6
         | 
| 75 75 | 
             
              type: :runtime
         | 
| 76 76 | 
             
              version_requirements: *id004
         | 
| 77 77 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -101,8 +101,10 @@ files: | |
| 101 101 | 
             
            - README
         | 
| 102 102 | 
             
            - UNLICENSE
         | 
| 103 103 | 
             
            - VERSION
         | 
| 104 | 
            +
            - lib/sparql/client/query.rb
         | 
| 105 | 
            +
            - lib/sparql/client/repository.rb
         | 
| 106 | 
            +
            - lib/sparql/client/version.rb
         | 
| 104 107 | 
             
            - lib/sparql/client.rb
         | 
| 105 | 
            -
            - lib/sparql/version.rb
         | 
| 106 108 | 
             
            - lib/sparql.rb
         | 
| 107 109 | 
             
            has_rdoc: false
         | 
| 108 110 | 
             
            homepage: http://sparql.rubyforge.org/
         |