lib/rom/http/dataset.rb in rom-http-0.7.0 vs lib/rom/http/dataset.rb in rom-http-0.8.0
- old
+ new
@@ -1,116 +1,196 @@
+# frozen_string_literal: true
+
require 'uri'
-require 'dry-configurable'
+
+require 'dry/configurable'
require 'dry/core/deprecations'
+
+require 'rom/support/memoizable'
+require 'rom/constants'
require 'rom/initializer'
-require 'rom/http/dataset/class_interface'
+require 'rom/http/types'
+require 'rom/http/transformer'
module ROM
module HTTP
# HTTP Dataset
#
- # Represents a specific HTTP collection resource
+ # Represents a specific HTTP collection resource. This class can be
+ # subclassed in a specialized HTTP adapter to provide its own
+ # response/request handlers or any other configuration that should
+ # differ from the defaults.
#
# @api public
class Dataset
PATH_SEPARATOR = '/'.freeze
- extend ::ROM::Initializer
- extend ::Dry::Configurable
- extend ::ROM::HTTP::Dataset::ClassInterface
- include ::Enumerable
- include ::Dry::Equalizer(:config, :options)
+ extend Dry::Configurable
+ extend ROM::Initializer
- setting :default_request_handler
- setting :default_response_handler
- setting :param_encoder, ->(params) { URI.encode_www_form(params) }
+ include ROM::Memoizable
+ include Enumerable
+ include Dry::Equalizer(:options)
- param :config
+ # @!method self.default_request_handler
+ # Return configured default request handler
+ #
+ # @example
+ # class MyDataset < ROM::HTTP::Dataset
+ # configure do |config|
+ # config.default_request_handler = MyRequestHandler
+ # end
+ # end
+ #
+ # MyDataset.default_request_handler # MyRequestHandler
+ # MyDataset.new(uri: "http://localhost").request_handler # MyRequestHandler
+ setting :default_request_handler, reader: true
- option :request_method, type: Types::Symbol, default: proc { :get }, reader: true
- option :base_path, type: Types::String, default: proc { name }
- option :path, type: Types::String, default: proc { '' }, reader: false
- option :params, type: Types::Hash, default: proc { {} }, reader: true
- option :headers, type: Types::Hash, default: proc { {} }
+ # @!method self.default_response_handler
+ # Return configured default response handler
+ #
+ # @example
+ # class MyDataset < ROM::HTTP::Dataset
+ # configure do |config|
+ # config.default_response_handler = MyResponseHandler
+ # end
+ # end
+ #
+ # MyDataset.default_response_handler # MyResponseHandler
+ # MyDataset.new(uri: "http://localhost").response_handler # MyResponseHandler
+ setting :default_response_handler, reader: true
- # Return the gateway's URI
+ # @!method self.param_encoder
+ # Return configured param encoder
#
- # @return [String]
+ # @example
+ # class MyDataset < ROM::HTTP::Dataset
+ # configure do |config|
+ # config.param_encoder = MyParamEncoder
+ # end
+ # end
#
- # @raise [Error] if the configuration does not contain a URI
+ # MyDataset.param_encoder # MyParamEncoder
+ # MyDataset.new(uri: "http://localhost").param_encoder # MyParamEncoder
+ setting :param_encoder, URI.method(:encode_www_form), reader: true
+
+ # @!attribute [r] request_handler
+ # @return [Object]
+ # @api public
+ option :request_handler, default: proc { self.class.default_request_handler }
+
+ # @!attribute [r] response_handler
+ # @return [Object]
+ # @api public
+ option :response_handler, default: proc { self.class.default_response_handler }
+
+ # @!attribute [r] request_method
+ # @return [Symbol]
+ # @api public
+ option :request_method, type: Types::Symbol, default: proc { :get }
+
+ # @!attribute [r] base_path
+ # @return [String]
+ # @api public
+ option :base_path, type: Types::Path, default: proc { EMPTY_STRING }
+
+ # @!attribute [r] path
+ # @return [String]
+ # @api public
+ option :path, type: Types::Path, default: proc { EMPTY_STRING }
+
+ # @!attribute [r] params
+ # @return [Hash]
+ # @api public
+ option :params, type: Types::Hash, default: proc { EMPTY_HASH }
+
+ # @!attribute [r] headers
+ # @return [Hash]
+ # @api public
+ option :headers, type: Types::Hash, default: proc { EMPTY_HASH }
+
+ # @!attribute [r] headers
+ # @return [Hash]
+ # @api public
+ option :param_encoder, default: proc { self.class.param_encoder }
+
+ # @!attribute [r] uri
+ # @return [String]
+ # @api public
+ option :uri, type: Types::String
+
+ # Return the dataset's URI
#
+ # @return [URI::HTTP]
+ #
# @api public
def uri
- uri = config.fetch(:uri) { fail Error, '+uri+ configuration missing' }
- uri = URI(join_path(uri, path))
- if request_method == :get && params.any?
- uri.query = self.class.config.param_encoder.call(params)
+ uri = URI(join_path(super, path))
+
+ if get? && params.any?
+ uri.query = param_encoder.call(params)
end
uri
end
- # Return request headers
+ # Return true if request method is set to :get
#
- # Merges default headers from the Gateway configuration and the
- # current Dataset
+ # @return [Boolean]
#
- # @example
- # config = { Accepts: 'application/json' }
- # users = Dataset.new(config, headers: { 'Cache-Control': 'no-cache' }
- # users.headers
- # # => {:Accepts => "application/json", :'Cache-Control' => 'no-cache'}
+ # @api public
+ def get?
+ request_method.equal?(:get)
+ end
+
+ # Return true if request method is set to :post
#
- # @return [Hash]
+ # @return [Boolean]
#
# @api public
- def headers
- config.fetch(:headers, {}).merge(options.fetch(:headers, {}))
+ def post?
+ request_method.equal?(:post)
end
- # Return the dataset name
+ # Return true if request method is set to :put
#
- # @return [String]
+ # @return [Boolean]
#
# @api public
- def name
- config[:name].to_s
+ def put?
+ request_method.equal?(:put)
end
- # Return the base path
+ # Return true if request method is set to :delete
#
- # @example
- # Dataset.new(config, base_path: '/users').base_path
- # # => 'users'
+ # @return [Boolean]
#
- # @return [String] the dataset path, without a leading slash
- #
# @api public
- def base_path
- strip_path(super)
+ def delete?
+ request_method.equal?(:delete)
end
# Return the dataset path
#
# @example
- # Dataset.new(config, path: '/users').path
+ # Dataset.new(path: '/users').path
# # => 'users'
#
# @return [String] the dataset path, without a leading slash
#
# @api public
def path
- join_path(base_path, strip_path(options[:path].to_s))
+ join_path(base_path, super)
end
# Return the dataset path
#
# @example
- # Dataset.new(config, path: '/users').path
+ # Dataset.new(path: '/users').path
# # => '/users'
#
- # @return [string] the dataset path, with leading slash
+ # @return [String] the dataset path, with leading slash
#
# @api public
def absolute_path
PATH_SEPARATOR + path
end
@@ -121,28 +201,28 @@
#
# @note this _replaces_ the dataset's currently configured headers.
# To non-destructively add a new header, use `#add_header`
#
# @example
- # users = Dataset.new(config, headers: { Accept: 'application/json' })
+ # users = Dataset.new(headers: { Accept: 'application/json' })
# users.with_headers(:'X-Api-Key' => '1234').headers
# # => { :'X-Api-Key' => '1234' }
#
# @return [Dataset]
#
# @api public
def with_headers(headers)
- __new__(config, options.merge(headers: headers))
+ with_options(headers: headers)
end
# Return a new dataset with additional header
#
# @param header [Symbol] the HTTP header to add
# @param value [String] the header value
#
# @example
- # users = Dataset.new(config, headers: { Accept: 'application/json' })
+ # users = Dataset.new(headers: { Accept: 'application/json' })
# users.add_header(:'X-Api-Key', '1234').headers
# # => { :Accept => 'application/json', :'X-Api-Key' => '1234' }
#
# @return [Dataset]
#
@@ -157,11 +237,11 @@
#
# @return [Dataset]
#
# @api public
def with_options(opts)
- __new__(config, options.merge(opts))
+ __new__(options.merge(opts))
end
# Return a new dataset with a different base path
#
# @param base_path [String] the new base request path
@@ -202,11 +282,11 @@
#
# @return [Dataset]
#
# @api public
def append_path(append_path)
- with_options(path: join_path(path, append_path))
+ with_path(join_path(options[:path], append_path))
end
# Return a new dataset with a different request method
#
# @param [Symbol] request_method the new HTTP verb
@@ -224,11 +304,11 @@
# Return a new dataset with replaced request parameters
#
# @param [Hash] params the new request parameters
#
# @example
- # users = Dataset.new(config, params: { uid: 33 })
+ # users = Dataset.new(params: { uid: 33 })
# users.with_params(login: 'jdoe').params
# # => { :login => 'jdoe' }
#
# @return [Dataset]
#
@@ -240,22 +320,19 @@
# Return a new dataset with merged request parameters
#
# @param [Hash] params the new request parameters to add
#
# @example
- # users = Dataset.new(config, params: { uid: 33 })
+ # users = Dataset.new(params: { uid: 33 })
# users.add_params(login: 'jdoe').params
# # => { uid: 33, :login => 'jdoe' }
#
# @return [Dataset]
#
# @api public
def add_params(new_params)
- # TODO: Should we merge arrays?
- with_options(
- params: ::ROM::HTTP::Transformer[:deep_merge][params, new_params]
- )
+ with_options(params: ::ROM::HTTP::Transformer[:deep_merge][params, new_params])
end
# Iterate over each response value
#
# @yield [Hash] a dataset tuple
@@ -275,40 +352,32 @@
#
# @return [Array<Hash>]
#
# @api public
def insert(params)
- with_options(
- request_method: :post,
- params: params
- ).response
+ with_options(request_method: :post, params: params).response
end
# Perform an update over HTTP Put
#
# @params [Hash] params The request parameters to send
#
# @return [Array<Hash>]
#
# @api public
def update(params)
- with_options(
- request_method: :put,
- params: params
- ).response
+ with_options(request_method: :put, params: params).response
end
# Perform an delete over HTTP Delete
#
#
# @return [Array<Hash>]
#
# @api public
def delete
- with_options(
- request_method: :delete
- ).response
+ with_options(request_method: :delete).response
end
# Execute the current dataset
#
# @return [Array<hash>]
@@ -316,39 +385,21 @@
# @api public
def response
response_handler.call(request_handler.call(self), self)
end
+ memoize :uri, :absolute_path
+
private
- def response_handler
- response_handler = config.fetch(
- :response_handler,
- self.class.config.default_response_handler
- )
- fail Error, '+default_response_handler+ configuration missing' if response_handler.nil?
- response_handler
- end
-
- def request_handler
- request_handler = config.fetch(
- :request_handler,
- self.class.config.default_request_handler
- )
- fail Error, '+default_response_handler+ configuration missing' if request_handler.nil?
- request_handler
- end
-
+ # @api private
def __new__(*args, &block)
self.class.new(*args, &block)
end
+ # @api private
def join_path(*paths)
paths.reject(&:empty?).join(PATH_SEPARATOR)
- end
-
- def strip_path(path)
- path.sub(%r{\A/}, '')
end
end
end
end