rack 1.6.13 → 2.1.4.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -0
  3. data/{COPYING → MIT-LICENSE} +4 -2
  4. data/README.rdoc +105 -141
  5. data/Rakefile +27 -28
  6. data/SPEC +6 -7
  7. data/bin/rackup +1 -0
  8. data/contrib/rack_logo.svg +164 -111
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +4 -2
  11. data/example/protectedlobster.ru +3 -1
  12. data/lib/rack/auth/abstract/handler.rb +3 -1
  13. data/lib/rack/auth/abstract/request.rb +7 -1
  14. data/lib/rack/auth/basic.rb +4 -1
  15. data/lib/rack/auth/digest/md5.rb +9 -7
  16. data/lib/rack/auth/digest/nonce.rb +6 -3
  17. data/lib/rack/auth/digest/params.rb +5 -4
  18. data/lib/rack/auth/digest/request.rb +3 -1
  19. data/lib/rack/body_proxy.rb +11 -9
  20. data/lib/rack/builder.rb +42 -18
  21. data/lib/rack/cascade.rb +6 -5
  22. data/lib/rack/chunked.rb +33 -10
  23. data/lib/rack/{commonlogger.rb → common_logger.rb} +14 -10
  24. data/lib/rack/{conditionalget.rb → conditional_get.rb} +3 -1
  25. data/lib/rack/config.rb +2 -0
  26. data/lib/rack/content_length.rb +5 -3
  27. data/lib/rack/content_type.rb +3 -1
  28. data/lib/rack/core_ext/regexp.rb +14 -0
  29. data/lib/rack/deflater.rb +33 -53
  30. data/lib/rack/directory.rb +75 -60
  31. data/lib/rack/etag.rb +8 -5
  32. data/lib/rack/events.rb +156 -0
  33. data/lib/rack/file.rb +4 -149
  34. data/lib/rack/files.rb +178 -0
  35. data/lib/rack/handler/cgi.rb +18 -17
  36. data/lib/rack/handler/fastcgi.rb +17 -16
  37. data/lib/rack/handler/lsws.rb +14 -12
  38. data/lib/rack/handler/scgi.rb +22 -19
  39. data/lib/rack/handler/thin.rb +6 -1
  40. data/lib/rack/handler/webrick.rb +28 -28
  41. data/lib/rack/handler.rb +9 -26
  42. data/lib/rack/head.rb +17 -17
  43. data/lib/rack/lint.rb +55 -52
  44. data/lib/rack/lobster.rb +8 -6
  45. data/lib/rack/lock.rb +17 -10
  46. data/lib/rack/logger.rb +4 -2
  47. data/lib/rack/media_type.rb +43 -0
  48. data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
  49. data/lib/rack/mime.rb +27 -6
  50. data/lib/rack/mock.rb +101 -60
  51. data/lib/rack/multipart/generator.rb +11 -12
  52. data/lib/rack/multipart/parser.rb +292 -161
  53. data/lib/rack/multipart/uploaded_file.rb +3 -2
  54. data/lib/rack/multipart.rb +38 -8
  55. data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
  56. data/lib/rack/query_parser.rb +218 -0
  57. data/lib/rack/recursive.rb +11 -9
  58. data/lib/rack/reloader.rb +10 -4
  59. data/lib/rack/request.rb +447 -305
  60. data/lib/rack/response.rb +196 -83
  61. data/lib/rack/rewindable_input.rb +5 -14
  62. data/lib/rack/runtime.rb +12 -18
  63. data/lib/rack/sendfile.rb +19 -14
  64. data/lib/rack/server.rb +118 -41
  65. data/lib/rack/session/abstract/id.rb +139 -94
  66. data/lib/rack/session/cookie.rb +34 -26
  67. data/lib/rack/session/memcache.rb +4 -93
  68. data/lib/rack/session/pool.rb +12 -10
  69. data/lib/rack/show_exceptions.rb +392 -0
  70. data/lib/rack/{showstatus.rb → show_status.rb} +7 -5
  71. data/lib/rack/static.rb +41 -11
  72. data/lib/rack/tempfile_reaper.rb +4 -2
  73. data/lib/rack/urlmap.rb +25 -15
  74. data/lib/rack/utils.rb +203 -277
  75. data/lib/rack.rb +76 -24
  76. data/rack.gemspec +25 -14
  77. metadata +62 -183
  78. data/HISTORY.md +0 -375
  79. data/KNOWN-ISSUES +0 -44
  80. data/lib/rack/backports/uri/common_18.rb +0 -56
  81. data/lib/rack/backports/uri/common_192.rb +0 -52
  82. data/lib/rack/backports/uri/common_193.rb +0 -29
  83. data/lib/rack/handler/evented_mongrel.rb +0 -8
  84. data/lib/rack/handler/mongrel.rb +0 -106
  85. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  86. data/lib/rack/showexceptions.rb +0 -387
  87. data/lib/rack/utils/okjson.rb +0 -600
  88. data/test/builder/anything.rb +0 -5
  89. data/test/builder/comment.ru +0 -4
  90. data/test/builder/end.ru +0 -5
  91. data/test/builder/line.ru +0 -1
  92. data/test/builder/options.ru +0 -2
  93. data/test/cgi/assets/folder/test.js +0 -1
  94. data/test/cgi/assets/fonts/font.eot +0 -1
  95. data/test/cgi/assets/images/image.png +0 -1
  96. data/test/cgi/assets/index.html +0 -1
  97. data/test/cgi/assets/javascripts/app.js +0 -1
  98. data/test/cgi/assets/stylesheets/app.css +0 -1
  99. data/test/cgi/lighttpd.conf +0 -26
  100. data/test/cgi/rackup_stub.rb +0 -6
  101. data/test/cgi/sample_rackup.ru +0 -5
  102. data/test/cgi/test +0 -9
  103. data/test/cgi/test+directory/test+file +0 -1
  104. data/test/cgi/test.fcgi +0 -8
  105. data/test/cgi/test.ru +0 -5
  106. data/test/gemloader.rb +0 -10
  107. data/test/multipart/bad_robots +0 -259
  108. data/test/multipart/binary +0 -0
  109. data/test/multipart/content_type_and_no_filename +0 -6
  110. data/test/multipart/empty +0 -10
  111. data/test/multipart/fail_16384_nofile +0 -814
  112. data/test/multipart/file1.txt +0 -1
  113. data/test/multipart/filename_and_modification_param +0 -7
  114. data/test/multipart/filename_and_no_name +0 -6
  115. data/test/multipart/filename_with_escaped_quotes +0 -6
  116. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  117. data/test/multipart/filename_with_null_byte +0 -7
  118. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  119. data/test/multipart/filename_with_unescaped_percentages +0 -6
  120. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  121. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  122. data/test/multipart/filename_with_unescaped_quotes +0 -6
  123. data/test/multipart/ie +0 -6
  124. data/test/multipart/invalid_character +0 -6
  125. data/test/multipart/mixed_files +0 -21
  126. data/test/multipart/nested +0 -10
  127. data/test/multipart/none +0 -9
  128. data/test/multipart/semicolon +0 -6
  129. data/test/multipart/text +0 -15
  130. data/test/multipart/three_files_three_fields +0 -31
  131. data/test/multipart/webkit +0 -32
  132. data/test/rackup/config.ru +0 -31
  133. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  134. data/test/spec_auth_basic.rb +0 -81
  135. data/test/spec_auth_digest.rb +0 -259
  136. data/test/spec_body_proxy.rb +0 -85
  137. data/test/spec_builder.rb +0 -223
  138. data/test/spec_cascade.rb +0 -61
  139. data/test/spec_cgi.rb +0 -102
  140. data/test/spec_chunked.rb +0 -101
  141. data/test/spec_commonlogger.rb +0 -93
  142. data/test/spec_conditionalget.rb +0 -102
  143. data/test/spec_config.rb +0 -22
  144. data/test/spec_content_length.rb +0 -85
  145. data/test/spec_content_type.rb +0 -45
  146. data/test/spec_deflater.rb +0 -339
  147. data/test/spec_directory.rb +0 -88
  148. data/test/spec_etag.rb +0 -107
  149. data/test/spec_fastcgi.rb +0 -107
  150. data/test/spec_file.rb +0 -221
  151. data/test/spec_handler.rb +0 -72
  152. data/test/spec_head.rb +0 -45
  153. data/test/spec_lint.rb +0 -550
  154. data/test/spec_lobster.rb +0 -58
  155. data/test/spec_lock.rb +0 -164
  156. data/test/spec_logger.rb +0 -23
  157. data/test/spec_methodoverride.rb +0 -111
  158. data/test/spec_mime.rb +0 -51
  159. data/test/spec_mock.rb +0 -297
  160. data/test/spec_mongrel.rb +0 -182
  161. data/test/spec_multipart.rb +0 -600
  162. data/test/spec_nulllogger.rb +0 -20
  163. data/test/spec_recursive.rb +0 -72
  164. data/test/spec_request.rb +0 -1232
  165. data/test/spec_response.rb +0 -407
  166. data/test/spec_rewindable_input.rb +0 -118
  167. data/test/spec_runtime.rb +0 -49
  168. data/test/spec_sendfile.rb +0 -130
  169. data/test/spec_server.rb +0 -167
  170. data/test/spec_session_abstract_id.rb +0 -53
  171. data/test/spec_session_cookie.rb +0 -410
  172. data/test/spec_session_memcache.rb +0 -358
  173. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  174. data/test/spec_session_pool.rb +0 -246
  175. data/test/spec_showexceptions.rb +0 -98
  176. data/test/spec_showstatus.rb +0 -103
  177. data/test/spec_static.rb +0 -145
  178. data/test/spec_tempfile_reaper.rb +0 -63
  179. data/test/spec_thin.rb +0 -91
  180. data/test/spec_urlmap.rb +0 -236
  181. data/test/spec_utils.rb +0 -647
  182. data/test/spec_version.rb +0 -17
  183. data/test/spec_webrick.rb +0 -184
  184. data/test/static/another/index.html +0 -1
  185. data/test/static/index.html +0 -1
  186. data/test/testrequest.rb +0 -78
  187. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  188. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/mock.rb CHANGED
