ramaze 0.0.7 → 0.0.8
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/Rakefile +52 -19
- data/bin/ramaze +19 -6
- data/doc/CHANGELOG +33 -0
- data/doc/COPYING +1 -1
- data/doc/FAQ +92 -0
- data/doc/GPL +340 -0
- data/doc/INSTALL +34 -0
- data/doc/ProjectInfo +53 -0
- data/doc/README +187 -110
- data/doc/readme_chunks/appendix.txt +13 -0
- data/doc/readme_chunks/examples.txt +38 -0
- data/doc/readme_chunks/features.txt +82 -0
- data/doc/readme_chunks/getting_help.txt +5 -0
- data/doc/readme_chunks/getting_started.txt +18 -0
- data/doc/readme_chunks/installing.txt +41 -0
- data/doc/readme_chunks/introduction.txt +18 -0
- data/doc/readme_chunks/principles.txt +41 -0
- data/doc/readme_chunks/thanks.txt +59 -0
- data/doc/tutorial/todolist.txt +546 -0
- data/examples/blog/main.rb +1 -1
- data/examples/blog/src/controller.rb +13 -11
- data/examples/blog/src/element.rb +11 -6
- data/examples/blog/src/model.rb +8 -23
- data/examples/blog/template/edit.xhtml +3 -1
- data/examples/blog/template/index.xhtml +4 -4
- data/examples/caching.rb +4 -4
- data/examples/element.rb +10 -7
- data/examples/hello.rb +3 -4
- data/examples/simple.rb +5 -3
- data/examples/templates/template/external.amrita +19 -0
- data/examples/templates/template/{external.rmze → external.zmr} +2 -2
- data/examples/templates/template_amrita2.rb +48 -0
- data/examples/templates/template_erubis.rb +5 -2
- data/examples/templates/{template_ramaze.rb → template_ezamar.rb} +13 -7
- data/examples/templates/template_haml.rb +4 -1
- data/examples/templates/template_liquid.rb +2 -1
- data/examples/templates/template_markaby.rb +2 -1
- data/examples/todolist/conf/benchmark.yaml +35 -0
- data/examples/todolist/conf/debug.yaml +34 -0
- data/examples/todolist/conf/live.yaml +33 -0
- data/examples/todolist/conf/silent.yaml +31 -0
- data/examples/todolist/conf/stage.yaml +33 -0
- data/examples/todolist/main.rb +18 -0
- data/examples/todolist/public/404.jpg +0 -0
- data/examples/todolist/public/css/coderay.css +105 -0
- data/examples/todolist/public/css/ramaze_error.css +42 -0
- data/{lib/proto → examples/todolist}/public/error.xhtml +0 -0
- data/examples/todolist/public/favicon.ico +0 -0
- data/examples/todolist/public/js/jquery.js +1923 -0
- data/examples/todolist/public/ramaze.png +0 -0
- data/examples/todolist/src/controller/main.rb +56 -0
- data/examples/todolist/src/element/page.rb +26 -0
- data/examples/todolist/src/model.rb +14 -0
- data/examples/todolist/template/index.xhtml +17 -0
- data/examples/todolist/template/new.xhtml +7 -0
- data/examples/todolist/todolist.db +9 -0
- data/examples/whywiki/main.rb +3 -8
- data/examples/whywiki/template/show.xhtml +4 -0
- data/lib/proto/public/error.zmr +77 -0
- data/lib/proto/src/controller/main.rb +2 -1
- data/lib/proto/src/element/page.rb +2 -1
- data/lib/proto/src/model.rb +3 -2
- data/lib/ramaze.rb +7 -9
- data/lib/ramaze/adapter.rb +51 -0
- data/lib/ramaze/adapter/cgi.rb +23 -0
- data/lib/ramaze/adapter/fcgi.rb +22 -0
- data/lib/ramaze/adapter/mongrel.rb +7 -86
- data/lib/ramaze/adapter/webrick.rb +14 -133
- data/lib/ramaze/cache/memcached.rb +6 -0
- data/lib/ramaze/cache/yaml_store.rb +3 -1
- data/lib/ramaze/controller.rb +292 -2
- data/lib/ramaze/dispatcher.rb +85 -213
- data/lib/ramaze/error.rb +10 -0
- data/lib/ramaze/global.rb +8 -0
- data/lib/ramaze/helper/aspect.rb +30 -7
- data/lib/ramaze/helper/auth.rb +16 -9
- data/lib/ramaze/helper/cache.rb +40 -35
- data/lib/ramaze/helper/feed.rb +1 -1
- data/lib/ramaze/helper/flash.rb +34 -0
- data/lib/ramaze/helper/link.rb +8 -2
- data/lib/ramaze/helper/openid.rb +63 -0
- data/lib/ramaze/helper/redirect.rb +12 -11
- data/lib/ramaze/helper/stack.rb +5 -7
- data/lib/ramaze/inform.rb +12 -1
- data/lib/ramaze/snippets/kernel/aquire.rb +1 -1
- data/lib/ramaze/snippets/kernel/{self_method.rb → method.rb} +3 -18
- data/lib/ramaze/snippets/kernel/{rescue_require.rb → pretty_inspect.rb} +7 -6
- data/lib/ramaze/snippets/method/name.rb +22 -0
- data/lib/ramaze/snippets/{kernel → ramaze}/autoreload.rb +0 -0
- data/lib/ramaze/snippets/ramaze/caller_info.rb +14 -0
- data/lib/ramaze/snippets/{kernel → ramaze}/caller_lines.rb +3 -10
- data/lib/ramaze/snippets/rdoc/usage_no_exit.rb +49 -23
- data/lib/ramaze/snippets/string/DIVIDE.rb +0 -1
- data/lib/ramaze/store/default.rb +58 -2
- data/lib/ramaze/store/yaml.rb +161 -0
- data/lib/ramaze/template.rb +27 -86
- data/lib/ramaze/template/amrita2.rb +14 -19
- data/lib/ramaze/template/erubis.rb +15 -38
- data/lib/ramaze/template/ezamar.rb +100 -0
- data/lib/ramaze/template/ezamar/element.rb +166 -0
- data/lib/ramaze/template/ezamar/engine.rb +124 -0
- data/lib/ramaze/template/ezamar/morpher.rb +155 -0
- data/lib/ramaze/template/haml.rb +16 -43
- data/lib/ramaze/template/liquid.rb +11 -51
- data/lib/ramaze/template/markaby.rb +44 -42
- data/lib/ramaze/tool/mime.rb +18 -0
- data/lib/ramaze/tool/mime_types.yaml +615 -0
- data/lib/ramaze/trinity/request.rb +20 -196
- data/lib/ramaze/trinity/response.rb +4 -33
- data/lib/ramaze/trinity/session.rb +150 -72
- data/lib/ramaze/version.rb +1 -1
- data/spec/adapter_spec.rb +20 -0
- data/spec/public/favicon.ico +0 -0
- data/spec/public/ramaze.png +0 -0
- data/spec/public/test_download.css +141 -0
- data/spec/{tc_request.rb → request_tc_helper.rb} +45 -21
- data/spec/spec_all.rb +77 -34
- data/spec/spec_helper.rb +8 -157
- data/spec/spec_helper_context.rb +72 -0
- data/spec/spec_helper_requester.rb +52 -0
- data/spec/spec_helper_simple_http.rb +433 -0
- data/spec/tc_adapter_mongrel.rb +3 -15
- data/spec/tc_adapter_webrick.rb +4 -14
- data/spec/tc_cache.rb +3 -5
- data/spec/tc_controller.rb +22 -12
- data/spec/tc_dependencies.rb +13 -0
- data/spec/tc_element.rb +8 -7
- data/spec/tc_error.rb +13 -7
- data/spec/tc_global.rb +16 -18
- data/spec/tc_helper_aspect.rb +2 -4
- data/spec/tc_helper_auth.rb +15 -14
- data/spec/tc_helper_cache.rb +5 -7
- data/spec/tc_helper_feed.rb +0 -2
- data/spec/tc_helper_flash.rb +103 -0
- data/spec/tc_helper_form.rb +4 -6
- data/spec/tc_helper_link.rb +1 -3
- data/spec/tc_helper_redirect.rb +23 -8
- data/spec/tc_helper_stack.rb +31 -15
- data/spec/tc_morpher.rb +1 -3
- data/spec/tc_params.rb +48 -7
- data/spec/tc_request_mongrel.rb +9 -0
- data/spec/tc_request_webrick.rb +5 -0
- data/spec/tc_session.rb +41 -25
- data/spec/tc_store.rb +55 -6
- data/spec/tc_store_yaml.rb +71 -0
- data/spec/tc_template_amrita2.rb +3 -3
- data/spec/tc_template_erubis.rb +2 -3
- data/spec/{tc_template_ramaze.rb → tc_template_ezamar.rb} +15 -5
- data/spec/tc_template_haml.rb +4 -3
- data/spec/tc_template_liquid.rb +3 -4
- data/spec/tc_template_markaby.rb +4 -6
- data/spec/tc_tidy.rb +1 -3
- data/spec/template/amrita2/{data.html → data.amrita} +0 -0
- data/spec/template/amrita2/{index.html → index.amrita} +0 -0
- data/spec/template/amrita2/{sum.html → sum.amrita} +0 -0
- data/spec/template/ezamar/another/long/action.zmr +1 -0
- data/spec/template/ezamar/combined.zmr +1 -0
- data/spec/template/{ramaze/file_only.rmze → ezamar/file_only.zmr} +0 -0
- data/spec/template/{ramaze/index.rmze → ezamar/index.zmr} +0 -0
- data/spec/template/{ramaze/nested.rmze → ezamar/nested.zmr} +0 -0
- data/spec/template/ezamar/some__long__action.zmr +1 -0
- data/spec/template/{ramaze/sum.rmze → ezamar/sum.zmr} +0 -0
- metadata +181 -123
- data/doc/allison/LICENSE +0 -184
- data/doc/allison/README +0 -37
- data/doc/allison/allison.css +0 -300
- data/doc/allison/allison.gif +0 -0
- data/doc/allison/allison.js +0 -307
- data/doc/allison/allison.rb +0 -287
- data/doc/allison/cache/BODY +0 -588
- data/doc/allison/cache/CLASS_INDEX +0 -4
- data/doc/allison/cache/CLASS_PAGE +0 -1
- data/doc/allison/cache/FILE_INDEX +0 -4
- data/doc/allison/cache/FILE_PAGE +0 -1
- data/doc/allison/cache/FONTS +0 -1
- data/doc/allison/cache/FR_INDEX_BODY +0 -1
- data/doc/allison/cache/IMGPATH +0 -1
- data/doc/allison/cache/INDEX +0 -1
- data/doc/allison/cache/JAVASCRIPT +0 -307
- data/doc/allison/cache/METHOD_INDEX +0 -4
- data/doc/allison/cache/METHOD_LIST +0 -1
- data/doc/allison/cache/SRC_PAGE +0 -1
- data/doc/allison/cache/STYLE +0 -322
- data/doc/allison/cache/URL +0 -1
- data/doc/changes.txt +0 -2021
- data/doc/changes.xml +0 -2024
- data/lib/ramaze/snippets/kernel/silently.rb +0 -13
- data/lib/ramaze/snippets/thread/deadQUESTIONMARK.rb +0 -11
- data/lib/ramaze/template/haml/actionview_stub.rb +0 -20
- data/lib/ramaze/template/ramaze.rb +0 -177
- data/lib/ramaze/template/ramaze/element.rb +0 -166
- data/lib/ramaze/template/ramaze/morpher.rb +0 -156
- data/spec/tc_test.rb +0 -17
|
@@ -7,20 +7,10 @@ require 'digest/md5'
|
|
|
7
7
|
|
|
8
8
|
module Ramaze
|
|
9
9
|
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
# is later available in the controller or as Thread.current[:request]
|
|
13
|
-
#
|
|
14
|
-
# Please note that the implementation is lacking performance and security
|
|
15
|
-
# in favor of simplicity. Hopefully I (or some CGI-guru) will come along
|
|
16
|
-
# and implement this properly, until then consider it unsafe, but functional.
|
|
17
|
-
#
|
|
18
|
-
# Most information you will need is in the #params, which is a compound of
|
|
19
|
-
# all the information available from POST, GET, DELETE and PUT.
|
|
10
|
+
# The purpose of this class is to act as a simple wrapper for Rack::Request
|
|
11
|
+
# and provide some convinient methods for our own use.
|
|
20
12
|
|
|
21
13
|
class Request
|
|
22
|
-
attr_accessor :request, :post_query, :get_query, :puts_query, :get_query
|
|
23
|
-
|
|
24
14
|
class << self
|
|
25
15
|
|
|
26
16
|
# get the current request out of Thread.current[:request]
|
|
@@ -32,213 +22,47 @@ module Ramaze
|
|
|
32
22
|
end
|
|
33
23
|
end
|
|
34
24
|
|
|
35
|
-
# create a new instance of Request, takes the original
|
|
36
|
-
#
|
|
25
|
+
# create a new instance of Request, takes the original Rack::Request
|
|
26
|
+
# instance
|
|
37
27
|
|
|
38
28
|
def initialize request = {}
|
|
39
29
|
@request = request
|
|
40
|
-
parse_queries
|
|
41
30
|
end
|
|
42
31
|
|
|
43
|
-
#
|
|
44
|
-
# first it tries to match your method with any of the HTTP parameters
|
|
45
|
-
# then, in case that fails, it will relay to @request
|
|
46
|
-
|
|
47
|
-
def method_missing meth, *args, &block
|
|
48
|
-
if value = @request.params[meth.to_s.upcase] rescue false
|
|
49
|
-
value
|
|
50
|
-
else
|
|
51
|
-
@request.send(meth, *args, &block)
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# containts all the parameters given, no matter wheter with
|
|
56
|
-
# POST, GET, PUT or DELETE
|
|
57
|
-
# answers with a hash that is generated from the respective
|
|
58
|
-
# _query instance-variables and cached subsequently in @params
|
|
59
|
-
|
|
60
|
-
def params
|
|
61
|
-
@params ||= [
|
|
62
|
-
@get_query, @post_query, @put_query, @delete_query
|
|
63
|
-
].inject({}) do |sum, hash|
|
|
64
|
-
sum.merge(hash || {})
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# this parses stuff like post-requests (very untested)
|
|
69
|
-
# and also ?foo=bar stuff (get-query)
|
|
70
|
-
# WEBrick uses body as a streaming-object, so we have to #read.
|
|
71
|
-
# Mongrel has a normal string as body, we just call to_s in case
|
|
72
|
-
# it's no POST
|
|
73
|
-
|
|
74
|
-
def parse_queries
|
|
75
|
-
case request_method
|
|
76
|
-
when 'GET' : process_get
|
|
77
|
-
when 'POST' : process_post
|
|
78
|
-
when 'PUT' : process_put
|
|
79
|
-
when 'DELETE' : process_delete
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
# very naive implementation of POST-body parsing, this won't withstand
|
|
84
|
-
# any serious testing or multiple simultanous huge posts...
|
|
85
|
-
# However, it just extracts the information inside the @request.body
|
|
86
|
-
# and puts it into proper form
|
|
87
|
-
# you can access its contents via #post_query
|
|
88
|
-
|
|
89
|
-
def process_post
|
|
90
|
-
@post_query = {}
|
|
91
|
-
|
|
92
|
-
type, boundary = content_type.split(';')
|
|
93
|
-
|
|
94
|
-
if type.downcase == 'multipart/form-data' and not boundary.empty?
|
|
95
|
-
parse_multipart(body, boundary.split('=').last)
|
|
96
|
-
else
|
|
97
|
-
post_query = query_parse(body.respond_to?(:read) ? body.read : body)
|
|
98
|
-
post_query.each do |key, value|
|
|
99
|
-
@post_query[CGI.unescape(key)] = CGI.unescape(value)
|
|
100
|
-
end
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
# processing incoming GET, stuffing the results into @get_query,
|
|
105
|
-
# you can access the information via #get_query
|
|
106
|
-
|
|
107
|
-
def process_get
|
|
108
|
-
@get_query = {}
|
|
109
|
-
|
|
110
|
-
get_query = query_parse(query_string) rescue {}
|
|
111
|
-
get_query.each do |key, value|
|
|
112
|
-
@get_query[CGI.unescape(key)] = CGI.unescape(value)
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
|
|
116
|
-
# TODO
|
|
117
|
-
# - implement and test DELETE
|
|
118
|
-
|
|
119
|
-
def process_delete
|
|
120
|
-
@delete_query = {}
|
|
121
|
-
raise "Implement me"
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
# again, rather naive, it just gives you the control over what to do
|
|
125
|
-
# with the #body but will parse the parameters from the URL
|
|
126
|
-
|
|
127
|
-
def process_put
|
|
128
|
-
@pust_query = {}
|
|
129
|
-
|
|
130
|
-
put_query = query_parse(query_string) rescue {}
|
|
131
|
-
put_query.each do |key, value|
|
|
132
|
-
@put_query[CGI.unescape(key)] = CGI.unescape(value)
|
|
133
|
-
end
|
|
134
|
-
end
|
|
135
|
-
|
|
136
|
-
# process the parameters passed over the URL, they look like
|
|
137
|
-
#
|
|
138
|
-
# http://foo.bar/action?eins=one&zwei=two
|
|
139
|
-
#
|
|
140
|
-
# that would result in #params containing {'eins' => 'one', 'zwei' => 'two'}
|
|
141
|
-
|
|
142
|
-
def query_parse str
|
|
143
|
-
str = str.split('?').last.to_s rescue ''
|
|
144
|
-
hash = CGI.parse(str)
|
|
145
|
-
hash.each do |key, values|
|
|
146
|
-
key = CGI.unescape(key)
|
|
147
|
-
values = values.map{|v| CGI.unescape(v)}
|
|
148
|
-
hash[key] = values.size == 1 ? values.first : values
|
|
149
|
-
end
|
|
150
|
-
hash
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
# parse multipart-requests, just pass it something that responds to .read
|
|
154
|
-
# and a boundary for the parts.
|
|
155
|
-
# again a naive implementation without any guarantee against DoS.
|
|
156
|
-
#
|
|
157
|
-
# TODO:
|
|
158
|
-
# - rewrite parsing of multipart
|
|
159
|
-
# - chunk through the body and pipe into tempfile
|
|
160
|
-
# - look at merb for example of correct parsing
|
|
161
|
-
|
|
162
|
-
def parse_multipart(body, boundary)
|
|
163
|
-
text = body.read
|
|
164
|
-
text.split("--" << boundary).each do |chunk|
|
|
165
|
-
header = chunk.split("\r\n\r\n").first
|
|
166
|
-
next if (!header or !body) || (header.strip.empty? or chunk.strip.empty?)
|
|
167
|
-
head = parse_multipart_head(header)
|
|
168
|
-
next if head.empty?
|
|
169
|
-
chunk = chunk[(header.size + 4)..-3]
|
|
170
|
-
hash = Digest::MD5.hexdigest([head['name'], chunk.size, head.hash].inspect)
|
|
171
|
-
filename = File.join(Dir.tmpdir, hash)
|
|
172
|
-
File.open(filename, "w+") do |file|
|
|
173
|
-
file.print(chunk)
|
|
174
|
-
end
|
|
175
|
-
@post_query[head['name']] = File.open(filename)
|
|
176
|
-
end
|
|
177
|
-
body.rewind
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
# parse the head of the one part of multipart
|
|
181
|
-
# you most likely won't have to use this on your own :)
|
|
182
|
-
|
|
183
|
-
def parse_multipart_head(string)
|
|
184
|
-
string.gsub("\r\n", ";").split(';').inject({}) do |sum, param|
|
|
185
|
-
key, value = param.strip.split('=')
|
|
186
|
-
sum[key] = value[1..-2] if key and value
|
|
187
|
-
sum
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
# like request.params[key]
|
|
32
|
+
# shortcut for request.params[key]
|
|
192
33
|
|
|
193
34
|
def [](key)
|
|
194
35
|
params[key]
|
|
195
36
|
end
|
|
196
37
|
|
|
197
|
-
#
|
|
38
|
+
# shortcut for request.params[key] = value
|
|
198
39
|
|
|
199
40
|
def []=(key, value)
|
|
200
41
|
params[key] = value
|
|
201
42
|
end
|
|
202
43
|
|
|
203
|
-
#
|
|
204
|
-
def get?() request_method == 'GET' end
|
|
205
|
-
# request_method == 'POST'
|
|
206
|
-
def post?() request_method == 'POST' end
|
|
207
|
-
# request_method == 'PUT'
|
|
208
|
-
def put?() request_method == 'PUT' end
|
|
209
|
-
# request_method == 'DELETE'
|
|
210
|
-
def delete?() request_method == 'DELETE' end
|
|
44
|
+
# like Hash#values_at
|
|
211
45
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
def local?
|
|
215
|
-
remote_addr == '127.0.0.1'
|
|
46
|
+
def values_at(*keys)
|
|
47
|
+
keys.map{|key| params[key] }
|
|
216
48
|
end
|
|
217
49
|
|
|
218
|
-
#
|
|
219
|
-
|
|
220
|
-
def local_net?(ip = remote_addr)
|
|
221
|
-
bip = ip.split('.').map{ |x| x.to_i }.pack('C4').unpack('N')[0]
|
|
222
|
-
|
|
223
|
-
# 127.0.0.1/32 => 2130706433
|
|
224
|
-
# 192.168.0.0/16 => 49320
|
|
225
|
-
# 172.16.0.0/12 => 2753
|
|
226
|
-
# 10.0.0.0/8 => 10
|
|
227
|
-
|
|
228
|
-
{ 0 => 2130706433, 16 => 49320, 20 => 2753, 24 => 10}.each do |s,c|
|
|
229
|
-
return true if (bip >> s) == c
|
|
230
|
-
end
|
|
50
|
+
# the referer of the client or '/'
|
|
231
51
|
|
|
232
|
-
|
|
52
|
+
def referer
|
|
53
|
+
@request.env['HTTP_REFERER'] || '/'
|
|
233
54
|
end
|
|
234
55
|
|
|
235
|
-
|
|
236
|
-
# '/' if no referer given.
|
|
56
|
+
alias referrer referer
|
|
237
57
|
|
|
238
|
-
|
|
239
|
-
|
|
58
|
+
# you can access the original @request via this method_missing,
|
|
59
|
+
# first it tries to match your method with any of the HTTP parameters
|
|
60
|
+
# then, in case that fails, it will relay to @request
|
|
61
|
+
|
|
62
|
+
def method_missing meth, *args, &block
|
|
63
|
+
@request.send(meth, *args, &block)
|
|
240
64
|
rescue
|
|
241
|
-
|
|
65
|
+
@request.env[meth.to_s.upcase]
|
|
242
66
|
end
|
|
243
67
|
end
|
|
244
68
|
end
|
|
@@ -2,40 +2,11 @@
|
|
|
2
2
|
# All files in this distribution are subject to the terms of the Ruby license.
|
|
3
3
|
|
|
4
4
|
module Ramaze
|
|
5
|
-
#
|
|
6
|
-
# made.
|
|
5
|
+
# get the current response out of Thread.current[:response]
|
|
7
6
|
#
|
|
8
|
-
#
|
|
9
|
-
# properties: #out, #code, #head
|
|
10
|
-
# where head has to #respond_to? #[]
|
|
11
|
-
#
|
|
12
|
-
# code is the status-code ( http://en.wikipedia.org/wiki/List_of_HTTP_status_codes )
|
|
13
|
-
# and out should be something very String-like
|
|
14
|
-
|
|
15
|
-
class ResponseStruct < Struct
|
|
16
|
-
|
|
17
|
-
# get the current response out of Thread.current[:response]
|
|
18
|
-
#
|
|
19
|
-
# You can call this from everywhere with Ramaze::Response.current
|
|
20
|
-
|
|
21
|
-
def current
|
|
22
|
-
Thread.current[:response]
|
|
23
|
-
end
|
|
7
|
+
# You can call this from everywhere with Ramaze::Response.current
|
|
24
8
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def inspect
|
|
29
|
-
"<Response##{object_id} @code => #{code}, @head => #{head.inspect}, @out.size => #{out.size}>"
|
|
30
|
-
end
|
|
31
|
-
alias pretty_inspect inspect
|
|
32
|
-
|
|
33
|
-
# same as #head['Content-Type']
|
|
34
|
-
|
|
35
|
-
def content_type
|
|
36
|
-
head['Content-Type']
|
|
37
|
-
end
|
|
9
|
+
def self.Response
|
|
10
|
+
Thread.current[:response]
|
|
38
11
|
end
|
|
39
|
-
|
|
40
|
-
Response = ResponseStruct.new(:out, :code, :head)
|
|
41
12
|
end
|
|
@@ -5,125 +5,203 @@ require 'digest/sha2'
|
|
|
5
5
|
|
|
6
6
|
module Ramaze
|
|
7
7
|
|
|
8
|
-
#
|
|
9
|
-
# It is heavily based on cookies storing the key to the information stored
|
|
10
|
-
# on the server.
|
|
8
|
+
# The SessionHash acts as the wrapper for a simple Hash
|
|
11
9
|
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
10
|
+
# Its purpose is to notify the underlying cache, in which the sessions
|
|
11
|
+
# are stored, about updates.
|
|
12
|
+
|
|
13
|
+
class SessionHash
|
|
14
|
+
def initialize
|
|
15
|
+
@hash = {}
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# relays all the methods to the @hash and updates the session_cache in
|
|
19
|
+
# Session.current.sessions if anything changes.
|
|
20
|
+
|
|
21
|
+
def method_missing(*args, &block)
|
|
22
|
+
old = @hash.dup
|
|
23
|
+
result = @hash.send(*args, &block)
|
|
24
|
+
unless old == @hash
|
|
25
|
+
Session.current.sessions[Session.current.session_id] = self
|
|
26
|
+
end
|
|
27
|
+
result
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def inspect
|
|
31
|
+
@hash.inspect
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# The purpose of Session is to hold key/value pairs like a Hash for a series
|
|
36
|
+
# of # request/response cycles from the same client.
|
|
37
|
+
#
|
|
38
|
+
# The persistence is achieved by setting a cookie with the session_id to
|
|
39
|
+
# the client, which is then passed back and forth until the cookie is either
|
|
40
|
+
# deleted or expires.
|
|
14
41
|
|
|
15
42
|
class Session
|
|
43
|
+
|
|
44
|
+
# The unique id for the current session which is also passed on to the cookie.
|
|
45
|
+
|
|
46
|
+
attr_accessor :session_id
|
|
47
|
+
|
|
48
|
+
# This variable holds the current SessionFlash
|
|
49
|
+
|
|
50
|
+
attr_accessor :flash
|
|
51
|
+
|
|
52
|
+
# the key used for the cookie
|
|
53
|
+
|
|
16
54
|
SESSION_KEY = '_ramaze_session_id'
|
|
17
|
-
|
|
55
|
+
|
|
56
|
+
trait :finalize => [:finalize_flash]
|
|
18
57
|
|
|
19
58
|
class << self
|
|
20
59
|
|
|
21
|
-
#
|
|
22
|
-
#
|
|
23
|
-
# You can call this from everywhere with Ramaze::Session.current
|
|
60
|
+
# answers with Thread.current[:session] which holds the current session
|
|
61
|
+
# set by the Dispatcher#setup_environment.
|
|
24
62
|
|
|
25
63
|
def current
|
|
26
64
|
Thread.current[:session]
|
|
27
65
|
end
|
|
28
66
|
end
|
|
29
67
|
|
|
30
|
-
#
|
|
31
|
-
#
|
|
68
|
+
# Initialize a new Session, requires the original Rack::Request instance
|
|
69
|
+
# given to us from Dispatcher#setup_environment.
|
|
70
|
+
#
|
|
71
|
+
# sets @session_id and @session_flash
|
|
72
|
+
#
|
|
73
|
+
# will set Thread.main[:session_cache] to an instance of
|
|
74
|
+
# Ramaze::Global.cache if no cache for the sessions is initialized yet
|
|
32
75
|
|
|
33
76
|
def initialize request
|
|
34
|
-
@session_id =
|
|
77
|
+
@session_id = (request.cookies[SESSION_KEY] || random_key)
|
|
78
|
+
@flash = Ramaze::SessionFlash.new
|
|
79
|
+
|
|
80
|
+
unless sessions
|
|
81
|
+
global_cache = Ramaze::Global.cache
|
|
82
|
+
|
|
83
|
+
if global_cache.respond_to?(:new)
|
|
84
|
+
cache = global_cache.new
|
|
85
|
+
else
|
|
86
|
+
cache = constant("::Ramaze::#{global_cache}")
|
|
87
|
+
cache = cache.new if cache.respond_to?(:new)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
Thread.main[:session_cache] = cache
|
|
91
|
+
end
|
|
35
92
|
end
|
|
36
93
|
|
|
37
|
-
#
|
|
38
|
-
# is currently active
|
|
94
|
+
# relay all messages we don't understand to the currently active session
|
|
39
95
|
|
|
40
|
-
def
|
|
41
|
-
|
|
96
|
+
def method_missing(*args, &block)
|
|
97
|
+
current.send(*args, &block)
|
|
42
98
|
end
|
|
43
99
|
|
|
44
|
-
# the
|
|
100
|
+
# answers with the currently active session, which is set unless it is
|
|
101
|
+
# existing already, the session itself is an instance of SessionHash
|
|
45
102
|
|
|
46
103
|
def current
|
|
47
|
-
sessions[session_id] ||=
|
|
104
|
+
sessions[session_id] ||= SessionHash.new
|
|
48
105
|
end
|
|
49
106
|
|
|
50
|
-
#
|
|
51
|
-
# set the constant Ramaze::SessionCache and from then on start populating
|
|
52
|
-
# it with the sessions. SessionCache is an instance of Global.cache as
|
|
53
|
-
# well.
|
|
107
|
+
# shortcut to Thread.main[:session_cache]
|
|
54
108
|
|
|
55
109
|
def sessions
|
|
56
|
-
Thread.main[:session_cache]
|
|
110
|
+
Thread.main[:session_cache]
|
|
57
111
|
end
|
|
58
112
|
|
|
59
|
-
#
|
|
60
|
-
# of the client, in case there is none it will try to set one.
|
|
61
|
-
# Unfortunatly we have to go seperate paths here for mongrel and webrick,
|
|
62
|
-
# since they do not share the same API.
|
|
113
|
+
# generate a random (and hopefully unique) id for the current session.
|
|
63
114
|
#
|
|
64
|
-
#
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
115
|
+
# It consists of the current time, the current request, the current PID of
|
|
116
|
+
# ruby and object_id of this instance.
|
|
117
|
+
#
|
|
118
|
+
# All this is joined by some calls to Kernel#rand and returned as a
|
|
119
|
+
# Digest::SHA256::hexdigest
|
|
120
|
+
|
|
121
|
+
def random_key
|
|
122
|
+
h = [
|
|
123
|
+
Time.now.to_f.to_s.reverse, rand,
|
|
124
|
+
Thread.current[:request].hash, rand,
|
|
125
|
+
Process.pid, rand,
|
|
126
|
+
object_id, rand
|
|
127
|
+
].join
|
|
128
|
+
Digest::SHA256.hexdigest(h)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# send each element of the trait[:finalize]
|
|
132
|
+
# this is at the moment used for flash_finalize.
|
|
133
|
+
|
|
134
|
+
def finalize
|
|
135
|
+
ancestral_trait[:finalize].each do |meth|
|
|
136
|
+
send meth
|
|
76
137
|
end
|
|
77
138
|
end
|
|
78
139
|
|
|
79
|
-
|
|
140
|
+
def inspect
|
|
141
|
+
current.inspect
|
|
142
|
+
end
|
|
80
143
|
|
|
81
|
-
|
|
82
|
-
cookie = pre_parse(request)
|
|
144
|
+
private
|
|
83
145
|
|
|
84
|
-
|
|
146
|
+
# at the end of a request delete the current[:FLASH] and assign it to
|
|
147
|
+
# current[:FLASH_PREVIOUS]
|
|
148
|
+
#
|
|
149
|
+
# this is needed so flash can iterate over requests
|
|
150
|
+
# and always just keep the current and previous key/value pairs.
|
|
85
151
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
152
|
+
def finalize_flash
|
|
153
|
+
old = delete(:FLASH)
|
|
154
|
+
current[:FLASH_PREVIOUS] = old if old
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
# The purpose of this class is to act as a unifier of the previous
|
|
159
|
+
# and current flash.
|
|
160
|
+
#
|
|
161
|
+
# Flash means pairs of keys and values that are held only over one
|
|
162
|
+
# request/response cycle. So you can assign a key/value in the current
|
|
163
|
+
# session and retrieve it in the current and following request.
|
|
164
|
+
#
|
|
165
|
+
# Please see the FlashHelper for details on the usage as you won't need
|
|
166
|
+
# to touch this class at all.
|
|
167
|
+
|
|
168
|
+
class SessionFlash
|
|
169
|
+
|
|
170
|
+
# the current session[:FLASH_PREVIOUS]
|
|
171
|
+
|
|
172
|
+
def previous
|
|
173
|
+
session[:FLASH_PREVIOUS] || {}
|
|
93
174
|
end
|
|
94
175
|
|
|
95
|
-
#
|
|
96
|
-
# this makes it easier to do i.e. hash-manipulation directly
|
|
97
|
-
# on #session in the controller.
|
|
176
|
+
# the current session[:FLASH]
|
|
98
177
|
|
|
99
|
-
def
|
|
100
|
-
|
|
178
|
+
def current
|
|
179
|
+
session[:FLASH] ||= {}
|
|
101
180
|
end
|
|
102
181
|
|
|
103
|
-
#
|
|
182
|
+
# combined key/value pairs of previous and current
|
|
183
|
+
# current keys overshadow the old ones.
|
|
104
184
|
|
|
105
|
-
def
|
|
106
|
-
|
|
107
|
-
tmp.delete SESSION_KEY
|
|
108
|
-
tmp.inspect
|
|
185
|
+
def combined
|
|
186
|
+
previous.merge(current)
|
|
109
187
|
end
|
|
110
188
|
|
|
111
|
-
|
|
189
|
+
def [](key)
|
|
190
|
+
combined[key]
|
|
191
|
+
end
|
|
112
192
|
|
|
113
|
-
def
|
|
114
|
-
|
|
193
|
+
def []=(key, value)
|
|
194
|
+
current[key] = value
|
|
115
195
|
end
|
|
116
196
|
|
|
117
|
-
|
|
197
|
+
def inspect
|
|
198
|
+
combined.inspect
|
|
199
|
+
end
|
|
118
200
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
Process.pid, rand,
|
|
124
|
-
object_id, rand
|
|
125
|
-
].join
|
|
126
|
-
Digest::SHA512.hexdigest(h)
|
|
201
|
+
private
|
|
202
|
+
|
|
203
|
+
def session
|
|
204
|
+
Ramaze::Session.current
|
|
127
205
|
end
|
|
128
206
|
end
|
|
129
207
|
end
|