nitro 0.8.0 → 0.9.3

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 (198) hide show
  1. data/AUTHORS +3 -4
  2. data/ChangeLog +418 -0
  3. data/LICENSE +1 -1
  4. data/README +157 -89
  5. data/RELEASES +50 -0
  6. data/Rakefile +5 -7
  7. data/benchmark/nitro/bench.rb +5 -0
  8. data/benchmark/nitro/simple-webrick-n-200.txt +44 -0
  9. data/benchmark/nitro/static-webrick-n-200.txt +43 -0
  10. data/benchmark/nitro/tiny-lhttpd-n-200-c-5.txt +43 -0
  11. data/benchmark/nitro/tiny-webrick-n-200-c-5.txt +44 -0
  12. data/benchmark/nitro/tiny-webrick-n-200.txt +44 -0
  13. data/benchmark/nitro/tiny2-webrick-n-200.txt +44 -0
  14. data/{lib/nitro/server/cluster.rb → bin/cluster} +26 -30
  15. data/bin/proto/README +2 -2
  16. data/bin/proto/{apache.conf → conf/apache.conf} +0 -0
  17. data/bin/proto/conf/app.conf.rb +22 -0
  18. data/bin/proto/conf/lhttpd.conf +236 -0
  19. data/bin/proto/ctl +4 -0
  20. data/bin/proto/lib/README +5 -0
  21. data/bin/proto/log/README +3 -0
  22. data/bin/proto/root/fcgi.rb +6 -0
  23. data/bin/proto/root/index.xhtml +65 -7
  24. data/bin/proto/root/m/nitro.png +0 -0
  25. data/examples/blog/README +7 -5
  26. data/examples/blog/{apache.conf → conf/apache.conf} +0 -0
  27. data/examples/blog/conf/app.conf.rb +56 -0
  28. data/examples/blog/conf/lhttpd.conf +236 -0
  29. data/examples/blog/ctl +4 -0
  30. data/examples/blog/lib/blog.rb +11 -136
  31. data/examples/blog/lib/blog/controller.rb +99 -0
  32. data/examples/blog/lib/blog/model.rb +39 -0
  33. data/examples/blog/log/README +3 -0
  34. data/examples/blog/root/comments.xhtml +2 -2
  35. data/examples/blog/root/fcgi.rb +6 -0
  36. data/examples/blog/root/index.xhtml +4 -5
  37. data/examples/blog/root/login.xhtml +2 -2
  38. data/examples/blog/root/style.xsl +9 -9
  39. data/examples/blog/root/view_entry.xhtml +2 -2
  40. data/examples/flash/conf/app.conf.rb +23 -0
  41. data/examples/flash/ctl +4 -0
  42. data/examples/flash/log/README +3 -0
  43. data/examples/flash/root/index.xhtml +0 -9
  44. data/examples/flash/root/show_inline_text.xhtml +10 -5
  45. data/examples/no_xsl_blog/README +12 -0
  46. data/examples/no_xsl_blog/conf/apache.conf +0 -0
  47. data/examples/no_xsl_blog/conf/app.conf.rb +57 -0
  48. data/examples/no_xsl_blog/conf/lhttpd.conf +236 -0
  49. data/examples/no_xsl_blog/ctl +4 -0
  50. data/examples/no_xsl_blog/lib/blog.rb +20 -0
  51. data/examples/no_xsl_blog/lib/blog/controller.rb +102 -0
  52. data/examples/no_xsl_blog/lib/blog/model.rb +39 -0
  53. data/examples/no_xsl_blog/lib/blog/template.rb +134 -0
  54. data/examples/no_xsl_blog/log/README +3 -0
  55. data/examples/no_xsl_blog/root/comments.xhtml +41 -0
  56. data/examples/no_xsl_blog/root/entry_form.xhtml +22 -0
  57. data/examples/no_xsl_blog/root/fcgi.rb +6 -0
  58. data/examples/no_xsl_blog/root/index.xhtml +39 -0
  59. data/examples/no_xsl_blog/root/login.xhtml +21 -0
  60. data/examples/no_xsl_blog/root/m/bubbles.gif +0 -0
  61. data/examples/no_xsl_blog/root/m/comments_curve.gif +0 -0
  62. data/examples/no_xsl_blog/root/m/down.gif +0 -0
  63. data/examples/no_xsl_blog/root/m/footer_bg.gif +0 -0
  64. data/examples/no_xsl_blog/root/m/garrow.gif +0 -0
  65. data/examples/no_xsl_blog/root/m/gbull.gif +0 -0
  66. data/examples/no_xsl_blog/root/m/grbull.gif +0 -0
  67. data/examples/no_xsl_blog/root/m/h1_bg.gif +0 -0
  68. data/examples/no_xsl_blog/root/m/header_bg.gif +0 -0
  69. data/examples/no_xsl_blog/root/m/nitro.gif +0 -0
  70. data/examples/no_xsl_blog/root/m/obull.gif +0 -0
  71. data/examples/no_xsl_blog/root/m/page_bg.gif +0 -0
  72. data/examples/no_xsl_blog/root/m/rss.gif +0 -0
  73. data/examples/no_xsl_blog/root/m/side_title_bg.gif +0 -0
  74. data/examples/no_xsl_blog/root/m/sidebar_bg.gif +0 -0
  75. data/examples/no_xsl_blog/root/recent_posts.xhtml +14 -0
  76. data/examples/no_xsl_blog/root/style.css +301 -0
  77. data/examples/no_xsl_blog/root/view_entry.xhtml +25 -0
  78. data/examples/no_xsl_blog/root/view_entry.xml +12 -0
  79. data/examples/og/run.rb +2 -2
  80. data/examples/tiny/README +2 -2
  81. data/examples/tiny/conf/apache.conf +5 -0
  82. data/examples/tiny/conf/app.conf.rb +21 -0
  83. data/examples/tiny/conf/lhttpd.conf +236 -0
  84. data/examples/tiny/ctl +4 -0
  85. data/examples/tiny/log/README +3 -0
  86. data/examples/tiny/root/fcgi.rb +6 -0
  87. data/examples/tiny/root/index.xhtml +7 -4
  88. data/examples/tiny/root/nitro.png +0 -0
  89. data/lib/glue.rb +13 -9
  90. data/lib/glue/array.rb +1 -1
  91. data/lib/glue/cache.rb +1 -1
  92. data/lib/glue/flexob.rb +12 -0
  93. data/lib/glue/hash.rb +1 -1
  94. data/lib/glue/inflector.rb +2 -2
  95. data/lib/glue/logger.rb +4 -8
  96. data/lib/glue/misc.rb +14 -0
  97. data/lib/glue/number.rb +1 -1
  98. data/lib/glue/object.rb +26 -0
  99. data/lib/glue/pool.rb +1 -1
  100. data/lib/glue/property.rb +84 -91
  101. data/lib/glue/string.rb +1 -1
  102. data/lib/glue/time.rb +1 -1
  103. data/lib/glue/validation.rb +1 -1
  104. data/lib/nitro.rb +18 -6
  105. data/lib/nitro/adaptors/cgi.rb +291 -0
  106. data/lib/nitro/adaptors/fastcgi.rb +42 -0
  107. data/lib/nitro/adaptors/runner.rb +123 -0
  108. data/lib/nitro/adaptors/webrick.rb +110 -0
  109. data/lib/nitro/buffering.rb +43 -0
  110. data/lib/nitro/builders/form.rb +1 -1
  111. data/lib/nitro/builders/rss.rb +1 -1
  112. data/{bin → lib/nitro}/cluster.rb +26 -30
  113. data/lib/nitro/context.rb +82 -0
  114. data/lib/nitro/controller.rb +50 -0
  115. data/lib/nitro/cookie.rb +46 -0
  116. data/lib/nitro/dispatcher.rb +105 -0
  117. data/lib/nitro/filters.rb +9 -10
  118. data/lib/nitro/localization.rb +42 -0
  119. data/lib/nitro/mail.rb +11 -14
  120. data/lib/nitro/render.rb +275 -0
  121. data/lib/nitro/request.rb +128 -0
  122. data/lib/nitro/response.rb +38 -0
  123. data/lib/nitro/scaffold.rb +11 -11
  124. data/lib/nitro/session.rb +84 -0
  125. data/lib/nitro/{server/shaders.rb → shaders.rb} +56 -36
  126. data/lib/nitro/ui/pager.rb +23 -26
  127. data/lib/nitro/{sitemap.rb → ui/sitemap.rb} +4 -12
  128. data/lib/nitro/uri.rb +1 -1
  129. data/lib/nitro/version.rb +10 -8
  130. data/lib/og.rb +66 -65
  131. data/lib/og/backend.rb +1 -1
  132. data/lib/og/backends/mysql.rb +48 -52
  133. data/lib/og/backends/psql.rb +34 -37
  134. data/lib/og/connection.rb +15 -15
  135. data/lib/og/enchant.rb +16 -9
  136. data/lib/og/meta.rb +127 -54
  137. data/lib/og/mock.rb +18 -18
  138. data/lib/og/version.rb +6 -4
  139. data/lib/parts/content.rb +4 -8
  140. data/test/glue/tc_logger.rb +3 -0
  141. data/test/glue/tc_property.rb +19 -3
  142. data/test/nitro/adaptors/tc_cgi.rb +63 -0
  143. data/test/nitro/adaptors/tc_webrick.rb +15 -0
  144. data/test/nitro/builders/tc_xml.rb +2 -2
  145. data/test/nitro/tc_context.rb +13 -0
  146. data/test/nitro/tc_controller.rb +47 -0
  147. data/test/nitro/tc_dispatcher.rb +64 -0
  148. data/test/nitro/tc_session.rb +20 -0
  149. data/test/nitro/{tc_sitemap.rb → ui/tc_sitemap.rb} +1 -1
  150. data/test/root/blog/list.xhtml +6 -0
  151. data/test/tc_og.rb +41 -4
  152. metadata +115 -59
  153. data/bin/proto/app.rb +0 -20
  154. data/bin/proto/config.rb +0 -77
  155. data/examples/blog/app.rb +0 -21
  156. data/examples/blog/config.rb +0 -95
  157. data/examples/blog/env.rb +0 -22
  158. data/examples/flash/README +0 -34
  159. data/examples/flash/app.rb +0 -20
  160. data/examples/flash/config.rb +0 -38
  161. data/examples/flash/lib/flash.rb +0 -40
  162. data/examples/flash/tmp.swf +0 -0
  163. data/examples/tiny/app.rb +0 -19
  164. data/examples/tiny/config.rb +0 -29
  165. data/examples/tiny/root/nitro-small.png +0 -0
  166. data/lib/nitro/application.rb +0 -217
  167. data/lib/nitro/config.rb +0 -128
  168. data/lib/nitro/events.rb +0 -122
  169. data/lib/nitro/html.rb +0 -151
  170. data/lib/nitro/http.rb +0 -102
  171. data/lib/nitro/l10n.rb +0 -30
  172. data/lib/nitro/server.rb +0 -59
  173. data/lib/nitro/server/appserver.rb +0 -67
  174. data/lib/nitro/server/cookie.rb +0 -87
  175. data/lib/nitro/server/dispatcher.rb +0 -62
  176. data/lib/nitro/server/filters.rb +0 -75
  177. data/lib/nitro/server/filters/autologin.rb +0 -51
  178. data/lib/nitro/server/fragment.rb +0 -70
  179. data/lib/nitro/server/handlers.rb +0 -127
  180. data/lib/nitro/server/render.rb +0 -426
  181. data/lib/nitro/server/request.rb +0 -658
  182. data/lib/nitro/server/requestpart.rb +0 -54
  183. data/lib/nitro/server/script.rb +0 -387
  184. data/lib/nitro/server/server.rb +0 -57
  185. data/lib/nitro/server/session.rb +0 -220
  186. data/lib/nitro/server/user.rb +0 -46
  187. data/lib/nitro/server/webrick.rb +0 -180
  188. data/lib/nitro/service.rb +0 -26
  189. data/lib/xsl/ui.xsl +0 -51
  190. data/lib/xsl/xforms.xsl +0 -28
  191. data/test/nitro/server/tc_cookie.rb +0 -34
  192. data/test/nitro/server/tc_filters.rb +0 -38
  193. data/test/nitro/server/tc_request.rb +0 -70
  194. data/test/nitro/server/tc_requestpart.rb +0 -28
  195. data/test/nitro/server/tc_session.rb +0 -34
  196. data/test/nitro/tc_events.rb +0 -44
  197. data/test/nitro/tc_html.rb +0 -79
  198. data/test/nitro/tc_http.rb +0 -18
