cuca 0.01

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. data/application_skeleton/README +21 -0
  2. data/application_skeleton/app/_controllers/application.rb +7 -0
  3. data/application_skeleton/app/_layouts/simple.rb +19 -0
  4. data/application_skeleton/app/_widgets/sourcecode.rb +21 -0
  5. data/application_skeleton/app/_widgets/test.rb +23 -0
  6. data/application_skeleton/app/demo.rb +64 -0
  7. data/application_skeleton/app/index.rb +39 -0
  8. data/application_skeleton/app/user/__default_username/index.rb +7 -0
  9. data/application_skeleton/conf/environment.rb +16 -0
  10. data/application_skeleton/log/access.log +1 -0
  11. data/application_skeleton/log/error.log +1 -0
  12. data/application_skeleton/log/messages +1 -0
  13. data/application_skeleton/public/css/style.css +27 -0
  14. data/application_skeleton/public/dispatch.cgi +31 -0
  15. data/application_skeleton/public/dispatch.fcgi +36 -0
  16. data/application_skeleton/public/img/cuca-seagull.png +0 -0
  17. data/application_skeleton/scripts/console +5 -0
  18. data/application_skeleton/scripts/console.rb +5 -0
  19. data/application_skeleton/scripts/server-lighttpd-fcgi.rb +116 -0
  20. data/application_skeleton/scripts/server-lighttpd.rb +109 -0
  21. data/application_skeleton/scripts/server-webrick.rb +26 -0
  22. data/application_skeleton/scripts/test.rb +8 -0
  23. data/application_skeleton/tests/widgets/link.rb +22 -0
  24. data/bin/cuca +43 -0
  25. data/lib/cuca/app.rb +317 -0
  26. data/lib/cuca/cgi_emu.rb +67 -0
  27. data/lib/cuca/cgi_fix.rb +58 -0
  28. data/lib/cuca/const.rb +3 -0
  29. data/lib/cuca/controller.rb +240 -0
  30. data/lib/cuca/generator/markaby.rb +80 -0
  31. data/lib/cuca/generator/view.rb +121 -0
  32. data/lib/cuca/layout.rb +62 -0
  33. data/lib/cuca/mimetypes.rb +89 -0
  34. data/lib/cuca/session.rb +143 -0
  35. data/lib/cuca/sessionflash.rb +56 -0
  36. data/lib/cuca/sessionpage.rb +41 -0
  37. data/lib/cuca/stdlib/arform.rb +208 -0
  38. data/lib/cuca/stdlib/arview.rb +16 -0
  39. data/lib/cuca/stdlib/form.rb +137 -0
  40. data/lib/cuca/stdlib/formerrors.rb +20 -0
  41. data/lib/cuca/stdlib/link.rb +37 -0
  42. data/lib/cuca/stdlib/list.rb +3 -0
  43. data/lib/cuca/stdlib/listwidget/dblist.rb +122 -0
  44. data/lib/cuca/stdlib/listwidget/list.rb +189 -0
  45. data/lib/cuca/stdlib/listwidget/querydef.rb +167 -0
  46. data/lib/cuca/stdlib/listwidget/staticdatalist.rb +79 -0
  47. data/lib/cuca/stdlib/slink.rb +30 -0
  48. data/lib/cuca/test/helpers.rb +42 -0
  49. data/lib/cuca/urlmap.rb +267 -0
  50. data/lib/cuca/widget.rb +212 -0
  51. data/lib/cuca.rb +68 -0
  52. metadata +141 -0
