mack 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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