@@ -0,0 +1,105 @@
1
+ #--
2
+ # George Moschovitis <gm@navel.gr>
3
+ # (c) 2004-2005 Navel, all rights reserved.
4
+ # $Id$
5
+ #++
6
+
7
+ module N
8
+
9
+ require 'nitro/controller'
10
+
11
+ # The Dispatcher manages a set of controllers.
12
+
13
+ class Dispatcher
14
+
15
+ # The root directory.
16
+
17
+ attr_accessor :root
18
+
19
+ # The controllers map.
20
+
21
+ attr_accessor :controllers
22
+
23
+ # APIs map.
24
+
25
+ attr_accessor :apis
26
+
27
+ def initialize(controllers = nil, apis = nil)
28
+ @root = 'root'
29
+ @controllers = controllers || { :index => Controller }
30
+ @apis = apis
31
+ end
32
+
33
+ # Process the given hash and mount the
34
+ # defined controllers.
35
+ #
36
+ # [+controllers+]
37
+ # A hash representing the mapping of
38
+ # mount points to controllers.
39
+ #
40
+ # === Examples
41
+ #
42
+ # dispatcher.mount {
43
+ # :index => MainController # mounts /
44
+ # 'users' => UsersController # mounts /users
45
+ # }
46
+
47
+ def mount(controllers)
48
+ (@controllers ||= {}).update(controllers)
49
+ end
50
+
51
+ # Add a new api to the dispatcher
52
+ #
53
+ # [+api+]
54
+ # API symbol
55
+ # [+data+]
56
+ # Data for this API [content_type, ..]
57
+
58
+ def add_api(api, data)
59
+ (@apis ||= {})[api] = data
60
+ end
61
+
62
+ # Processes the path and dispatches to the corresponding
63
+ # controller/action pair.
64
+ # The base returned contains a trailing '/'.
65
+
66
+ def dispatch(path)
67
+ api = :xhtml
68
+
69
+ if @apis
70
+ @apis.each { |k, v| api = k if path.slice!(/#{k}\//) }
71
+ end
72
+
73
+ parts = path.split('/')
74
+
75
+ case parts.size
76
+ when 0
77
+ base = @root
78
+ controller_class = @controllers[:index]
79
+ action = 'index'
80
+
81
+ when 2
82
+ if controller_class = @controllers[parts[1]]
83
+ base = "#{@root}/#{parts[1]}"
84
+ action = 'index'
85
+ else
86
+ base = @root
87
+ controller_class = @controllers[:index]
88
+ action = parts[1]
89
+ end
90
+
91
+ when 3
92
+ base = "#{@root}/#{parts[1]}"
93
+ controller_class = @controllers[parts[1]]
94
+ action = parts[2]
95
+ end
96
+
97
+ content_type = @apis ? @apis[:api] : 'text/html'
98
+
99
+ return controller_class, "__#{api}__#{action}", base, content_type
100
+ end
101
+ alias_method :split_path, :dispatch
102
+
103
+ end
104
+
105
+ end
@@ -1,17 +1,15 @@
1
- # code:
2
- # * George Moschovitis <gm@navel.gr>
3
- #
1
+ #--
2
+ # George Moschovitis <gm@navel.gr>
4
3
  # (c) 2004 Navel, all rights reserved.
5
- # $Id: filters.rb 184 2004-12-07 14:42:22Z gmosx $
4
+ # $Id: filters.rb 215 2005-01-24 10:44:05Z gmosx $
5
+ #++
6
6
 
7
7
  module N
8
8
 
9
- # = Filtering
10
- #
11
9
  # Filtering functionality for renders/services. The design
12
10
  # and implementation is HEAVILY influenced by Rails.
13
11
  #
14
- # Examples:
12
+ # == Examples
15
13
  #
16
14
  # Filter as class:
17
15
  #
@@ -22,10 +20,11 @@ module N
22
20
  # before
23
21
  # filter
24
22
  # after
25
- #
23
+ #--
26
24
  # TODO:
27
25
  # implement inheritable filters.
28
- #
26
+ #++
27
+
29
28
  module Filtering
30
29
 
31
30
  # Ruby is sometimes VERY surprising, the following trick is needed
@@ -154,4 +153,4 @@ module Filtering
154
153
 
155
154
  end
156
155
 
157
- end # module
156
+ end
@@ -0,0 +1,42 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: l10n.rb 185 2004-12-10 13:29:09Z gmosx $
4
+
5
+ require 'nitro/filters'
6
+
7
+ module N
8
+
9
+ # Localization support.
10
+ #--
11
+ # TODO: use inflector to convert symbols to strings.
12
+ #++
13
+
14
+ class Localization
15
+
16
+ # This map gives the correct localization hash
17
+ # for the given locale.
18
+
19
+ attr_accessor :map
20
+
21
+ def initialize(map = {})
22
+ @map = map
23
+ end
24
+
25
+ # Return the localization hash for the given
26
+ # locale.
27
+
28
+ def get(locale = 'en')
29
+ locale || = 'en'
30
+ @map[locale]
31
+ end
32
+ end
33
+
34
+ # Localization filter
35
+
36
+ module LocalizationFilter
37
+ def localize
38
+ @lc = @context.conf.lc.get(@session[:LC])
39
+ end
40
+ end
41
+
42
+ end
@@ -1,28 +1,25 @@
1
- # code:
2
1
  # * George Moschovitis <gm@navel.gr>
3
- #
4
- # (c) 2004 Navel, all rights reserved.
5
- # $Id: mail.rb 164 2004-11-18 11:47:50Z gmosx $
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id: mail.rb 248 2005-01-31 13:38:34Z gmosx $
6
4
 
7
- require "net/smtp"
5
+ require 'net/smtp'
8
6
 
9
7
  module N
10
8
 
11
- # = Mail
12
- #
13
9
  # A thin wrapper arround net/smtp
14
- #
10
+
15
11
  module Mail
16
-
12
+
13
+ mattr_accessor :smtp_server, 'localhost'
14
+
17
15
  # Send an email
18
- #
19
- #
16
+
20
17
  def self.send(from, to, body)
21
- Net::SMTP.start($smtp_server, 25) { |smtp|
18
+ Net::SMTP.start(N::Mail.smtp_server, 25) do |smtp|
22
19
  smtp.send_message(body, from, to)
23
- }
20
+ end
24
21
  end
25
22
 
26
23
  end
27
24
 
28
- end # module
25
+ end
@@ -0,0 +1,275 @@
1
+ # * George Moschovitis <gm@navel.gr>
2
+ # (c) 2004-2005 Navel, all rights reserved.
3
+ # $Id$
4
+
5
+ require 'glue/attribute'
6
+ require 'glue/misc'
7
+ require 'glue/object'
8
+
9
+ require 'nitro/shaders'
10
+ require 'nitro/buffering'
11
+
12
+ module N
13
+
14
+ # Raise this exception to stop rendering.
15
+
16
+ class RenderExit < Exception; end
17
+
18
+ # Rendering utility methods
19
+
20
+ module Rendering
21
+
22
+ # The default template name (no extension).
23
+
24
+ mattr_accessor :default_template, 'index'
25
+
26
+ # The shader used for transforming templates.
27
+ # The default shader is very simple, here is a
28
+ # typical example of a production shader pipeline:
29
+ #
30
+ # <tt>
31
+ # Rendering.shader =
32
+ # XSLTShader.new("xsl/style.xsl",
33
+ # RubyShader.new(
34
+ # CompressShader.new
35
+ # )
36
+ # )
37
+ # </tt>
38
+
39
+ mattr_accessor :shader; @@shader = RubyShader.new
40
+
41
+ # If true, reloads all controllers. Useful in
42
+ # development.
43
+
44
+ mattr_accessor :reload, :partial
45
+
46
+ # Given the action try find the matching template.
47
+ # Can search for xhtml or xml templates.
48
+ # Returns nil if no template file is found.
49
+
50
+ def self.template_for_action(base, action, ext = :xhtml)
51
+
52
+ # attempt to find a template of the form
53
+ # base/action.xhtml
54
+
55
+ path = "#{base}/#{action}.#{ext}".squeeze('/')
56
+
57
+ unless File.exist?(path)
58
+
59
+ # attempt to find a template of the form
60
+ # base/action/index.xhtml
61
+
62
+ path = "#{base}/#{action}/#{Rendering.default_template}.#{ext}".squeeze('/')
63
+
64
+ unless File.exist?(path)
65
+ # No template found!
66
+ path = nil
67
+ end
68
+ end
69
+
70
+ return path
71
+ end
72
+
73
+ # Transform a template to ruby rendering code.
74
+
75
+ def self.transform_template(path, shader)
76
+ Logger.debug "Transforming '#{path}'" if $DBG
77
+
78
+ text = File.read(path)
79
+ hash, text = shader.process(path, text)
80
+
81
+ return text
82
+ end
83
+
84
+ # Compile a controller action.
85
+
86
+ def self.compile_action(klass, action, base)
87
+ dummy, api, action = action.to_s.split('__')
88
+
89
+ # This is not a controller action.
90
+
91
+ return false unless action
92
+
93
+ Logger.debug "Compiling action '#{base}/#{action}'" if $DBG
94
+
95
+ valid = false
96
+
97
+ code = %{
98
+ def __#{api}__#{action}
99
+ }
100
+
101
+ # call 'before' filter chain.
102
+
103
+ if klass.respond_to?(:before_filters)
104
+ code << %{
105
+ #{klass.gen_filters_call_code(klass.before_filters)}
106
+ }
107
+ end
108
+
109
+ # call the action
110
+
111
+ if klass.instance_methods.include?(action)
112
+ valid = true
113
+ code << %{
114
+ #{action}();
115
+ }
116
+ end
117
+
118
+ # call the programmatically generated template if exists.
119
+
120
+ if klass.instance_methods.include?("#{action}__#{api}")
121
+ valid = true
122
+ code << %{
123
+ return unless #{action}__#{api}();
124
+ }
125
+ end
126
+
127
+ # call the template if exists.
128
+
129
+ if template = template_for_action(base, action)
130
+ valid = true
131
+ code << %{
132
+ return unless __#{api}__#{action}__template();
133
+ }
134
+ end
135
+
136
+ # raise "Invalid action '#{action}' for '#{klass}'!" unless valid
137
+ return false unless valid
138
+
139
+ # call 'after' filter chain.
140
+
141
+ if klass.respond_to?(:after_filters)
142
+ code << %{
143
+ #{klass.gen_filters_call_code(klass.after_filters)}
144
+ }
145
+ end
146
+
147
+ code << %{
148
+ redirect_referer if @out.empty?
149
+ end
150
+ }
151
+
152
+ if template
153
+ code << %{
154
+ def __#{api}__#{action}__template
155
+ #{transform_template(template, Rendering.shader)}
156
+ end
157
+ }
158
+ end
159
+
160
+ klass.class_eval(code)
161
+
162
+ return true
163
+ end
164
+
165
+ end
166
+
167
+ # The rendering mixin.
168
+
169
+ module Render
170
+
171
+ # The outbut buffer. The output of a script/action is accumulated
172
+ # in this buffer.
173
+
174
+ attr_accessor :out
175
+
176
+ # The context.
177
+
178
+ attr_accessor :context
179
+ alias_method :ctx, :context
180
+ alias_method :ctx=, :context=
181
+ alias_method :request, :context
182
+
183
+ # An array holding the rendering errors for this
184
+ # request.
185
+
186
+ attr_accessor :rendering_errors
187
+
188
+ # Initialize the render.
189
+ #
190
+ # [+context+]
191
+ # A parent render/controller acts as the context.
192
+
193
+ def initialize(context, base)
194
+ @context = context
195
+ @out = context.out
196
+ @base = base
197
+ end
198
+
199
+ # Renders the action denoted by path. The path
200
+ # is resolved by the dispatcher to get the correct
201
+ # controller.
202
+
203
+ def render(path)
204
+ Logger.debug "Rendering '#{path}'." if $DBG
205
+
206
+ klass, action, base, ctype = @context.dispatcher.dispatch(path)
207
+
208
+ if :full == Rendering.reload
209
+ def_file = klass::DEF_FILE
210
+ Controller.remove_subclasses
211
+ load(def_file)
212
+ end
213
+
214
+ @context.content_type = ctype
215
+
216
+ raise 'No controller for action' unless klass
217
+
218
+ if self.class == klass
219
+ self.send(action)
220
+ else
221
+ klass.new(self, base).send(action)
222
+ end
223
+
224
+ rescue RenderExit => e
225
+
226
+ # Just stop rendering.
227
+ # For example called by redirects.
228
+
229
+ rescue Exception, StandardError => e
230
+ log_error "Error while handling '#{path}'."
231
+ log_error pp_exception(e)
232
+
233
+ # More fault tolerant, only flags the erroneous box with
234
+ # error not the full page.
235
+
236
+ @out << '(error)'
237
+ end
238
+
239
+ # Send a redirect response.
240
+
241
+ def redirect(url, status = 303)
242
+ @context.status = status
243
+ @context.out = "<html><a href=\"#{url.to_s}\">#{url.to_s}</a>.</html>\n"
244
+ @context.response_headers['location'] = url.to_s
245
+
246
+ raise RenderExit
247
+ end
248
+
249
+ # Redirect to the referer of this method.
250
+
251
+ def redirect_referer(postfix = nil, status = 303)
252
+ redirect("#{@context.referer}#{postfix}", status)
253
+ end
254
+
255
+ # Log a rendering error.
256
+
257
+ def log_error(str)
258
+ @rendering_errors ||= []
259
+ @rendering_errors << str
260
+
261
+ # gmosx: Hmm perhaps this should not be logged
262
+ # to avoid DOS attacks.
263
+
264
+ Logger.error str
265
+ end
266
+
267
+ # Convenience method to lookup the session.
268
+
269
+ def session
270
+ @context.session
271
+ end
272
+
273
+ end
274
+
275
+ end