Class Index [+]

Quicksearch

Rack::Utils

Rack::Utils contains a grab-bag of useful methods for writing web applications adopted from all kinds of Ruby libraries.

Constants

DEFAULT_SEP
ESCAPE_HTML
ESCAPE_HTML_PATTERN
HTTP_STATUS_CODES

Every standard HTTP code mapped to the appropriate message. Generated with:

  curl -s http://www.iana.org/assignments/http-status-codes | \
    ruby -ane 'm = /^(\d{3}) +(\S[^\[(]+)/.match($_) and
               puts "      #{m[1]}  => \x27#{m[2].strip}x27,"'
STATUS_WITH_NO_ENTITY_BODY

Responses with HTTP status codes that should not have an entity body

SYMBOL_TO_STATUS_CODE

Public Class Methods

build_nested_query(value, prefix = nil) click to toggle source
     # File lib/rack/utils.rb, line 112
112:     def build_nested_query(value, prefix = nil)
113:       case value
114:       when Array
115:         value.map { |v|
116:           build_nested_query(v, "#{prefix}[]")
117:         }.join("&")
118:       when Hash
119:         value.map { |k, v|
120:           build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
121:         }.join("&")
122:       when String
123:         raise ArgumentError, "value must be a Hash" if prefix.nil?
124:         "#{prefix}=#{escape(value)}"
125:       else
126:         prefix
127:       end
128:     end
build_query(params) click to toggle source
     # File lib/rack/utils.rb, line 101
101:     def build_query(params)
102:       params.map { |k, v|
103:         if v.class == Array
104:           build_query(v.map { |x| [k, x] })
105:         else
106:           "#{escape(k)}=#{escape(v)}"
107:         end
108:       }.join("&")
109:     end
bytesize(string) click to toggle source
     # File lib/rack/utils.rb, line 238
238:       def bytesize(string)
239:         string.bytesize
240:       end
bytesize(string) click to toggle source
     # File lib/rack/utils.rb, line 242
242:       def bytesize(string)
243:         string.size
244:       end
escape(s) click to toggle source

Performs URI escaping so that you can construct proper query strings faster. Use this rather than the cgi.rb version since it’s faster. (Stolen from Camping).

    # File lib/rack/utils.rb, line 15
15:     def escape(s)
16:       s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/) {
17:         '%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
18:       }.tr(' ', '+')
19:     end
escape_html(string) click to toggle source

Escape ampersands, brackets and quotes to their HTML/XML entities.

     # File lib/rack/utils.rb, line 141
141:     def escape_html(string)
142:       string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
143:     end
normalize_params(params, name, v = nil) click to toggle source
    # File lib/rack/utils.rb, line 69
69:     def normalize_params(params, name, v = nil)
70:       name =~ %(\A[\[\]]*([^\[\]]+)\]*)
71:       k = $1 || ''
72:       after = $' || ''
73: 
74:       return if k.empty?
75: 
76:       if after == ""
77:         params[k] = v
78:       elsif after == "[]"
79:         params[k] ||= []
80:         raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
81:         params[k] << v
82:       elsif after =~ %(^\[\]\[([^\[\]]+)\]$) || after =~ %(^\[\](.+)$)
83:         child_key = $1
84:         params[k] ||= []
85:         raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
86:         if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key)
87:           normalize_params(params[k].last, child_key, v)
88:         else
89:           params[k] << normalize_params({}, child_key, v)
90:         end
91:       else
92:         params[k] ||= {}
93:         raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash)
94:         params[k] = normalize_params(params[k], after, v)
95:       end
96: 
97:       return params
98:     end
parse_nested_query(qs, d = nil) click to toggle source
    # File lib/rack/utils.rb, line 57