@@ -1,9 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
  require 'stringio'
3
5
  require 'rack'
4
6
  require 'rack/lint'
5
7
  require 'rack/utils'
6
8
  require 'rack/response'
9
+ require 'cgi/cookie'
7
10
 
8
11
  module Rack
9
12
  # Rack::MockRequest helps testing your Rack application without
@@ -41,28 +44,28 @@ module Rack
41
44
  end
42
45
 
43
46
  DEFAULT_ENV = {
44
- "rack.version" => Rack::VERSION,
45
- "rack.input" => StringIO.new,
46
- "rack.errors" => StringIO.new,
47
- "rack.multithread" => true,
48
- "rack.multiprocess" => true,
49
- "rack.run_once" => false,
50
- }
47
+ RACK_VERSION => Rack::VERSION,
48
+ RACK_INPUT => StringIO.new,
49
+ RACK_ERRORS => StringIO.new,
50
+ RACK_MULTITHREAD => true,
51
+ RACK_MULTIPROCESS => true,
52
+ RACK_RUNONCE => false,
53
+ }.freeze
51
54
 
52
55
  def initialize(app)
53
56
  @app = app
54
57
  end
55
58
 
56
- def get(uri, opts={}) request("GET", uri, opts) end
57
- def post(uri, opts={}) request("POST", uri, opts) end
58
- def put(uri, opts={}) request("PUT", uri, opts) end
59
- def patch(uri, opts={}) request("PATCH", uri, opts) end
60
- def delete(uri, opts={}) request("DELETE", uri, opts) end
61
- def head(uri, opts={}) request("HEAD", uri, opts) end
62
- def options(uri, opts={}) request("OPTIONS", uri, opts) end
59
+ def get(uri, opts = {}) request(GET, uri, opts) end
60
+ def post(uri, opts = {}) request(POST, uri, opts) end
61
+ def put(uri, opts = {}) request(PUT, uri, opts) end
62
+ def patch(uri, opts = {}) request(PATCH, uri, opts) end
63
+ def delete(uri, opts = {}) request(DELETE, uri, opts) end
64
+ def head(uri, opts = {}) request(HEAD, uri, opts) end
65
+ def options(uri, opts = {}) request(OPTIONS, uri, opts) end
63
66
 
