ramaze 0.0.6
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 +360 -0
- data/bin/ramaze +152 -0
- data/doc/CHANGELOG +2021 -0
- data/doc/COPYING +56 -0
- data/doc/COPYING.ja +51 -0
- data/doc/README +275 -0
- data/doc/TODO +33 -0
- data/doc/allison/LICENSE +184 -0
- data/doc/allison/README +37 -0
- data/doc/allison/allison.css +300 -0
- data/doc/allison/allison.gif +0 -0
- data/doc/allison/allison.js +307 -0
- data/doc/allison/allison.rb +287 -0
- data/doc/allison/cache/BODY +588 -0
- data/doc/allison/cache/CLASS_INDEX +4 -0
- data/doc/allison/cache/CLASS_PAGE +1 -0
- data/doc/allison/cache/FILE_INDEX +4 -0
- data/doc/allison/cache/FILE_PAGE +1 -0
- data/doc/allison/cache/FONTS +1 -0
- data/doc/allison/cache/FR_INDEX_BODY +1 -0
- data/doc/allison/cache/IMGPATH +1 -0
- data/doc/allison/cache/INDEX +1 -0
- data/doc/allison/cache/JAVASCRIPT +307 -0
- data/doc/allison/cache/METHOD_INDEX +4 -0
- data/doc/allison/cache/METHOD_LIST +1 -0
- data/doc/allison/cache/SRC_PAGE +1 -0
- data/doc/allison/cache/STYLE +322 -0
- data/doc/allison/cache/URL +1 -0
- data/examples/blog/main.rb +16 -0
- data/examples/blog/public/screen.css +106 -0
- data/examples/blog/src/controller.rb +50 -0
- data/examples/blog/src/element.rb +53 -0
- data/examples/blog/src/model.rb +29 -0
- data/examples/blog/template/edit.xhtml +6 -0
- data/examples/blog/template/index.xhtml +24 -0
- data/examples/blog/template/new.xhtml +5 -0
- data/examples/blog/template/view.xhtml +15 -0
- data/examples/blog/test/tc_entry.rb +18 -0
- data/examples/caching.rb +23 -0
- data/examples/element.rb +40 -0
- data/examples/hello.rb +23 -0
- data/examples/simple.rb +60 -0
- data/examples/templates/template/external.haml +21 -0
- data/examples/templates/template/external.liquid +28 -0
- data/examples/templates/template/external.mab +27 -0
- data/examples/templates/template/external.rhtml +29 -0
- data/examples/templates/template/external.rmze +24 -0
- data/examples/templates/template_erubis.rb +50 -0
- data/examples/templates/template_haml.rb +48 -0
- data/examples/templates/template_liquid.rb +64 -0
- data/examples/templates/template_markaby.rb +52 -0
- data/examples/templates/template_ramaze.rb +49 -0
- data/examples/whywiki/main.rb +56 -0
- data/examples/whywiki/template/edit.xhtml +14 -0
- data/examples/whywiki/template/show.xhtml +17 -0
- data/lib/proto/conf/benchmark.yaml +35 -0
- data/lib/proto/conf/debug.yaml +34 -0
- data/lib/proto/conf/live.yaml +33 -0
- data/lib/proto/conf/silent.yaml +31 -0
- data/lib/proto/conf/stage.yaml +33 -0
- data/lib/proto/main.rb +18 -0
- data/lib/proto/public/404.jpg +0 -0
- data/lib/proto/public/css/coderay.css +105 -0
- data/lib/proto/public/css/ramaze_error.css +42 -0
- data/lib/proto/public/error.xhtml +74 -0
- data/lib/proto/public/favicon.ico +0 -0
- data/lib/proto/public/js/jquery.js +1923 -0
- data/lib/proto/public/ramaze.png +0 -0
- data/lib/proto/src/controller/main.rb +7 -0
- data/lib/proto/src/element/page.rb +16 -0
- data/lib/proto/src/model.rb +5 -0
- data/lib/proto/template/index.xhtml +6 -0
- data/lib/ramaze.rb +317 -0
- data/lib/ramaze/adapter/mongrel.rb +111 -0
- data/lib/ramaze/adapter/webrick.rb +161 -0
- data/lib/ramaze/cache.rb +11 -0
- data/lib/ramaze/cache/memcached.rb +52 -0
- data/lib/ramaze/cache/memory.rb +6 -0
- data/lib/ramaze/cache/yaml_store.rb +37 -0
- data/lib/ramaze/controller.rb +10 -0
- data/lib/ramaze/dispatcher.rb +315 -0
- data/lib/ramaze/error.rb +11 -0
- data/lib/ramaze/gestalt.rb +108 -0
- data/lib/ramaze/global.rb +120 -0
- data/lib/ramaze/helper.rb +32 -0
- data/lib/ramaze/helper/aspect.rb +189 -0
- data/lib/ramaze/helper/auth.rb +120 -0
- data/lib/ramaze/helper/cache.rb +52 -0
- data/lib/ramaze/helper/feed.rb +135 -0
- data/lib/ramaze/helper/form.rb +204 -0
- data/lib/ramaze/helper/link.rb +80 -0
- data/lib/ramaze/helper/redirect.rb +48 -0
- data/lib/ramaze/helper/stack.rb +67 -0
- data/lib/ramaze/http_status.rb +66 -0
- data/lib/ramaze/inform.rb +166 -0
- data/lib/ramaze/snippets.rb +5 -0
- data/lib/ramaze/snippets/hash/keys_to_sym.rb +19 -0
- data/lib/ramaze/snippets/kernel/aquire.rb +22 -0
- data/lib/ramaze/snippets/kernel/autoreload.rb +79 -0
- data/lib/ramaze/snippets/kernel/caller_lines.rb +58 -0
- data/lib/ramaze/snippets/kernel/constant.rb +24 -0
- data/lib/ramaze/snippets/kernel/rescue_require.rb +12 -0
- data/lib/ramaze/snippets/kernel/self_method.rb +41 -0
- data/lib/ramaze/snippets/kernel/silently.rb +13 -0
- data/lib/ramaze/snippets/object/traits.rb +60 -0
- data/lib/ramaze/snippets/openstruct/temp.rb +10 -0
- data/lib/ramaze/snippets/string/DIVIDE.rb +16 -0
- data/lib/ramaze/snippets/string/camel_case.rb +14 -0
- data/lib/ramaze/snippets/string/snake_case.rb +12 -0
- data/lib/ramaze/snippets/symbol/to_proc.rb +14 -0
- data/lib/ramaze/snippets/thread/deadQUESTIONMARK.rb +11 -0
- data/lib/ramaze/store/default.rb +48 -0
- data/lib/ramaze/template.rb +102 -0
- data/lib/ramaze/template/amrita2.rb +40 -0
- data/lib/ramaze/template/erubis.rb +58 -0
- data/lib/ramaze/template/haml.rb +65 -0
- data/lib/ramaze/template/haml/actionview_stub.rb +20 -0
- data/lib/ramaze/template/liquid.rb +74 -0
- data/lib/ramaze/template/markaby.rb +68 -0
- data/lib/ramaze/template/ramaze.rb +177 -0
- data/lib/ramaze/template/ramaze/element.rb +166 -0
- data/lib/ramaze/template/ramaze/morpher.rb +156 -0
- data/lib/ramaze/tool/create.rb +70 -0
- data/lib/ramaze/tool/tidy.rb +71 -0
- data/lib/ramaze/trinity.rb +38 -0
- data/lib/ramaze/trinity/request.rb +244 -0
- data/lib/ramaze/trinity/response.rb +41 -0
- data/lib/ramaze/trinity/session.rb +129 -0
- data/lib/ramaze/version.rb +14 -0
- data/spec/spec_all.rb +73 -0
- data/spec/spec_helper.rb +215 -0
- data/spec/tc_adapter_mongrel.rb +24 -0
- data/spec/tc_adapter_webrick.rb +22 -0
- data/spec/tc_cache.rb +79 -0
- data/spec/tc_controller.rb +39 -0
- data/spec/tc_element.rb +100 -0
- data/spec/tc_error.rb +23 -0
- data/spec/tc_gestalt.rb +90 -0
- data/spec/tc_global.rb +46 -0
- data/spec/tc_helper_aspect.rb +65 -0
- data/spec/tc_helper_auth.rb +61 -0
- data/spec/tc_helper_cache.rb +81 -0
- data/spec/tc_helper_feed.rb +129 -0
- data/spec/tc_helper_form.rb +146 -0
- data/spec/tc_helper_link.rb +58 -0
- data/spec/tc_helper_redirect.rb +51 -0
- data/spec/tc_helper_stack.rb +55 -0
- data/spec/tc_morpher.rb +90 -0
- data/spec/tc_params.rb +84 -0
- data/spec/tc_request.rb +111 -0
- data/spec/tc_session.rb +56 -0
- data/spec/tc_store.rb +25 -0
- data/spec/tc_template_amrita2.rb +34 -0
- data/spec/tc_template_erubis.rb +41 -0
- data/spec/tc_template_haml.rb +44 -0
- data/spec/tc_template_liquid.rb +98 -0
- data/spec/tc_template_markaby.rb +74 -0
- data/spec/tc_template_ramaze.rb +54 -0
- data/spec/tc_tidy.rb +14 -0
- data/spec/template/amrita2/data.html +6 -0
- data/spec/template/amrita2/index.html +1 -0
- data/spec/template/amrita2/sum.html +1 -0
- data/spec/template/erubis/sum.rhtml +1 -0
- data/spec/template/haml/index.haml +5 -0
- data/spec/template/haml/with_vars.haml +4 -0
- data/spec/template/liquid/index.liquid +1 -0
- data/spec/template/liquid/products.liquid +45 -0
- data/spec/template/markaby/external.mab +8 -0
- data/spec/template/markaby/sum.mab +1 -0
- data/spec/template/ramaze/file_only.rmze +1 -0
- data/spec/template/ramaze/index.rmze +1 -0
- data/spec/template/ramaze/nested.rmze +1 -0
- data/spec/template/ramaze/sum.rmze +1 -0
- metadata +317 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
# Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
|
|
2
|
+
# All files in this distribution are subject to the terms of the Ruby license.
|
|
3
|
+
|
|
4
|
+
require 'cgi'
|
|
5
|
+
require 'webrick'
|
|
6
|
+
require 'benchmark'
|
|
7
|
+
|
|
8
|
+
require 'ramaze/tool/tidy'
|
|
9
|
+
|
|
10
|
+
# for OSX compatibility
|
|
11
|
+
Socket.do_not_reverse_lookup = true
|
|
12
|
+
|
|
13
|
+
module WEBrick
|
|
14
|
+
class HTTPRequest
|
|
15
|
+
attr_accessor :params
|
|
16
|
+
|
|
17
|
+
# request_uri.path
|
|
18
|
+
|
|
19
|
+
def request_path
|
|
20
|
+
request_uri.path
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# peeraddr.last
|
|
24
|
+
|
|
25
|
+
def remote_addr
|
|
26
|
+
peeraddr.last
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# request_uri.path
|
|
30
|
+
|
|
31
|
+
def request_path
|
|
32
|
+
request_uri.path
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# the headers of the current request.
|
|
36
|
+
|
|
37
|
+
def headers
|
|
38
|
+
return @headers if @headers
|
|
39
|
+
@headers = meta_vars.merge(header)
|
|
40
|
+
@headers.each do |key, value|
|
|
41
|
+
@headers.delete(key)
|
|
42
|
+
@headers[key.upcase] = value
|
|
43
|
+
end
|
|
44
|
+
@headers
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module Ramaze::Adapter
|
|
51
|
+
class Webrick
|
|
52
|
+
class << self
|
|
53
|
+
|
|
54
|
+
# The method to start a new webrick-adapter on the specified
|
|
55
|
+
# host/ports, will return the first of the started adapters.
|
|
56
|
+
#
|
|
57
|
+
# sets up the default handler for the request/response cycle.
|
|
58
|
+
|
|
59
|
+
def start host, ports
|
|
60
|
+
handler = lambda do |request, response|
|
|
61
|
+
self.new.process(request, response)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
ports.map{|port| run_server(host, port, handler) }.first
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# run the actual server on host/port with the handler given.
|
|
68
|
+
# passes WEBrick::HTTPServlet the default options and starts
|
|
69
|
+
# it up in a new Thread, setting Thread.current[:adapter]
|
|
70
|
+
|
|
71
|
+
def run_server host, port, handler
|
|
72
|
+
options = {
|
|
73
|
+
:Port => port,
|
|
74
|
+
:BindAddress => host,
|
|
75
|
+
:Logger => Informer,
|
|
76
|
+
:AccessLog => [
|
|
77
|
+
[Informer, WEBrick::AccessLog::COMMON_LOG_FORMAT],
|
|
78
|
+
[Informer, WEBrick::AccessLog::REFERER_LOG_FORMAT]
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
server = WEBrick::HTTPServer.new(options)
|
|
83
|
+
server.mount('/', WEBrick::HTTPServlet::ProcHandler.new(handler))
|
|
84
|
+
|
|
85
|
+
Thread.new do
|
|
86
|
+
Thread.current[:task] = :webrick
|
|
87
|
+
Thread.current[:adapter] = server
|
|
88
|
+
server.start
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# doesn't do anything, for the time being.
|
|
93
|
+
|
|
94
|
+
def stop
|
|
95
|
+
debug "stopping WEBrick"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
# process a request and give a response, based on the objects
|
|
100
|
+
# WEBrick gives it.
|
|
101
|
+
#
|
|
102
|
+
# if the Global.inform_tags include :benchmark it will run #bench_process,
|
|
103
|
+
# otherwise simply #respond.
|
|
104
|
+
|
|
105
|
+
def process request, response
|
|
106
|
+
if Global.inform_tags.include?(:benchmark)
|
|
107
|
+
bench_process(request, response)
|
|
108
|
+
else
|
|
109
|
+
respond(response, Dispatcher.handle(request, response))
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# benchmark the current request/respond cycle and output the result
|
|
114
|
+
# via Inform#debug (so make sure you got :debug in your Global.inform_tags
|
|
115
|
+
#
|
|
116
|
+
# It works as a simple wrapper with no other impacts on the rest
|
|
117
|
+
# of the system.
|
|
118
|
+
|
|
119
|
+
def bench_process(request, response)
|
|
120
|
+
time = Benchmark.measure do
|
|
121
|
+
response = respond(response, Dispatcher.handle(request, response))
|
|
122
|
+
end
|
|
123
|
+
debug "#{request} took #{time.real}s"
|
|
124
|
+
response
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
# simply respond to a given request, #set_head and #set_out in the process
|
|
128
|
+
# as well as setting the response-status (which is, in case it is not
|
|
129
|
+
# given, 500, if nothing goes wrong it should be 200 or 302)
|
|
130
|
+
|
|
131
|
+
def respond orig_response, response
|
|
132
|
+
@response = orig_response
|
|
133
|
+
if response
|
|
134
|
+
set_head(response)
|
|
135
|
+
set_out(response)
|
|
136
|
+
@response.status = response.code || STATUS_CODE[:internal_server_error]
|
|
137
|
+
end
|
|
138
|
+
@response
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# map the respond.head[key] to @response[key]
|
|
142
|
+
|
|
143
|
+
def set_head(response)
|
|
144
|
+
response.head.each do |key, val|
|
|
145
|
+
@response[key] = val
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# set the body... in case you have Global.tidy = true it will run it
|
|
150
|
+
# through Tool::Tidy.tidy first (if your content-type is text/html)
|
|
151
|
+
|
|
152
|
+
def set_out response
|
|
153
|
+
@response.body =
|
|
154
|
+
if Global.tidy and response.content_type == 'text/html'
|
|
155
|
+
Tool::Tidy.tidy(response.out)
|
|
156
|
+
else
|
|
157
|
+
response.out
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
data/lib/ramaze/cache.rb
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
|
|
2
|
+
# All files in this distribution are subject to the terms of the Ruby license.
|
|
3
|
+
|
|
4
|
+
module Ramaze
|
|
5
|
+
autoload :MemoryCache, "ramaze/cache/memory.rb"
|
|
6
|
+
autoload :YAMLStoreCache, "ramaze/cache/yaml_store.rb"
|
|
7
|
+
autoload :MemcachedCache, "ramaze/cache/memcached.rb"
|
|
8
|
+
|
|
9
|
+
Cache = nil
|
|
10
|
+
SessionCache = nil
|
|
11
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
|
|
2
|
+
# All files in this distribution are subject to the terms of the Ruby license.
|
|
3
|
+
require 'memcache'
|
|
4
|
+
|
|
5
|
+
module Ramaze
|
|
6
|
+
class MemcachedCache
|
|
7
|
+
def initialize(host = 'localhost', port = '11211', namespace = 'ramaze')
|
|
8
|
+
@cache = MemCache.new("#{host}:#{port}", :namespace => namespace)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# please read the documentation of memcache-client for further methods.
|
|
12
|
+
# also, it is highly recommended to install memcache-client_extensions
|
|
13
|
+
# for a bit of speedup and more functionality
|
|
14
|
+
# Some examples:
|
|
15
|
+
#
|
|
16
|
+
# [key] #=> get a key
|
|
17
|
+
# [key] = value #=> set a key
|
|
18
|
+
# delete(key) #=> delete key
|
|
19
|
+
# set_many :x => :y, :n => :m #=> set many key/value pairs
|
|
20
|
+
# get_hash :x, :y #=> return a hash with key/value pairs
|
|
21
|
+
# stats #=> get some statistics about usage
|
|
22
|
+
# namespace #=> get the current namespace
|
|
23
|
+
# namespace = 'ramaze' #=> set a different namespace ('ramaze' is default)
|
|
24
|
+
# flush_all #=> flush the whole cache (deleting all)
|
|
25
|
+
# compression #=> see if compression is true/false
|
|
26
|
+
# compression = false #=> turn off compression (it's by default true)
|
|
27
|
+
|
|
28
|
+
def method_missing(*args, &block)
|
|
29
|
+
@cache.__send__(*args, &block)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# out of some reason MemCache sometimes doesn't respond to
|
|
33
|
+
# get_multi, have to investigate this further.
|
|
34
|
+
#
|
|
35
|
+
# for now, i'll just use the dumbed down version and ask it
|
|
36
|
+
# whether it implements this functionality or not.
|
|
37
|
+
|
|
38
|
+
def get_multi(*keys)
|
|
39
|
+
if @cache.respond_to?(:get_multi)
|
|
40
|
+
@cache.get_multi(*keys)
|
|
41
|
+
else
|
|
42
|
+
@cache.get_hash(*keys)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# same as get_multi, but returns only the values (in order)
|
|
47
|
+
|
|
48
|
+
def values_at(*keys)
|
|
49
|
+
get_multi(*keys).values_at(*keys)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
|
|
2
|
+
# All files in this distribution are subject to the terms of the Ruby license.
|
|
3
|
+
require 'yaml/store'
|
|
4
|
+
|
|
5
|
+
module Ramaze
|
|
6
|
+
class YAMLStoreCache
|
|
7
|
+
|
|
8
|
+
# create a new YAML::Store with the given file (which will be created if it
|
|
9
|
+
# is not already there).
|
|
10
|
+
|
|
11
|
+
def initialize(file = 'cache.yaml')
|
|
12
|
+
@cache = YAML::Store.new(file)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# return the values for given keys.
|
|
16
|
+
|
|
17
|
+
def values_at(*keys)
|
|
18
|
+
transaction do |y|
|
|
19
|
+
keys.map{|k| y[k]}
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# just a helper to use transactions.
|
|
24
|
+
|
|
25
|
+
def transaction(&block)
|
|
26
|
+
@cache.transaction(&block)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# catch everything else and use a transaction to send it.
|
|
30
|
+
|
|
31
|
+
def method_missing(*args, &block)
|
|
32
|
+
transaction do |y|
|
|
33
|
+
y.send(*args, &block)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
# Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
|
|
2
|
+
# All files in this distribution are subject to the terms of the Ruby license.
|
|
3
|
+
|
|
4
|
+
require 'timeout'
|
|
5
|
+
|
|
6
|
+
module Ramaze
|
|
7
|
+
|
|
8
|
+
# The Dispatcher is the very heart of Ramaze itself.
|
|
9
|
+
#
|
|
10
|
+
# It will take requests and guide the request through all parts of the
|
|
11
|
+
# framework and your application.
|
|
12
|
+
#
|
|
13
|
+
# It is built in a way that lets you easily replace it with something you
|
|
14
|
+
# like better, since i'm very fond of the current implementation you can't
|
|
15
|
+
# find any examples of how this is done exactly yet.
|
|
16
|
+
|
|
17
|
+
module Dispatcher
|
|
18
|
+
class << self
|
|
19
|
+
include Trinity
|
|
20
|
+
|
|
21
|
+
# handle a request/response pair as given by the adapter.
|
|
22
|
+
# has to answer with a response.
|
|
23
|
+
#
|
|
24
|
+
# It is built so it will catch _all_ errors and exceptions
|
|
25
|
+
# thrown during processing of the request and #handle_error if
|
|
26
|
+
# a problem occurs.
|
|
27
|
+
|
|
28
|
+
def handle orig_request, orig_response
|
|
29
|
+
@orig_request, @orig_response = orig_request, orig_response
|
|
30
|
+
respond(orig_response, orig_request)
|
|
31
|
+
rescue Object => exception
|
|
32
|
+
error(exception)
|
|
33
|
+
handle_error(exception)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# The handle_error method takes an exception and decides based on that
|
|
37
|
+
# how it is going to respond in case of an error.
|
|
38
|
+
#
|
|
39
|
+
# In future this will become more and more configurable, right now
|
|
40
|
+
# you can provide your own error-method and error.xhtml inside either
|
|
41
|
+
# your trait[:template_root] or trait[:public].
|
|
42
|
+
#
|
|
43
|
+
# As more and more error-classes are being added to Ramaze you will get
|
|
44
|
+
# the ability to define your own response-pages and/or behaviour like
|
|
45
|
+
# automatic redirects.
|
|
46
|
+
#
|
|
47
|
+
# This feature is only available if your Global.error is true, which is
|
|
48
|
+
# the default.
|
|
49
|
+
#
|
|
50
|
+
# Yes, again, webrick _has_ to be really obscure, I searched for half an hour
|
|
51
|
+
# and still have not the faintest idea how request_path is related to
|
|
52
|
+
# request_uri...
|
|
53
|
+
# anyway, the solution might be simple?
|
|
54
|
+
|
|
55
|
+
def handle_error exception
|
|
56
|
+
meth_debug :handle_error, exception
|
|
57
|
+
Thread.current[:exception] = exception
|
|
58
|
+
|
|
59
|
+
case exception
|
|
60
|
+
when nil #Error::NoAction, Error::NoController
|
|
61
|
+
build_response(exception.message, STATUS_CODE[:not_found])
|
|
62
|
+
else
|
|
63
|
+
if Global.error_page
|
|
64
|
+
req = Thread.current[:request]
|
|
65
|
+
|
|
66
|
+
unless ((req.request_uri.path = '/error') rescue false)
|
|
67
|
+
req.request.params['REQUEST_PATH'] = '/error'
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
fill_out
|
|
71
|
+
else
|
|
72
|
+
build_response(exception.message, STATUS_CODE[:internal_server_error])
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# setup the #setup_environment (Trinity) and start #fill_out
|
|
78
|
+
|
|
79
|
+
def respond orig_response, orig_request
|
|
80
|
+
setup_environment orig_response, orig_request
|
|
81
|
+
fill_out
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
#
|
|
85
|
+
|
|
86
|
+
def build_response out = '', code = STATUS_CODE[:internal_server_error], head = {}
|
|
87
|
+
default_head = {
|
|
88
|
+
'Content-Type' => 'text/plain',
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if Global.cookies
|
|
92
|
+
default_head['Set-Cookie'] = session.export
|
|
93
|
+
else
|
|
94
|
+
head.delete('Set-Cookie')
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
head = default_head.merge(head)
|
|
98
|
+
|
|
99
|
+
Response.new(out, code, head)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
# Obtain the path requested from the request and search for a static
|
|
104
|
+
# file matching the request, #respond_file is called if it finds one,
|
|
105
|
+
# otherwise the path is given on to #respond_action.
|
|
106
|
+
# Answers with a response
|
|
107
|
+
|
|
108
|
+
def fill_out
|
|
109
|
+
path = request.request_path.squeeze('/')
|
|
110
|
+
info "Request from #{request.remote_addr}: #{path}"
|
|
111
|
+
|
|
112
|
+
the_paths = $:.map{|way| (way/'public'/path) }
|
|
113
|
+
if file = the_paths.find{|way| File.exist?(way) and File.file?(way)}
|
|
114
|
+
respond_file file
|
|
115
|
+
else
|
|
116
|
+
respond_action path
|
|
117
|
+
end
|
|
118
|
+
response
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# takes a file and sets the response.out to the contents of the file
|
|
122
|
+
# If you are running mongrel as your adapter it will take advantage of
|
|
123
|
+
# mongrels #send_file
|
|
124
|
+
|
|
125
|
+
def respond_file file
|
|
126
|
+
debug "Responding with static file: #{file}"
|
|
127
|
+
|
|
128
|
+
response.head['Content-Type'] = ''
|
|
129
|
+
if @orig_response.respond_to?(:send_file)
|
|
130
|
+
@orig_response.send_file(file)
|
|
131
|
+
else
|
|
132
|
+
response.out = File.read(file)
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# Takes the path, figures out the controller by asking #resolve_controller
|
|
137
|
+
# for the controller, action and params for the path.
|
|
138
|
+
#
|
|
139
|
+
# Sets the cookies in the response.head if Global.cookies is set
|
|
140
|
+
#
|
|
141
|
+
# finally it runs #handle_controller
|
|
142
|
+
|
|
143
|
+
def respond_action path
|
|
144
|
+
debug "Responding with action: #{path}"
|
|
145
|
+
|
|
146
|
+
controller, action, params = resolve_controller(path)
|
|
147
|
+
catch :respond do
|
|
148
|
+
response.out = handle_controller(controller, action, params)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# find out which controller should be used based on the path.
|
|
153
|
+
# it will answer [controller, action, params] or raise an
|
|
154
|
+
#
|
|
155
|
+
# Ramaze::Error::NoController # if no controller is found
|
|
156
|
+
# Ramaze::Error::NoAction # if no action but a controller is found
|
|
157
|
+
#
|
|
158
|
+
# It actually uses #resolve_action on almost every combination of
|
|
159
|
+
# so-called paractions (yet unsplit but possible combination of action
|
|
160
|
+
# and parameters for the action)
|
|
161
|
+
#
|
|
162
|
+
# If your templating is action-less, which means it does not depend on
|
|
163
|
+
# methods on the controller, but rather on templates or just dynamically
|
|
164
|
+
# calculated stuff you can set trait[:actionless] for your templating.
|
|
165
|
+
#
|
|
166
|
+
# Please see the documentation for Ramaze::Template::Amrita2 for an more
|
|
167
|
+
# specific example of how it is used in practice.
|
|
168
|
+
#
|
|
169
|
+
# Further it uses the Global.mapping to look up the controller to be used.
|
|
170
|
+
#
|
|
171
|
+
# Also, the action '/' will be expanded to 'index'
|
|
172
|
+
#
|
|
173
|
+
# Parameters are CGI.unescaped
|
|
174
|
+
|
|
175
|
+
def resolve_controller path
|
|
176
|
+
meth_debug :resolve_controller, path
|
|
177
|
+
track = path.split('/')
|
|
178
|
+
controller = false
|
|
179
|
+
action = false
|
|
180
|
+
tracks = []
|
|
181
|
+
|
|
182
|
+
track.unshift '/'
|
|
183
|
+
|
|
184
|
+
track.each do |atom|
|
|
185
|
+
tracks << (tracks.last.to_s / atom)
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
until controller and action or tracks.empty?
|
|
189
|
+
current = Regexp.escape(tracks.pop.to_s)
|
|
190
|
+
paraction = path.gsub(/^#{current}/, '').split('/').map{|e| CGI.unescape(e)}
|
|
191
|
+
paraction.delete('')
|
|
192
|
+
if controller = Ramaze::Global.mapping[current]
|
|
193
|
+
if controller.ancestral_trait[:actionless] or paraction == ['error']
|
|
194
|
+
|
|
195
|
+
action = paraction.shift
|
|
196
|
+
params = paraction
|
|
197
|
+
action = 'index' if action == nil
|
|
198
|
+
else
|
|
199
|
+
action, params = resolve_action controller, paraction
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
raise Ramaze::Error::NoController, "No Controller found for #{path}" unless controller
|
|
205
|
+
raise Ramaze::Error::NoAction, "No Action found for #{path}" unless action
|
|
206
|
+
|
|
207
|
+
return controller, action, params
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
# Resolve the method to be called and the number of parameters
|
|
211
|
+
# it will receive for a specific class (the controller) given the
|
|
212
|
+
# paraction (like 'foo/bar' => controller.call('foo', 'bar'))
|
|
213
|
+
# in case arity is 1 and a public instance-method named foo is defined.
|
|
214
|
+
#
|
|
215
|
+
# TODO:
|
|
216
|
+
# - find a solution for def x(a = :a) which has arity -1
|
|
217
|
+
# identical to def x(*a) for some odd reason
|
|
218
|
+
|
|
219
|
+
def resolve_action controller, paraction
|
|
220
|
+
meth_debug :resolve_action, controller, paraction
|
|
221
|
+
|
|
222
|
+
meths =
|
|
223
|
+
(controller.ancestors - [Kernel, Object]).inject([]) do |sum, klass|
|
|
224
|
+
sum | (klass.is_a?(Module) ? klass.instance_methods(false) : sum)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
track = paraction.dup
|
|
228
|
+
tracks = []
|
|
229
|
+
action = false
|
|
230
|
+
|
|
231
|
+
track.each do |atom|
|
|
232
|
+
atom = [tracks.last.to_s, atom]
|
|
233
|
+
atom.delete('')
|
|
234
|
+
tracks << atom.join('__')
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
tracks.unshift 'index'
|
|
238
|
+
|
|
239
|
+
until action or tracks.empty?
|
|
240
|
+
current = tracks.pop
|
|
241
|
+
if meths.include?(current)
|
|
242
|
+
arity = controller.instance_method(current).arity
|
|
243
|
+
params = (paraction - current.split('__'))
|
|
244
|
+
|
|
245
|
+
if params.size == arity
|
|
246
|
+
return current, params
|
|
247
|
+
elsif arity < 0 and arity + params.size >= 0
|
|
248
|
+
return current, params
|
|
249
|
+
elsif arity == -1
|
|
250
|
+
return current, params
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
# Depending on Global.cache_all and Global.cache_actions it will
|
|
257
|
+
# call either #handle_uncached_controller or #handle_cached_controller
|
|
258
|
+
# takes the controller, action and params and just passes them on.
|
|
259
|
+
|
|
260
|
+
def handle_controller controller, action, params
|
|
261
|
+
if Global.cache_all or Global.cache_actions[controller].include?(action.to_s)
|
|
262
|
+
handle_cached_controller(controller, action, *params)
|
|
263
|
+
else
|
|
264
|
+
handle_uncached_controller(controller, action, *params)
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Call the class-method handle_request with action and *params, all
|
|
269
|
+
# the controller has to do is to respond with a string.
|
|
270
|
+
|
|
271
|
+
def handle_uncached_controller controller, action, *params
|
|
272
|
+
controller.handle_request(action, *params)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Call the class-method handle_request with action and *params, all
|
|
276
|
+
# the controller has to do is to respond with a string.
|
|
277
|
+
#
|
|
278
|
+
# To add a method for caching you can either use the CacheHelper
|
|
279
|
+
# or directly
|
|
280
|
+
# Global.cache_actions[self] << 'index'
|
|
281
|
+
#
|
|
282
|
+
# Caching is done for [action, params] pairs per controller.
|
|
283
|
+
|
|
284
|
+
def handle_cached_controller controller, action, *params
|
|
285
|
+
Global.cached_actions ||= Global.cache.new
|
|
286
|
+
|
|
287
|
+
key = [action, params].inspect
|
|
288
|
+
|
|
289
|
+
Global.cached_actions[controller] ||= {key => nil}
|
|
290
|
+
|
|
291
|
+
if out = Global.cached_actions[controller][key]
|
|
292
|
+
debug "Using Cached version for #{key.inspect}"
|
|
293
|
+
return out
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
debug "Compiling Action: #{action} #{params.join(', ')}"
|
|
297
|
+
Global.cached_actions[controller][key] =
|
|
298
|
+
handle_uncached_controller(controller, action, *params)
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Setup the Trinity (Request, Response, Session) and store them as
|
|
302
|
+
# thread-variables in Thread.current
|
|
303
|
+
# Thread.current[:request] == Request.current
|
|
304
|
+
# Thread.current[:response] == Response.current
|
|
305
|
+
# Thread.current[:session] == Session.current
|
|
306
|
+
|
|
307
|
+
def setup_environment orig_response, orig_request
|
|
308
|
+
this = Thread.current
|
|
309
|
+
this[:request] = Request.new(orig_request)
|
|
310
|
+
this[:session] = Session.new(request)
|
|
311
|
+
this[:response] = build_response('', STATUS_CODE[:ok], 'Content-Type' => 'text/html')
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
end
|