mack 0.0.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 (55) hide show
  1. data/README +43 -0
  2. data/bin/mack +60 -0
  3. data/bin/templates/Rakefile.template +6 -0
  4. data/bin/templates/app/controllers/default_controller.rb.template +7 -0
  5. data/bin/templates/app/helpers/application_helper.rb.template +2 -0
  6. data/bin/templates/app/views/default/index.html.erb.template +3 -0
  7. data/bin/templates/app/views/layouts/application.html.erb.template +15 -0
  8. data/bin/templates/config/app_config/default.yml.template +7 -0
  9. data/bin/templates/config/app_config/development.yml.template +0 -0
  10. data/bin/templates/config/app_config/production.yml.template +0 -0
  11. data/bin/templates/config/app_config/test.yml.template +0 -0
  12. data/bin/templates/config/boot.rb.template +6 -0
  13. data/bin/templates/config/database.yml.template +20 -0
  14. data/bin/templates/config/routes.rb.template +7 -0
  15. data/bin/templates/config/thin.ru.template +1 -0
  16. data/bin/templates/config/thin.yml.template +8 -0
  17. data/bin/templates/public/favicon.ico +0 -0
  18. data/bin/templates/public/stylesheets/scaffold.css.template +74 -0
  19. data/core_extensions/hash.rb +9 -0
  20. data/core_extensions/module.rb +29 -0
  21. data/core_extensions/nil.rb +8 -0
  22. data/core_extensions/object.rb +9 -0
  23. data/core_extensions/string.rb +28 -0
  24. data/errors/errors.rb +79 -0
  25. data/initialize/configuration.rb +99 -0
  26. data/initialize/configure_logging.rb +24 -0
  27. data/initialize/configure_orm_support.rb +23 -0
  28. data/initialize/console.rb +13 -0
  29. data/initialize/initializer.rb +88 -0
  30. data/initialize/server/simple_server.rb +21 -0
  31. data/lib/utils/html.rb +88 -0
  32. data/lib/utils/server.rb +27 -0
  33. data/mack.rb +124 -0
  34. data/mack_tasks.rb +16 -0
  35. data/routing/route_map.rb +268 -0
  36. data/routing/urls.rb +54 -0
  37. data/sea_level/controller_base.rb +293 -0
  38. data/sea_level/cookie_jar.rb +67 -0
  39. data/sea_level/filter.rb +63 -0
  40. data/sea_level/helpers/view_helpers/html_helpers.rb +33 -0
  41. data/sea_level/helpers/view_helpers/orm_helpers.rb +72 -0
  42. data/sea_level/request.rb +83 -0
  43. data/sea_level/response.rb +6 -0
  44. data/sea_level/session.rb +33 -0
  45. data/sea_level/view_binder.rb +101 -0
  46. data/tasks/cachetastic_tasks.rake +69 -0
  47. data/tasks/log_tasks.rake +9 -0
  48. data/tasks/mack_tasks.rake +15 -0
  49. data/tasks/rake_helpers.rb +24 -0
  50. data/tasks/rake_rules.rake +19 -0
  51. data/tasks/script_tasks.rake +44 -0
  52. data/tasks/test_tasks.rake +7 -0
  53. data/test_extensions/test_assertions.rb +47 -0
  54. data/test_extensions/test_helpers.rb +84 -0
  55. metadata +173 -0
