rack-test 0.6.3 → 0.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,16 +1,15 @@
1
- require "tempfile"
2
- require "fileutils"
1
+ require 'fileutils'
2
+ require 'pathname'
3
+ require 'tempfile'
3
4
 
4
5
  module Rack
5
6
  module Test
6
-
7
7
  # Wraps a Tempfile with a content type. Including one or more UploadedFile's
8
8
  # in the params causes Rack::Test to build and issue a multipart request.
9
9
  #
10
10
  # Example:
11
11
  # post "/photos", "file" => Rack::Test::UploadedFile.new("me.jpg", "image/jpeg")
12
12
  class UploadedFile
13
-
14
13
  # The filename, *not* including the path, of the "uploaded" file
15
14
  attr_reader :original_filename
16
15
 
@@ -20,34 +19,66 @@ module Rack
20
19
  # The content type of the "uploaded" file
21
20
  attr_accessor :content_type
22
21
 
23
- def initialize(path, content_type = "text/plain", binary = false)
24
- raise "#{path} file does not exist" unless ::File.exist?(path)
25
-
22
+ # Creates a new UploadedFile instance.
23
+ #
24
+ # @param content [IO, Pathname, String, StringIO] a path to a file, or an {IO} or {StringIO} object representing the
25
+ # file.
26
+ # @param content_type [String]
27
+ # @param binary [Boolean] an optional flag that indicates whether the file should be open in binary mode or not.
28
+ # @param original_filename [String] an optional parameter that provides the original filename if `content` is a StringIO
29
+ # object. Not used for other kind of `content` objects.
30
+ def initialize(content, content_type = 'text/plain', binary = false, original_filename: nil)
31
+ if original_filename
32
+ initialize_from_stringio(content, original_filename)
33
+ else
34
+ initialize_from_file_path(content)
35
+ end
26
36
  @content_type = content_type
27
- @original_filename = ::File.basename(path)
28
-
29
- @tempfile = Tempfile.new(@original_filename)
30
- @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
31
37
  @tempfile.binmode if binary
32
-
33
- FileUtils.copy_file(path, @tempfile.path)
34
38
  end
35
39
 
36
40
  def path
37
- @tempfile.path
41
+ tempfile.path
38
42
  end
39
43
 
40
- alias_method :local_path, :path
44
+ alias local_path path
41
45
 
42
46
  def method_missing(method_name, *args, &block) #:nodoc:
43
- @tempfile.__send__(method_name, *args, &block)
47
+ tempfile.public_send(method_name, *args, &block)
44
48
  end
45
49
 
46
- def respond_to?(method_name, include_private = false) #:nodoc:
47
- @tempfile.respond_to?(method_name, include_private) || super
50
+ def respond_to_missing?(method_name, include_private = false) #:nodoc:
51
+ tempfile.respond_to?(method_name, include_private) || super
48
52
  end
49
53
 
50
- end
54
+ def self.finalize(file)
55
+ proc { actually_finalize file }
56
+ end
57
+
58
+ def self.actually_finalize(file)
59
+ file.close
60
+ file.unlink
61
+ end
51
62
 
63
+ private
64
+
65
+ def initialize_from_stringio(stringio, original_filename)
66
+ @tempfile = stringio
67
+ @original_filename = original_filename || raise(ArgumentError, 'Missing `original_filename` for StringIO object')
68
+ end
69
+
70
+ def initialize_from_file_path(path)
71
+ raise "#{path} file does not exist" unless ::File.exist?(path)
72
+
73
+ @original_filename = ::File.basename(path)
74
+
75
+ @tempfile = Tempfile.new([@original_filename, ::File.extname(path)])
76
+ @tempfile.set_encoding(Encoding::BINARY) if @tempfile.respond_to?(:set_encoding)
77
+
78
+ ObjectSpace.define_finalizer(self, self.class.finalize(@tempfile))
79
+
80
+ FileUtils.copy_file(path, @tempfile.path)
81
+ end
82
+ end
52
83
  end
53
84
  end
@@ -1,38 +1,36 @@
1
1
  module Rack
2
2
  module Test
3
-
4
3
  module Utils # :nodoc:
5
4
  include Rack::Utils
5
+ extend Rack::Utils
6
6
 
7
7
  def build_nested_query(value, prefix = nil)
8
8
  case value
