Class: Rack::MatrixParams

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/matrix_params.rb

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ MatrixParams

Returns a new instance of MatrixParams.



25
26
27
# File 'lib/rack/matrix_params.rb', line 25

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Object

This will allow to use ‘matrix’ params in requests, like:

example.com/library;section=nw/books;topic=money;binding=hardcover

Will result in this params matrix:

> params[‘section’] = ‘nw’

> params[‘topic’] = ‘money’

> params[‘binding’] = ‘hardcover’

All HTTP methods are supported, in case of POST they will be passed as a regular <form> parameters.



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/rack/matrix_params.rb', line 42

def call(env)
  # Split URI to components and then extract ;var=value pairs
  uri_components = env['PATH_INFO'].split('/')
  matrix_params = {}
  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
        # There are matrix components to this path element
        (matrix_params[sub_components.first] ||= {}).merge!( param => value )

        value = nil
        next
      else
        # There are no matrix components to this path element
        value = param
      end
    end
  end

  # No need for anything else if there are no matrix params
  return @app.call(env) if matrix_params.keys.empty?

  # If request method is POST, simply include matrix params in form_hash
  env['rack.request.form_hash'].merge!(matrix_params) if env['rack.request.form_hash']

  # For other methods it's a way complicated ;-)
  if env['REQUEST_METHOD'] != 'POST'

    # Rewrite current path and query string and strip all query params from it
    env['PATH_INFO'] = env['PATH_INFO'].gsub(/;([^\/]*)/, '').gsub(/\?(.*)$/, '')

    env['QUERY_STRING'] = env['QUERY_STRING'].gsub(/;([^\/]*)/, '').freeze
    
    new_params = matrix_params.collect do |component, params|
      params.collect do |k,v|
        "#{component}[#{k}]=#{CGI::escape(v.to_s)}"
      end.reverse
    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

  @app.call(env)
end