cuca 0.01

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 (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
+