9
9
  when Array
10
- value.map do |v|
11
- unless unescape(prefix) =~ /\[\]$/
12
- prefix = "#{prefix}[]"
13
- end
14
- build_nested_query(v, "#{prefix}")
15
- end.join("&")
10
+ if value.empty?
11
+ "#{prefix}[]="
12
+ else
13
+ value.map do |v|
14
+ prefix = "#{prefix}[]" unless unescape(prefix) =~ /\[\]$/
15
+ build_nested_query(v, prefix.to_s)
16
+ end.join('&')
17
+ end
16
18
  when Hash
17
19
  value.map do |k, v|
18
20
  build_nested_query(v, prefix ? "#{prefix}[#{escape(k)}]" : escape(k))
19
- end.join("&")
21
+ end.join('&')
20
22
  when NilClass
21
23
  prefix.to_s
22
24
  else
23
25
  "#{prefix}=#{escape(value)}"
24
26
  end
25
27
  end
26
-
27
28
  module_function :build_nested_query
28
29
 
29
- def build_multipart(params, first = true)
30
+ def build_multipart(params, first = true, multipart = false)
30
31
  if first
31
- unless params.is_a?(Hash)
32
- raise ArgumentError, "value must be a Hash"
33
- end
32
+ raise ArgumentError, 'value must be a Hash' unless params.is_a?(Hash)
34
33
 