64
- def request(method="GET", uri="", opts={})
65
- env = self.class.env_for(uri, opts.merge(:method => method))
67
+ def request(method = GET, uri = "", opts = {})
68
+ env = self.class.env_for(uri, opts.merge(method: method))
66
69
 
67
70
  if opts[:lint]
68
71
  app = Rack::Lint.new(@app)
@@ -70,49 +73,55 @@ module Rack
70
73
  app = @app
71
74
  end
72
75
 
73
- errors = env["rack.errors"]
74
- status, headers, body = app.call(env)
76
+ errors = env[RACK_ERRORS]
77
+ status, headers, body = app.call(env)
75
78
  MockResponse.new(status, headers, body, errors)
76
79
  ensure
77
80
  body.close if body.respond_to?(:close)
78
81
  end
79
82
 
80
- # For historical reasons, we're pinning to RFC 2396. It's easier for users
81
- # and we get support from ruby 1.8 to 2.2 using this method.
83
+ # For historical reasons, we're pinning to RFC 2396.
84
+ # URI::Parser = URI::RFC2396_Parser
82
85
  def self.parse_uri_rfc2396(uri)
83
- @parser ||= defined?(URI::RFC2396_Parser) ? URI::RFC2396_Parser.new : URI
86
+ @parser ||= URI::Parser.new
84
87
  @parser.parse(uri)