57:     def parse_nested_query(qs, d = nil)
58:       params = {}
59: 
60:       (qs || '').split(d ? /[#{d}] */ : DEFAULT_SEP).each do |p|
61:         k, v = unescape(p).split('=', 2)
62:         normalize_params(params, k, v)
63:       end
64: 
65:       return params
66:     end
parse_query(qs, d = nil) click to toggle source

Stolen from Mongrel, with some small modifications: Parses a query string by breaking it up at the ’&’ and ’;’ characters. You can also use this to parse cookies by changing the characters used in the second parameter (which defaults to ’&;’).

    # File lib/rack/utils.rb, line 37
37:     def parse_query(qs, d = nil)
38:       params = {}
39: 
40:       (qs || '').split(d ? /[#{d}] */ : DEFAULT_SEP).each do |p|
41:         k, v = p.split('=', 2).map { |x| unescape(x) }
42:         if cur = params[k]
43:           if cur.class == Array
44:             params[k] << v
45:           else
46:             params[k] = [cur, v]
47:           end
48:         else
49:           params[k] = v
50:         end
51:       end
52: 
53:       return params
54:     end
rfc2822(time) click to toggle source

Modified version of stdlib time.rb Time#rfc2822 to use ’%d-%b-%Y’ instead of ’% %b %Y’. It assumes that the time is in GMT to comply to the RFC 2109.

NOTE: I’m not sure the RFC says it requires GMT, but is ambigous enough that I’m certain someone implemented only that option. Do not use %a and %b from Time.strptime, it would use localized names for weekday and month.

     # File lib/rack/utils.rb, line 257
257:     def rfc2822(time)
258:       wday = Time::RFC2822_DAY_NAME[time.wday]
259:       mon = Time::RFC2822_MONTH_NAME[time.mon - 1]
260:       time.strftime("#{wday}, %d-#{mon}-%Y %T GMT")
261:     end
select_best_encoding(available_encodings, accept_encoding) click to toggle source
     # File lib/rack/utils.rb, line 146
146:     def select_best_encoding(available_encodings, accept_encoding)
147:       # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
148: 
149:       expanded_accept_encoding =
150:         accept_encoding.map { |m, q|
151:           if m == "*"
152:             (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] }
153:           else
154:             [[m, q]]
155:           end
156:         }.inject([]) { |mem, list|
157:           mem + list
158:         }
159: 
160:       encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m }
161: 
162:       unless encoding_candidates.include?("identity")
163:         encoding_candidates.push("identity")
164:       end
165: 
166:       expanded_accept_encoding.find_all { |m, q|
167:         q == 0.0
168:       }.each { |m, _|
169:         encoding_candidates.delete(m)
170:       }
171: 
172:       return (encoding_candidates & available_encodings)[0]
173:     end
status_code(status) click to toggle source
     # File lib/rack/utils.rb, line 430
430:     def status_code(status)
431:       if status.is_a?(Symbol)
432:         SYMBOL_TO_STATUS_CODE[status] || 500
433:       else
434:         status.to_i
435:       end
436:     end
unescape(s) click to toggle source

Unescapes a URI escaped string. (Stolen from Camping).

    # File lib/rack/utils.rb, line 23
23:     def unescape(s)
24:       s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/){
25:         [$1.delete('%')].pack('H*')
26:       }
27:     end

Private Instance Methods

build_nested_query(value, prefix = nil) click to toggle source
     # File lib/rack/utils.rb, line 112
112:     def build_nested_query(value, prefix = nil)
113:       case value
114:       when Array
115:         value.map { |v|
116:           build_nested_query(v, "#{prefix}[]")
117:         }.join("&")
118:       when Hash
119:         value.map { |k, v|
120:           build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
121:         }.join("&")
122:       when String
123:         raise ArgumentError, "value must be a Hash" if prefix.nil?
124:         "#{prefix}=#{escape(value)}"
125:       else
126:         prefix
127:       end
128:     end
build_query(params) click to toggle source
     # File lib/rack/utils.rb, line 101
101:     def build_query(params)
102:       params.map { |k, v|
103:         if v.class == Array
104:           build_query(v.map { |x| [k, x] })
105:         else
106:           "#{escape(k)}=#{escape(v)}"
107:         end
108:       }.join("&")
109:     end
bytesize(string) click to toggle source
     # File lib/rack/utils.rb, line 238
238:       def bytesize(string)
239:         string.bytesize
240:       end
bytesize(string) click to toggle source
     # File lib/rack/utils.rb, line 242
242:       def bytesize(string)
243:         string.size
244:       end
escape(s) click to toggle source

Performs URI escaping so that you can construct proper query strings faster. Use this rather than the cgi.rb version since it’s faster. (Stolen from Camping).

    # File lib/rack/utils.rb, line 15
15:     def escape(s)
16:       s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/) {
17:         '%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
18:       }.tr(' ', '+')
19:     end
escape_html(string) click to toggle source

Escape ampersands, brackets and quotes to their HTML/XML entities.

     # File lib/rack/utils.rb, line 141
141:     def escape_html(string)
142:       string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] }
143:     end
normalize_params(params, name, v = nil) click to toggle source
    # File lib/rack/utils.rb, line 69