35
- multipart = false
36
34
  query = lambda { |value|
37
35
  case value
38
36
  when Array
@@ -47,7 +45,7 @@ module Rack
47
45
  return nil unless multipart
48
46
  end
49
47
 
50
- flattened_params = Hash.new
48
+ flattened_params = {}
51
49
 
52
50
  params.each do |key, value|
53
51
  k = first ? key.to_s : "[#{key}]"
@@ -55,23 +53,21 @@ module Rack
55
53
  case value
56
54
  when Array
57
55
  value.map do |v|
58
-
59
- if (v.is_a?(Hash))
56
+ if v.is_a?(Hash)
60
57
  nested_params = {}
61
- build_multipart(v, false).each { |subkey, subvalue|
58
+ build_multipart(v, false).each do |subkey, subvalue|
62
59
  nested_params[subkey] = subvalue
63
- }
60
+ end
64
61
  flattened_params["#{k}[]"] ||= []
65
62
  flattened_params["#{k}[]"] << nested_params
66
63
  else
67
64
  flattened_params["#{k}[]"] = value
68
65
  end
69
-
70
66
  end
71
67
  when Hash
72
- build_multipart(value, false).each { |subkey, subvalue|
68
+ build_multipart(value, false).each do |subkey, subvalue|
73
69
  flattened_params[k + subkey] = subvalue
74
- }
70
+ end
75
71
  else
76
72
  flattened_params[k] = value
77
73
  end
@@ -83,27 +79,28 @@ module Rack
83
79
  flattened_params
84
80
  end
85
81
  end
86
-
87
82
  module_function :build_multipart
88
83
 
89
- private
84
+ private
85
+
90
86
  def build_parts(parameters)
91
87
  get_parts(parameters).join + "--#{MULTIPART_BOUNDARY}--\r"
92
88
  end
89
+ module_function :build_parts
93
90
 
94
91
  def get_parts(parameters)
95
- parameters.map { |name, value|
96
- if name =~ /\[\]\Z/ && value.is_a?(Array) && value.all? {|v| v.is_a?(Hash)}
97
- value.map { |hash|
92
+ parameters.map do |name, value|
93
+ if name =~ /\[\]\Z/ && value.is_a?(Array) && value.all? { |v| v.is_a?(Hash) }
94
+ value.map do |hash|
98
95
  new_value = {}
99
- hash.each { |k, v| new_value[name+k] = v }
96
+ hash.each { |k, v| new_value[name + k] = v }
100
97
  get_parts(new_value).join
101
- }.join
98
+ end.join
102
99
  else
103
100
  if value.respond_to?(:original_filename)
104
101
  build_file_part(name, value)
105
102
 
106
- elsif value.is_a?(Array) and value.all? { |v| v.respond_to?(:original_filename) }
103
+ elsif value.is_a?(Array) && value.all? { |v| v.respond_to?(:original_filename) }
107
104
  value.map do |v|
108
105
  build_file_part(name, v)
109
106
  end.join
@@ -113,15 +110,14 @@ module Rack
113
110
  Rack::Test.encoding_aware_strings? ? primitive_part.force_encoding('BINARY') : primitive_part
114
111
  end
115
112
  end
116
- }
113
+ end
117
114
  end
115
+ module_function :get_parts
118
116
 
119
117
  def build_primitive_part(parameter_name, value)
120
- unless value.is_a? Array
121
- value = [value]
122
- end
118
+ value = [value] unless value.is_a? Array
123
119
  value.map do |v|
124
- <<-EOF
120
+ <<-EOF
125
121
  --#{MULTIPART_BOUNDARY}\r
126
122
  Content-Disposition: form-data; name="#{parameter_name}"\r
127
123
  \r
@@ -129,22 +125,20 @@ Content-Disposition: form-data; name="#{parameter_name}"\r
129
125
  EOF
130
126
  end.join
131
127
  end
128
+ module_function :build_primitive_part
132
129
 
133
130
  def build_file_part(parameter_name, uploaded_file)
134
- ::File.open(uploaded_file.path, "rb") do |physical_file|
135
- physical_file.set_encoding(Encoding::BINARY) if physical_file.respond_to?(:set_encoding)
136
- <<-EOF
131
+ uploaded_file.set_encoding(Encoding::BINARY) if uploaded_file.respond_to?(:set_encoding)
132
+ <<-EOF
137
133
  --#{MULTIPART_BOUNDARY}\r
138
134
  Content-Disposition: form-data; name="#{parameter_name}"; filename="#{escape(uploaded_file.original_filename)}"\r
139
135
  Content-Type: #{uploaded_file.content_type}\r
140
- Content-Length: #{::File.stat(uploaded_file.path).size}\r
136
+ Content-Length: #{uploaded_file.size}\r
141
137
  \r
142
- #{physical_file.read}\r
138
+ #{uploaded_file.read}\r
143
139
  EOF
144
- end
145
140
  end
146
-
141
+ module_function :build_file_part
147
142
  end
148
-
149
143
  end
150
144
  end
@@ -0,0 +1,5 @@
1
+ module Rack
2
+ module Test
3
+ VERSION = '0.8.3'.freeze
4
+ end
5
+ end
data/lib/rack/test.rb CHANGED
@@ -1,18 +1,17 @@
1
- require "uri"
2
- require "rack"
3
- require "rack/mock_session"
4
- require "rack/test/cookie_jar"
5
- require "rack/test/mock_digest_request"
6
- require "rack/test/utils"
7
- require "rack/test/methods"
8
- require "rack/test/uploaded_file"
1
+ require 'uri'
2
+ require 'rack'
3
+ require 'rack/mock_session'
4
+ require 'rack/test/cookie_jar'
5
+ require 'rack/test/mock_digest_request'
6
+ require 'rack/test/utils'
7
+ require 'rack/test/methods'
8
+ require 'rack/test/uploaded_file'
9
+ require 'rack/test/version'
9
10
 
10
11
  module Rack
11
12
  module Test
12
- VERSION = "0.6.3"
13
-
14
- DEFAULT_HOST = "example.org"
15
- MULTIPART_BOUNDARY = "----------XnJLe9ZIbbGUYtzPQJ16u1"
13
+ DEFAULT_HOST = 'example.org'.freeze
14
+ MULTIPART_BOUNDARY = '----------XnJLe9ZIbbGUYtzPQJ16u1'.freeze
16
15
 
17
16
  # The common base class for exceptions raised by Rack::Test
18
17
  class Error < StandardError; end
@@ -36,11 +35,13 @@ module Rack
36
35
  def initialize(mock_session)
37
36
  @headers = {}
38
37
  @env = {}
38
+ @digest_username = nil
39
+ @digest_password = nil
39
40
 
40
- if mock_session.is_a?(MockSession)
41
- @rack_mock_session = mock_session
41
+ @rack_mock_session = if mock_session.is_a?(MockSession)
42
+ mock_session
42
43
  else
43
- @rack_mock_session = MockSession.new(mock_session)
44
+ MockSession.new(mock_session)
44
45
  end
45
46
 
46
47
  @default_host = @rack_mock_session.default_host
@@ -54,8 +55,7 @@ module Rack
54
55
  # Example:
55
56
  # get "/"
56
57
  def get(uri, params = {}, env = {}, &block)
57
- env = env_for(uri, env.merge(:method => "GET", :params => params))
58
- process_request(uri, env, &block)
58
+ custom_request('GET', uri, params, env, &block)
59
59
  end
60
60
 
61
61
  # Issue a POST request for the given URI. See #get
@@ -63,8 +63,7 @@ module Rack
63
63
  # Example:
64
64
  # post "/signup", "name" => "Bryan"
65
65
  def post(uri, params = {}, env = {}, &block)
66
- env = env_for(uri, env.merge(:method => "POST", :params => params))
67
- process_request(uri, env, &block)
66
+ custom_request('POST', uri, params, env, &block)
68
67
  end
69
68
 
70
69
  # Issue a PUT request for the given URI. See #get
@@ -72,8 +71,7 @@ module Rack
72
71
  # Example:
73
72
  # put "/"
74
73
  def put(uri, params = {}, env = {}, &block)
75
- env = env_for(uri, env.merge(:method => "PUT", :params => params))
76
- process_request(uri, env, &block)
74
+ custom_request('PUT', uri, params, env, &block)
77
75
  end
78
76
 
79
77
  # Issue a PATCH request for the given URI. See #get
@@ -81,8 +79,7 @@ module Rack
81
79
  # Example:
82
80
  # patch "/"
83
81
  def patch(uri, params = {}, env = {}, &block)
84
- env = env_for(uri, env.merge(:method => "PATCH", :params => params))
85
- process_request(uri, env, &block)
82
+ custom_request('PATCH', uri, params, env, &block)
86
83
  end
87
84
 
88
85
  # Issue a DELETE request for the given URI. See #get
@@ -90,8 +87,7 @@ module Rack
90
87
  # Example:
91
88
  # delete "/"
92
89
  def delete(uri, params = {}, env = {}, &block)
93
- env = env_for(uri, env.merge(:method => "DELETE", :params => params))
94
- process_request(uri, env, &block)
90
+ custom_request('DELETE', uri, params, env, &block)
95
91
  end
96
92
 
97
93
  # Issue an OPTIONS request for the given URI. See #get
@@ -99,8 +95,7 @@ module Rack
99
95
  # Example:
100
96
  # options "/"
101
97
  def options(uri, params = {}, env = {}, &block)
102
- env = env_for(uri, env.merge(:method => "OPTIONS", :params => params))
103
- process_request(uri, env, &block)
98
+ custom_request('OPTIONS', uri, params, env, &block)
104
99
  end
105
100
 
106
101
  # Issue a HEAD request for the given URI. See #get
@@ -108,8 +103,7 @@ module Rack
108
103
  # Example:
109
104
  # head "/"
110
105
  def head(uri, params = {}, env = {}, &block)
111
- env = env_for(uri, env.merge(:method => "HEAD", :params => params))
112
- process_request(uri, env, &block)
106
+ custom_request('HEAD', uri, params, env, &block)
113
107
  end
114
108
 
115
109
  # Issue a request to the Rack app for the given URI and optional Rack
@@ -120,10 +114,21 @@ module Rack
120
114
  # Example:
121
115
  # request "/"
122
116
  def request(uri, env = {}, &block)
117
+ uri = parse_uri(uri, env)
123
118
  env = env_for(uri, env)
124
119
  process_request(uri, env, &block)
125
120
  end
126
121
 
122
+ # Issue a request using the given verb for the given URI. See #get
123
+ #
124
+ # Example:
125
+ # custom_request "LINK", "/"
126
+ def custom_request(verb, uri, params = {}, env = {}, &block)
127
+ uri = parse_uri(uri, env)
128
+ env = env_for(uri, env.merge(method: verb.to_s.upcase, params: params))
129
+ process_request(uri, env, &block)
130
+ end
131
+
127
132
  # Set a header to be included on all subsequent requests through the
128
133
  # session. Use a value of nil to remove a previously configured header.
129
134
  #
@@ -159,11 +164,11 @@ module Rack
159
164
  # Example:
160
165
  # basic_authorize "bryan", "secret"
161
166
  def basic_authorize(username, password)
162
- encoded_login = ["#{username}:#{password}"].pack("m*")
167
+ encoded_login = ["#{username}:#{password}"].pack('m0')
163
168
  header('Authorization', "Basic #{encoded_login}")
164
169
  end
165
170
 
166
- alias_method :authorize, :basic_authorize
171
+ alias authorize basic_authorize
167
172
 
168
173
  # Set the username and password for HTTP Digest authorization, to be
169
174
  # included in subsequent requests in the HTTP_AUTHORIZATION header.
@@ -181,73 +186,73 @@ module Rack
181
186
  # a redirect, an error will be raised.
182
187
  def follow_redirect!
183
188
  unless last_response.redirect?
184
- raise Error.new("Last response was not a redirect. Cannot follow_redirect!")
189
+ raise Error, 'Last response was not a redirect. Cannot follow_redirect!'
190
+ end
191
+ if last_response.status == 307
192
+ send(last_request.request_method.downcase.to_sym, last_response['Location'], last_request.params, 'HTTP_REFERER' => last_request.url)
193
+ else
194
+ get(last_response['Location'], {}, 'HTTP_REFERER' => last_request.url)
185
195
  end
186
-
187
- get(last_response["Location"], {}, { "HTTP_REFERER" => last_request.url })
188
196
  end
189
197
 
190
- private
198
+ private
191
199
 
192
- def env_for(path, env)
193
- uri = URI.parse(path)
194
- uri.path = "/#{uri.path}" unless uri.path[0] == ?/
195
- uri.host ||= @default_host
200
+ def parse_uri(path, env)
201
+ URI.parse(path).tap do |uri|
202
+ uri.path = "/#{uri.path}" unless uri.path[0] == '/'
203
+ uri.host ||= @default_host
204
+ uri.scheme ||= 'https' if env['HTTPS'] == 'on'
205
+ end
206
+ end
196
207
 
208
+ def env_for(uri, env)
197
209
  env = default_env.merge(env)
198
210
 
199
- env["HTTP_HOST"] ||= [uri.host, (uri.port if uri.port != uri.default_port)].compact.join(":")
211
+ env['HTTP_HOST'] ||= [uri.host, (uri.port if uri.port != uri.default_port)].compact.join(':')
200
212
 
201
- env.update("HTTPS" => "on") if URI::HTTPS === uri
202
- env["HTTP_X_REQUESTED_WITH"] = "XMLHttpRequest" if env[:xhr]
213
+ env.update('HTTPS' => 'on') if URI::HTTPS === uri
214
+ env['HTTP_X_REQUESTED_WITH'] = 'XMLHttpRequest' if env[:xhr]
203
215
 
204
216
  # TODO: Remove this after Rack 1.1 has been released.
205
217
  # Stringifying and upcasing methods has be commit upstream
206
- env["REQUEST_METHOD"] ||= env[:method] ? env[:method].to_s.upcase : "GET"
218
+ env['REQUEST_METHOD'] ||= env[:method] ? env[:method].to_s.upcase : 'GET'
219
+
220
+ params = env.delete(:params) do {} end
207
221
 
208
- if env["REQUEST_METHOD"] == "GET"
222
+ if env['REQUEST_METHOD'] == 'GET'
209
223
  # merge :params with the query string
210
- if params = env[:params]
224
+ if params
211
225
  params = parse_nested_query(params) if params.is_a?(String)
212
- params.update(parse_nested_query(uri.query))
213
- uri.query = build_nested_query(params)
226
+
227
+ uri.query = [uri.query, build_nested_query(params)].compact.reject { |v| v == '' }.join('&')
214
228
  end
215
- elsif !env.has_key?(:input)
216
- env["CONTENT_TYPE"] ||= "application/x-www-form-urlencoded"
229
+ elsif !env.key?(:input)
230
+ env['CONTENT_TYPE'] ||= 'application/x-www-form-urlencoded' unless params.nil?
217
231
 
218
- if env[:params].is_a?(Hash)
219
- if data = build_multipart(env[:params])
232
+ if params.is_a?(Hash)
233
+ if data = build_multipart(params)
220
234
  env[:input] = data
221
- env["CONTENT_LENGTH"] ||= data.length.to_s
222
- env["CONTENT_TYPE"] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}"
235
+ env['CONTENT_LENGTH'] ||= data.length.to_s
236
+ env['CONTENT_TYPE'] = "multipart/form-data; boundary=#{MULTIPART_BOUNDARY}"
223
237
  else