85
88
  end
86
89
 
87
90
  # Return the Rack environment used for a request to +uri+.
88
- def self.env_for(uri="", opts={})
91
+ def self.env_for(uri = "", opts = {})
89
92
  uri = parse_uri_rfc2396(uri)
90
93
  uri.path = "/#{uri.path}" unless uri.path[0] == ?/
91
94
 
92
95
  env = DEFAULT_ENV.dup
93
96
 
94
- env_with_encoding(env, opts, uri)
97
+ env[REQUEST_METHOD] = (opts[:method] ? opts[:method].to_s.upcase : GET).b
98
+ env[SERVER_NAME] = (uri.host || "example.org").b
99
+ env[SERVER_PORT] = (uri.port ? uri.port.to_s : "80").b
100
+ env[QUERY_STRING] = (uri.query.to_s).b
101
+ env[PATH_INFO] = ((!uri.path || uri.path.empty?) ? "/" : uri.path).b
102
+ env[RACK_URL_SCHEME] = (uri.scheme || "http").b
103
+ env[HTTPS] = (env[RACK_URL_SCHEME] == "https" ? "on" : "off").b
95
104
 
96
105
  env[SCRIPT_NAME] = opts[:script_name] || ""
97
106
 
98
107
  if opts[:fatal]
99
- env["rack.errors"] = FatalWarner.new
108
+ env[RACK_ERRORS] = FatalWarner.new
100
109
  else
101
- env["rack.errors"] = StringIO.new
110
+ env[RACK_ERRORS] = StringIO.new
102
111
  end
103
112
 
104
113
  if params = opts[:params]
105
- if env[REQUEST_METHOD] == "GET"
114
+ if env[REQUEST_METHOD] == GET
106
115
  params = Utils.parse_nested_query(params) if params.is_a?(String)
107
116
  params.update(Utils.parse_nested_query(env[QUERY_STRING]))
108
117
  env[QUERY_STRING] = Utils.build_nested_query(params)
109
118
  elsif !opts.has_key?(:input)
110
119
  opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
111
120
  if params.is_a?(Hash)
