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.
Files changed (193) hide show
  1. data/Rakefile +52 -19
  2. data/bin/ramaze +19 -6
  3. data/doc/CHANGELOG +33 -0
  4. data/doc/COPYING +1 -1
  5. data/doc/FAQ +92 -0
  6. data/doc/GPL +340 -0
  7. data/doc/INSTALL +34 -0
  8. data/doc/ProjectInfo +53 -0
  9. data/doc/README +187 -110
  10. data/doc/readme_chunks/appendix.txt +13 -0
  11. data/doc/readme_chunks/examples.txt +38 -0
  12. data/doc/readme_chunks/features.txt +82 -0
  13. data/doc/readme_chunks/getting_help.txt +5 -0
  14. data/doc/readme_chunks/getting_started.txt +18 -0
  15. data/doc/readme_chunks/installing.txt +41 -0
  16. data/doc/readme_chunks/introduction.txt +18 -0
  17. data/doc/readme_chunks/principles.txt +41 -0
  18. data/doc/readme_chunks/thanks.txt +59 -0
  19. data/doc/tutorial/todolist.txt +546 -0
  20. data/examples/blog/main.rb +1 -1
  21. data/examples/blog/src/controller.rb +13 -11
  22. data/examples/blog/src/element.rb +11 -6
  23. data/examples/blog/src/model.rb +8 -23
  24. data/examples/blog/template/edit.xhtml +3 -1
  25. data/examples/blog/template/index.xhtml +4 -4
  26. data/examples/caching.rb +4 -4
  27. data/examples/element.rb +10 -7
  28. data/examples/hello.rb +3 -4
  29. data/examples/simple.rb +5 -3
  30. data/examples/templates/template/external.amrita +19 -0
  31. data/examples/templates/template/{external.rmze → external.zmr} +2 -2
  32. data/examples/templates/template_amrita2.rb +48 -0
  33. data/examples/templates/template_erubis.rb +5 -2
  34. data/examples/templates/{template_ramaze.rb → template_ezamar.rb} +13 -7
  35. data/examples/templates/template_haml.rb +4 -1
  36. data/examples/templates/template_liquid.rb +2 -1
  37. data/examples/templates/template_markaby.rb +2 -1
  38. data/examples/todolist/conf/benchmark.yaml +35 -0
  39. data/examples/todolist/conf/debug.yaml +34 -0
  40. data/examples/todolist/conf/live.yaml +33 -0
  41. data/examples/todolist/conf/silent.yaml +31 -0
  42. data/examples/todolist/conf/stage.yaml +33 -0
  43. data/examples/todolist/main.rb +18 -0
  44. data/examples/todolist/public/404.jpg +0 -0
  45. data/examples/todolist/public/css/coderay.css +105 -0
  46. data/examples/todolist/public/css/ramaze_error.css +42 -0
  47. data/{lib/proto → examples/todolist}/public/error.xhtml +0 -0
  48. data/examples/todolist/public/favicon.ico +0 -0
  49. data/examples/todolist/public/js/jquery.js +1923 -0
  50. data/examples/todolist/public/ramaze.png +0 -0
  51. data/examples/todolist/src/controller/main.rb +56 -0
  52. data/examples/todolist/src/element/page.rb +26 -0
  53. data/examples/todolist/src/model.rb +14 -0
  54. data/examples/todolist/template/index.xhtml +17 -0
  55. data/examples/todolist/template/new.xhtml +7 -0
  56. data/examples/todolist/todolist.db +9 -0
  57. data/examples/whywiki/main.rb +3 -8
  58. data/examples/whywiki/template/show.xhtml +4 -0
  59. data/lib/proto/public/error.zmr +77 -0
  60. data/lib/proto/src/controller/main.rb +2 -1
  61. data/lib/proto/src/element/page.rb +2 -1
  62. data/lib/proto/src/model.rb +3 -2
  63. data/lib/ramaze.rb +7 -9
  64. data/lib/ramaze/adapter.rb +51 -0
  65. data/lib/ramaze/adapter/cgi.rb +23 -0
  66. data/lib/ramaze/adapter/fcgi.rb +22 -0
  67. data/lib/ramaze/adapter/mongrel.rb +7 -86
  68. data/lib/ramaze/adapter/webrick.rb +14 -133
  69. data/lib/ramaze/cache/memcached.rb +6 -0
  70. data/lib/ramaze/cache/yaml_store.rb +3 -1
  71. data/lib/ramaze/controller.rb +292 -2
  72. data/lib/ramaze/dispatcher.rb +85 -213
  73. data/lib/ramaze/error.rb +10 -0
  74. data/lib/ramaze/global.rb +8 -0
  75. data/lib/ramaze/helper/aspect.rb +30 -7
  76. data/lib/ramaze/helper/auth.rb +16 -9
  77. data/lib/ramaze/helper/cache.rb +40 -35
  78. data/lib/ramaze/helper/feed.rb +1 -1
  79. data/lib/ramaze/helper/flash.rb +34 -0
  80. data/lib/ramaze/helper/link.rb +8 -2
  81. data/lib/ramaze/helper/openid.rb +63 -0
  82. data/lib/ramaze/helper/redirect.rb +12 -11
  83. data/lib/ramaze/helper/stack.rb +5 -7
  84. data/lib/ramaze/inform.rb +12 -1
  85. data/lib/ramaze/snippets/kernel/aquire.rb +1 -1
  86. data/lib/ramaze/snippets/kernel/{self_method.rb → method.rb} +3 -18
  87. data/lib/ramaze/snippets/kernel/{rescue_require.rb → pretty_inspect.rb} +7 -6
  88. data/lib/ramaze/snippets/method/name.rb +22 -0
  89. data/lib/ramaze/snippets/{kernel → ramaze}/autoreload.rb +0 -0
  90. data/lib/ramaze/snippets/ramaze/caller_info.rb +14 -0
  91. data/lib/ramaze/snippets/{kernel → ramaze}/caller_lines.rb +3 -10
  92. data/lib/ramaze/snippets/rdoc/usage_no_exit.rb +49 -23
  93. data/lib/ramaze/snippets/string/DIVIDE.rb +0 -1
  94. data/lib/ramaze/store/default.rb +58 -2
  95. data/lib/ramaze/store/yaml.rb +161 -0
  96. data/lib/ramaze/template.rb +27 -86
  97. data/lib/ramaze/template/amrita2.rb +14 -19
  98. data/lib/ramaze/template/erubis.rb +15 -38
  99. data/lib/ramaze/template/ezamar.rb +100 -0
  100. data/lib/ramaze/template/ezamar/element.rb +166 -0
  101. data/lib/ramaze/template/ezamar/engine.rb +124 -0
  102. data/lib/ramaze/template/ezamar/morpher.rb +155 -0
  103. data/lib/ramaze/template/haml.rb +16 -43
  104. data/lib/ramaze/template/liquid.rb +11 -51
  105. data/lib/ramaze/template/markaby.rb +44 -42
  106. data/lib/ramaze/tool/mime.rb +18 -0
  107. data/lib/ramaze/tool/mime_types.yaml +615 -0
  108. data/lib/ramaze/trinity/request.rb +20 -196
  109. data/lib/ramaze/trinity/response.rb +4 -33
  110. data/lib/ramaze/trinity/session.rb +150 -72
  111. data/lib/ramaze/version.rb +1 -1
  112. data/spec/adapter_spec.rb +20 -0
  113. data/spec/public/favicon.ico +0 -0
  114. data/spec/public/ramaze.png +0 -0
  115. data/spec/public/test_download.css +141 -0
  116. data/spec/{tc_request.rb → request_tc_helper.rb} +45 -21
  117. data/spec/spec_all.rb +77 -34
  118. data/spec/spec_helper.rb +8 -157
  119. data/spec/spec_helper_context.rb +72 -0
  120. data/spec/spec_helper_requester.rb +52 -0
  121. data/spec/spec_helper_simple_http.rb +433 -0
  122. data/spec/tc_adapter_mongrel.rb +3 -15
  123. data/spec/tc_adapter_webrick.rb +4 -14
  124. data/spec/tc_cache.rb +3 -5
  125. data/spec/tc_controller.rb +22 -12
  126. data/spec/tc_dependencies.rb +13 -0
  127. data/spec/tc_element.rb +8 -7
  128. data/spec/tc_error.rb +13 -7
  129. data/spec/tc_global.rb +16 -18
  130. data/spec/tc_helper_aspect.rb +2 -4
  131. data/spec/tc_helper_auth.rb +15 -14
  132. data/spec/tc_helper_cache.rb +5 -7
  133. data/spec/tc_helper_feed.rb +0 -2
  134. data/spec/tc_helper_flash.rb +103 -0
  135. data/spec/tc_helper_form.rb +4 -6
  136. data/spec/tc_helper_link.rb +1 -3
  137. data/spec/tc_helper_redirect.rb +23 -8
  138. data/spec/tc_helper_stack.rb +31 -15
  139. data/spec/tc_morpher.rb +1 -3
  140. data/spec/tc_params.rb +48 -7
  141. data/spec/tc_request_mongrel.rb +9 -0
  142. data/spec/tc_request_webrick.rb +5 -0
  143. data/spec/tc_session.rb +41 -25
  144. data/spec/tc_store.rb +55 -6
  145. data/spec/tc_store_yaml.rb +71 -0
  146. data/spec/tc_template_amrita2.rb +3 -3
  147. data/spec/tc_template_erubis.rb +2 -3
  148. data/spec/{tc_template_ramaze.rb → tc_template_ezamar.rb} +15 -5
  149. data/spec/tc_template_haml.rb +4 -3
  150. data/spec/tc_template_liquid.rb +3 -4
  151. data/spec/tc_template_markaby.rb +4 -6
  152. data/spec/tc_tidy.rb +1 -3
  153. data/spec/template/amrita2/{data.html → data.amrita} +0 -0
  154. data/spec/template/amrita2/{index.html → index.amrita} +0 -0
  155. data/spec/template/amrita2/{sum.html → sum.amrita} +0 -0
  156. data/spec/template/ezamar/another/long/action.zmr +1 -0
  157. data/spec/template/ezamar/combined.zmr +1 -0
  158. data/spec/template/{ramaze/file_only.rmze → ezamar/file_only.zmr} +0 -0
  159. data/spec/template/{ramaze/index.rmze → ezamar/index.zmr} +0 -0
  160. data/spec/template/{ramaze/nested.rmze → ezamar/nested.zmr} +0 -0
  161. data/spec/template/ezamar/some__long__action.zmr +1 -0
  162. data/spec/template/{ramaze/sum.rmze → ezamar/sum.zmr} +0 -0
  163. metadata +181 -123
  164. data/doc/allison/LICENSE +0 -184
  165. data/doc/allison/README +0 -37
  166. data/doc/allison/allison.css +0 -300
  167. data/doc/allison/allison.gif +0 -0
  168. data/doc/allison/allison.js +0 -307
  169. data/doc/allison/allison.rb +0 -287
  170. data/doc/allison/cache/BODY +0 -588
  171. data/doc/allison/cache/CLASS_INDEX +0 -4
  172. data/doc/allison/cache/CLASS_PAGE +0 -1
  173. data/doc/allison/cache/FILE_INDEX +0 -4
  174. data/doc/allison/cache/FILE_PAGE +0 -1
  175. data/doc/allison/cache/FONTS +0 -1
  176. data/doc/allison/cache/FR_INDEX_BODY +0 -1
  177. data/doc/allison/cache/IMGPATH +0 -1
  178. data/doc/allison/cache/INDEX +0 -1
  179. data/doc/allison/cache/JAVASCRIPT +0 -307
  180. data/doc/allison/cache/METHOD_INDEX +0 -4
  181. data/doc/allison/cache/METHOD_LIST +0 -1
  182. data/doc/allison/cache/SRC_PAGE +0 -1
  183. data/doc/allison/cache/STYLE +0 -322
  184. data/doc/allison/cache/URL +0 -1
  185. data/doc/changes.txt +0 -2021
  186. data/doc/changes.xml +0 -2024
  187. data/lib/ramaze/snippets/kernel/silently.rb +0 -13
  188. data/lib/ramaze/snippets/thread/deadQUESTIONMARK.rb +0 -11
  189. data/lib/ramaze/template/haml/actionview_stub.rb +0 -20
  190. data/lib/ramaze/template/ramaze.rb +0 -177
  191. data/lib/ramaze/template/ramaze/element.rb +0 -166
  192. data/lib/ramaze/template/ramaze/morpher.rb +0 -156
  193. 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 'benchmark'
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 < ::Mongrel::HttpHandler
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
- h = ::Mongrel::HttpServer.new host, port
40
- h.register "/", self.new
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
- def process(request, response)
59
- @request, @response = request, response
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 'cgi'
5
- require 'webrick'
6
- require 'benchmark'
7
-
8
- require 'ramaze/tool/tidy'
4
+ require 'ramaze/adapter'
9
5
 
10
- # for OSX compatibility
11
- Socket.do_not_reverse_lookup = true
6
+ require 'webrick'
12
7
 
13
8
  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
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
- handler = lambda do |request, response|
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
- # 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
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
- Thread.current[:adapter] = server
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
@@ -23,7 +23,9 @@ module Ramaze
23
23
  # just a helper to use transactions.
24
24
 
25
25
  def transaction(&block)
26
- @cache.transaction(&block)
26
+ @cache.transaction do
27
+ yield(@cache)
28
+ end
27
29
  end
28
30
 
29
31
  # catch everything else and use a transaction to send it.
@@ -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/helper'
4
+ require 'ramaze/template'
5
5
 
6
6
  module Ramaze
7
- module Controller
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