0
0
Fork 0

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:
Gibheer 2012-11-08 21:31:24 +01:00
parent 396151eb70
commit 24eba118e6
3 changed files with 193 additions and 0 deletions

53
lib/zero/request.rb Normal file
View File

@ -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

View File

@ -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

View File

@ -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