112
- if data = Utils::Multipart.build_multipart(params)
121
+ if data = Rack::Multipart.build_multipart(params)
113
122
  opts[:input] = data
114
123
  opts["CONTENT_LENGTH"] ||= data.length.to_s
115
- opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Utils::Multipart::MULTIPART_BOUNDARY}"
124
+ opts["CONTENT_TYPE"] = "multipart/form-data; boundary=#{Rack::Multipart::MULTIPART_BOUNDARY}"
116
125
  else
117
126
  opts[:input] = Utils.build_nested_query(params)
118
127
  end
@@ -122,8 +131,7 @@ module Rack
122
131
  end
123
132
  end
124
133
 
125
- empty_str = ""
126
- empty_str.force_encoding("ASCII-8BIT") if empty_str.respond_to? :force_encoding
134
+ empty_str = String.new
127
135
  opts[:input] ||= empty_str
128
136
  if String === opts[:input]
129
137
  rack_input = StringIO.new(opts[:input])
@@ -131,10 +139,10 @@ module Rack
131
139
  rack_input = opts[:input]
132
140
  end
133
141
 
134
- rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
135
- env['rack.input'] = rack_input
142
+ rack_input.set_encoding(Encoding::BINARY)
143
+ env[RACK_INPUT] = rack_input
136
144
 
137
- env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s
145
+ env["CONTENT_LENGTH"] ||= env[RACK_INPUT].size.to_s if env[RACK_INPUT].respond_to?(:size)
138
146
 
