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
|
@@ -1,111 +1,32 @@
|
|
|
1
1
|
# Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
|
|
2
2
|
# All files in this distribution are subject to the terms of the Ruby license.
|
|
3
3
|
|
|
4
|
-
require '
|
|
4
|
+
require 'ramaze/adapter'
|
|
5
5
|
|
|
6
6
|
require 'mongrel'
|
|
7
|
-
require 'ramaze/tool/tidy'
|
|
8
7
|
|
|
9
8
|
# for OSX compatibility
|
|
10
9
|
Socket.do_not_reverse_lookup = true
|
|
11
10
|
|
|
12
|
-
module Mongrel
|
|
13
|
-
class Configurator
|
|
14
|
-
|
|
15
|
-
# the default for log is Informer#<< like WEBrick
|
|
16
|
-
|
|
17
|
-
def log(msg)
|
|
18
|
-
Informer << "Mongrel: #{msg}"
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
11
|
module Ramaze::Adapter
|
|
24
|
-
class Mongrel <
|
|
25
|
-
|
|
12
|
+
class Mongrel < Base
|
|
26
13
|
class << self
|
|
27
|
-
|
|
28
|
-
# starts a range of servers on the given host/ports.
|
|
29
|
-
# answers with the first adapter it creates.
|
|
30
|
-
|
|
31
14
|
def start host, ports
|
|
32
15
|
ports.map{|port| run_server(host, port) }.first
|
|
33
16
|
end
|
|
34
17
|
|
|
35
|
-
# run the actual adapter on host/port, answering with the Thread
|
|
36
|
-
# mongrel creates.
|
|
37
|
-
|
|
38
18
|
def run_server host, port
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
h.run
|
|
19
|
+
server = ::Mongrel::HttpServer.new(host, port)
|
|
20
|
+
server.register('/', ::Rack::Handler::Mongrel.new(self))
|
|
21
|
+
server.run
|
|
43
22
|
end
|
|
44
23
|
|
|
45
|
-
# doesn't do anything, for the time being.
|
|
46
|
-
|
|
47
24
|
def stop
|
|
48
|
-
debug "stopping Mongrel"
|
|
49
25
|
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
# Process a request and give a response, based on the objects
|
|
53
|
-
# Mongrel gives it.
|
|
54
|
-
#
|
|
55
|
-
# if the Global.inform_tags include :benchmark it will run #bench_process,
|
|
56
|
-
# otherwise simply #respond.
|
|
57
26
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Global.inform_tags.include?(:benchmark) ? bench_respond : respond
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
# benchmark the current request/respond cycle and output the result
|
|
64
|
-
# via Inform#debug (so make sure you got :debug in your Global.inform_tags
|
|
65
|
-
#
|
|
66
|
-
# It works as a simple wrapper with no other impacts on the rest
|
|
67
|
-
# of the system.
|
|
68
|
-
|
|
69
|
-
def bench_respond
|
|
70
|
-
time = Benchmark.measure do
|
|
71
|
-
respond
|
|
72
|
-
end
|
|
73
|
-
info "request took #{time.real}s"
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# simply respond to a given request, #set_head and #set_out in the process
|
|
77
|
-
# as well as setting the response-status (which is, in case it is not
|
|
78
|
-
# given, 500, if nothing goes wrong it should be 200 or 302)
|
|
79
|
-
|
|
80
|
-
def respond
|
|
81
|
-
@our_response = Dispatcher.handle(@request, @response)
|
|
82
|
-
code = @our_response.code || STATUS_CODE[:internal_server_error]
|
|
83
|
-
@response.start(code) do |head, out|
|
|
84
|
-
set_head head
|
|
85
|
-
set_out out
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
# map the respond.head[key] to @response[key]
|
|
90
|
-
|
|
91
|
-
def set_head head
|
|
92
|
-
@our_response.head.each do |key, value|
|
|
93
|
-
head[key] = value
|
|
27
|
+
def call(env)
|
|
28
|
+
new.call(env)
|
|
94
29
|
end
|
|
95
30
|
end
|
|
96
|
-
|
|
97
|
-
# set the body... in case you have Global.tidy = true it will run it
|
|
98
|
-
# through Tool::Tidy.tidy first (if your content-type is text/html)
|
|
99
|
-
|
|
100
|
-
def set_out out
|
|
101
|
-
our_out =
|
|
102
|
-
if Global.tidy and @our_response.content_type == 'text/html'
|
|
103
|
-
Tool::Tidy.tidy(@our_response.out)
|
|
104
|
-
else
|
|
105
|
-
@our_response.out
|
|
106
|
-
end
|
|
107
|
-
out << our_out
|
|
108
|
-
end
|
|
109
|
-
|
|
110
31
|
end
|
|
111
32
|
end
|
|
@@ -1,161 +1,42 @@
|
|
|
1
1
|
# Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
|
|
2
2
|
# All files in this distribution are subject to the terms of the Ruby license.
|
|
3
3
|
|
|
4
|
-
require '
|
|
5
|
-
require 'webrick'
|
|
6
|
-
require 'benchmark'
|
|
7
|
-
|
|
8
|
-
require 'ramaze/tool/tidy'
|
|
4
|
+
require 'ramaze/adapter'
|
|
9
5
|
|
|
10
|
-
|
|
11
|
-
Socket.do_not_reverse_lookup = true
|
|
6
|
+
require 'webrick'
|
|
12
7
|
|
|
13
8
|
module WEBrick
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
|
9
|
+
module HTTPServlet
|
|
10
|
+
class ProcHandler
|
|
11
|
+
alias do_PUT do_GET
|
|
12
|
+
alias do_DELETE do_GET
|
|
33
13
|
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
14
|
end
|
|
48
15
|
end
|
|
49
16
|
|
|
50
17
|
module Ramaze::Adapter
|
|
51
|
-
class Webrick
|
|
18
|
+
class Webrick < Base
|
|
52
19
|
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
20
|
def start host, ports
|
|
60
|
-
|
|
61
|
-
self.new.process(request, response)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
ports.map{|port| run_server(host, port, handler) }.first
|
|
21
|
+
ports.map{|port| run_server(host, port) }.first
|
|
65
22
|
end
|
|
66
23
|
|
|
67
|
-
|
|
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
|
|
24
|
+
def run_server host, port, options = {}
|
|
72
25
|
options = {
|
|
73
26
|
:Port => port,
|
|
74
27
|
:BindAddress => host,
|
|
75
|
-
:Logger => Informer,
|
|
28
|
+
:Logger => Ramaze::Informer,
|
|
76
29
|
:AccessLog => [
|
|
77
|
-
[Informer, WEBrick::AccessLog::COMMON_LOG_FORMAT],
|
|
78
|
-
[Informer, WEBrick::AccessLog::REFERER_LOG_FORMAT]
|
|
30
|
+
[Ramaze::Informer, WEBrick::AccessLog::COMMON_LOG_FORMAT],
|
|
31
|
+
[Ramaze::Informer, WEBrick::AccessLog::REFERER_LOG_FORMAT]
|
|
79
32
|
]
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
server = WEBrick::HTTPServer.new(options)
|
|
83
|
-
server.mount('/', WEBrick::HTTPServlet::ProcHandler.new(handler))
|
|
33
|
+
}.merge(options)
|
|
84
34
|
|
|
85
35
|
Thread.new do
|
|
86
36
|
Thread.current[:task] = :webrick
|
|
87
|
-
|
|
88
|
-
server.start
|
|
37
|
+
Rack::Handler::WEBrick.run(self, options)
|
|
89
38
|
end
|
|
90
39
|
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
40
|
end
|
|
160
41
|
end
|
|
161
42
|
end
|
|
@@ -4,6 +4,12 @@ require 'memcache'
|
|
|
4
4
|
|
|
5
5
|
module Ramaze
|
|
6
6
|
class MemcachedCache
|
|
7
|
+
|
|
8
|
+
# Create a new MemcachedCache with host, port and a namespace that defaults
|
|
9
|
+
# to 'ramaze'
|
|
10
|
+
#
|
|
11
|
+
# For your own usage you should use another namespace.
|
|
12
|
+
|
|
7
13
|
def initialize(host = 'localhost', port = '11211', namespace = 'ramaze')
|
|
8
14
|
@cache = MemCache.new("#{host}:#{port}", :namespace => namespace)
|
|
9
15
|
end
|
data/lib/ramaze/controller.rb
CHANGED
|
@@ -1,10 +1,300 @@
|
|
|
1
1
|
# Copyright (c) 2006 Michael Fellinger m.fellinger@gmail.com
|
|
2
2
|
# All files in this distribution are subject to the terms of the Ruby license.
|
|
3
3
|
|
|
4
|
-
require 'ramaze/
|
|
4
|
+
require 'ramaze/template'
|
|
5
5
|
|
|
6
6
|
module Ramaze
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
# The Controller is responsible for combining and rendering actions.
|
|
9
|
+
|
|
10
|
+
class Controller
|
|
8
11
|
include Ramaze::Helper
|
|
12
|
+
extend Ramaze::Helper
|
|
13
|
+
|
|
14
|
+
helper :redirect, :link
|
|
15
|
+
|
|
16
|
+
trait :template_extensions => { }
|
|
17
|
+
|
|
18
|
+
# Path to the ramaze-internal public directory for error-pages and the like.
|
|
19
|
+
# It acts just as a shadow.
|
|
20
|
+
trait :public => ( ::Ramaze::BASEDIR / 'proto' / 'public' )
|
|
21
|
+
|
|
22
|
+
class << self
|
|
23
|
+
include Ramaze::Helper
|
|
24
|
+
extend Ramaze::Helper
|
|
25
|
+
|
|
26
|
+
def handle path
|
|
27
|
+
controller, action, params = *resolve_controller(path)
|
|
28
|
+
action, params = path.gsub(/^\//, '').split('/').join('__'), [] unless action
|
|
29
|
+
controller = self unless controller
|
|
30
|
+
controller.render action, *params
|
|
31
|
+
rescue Ramaze::Error::Template => ex
|
|
32
|
+
puts ex
|
|
33
|
+
''
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# find out which controller should be used based on the path.
|
|
37
|
+
# it will answer [controller, action, params] or raise an
|
|
38
|
+
#
|
|
39
|
+
# Ramaze::Error::NoController # if no controller is found
|
|
40
|
+
# Ramaze::Error::NoAction # if no action but a controller is found
|
|
41
|
+
#
|
|
42
|
+
# It actually uses #resolve_action on almost every combination of
|
|
43
|
+
# so-called paractions (yet unsplit but possible combination of action
|
|
44
|
+
# and parameters for the action)
|
|
45
|
+
#
|
|
46
|
+
# If your templating is action-less, which means it does not depend on
|
|
47
|
+
# methods on the controller, but rather on templates or just dynamically
|
|
48
|
+
# calculated stuff you can set trait[:actionless] for your templating.
|
|
49
|
+
#
|
|
50
|
+
# Please see the documentation for Ramaze::Template::Amrita2 for an more
|
|
51
|
+
# specific example of how it is used in practice.
|
|
52
|
+
#
|
|
53
|
+
# Further it uses the Global.mapping to look up the controller to be used.
|
|
54
|
+
#
|
|
55
|
+
# Also, the action '/' will be expanded to 'index'
|
|
56
|
+
#
|
|
57
|
+
# Parameters are CGI.unescaped
|
|
58
|
+
|
|
59
|
+
def resolve_controller path
|
|
60
|
+
Informer.meth_debug :resolve_controller, path
|
|
61
|
+
track = path.split('/')
|
|
62
|
+
controller = false
|
|
63
|
+
action = false
|
|
64
|
+
tracks = []
|
|
65
|
+
|
|
66
|
+
track.unshift '/'
|
|
67
|
+
|
|
68
|
+
track.each do |atom|
|
|
69
|
+
tracks << (tracks.last.to_s / atom)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
until controller and action or tracks.empty?
|
|
73
|
+
current = Regexp.escape(tracks.pop.to_s)
|
|
74
|
+
paraction = path.gsub(/^#{current}/, '').split('/').map{|e| CGI.unescape(e)}
|
|
75
|
+
paraction.delete('')
|
|
76
|
+
if controller = Ramaze::Global.mapping[current] and controller.respond_to?(:render)
|
|
77
|
+
if paraction == ['error']
|
|
78
|
+
|
|
79
|
+
action = paraction.shift
|
|
80
|
+
params = paraction
|
|
81
|
+
action = 'index' if action == nil
|
|
82
|
+
else
|
|
83
|
+
action, params = resolve_action controller, paraction
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
return controller, action, params
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Resolve the method to be called and the number of parameters
|
|
92
|
+
# it will receive for a specific class (the controller) given the
|
|
93
|
+
# paraction (like 'foo/bar' => controller.call('foo', 'bar'))
|
|
94
|
+
# in case arity is 1 and a public instance-method named foo is defined.
|
|
95
|
+
#
|
|
96
|
+
# TODO:
|
|
97
|
+
# - find a solution for def x(a = :a) which has arity -1
|
|
98
|
+
# identical to def x(*a) for some odd reason
|
|
99
|
+
|
|
100
|
+
def resolve_action controller, paraction
|
|
101
|
+
Informer.meth_debug :resolve_action, controller, paraction
|
|
102
|
+
|
|
103
|
+
meths =
|
|
104
|
+
(controller.ancestors - [Kernel, Object]).inject([]) do |sum, klass|
|
|
105
|
+
sum | (klass.is_a?(Module) ? klass.instance_methods(false) : sum)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
track = paraction.dup
|
|
109
|
+
tracks = []
|
|
110
|
+
action = false
|
|
111
|
+
|
|
112
|
+
track.each do |atom|
|
|
113
|
+
atom = [tracks.last.to_s, atom]
|
|
114
|
+
atom.delete('')
|
|
115
|
+
tracks << atom.join('__')
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
tracks.unshift 'index'
|
|
119
|
+
|
|
120
|
+
until action or tracks.empty?
|
|
121
|
+
current = tracks.pop
|
|
122
|
+
if meths.include?(current) #or current = controller.ancestral_trait[:template_map][current]
|
|
123
|
+
arity = controller.instance_method(current).arity
|
|
124
|
+
params = (paraction - current.split('__'))
|
|
125
|
+
|
|
126
|
+
if params.size == arity
|
|
127
|
+
return current, params
|
|
128
|
+
elsif arity < 0
|
|
129
|
+
return current, params
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# The universal #render method that has to be provided by every
|
|
136
|
+
# prospective Controller, pass it your action and parameters.
|
|
137
|
+
#
|
|
138
|
+
# This is called upon by the Dispatcher, but you can use it in your
|
|
139
|
+
# Controller/View to get the contents of another action.
|
|
140
|
+
#
|
|
141
|
+
# It will set the instance-variable @action in the instance of itself
|
|
142
|
+
# to the value of the current action.
|
|
143
|
+
|
|
144
|
+
def render action, *parameter
|
|
145
|
+
trait[:actions_cached] ||= Set.new
|
|
146
|
+
|
|
147
|
+
cache_indicators = [
|
|
148
|
+
Global.cache_all,
|
|
149
|
+
ancestral_trait[:cache_all],
|
|
150
|
+
ancestral_trait[:actions_cached].map{|k| k.to_s}.include?(action.to_s),
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
if cache_indicators.any?
|
|
154
|
+
cached_render(action, *parameter)
|
|
155
|
+
else
|
|
156
|
+
uncached_render(action, *parameter)
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def uncached_render action, *parameter
|
|
161
|
+
controller = self.new
|
|
162
|
+
controller.instance_variable_set('@action', action)
|
|
163
|
+
|
|
164
|
+
file = find_template(action)
|
|
165
|
+
engine = ancestral_trait[:engine] || engine_for(file)
|
|
166
|
+
|
|
167
|
+
options = {
|
|
168
|
+
:file => file,
|
|
169
|
+
:binding => controller.send(:send, :binding),
|
|
170
|
+
:action => action,
|
|
171
|
+
:parameter => parameter,
|
|
172
|
+
}
|
|
173
|
+
engine.transform(controller, options)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def cached_render action, *parameter
|
|
177
|
+
key = [action, parameter].inspect
|
|
178
|
+
|
|
179
|
+
trait[:action_cache] ||= Global.cache.new
|
|
180
|
+
|
|
181
|
+
if out = ancestral_trait[:action_cache][key]
|
|
182
|
+
Informer.debug "Using Cached version for #{key}"
|
|
183
|
+
return out
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
Informer.debug "Compiling Action: #{action} #{parameter.join(', ')}"
|
|
187
|
+
ancestral_trait[:action_cache][key] = uncached_render(action, *parameter)
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
# This finds the template for the given action on the current controller
|
|
191
|
+
# there are some basic ways how you can provide an alternative path:
|
|
192
|
+
#
|
|
193
|
+
# Global.template_root = 'default/path'
|
|
194
|
+
#
|
|
195
|
+
# class FooController < Controller
|
|
196
|
+
# trait :template_root => 'another/path'
|
|
197
|
+
# trait :index_template => :foo
|
|
198
|
+
#
|
|
199
|
+
# def index
|
|
200
|
+
# end
|
|
201
|
+
# end
|
|
202
|
+
#
|
|
203
|
+
# One feature also used in the above example is the custom template for
|
|
204
|
+
# one action, in this case :index - now the template of :foo will be
|
|
205
|
+
# used instead.
|
|
206
|
+
|
|
207
|
+
def find_template action, klass = self
|
|
208
|
+
custom_template = ancestral_trait["#{action}_template".intern]
|
|
209
|
+
action = (custom_template ? custom_template : action).to_s
|
|
210
|
+
action_converted = action.split('__').inject {|s,v| "#{s}/#{v}"}
|
|
211
|
+
|
|
212
|
+
first_path =
|
|
213
|
+
if template_root = klass.ancestral_trait[:template_root]
|
|
214
|
+
template_root
|
|
215
|
+
else
|
|
216
|
+
Global.template_root / Global.mapping.invert[self]
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
extensions = [ancestral_trait[:template_extensions].values].flatten.uniq
|
|
220
|
+
|
|
221
|
+
paths = [ first_path, ancestral_trait[:public], ].
|
|
222
|
+
map{|pa| [ pa / action, pa / action_converted ] }.
|
|
223
|
+
flatten.map{|pa| File.expand_path(pa) }.join(',')
|
|
224
|
+
|
|
225
|
+
glob = "{#{paths}}.{#{extensions.join(',')}}"
|
|
226
|
+
|
|
227
|
+
possible = Dir[glob]
|
|
228
|
+
possible.first
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# lookup the trait[:template_extensions] for the extname of the filename
|
|
232
|
+
# you pass.
|
|
233
|
+
#
|
|
234
|
+
# Answers with the engine that matches the extension, Template::Ezamar
|
|
235
|
+
# is used if none matches.
|
|
236
|
+
|
|
237
|
+
def engine_for file
|
|
238
|
+
file = file.to_s
|
|
239
|
+
extension = File.extname(file).gsub(/^\./, '')
|
|
240
|
+
engines = trait[:template_extensions]
|
|
241
|
+
engines.find{|k,v| v == extension or [v].flatten.include?(extension)}.first
|
|
242
|
+
rescue
|
|
243
|
+
Template::Ezamar
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
# This method is called by templating-engines to register themselves with
|
|
247
|
+
# a list of extensions that will be looked up on #render of an action.
|
|
248
|
+
|
|
249
|
+
def register_engine engine, *extensions
|
|
250
|
+
trait[:template_extensions][engine] = [extensions].flatten.uniq
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# the default error-page handler. you can overwrite this method
|
|
255
|
+
# in your controller and create your own error-template for use.
|
|
256
|
+
#
|
|
257
|
+
# Error-pages can be in whatever the templating-engine of your controller
|
|
258
|
+
# is set to.
|
|
259
|
+
# Thread.current[:exception]
|
|
260
|
+
# holds the exception thrown.
|
|
261
|
+
|
|
262
|
+
def error
|
|
263
|
+
error = Thread.current[:exception]
|
|
264
|
+
backtrace = error.backtrace[0..20]
|
|
265
|
+
title = error.message
|
|
266
|
+
|
|
267
|
+
colors = []
|
|
268
|
+
min = 200
|
|
269
|
+
max = 255
|
|
270
|
+
step = -((max - min) / backtrace.size).abs
|
|
271
|
+
max.step(min, step) do |color|
|
|
272
|
+
colors << color
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
backtrace.map! do |line|
|
|
276
|
+
file, lineno, meth = *Ramaze.caller_info
|
|
277
|
+
backtrace_size = Ramaze::Global.inform_backtrace_size
|
|
278
|
+
lines = Ramaze.caller_lines(file, lineno, backtrace_size)
|
|
279
|
+
|
|
280
|
+
[ lines, lines.object_id.abs, file, lineno, meth ]
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
response.status = 404
|
|
284
|
+
|
|
285
|
+
@backtrace = backtrace
|
|
286
|
+
@colors = colors
|
|
287
|
+
@title = CGI.escapeHTML(title)
|
|
288
|
+
require 'coderay'
|
|
289
|
+
@coderay = true
|
|
290
|
+
rescue LoadError => ex
|
|
291
|
+
@coderay = false
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
private
|
|
295
|
+
|
|
296
|
+
def render *args
|
|
297
|
+
self.class.handle(*args)
|
|
298
|
+
end
|
|
9
299
|
end
|
|
10
300
|
end
|