224
- env[:input] = params_to_string(env[:params])
238
+ env[:input] = params_to_string(params)
225
239
  end
226
240
  else
227
- env[:input] = env[:params]
241
+ env[:input] = params
228
242
  end
229
243
  end
230
244
 
231
- env.delete(:params)
232
-
233
- if env.has_key?(:cookie)
234
- set_cookie(env.delete(:cookie), uri)
235
- end
245
+ set_cookie(env.delete(:cookie), uri) if env.key?(:cookie)
236
246
 
237
247
  Rack::MockRequest.env_for(uri.to_s, env)
238
248
  end
239
249
 
240
250
  def process_request(uri, env)
241
- uri = URI.parse(uri)
242
- uri.host ||= @default_host
243
-
244
251
  @rack_mock_session.request(uri, env)
245
252
 
246
253
  if retry_with_digest_auth?(env)
247
- auth_env = env.merge({
248
- "HTTP_AUTHORIZATION" => digest_auth_header,
249
- "rack-test.digest_auth_retry" => true
250
- })
254
+ auth_env = env.merge('HTTP_AUTHORIZATION' => digest_auth_header,
255
+ 'rack-test.digest_auth_retry' => true)
251
256
  auth_env.delete('rack.request')
252
257
  process_request(uri.path, auth_env)
