rack-test 0.8.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 98d93b9da867444521efc5c2d82d14b37c2b5743324865f96d2f6c0603ad8256
4
- data.tar.gz: 3f78a90b58f6de6582088185f995195841995e9b2a0a9518a93ecee081eb8416
3
+ metadata.gz: f6f9d525a0e1136056dcc7ebfb288dd4a0f2d82b02bc7f6b4de8a8b1e1b2f653
4
+ data.tar.gz: 2503679c0681795e9db75ec5963eaea12f2f934b4e5e3d23a30396a318e2ad3c
5
5
  SHA512:
6
- metadata.gz: 3bd23e7ffcfa4ab19ad2966f36bcab31f49f3ea7f819fb81f15ce874437d8c6b96c6844f40499512042166b007d940b819b44e8d978ba4001f77fe515225f529
7
- data.tar.gz: 9d0479de503ae1a74f2aa9263b39dfdabf1745c17bed3fc18e6aaf757bf0b7428510f26a08c0021090ec98f8125eca74fb19e9f7f19eef41a94dd9847a441472
6
+ metadata.gz: 2b593ae59ec047f4048c96af421865855129563be719e9a0da088d275f20b3143300d83b4783aa073230bc8cc9118289562f83797682dd1a09073e0cbedc8fcb
7
+ data.tar.gz: 9f98f0e2d36fe2cf33193a279acca2c62bcf3e5c91bb8adc3a0a71d929ff92b24ab27e7bb826c70cecc52fda5c67c7af57a7d471ff7456c13421d6c719ace434
data/History.md CHANGED
@@ -1,3 +1,111 @@
1
+ ## 2.0.0 / 2022-06-24
2
+
3
+ * Breaking changes:
4
+ * Digest authentication support is now deprecated, as it relies on
5
+ digest authentication support in rack, which has been deprecated
6
+ (Jeremy Evans #294)
7
+ * `Rack::Test::Utils.build_primitive_part` no longer handles array
8
+ values (Jeremy Evans #292)
9
+ * `Rack::Test::Utils` module methods other than `build_nested_query`
10
+ and `build_multipart` are now private methods (Jeremy Evans #297)
11
+ * `Rack::MockSession` has been combined into `Rack::Test::Session`,
12
+ and remains as an alias to `Rack::Test::Session`, but to keep some
13
+ backwards compatibility, `Rack::Test::Session.new` will accept a
14
+ `Rack::Test::Session` instance and return it (Jeremy Evans #297)
15
+ * Previously protected methods in `Rack::Test::Cookie{,Jar}` are now
16
+ private methods (Jeremy Evans #297)
17
+ * `Rack::Test::Methods` no longer defines `build_rack_mock_session`,
18
+ but for backwards compatibility, `build_rack_test_session` will call
19
+ `build_rack_mock_session` if it is defined (Jeremy Evans #297)
20
+ * `Rack::Test::Methods::METHODS` is no longer defined
21
+ (Jeremy Evans #297)
22
+ * `Rack::Test::Methods#_current_session_names` has been removed
23
+ (Jeremy Evans #297)
24
+ * Headers used/accessed by rack-test are now lower case, for rack 3
25
+ compliance (Jeremy Evans #295)
26
+ * Frozen literal strings are now used internally, which may break
27
+ code that mutates static strings returned by rack-test, if any
28
+ (Jeremy Evans #304)
29
+
30
+ * Minor enhancements:
31
+ * rack-test now works with the rack main branch (what will be rack 3)
32
+ (Jeremy Evans #280 #292)
33
+ * rack-test only loads the parts of rack it uses when running on the
34
+ rack main branch (what will be rack 3) (Jeremy Evans #292)
35
+ * Development dependencies have been significantly reduced, and are
36
+ now a subset of the development dependencies of rack itself
37
+ (Jeremy Evans #292)
38
+ * Avoid creating multiple large copies of uploaded file data in
39
+ memory (Jeremy Evans #286)
40
+ * Specify HTTP/1.0 when submitting requests, to avoid responses with
41
+ Transfer-Encoding: chunked (Jeremy Evans #288)
42
+ * Support `:query_params` in rack environment for parameters that
43
+ are appended to the query string instead of used in the request
44
+ body (Jeremy Evans #150 #287)
45
+ * Reduce required ruby version to 2.0, since tests run fine on
46
+ Ruby 2.0 (Jeremy Evans #292)
47
+ * Support :multipart env key for request methods to force multipart
48
+ input (Jeremy Evans #303)
49
+ * Force multipart input for request methods if content type starts
50
+ with multipart (Jeremy Evans #303)
51
+ * Improve performance of Utils.build_multipart by using an
52
+ append-only design (Jeremy Evans #304)
53
+ * Improve performance of Utils.build_nested_query for array values
54
+ (Jeremy Evans #304)
55
+
56
+ * Bug fixes:
57
+ * The `CONTENT_TYPE` of multipart requests is now respected, if it
58
+ starts with `multipart/` (Tom Knig #238)
59
+ * Work correctly with responses that respond to `to_a` but not
60
+ `to_ary` (Sergio Faria #276)
61
+ * Raise an ArgumentError instead of a TypeError when providing a
62
+ StringIO without an original filename when creating an
63
+ UploadedFile (Nuno Correia #279)
64
+ * Allow combining both an UploadedFile and a plain string when
65
+ building a multipart upload (Mitsuhiro Shibuya #278)
66
+ * Fix the generation of filenames with spaces to use path
67
+ escaping instead of regular escaping, since path unescaping is
68
+ used to decode it (Muir Manders, Jeremy Evans #275 #284)
69
+ * Rewind tempfile used for multipart uploads before it is
70
+ submitted to the application
71
+ (Jeremy Evans, Alexander Dervish #261 #268 #286)
72
+ * Fix Rack::Test.encoding_aware_strings to be true only on rack
73
+ 1.6+ (Jeremy Evans #292)
74
+ * Make Rack::Test::CookieJar#valid? return true/false
75
+ (Jeremy Evans #292)
76
+ * Cookies without a domain attribute no longer are submitted to
77
+ requests for subdomains of that domain, for RFC 6265
78
+ compliance (Jeremy Evans #292)
79
+ * Increase required rack version to 1.3, since tests fail on
80
+ rack 1.2 and below (Jeremy Evans #293)
81
+
82
+ ## 1.1.0 / 2018-07-21
83
+
84
+ * Breaking changes:
85
+ * None
86
+
87
+ * Minor enhancements / new functionality:
88
+ * [GitHub] Added configuration for Stale (Per Lundberg #232)
89
+ * follow_direct: Include rack.session.options (Mark Edmondson #233)
90
+ * [CI] Add simplecov (fatkodima #227)
91
+
92
+ * Bug fixes:
93
+ * Follow relative locations correctly. (Samuel Williams #230)
94
+
95
+ ## 1.0.0 / 2018-03-27
96
+
97
+ * Breaking changes:
98
+ * Always set CONTENT_TYPE for non-GET requests
99
+ (Per Lundberg #223)
100
+
101
+ * Minor enhancements / bug fixes:
102
+ * Create tempfile using the basename without extension
103
+ (Edouard Chin #201)
104
+ * Save `session` during `follow_redirect!`
105
+ (Alexander Popov #218)
106
+ * Document how to use URL params with DELETE method
107
+ (Timur Platonov #220)
108
+
1
109
  ## 0.8.3 / 2018-02-27
2
110
 
3
111
  * Bug fixes:
data/MIT-LICENSE.txt CHANGED
@@ -1,4 +1,5 @@
1
1
  Copyright (c) 2008-2009 Bryan Helmkamp, Engine Yard Inc.
2
+ Copyright (c) 2022 Jeremy Evans
2
3
 
3
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
5
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,10 +1,7 @@
1
1
  # Rack::Test
2
2
  [![Gem Version](https://badge.fury.io/rb/rack-test.svg)](https://badge.fury.io/rb/rack-test)
3
- [<img src="https://travis-ci.org/rack-test/rack-test.svg?branch=master" />](https://travis-ci.org/rack-test/rack-test)
4
- [![Code Climate](https://codeclimate.com/github/codeclimate/codeclimate/badges/gpa.svg)](https://codeclimate.com/github/codeclimate/codeclimate)
5
- [![Test Coverage](https://codeclimate.com/github/codeclimate/codeclimate/badges/coverage.svg)](https://codeclimate.com/github/codeclimate/codeclimate/coverage)
6
3
 
7
- Code: https://github.com/rack-test/rack-test
4
+ Code: https://github.com/rack/rack-test
8
5
 
9
6
  ## Description
10
7
 
@@ -14,68 +11,66 @@ to build on.
14
11
 
15
12
  ## Features
16
13
 
14
+ * Allows for submitting requests and testing responses
17
15
  * Maintains a cookie jar across requests
18
- * Easily follow redirects when desired
19
- * Set request headers to be used by all subsequent requests
20
- * Small footprint. Approximately 200 LOC
21
-
22
- ## Supported platforms
23
-
24
- * 2.2.2+
25
- * 2.3
26
- * 2.4
27
- * JRuby 9.1.+
28
-
29
- If you are using Ruby 1.8, 1.9 or JRuby 1.7, use rack-test 0.6.3.
16
+ * Supports request headers used for subsequent requests
17
+ * Follow redirects when requested
30
18
 
31
19
  ## Examples
32
- (The examples use `Test::Unit` but it's equally possible to use `rack-test` with other testing frameworks like `rspec`.)
20
+
21
+ These examples use `test/unit` but it's equally possible to use `rack-test` with
22
+ other testing frameworks such as `minitest` or `rspec`.
33
23
 
34
24
  ```ruby
35
25
  require "test/unit"
36
26
  require "rack/test"
27
+ require "json"
37
28
 
38
29
  class HomepageTest < Test::Unit::TestCase
39
30
  include Rack::Test::Methods
40
31
 
41
32
  def app
42
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['All responses are OK']] }
43
- builder = Rack::Builder.new
44
- builder.run app
33
+ lambda { |env| [200, {'content-type' => 'text/plain'}, ['All responses are OK']] }
45
34
  end
46
35
 
47
36
  def test_response_is_ok
48
- get '/'
37
+ # Optionally set headers used for all requests in this spec:
38
+ #header 'accept-charset', 'utf-8'
49
39
 
50
- assert last_response.ok?
51
- assert_equal last_response.body, 'All responses are OK'
52
- end
53
-
54
- def set_request_headers
55
- header 'Accept-Charset', 'utf-8'
40
+ # First argument is treated as the path
56
41
  get '/'
57
42
 
58
43
  assert last_response.ok?
59
44
  assert_equal last_response.body, 'All responses are OK'
60
45
  end
61
46
 
62
- def test_response_is_ok_for_other_paths
63
- get '/other_paths'
64
-
65
- assert last_response.ok?
66
- assert_equal last_response.body, 'All responses are OK'
47
+ def delete_with_url_params_and_body
48
+ # First argument can have a query string
49
+ #
50
+ # Second argument is used as the parameters for the request, which will be
51
+ # included in the request body for non-GET requests.
52
+ delete '/?foo=bar', JSON.generate('baz' => 'zot')
67
53
  end
68
54
 
69
55
  def post_with_json
70
- # No assertion in this, we just demonstrate how you can post a JSON-encoded string.
71
- # By default, Rack::Test will use HTTP form encoding if you pass in a Hash as the
72
- # parameters, so make sure that `json` below is already a JSON-serialized string.
73
- post(uri, json, { 'CONTENT_TYPE' => 'application/json' })
56
+ # Third argument is the rack environment to use for the request. The following
57
+ # entries in the submitted rack environment are treated specially (in addition
58
+ # to options supported by `Rack::MockRequest#env_for`:
59
+ #
60
+ # :cookie : Set a cookie for the current session before submitting the request.
61
+ #
62
+ # :query_params : Set parameters for the query string (as opposed to the body).
63
+ # Value should be a hash of parameters.
64
+ #
65
+ # :xhr : Set HTTP_X_REQUESTED_WITH env key to XMLHttpRequest.
66
+ post(uri, JSON.generate('baz' => 'zot'), 'CONTENT_TYPE' => 'application/json')
74
67
  end
75
68
  end
76
69
  ```
77
70
 
78
- If you want to test one app in isolation, you just return that app as shown above. But if you want to test the entire app stack, including middlewares, cascades etc. you need to parse the app defined in config.ru.
71
+ `rack-test` will test the app returned by the `app` method. If you are loading middleware
72
+ in a `config.ru` file, and want to test that, you should load the Rack app created from
73
+ the `config.ru` file:
79
74
 
80
75
  ```ruby
81
76
  OUTER_APP = Rack::Builder.parse_file("config.ru").first
@@ -94,7 +89,6 @@ class TestApp < Test::Unit::TestCase
94
89
  end
95
90
  ```
96
91
 
97
-
98
92
  ## Install
99
93
 
100
94
  To install the latest release as a gem:
@@ -103,38 +97,43 @@ To install the latest release as a gem:
103
97
  gem install rack-test
104
98
  ```
105
99
 
106
- Or via Bundler:
100
+ Or add to your `Gemfile`:
107
101
 
108
102
  ```
109
- gem 'rack-test', require: 'rack/test'
103
+ gem 'rack-test'
110
104
  ```
111
105
 
112
- Or to install unreleased version via Bundler:
106
+ ## Contribution
107
+
108
+ Contributions are welcome. Please make sure to:
113
109
 
114
- ```
115
- gem 'rack-test', github: 'rack-test', branch: 'master'
116
- ```
110
+ * Use a regular forking workflow
111
+ * Write tests for the new or changed behaviour
112
+ * Provide an explanation/motivation in your commit message / PR message
113
+ * Ensure `History.md` is updated
117
114
 
118
115
  ## Authors
119
116
 
120
- - Contributions from Bryan Helmkamp, Simon Rozet, Pat Nakajima and others
117
+ - Contributions from Bryan Helmkamp, Jeremy Evans, Simon Rozet, and others
121
118
  - Much of the original code was extracted from Merb 1.0's request helper
122
119
 
123
120
  ## License
124
- `rack-test` is released under the [MIT License](MIT-LICENSE.txt).
125
121
 
126
- ## Contribution
122
+ `rack-test` is released under the [MIT License](MIT-LICENSE.txt).
127
123
 
128
- Contributions are welcome. Please make sure to:
124
+ ## Supported platforms
129
125
 
130
- * Use a regular forking workflow
131
- * Write tests for the new or changed behaviour
132
- * Provide an explanation/motivation in your commit message / PR message
133
- * Ensure History.txt is updated
126
+ * Ruby 2.0+
127
+ * JRuby 9.1+
134
128
 
135
129
  ## Releasing
136
130
 
137
- * Ensure `History.md` is up-to-date
138
131
  * Bump VERSION in lib/rack/test/version.rb
139
- * bundle exec thor :release
140
- * Updated the [GitHub releases page](https://github.com/rack-test/rack-test/releases)
132
+ * Ensure `History.md` is up-to-date, including correct version and date
133
+ * `git commit . -m 'Release $VERSION'`
134
+ * `git push`
135
+ * `git tag -a -m 'Tag the $VERSION release' $VERSION`
136
+ * `git push --tags`
137
+ * `gem build rack-test.gemspec`
138
+ * `gem push rack-test-$VERSION.gem`
139
+ * Add a discussion post for the release
@@ -1,63 +1,2 @@
1
- module Rack
2
- class MockSession # :nodoc:
3
- attr_writer :cookie_jar
4
- attr_reader :default_host
5
-
6
- def initialize(app, default_host = Rack::Test::DEFAULT_HOST)
7
- @app = app
8
- @after_request = []
9
- @default_host = default_host
10
- @last_request = nil
11
- @last_response = nil
12
- end
13
-
14
- def after_request(&block)
15
- @after_request << block
16
- end
17
-
18
- def clear_cookies
19
- @cookie_jar = Rack::Test::CookieJar.new([], @default_host)
20
- end
21
-
22
- def set_cookie(cookie, uri = nil)
23
- cookie_jar.merge(cookie, uri)
24
- end
25
-
26
- def request(uri, env)
27
- env['HTTP_COOKIE'] ||= cookie_jar.for(uri)
28
- @last_request = Rack::Request.new(env)
29
- status, headers, body = @app.call(@last_request.env)
30
-
31
- @last_response = MockResponse.new(status, headers, body, env['rack.errors'].flush)
32
- body.close if body.respond_to?(:close)
33
-
34
- cookie_jar.merge(last_response.headers['Set-Cookie'], uri)
35
-
36
- @after_request.each(&:call)
37
-
38
- if @last_response.respond_to?(:finish)
39
- @last_response.finish
40
- else
41
- @last_response
42
- end
43
- end
44
-
45
- # Return the last request issued in the session. Raises an error if no
46
- # requests have been sent yet.
47
- def last_request
48
- raise Rack::Test::Error, 'No request yet. Request a page first.' unless @last_request
49
- @last_request
50
- end
51
-
52
- # Return the last response received in the session. Raises an error if
53
- # no requests have been sent yet.
54
- def last_response
55
- raise Rack::Test::Error, 'No response yet. Request a page first.' unless @last_response
56
- @last_response
57
- end
58
-
59
- def cookie_jar
60
- @cookie_jar ||= Rack::Test::CookieJar.new([], @default_host)
61
- end
62
- end
63
- end
1
+ warn("requiring rack/mock_session is deprecated, require rack/test and use Rack::Test::Session", uplevel: 1)
2
+ require_relative 'test'
@@ -1,94 +1,114 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'uri'
2
4
  require 'time'
3
5
 
4
6
  module Rack
5
7
  module Test
8
+ # Represents individual cookies in the cookie jar. This is considered private
9
+ # API and behavior of this class can change at any time.
6
10
  class Cookie # :nodoc:
7
11
  include Rack::Utils
8
12
 
9
- # :api: private
10
- attr_reader :name, :value
13
+ # The name of the cookie, will be a string
14
+ attr_reader :name
15
+
16
+ # The value of the cookie, will be a string or nil if there is no value.
17
+ attr_reader :value
18
+
19
+ # The raw string for the cookie, without options. Will generally be in
20
+ # name=value format is name and value are provided.
21
+ attr_reader :raw
11
22
 
12
- # :api: private
13
23
  def initialize(raw, uri = nil, default_host = DEFAULT_HOST)
14
24
  @default_host = default_host
15
25
  uri ||= default_uri
16
26
 
17
27
  # separate the name / value pair from the cookie options
18
- @name_value_raw, options = raw.split(/[;,] */n, 2)
28
+ @raw, options = raw.split(/[;,] */n, 2)
19
29
 
20
- @name, @value = parse_query(@name_value_raw, ';').to_a.first
30
+ @name, @value = parse_query(@raw, ';').to_a.first
21
31
  @options = parse_query(options, ';')
22
32
 
23
- @options['domain'] ||= (uri.host || default_host)
24
- @options['path'] ||= uri.path.sub(/\/[^\/]*\Z/, '')
33
+ if @options['domain']
34
+ @exact_domain_match = false
35
+ else
36
+ # If the domain attribute is not present in the cookie,
37
+ # the domain must match exactly.
38
+ @exact_domain_match = true
39
+ @options['domain'] = (uri.host || default_host)
40
+ end
41
+
42
+ # Set the path for the cookie to the directory containing
43
+ # the request if it isn't set.
44
+ @options['path'] ||= uri.path.sub(/\/[^\/]*\Z/, '')
25
45
  end
26
46
 
47
+ # Wether the given cookie can replace the current cookie in the cookie jar.
27
48
  def replaces?(other)
28
49
  [name.downcase, domain, path] == [other.name.downcase, other.domain, other.path]
29
50
  end
30
51
 
31
- # :api: private
32
- def raw
33
- @name_value_raw
34
- end
35
-
36
- # :api: private
52
+ # Whether the cookie has a value.
37
53
  def empty?
38
54
  @value.nil? || @value.empty?
39
55
  end
40
56
 
41
- # :api: private
57
+ # The explicit or implicit domain for the cookie.
42
58
  def domain
43
59
  @options['domain']
44
60
  end
45
61
 
62
+ # Whether the cookie has the secure flag, indicating it can only be sent over
63
+ # an encrypted connection.
46
64
  def secure?
47
65
  @options.key?('secure')
48
66
  end
49
67
 
68
+ # Whether the cookie has the httponly flag, indicating it is not available via
69
+ # a javascript API.
50
70
  def http_only?
51
- @options.key?('HttpOnly')
71
+ @options.key?('HttpOnly') || @options.key?('httponly')
52
72
  end
53
73
 
54
- # :api: private
74
+ # The explicit or implicit path for the cookie.
55
75
  def path
56
76
  ([*@options['path']].first.split(',').first || '/').strip
57
77
  end
58
78
 
59
- # :api: private
79
+ # A Time value for when the cookie expires, if the expires option is set.
60
80
  def expires
61
81
  Time.parse(@options['expires']) if @options['expires']
62
82
  end
63
83
 
64
- # :api: private
84
+ # Whether the cookie is currently expired.
65
85
  def expired?
66
86
  expires && expires < Time.now
67
87
  end
68
88
 
69
- # :api: private
89
+ # Whether the cookie is valid for the given URI.
70
90
  def valid?(uri)
71
91
  uri ||= default_uri
72
92
 
73
93
  uri.host = @default_host if uri.host.nil?
74
94
 
75
95
  real_domain = domain =~ /^\./ ? domain[1..-1] : domain
76
- (!secure? || (secure? && uri.scheme == 'https')) &&
77
- uri.host =~ Regexp.new("#{Regexp.escape(real_domain)}$", Regexp::IGNORECASE) &&
78
- uri.path =~ Regexp.new("^#{Regexp.escape(path)}")
96
+ !!((!secure? || (secure? && uri.scheme == 'https')) &&
97
+ uri.host =~ Regexp.new("#{'^' if @exact_domain_match}#{Regexp.escape(real_domain)}$", Regexp::IGNORECASE) &&
98
+ uri.path =~ Regexp.new("^#{Regexp.escape(path)}"))
79
99
  end
80
100
 
81
- # :api: private
101
+ # Cookies that do not match the URI will not be sent in requests to the URI.
82
102
  def matches?(uri)
83
103
  !expired? && valid?(uri)
84
104
  end
85
105
 
86
- # :api: private
106
+ # Order cookies by name, path, and domain.
87
107
  def <=>(other)
88
- # Orders the cookies from least specific to most
89
108
  [name, path, domain.reverse] <=> [other.name, other.path, other.domain.reverse]
90
109
  end
91
110
 
111
+ # A hash of cookie options, including the cookie value, but excluding the cookie name.
92
112
  def to_h
93
113
  @options.merge(
94
114
  'value' => @value,
@@ -98,41 +118,62 @@ module Rack
98
118
  end
99
119
  alias to_hash to_h
100
120
 
101
- protected
121
+ private
102
122
 
123
+ # The default URI to use for the cookie, including just the host.
103
124
  def default_uri
104
125
  URI.parse('//' + @default_host + '/')
105
126
  end
106
127
  end
107
128
 
129
+ # Represents all cookies for a session, handling adding and
130
+ # removing cookies, and finding which cookies apply to a given
131
+ # request. This is considered private API and behavior of this
132
+ # class can change at any time.
108
133
  class CookieJar # :nodoc:
109
- # :api: private
134
+ DELIMITER = '; '.freeze
135
+
110
136
  def initialize(cookies = [], default_host = DEFAULT_HOST)
111
137
  @default_host = default_host
112
- @cookies = cookies
113
- @cookies.sort!
138
+ @cookies = cookies.sort!
114
139
  end
115
140
 
141
+ # Return the value for first cookie with the given name, or nil
142
+ # if no such cookie exists.
116
143
  def [](name)
117
- cookies = hash_for(nil)
118
- # TODO: Should be case insensitive
119
- cookies[name.to_s] && cookies[name.to_s].value
144
+ name = name.to_s
145
+ @cookies.each do |cookie|
146
+ return cookie.value if cookie.name == name
147
+ end
148
+ nil
120
149
  end
121
150
 
151
+ # Set a cookie with the given name and value in the
152
+ # cookie jar.
122
153
  def []=(name, value)
123
154
  merge("#{name}=#{Rack::Utils.escape(value)}")
124
155
  end
125
156
 
157
+ # Return the first cookie with the given name, or nil if
158
+ # no such cookie exists.
126
159
  def get_cookie(name)
127
- hash_for(nil).fetch(name, nil)
160
+ @cookies.each do |cookie|
161
+ return cookie if cookie.name == name
162
+ end
163
+ nil
128
164
  end
129
165
 
166
+ # Delete all cookies with the given name from the cookie jar.
130
167
  def delete(name)
131
168
  @cookies.reject! do |cookie|
132
169
  cookie.name == name
133
170
  end
171
+ nil
134
172
  end
135
173
 
174
+ # Add a string of raw cookie information to the cookie jar,
175
+ # if the cookie is valid for the given URI.
176
+ # Cookies should be separated with a newline.
136
177
  def merge(raw_cookies, uri = nil)
137
178
  return unless raw_cookies
138
179
 
@@ -147,6 +188,7 @@ module Rack
147
188
  end
148
189
  end
149
190
 
191
+ # Add a Cookie to the cookie jar.
150
192
  def <<(new_cookie)
151
193
  @cookies.reject! do |existing_cookie|
152
194
  new_cookie.replaces?(existing_cookie)
@@ -156,36 +198,48 @@ module Rack
156
198
  @cookies.sort!
157
199
  end
158
200
 
159
- # :api: private
201
+ # Return a raw cookie string for the cookie header to
202
+ # use for the given URI.
160
203
  def for(uri)
161
- hash_for(uri).values.map(&:raw).join(';')
204
+ buf = String.new
205
+ delimiter = nil
206
+
207
+ each_cookie_for(uri) do |cookie|
208
+ if delimiter
209
+ buf << delimiter
210
+ else
211
+ delimiter = DELIMITER
212
+ end
213
+ buf << cookie.raw
214
+ end
215
+
216
+ buf
162
217
  end
163
218
 
219
+ # Return a hash cookie names and cookie values for cookies in the jar.
164
220
  def to_hash
165
221
  cookies = {}
166
222
 
167
- hash_for(nil).each do |name, cookie|
168
- cookies[name] = cookie.value
223
+ @cookies.each do |cookie|
224
+ cookies[cookie.name] = cookie.value
169
225
  end
170
226
 
171
227
  cookies
172
228
  end
173
229
 
174
- protected
230
+ private
175
231
 
176
- def hash_for(uri = nil)
177
- cookies = {}
178
-
179
- # The cookies are sorted by most specific first. So, we loop through
180
- # all the cookies in order and add it to a hash by cookie name if
181
- # the cookie can be sent to the current URI. It's added to the hash
182
- # so that when we are done, the cookies will be unique by name and
183
- # we'll have grabbed the most specific to the URI.
232
+ # Yield each cookie that matches for the URI.
233
+ #
234
+ # The cookies are sorted by most specific first. So, we loop through
235
+ # all the cookies in order and add it to a hash by cookie name if
236
+ # the cookie can be sent to the current URI. It's added to the hash
237
+ # so that when we are done, the cookies will be unique by name and
238
+ # we'll have grabbed the most specific to the URI.
239
+ def each_cookie_for(uri)
184
240
  @cookies.each do |cookie|
185
- cookies[cookie.name] = cookie if !uri || cookie.matches?(uri)
241
+ yield cookie if !uri || cookie.matches?(uri)
186
242
  end
187
-
188
- cookies
189
243
  end
190
244
  end
191
245
  end