replacement for rack request
This should replace Rack::Request in the hole lib. It seperates everything worth into its own classes, like parameters and the accept header till now. More will follow
This commit is contained in:
parent
396151eb70
commit
24eba118e6
|
@ -0,0 +1,53 @@
|
|||
require_relative 'request/accept'
|
||||
require_relative 'request/parameter'
|
||||
|
||||
module Zero
|
||||
# This class wraps around a rack environment for easier access to all data.
|
||||
class Request
|
||||
CONST_CONTENT_TYPE = 'CONTENT_TYPE'
|
||||
CONST_HTTP_ACCEPT = 'HTTP_ACCEPT'
|
||||
CONST_PATH_INFO = 'PATH_INFO'
|
||||
CONST_REQUEST_METHOD = 'REQUEST_METHOD'
|
||||
|
||||
# create a new request object
|
||||
def initialize(env)
|
||||
@env = env
|
||||
@method = @env[CONST_REQUEST_METHOD].downcase.to_sym
|
||||
end
|
||||
|
||||
# get the requested path
|
||||
def path
|
||||
@path ||= @env[CONST_PATH_INFO]
|
||||
end
|
||||
|
||||
# returns a set of get and post variables
|
||||
def params
|
||||
@params ||= Request::Parameter.new(@env)
|
||||
end
|
||||
|
||||
# return the content type of the request
|
||||
# TODO change into its own object?
|
||||
def content_type
|
||||
@env[CONST_CONTENT_TYPE] if @env.has_key?(CONST_CONTENT_TYPE)
|
||||
end
|
||||
|
||||
# get the media types
|
||||
# @return Accept on Accept object managing all types and their order
|
||||
def media_types
|
||||
@accept ||= Request::Accept.new(@env[CONST_HTTP_ACCEPT])
|
||||
end
|
||||
|
||||
# is the method 'GET'?
|
||||
def get?; @method == :get; end
|
||||
# is the method 'POST'?
|
||||
def post?; @method == :post; end
|
||||
# is the method 'PUT'?
|
||||
def put?; @method == :put; end
|
||||
# is the method 'DELETE'?
|
||||
def delete?; @method == :delete; end
|
||||
# is the method 'HEAD'?
|
||||
def head?; @method == :head; end
|
||||
# is the method 'PATCH'?
|
||||
def head?; @method == :patch; end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,76 @@
|
|||
module Zero
|
||||
class Request
|
||||
# encapsulates the accept header to easier work with
|
||||
# this is partly copied from sinatra
|
||||
class Accept
|
||||
MEDIA_TYPE_SEPERATOR = ','
|
||||
MEDIA_PARAM_SEPERATOR = ';'
|
||||
MEDIA_QUALITY_REGEX = /q=[01]\./
|
||||
|
||||
def self.media_map(map)
|
||||
@@map = map
|
||||
end
|
||||
|
||||
def self.map
|
||||
@@map ||= {}
|
||||
end
|
||||
|
||||
# create a new accept object
|
||||
def initialize(accept_string)
|
||||
@types = parse_media_types(accept_string)
|
||||
end
|
||||
|
||||
# return the preferred type
|
||||
# @return String the preferred media type
|
||||
def preferred
|
||||
@types.first
|
||||
end
|
||||
|
||||
# iterate over all media types
|
||||
def each
|
||||
@types.each {|type| yield type}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# converts the accept string to a useable array
|
||||
# @param accept_string the string containing media ranges and options
|
||||
def parse_media_types(accept_string = '*/*')
|
||||
accept_string.
|
||||
gsub(/\s/, '').
|
||||
split(MEDIA_TYPE_SEPERATOR).
|
||||
map do |accept_range|
|
||||
extract_order(*accept_range.split(MEDIA_PARAM_SEPERATOR))
|
||||
end.
|
||||
sort_by(&:last).
|
||||
map(&:first)
|
||||
end
|
||||
|
||||
# extract the order of the type
|
||||
# @param media_type the type itself
|
||||
# @param params further options to the type
|
||||
# @return Array the media type and quality in that order
|
||||
def extract_order(media_type, *params)
|
||||
params.each do |param|
|
||||
if param.match(MEDIA_QUALITY_REGEX)
|
||||
return [map_type(media_type), 10 - param[4..-1].to_i]
|
||||
end
|
||||
end
|
||||
[map_type(media_type), 0]
|
||||
end
|
||||
|
||||
# map media types to the type given in the map
|
||||
# @param type [String] the media type
|
||||
# @return the media type of the mapping or the original
|
||||
def map_type(type)
|
||||
return map[type] if map.has_key?(type)
|
||||
type
|
||||
end
|
||||
|
||||
# a small wrapper to the class method
|
||||
def map
|
||||
self.class.map
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,64 @@
|
|||
# TODO should that go into the main zero file?
|
||||
require 'set'
|
||||
|
||||
module Zero
|
||||
class Request
|
||||
# represents all parameter set in a session
|
||||
#
|
||||
# This class holds all parameters available in the rack environment, split
|
||||
# on query and payload parameters.
|
||||
class Parameter
|
||||
ENV_KEY_QUERY = 'QUERY_STRING'
|
||||
ENV_KEY_PAYLOAD = 'rack.input'
|
||||
ENV_KEY_CONTENT_TYPE = 'CONTENT_TYPE'
|
||||
PAYLOAD_CONTENT_TYPES = [
|
||||
'application/x-www-form-urlencoded',
|
||||
'multipart/form-data'
|
||||
].to_set
|
||||
|
||||
# get the query parameters
|
||||
attr_reader :query
|
||||
alias_method(:get, :query)
|
||||
|
||||
# get the payload or form data parameters
|
||||
attr_reader :payload
|
||||
alias_method(:post, :payload)
|
||||
|
||||
# creates a new parameter instance
|
||||
#
|
||||
# This should never be called directly, as it will be generated for you.
|
||||
# This instance gives you the options to get query parameters (mostly
|
||||
# called GET parameters) and payload parameters (or POST parameters).
|
||||
# @param environment [Hash] the rack environment
|
||||
def initialize(environment)
|
||||
@query = extract_query_params(environment)
|
||||
@payload = extract_payload_params(environment)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# extracts the key value pairs from the environment
|
||||
# @return Hash all key value pairs from query string
|
||||
def extract_query_params(environment)
|
||||
return {} if environment[ENV_KEY_QUERY].length == 0
|
||||
parse_string(environment[ENV_KEY_QUERY])
|
||||
end
|
||||
|
||||
# extracts the key value pairs from the body
|
||||
# @return Hash all key value pairs from the payload
|
||||
def extract_payload_params(environment)
|
||||
return {} unless PAYLOAD_CONTENT_TYPES.include?(environment[ENV_KEY_CONTENT_TYPE])
|
||||
parse_string(environment[ENV_KEY_PAYLOAD].read)
|
||||
end
|
||||
|
||||
# parse the query string like input to a hash
|
||||
# @param query [String] the query string
|
||||
# @return [Hash] the key/valuie pairs
|
||||
def parse_string(query)
|
||||
params = query.split('&')
|
||||
params.map! {|part| part.split('=') }
|
||||
Hash[params]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in New Issue