data/mack_tasks.rb ADDED
@@ -0,0 +1,16 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ # Requires all rake tasks that ship with the Mack framework.
5
+ [File.join(File.dirname(__FILE__)), File.join(FileUtils.pwd, "lib")].each do |dir|
6
+ begin
7
+ require File.join(dir, "tasks", "rake_helpers.rb")
8
+ rescue Exception => e
9
+ end
10
+ files = Dir.glob(File.join(dir, "tasks", "*.rake"))
11
+ files.each do |f|
12
+ unless f == __FILE__
13
+ load f
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,268 @@
1
+ require 'singleton'
2
+ module Mack
3
+
4
+ module Routes
5
+
6
+ # This method yields up Mack::Routes::RouteMap and allows for the creation of routes in the system.
7
+ #
8
+ # See Mack::Routes::RouteMap for more information.
9
+ def self.build
10
+ yield Mack::Routes::RouteMap.instance
11
+ Mack::Routes::Urls.include_safely_into(Mack::Controller::Base, Mack::ViewBinder, Test::Unit::TestCase)
12
+ # puts "Finished compiling routes: #{Mack::Routes::RouteMap.instance.routes_list.inspect}"
13
+ end
14
+
15
+ # Routes are the back bone of the Mack framework. They are used to map incoming urls to controllers.
16
+ #
17
+ # === Defining Routes:
18
+ # Example:
19
+ # Mack::Routes.build do |r|
20
+ #
21
+ # # Connects "/" to the HomeController and the '/' action.
22
+ # r.connect "/", :controller => :home
23
+ #
24
+ # # Connects "/foo", to the HomeController and the 'foo' action.
25
+ # r.connect "/foo", :controller => :home, :action => :foo
26
+ #
27
+ # # Connects "/blog" to the BlogController and the 'list' action.
28
+ # r.connect "/blog", :controller => :blog, :action => :list
29
+ #
30
+ # # Connects "/blog/:id" to the BlogController and the 'index' action.
31
+ # # It will also take the second half of the url and map it to a parameter called :id.
32
+ # # Example:
33
+ # # '/blog/1' # => goes to the BlogController, 'index' action, and has an :id parameter == 1.
34
+ # r.connect "/blog/:id", :controller => :blog, :action => :index
35
+ #
36
+ # # Connects "/blog/create" to the BlogController and the 'create' action.
37
+ # # It also insists that the HTTP method be 'post'. If it's not 'post' it will not match this route.
38
+ # r.connect "/blog/create", :controller => :blog, :action => :create, :method => :post
39
+ #
40
+ # # Connects "/comment/destroy/:id" to the CommentController and the 'destroy' action.
41
+ # # It also insists that the HTTP method be 'delete'. If it's not 'delete' it will not match this route.
42
+ # # It will also create an :id parameter.
43
+ # r.connect "/comment/destroy/:id", :controller => :comment, :action => :destroy, :method => :delete
44
+ #
45
+ # # This will create 'RESTful' routes. Unlike Rails, it doesn't generate a mixture of singular/plural
46
+ # # routes. It uses whatever you pass in to it. This will also create named routes in Mack::Routes::Urls.
47
+ # # Examples:
48
+ # # '/users' # => {:controller => 'users', :action => :index, :method => :get}
49
+ # # # => users_index_url
50
+ # # # => users_index_full_url
51
+ # # '/users' # => {:controller => 'users', :action => :create, :method => :post}
52
+ # # # => users_create_url
53
+ # # # => users_create_full_url
54
+ # # '/users/new' # => {:controller => 'users', :action => :new, :method => :get}
55
+ # # # => users_new_url
56
+ # # # => users_new_full_url
57
+ # # '/users/:id' # => {:controller => 'users', :action => :show, :method => :get}
58
+ # # # => users_show_url
59
+ # # # => users_show_full_url
60
+ # # '/users/:id/:edit # => {:controller => 'users', :action => :edit, :method => :get}
61
+ # # # => users_edit_url
62
+ # # # => users_edit_full_url
63
+ # # '/users/:id/update # => {:controller => 'users', :action => :update, :method => :post}
64
+ # # # => users_update_url
65
+ # # # => users_update_full_url
66
+ # # '/users/:id # => {:controller => 'users', :action => :delete, :method => :delete}
67
+ # # # => users_delete_url
68
+ # # # => users_delete_full_url
69
+ # r.resource :users
70
+ #
71
+ # # This will redirect '/old_users/show/:id' to '/users/:id' with a status of 302, 'Moved Temporarily'.
72
+ # # Examples:
73
+ # # '/old_users/show/1' # => '/users/1' (status of 302)
74
+ # # '/old_users/show/1?foo=bar' # => '/users/1?foo=bar' (status of 302)
75
+ # r.connect '/old_users/show/:id', :redirect_to => "/users/:id"
76
+ #
77
+ # # This will redirect '/old_blog' to '/blog' with a status of 301, 'Moved Permanently'.
78
+ # # Examples:
79
+ # # '/old_blog' # => '/blog' (status of 301)
80
+ # # '/old_blog?foo=bar' # => '/blogfoo=bar' (status of 301)
81
+ # r.connect '/old_blog', :redirect_to => "/blog", :status => 301
82
+ #
83
+ # # Connects "/comment/update/:id" to the CommentController and the 'update' action.
84
+ # # It will also create an :id parameter.
85
+ # # It will also create a named route in Mack::Routes::Urls called, 'c_u_url'.
86
+ # # In a controller or a view this: c_u_url(:id => 1) would return '/comment/update/1'.
87
+ # # It will also create a named route in Mack::Routes::Urls called, 'c_u_full_url'.
88
+ # # In a controller or a view this: c_u_full_url(:id => 1) would return 'http://example.org/comment/update/1'.
89
+ # r.c_u "/comment/update/:id", {:controller => :comment, :action => :update}
90
+ #
91
+ # # This creates 'Rails' style routes.
92
+ # # Any requests that come in that aren't found by explicit routes, will fall into these routes.
93
+ # # '/:controller/:action'
94
+ # # '/:controller/:action/:id'
95
+ # #
96
+ # # Example:
97
+ # # '/comment/show/1' # => Goes to CommentController, the 'show' action, with a parameter of 1.
98
+ # r.defaults
99
+ #
100
+ # end
101
+ #
102
+ # === Named Routes:
103
+ # Mack::Routes.build do |r|
104
+ # r.resource :users
105
+ # end
106
+ # See above in 'Defining Routes' to see what fully gets created when you map a resource, but let's look
107
+ # at the named route stuff that gets generated. In particular let's look at one example:
108
+ # '/users/:id' # => {:controller => 'users', :action => :show, :method => :get}
109
+ # # => users_show_url
110
+ # # => users_show_full_url
111
+ # The following can be used in controllers, views, and tests:
112
+ # users_show_url(:id => 1) # => '/users/1'
113
+ # # The following can only be used when there is a @request (Mack::Request) instance variable around:
114
+ # users_show_full_url(:id => 1) # => 'http://example.org/users/1'
115
+ #
116
+ # Mack::Routes.build do |r|
117
+ # r.hello_world "/", :controller => :home_page, :action => :hello
118
+ # end
119
+ # This will give you the following two methods:
120
+ # hello_world_url # => "/"
121
+ # hello_world_full_url # => "http://example.org/"
122
+ # These methods act just like the ones created when you use the resource method.
123
+ class RouteMap
124
+ include Singleton
125
+
126
+ def initialize # :nodoc:
127
+ @routes_list = []
128
+ end
129
+
130
+ # Creates 'Rails' style default mappings:
131
+ # "/:controller/:action/:id"
132
+ # "/:controller/:action"
133
+ # These get created for each of the 4 HTTP verbs.
134
+ def defaults
135
+ [:get, :post, :put, :delete].each do |verb|
136
+ connect("/:controller/:action/:id", :method => verb)
137
+ connect("/:controller/:action", :method => verb)
138
+ end
139
+ end
140
+
141
+ # Connects a url pattern to a controller, an action, and an HTTP verb.
142
+ def connect(pattern, options = {})
143
+ # set the default options:
144
+ options = {:action => :index, :method => :get}.merge(options)
145
+ meth = options[:method].to_sym
146
+ # if the pattern doesn't start with /, then add it.
147
+ pattern = "/" << pattern unless pattern.match(/^\//)
148
+ pt = pattern.downcase
149
+ route = Route.new(pt, regex_from_pattern(pt), meth, options)
150
+ routes_list << route
151
+ return route
152
+ end
153
+
154
+ # Sets up mappings and named routes for a resource.
155
+ def resource(controller)
156
+ connect_with_named_route("#{controller}_index", "/#{controller}", {:controller => controller, :action => :index, :method => :get})
157
+ connect_with_named_route("#{controller}_create", "/#{controller}", {:controller => controller, :action => :create, :method => :post})
158
+ connect_with_named_route("#{controller}_new", "/#{controller}/new", {:controller => controller, :action => :new, :method => :get})
159
+ connect_with_named_route("#{controller}_show", "/#{controller}/:id", {:controller => controller, :action => :show, :method => :get})
160
+ connect_with_named_route("#{controller}_edit", "/#{controller}/:id/edit", {:controller => controller, :action => :edit, :method => :get})
161
+ connect_with_named_route("#{controller}_update", "/#{controller}/:id/update", {:controller => controller, :action => :update, :method => :post})
162
+ connect_with_named_route("#{controller}_delete", "/#{controller}/:id", {:controller => controller, :action => :delete, :method => :delete})
163
+ end
164
+
165
+ def method_missing(sym, *args) # :nodoc:
166
+ connect_with_named_route(sym, args.first, args.last)
167
+ end
168
+
169
+ # Pass in a request and it will try and give you back a Hash representing the
170
+ # options for that route. IE: controller, action, verb, etc...
171
+ # If there are embedded options they added to the Hash. These parameters are
172
+ # also added to the 'params' object in the request.
173
+ # If the route can not be found a Mack::Errors::UndefinedRoute exception is raised.
174
+ def get_route_from_request(req)
175
+ pattern = req.path_info.downcase
176
+ unless pattern == "/"
177
+ pattern.chop! if pattern.match(/\/$/)
178
+ end
179
+ meth = (req.params("_method") || req.request_method.downcase).to_sym
180
+ begin
181
+ routes_list.each do |route|
182
+ if pattern.match(route.regex_pattern) && route.method == meth
183
+ r = route
184
+ opts = r.options_with_embedded_parameters(pattern)
185
+ req.merge_params(opts)
186
+ return opts
187
+ end
188
+ end
189
+ rescue Exception => e
190
+ raise e
191
+ end
192
+ # Can't find the route!
193
+ raise Mack::Errors::UndefinedRoute.new(req)
194
+ end # get
195
+
196
+ private
197
+ attr_reader :routes_list # :nodoc:
198
+
199
+ def connect_with_named_route(n_route, pattern, options = {})
200
+ route = connect(pattern, options)
201
+ Mack::Routes::Urls.class_eval %{
202
+ def #{n_route}_url(options = {})
203
+ url_for_pattern("#{route.original_pattern}", options)
204
+ end
205
+
206
+ def #{n_route}_full_url(options = {})
207
+ u = #{n_route}_url(options)
208
+ "\#{@request.full_host}\#{u}"
209
+ end
210
+ }
211
+ end
212
+
213
+ def regex_from_pattern(pattern)
214
+ pattern.chop! if pattern.match(/\/$/)
215
+ segs = []
216
+ sections = pattern.split("/")
217
+ sections.each_with_index do |sec, ind|
218
+ if sec.match(/\A:/)
219
+ segs << "[^/]+"
220
+ else
221
+ segs << sec
222
+ end
223
+ end
224
+ s = segs.join("/")
225
+ s = "/" if s.blank?
226
+ rx = /^#{s}$/
227
+ rx
228
+ end # regex_from_pattern
229
+
230
+ class Route # :nodoc:
231
+ attr_accessor :regex_pattern
232
+ attr_accessor :method
233
+ attr_accessor :original_pattern
234
+ attr_accessor :options
235
+ attr_accessor :embedded_parameters
236
+
237
+ def initialize(original_pattern, regex_pattern, method, options)
238
+ self.original_pattern = original_pattern
239
+ self.regex_pattern = regex_pattern
240
+ self.method = method
241
+ self.options = options
242
+ self.embedded_parameters = []
243
+ # find out where the embedded_parameters are:
244
+ original_pattern.split("/").each_with_index do |seg, ind|
245
+ if seg.match(/^:/)
246
+ self.embedded_parameters[ind] = seg[1..seg.length].to_sym
247
+ end
248
+ end
249
+ end
250
+
251
+ def options_with_embedded_parameters(uri)
252
+ opts = self.options
253
+ split_uri = uri.split("/")
254
+ self.embedded_parameters.each_with_index do |val, ind|
255
+ unless val.nil?
256
+ opts[val] = split_uri[ind]
257
+ end
258
+ end
259
+ opts
260
+ end
261
+
262
+ end # Route
263
+
264
+ end # RouteMap
265
+
266
+ end # Routes
267
+
268
+ end # Mack
data/routing/urls.rb ADDED
@@ -0,0 +1,54 @@
1
+ module Mack
2
+ module Routes
3
+ # This module is the repository for named_routes. See Mack::Routes::RouteMap for more information.
4
+ module Urls
5
+
6
+ # Takes a url pattern and merges it with the options to hopefully produce a well formed url.
7
+ # Query string parameters will get escaped.
8
+ #
9
+ # Example:
10
+ # url_for_pattern("/:controller/:action/:id", {:controller => :blog, :action => :show, :id => 1})
11
+ # # => "/blog/show/1
12
+ # url_for_pattern("/:controller/:action/:id", {:controller => :blog, :action => :show})
13
+ # # => "/blog/show/:id"
14
+ # url_for_pattern("/blog/:id", {:id => 1})
15
+ # # => "/blog/1
16
+ # url_for_pattern("/blog/:id", {:id => 1, :n_id => 2})
17
+ # # => "/blog/1?n_id=2
18
+ def url_for_pattern(url, options = {})
19
+ u = url.dup
20
+ unused_params = []
21
+ options.each_pair do |k, v|
22
+ vp = Rack::Utils.escape(v.to_param)
23
+ if u.gsub!(":#{k}", vp).nil?
24
+ unused_params << "#{Rack::Utils.escape(k)}=#{vp}"
25
+ end
26
+ end
27
+ unless unused_params.empty?
28
+ u << "?" << unused_params.sort.join("&")
29
+ end
30
+ u
31
+ end
32
+
33
+ # Builds a simple HTML page to be rendered when a redirect occurs.
34
+ # Hopefully no one sees the HTML, but in case the browser won't do the
35
+ # redirect it's nice to let people know what's happening.
36
+ def redirect_html(original_path, new_path, status)
37
+ %{
38
+ <!DOCTYPE HTML PUBLIC
39
+ "-//IETF//DTD HTML 2.0//EN">
40
+ <html>
41
+ <head>
42
+ <title>#{status} Found</title>
43
+ </head>
44
+ <body>
45
+ <h1>Found</h1>
46
+ <p>The document has moved <a href="#{new_path}">here</a>.</p>
47
+ </body>
48
+ </html>
49
+ }
50
+ end
51
+
52
+ end # Urls
53
+ end # Routes
54
+ end # Mack
@@ -0,0 +1,293 @@
1
+ require 'erb'
2
+ module Mack
3
+ module Controller # :nodoc:
4
+ # All controllers in a Mack application have to extend this class. I'll be honest, if they don't extend this class
5
+ # then, well, things just won't work very well!
6
+ #
7
+ # Example:
8
+ # class MyAwesomeController < Mack::Controller::Base
9
+ # def index
10
+ # render(:text => "Hello World!")
11
+ # end
12
+ # end
13
+ class Base
14
+
15
+ # See Mack::Request for more information.
16
+ attr_reader :request
17
+ # See Mack::Response for more information.
18
+ attr_reader :response
19
+ # The 'underscore' version of the controller requested. Example: 'my_awesome_controller'
20
+ attr_reader :controller_name
21
+ # The name of the action being requested.
22
+ attr_reader :action_name
23
+ # See Mack::CookieJar for more information.
24
+ attr_reader :cookies
25
+
26
+ def initialize(request, response, cookies)
27
+ @request = request
28
+ @response = response
29
+ @render_options = {}
30
+ @render_performed = false
31
+ @controller_name = params(:controller)
32
+ @action_name = params(:action)
33
+ @cookies = cookies
34
+ end
35
+
36
+ # Gives access to all the parameters for this request.
37
+ def params(key)
38
+ self.request.params(key)
39
+ end
40
+
41
+ # Gives access to the session. See Mack::Session for more information.
42
+ def session
43
+ self.request.session
44
+ end
45
+
46
+ # This does the heavy lifting for controllers. It calls the action, and then completes the rendering
47
+ # of the action to a String to send back to Rack.
48
+ def run
49
+ run_filters(:before)
50
+ # check to see if this controller responds to this action.
51
+ # only run public methods!
52
+ if self.public_methods.include?(self.action_name)
53
+ # call the action and capture the results to a variable.
54
+ @result_of_action_called = self.send(self.action_name)
55
+ else
56
+ # there is no action on this controller, so call the render method
57
+ # which will check the view directory and run action.html.erb if it exists.
58
+ render(:action => self.action_name)
59
+ end
60
+ run_filters(:after)
61
+ # do the work of rendering.
62
+ @final_rendered_action = complete_layout_render(complete_action_render)
63
+ run_filters(:after_render)
64
+ @final_rendered_action
65
+ end
66
+
67
+ # This method can be called from within an action. This 'registers' the render that you
68
+ # would like to happen once the action is completed.
69
+ #
70
+ # It's important to note that calling render in an action does NOT end the processing of
71
+ # the action. The action will continue to process unless you explicity put 'return' before the
72
+ # render call.
73
+ #
74
+ # If you call render twice in an action then a Mack::Errors::DoubleRender error will be thrown.
75
+ #
76
+ # An implicit render will happen if one is not specified in the action.
77
+ #
78
+ # Only :action and :text will get layouts wrapped around them.
79
+ #
80
+ # Examples:
81
+ # class MyAwesomeController < Mack::Controller::Base
82
+ # # This will render the text 'Hello World!' to the screen.
83
+ # def index
84
+ # render(:text => "Hello World!")
85
+ # end
86
+ #
87
+ # # This will render MACK_ROOT/views/my_awesome_controller/foo.html.erb
88
+ # def show
89
+ # render(:action => :foo)
90
+ # end
91
+ #
92
+ # # This will raise a Mack::Errors::DoubleRender error.
93
+ # def edit
94
+ # render(:text => "Hello World!")
95
+ # render(:action => :foo)
96
+ # end
97
+ #
98
+ # # This will render MACK_ROOT/views/my_awesome_controller/delete.html.erb
99
+ # def delete
100
+ # end
101
+ #
102
+ # # This will render the text 'Hello World!' to the screen. Assuming that
103
+ # # there is no file: MACK_ROOT/views/my_awesome_controller/update.html.erb
104
+ # # The reason for this is if the view for the action doesn't exist, and the
105
+ # # last thing returned from the action is a String, that string will be returned.
106
+ # def update
107
+ # "Hello World!"
108
+ # end
109
+ #
110
+ # # This will raise a Mack::Errors::InvalidRenderType error. Assuming that
111
+ # # there is no file: MACK_ROOT/views/my_awesome_controller/create.html.erb
112
+ # def create
113
+ # @user = User.find(1)
114
+ # end
115
+ #
116
+ # # This will raise a Errno::ENOENT error. Assuming that
117
+ # # there is no file: MACK_ROOT/views/my_awesome_controller/bar.html.erb
118
+ # def bar
119
+ # render(:action => "bar")
120
+ # end
121
+ #
122
+ # # This will render a file from the public directory. Files served from the
123
+ # # public directory do NOT get layouts. The default file extension for files
124
+ # # served from the public directory is .html. This can be overridden with the
125
+ # # :ext => ".<ext>" option.
126
+ # def show_public_file
127
+ # render(:public => "my/files/foo")
128
+ # end
129
+ #
130
+ # # This will render a file from the public directory. Files served from the
131
+ # # public directory do NOT get layouts. The default file extension for files
132
+ # # served from the public directory is .html. This can be overridden with the
133
+ # # :ext => ".<ext>" option.
134
+ # def show_public_xml_file
135
+ # render(:public => "my/files/foo", :ext => ".xml")
136
+ # end
137
+ #
138
+ # # This will render a partial. In this case it will look for:
139
+ # # MACK_ROOT/views/my_awesome_controller/_latest_news.html.erb
140
+ # # Partials do NOT get wrapped in layouts.
141
+ # def latest_news
142
+ # render(:partial => :latest_news)
143
+ # end
144
+ #
145
+ # # This will render a partial. In this case it will look for:
146
+ # # MACK_ROOT/views/some_other/_old_news.html.erb
147
+ # # Partials do NOT get wrapped in layouts.
148
+ # def latest_news
149
+ # render(:partial => "some_other/old_news")
150
+ # end
151
+ # end
152
+ def render(options = {:action => self.action_name})
153
+ raise Mack::Errors::DoubleRender.new if render_performed?
154
+ unless options[:action] || options[:text]
155
+ options = {:layout => false}.merge(options)
156
+ end
157
+ @render_options = options
158
+ @render_performed = true
159
+ end
160
+
161
+ # This will redirect the request to the specified url. A default status of
162
+ # 302, Moved Temporarily, is set if no status is specified. A simple HTML
163
+ # page is rendered in case the redirect does not occur.
164
+ def redirect_to(url, status = 302)
165
+ response.status = status
166
+ response[:location] = url
167
+ render(:text => redirect_html(request.path_info, url, status))
168
+ end
169
+
170
+ # Returns true/false depending on whether the render action has been called yet.
171
+ def render_performed?
172
+ @render_performed
173
+ end
174
+
175
+ # Gives access to the MACK_DEFAULT_LOGGER.
176
+ def logger
177
+ MACK_DEFAULT_LOGGER
178
+ end
179
+
180
+ private
181
+
182
+ def run_filters(type)
183
+ filters = self.class.controller_filters[type]
184
+ return true if filters.empty?
185
+ filters.each do |filter|
186
+ if filter.run?(self.action_name.to_sym)
187
+ r = self.send(filter.filter_method)
188
+ raise Mack::Errors::FilterChainHalted.new(filter.filter_method) unless r
189
+ end
190
+ end
191
+ end
192
+
193
+ def complete_layout_render(action_content)
194
+ @content_for_layout = action_content
195
+ # if @render_options[:action] || @render_options[:text]
196
+ # only action and text should get a layout.
197
+ # if a layout is specified, use that:
198
+ # i use has_key? here because we want people
199
+ # to be able to override layout with nil/false.
200
+ if @render_options.has_key?(:layout)
201
+ if @render_options[:layout]
202
+ return Mack::ViewBinder.new(self).render(@render_options.merge({:action => "layouts/#{@render_options[:layout]}"}))
203
+ else
204
+ # someone has specified NO layout via nil/false
205
+ return @content_for_layout
206
+ end
207
+ else layout
208
+ # use the layout specified by the layout method
209
+ return Mack::ViewBinder.new(self).render(@render_options.merge({:action => "layouts/#{layout}"}))
210
+ end
211
+ # end
212
+ @content_for_layout
213
+ end
214
+
215
+ def complete_action_render
216
+ if render_performed?
217
+ return Mack::ViewBinder.new(self, @render_options).render(@render_options)
218
+ else
219
+ begin
220
+ # try action.html.erb
221
+ return Mack::ViewBinder.new(self).render({:action => self.action_name})
222
+ rescue Exception => e
223
+ if @result_of_action_called.is_a?(String)
224
+ @render_options[:text] = @result_of_action_called
225
+ return Mack::ViewBinder.new(self).render(@render_options)
226
+ end
227
+ raise e
228
+ end
229
+ end
230
+ end # complete_action_render
231
+
232
+ def layout
233
+ :application
234
+ end
235
+
236
+ public
237
+ class << self
238
+
239
+ def before_filter(meth, options = {})
240
+ add_filter(:before, meth, options)
241
+ end
242
+
243
+ def after_filter(meth, options = {})
244
+ add_filter(:after, meth, options)
245
+ end
246
+
247
+ def after_render_filter(meth, options = {})
248
+ add_filter(:after_render, meth, options)
249
+ end
250
+
251
+ def add_filter(type, meth, options)
252
+ controller_filters[type.to_sym] << Mack::Controller::Filter.new(meth, options)
253
+ end
254
+
255
+ def controller_filters
256
+ @controller_filters = {:before => [], :after => [], :after_render => []} unless @controller_filters
257
+ @controller_filters
258
+ end
259
+
260
+ # Sets a layout to be used by a particular controller.
261
+ #
262
+ # Example:
263
+ # class MyAwesomeController < Mack::Controller::Base
264
+ # # Sets all actions to use: "#{MACK_ROOT}/app/views/layouts/dark.html.erb" as they're layout.
265
+ # layout :dark
266
+ #
267
+ # def index
268
+ # # Sets this action to use: "#{MACK_ROOT}/app/views/layouts/bright.html.erb" as it's layout.
269
+ # render(:text => "Welcome...", :layout => :bright)
270
+ # end
271
+ #
272
+ # def index
273
+ # # This will no use a layout.
274
+ # render(:text => "Welcome...", :layout => false)
275
+ # end
276
+ # end
277
+ #
278
+ # The default layout is "#{MACK_ROOT}/app/views/layouts/application.html.erb".
279
+ #
280
+ # If a layout is specified, and it doesn't exist a Mack::Errors::UnknownLayout error will be raised.
281
+ def layout(lay)
282
+ self.class_eval do
283
+ define_method(:layout) do
284
+ lay
285
+ end
286
+ end
287
+ end # layout
288
+
289
+ end # class << self
290
+
291
+ end # Base
292
+ end # Controller
293
+ end # Mack