data/lib/cuca/app.rb ADDED
@@ -0,0 +1,317 @@
1
+ require 'logger'
2
+
3
+
4
+ module Cuca
5
+
6
+ # Sandbox is used internally run the action script defined by the controller
7
+ # In future this can be extended to implement some security features etc..
8
+ class Sandbox
9
+ def self.run(controller_class_name, mod, assigns, request_method, subcall)
10
+ self.class.send(:include, mod)
11
+ controller_class = mod::const_get(controller_class_name)
12
+ controller = controller_class.send(:new, :assigns=>assigns)
13
+ controller.run_before_filters
14
+
15
+
16
+ controller.send('_do'.intern, 'run', subcall)
17
+ case $cgi.request_method
18
+ when 'POST'
19
+ controller.send('_do'.intern, 'post', subcall)
20
+ when 'GET'
21
+ controller.send('_do'.intern, 'get', subcall)
22
+ end
23
+ return controller.send(:to_s)
24
+ end
25
+ end
26
+
27
+ # == Cuca Application
28
+ #
29
+ # A Cuca::App object will be created directly by the dispatcher - which again is the
30
+ # direct cgi or fastcgi script that get run by the webserver.
31
+ # Normally you just create a Cuca::App object and run the cgicall function with optional with
32
+ # a cgi object as paramenter.
33
+ # Before doing that you must set $cuca_path to the root of your appication structure.
34
+
35
+ class App
36
+
37
+ # == Configure the application
38
+ # App::Config is normally called from conf/environment.rb . The attributes below the framework
39
+ # will make use of, but you can always define own ones.
40
+ #
41
+ # == Example
42
+ #
43
+ # Cuca::App.configure do |conf|
44
+ # conf.include_directories = %{_widgets _special_widgets}
45
+ # conf.database = 'mydb' # application specific
46
+ # end
47
+ # === Attributes:
48
+ #
49
+ # * include_directories
50
+ # An array of directories that will be automatically included if you call an action.
51
+ # If one of the directories is found in the path where the action file is located it will require
52
+ # all files found. (default: %w{_controllers _widgets _layouts} )
53
+ # * log_level - default 3
54
+ # * magic_prefix - default: '__default_' (see Cuca::Controller)
55
+ class Config < Hash
56
+ def method_missing(m, *params)
57
+ met = m.id2name
58
+ raise NoMethodError if met[met.size-1].chr != '='
59
+ self[met[0..met.size-2]] = params[0]
60
+ end
61
+
62
+ # some default stuff
63
+ def initialize
64
+ self['include_directories'] = %w{_controllers _widgets _layouts}
65
+ self['log_level'] = 3
66
+ self['magic_prefix'] = '__default_'
67
+ self['directory_seperator'] = '/' # future?
68
+ self['session_key'] = 'cuca_session'
69
+ self['session_prefix'] = 'cuca.'
70
+ self['session_valid'] = 3600*24
71
+ self['view_directoru'] = 'app/_view' # where to find views for the view/erb generator
72
+
73
+ end
74
+
75
+ end
76
+
77
+ attr_reader :conf, :cgi, :logger, :urlmap
78
+
79
+ @@app_config = Config.new
80
+
81
+ ## Application configuration
82
+ public
83
+ def self.configure
84
+ yield @@app_config
85
+ end
86
+
87
+ def self.config
88
+ @@app_config
89
+ end
90
+
91
+
92
+ # cgi implementation test
93
+ private
94
+ def cgidump(cgi)
95
+ s = ""
96
+ s << "-----ENV------<br>"
97
+ cgi.env_table.each_pair { |k,v| s << "#{k} => #{v}<br>" }
98
+ s << "--------------<br>"
99
+ s << "Server Software: #{cgi.server_software}<br>"
100
+ s << "PATH INFO: #{cgi.path_info}<br>"
101
+ end
102
+
103
+ # Creates the @conf global variable - internal config
104
+ #
105
+ # APP_PATH = Path the the /app folder
106
+ # CGI = CGI object
107
+ # DEF_EXT = Default script extensions (.rb)
108
+ # DEF_ACTION = (like 'index')
109
+ # SCRIPT = Full path to the ruby script dealing with ACTION
110
+ # ACTION = Action called (=links to SCRIPT, eg 'show' or 'index')
111
+ # PATH_INFO = raw path info as from cgi
112
+ # PATH_TREE = array of path, without action
113
+ private
114
+ def mk_config
115
+ @conf = {}
116
+
117
+ # To have a look at ENV and cgi uncomment this
118
+ # @cgi.out { cgidump(@cgi) }
119
+ # raise "Debug stop"
120
+
121
+
122
+ # APP_PATH = Path the the /app folder
123
+ # @conf['APP_PATH'] = File.expand_path(File.dirname(__FILE__)+"/../app")
124
+ @conf['APP_PATH'] = $cuca_path + "/app"
125
+
126
+ # PUBLIC_PATH = Path to the /public folder
127
+ # @conf['PUBLIC_PATH'] = File.expand_path(File.dirname(__FILE__)+"/../public")
128
+ @conf['PUBLIC_PATH'] = $cuca_path + "/public"
129
+
130
+ # LOG_PATH = Path to logging directory
131
+ # @conf['LOG_PATH'] = File.expand_path(File.dirname(__FILE__)+"/../log")
132
+ @conf['LOG_PATH'] = $cuca_path + "/log"
133
+
134
+ # CGI = CGI object
135
+ @conf['CGI'] = @cgi
136
+
137
+ # DEF_EXT = Default script extensions
138
+ @conf['DEF_EXT'] = ".rb"
139
+
140
+ @conf['DEF_ACTION'] = 'index'
141
+
142
+ # Cookie name
143
+ @conf['COOKIE_NAME'] = 'cucahap'
144
+
145
+ # ACTION = Action called (=links to SCRIPT), eg 'index'
146
+ @conf['ACTION'] = @cgi.path_info.reverse[0].chr == '/' ? @conf['DEF_ACTION'] : @cgi.path_info.split('/').last.downcase
147
+
148
+ # PATH_INFO = raw path info as from cgi
149
+ @conf['PATH_INFO'] = @cgi.path_info
150
+
151
+ # PATH_TREE = path info as array - without action
152
+ # @conf['PATH_TREE'] = [''].concat(@conf['PATH_INFO'].split('/').collect { |e| (e==@conf['ACTION'] || e == '') ? nil : e }.compact)
153
+
154
+
155
+ require 'cuca/urlmap'
156
+
157
+ begin
158
+ mapping = URLMap.new(File.expand_path(@conf['APP_PATH']), @conf['PATH_INFO'])
159
+ @conf['SUBCALL'] = mapping.subcall
160
+ @conf['SCRIPT'] = mapping.script
161
+ @conf['ASSIGNS'] = mapping.assigns
162
+ @conf['ACTION'] = mapping.action
163
+ @urlmap = mapping
164
+ rescue RoutingError => r
165
+ @conf['SCRIPT'] = "#{@conf['PUBLIC_PATH']}/#{@conf['PATH_INFO']}"
166
+ return
167
+ # raise "RoutingError: #{r}"
168
+ end
169
+
170
+ # get the PATH_TREE for file inclusion!
171
+
172
+ c_ap = File.expand_path(@conf['APP_PATH'])
173
+ pt = @conf['SCRIPT'][c_ap.size..-1]
174
+ ac_script = @conf['SCRIPT'].split('/').last
175
+ @conf['PATH_TREE'] = [''].concat(pt.split('/').collect { |e| (e==ac_script || e == '') ? nil : e }.compact)
176
+ end
177
+
178
+ # will do a 'require' on all .rb files in path
179
+ private
180
+ def include_files(path)
181
+ return unless File.exist?(path)
182
+ pwd = Dir.pwd
183
+ Dir.chdir(path)
184
+ Dir['*.rb'].each do |f|
185
+ require "#{path}/#{f}"
186
+ end
187
+ Dir.chdir(pwd)
188
+ end
189
+
190
+
191
+
192
+ public
193
+ def initialize(cgi = nil)
194
+
195
+ $cgi = cgi || CGI.new
196
+ @cgi = $cgi
197
+
198
+ mk_config
199
+
200
+ @logger = Logger.new(@conf['LOG_PATH'] + "/messages")
201
+ $logger = @logger
202
+ $conf = @conf
203
+ $app = self
204
+
205
+ rescue RuntimeError => e
206
+ @cgi.out { "Error initializing the app: #{$!}" }
207
+ end
208
+
209
+ # this has to be public for testing scripts
210
+ public
211
+ def load_support_files # :nodoc:
212
+ # $stderr.puts "======== load support files ========="
213
+ # $stderr.puts "Inc Dir: #{App::config['include_directories'].inspect}"
214
+ # $stderr.puts "Path tr: #{@conf['PATH_TREE'].inspect}"
215
+ # $stderr.puts "====================================="
216
+
217
+ base_path = @conf['APP_PATH']
218
+ @conf['PATH_TREE'].each do |t|
219
+ base_path << "/#{t}"
220
+ (App::config['include_directories'] || []).each do |id|
221
+ include_files "#{base_path}/#{id}"
222
+ end
223
+ end
224
+
225
+ # (App::config['include_directories'] || []).each do |id|
226
+ # @conf['PATH_TREE'].each { |t| include_files @conf['APP_PATH'] + '/'+t+"/#{id}/"}
227
+ # end
228
+ end
229
+
230
+ public
231
+ def cgicall
232
+ script = @conf['SCRIPT']
233
+
234
+
235
+ #
236
+ # 1st priority: Serve a file if it exists in the 'public' folder
237
+ #
238
+ file = @conf['PUBLIC_PATH'] + '/' + @conf['PATH_INFO']
239
+ if File.exists?(file) && File.ftype(file) == 'file' then
240
+ require 'cuca/mimetypes'
241
+ mt = MimeTypes.new
242
+ f = File.new(file)
243
+ extension = file.scan(/.*\.(.*)$/)[0][0] if file.include?('.')
244
+ extension ||= 'html'
245
+ mime = mt[extension] || 'text/html'
246
+ @cgi.out(mime) { f.read }
247
+ f.close
248
+ return
249
+ end
250
+
251
+
252
+ #
253
+ # 2nd: Check if we have a script for requested action
254
+ #
255
+ if (!File.exists?(script)) then
256
+ @cgi.out { "Script not found: #{script}" }
257
+ return
258
+ end
259
+
260
+
261
+ # 3rd: Load additional files
262
+ load_support_files
263
+
264
+
265
+ # 4th: Now let's run the actual page script code
266
+ controller_class_name = @conf['ACTION'].capitalize+"Controller"
267
+
268
+ # Clear all hints
269
+ Widget::clear_hints()
270
+
271
+ # Load the code of the action into the module
272
+ controller_module = @urlmap.action_module
273
+
274
+
275
+ controller_module.module_eval(File.open(script).read, script) unless \
276
+ controller_module.const_defined?(controller_class_name.intern)
277
+
278
+ # Catch a common user error
279
+ if !controller_module.const_defined?(controller_class_name.intern) then
280
+ @cgi.out { "Could not find #{controller_class_name} defined in #{script}" }
281
+ return
282
+ end
283
+
284
+ #
285
+ # Load the controller
286
+ #
287
+ begin
288
+
289
+ result = Sandbox.run(controller_class_name, @urlmap.action_module, @conf['ASSIGNS'],
290
+ $cgi.request_method, @conf['SUBCALL'])
291
+
292
+
293
+ @cgi.out('type' => 'text/html') {result}
294
+
295
+ rescue Cuca::ApplicationException => e
296
+ err = "<b>Application Error: #{e}</b><br/>"
297
+ e.backtrace.each do |b|
298
+ err +="<br/>#{b}"
299
+ end
300
+ @cgi.out('status' => 'SERVER_ERROR') { err }
301
+ return
302
+
303
+ rescue => e
304
+ err = "<b>System Error: #{e}</b><br/>"
305
+ e.backtrace.each do |b|
306
+ err +="<br/>#{b}"
307
+ end
308
+ @cgi.out('status' => 'SERVER_ERROR') { err }
309
+ return
310
+
311
+ end
312
+ end
313
+
314
+ end
315
+
316
+
317
+ end # module
@@ -0,0 +1,67 @@
1
+ # little fake cgi class that allows automated testing of cgi application
2
+
3
+ class CGIEmu < CGI
4
+ class EnvTable
5
+ def initialize(options)
6
+ @test_path_info = options['PATH_INFO'] || '/'
7
+ @test_query_params = options['QUERY_PARAMS'] || {}
8
+
9
+ the_env_table.each_pair { |k,v| ENV[k] = v }
10
+
11
+ # ENV.merge(the_env_table)
12
+ end
13
+
14
+ def query_string
15
+ r = []
16
+ @test_query_params.each_pair { |k,v| r << "#{k}=#{v}" }
17
+ return r.join('&')
18
+ end
19
+
20
+
21
+ def the_env_table
22
+ {"SERVER_NAME"=>"localhost",
23
+ "PATH_INFO"=>@test_path_info,
24
+ "REMOTE_HOST"=>"localhost",
25
+ "HTTP_ACCEPT_ENCODING"=>"x-gzip, x-deflate, gzip, deflate",
26
+ "HTTP_USER_AGENT"=>"Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.8 (like Gecko)",
27
+ "SCRIPT_NAME"=>"",
28
+ "SERVER_PROTOCOL"=>"HTTP/1.1",
29
+ "HTTP_ACCEPT_LANGUAGE"=>"en",
30
+ "HTTP_HOST"=>"localhost:2000",
31
+ "REMOTE_ADDR"=>"127.0.0.1",
32
+ "SERVER_SOFTWARE"=>"WEBrick/1.3.1 (Ruby/1.8.6/2007-06-07)",
33
+ "HTTP_REFERER"=>"http://localhost:2000/",
34
+ "HTTP_COOKIE"=>"cuca_session=285715682bf030a19cb24b2560aabc36",
35
+ "HTTP_ACCEPT_CHARSET"=>"utf-8, utf-8;q=0.5, *;q=0.5",
36
+ "REQUEST_URI"=>"http://localhost:2000" + @test_path_info,
37
+ "SERVER_PORT"=>"2000",
38
+ "GATEWAY_INTERFACE"=>"CGI/1.1",
39
+ "QUERY_STRING"=>query_string,
40
+ "HTTP_ACCEPT"=>"text/html, image/jpeg, image/png, text/*, image/*, */*",
41
+ "SCRIPT_FILENAME"=>"/home/bones/workspace/cuca/scripts/../public/dispatch.cgi",
42
+ "REQUEST_METHOD"=>"GET",
43
+ "HTTP_CONNECTION"=>"Keep-Alive"}
44
+ end
45
+
46
+ def [](key)
47
+ # $stderr.puts "get FROM ENV_TABLE(#{key}) ==> #{the_env_table[key]}"
48
+ return the_env_table[key] || nil
49
+ end
50
+ end
51
+
52
+ def env_table
53
+ EnvTable.new(@test_options)
54
+ end
55
+
56
+ def stdinput
57
+ # $stderr.puts "Returning STDINPUT"
58
+ StringIO.new("")
59
+ end
60
+
61
+ def initialize(options)
62
+ @test_options = options
63
+ super()
64
+ end
65
+
66
+ end
67
+
@@ -0,0 +1,58 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require 'cgi'
4
+
5
+ # We'll add three methods to the cgi class in order to separete get/post requests:
6
+ # * parameters -- all (mixed) get and post
7
+ # * query_parameters -- get
8
+ # * request_parameters -- post
9
+ #
10
+ class CGI # :nodoc:
11
+ class << self
12
+ def fix_env(ec)
13
+ if (ec['PATH_INFO'].nil? || ec['PATH_INFO'] == '') then
14
+ pi = ec['REQUEST_URI']
15
+ pi = pi[0..(pi.index('?')-1)] if pi.include?('?')
16
+ ec['PATH_INFO'] = pi
17
+ end
18
+
19
+ if (ec['QUERY_STRING'].nil? || ec['QUERY_STRING'] == '') then
20
+ ec['QUERY_STRING'] = ec['REQUEST_URI'].include?('?') ?
21
+ ec['REQUEST_URI'].scan(/.?\?(.*)/)[0][0] :
22
+ ""
23
+ end
24
+ ec
25
+ end
26
+ end
27
+
28
+
29
+ def env_table
30
+ CGI::fix_env(ENV)
31
+ ENV
32
+ end
33
+
34
+ def parameters
35
+ query_parameters.merge(request_parameters)
36
+ end
37
+
38
+ def query_parameters
39
+ res = {}
40
+ query_string.split(/[&;]/).each do |p|
41
+ k, v = p.split("=")
42
+ v = '' if v.nil?
43
+ res[CGI.unescape(k)] = CGI.unescape(v)
44
+ end
45
+ res
46
+ end
47
+
48
+ def request_parameters
49
+ if request_method == 'POST' then
50
+ res = {}
51
+ params.each_pair { |k,v| res[k] = v[0] }
52
+ return res
53
+ else
54
+ return {}
55
+ end
56
+ end
57
+
58
+ end
data/lib/cuca/const.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Cuca
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,240 @@
1
+ module Cuca
2
+
3
+ # :nodoc:
4
+ class BreakControllerException < StandardError
5
+ # flags can be:
6
+ # :layout => 'new_layout' or false
7
+ # :redirect => '/to/new/url' = dont render, just redirect
8
+ # :error => "something happend" = display an application error
9
+ attr_reader :flags
10
+ def initialize(flags = {})
11
+ @flags = flags
12
+ end
13
+ end
14
+
15
+
16
+ # === Cuca Controller
17
+ #
18
+ # A controller handles the get/post request for your website and has the ability to
19
+ # generate an output directly making use of other Widgets and Layouts.
20
+ #
21
+ # The Controller class itself behaves just like Cuca::Widget, but instead of overwriting
22
+ # the output method you must implement run or post or get or any combination.
23
+ #
24
+ # Additionally you can also define a wrapping layout (using the layout function) and you can
25
+ # run code before a certain action is called using before_filter's.
26
+ #
27
+ # == Naming
28
+ #
29
+ # When you open a url like: http://your.website.com/users/list cuca will load the file /users/list.rb
30
+ # from your application path (usually app/users/list.rb). Within that file you must define one
31
+ # class derrived from Cuca::Controller with name FilenameController. The /users/list.rb example must
32
+ # therefor implement the ListController class.
33
+ #
34
+ # == Subcalls
35
+ #
36
+ # Sometimes you might want to implement another URL that is logically joined with your
37
+ # current page ("Ajax"?). To do this you can implement a (get|post|run)_subcallname method within
38
+ # your controller. This one will get called if you open http://your.website.com/-controller-subcallname .
39
+ #
40
+ # == Routing / Pretty URL's
41
+ #
42
+ # Depending on your directory structure within the app folder you can define variable directory names
43
+ # that will hint you within the controller.
44
+ #
45
+ # Example:
46
+ # File: app/user/__default_username/show.rb will map to http://user/johnrambo/show and define instance variable
47
+ # @username within the Controller defined in show.rb
48
+ #
49
+ # The magic URL prefix (default: __default_) can be change within App::Config
50
+ #
51
+ # == Examples
52
+ #
53
+ # Hello world (index.rb):
54
+ #
55
+ # class IndexController < Cuca::Controller
56
+ # def run
57
+ # content << "Hello World"
58
+ # end
59
+ # end
60
+ #
61
+ # Using filters and layouts and generate page using the Markaby generator (fancy.rb):
62
+ #
63
+ # require 'cuca/generators/markaby'
64
+ #
65
+ # class FancyController < Cuca::Controller
66
+ # include Cuca::Generator::Markaby
67
+ # layout 'fancy'
68
+ # before_filter 'set_title'
69
+ #
70
+ # def set_title
71
+ # @page_title = "A Fancy Page"
72
+ # end
73
+ #
74
+ # def get
75
+ # mab do
76
+ # h1 "Welcome to the Fancy Page called #{@page_title}"
77
+ # p { text "Welcome to my"; b { paragraph } }
78
+ # end
79
+ # end
80
+ # end
81
+ #
82
+ #
83
+ class Controller < Widget
84
+
85
+ attr_reader :cancel_execution # this can be set by anyone,
86
+ # methods get/post/run will not be executed
87
+
88
+ def self.def_layout
89
+ begin
90
+ self.def_layout_name
91
+ rescue
92
+ nil
93
+ end
94
+ end
95
+
96
+ def self.layout(name)
97
+ define_attr_method(:def_layout_name, name)
98
+ end
99
+
100
+ def self.before_filter(method)
101
+ begin
102
+ filters = self.def_before_filter
103
+ filters = "#{filters};#{method}"
104
+ define_attr_method(:def_before_filter, filters)
105
+ rescue => e
106
+ define_attr_method(:def_before_filter, method)
107
+ end
108
+ end
109
+
110
+ def run_before_filters
111
+ # $stderr.puts "Run before filters"
112
+ begin
113
+ before_filter = self.class.def_before_filter
114
+ rescue NoMethodError => e
115
+ # == no filters defined at all
116
+ # $stderr.puts " No before filters defined for #{self.class}"
117
+ return
118
+ end
119
+ before_filter.split(';').each do |filter|
120
+ begin
121
+ if (!self.methods.include?(filter)) then
122
+ raise ApplicationException.new("Before filter method not defined: '#{filter}'")
123
+ end
124
+ ret = self.send(filter)
125
+ @cancel_execution = true if ret == false
126
+ # rescue NoMethodError => e
127
+ # raise ApplicationException.new "Before filter method not defined: '#{filter}'"
128
+ rescue BreakControllerException => bc
129
+ handle_exception(bc)
130
+ end
131
+ end
132
+ end
133
+
134
+
135
+ # this method will stop execution of the controller
136
+ # it's usefull to break somewhere in the middle or to
137
+ # set a different layout
138
+ # flags can be
139
+ # :layout - Set a new layout
140
+ # :redirect - redirect to a different page
141
+ # :error - An error message (for application errors)
142
+ def stop(flags = {})
143
+ raise BreakControllerException.new(flags)
144
+ end
145
+
146
+
147
+ # this piece of code will handle a thrown exception BreakControllerException
148
+ def handle_exception(e)
149
+ if e.flags.has_key?(:layout) then
150
+ self.class.layout(e.flags[:layout])
151
+ end
152
+
153
+ if e.flags.has_key?(:redirect) then
154
+ self.class.layout false
155
+ to = e.flags[:redirect]
156
+ clear
157
+ @_content = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\"><html><head><title>Redirecting...</title><meta http-equiv=\"REFRESH\" content=\"0;url=#{to}\"></HEAD></HTML>"
158
+ @cancel_execution = true
159
+ end
160
+
161
+ if e.flags.has_key?(:error) then
162
+ self.class.layout false
163
+ clear
164
+ @error_message = e.flags[:error]
165
+ @cancel_execution = true
166
+ mab { html { body { h2 "Error"; text @error_message }}}
167
+ end
168
+ end
169
+
170
+ private
171
+ # Overwrite this method to handle get and post events
172
+ def run
173
+ end
174
+
175
+ # Overwrite this method to handle get events
176
+ def get
177
+ end
178
+
179
+ # Overwrite this method to handle post events
180
+ def post
181
+ end
182
+
183
+
184
+
185
+ # This is the method as called from App. It will call 'get', 'post', 'run' and handle
186
+ # exceptions. what within [post,get,run]
187
+ # TOTHINKABOUT: run before filter from this method?
188
+ public
189
+ def _do(what, subcall)
190
+ return if @cancel_execution
191
+
192
+ method_name = what
193
+ method_name = "#{method_name}_#{subcall}" if subcall
194
+ begin
195
+ self.send(method_name) if self.methods.include?(method_name)
196
+ rescue BreakControllerException => e
197
+ handle_exception(e)
198
+ end
199
+ end
200
+
201
+
202
+ def initialize(*args)
203
+ # set a global variable of the controller object.
204
+ # Widgets can make use of this to call or modify the controller class.
205
+ $controller_object = self
206
+
207
+ @cancel_execution = false
208
+ super(*args)
209
+
210
+ # FIXME: to think about...
211
+ get_assigns.each_pair do |k,v|
212
+ instance_variable_set("@#{k}", v)
213
+ end
214
+ end
215
+
216
+ private
217
+ def load_layout
218
+ return nil if self.class.def_layout.nil?
219
+ begin
220
+ layout_class = Object::const_get(self.class.def_layout.capitalize+"Layout")
221
+ rescue => e
222
+ # fixme - if layout loading fails we should display some error
223
+ return nil
224
+ end
225
+ end
226
+
227
+ public
228
+ def output
229
+ layout_class = load_layout
230
+ return content unless layout_class
231
+ c = content.to_s
232
+ a = get_assigns
233
+ a[:content_for_layout] = c
234
+ @_content = layout_class.new(:assigns=>a)
235
+ end
236
+ end
237
+
238
+
239
+ end # Module
240
+