253
258
  else
@@ -258,26 +263,24 @@ module Rack
258
263
  end
259
264
 
260
265
  def digest_auth_header
261
- challenge = last_response["WWW-Authenticate"].split(" ", 2).last
266
+ challenge = last_response['WWW-Authenticate'].split(' ', 2).last
262
267
  params = Rack::Auth::Digest::Params.parse(challenge)
263
268
 
264
- params.merge!({
265
- "username" => @digest_username,
266
- "nc" => "00000001",
267
- "cnonce" => "nonsensenonce",
268
- "uri" => last_request.fullpath,
269
- "method" => last_request.env["REQUEST_METHOD"],
270
- })
269
+ params.merge!('username' => @digest_username,
270
+ 'nc' => '00000001',
271
+ 'cnonce' => 'nonsensenonce',
272
+ 'uri' => last_request.fullpath,
273
+ 'method' => last_request.env['REQUEST_METHOD'])
271
274
 
272
- params["response"] = MockDigestRequest.new(params).response(@digest_password)
275
+ params['response'] = MockDigestRequest.new(params).response(@digest_password)
273
276
 
274
277
  "Digest #{params}"
275
278
  end
276
279
 
277
280
  def retry_with_digest_auth?(env)
278
281
  last_response.status == 401 &&
279
- digest_auth_configured? &&
280
- !env["rack-test.digest_auth_retry"]
282
+ digest_auth_configured? &&
283
+ !env['rack-test.digest_auth_retry']
281
284
  end
