server/lib/sinatra/rack_matrix_params.rb
# This will allow to use 'matrix' params in requests, like:
#
# http://example.com/library;section=nw/books;topic=money;binding=hardcover
#
# Will result in this params matrix:
#
# => params['library']['section'] = 'nw'
# => params['books']['topic'] = 'money'
# => params['books']['binding'] = 'hardcover'
#
# All HTTP methods are supported, in case of POST they will be passed as a
# regular <form> parameters.


Will result in this params matrix.



All HTTP methods are supported, in case of POST they will be passed as a
regular  parameters.
Will result in this params matrix . All HTTP methods are supported in case of POST they will be passed as a regular parameters .
def call(env)
      if env['rack.test']
        env['REQUEST_URI'] = env['PATH_INFO']
        env['REQUEST_PATH'] = env['PATH_INFO']
      end
       Split URI to components and then extract ;var=value pairs
      matrix_params = {}
      uri_components = (env['rack.test'] ? env['PATH_INFO'] : env['REQUEST_URI']).split('/')
      uri_components.each do |component|
        sub_components, value = component.split(/\;(\w+)\=/), nil
        next unless sub_components.first   Skip subcomponent if it's empty (usually /)
        while param=sub_components.pop do
          if value
            matrix_params[sub_components.first] ||= {}
            matrix_params[sub_components.first].merge!(param => value)
            value=nil
            next
          else
            value = param.gsub(/\?.*$/, '')
          end
        end
      end
       Two things need to happen to make matrix params work:
           (1) the parameters need to be appended to the 'normal' params
               for the request. 'Normal' really depends on the content
               type of the request, which does not seem accessible from
               Middleware, so we use the existence of
               rack.request.form_hash in the environment to distinguish
               between basic and application/x-www-form-urlencoded
               requests
           (2) the parameters need to be stripped from the appropriate
               path related env variables, so that request dispatching
               does not trip over them
       (1) Rewrite current path by stripping all matrix params from it
      ['REQUEST_PATH', 'REQUEST_URI', 'PATH_INFO'].select { |k|
        env[k] }.each do |k|
        env[k] = env[k].remove_matrix_params
      end
       (2) Append the matrix params to the 'normal' request params
       FIXME: Make this work for multipart/form-data
      if env['rack.request.form_hash']
         application/x-www-form-urlencoded, most likely a POST
        env['rack.request.form_hash'].merge!(matrix_params)
      else
         For other methods it's more complicated
        if env['REQUEST_METHOD']!='POST' and not matrix_params.keys.empty?
          env['QUERY_STRING'] = env['QUERY_STRING'].gsub(/;([^\/]*)/, '')
          new_params = matrix_params.collect do |component, params|
            params.collect { |k,v| "{component}[{k}]={CGI::escape(v.to_s)}" }
          end.flatten
           Add matrix params as a regular GET params
          env['QUERY_STRING'] += '&' if not env['QUERY_STRING'].empty?
          env['QUERY_STRING'] += "{new_params.join('&')}"
        end
      end
      @app.call(env)
    end
def call ( env ) if env [ 'rack.test' ] env [ 'REQUEST_URI' ] = env [ 'PATH_INFO' ] env [ 'REQUEST_PATH' ] = env [ 'PATH_INFO' ] end matrix_params = { } uri_components = ( env [ 'rack.test' ] ? env [ 'PATH_INFO' ] : env [ 'REQUEST_URI' ] ) . split ( '/' ) uri_components . each do | component | sub_components , value = component . split ( / \; ( \w +) \= / ) , nil next unless sub_components . first while param = sub_components . pop do if value matrix_params [ sub_components . first ] ||= { } matrix_params [ sub_components . first ] . merge! ( param => value ) value = nil next else value = param . gsub ( / \? .*$ / , '' ) end end end [ 'REQUEST_PATH' , 'REQUEST_URI' , 'PATH_INFO' ] . select { | k | env [ k ] } . each do | k | env [ k ] = env [ k ] . remove_matrix_params end if env [ 'rack.request.form_hash' ] env [ 'rack.request.form_hash' ] . merge! ( matrix_params ) else if env [ 'REQUEST_METHOD' ] != 'POST' and not matrix_params . keys . empty? env [ 'QUERY_STRING' ] = env [ 'QUERY_STRING' ] . gsub ( / ;([^ \/ ]*) / , '' ) new_params = matrix_params . collect do | component , params | params . collect { | k , v | "#{component}[#{k}]=#{CGI::escape(v.to_s)}" } end . flatten env [ 'QUERY_STRING' ] += '&' if not env [ 'QUERY_STRING' ] . empty? env [ 'QUERY_STRING' ] += "#{new_params.join('&')}" end end @app . call ( env ) end
This will allow to use 'matrix' params in requests, like:
http://example.com/library;section=nw/books;topic=money;binding=hardcover
This will allow to use ' matrix ' params in requests like : http : // example . com / library ; section = nw / books ; topic = money ; binding = hardcover
# This ugly hack should fix the issue with Rack::Test where # these two variables are empty and Rack::Test will always # return 404. # # Split URI to components and then extract ;var=value pairs # Skip subcomponent if it's empty (usually /) # Two things need to happen to make matrix params work: #     (1) the parameters need to be appended to the 'normal' params #         for the request. 'Normal' really depends on the content #         type of the request, which does not seem accessible from #         Middleware, so we use the existence of #         rack.request.form_hash in the environment to distinguish #         between basic and application/x-www-form-urlencoded #         requests #     (2) the parameters need to be stripped from the appropriate #         path related env variables, so that request dispatching #         does not trip over them # (1) Rewrite current path by stripping all matrix params from it # (2) Append the matrix params to the 'normal' request params # FIXME: Make this work for multipart/form-data # application/x-www-form-urlencoded, most likely a POST # For other methods it's more complicated # Add matrix params as a regular GET params
env
<not_specific>