139
147
  opts.each { |field, value|
140
148
  env[field] = value if String === field
@@ -142,28 +150,6 @@ module Rack
142
150
 
143
151
  env
144
152
  end
145
-
146
- if "<3".respond_to? :b
147
- def self.env_with_encoding(env, opts, uri)
148
- env[REQUEST_METHOD] = (opts[:method] ? opts[:method].to_s.upcase : "GET").b
149
- env["SERVER_NAME"] = (uri.host || "example.org").b
150
- env["SERVER_PORT"] = (uri.port ? uri.port.to_s : "80").b
151
- env[QUERY_STRING] = (uri.query.to_s).b
152
- env[PATH_INFO] = ((!uri.path || uri.path.empty?) ? "/" : uri.path).b
153
- env["rack.url_scheme"] = (uri.scheme || "http").b
154
- env["HTTPS"] = (env["rack.url_scheme"] == "https" ? "on" : "off").b
155
- end
156
- else
157
- def self.env_with_encoding(env, opts, uri)
158
- env[REQUEST_METHOD] = opts[:method] ? opts[:method].to_s.upcase : "GET"
159
- env["SERVER_NAME"] = uri.host || "example.org"
160
- env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80"
161
- env[QUERY_STRING] = uri.query.to_s
162
- env[PATH_INFO] = (!uri.path || uri.path.empty?) ? "/" : uri.path
163
- env["rack.url_scheme"] = uri.scheme || "http"
164
- env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off"
165
- end
166
- end
167
153
  end
168
154
 
169
155
  # Rack::MockResponse provides useful helpers for testing your apps.
@@ -172,17 +158,19 @@ module Rack
172
158
 
173
159
  class MockResponse < Rack::Response
174
160
  # Headers
175
- attr_reader :original_headers
161
+ attr_reader :original_headers, :cookies
176
162
 
177
163
  # Errors
178
164
  attr_accessor :errors
179
165
 
180
- def initialize(status, headers, body, errors=StringIO.new(""))
166
+ def initialize(status, headers, body, errors = StringIO.new(""))
181
167
  @original_headers = headers
182
168
  @errors = errors.string if errors.respond_to?(:string)
183
- @body_string = nil
169
+ @cookies = parse_cookies_from_header
184
170
 
185
171
  super(body, status, headers)
172
+
173
+ buffered_body!
186
174
  end
187
175
 
188
176
  def =~(other)
@@ -204,11 +192,64 @@ module Rack
204
192
  # ...
205
193
  # res.body.should == "foo!"
206
194
  # end
207
- super.join
195
+ buffer = String.new
196
+
197
+ super.each do |chunk|
198
+ buffer << chunk
199
+ end
200
+
201
+ return buffer
208
202
  end
209
203
 
210
204
  def empty?
211
- [201, 204, 205, 304].include? status
205
+ [201, 204, 304].include? status
206
+ end
207
+
208
+ def cookie(name)
209
+ cookies.fetch(name, nil)
212
210
  end
211
+
212
+ private
213
+
214
+ def parse_cookies_from_header
215
+ cookies = Hash.new
216
+ if original_headers.has_key? 'Set-Cookie'
217
+ set_cookie_header = original_headers.fetch('Set-Cookie')
218
+ set_cookie_header.split("\n").each do |cookie|
219
+ cookie_name, cookie_filling = cookie.split('=', 2)
220
+ cookie_attributes = identify_cookie_attributes cookie_filling
221
+ parsed_cookie = CGI::Cookie.new(
222
+ 'name' => cookie_name.strip,
223
+ 'value' => cookie_attributes.fetch('value'),
224
+ 'path' => cookie_attributes.fetch('path', nil),
225
+ 'domain' => cookie_attributes.fetch('domain', nil),
226
+ 'expires' => cookie_attributes.fetch('expires', nil),
227
+ 'secure' => cookie_attributes.fetch('secure', false)
228
+ )
229
+ cookies.store(cookie_name, parsed_cookie)
230
+ end
231
+ end
232
+ cookies
233
+ end
234
+
235
+ def identify_cookie_attributes(cookie_filling)
236
+ cookie_bits = cookie_filling.split(';')
237
+ cookie_attributes = Hash.new
238
+ cookie_attributes.store('value', cookie_bits[0].strip)
239
+ cookie_bits.each do |bit|
240
+ if bit.include? '='
241
+ cookie_attribute, attribute_value = bit.split('=')
242
+ cookie_attributes.store(cookie_attribute.strip, attribute_value.strip)
243
+ if cookie_attribute.include? 'max-age'
244
+ cookie_attributes.store('expires', Time.now + attribute_value.strip.to_i)
245
+ end
246
+ end
247
+ if bit.include? 'secure'
248
+ cookie_attributes.store('secure', true)
249
+ end
250
+ end
251
+ cookie_attributes
252
+ end
253
+
213
254
  end
214
255
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  module Multipart
3
5
  class Generator
@@ -11,37 +13,34 @@ module Rack
11
13
 
12
14
  def dump
13
15
  return nil if @first && !multipart?
14
- return flattened_params if !@first
16
+ return flattened_params unless @first
15
17
 
16
18
  flattened_params.map do |name, file|
17
19
  if file.respond_to?(:original_filename)
18
- ::File.open(file.path, "rb") do |f|
19
- f.set_encoding(Encoding::BINARY) if f.respond_to?(:set_encoding)
20
+ ::File.open(file.path, 'rb') do |f|
21
+ f.set_encoding(Encoding::BINARY)
20
22
  content_for_tempfile(f, file, name)
21
23
  end
22
24
  else
23
25
  content_for_other(file, name)
24
26
  end
25
- end.join + "--#{MULTIPART_BOUNDARY}--\r"
27
+ end.join << "--#{MULTIPART_BOUNDARY}--\r"
26
28
  end
27
29
 
28
30
  private
29
31
  def multipart?
30
- multipart = false
31
-
32
32
  query = lambda { |value|
33
33
  case value
34
34
  when Array
35
- value.each(&query)
35
+ value.any?(&query)
36
36
  when Hash
37
- value.values.each(&query)
37
+ value.values.any?(&query)
38
38
  when Rack::Multipart::UploadedFile
39
- multipart = true
39
+ true
40
40
  end
41
41
  }
42
- @params.values.each(&query)
43
42
 
44
- multipart
43
+ @params.values.any?(&query)
45
44
  end
46
45
 
47
46
  def flattened_params
@@ -90,4 +89,4 @@ EOF
90
89
  end
91
90
  end
92
91
  end
93
- end
92
+ end