sinatra-contrib 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.md +135 -0
- data/Rakefile +75 -0
- data/ideas.md +29 -0
- data/lib/sinatra/capture.rb +42 -0
- data/lib/sinatra/config_file.rb +151 -0
- data/lib/sinatra/content_for.rb +111 -0
- data/lib/sinatra/contrib.rb +39 -0
- data/lib/sinatra/contrib/all.rb +2 -0
- data/lib/sinatra/contrib/setup.rb +53 -0
- data/lib/sinatra/contrib/version.rb +45 -0
- data/lib/sinatra/cookies.rb +331 -0
- data/lib/sinatra/decompile.rb +113 -0
- data/lib/sinatra/engine_tracking.rb +96 -0
- data/lib/sinatra/extension.rb +95 -0
- data/lib/sinatra/json.rb +134 -0
- data/lib/sinatra/link_header.rb +132 -0
- data/lib/sinatra/multi_route.rb +81 -0
- data/lib/sinatra/namespace.rb +282 -0
- data/lib/sinatra/reloader.rb +384 -0
- data/lib/sinatra/respond_with.rb +245 -0
- data/lib/sinatra/streaming.rb +267 -0
- data/lib/sinatra/test_helpers.rb +87 -0
- data/sinatra-contrib.gemspec +125 -0
- data/spec/capture_spec.rb +80 -0
- data/spec/config_file/key_value.yml +6 -0
- data/spec/config_file/missing_env.yml +4 -0
- data/spec/config_file/with_envs.yml +7 -0
- data/spec/config_file/with_nested_envs.yml +11 -0
- data/spec/config_file_spec.rb +44 -0
- data/spec/content_for/different_key.erb +1 -0
- data/spec/content_for/different_key.erubis +1 -0
- data/spec/content_for/different_key.haml +2 -0
- data/spec/content_for/different_key.slim +2 -0
- data/spec/content_for/layout.erb +1 -0
- data/spec/content_for/layout.erubis +1 -0
- data/spec/content_for/layout.haml +1 -0
- data/spec/content_for/layout.slim +1 -0
- data/spec/content_for/multiple_blocks.erb +4 -0
- data/spec/content_for/multiple_blocks.erubis +4 -0
- data/spec/content_for/multiple_blocks.haml +8 -0
- data/spec/content_for/multiple_blocks.slim +8 -0
- data/spec/content_for/multiple_yields.erb +3 -0
- data/spec/content_for/multiple_yields.erubis +3 -0
- data/spec/content_for/multiple_yields.haml +3 -0
- data/spec/content_for/multiple_yields.slim +3 -0
- data/spec/content_for/passes_values.erb +1 -0
- data/spec/content_for/passes_values.erubis +1 -0
- data/spec/content_for/passes_values.haml +1 -0
- data/spec/content_for/passes_values.slim +1 -0
- data/spec/content_for/same_key.erb +1 -0
- data/spec/content_for/same_key.erubis +1 -0
- data/spec/content_for/same_key.haml +2 -0
- data/spec/content_for/same_key.slim +2 -0
- data/spec/content_for/takes_values.erb +1 -0
- data/spec/content_for/takes_values.erubis +1 -0
- data/spec/content_for/takes_values.haml +3 -0
- data/spec/content_for/takes_values.slim +3 -0
- data/spec/content_for_spec.rb +201 -0
- data/spec/cookies_spec.rb +782 -0
- data/spec/decompile_spec.rb +44 -0
- data/spec/extension_spec.rb +33 -0
- data/spec/json_spec.rb +115 -0
- data/spec/link_header_spec.rb +100 -0
- data/spec/multi_route_spec.rb +45 -0
- data/spec/namespace/foo.erb +1 -0
- data/spec/namespace/nested/foo.erb +1 -0
- data/spec/namespace_spec.rb +623 -0
- data/spec/okjson.rb +581 -0
- data/spec/reloader/app.rb.erb +40 -0
- data/spec/reloader_spec.rb +441 -0
- data/spec/respond_with/bar.erb +1 -0
- data/spec/respond_with/bar.json.erb +1 -0
- data/spec/respond_with/foo.html.erb +1 -0
- data/spec/respond_with/not_html.sass +2 -0
- data/spec/respond_with_spec.rb +289 -0
- data/spec/spec_helper.rb +6 -0
- data/spec/streaming_spec.rb +436 -0
- metadata +256 -0
@@ -0,0 +1,111 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/capture'
|
3
|
+
|
4
|
+
module Sinatra
|
5
|
+
|
6
|
+
# = Sinatra::ContentFor
|
7
|
+
#
|
8
|
+
# <tt>Sinatra::ContentFor</tt> is a set of helpers that allows you to capture
|
9
|
+
# blocks inside views to be rendered later during the request. The most
|
10
|
+
# common use is to populate different parts of your layout from your view.
|
11
|
+
#
|
12
|
+
# The currently supported engines are: Erb, Erubis, Haml and Slim.
|
13
|
+
#
|
14
|
+
# == Usage
|
15
|
+
#
|
16
|
+
# You call +content_for+, generally from a view, to capture a block of markup
|
17
|
+
# giving it an identifier:
|
18
|
+
#
|
19
|
+
# # index.erb
|
20
|
+
# <% content_for :some_key do %>
|
21
|
+
# <chunk of="html">...</chunk>
|
22
|
+
# <% end %>
|
23
|
+
#
|
24
|
+
# Then, you call +yield_content+ with that identifier, generally from a
|
25
|
+
# layout, to render the captured block:
|
26
|
+
#
|
27
|
+
# # layout.erb
|
28
|
+
# <%= yield_content :some_key %>
|
29
|
+
#
|
30
|
+
# === Classic Application
|
31
|
+
#
|
32
|
+
# To use the helpers in a classic application all you need to do is require
|
33
|
+
# them:
|
34
|
+
#
|
35
|
+
# require "sinatra"
|
36
|
+
# require "sinatra/content_for"
|
37
|
+
#
|
38
|
+
# # Your classic application code goes here...
|
39
|
+
#
|
40
|
+
# === Modular Application
|
41
|
+
#
|
42
|
+
# To use the helpers in a modular application you need to require them, and
|
43
|
+
# then, tell the application you will use them:
|
44
|
+
#
|
45
|
+
# require "sinatra/base"
|
46
|
+
# require "sinatra/content_for"
|
47
|
+
#
|
48
|
+
# class MyApp < Sinatra::Base
|
49
|
+
# register Sinatra::ContentFor
|
50
|
+
#
|
51
|
+
# # The rest of your modular application code goes here...
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# == And How Is This Useful?
|
55
|
+
#
|
56
|
+
# For example, some of your views might need a few javascript tags and
|
57
|
+
# stylesheets, but you don't want to force this files in all your pages.
|
58
|
+
# Then you can put <tt><% yield_content :scripts_and_styles %></tt> on your
|
59
|
+
# layout, inside the <head> tag, and each view can call <tt>content_for</tt>
|
60
|
+
# setting the appropriate set of tags that should be added to the layout.
|
61
|
+
#
|
62
|
+
module ContentFor
|
63
|
+
include Capture
|
64
|
+
|
65
|
+
# Capture a block of content to be rendered later. For example:
|
66
|
+
#
|
67
|
+
# <% content_for :head do %>
|
68
|
+
# <script type="text/javascript" src="/foo.js"></script>
|
69
|
+
# <% end %>
|
70
|
+
#
|
71
|
+
# You can call +content_for+ multiple times with the same key
|
72
|
+
# (in the example +:head+), and when you render the blocks for
|
73
|
+
# that key all of them will be rendered, in the same order you
|
74
|
+
# captured them.
|
75
|
+
#
|
76
|
+
# Your blocks can also receive values, which are passed to them
|
77
|
+
# by <tt>yield_content</tt>
|
78
|
+
def content_for(key, &block)
|
79
|
+
content_blocks[key.to_sym] << capture_later(&block)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Render the captured blocks for a given key. For example:
|
83
|
+
#
|
84
|
+
# <head>
|
85
|
+
# <title>Example</title>
|
86
|
+
# <%= yield_content :head %>
|
87
|
+
# </head>
|
88
|
+
#
|
89
|
+
# Would render everything you declared with <tt>content_for
|
90
|
+
# :head</tt> before closing the <tt><head></tt> tag.
|
91
|
+
#
|
92
|
+
# You can also pass values to the content blocks by passing them
|
93
|
+
# as arguments after the key:
|
94
|
+
#
|
95
|
+
# <%= yield_content :head, 1, 2 %>
|
96
|
+
#
|
97
|
+
# Would pass <tt>1</tt> and <tt>2</tt> to all the blocks registered
|
98
|
+
# for <tt>:head</tt>.
|
99
|
+
def yield_content(key, *args)
|
100
|
+
content_blocks[key.to_sym].map { |b| capture(*args, &b) }.join
|
101
|
+
end
|
102
|
+
|
103
|
+
private
|
104
|
+
|
105
|
+
def content_blocks
|
106
|
+
@content_blocks ||= Hash.new {|h,k| h[k] = [] }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
helpers ContentFor
|
111
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'sinatra/contrib/setup'
|
2
|
+
|
3
|
+
module Sinatra
|
4
|
+
module Contrib
|
5
|
+
##
|
6
|
+
# Common middleware that doesn't bring run time overhead if not used
|
7
|
+
# or breaks if external dependencies are missing. Will extend
|
8
|
+
# Sinatra::Application by default.
|
9
|
+
module Common
|
10
|
+
register :ConfigFile
|
11
|
+
register :MultiRoute
|
12
|
+
register :Namespace
|
13
|
+
register :RespondWith
|
14
|
+
|
15
|
+
helpers :Capture
|
16
|
+
helpers :ContentFor
|
17
|
+
helpers :Cookies
|
18
|
+
helpers :EngineTracking
|
19
|
+
helpers :JSON
|
20
|
+
helpers :LinkHeader
|
21
|
+
helpers :Streaming
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Other extensions you don't want to be loaded unless needed.
|
26
|
+
module Custom
|
27
|
+
# register :Compass
|
28
|
+
register :Decompile
|
29
|
+
register :Reloader
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Stuff that aren't Sinatra extensions, technically.
|
34
|
+
autoload :Extension
|
35
|
+
autoload :TestHelpers
|
36
|
+
end
|
37
|
+
|
38
|
+
register Sinatra::Contrib::Common
|
39
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'sinatra/contrib/version'
|
3
|
+
require 'backports'
|
4
|
+
|
5
|
+
module Sinatra
|
6
|
+
module Contrib
|
7
|
+
module Loader
|
8
|
+
def extensions
|
9
|
+
@extensions ||= {:helpers => [], :register => []}
|
10
|
+
end
|
11
|
+
|
12
|
+
def register(name, path = nil)
|
13
|
+
autoload name, path, :register
|
14
|
+
end
|
15
|
+
|
16
|
+
def helpers(name, path = nil)
|
17
|
+
autoload name, path, :helpers
|
18
|
+
end
|
19
|
+
|
20
|
+
def autoload(name, path = nil, method = nil)
|
21
|
+
path ||= "sinatra/#{name.to_s.underscore}"
|
22
|
+
extensions[method] << name if method
|
23
|
+
Sinatra.autoload(name, path)
|
24
|
+
end
|
25
|
+
|
26
|
+
def registered(base)
|
27
|
+
@extensions.each do |meth, list|
|
28
|
+
list = list.map { |name| Sinatra.const_get name }
|
29
|
+
base.send(meth, *list) unless base == ::Sinatra::Application
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module Common
|
35
|
+
extend Loader
|
36
|
+
end
|
37
|
+
|
38
|
+
module Custom
|
39
|
+
extend Loader
|
40
|
+
end
|
41
|
+
|
42
|
+
module All
|
43
|
+
def self.registered(base)
|
44
|
+
base.register Common, Custom
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
extend Loader
|
49
|
+
def self.registered(base)
|
50
|
+
base.register Common, Custom
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Sinatra
|
2
|
+
module Contrib
|
3
|
+
def self.version
|
4
|
+
VERSION
|
5
|
+
end
|
6
|
+
|
7
|
+
module VERSION
|
8
|
+
extend Comparable
|
9
|
+
|
10
|
+
MAJOR = 1
|
11
|
+
MINOR = 3
|
12
|
+
TINY = 0
|
13
|
+
SIGNATURE = [MAJOR, MINOR, TINY]
|
14
|
+
STRING = SIGNATURE.join '.'
|
15
|
+
|
16
|
+
def self.major; MAJOR end
|
17
|
+
def self.minor; MINOR end
|
18
|
+
def self.tiny; TINY end
|
19
|
+
def self.to_s; STRING end
|
20
|
+
|
21
|
+
def self.hash
|
22
|
+
STRING.hash
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.<=>(other)
|
26
|
+
other = other.split('.').map { |i| i.to_i } if other.respond_to? :split
|
27
|
+
SIGNATURE <=> Array(other)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.inspect
|
31
|
+
STRING.inspect
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.respond_to?(meth, *)
|
35
|
+
return true if super
|
36
|
+
meth.to_s !~ /^__|^to_str$/ and STRING.respond_to? meth
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.method_missing(meth, *args, &block)
|
40
|
+
return super unless STRING.respond_to?(meth)
|
41
|
+
STRING.send(meth, *args, &block)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,331 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'backports'
|
3
|
+
|
4
|
+
module Sinatra
|
5
|
+
# = Sinatra::Cookies
|
6
|
+
#
|
7
|
+
# Easy way to deal with cookies
|
8
|
+
#
|
9
|
+
# == Usage
|
10
|
+
#
|
11
|
+
# Allows you to read cookies:
|
12
|
+
#
|
13
|
+
# get '/' do
|
14
|
+
# "value: #{cookie[:something]}"
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# And of course to write cookies:
|
18
|
+
#
|
19
|
+
# get '/set' do
|
20
|
+
# cookies[:something] = 'foobar'
|
21
|
+
# redirect to('/')
|
22
|
+
# end
|
23
|
+
#
|
24
|
+
# And generally behaves like a hash:
|
25
|
+
#
|
26
|
+
# get '/demo' do
|
27
|
+
# cookies.merge! 'foo' => 'bar', 'bar' => 'baz'
|
28
|
+
# cookies.keep_if { |key, value| key.start_with? 'b' }
|
29
|
+
# foo, bar = cookies.values_at 'foo', 'bar'
|
30
|
+
# "size: #{cookies.length}"
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# === Classic Application
|
34
|
+
#
|
35
|
+
# In a classic application simply require the helpers, and start using them:
|
36
|
+
#
|
37
|
+
# require "sinatra"
|
38
|
+
# require "sinatra/cookies"
|
39
|
+
#
|
40
|
+
# # The rest of your classic application code goes here...
|
41
|
+
#
|
42
|
+
# === Modular Application
|
43
|
+
#
|
44
|
+
# In a modular application you need to require the helpers, and then tell
|
45
|
+
# the application you will use them:
|
46
|
+
#
|
47
|
+
# require "sinatra/base"
|
48
|
+
# require "sinatra/link_header"
|
49
|
+
#
|
50
|
+
# class MyApp < Sinatra::Base
|
51
|
+
# helpers Sinatra::Cookies
|
52
|
+
#
|
53
|
+
# # The rest of your modular application code goes here...
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
module Cookies
|
57
|
+
class Jar
|
58
|
+
include Enumerable
|
59
|
+
attr_reader :options
|
60
|
+
|
61
|
+
def initialize(app)
|
62
|
+
@response_string = nil
|
63
|
+
@response_hash = {}
|
64
|
+
@response = app.response
|
65
|
+
@request = app.request
|
66
|
+
@deleted = []
|
67
|
+
|
68
|
+
@options = {
|
69
|
+
:path => @request.script_name,
|
70
|
+
:domain => @request.host,
|
71
|
+
:secure => @request.secure?,
|
72
|
+
:httponly => true
|
73
|
+
}
|
74
|
+
|
75
|
+
@options[:path] = '/' if @options[:path].to_s.empty?
|
76
|
+
|
77
|
+
if app.settings.respond_to? :cookie_options
|
78
|
+
@options.merge! app.settings.cookie_options
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def ==(other)
|
83
|
+
other.respond_to? :to_hash and to_hash == other.to_hash
|
84
|
+
end
|
85
|
+
|
86
|
+
def [](key)
|
87
|
+
response_cookies[key.to_s] || request_cookies[key.to_s]
|
88
|
+
end
|
89
|
+
|
90
|
+
def []=(key, value)
|
91
|
+
@response.set_cookie key.to_s, @options.merge(:value => value)
|
92
|
+
end
|
93
|
+
|
94
|
+
def assoc(key)
|
95
|
+
to_hash.assoc(key.to_s)
|
96
|
+
end if Hash.method_defined? :assoc
|
97
|
+
|
98
|
+
def clear
|
99
|
+
each_key { |k| delete(k) }
|
100
|
+
end
|
101
|
+
|
102
|
+
def compare_by_identity?
|
103
|
+
false
|
104
|
+
end
|
105
|
+
|
106
|
+
def default
|
107
|
+
nil
|
108
|
+
end
|
109
|
+
|
110
|
+
alias default_proc default
|
111
|
+
|
112
|
+
def delete(key)
|
113
|
+
result = self[key]
|
114
|
+
@response.delete_cookie(key.to_s)
|
115
|
+
result
|
116
|
+
end
|
117
|
+
|
118
|
+
def delete_if
|
119
|
+
return enum_for(__method__) unless block_given?
|
120
|
+
each { |k, v| delete(k) if yield(k, v) }
|
121
|
+
self
|
122
|
+
end
|
123
|
+
|
124
|
+
def each(&block)
|
125
|
+
return enum_for(__method__) unless block_given?
|
126
|
+
to_hash.each(&block)
|
127
|
+
end
|
128
|
+
|
129
|
+
def each_key(&block)
|
130
|
+
return enum_for(__method__) unless block_given?
|
131
|
+
to_hash.each_key(&block)
|
132
|
+
end
|
133
|
+
|
134
|
+
alias each_pair each
|
135
|
+
|
136
|
+
def each_value(&block)
|
137
|
+
return enum_for(__method__) unless block_given?
|
138
|
+
to_hash.each_value(&block)
|
139
|
+
end
|
140
|
+
|
141
|
+
def empty?
|
142
|
+
to_hash.empty?
|
143
|
+
end
|
144
|
+
|
145
|
+
def fetch(key, &block)
|
146
|
+
response_cookies.fetch(key.to_s) do
|
147
|
+
request_cookies.fetch(key.to_s, &block)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def flatten
|
152
|
+
to_hash.flatten
|
153
|
+
end if Hash.method_defined? :flatten
|
154
|
+
|
155
|
+
def has_key?(key)
|
156
|
+
response_cookies.has_key? key.to_s or request_cookies.has_key? key.to_s
|
157
|
+
end
|
158
|
+
|
159
|
+
def has_value?(value)
|
160
|
+
response_cookies.has_value? value or request_cookies.has_value? value
|
161
|
+
end
|
162
|
+
|
163
|
+
def hash
|
164
|
+
to_hash.hash
|
165
|
+
end
|
166
|
+
|
167
|
+
alias include? has_key?
|
168
|
+
alias member? has_key?
|
169
|
+
|
170
|
+
def index(value)
|
171
|
+
warn "Hash#index is deprecated; use Hash#key" if RUBY_VERSION > '1.9'
|
172
|
+
key(value)
|
173
|
+
end
|
174
|
+
|
175
|
+
def inspect
|
176
|
+
"<##{self.class}: #{to_hash.inspect[1..-2]}>"
|
177
|
+
end
|
178
|
+
|
179
|
+
def invert
|
180
|
+
to_hash.invert
|
181
|
+
end if Hash.method_defined? :invert
|
182
|
+
|
183
|
+
def keep_if
|
184
|
+
return enum_for(__method__) unless block_given?
|
185
|
+
delete_if { |*a| not yield(*a) }
|
186
|
+
end
|
187
|
+
|
188
|
+
def key(value)
|
189
|
+
to_hash.key(value)
|
190
|
+
end
|
191
|
+
|
192
|
+
alias key? has_key?
|
193
|
+
|
194
|
+
def keys
|
195
|
+
to_hash.keys
|
196
|
+
end
|
197
|
+
|
198
|
+
def length
|
199
|
+
to_hash.length
|
200
|
+
end
|
201
|
+
|
202
|
+
def merge(other, &block)
|
203
|
+
to_hash.merge(other, &block)
|
204
|
+
end
|
205
|
+
|
206
|
+
def merge!(other)
|
207
|
+
other.each_pair do |key, value|
|
208
|
+
if block_given? and include? key
|
209
|
+
self[key] = yield(key.to_s, self[key], value)
|
210
|
+
else
|
211
|
+
self[key] = value
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def rassoc(value)
|
217
|
+
to_hash.rassoc(value)
|
218
|
+
end
|
219
|
+
|
220
|
+
def rehash
|
221
|
+
response_cookies.rehash
|
222
|
+
request_cookies.rehash
|
223
|
+
self
|
224
|
+
end
|
225
|
+
|
226
|
+
def reject(&block)
|
227
|
+
return enum_for(__method__) unless block_given?
|
228
|
+
to_hash.reject(&block)
|
229
|
+
end
|
230
|
+
|
231
|
+
alias reject! delete_if
|
232
|
+
|
233
|
+
def replace(other)
|
234
|
+
select! { |k, v| other.include?(k) or other.include?(k.to_s) }
|
235
|
+
merge! other
|
236
|
+
end
|
237
|
+
|
238
|
+
def select(&block)
|
239
|
+
return enum_for(__method__) unless block_given?
|
240
|
+
to_hash.select(&block)
|
241
|
+
end
|
242
|
+
|
243
|
+
alias select! keep_if if Hash.method_defined? :select!
|
244
|
+
|
245
|
+
def shift
|
246
|
+
key, value = to_hash.shift
|
247
|
+
delete(key)
|
248
|
+
[key, value]
|
249
|
+
end
|
250
|
+
|
251
|
+
alias size length
|
252
|
+
|
253
|
+
def sort(&block)
|
254
|
+
to_hash.sort(&block)
|
255
|
+
end if Hash.method_defined? :sort
|
256
|
+
|
257
|
+
alias store []=
|
258
|
+
|
259
|
+
def to_hash
|
260
|
+
request_cookies.merge(response_cookies)
|
261
|
+
end
|
262
|
+
|
263
|
+
def to_a
|
264
|
+
to_hash.to_a
|
265
|
+
end
|
266
|
+
|
267
|
+
def to_s
|
268
|
+
to_hash.to_s
|
269
|
+
end
|
270
|
+
|
271
|
+
alias update merge!
|
272
|
+
alias value? has_value?
|
273
|
+
|
274
|
+
def values
|
275
|
+
to_hash.values
|
276
|
+
end
|
277
|
+
|
278
|
+
def values_at(*list)
|
279
|
+
list.map { |k| self[k] }
|
280
|
+
end
|
281
|
+
|
282
|
+
private
|
283
|
+
|
284
|
+
def warn(message)
|
285
|
+
super "#{caller.first[/^[^:]:\d+:/]} warning: #{message}"
|
286
|
+
end
|
287
|
+
|
288
|
+
def deleted
|
289
|
+
parse_response
|
290
|
+
@deleted
|
291
|
+
end
|
292
|
+
|
293
|
+
def response_cookies
|
294
|
+
parse_response
|
295
|
+
@response_hash
|
296
|
+
end
|
297
|
+
|
298
|
+
def parse_response
|
299
|
+
string = @response['Set-Cookie']
|
300
|
+
return if @response_string == string
|
301
|
+
|
302
|
+
hash = {}
|
303
|
+
|
304
|
+
string.each_line do |line|
|
305
|
+
key, value = line.split(';', 2).first.to_s.split('=', 2)
|
306
|
+
next if key.nil?
|
307
|
+
key = Rack::Utils.unescape(key)
|
308
|
+
if line.include? "expires=Thu, 01-Jan-1970 00:00:00 GMT"
|
309
|
+
@deleted << key
|
310
|
+
else
|
311
|
+
@deleted.delete key
|
312
|
+
hash[key] = value
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
@response_hash.replace hash
|
317
|
+
@response_string = string
|
318
|
+
end
|
319
|
+
|
320
|
+
def request_cookies
|
321
|
+
@request.cookies.reject { |key, value| deleted.include? key }
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
def cookies
|
326
|
+
@cookies ||= Jar.new(self)
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
helpers Cookies
|
331
|
+
end
|