69:     def normalize_params(params, name, v = nil)
70:       name =~ %(\A[\[\]]*([^\[\]]+)\]*)
71:       k = $1 || ''
72:       after = $' || ''
73: 
74:       return if k.empty?
75: 
76:       if after == ""
77:         params[k] = v
78:       elsif after == "[]"
79:         params[k] ||= []
80:         raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
81:         params[k] << v
82:       elsif after =~ %(^\[\]\[([^\[\]]+)\]$) || after =~ %(^\[\](.+)$)
83:         child_key = $1
84:         params[k] ||= []
85:         raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array)
86:         if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key)
87:           normalize_params(params[k].last, child_key, v)
88:         else
89:           params[k] << normalize_params({}, child_key, v)
90:         end
91:       else
92:         params[k] ||= {}
93:         raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash)
94:         params[k] = normalize_params(params[k], after, v)
95:       end
96: 
97:       return params
98:     end
parse_nested_query(qs, d = nil) click to toggle source
    # File lib/rack/utils.rb, line 57
57:     def parse_nested_query(qs, d = nil)
58:       params = {}
59: 
60:       (qs || '').split(d ? /[#{d}] */ : DEFAULT_SEP).each do |p|
61:         k, v = unescape(p).split('=', 2)
62:         normalize_params(params, k, v)
63:       end
64: 
65:       return params
66:     end
parse_query(qs, d = nil) click to toggle source

Stolen from Mongrel, with some small modifications: Parses a query string by breaking it up at the ’&’ and ’;’ characters. You can also use this to parse cookies by changing the characters used in the second parameter (which defaults to ’&;’).

    # File lib/rack/utils.rb, line 37
37:     def parse_query(qs, d = nil)
38:       params = {}
39: 
40:       (qs || '').split(d ? /[#{d}] */ : DEFAULT_SEP).each do |p|
41:         k, v = p.split('=', 2).map { |x| unescape(x) }
42:         if cur = params[k]
43:           if cur.class == Array
44:             params[k] << v
45:           else
46:             params[k] = [cur, v]
47:           end
48:         else
49:           params[k] = v
50:         end
51:       end
52: 
53:       return params
54:     end
rfc2822(time) click to toggle source

Modified version of stdlib time.rb Time#rfc2822 to use ’%d-%b-%Y’ instead of ’% %b %Y’. It assumes that the time is in GMT to comply to the RFC 2109.

NOTE: I’m not sure the RFC says it requires GMT, but is ambigous enough that I’m certain someone implemented only that option. Do not use %a and %b from Time.strptime, it would use localized names for weekday and month.

     # File lib/rack/utils.rb, line 257
257:     def rfc2822(time)
258:       wday = Time::RFC2822_DAY_NAME[time.wday]
259:       mon = Time::RFC2822_MONTH_NAME[time.mon - 1]
260:       time.strftime("#{wday}, %d-#{mon}-%Y %T GMT")
261:     end
select_best_encoding(available_encodings, accept_encoding) click to toggle source
     # File lib/rack/utils.rb, line 146
146:     def select_best_encoding(available_encodings, accept_encoding)
147:       # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
148: 
149:       expanded_accept_encoding =
150:         accept_encoding.map { |m, q|
151:           if m == "*"
152:             (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] }
153:           else
154:             [[m, q]]
155:           end
156:         }.inject([]) { |mem, list|
157:           mem + list
158:         }
159: 
160:       encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m }
161: 
162:       unless encoding_candidates.include?("identity")
163:         encoding_candidates.push("identity")
164:       end
165: 
166:       expanded_accept_encoding.find_all { |m, q|
167:         q == 0.0
168:       }.each { |m, _|
169:         encoding_candidates.delete(m)
170:       }
171: 
172:       return (encoding_candidates & available_encodings)[0]
173:     end
status_code(status) click to toggle source
     # File lib/rack/utils.rb, line 430
430:     def status_code(status)
431:       if status.is_a?(Symbol)
432:         SYMBOL_TO_STATUS_CODE[status] || 500
433:       else
434:         status.to_i
435:       end
436:     end
unescape(s) click to toggle source

Unescapes a URI escaped string. (Stolen from Camping).

    # File lib/rack/utils.rb, line 23
23:     def unescape(s)
24:       s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/){
25:         [$1.delete('%')].pack('H*')
26:       }
27:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.