mack 0.7.1.1 → 0.8.0
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.
- data/CHANGELOG +32 -0
- data/bin/gem_load_path.rb +1 -1
- data/bin/mackery +0 -1
- data/bin/mackery-server +5 -1
- data/lib/mack/assets/asset_helpers.rb +51 -0
- data/lib/mack/assets/assets_mgr.rb +165 -0
- data/lib/mack/controller/controller.rb +4 -4
- data/lib/mack/controller/cookie_jar.rb +1 -1
- data/lib/mack/controller/request.rb +13 -3
- data/lib/mack/controller/response.rb +12 -0
- data/lib/mack/core_extensions/kernel.rb +69 -0
- data/lib/mack/core_extensions/symbol.rb +4 -0
- data/lib/mack/errors/errors.rb +5 -1
- data/lib/mack/generators/controller_generator/manifest.yml +2 -2
- data/lib/mack/generators/controller_helper_generator/manifest.yml +2 -2
- data/lib/mack/generators/mack_application_generator/manifest.yml +10 -2
- data/lib/mack/generators/mack_application_generator/templates/config/{app_config/default.yml.template → configatron/default.rb.template} +10 -15
- data/lib/mack/generators/mack_application_generator/templates/config/{app_config/development.yml.template → configatron/development.rb.template} +1 -1
- data/lib/mack/generators/mack_application_generator/templates/config/{app_config/production.yml.template → configatron/production.rb.template} +0 -0
- data/lib/mack/generators/mack_application_generator/templates/config/{app_config/test.yml.template → configatron/test.rb.template} +1 -1
- data/lib/mack/generators/mack_application_generator/templates/public/404.html.template +15 -0
- data/lib/mack/generators/mack_application_generator/templates/public/500.html.template +15 -0
- data/lib/mack/generators/view_helper_generator/manifest.yml +2 -2
- data/lib/mack/initialization/application.rb +9 -5
- data/lib/mack/initialization/boot_loader.rb +2 -104
- data/lib/mack/initialization/configuration.rb +72 -69
- data/lib/mack/initialization/console.rb +1 -1
- data/lib/mack/initialization/helpers.rb +1 -6
- data/lib/mack/initialization/logging/basic_layout.rb +14 -0
- data/lib/mack/initialization/logging/color_layout.rb +23 -0
- data/lib/mack/initialization/logging/filter.rb +45 -0
- data/lib/mack/initialization/logging.rb +33 -89
- data/lib/mack/initialization/plugins.rb +1 -1
- data/lib/mack/rendering/engine/builder.rb +3 -0
- data/lib/mack/rendering/engine/erubis.rb +28 -16
- data/lib/mack/rendering/type/file_base.rb +1 -1
- data/lib/mack/rendering/type/url.rb +3 -3
- data/lib/mack/rendering/view_template.rb +4 -7
- data/lib/mack/routing/resource_proxy.rb +33 -0
- data/lib/mack/routing/route_map.rb +122 -288
- data/lib/mack/routing/route_object.rb +88 -0
- data/lib/mack/routing/routes.rb +169 -0
- data/lib/mack/routing/urls.rb +39 -5
- data/lib/mack/runner.rb +65 -32
- data/lib/mack/runner_helpers/request_logger.rb +3 -3
- data/lib/mack/runner_helpers/session.rb +4 -4
- data/lib/mack/sessions/cookie_session_store.rb +3 -3
- data/lib/mack/sessions/session.rb +1 -1
- data/lib/mack/sessions/session_store_base.rb +1 -1
- data/lib/mack/tasks/gem_tasks.rake +156 -1
- data/lib/mack/tasks/mack_dump_tasks.rake +1 -1
- data/lib/mack/tasks/mack_update_tasks.rake +85 -1
- data/lib/mack/tasks/rake_rules.rake +6 -0
- data/lib/mack/tasks/test_tasks.rake +4 -4
- data/lib/mack/testing/helpers.rb +13 -6
- data/lib/mack/testing/rspec.rb +27 -9
- data/lib/mack/testing/test_case.rb +1 -1
- data/lib/mack/utils/ansi/ansi_color.rb +4 -1
- data/lib/mack/utils/forgery_detector.rb +3 -3
- data/lib/mack/utils/http_status_codes.rb +19 -0
- data/lib/mack/utils/http_status_codes.yml +55 -0
- data/lib/mack/utils/paths.rb +32 -32
- data/lib/mack/utils/reloader.rb +60 -0
- data/lib/mack/utils/server.rb +3 -3
- data/lib/mack/version.rb +1 -1
- data/lib/mack/view_helpers/all_helpers.rb +7 -0
- data/lib/mack/view_helpers/date_time_helpers.rb +16 -10
- data/lib/mack/view_helpers/form_helpers.rb +1 -1
- data/lib/mack/view_helpers/html_helpers.rb +22 -1
- data/lib/mack/view_helpers/link_helpers.rb +51 -10
- data/lib/mack/view_helpers/string_helpers.rb +1 -1
- data/lib/mack.rb +0 -1
- data/lib/mack_core.rb +8 -8
- data/lib/mack_tasks.rb +1 -1
- metadata +27 -15
- data/lib/mack/view_helpers/asset_helpers.rb +0 -50
@@ -0,0 +1,169 @@
|
|
1
|
+
module Mack
|
2
|
+
# Routes are the back bone of the Mack framework. They are used to map incoming urls to controllers.
|
3
|
+
#
|
4
|
+
# === Defining Routes:
|
5
|
+
# Example:
|
6
|
+
# Mack::Routes.build do |r|
|
7
|
+
#
|
8
|
+
# # Connects "/" to the HomeController and the '/' action.
|
9
|
+
# r.connect "/", :controller => :home
|
10
|
+
#
|
11
|
+
# # Connects "/foo", to the HomeController and the 'foo' action.
|
12
|
+
# r.connect "/foo", :controller => :home, :action => :foo
|
13
|
+
#
|
14
|
+
# # Connects "/blog" to the BlogController and the 'list' action.
|
15
|
+
# r.connect "/blog", :controller => :blog, :action => :list
|
16
|
+
#
|
17
|
+
# # Connects "/blog/:id" to the BlogController and the 'index' action.
|
18
|
+
# # It will also take the second half of the url and map it to a parameter called :id.
|
19
|
+
# # Example:
|
20
|
+
# # '/blog/1' # => goes to the BlogController, 'index' action, and has an :id parameter == 1.
|
21
|
+
# r.connect "/blog/:id", :controller => :blog, :action => :index
|
22
|
+
#
|
23
|
+
# # Connects "/blog/create" to the BlogController and the 'create' action.
|
24
|
+
# # It also insists that the HTTP method be 'post'. If it's not 'post' it will not match this route.
|
25
|
+
# r.connect "/blog/create", :controller => :blog, :action => :create, :method => :post
|
26
|
+
#
|
27
|
+
# # Connects "/comment/destroy/:id" to the CommentController and the 'destroy' action.
|
28
|
+
# # It also insists that the HTTP method be 'delete'. If it's not 'delete' it will not match this route.
|
29
|
+
# # It will also create an :id parameter.
|
30
|
+
# r.connect "/comment/destroy/:id", :controller => :comment, :action => :destroy, :method => :delete
|
31
|
+
#
|
32
|
+
# # This will create 'RESTful' routes. Unlike Rails, it doesn't generate a mixture of singular/plural
|
33
|
+
# # routes. It uses whatever you pass in to it. This will also create named routes in Mack::Routes::Urls.
|
34
|
+
# # Examples:
|
35
|
+
# # '/users' # => {:controller => 'users', :action => :index, :method => :get}
|
36
|
+
# # # => users_index_url
|
37
|
+
# # # => users_index_full_url
|
38
|
+
# # '/users' # => {:controller => 'users', :action => :create, :method => :post}
|
39
|
+
# # # => users_create_url
|
40
|
+
# # # => users_create_full_url
|
41
|
+
# # '/users/new' # => {:controller => 'users', :action => :new, :method => :get}
|
42
|
+
# # # => users_new_url
|
43
|
+
# # # => users_new_full_url
|
44
|
+
# # '/users/:id' # => {:controller => 'users', :action => :show, :method => :get}
|
45
|
+
# # # => users_show_url
|
46
|
+
# # # => users_show_full_url
|
47
|
+
# # '/users/:id/:edit # => {:controller => 'users', :action => :edit, :method => :get}
|
48
|
+
# # # => users_edit_url
|
49
|
+
# # # => users_edit_full_url
|
50
|
+
# # '/users/:id # => {:controller => 'users', :action => :update, :method => :put}
|
51
|
+
# # # => users_update_url
|
52
|
+
# # # => users_update_full_url
|
53
|
+
# # '/users/:id # => {:controller => 'users', :action => :delete, :method => :delete}
|
54
|
+
# # # => users_delete_url
|
55
|
+
# # # => users_delete_full_url
|
56
|
+
# r.resource :users
|
57
|
+
#
|
58
|
+
# # This will redirect '/old_users/show/:id' to '/users/:id' with a status of 302, 'Moved Temporarily'.
|
59
|
+
# # Examples:
|
60
|
+
# # '/old_users/show/1' # => '/users/1' (status of 302)
|
61
|
+
# # '/old_users/show/1?foo=bar' # => '/users/1?foo=bar' (status of 302)
|
62
|
+
# r.connect '/old_users/show/:id', :redirect_to => "/users/:id"
|
63
|
+
#
|
64
|
+
# # This will redirect '/old_blog' to '/blog' with a status of 301, 'Moved Permanently'.
|
65
|
+
# # Examples:
|
66
|
+
# # '/old_blog' # => '/blog' (status of 301)
|
67
|
+
# # '/old_blog?foo=bar' # => '/blogfoo=bar' (status of 301)
|
68
|
+
# r.connect '/old_blog', :redirect_to => "/blog", :status => 301
|
69
|
+
#
|
70
|
+
# # Connects "/comment/update/:id" to the CommentController and the 'update' action.
|
71
|
+
# # It will also create an :id parameter.
|
72
|
+
# # It will also create a named route in Mack::Routes::Urls called, 'c_u_url'.
|
73
|
+
# # In a controller or a view this: c_u_url(:id => 1) would return '/comment/update/1'.
|
74
|
+
# # It will also create a named route in Mack::Routes::Urls called, 'c_u_full_url'.
|
75
|
+
# # In a controller or a view this: c_u_full_url(:id => 1) would return 'http://example.org/comment/update/1'.
|
76
|
+
# r.c_u "/comment/update/:id", {:controller => :comment, :action => :update}
|
77
|
+
#
|
78
|
+
# # This creates 'Rails' style routes.
|
79
|
+
# # Any requests that come in that aren't found by explicit routes, will fall into these routes.
|
80
|
+
# # '/:controller/:action'
|
81
|
+
# # '/:controller/:action/:id'
|
82
|
+
# #
|
83
|
+
# # Example:
|
84
|
+
# # '/comment/show/1' # => Goes to CommentController, the 'show' action, with a parameter of 1.
|
85
|
+
# r.defaults
|
86
|
+
#
|
87
|
+
# end
|
88
|
+
#
|
89
|
+
# === Named Routes:
|
90
|
+
# Mack::Routes.build do |r|
|
91
|
+
# r.resource :users
|
92
|
+
# end
|
93
|
+
# See above in 'Defining Routes' to see what fully gets created when you map a resource, but let's look
|
94
|
+
# at the named route stuff that gets generated. In particular let's look at one example:
|
95
|
+
# '/users/:id' # => {:controller => 'users', :action => :show, :method => :get}
|
96
|
+
# # => users_show_url
|
97
|
+
# # => users_show_full_url
|
98
|
+
# The following can be used in controllers, views, and tests:
|
99
|
+
# users_show_url(:id => 1) # => '/users/1'
|
100
|
+
# # The following can only be used when there is a @request (Mack::Request) instance variable around:
|
101
|
+
# users_show_full_url(:id => 1) # => 'http://example.org/users/1'
|
102
|
+
#
|
103
|
+
# Mack::Routes.build do |r|
|
104
|
+
# r.hello_world "/", :controller => :home_page, :action => :hello
|
105
|
+
# end
|
106
|
+
# This will give you the following two methods:
|
107
|
+
# hello_world_url # => "/"
|
108
|
+
# hello_world_full_url # => "http://example.org/"
|
109
|
+
# These methods act just like the ones created when you use the resource method.
|
110
|
+
#
|
111
|
+
# === Exception Routes:
|
112
|
+
# You can define a route that will catch exceptions that are raised in other controllers.
|
113
|
+
#
|
114
|
+
# Mack::Routes.build do |r|
|
115
|
+
# r.handle_error Mack::ResourceNotFound, :controller => :oops, :action => :404
|
116
|
+
# r.handle_error HollyCrapError, :controller => :oops, :action => :500
|
117
|
+
# end
|
118
|
+
# In the example if an action raises a Mack::ResourceNotFound it will be caught and rendered
|
119
|
+
# using the OopsController and the 404 action.
|
120
|
+
# If A HollyCrapError is thrown it will be caught and rendered using the OopsController and the 500 action.
|
121
|
+
# You can catch all exceptions using Exception.
|
122
|
+
module Routes
|
123
|
+
include Extlib::Hook
|
124
|
+
|
125
|
+
class << self
|
126
|
+
|
127
|
+
# This method yields up Mack::Routes::RouteMap and allows for the creation of routes in the system.
|
128
|
+
def build
|
129
|
+
yield Mack::Routes::RouteMap.instance
|
130
|
+
Mack::Routes::Urls.include_safely_into(Mack::Controller,
|
131
|
+
Mack::Rendering::ViewTemplate,
|
132
|
+
Test::Unit::TestCase)
|
133
|
+
end
|
134
|
+
|
135
|
+
def any?
|
136
|
+
Mack::Routes::RouteMap.instance.any?
|
137
|
+
end
|
138
|
+
|
139
|
+
def empty?
|
140
|
+
Mack::Routes::RouteMap.instance.empty?
|
141
|
+
end
|
142
|
+
|
143
|
+
def reset!
|
144
|
+
Mack::Routes::RouteMap.instance.reset!
|
145
|
+
end
|
146
|
+
|
147
|
+
# Pass in a request or a String and it will try and give you back a Hash representing the
|
148
|
+
# options for that route. IE: controller, action, verb, etc...
|
149
|
+
# If there are embedded options they added to the Hash. These parameters are
|
150
|
+
# also added to the 'params' object in the request.
|
151
|
+
# If the route can not be found a Mack::Errors::UndefinedRoute exception is raised.
|
152
|
+
def retrieve(url_or_request, verb = :get)
|
153
|
+
Mack::Routes::RouteMap.instance.retrieve(url_or_request, verb)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Given an error class name it will return a routing options Hash, or nil, if one
|
157
|
+
# has not been mapped.
|
158
|
+
def retrieve_from_error(error)
|
159
|
+
Mack::Routes::RouteMap.instance.retrieve_from_error(error)
|
160
|
+
end
|
161
|
+
|
162
|
+
def inspect # :nodoc:
|
163
|
+
Mack::Routes::RouteMap.instance.inspect
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
end # Routes
|
169
|
+
end # Mack
|
data/lib/mack/routing/urls.rb
CHANGED
@@ -20,11 +20,20 @@ module Mack
|
|
20
20
|
u = "/" if url.blank?
|
21
21
|
unused_params = []
|
22
22
|
format = nil
|
23
|
+
host_options = {:host => options[:host], :port => options[:port], :scheme => options[:scheme]}
|
24
|
+
options - [:host, :port, :scheme]
|
23
25
|
options.each_pair do |k, v|
|
24
26
|
unless k.to_sym == :format
|
25
|
-
|
26
|
-
|
27
|
-
|
27
|
+
if u.match(/\*#{k}/)
|
28
|
+
vp = [v].flatten.collect {|c| Rack::Utils.escape(c.to_param)}
|
29
|
+
if u.gsub!("*#{k}", File.join(vp)).nil?
|
30
|
+
unused_params << "#{Rack::Utils.escape(k)}=#{vp}"
|
31
|
+
end
|
32
|
+
else
|
33
|
+
vp = Rack::Utils.escape(v.to_param)
|
34
|
+
if u.gsub!(":#{k}", vp).nil?
|
35
|
+
unused_params << "#{Rack::Utils.escape(k)}=#{vp}"
|
36
|
+
end
|
28
37
|
end
|
29
38
|
else
|
30
39
|
format = v
|
@@ -36,13 +45,14 @@ module Mack
|
|
36
45
|
unless unused_params.empty?
|
37
46
|
u << "?" << unused_params.sort.join("&")
|
38
47
|
end
|
39
|
-
u
|
48
|
+
File.join(build_full_host_from_options(host_options), u)
|
49
|
+
# u
|
40
50
|
end
|
41
51
|
|
42
52
|
# Builds a simple HTML page to be rendered when a redirect occurs.
|
43
53
|
# Hopefully no one sees the HTML, but in case the browser won't do the
|
44
54
|
# redirect it's nice to let people know what's happening.
|
45
|
-
def redirect_html(original_path, new_path, status)
|
55
|
+
def redirect_html(original_path, new_path, status) # :nodoc:
|
46
56
|
%{
|
47
57
|
<!DOCTYPE HTML PUBLIC
|
48
58
|
"-//IETF//DTD HTML 2.0//EN">
|
@@ -58,6 +68,30 @@ module Mack
|
|
58
68
|
}
|
59
69
|
end
|
60
70
|
|
71
|
+
def self.create_method(sym, &block) # :nodoc:
|
72
|
+
define_method(sym, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
def build_full_host_from_options(options = {})
|
77
|
+
scheme = options[:scheme]
|
78
|
+
host = options[:host]
|
79
|
+
port = options[:port]
|
80
|
+
return '' if host.blank? && scheme.blank? && port.nil?
|
81
|
+
if @request
|
82
|
+
scheme = @request.scheme if scheme.nil?
|
83
|
+
port = @request.port if port.nil?
|
84
|
+
host = @request.host if host.nil?
|
85
|
+
end
|
86
|
+
port = 80 if port.nil?
|
87
|
+
port = case port.to_i
|
88
|
+
when 80, 443
|
89
|
+
else
|
90
|
+
":#{port}"
|
91
|
+
end
|
92
|
+
return "#{scheme.downcase}://#{host.downcase}#{port}"
|
93
|
+
end
|
94
|
+
|
61
95
|
end # Urls
|
62
96
|
end # Routes
|
63
97
|
end # Mack
|
data/lib/mack/runner.rb
CHANGED
@@ -16,10 +16,11 @@ module Mack
|
|
16
16
|
# This method needs to be defined as part of the Rack framework. As is noted for the Mack::Runner
|
17
17
|
# class, this is where the center of the Mack framework lies.
|
18
18
|
def call(env)
|
19
|
+
env["rack.errors"] = StringIO.new # Send Rack errors nowhere fast!
|
19
20
|
begin
|
20
21
|
setup(env)
|
21
22
|
begin
|
22
|
-
route = Mack::Routes
|
23
|
+
route = Mack::Routes.retrieve(self.request)
|
23
24
|
if route[:redirect_to]
|
24
25
|
# because the route is specified to be a redirect, let's do that:
|
25
26
|
redirect_to(route)
|
@@ -29,48 +30,70 @@ module Mack
|
|
29
30
|
@original_action = route[:action]
|
30
31
|
run_controller(route)
|
31
32
|
end
|
32
|
-
|
33
|
-
# return try_to_find_resource(env, e)
|
33
|
+
# return teardown
|
34
34
|
rescue Exception => e
|
35
|
-
|
36
|
-
|
37
|
-
self.request.all_params[:original_action] = @original_action
|
35
|
+
# There was an exception, let's see if there's a handler for this error in routes:
|
36
|
+
route = Mack::Routes.retrieve_from_error(e.class)
|
38
37
|
unless route.nil?
|
38
|
+
self.request.all_params[:original_controller] = @original_controller
|
39
|
+
self.request.all_params[:original_action] = @original_action
|
40
|
+
# There is a handler, let's try running that:
|
39
41
|
run_controller(route, e)
|
40
42
|
else
|
41
|
-
|
43
|
+
# If we can't find the resource, or there's no route, let's check the public directory:
|
44
|
+
case e
|
45
|
+
when Mack::Errors::ResourceNotFound, Mack::Errors::UndefinedRoute
|
42
46
|
return try_to_find_resource(env, e)
|
43
47
|
else
|
48
|
+
# Re-raise the exception
|
44
49
|
raise e
|
45
50
|
end
|
46
51
|
end
|
52
|
+
# return teardown
|
47
53
|
end
|
48
|
-
|
54
|
+
# Capture all the Exceptions for this call:
|
49
55
|
rescue Exception => e
|
50
|
-
Mack.logger.error
|
51
|
-
|
56
|
+
Mack.logger.error e
|
57
|
+
case e
|
58
|
+
when Mack::Errors::ResourceNotFound, Mack::Errors::UndefinedRoute
|
59
|
+
handle_error(404, 'Page Not Found!', e)
|
60
|
+
# If it's any other type of exception render the 500.html page:
|
61
|
+
else
|
62
|
+
handle_error(500, 'Server Error!', e)
|
63
|
+
end
|
64
|
+
# return teardown
|
65
|
+
ensure
|
66
|
+
teardown
|
52
67
|
end
|
68
|
+
return self.response.finish
|
53
69
|
end
|
54
70
|
|
55
71
|
#private
|
56
72
|
def run_controller(route, e = nil)
|
57
|
-
|
58
|
-
|
59
|
-
cont = "#{route[:controller].to_s.camelcase}Controller".constantize
|
60
|
-
rescue NameError => e
|
61
|
-
raise Mack::Errors::ResourceNotFound.new(self.request.path_info)
|
62
|
-
end
|
63
|
-
self.request.all_params[:controller] = route[:controller]
|
64
|
-
self.request.all_params[:action] = route[:action]
|
65
|
-
self.request.instance_variable_set("@params_controller", nil)
|
66
|
-
self.request.instance_variable_set("@params_action", nil)
|
73
|
+
runner_block = route[:runner_block]
|
74
|
+
route - :runner_block
|
67
75
|
|
68
|
-
|
69
|
-
|
70
|
-
|
76
|
+
self.request.params = self.request.all_params.merge(route)
|
77
|
+
self.response.content_type = Mack::Utils::MimeTypes[self.request.params[:format]]
|
78
|
+
catch(:finished) do
|
79
|
+
if runner_block
|
80
|
+
runner_block.call(self.request, self.response, self.cookies)
|
81
|
+
end
|
82
|
+
|
83
|
+
# let's handle a normal request:
|
84
|
+
begin
|
85
|
+
cont = "#{route[:controller].to_s.camelcase}Controller".constantize
|
86
|
+
rescue NameError => e
|
87
|
+
raise Mack::Errors::ResourceNotFound.new(self.request.path_info)
|
88
|
+
end
|
89
|
+
|
90
|
+
c = cont.new
|
91
|
+
c.configure_controller(self.request, self.response, self.cookies)
|
92
|
+
c.caught_exception = e unless e.nil?
|
71
93
|
|
72
|
-
|
73
|
-
|
94
|
+
self.response.controller = c
|
95
|
+
return self.response.write(c.run)
|
96
|
+
end
|
74
97
|
end
|
75
98
|
|
76
99
|
# Setup the request, response, cookies, session, etc...
|
@@ -91,17 +114,16 @@ module Mack
|
|
91
114
|
self.runner_helpers.reverse.each do |help|
|
92
115
|
help.complete(self.request, self.response, self.cookies)
|
93
116
|
end
|
94
|
-
self.response.finish
|
117
|
+
# self.response.finish
|
95
118
|
end
|
96
119
|
|
97
120
|
def try_to_find_resource(env, exception)
|
98
|
-
env = env.dup
|
99
121
|
# we can't find a route for this, so let's try and see if it's in the public directory:
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
if File.exists?(Mack::Paths.public(
|
104
|
-
return Rack::File.new(Mack::Paths.public).call(
|
122
|
+
path = env["PATH_INFO"].dup
|
123
|
+
path << ".html" if File.extname(path).blank?
|
124
|
+
|
125
|
+
if File.exists?(Mack::Paths.public(path))
|
126
|
+
return Rack::File.new(Mack::Paths.public).call(Rack::MockRequest.env_for(path))
|
105
127
|
else
|
106
128
|
raise exception
|
107
129
|
end
|
@@ -122,5 +144,16 @@ module Mack
|
|
122
144
|
self.response.write(redirect_html(self.request.path_info, url, status))
|
123
145
|
end
|
124
146
|
|
147
|
+
private
|
148
|
+
def handle_error(status, body, e)
|
149
|
+
self.response.status = status
|
150
|
+
raise e if configatron.mack.show_exceptions
|
151
|
+
path = Mack::Paths.public("#{status}.html")
|
152
|
+
if File.exists?(path)
|
153
|
+
body = File.read(path)
|
154
|
+
end
|
155
|
+
self.response.write(body)
|
156
|
+
end
|
157
|
+
|
125
158
|
end
|
126
159
|
end
|
@@ -16,11 +16,11 @@ module Mack
|
|
16
16
|
@end_time = Time.now
|
17
17
|
@total_time = @end_time - @start_time
|
18
18
|
@requests_per_second = (1 / @total_time).round
|
19
|
-
if
|
19
|
+
if configatron.mack.log.detailed_requests
|
20
20
|
msg = "\n\t[#{request.params[:method].to_s.upcase}] '#{request.path_info}'\n"
|
21
|
-
msg << "\tSession ID: #{request.session.id}\n" if
|
21
|
+
msg << "\tSession ID: #{request.session.id}\n" if configatron.mack.use_sessions
|
22
22
|
msg << "\tParameters: #{request.all_params}\n"
|
23
|
-
msg << Mack::Utils::Ansi::Color.wrap(
|
23
|
+
msg << Mack::Utils::Ansi::Color.wrap(configatron.mack.log.colors.completed, "\tCompleted in #{@total_time} (#{@requests_per_second} reqs/sec) | #{response.status} (#{Mack::Utils::HttpStatusCodes.get(response.status)}) [#{request.full_host}]")
|
24
24
|
else
|
25
25
|
msg = "[#{request.request_method.upcase}] '#{request.path_info}' (#{total_time})"
|
26
26
|
end
|
@@ -6,7 +6,7 @@ module Mack
|
|
6
6
|
attr_accessor :sess_id
|
7
7
|
|
8
8
|
def start(request, response, cookies)
|
9
|
-
if
|
9
|
+
if configatron.mack.use_sessions
|
10
10
|
self.sess_id = retrieve_session_id(request, response, cookies)
|
11
11
|
unless self.sess_id
|
12
12
|
self.sess_id = create_new_session(request, response, cookies)
|
@@ -23,7 +23,7 @@ module Mack
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def complete(request, response, cookies)
|
26
|
-
if
|
26
|
+
if configatron.mack.use_sessions
|
27
27
|
unless response.redirection?
|
28
28
|
request.session.delete(:tell)
|
29
29
|
end
|
@@ -33,12 +33,12 @@ module Mack
|
|
33
33
|
|
34
34
|
private
|
35
35
|
def retrieve_session_id(request, response, cookies)
|
36
|
-
cookies[
|
36
|
+
cookies[configatron.mack.session_id]
|
37
37
|
end
|
38
38
|
|
39
39
|
def create_new_session(request, response, cookies)
|
40
40
|
id = String.randomize(40).downcase
|
41
|
-
cookies[
|
41
|
+
cookies[configatron.mack.session_id] = {:value => id, :expires => nil}
|
42
42
|
sess = Mack::Session.new(id)
|
43
43
|
request.session = sess
|
44
44
|
Mack::SessionStore.set(request.session.id, request, response, cookies)
|
@@ -4,9 +4,9 @@ module Mack
|
|
4
4
|
# Stores session information in the user's cookie.
|
5
5
|
# The session information is encrypted using the mack-encryption library.
|
6
6
|
# This is the default session store for Mack applications.
|
7
|
-
# To set the expiry time for this session store use the following
|
7
|
+
# To set the expiry time for this session store use the following configatron setting:
|
8
8
|
# cookie_session_store::expiry_time: <%= 4.hours %>
|
9
|
-
# It is recommend that you set the
|
9
|
+
# It is recommend that you set the configatron setting 'default_secret_key' to
|
10
10
|
# something, otherwise it will generate a random one each time you start your application,
|
11
11
|
# which could make decrypting cookies a bit of a pain. :)
|
12
12
|
class Cookie < Mack::SessionStore::Base
|
@@ -29,7 +29,7 @@ module Mack
|
|
29
29
|
|
30
30
|
# Encrypts the session and places it into the cookie.
|
31
31
|
def set(id, request, response, cookies)
|
32
|
-
cookies[id] = {:value => YAML.dump(request.session).encrypt, :expires => (Time.now +
|
32
|
+
cookies[id] = {:value => YAML.dump(request.session).encrypt, :expires => (Time.now + configatron.mack.cookie_session_store.expiry_time)}
|
33
33
|
end
|
34
34
|
|
35
35
|
# Deletes the cookie.
|
@@ -2,7 +2,7 @@ module Mack
|
|
2
2
|
|
3
3
|
# A holder for the session information. This objects gets stored using the Cachetastic system.
|
4
4
|
# For more information about how Cachetastic works see the RDoc for that gem.
|
5
|
-
# The session cookie name defaults to: _mack_session_id but can be changed using the
|
5
|
+
# The session cookie name defaults to: _mack_session_id but can be changed using the configatron
|
6
6
|
# system like such:
|
7
7
|
# mack::session_id: _my_cool_app_sess_id
|
8
8
|
class Session
|
@@ -1,3 +1,4 @@
|
|
1
|
+
|
1
2
|
namespace :gems do
|
2
3
|
|
3
4
|
desc "lists all the gem required for this application."
|
@@ -17,4 +18,158 @@ namespace :gems do
|
|
17
18
|
end
|
18
19
|
end # install
|
19
20
|
|
20
|
-
|
21
|
+
task :freeze do
|
22
|
+
Mack::Utils::GemManager.instance.required_gem_list.each do |g|
|
23
|
+
version = g.version? ? g.version : '> 0.0.0'
|
24
|
+
ENV['gem_name'] = g.name.to_s
|
25
|
+
ENV['version'] = version
|
26
|
+
ENV['source'] = g.source? ? g.source : 'http://gems.rubyforge.org'
|
27
|
+
sh('rake gems:install_and_freeze')
|
28
|
+
end
|
29
|
+
end # freeze
|
30
|
+
|
31
|
+
task :install_and_freeze do
|
32
|
+
require 'rubygems/gem_runner'
|
33
|
+
add_dependencies = ENV['INCLUDE_DEPENDENCIES'] || ENV['include_dependencies'] || false
|
34
|
+
add_dependencies = false if add_dependencies.to_s.downcase == 'false'
|
35
|
+
version = ENV['version'] || ENV['VERSION'] || ENV['ver'] || ENV['VER'] || '> 0.0.0'
|
36
|
+
source = ENV['source'] || ENV['SOURCE'] || 'http://gems.rubyforge.org'
|
37
|
+
gem_name = ENV['gem_name']
|
38
|
+
|
39
|
+
dep_msg = "and its dependencies" if add_dependencies
|
40
|
+
puts "\nTask: freezing #{gem_name} #{dep_msg} to #{local_gem_dir}."
|
41
|
+
puts "Phase 1: Collecting information..."
|
42
|
+
if add_dependencies
|
43
|
+
collect_dependencies(gem_name, version)
|
44
|
+
else
|
45
|
+
version = source_index.find_name(gem_name, version).last.version.to_s
|
46
|
+
processed_gems << LocalGem.new(gem_name, version)
|
47
|
+
end
|
48
|
+
puts "\nPhase 2: Checking installation states..."
|
49
|
+
check_installation(source)
|
50
|
+
puts "\nPhase 3: Freezing Gems and Specs..."
|
51
|
+
freeze_gems
|
52
|
+
puts "\nPhase 4: validating data..."
|
53
|
+
validate
|
54
|
+
puts "\nTotal of #{processed_gems.size} gems frozen to #{local_gem_dir}"
|
55
|
+
end # install_and_freeze
|
56
|
+
end # gem
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
def local_gem_dir
|
61
|
+
dir = Mack::Paths.vendor('gems')
|
62
|
+
mkdir(dir) if !File.exists?(dir)
|
63
|
+
return dir
|
64
|
+
end
|
65
|
+
|
66
|
+
def processed_gems
|
67
|
+
@gem_list ||= []
|
68
|
+
return @gem_list
|
69
|
+
end
|
70
|
+
|
71
|
+
def source_index
|
72
|
+
@src_index ||= Gem::SourceIndex.from_installed_gems
|
73
|
+
return @src_index
|
74
|
+
end
|
75
|
+
|
76
|
+
def collect_dependencies(gem_name, version)
|
77
|
+
# normalize the version
|
78
|
+
version = source_index.find_name(gem_name, version).last.version.to_s
|
79
|
+
gem = LocalGem.new(gem_name, version)
|
80
|
+
|
81
|
+
if !processed_gems.include?gem
|
82
|
+
processed_gems << gem
|
83
|
+
do_dependencies(gem_name, version) do |dep_gem|
|
84
|
+
collect_dependencies(dep_gem.name, dep_gem.version_requirements.to_s)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate
|
90
|
+
processed_gems.each do |gem|
|
91
|
+
file_name = File.join(local_gem_dir, gem.name + "-" + gem.version)
|
92
|
+
if !File.exists?file_name
|
93
|
+
puts " ** Warning: #{gem.name} was skipped"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
def check_installation(source = 'http://gems.rubyforge.org')
|
99
|
+
processed_gems.each do |gem|
|
100
|
+
res = Gem.cache.search(/^#{gem.name}$/i, gem.version)
|
101
|
+
if !res or res.empty?
|
102
|
+
msg " ** #{gem.name} not installed. Installing #{gem.name} - #{gem.version}"
|
103
|
+
params = ["install", gem.name]
|
104
|
+
params << "--version=#{gem.version}"
|
105
|
+
params << "--source=#{source}"
|
106
|
+
sh "sudo gem #{params.join(" ")}"
|
107
|
+
else
|
108
|
+
msg " ** #{gem.name} has been installed."
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def freeze_gems
|
114
|
+
processed_gems.each do |gem|
|
115
|
+
file_name = File.join(local_gem_dir, gem.name + "-" + gem.version)
|
116
|
+
if File.exists?file_name
|
117
|
+
msg " ** #{gem.name} is already frozen, skipping it."
|
118
|
+
else
|
119
|
+
chdir(local_gem_dir) do
|
120
|
+
begin
|
121
|
+
Gem::GemRunner.new.run(["unpack", gem.name, "--version", gem.version])
|
122
|
+
spec = source_index.find_name(gem.name, gem.version).last
|
123
|
+
spec_file = File.join(file_name, "spec.yaml")
|
124
|
+
File.open(spec_file, "w") { |f| f.write(spec.to_yaml) }
|
125
|
+
rescue Exception => ex
|
126
|
+
puts ex
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
def do_dependencies(gem_name, version = "> 0.0.0", &block)
|
134
|
+
raise "Block expected!" if !block_given?
|
135
|
+
source_indexes = Gem::SourceIndex.from_installed_gems
|
136
|
+
# get the last item in the 'found list'. That's the latest version. If user passed in specific version, then there's only 1 in the list
|
137
|
+
deps = source_indexes.find_name(gem_name, version).last.dependencies
|
138
|
+
msg " ** Found #{deps.size} dependencies for #{gem_name}-#{version}"
|
139
|
+
deps.each do |dep_gem|
|
140
|
+
yield(dep_gem)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def msg(msg)
|
145
|
+
verbose = ENV['VERBOSE'] || ENV['verbose'] || false
|
146
|
+
verbose = false if verbose.to_s.downcase == 'false'
|
147
|
+
puts msg if verbose
|
148
|
+
print "." if !verbose
|
149
|
+
end
|
150
|
+
|
151
|
+
class LocalGem
|
152
|
+
attr_accessor :name
|
153
|
+
attr_accessor :version
|
154
|
+
|
155
|
+
def initialize(name, version)
|
156
|
+
self.name = name
|
157
|
+
self.version = version
|
158
|
+
end
|
159
|
+
|
160
|
+
def to_s
|
161
|
+
"#{name}-#{version}"
|
162
|
+
end
|
163
|
+
|
164
|
+
def ==(other)
|
165
|
+
other.to_s == self.to_s
|
166
|
+
end
|
167
|
+
|
168
|
+
def eql?(other)
|
169
|
+
other.to_s == self.to_s
|
170
|
+
end
|
171
|
+
|
172
|
+
def hash
|
173
|
+
self.to_s.hash
|
174
|
+
end
|
175
|
+
end
|