282
285
 
283
286
  def digest_auth_configured?
@@ -285,15 +288,15 @@ module Rack
285
288
  end
286
289
 
287
290
  def default_env
288
- { "rack.test" => true, "REMOTE_ADDR" => "127.0.0.1" }.merge(@env).merge(headers_for_env)
291
+ { 'rack.test' => true, 'REMOTE_ADDR' => '127.0.0.1' }.merge(@env).merge(headers_for_env)
289
292
  end
290
293
 
291
294
  def headers_for_env
292
295
  converted_headers = {}
293
296
 
294
297
  @headers.each do |name, value|
295
- env_key = name.upcase.gsub("-", "_")
296
- env_key = "HTTP_" + env_key unless "CONTENT_TYPE" == env_key
298
+ env_key = name.upcase.tr('-', '_')
299
+ env_key = 'HTTP_' + env_key unless env_key == 'CONTENT_TYPE'
297
300
  converted_headers[env_key] = value
298
301
  end
299
302
 
@@ -303,16 +306,14 @@ module Rack
303
306
  def params_to_string(params)
304
307
  case params
305
308
  when Hash then build_nested_query(params)
306
- when nil then ""
309
+ when nil then ''
307
310
  else params
308
311
  end
309
312
  end
310
-
311
313
  end
312
314
 
313
315
  def self.encoding_aware_strings?
314
- defined?(Encoding) && "".respond_to?(:encode)
316
+ defined?(Encoding) && ''.respond_to?(:encode)
315
317
  end
316
-
317
318
  end
318
319
  end