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.
- data/README +43 -0
- data/bin/mack +60 -0
- data/bin/templates/Rakefile.template +6 -0
- data/bin/templates/app/controllers/default_controller.rb.template +7 -0
- data/bin/templates/app/helpers/application_helper.rb.template +2 -0
- data/bin/templates/app/views/default/index.html.erb.template +3 -0
- data/bin/templates/app/views/layouts/application.html.erb.template +15 -0
- data/bin/templates/config/app_config/default.yml.template +7 -0
- data/bin/templates/config/app_config/development.yml.template +0 -0
- data/bin/templates/config/app_config/production.yml.template +0 -0
- data/bin/templates/config/app_config/test.yml.template +0 -0
- data/bin/templates/config/boot.rb.template +6 -0
- data/bin/templates/config/database.yml.template +20 -0
- data/bin/templates/config/routes.rb.template +7 -0
- data/bin/templates/config/thin.ru.template +1 -0
- data/bin/templates/config/thin.yml.template +8 -0
- data/bin/templates/public/favicon.ico +0 -0
- data/bin/templates/public/stylesheets/scaffold.css.template +74 -0
- data/core_extensions/hash.rb +9 -0
- data/core_extensions/module.rb +29 -0
- data/core_extensions/nil.rb +8 -0
- data/core_extensions/object.rb +9 -0
- data/core_extensions/string.rb +28 -0
- data/errors/errors.rb +79 -0
- data/initialize/configuration.rb +99 -0
- data/initialize/configure_logging.rb +24 -0
- data/initialize/configure_orm_support.rb +23 -0
- data/initialize/console.rb +13 -0
- data/initialize/initializer.rb +88 -0
- data/initialize/server/simple_server.rb +21 -0
- data/lib/utils/html.rb +88 -0
- data/lib/utils/server.rb +27 -0
- data/mack.rb +124 -0
- data/mack_tasks.rb +16 -0
- data/routing/route_map.rb +268 -0
- data/routing/urls.rb +54 -0
- data/sea_level/controller_base.rb +293 -0
- data/sea_level/cookie_jar.rb +67 -0
- data/sea_level/filter.rb +63 -0
- data/sea_level/helpers/view_helpers/html_helpers.rb +33 -0
- data/sea_level/helpers/view_helpers/orm_helpers.rb +72 -0
- data/sea_level/request.rb +83 -0
- data/sea_level/response.rb +6 -0
- data/sea_level/session.rb +33 -0
- data/sea_level/view_binder.rb +101 -0
- data/tasks/cachetastic_tasks.rake +69 -0
- data/tasks/log_tasks.rake +9 -0
- data/tasks/mack_tasks.rake +15 -0
- data/tasks/rake_helpers.rb +24 -0
- data/tasks/rake_rules.rake +19 -0
- data/tasks/script_tasks.rake +44 -0
- data/tasks/test_tasks.rake +7 -0
- data/test_extensions/test_assertions.rb +47 -0
- data/test_extensions/test_helpers.rb +84 -0
- metadata +173 -0
@@ -0,0 +1,99 @@
|
|
1
|
+
module Mack
|
2
|
+
# All configuration for the Mack subsystem happens here. Each of the default environments,
|
3
|
+
# production, development, and test have their own default configuration options. These
|
4
|
+
# get merged with overall default options.
|
5
|
+
module Configuration # :nodoc:
|
6
|
+
|
7
|
+
# use local memory and store stuff for 24 hours:
|
8
|
+
# use file for sessions and store them for 4 hours:
|
9
|
+
DEFAULTS_PRODUCTION = {
|
10
|
+
"mack::use_lint" => false,
|
11
|
+
"mack::show_exceptions" => false,
|
12
|
+
"log::level" => "info",
|
13
|
+
"log::detailed_requests" => false,
|
14
|
+
"cachetastic_default_options" => {
|
15
|
+
"debug" => false,
|
16
|
+
"adapter" => "local_memory",
|
17
|
+
"expiry_time" => 86400,
|
18
|
+
"logging" => {
|
19
|
+
"logger_1" => {
|
20
|
+
"type" => "file",
|
21
|
+
"file" => File.join(MACK_ROOT, "log", "cachetastic.log")
|
22
|
+
}
|
23
|
+
}
|
24
|
+
},
|
25
|
+
"cachetastic_caches_mack_session_cache_options" => {
|
26
|
+
"debug" => false,
|
27
|
+
"adapter" => "file",
|
28
|
+
"store_options" =>
|
29
|
+
{"dir" => File.join(MACK_ROOT, "tmp")},
|
30
|
+
"expiry_time" => 14400,
|
31
|
+
"logging" => {
|
32
|
+
"logger_1" => {
|
33
|
+
"type" => "file",
|
34
|
+
"file" => File.join(MACK_ROOT, "log", "cachetastic.log")
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
} unless self.const_defined?("DEFAULTS_PRODUCTION")
|
39
|
+
|
40
|
+
# use local memory and store stuff for 5 minutes:
|
41
|
+
DEFAULTS_DEVELOPMENT = {
|
42
|
+
"mack::cache_classes" => false,
|
43
|
+
"log::level" => "debug",
|
44
|
+
"log::console" => true,
|
45
|
+
"cachetastic_default_options" => {
|
46
|
+
"debug" => false,
|
47
|
+
"adapter" => "local_memory",
|
48
|
+
"expiry_time" => 300,
|
49
|
+
"logging" => {
|
50
|
+
"logger_1" => {
|
51
|
+
"type" => "file",
|
52
|
+
"file" => File.join(MACK_ROOT, "log", "cachetastic.log")
|
53
|
+
}
|
54
|
+
}
|
55
|
+
}
|
56
|
+
} unless self.const_defined?("DEFAULTS_DEVELOPMENT")
|
57
|
+
|
58
|
+
# use local memory and store stuff for 1 hour:
|
59
|
+
DEFAULTS_TEST = {
|
60
|
+
"log::level" => "error",
|
61
|
+
"cachetastic_default_options" => {
|
62
|
+
"debug" => false,
|
63
|
+
"adapter" => "local_memory",
|
64
|
+
"expiry_time" => 3600,
|
65
|
+
"logging" => {
|
66
|
+
"logger_1" => {
|
67
|
+
"type" => "file",
|
68
|
+
"file" => File.join(MACK_ROOT, "log", "cachetastic.log")
|
69
|
+
}
|
70
|
+
}
|
71
|
+
}
|
72
|
+
} unless self.const_defined?("DEFAULTS_TEST")
|
73
|
+
|
74
|
+
unless self.const_defined?("DEFAULTS")
|
75
|
+
DEFAULTS = {
|
76
|
+
"mack::cache_classes" => true,
|
77
|
+
"mack::use_lint" => true,
|
78
|
+
"mack::show_exceptions" => true,
|
79
|
+
"mack::session_id" => "_mack_session_id",
|
80
|
+
"mack::cookie_values" => {
|
81
|
+
"path" => "/"
|
82
|
+
},
|
83
|
+
# "mack::orm" => "activerecord",
|
84
|
+
"log::detailed_requests" => true,
|
85
|
+
"log::level" => "info",
|
86
|
+
"log::console" => false,
|
87
|
+
"log::file" => true,
|
88
|
+
"log::console_format" => "%l:\t[%d]\t%M",
|
89
|
+
"log::file_format" => "%l:\t[%d]\t%M"
|
90
|
+
}.merge(eval("DEFAULTS_#{MACK_ENV.upcase}"))
|
91
|
+
end
|
92
|
+
|
93
|
+
app_config.load_hash(DEFAULTS, "mack_defaults")
|
94
|
+
app_config.load_file(File.join(MACK_CONFIG, "app_config", "default.yml"))
|
95
|
+
app_config.load_file(File.join(MACK_CONFIG, "app_config", "#{MACK_ENV}.yml"))
|
96
|
+
# app_config.reload
|
97
|
+
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#--
|
2
|
+
# Configure logging
|
3
|
+
#++
|
4
|
+
include Log4r
|
5
|
+
|
6
|
+
log_dir_loc = File.join(MACK_ROOT, "log")
|
7
|
+
FileUtils.mkdir_p(log_dir_loc)
|
8
|
+
|
9
|
+
unless Object.const_defined?("MACK_DEFAULT_LOGGER")
|
10
|
+
log = Log4r::Logger.new('')
|
11
|
+
log.level = Module.instance_eval("Log4r::#{app_config.log.level.to_s.upcase}")
|
12
|
+
# console:
|
13
|
+
if app_config.log.console
|
14
|
+
console_format = PatternFormatter.new(:pattern => app_config.log.console_format)
|
15
|
+
log.add(Log4r::StdoutOutputter.new('console', :formatter => console_format))
|
16
|
+
end
|
17
|
+
# file:
|
18
|
+
if app_config.log.file
|
19
|
+
file_format = PatternFormatter.new(:pattern => app_config.log.file_format)
|
20
|
+
log.add(FileOutputter.new('fileOutputter', :filename => File.join(log_dir_loc, "#{MACK_ENV}.log"), :trunc => false, :formatter => file_format))
|
21
|
+
end
|
22
|
+
|
23
|
+
Object::MACK_DEFAULT_LOGGER = log
|
24
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# setup ORM:
|
2
|
+
|
3
|
+
[:activerecord, :data_mapper].each do |orm|
|
4
|
+
eval("def using_#{orm}?; false; end")
|
5
|
+
end
|
6
|
+
|
7
|
+
unless app_config.mack.orm.nil?
|
8
|
+
dbs = YAML::load(ERB.new(IO.read(File.join(MACK_CONFIG, "database.yml"))).result)
|
9
|
+
case app_config.mack.orm
|
10
|
+
when 'activerecord'
|
11
|
+
require 'activerecord'
|
12
|
+
ActiveRecord::Base.establish_connection(dbs[MACK_ENV])
|
13
|
+
eval("def using_activerecord?; true; end")
|
14
|
+
when 'data_mapper'
|
15
|
+
require 'data_mapper'
|
16
|
+
DataMapper::Database.setup(dbs[MACK_ENV])
|
17
|
+
eval("def using_data_mapper?; true; end")
|
18
|
+
else
|
19
|
+
MACK_DEFAULT_LOGGER.warn("Attempted to configure an unknown ORM: #{app_config.mack.orm}")
|
20
|
+
end
|
21
|
+
else
|
22
|
+
MACK_DEFAULT_LOGGER.warn("No ORM has been configured!")
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# This file gets loaded when you run:
|
2
|
+
# rake console
|
3
|
+
# It loads the following classes to make using the application via the console easier:
|
4
|
+
#
|
5
|
+
# * Mack::TestHelpers
|
6
|
+
# * Mack::Routes::Urls
|
7
|
+
|
8
|
+
fl = File.join(File.dirname(__FILE__), "..")
|
9
|
+
|
10
|
+
require File.join(fl, "test_extensions", "test_helpers")
|
11
|
+
|
12
|
+
self.send(:include, Mack::TestHelpers)
|
13
|
+
self.send(:include, Mack::Routes::Urls)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rack'
|
3
|
+
require 'digest'
|
4
|
+
require 'ruby_extensions'
|
5
|
+
require 'application_configuration'
|
6
|
+
require 'cachetastic'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'log4r'
|
9
|
+
|
10
|
+
# Set up Mack constants, if they haven't already been set up.
|
11
|
+
unless Object.const_defined?("MACK_ENV")
|
12
|
+
(Object::MACK_ENV = (ENV["MACK_ENV"] ||= "development")).to_sym
|
13
|
+
end
|
14
|
+
(Object::MACK_ROOT = (ENV["MACK_ROOT"] ||= FileUtils.pwd)) unless Object.const_defined?("MACK_ROOT")
|
15
|
+
|
16
|
+
Object::MACK_PUBLIC = File.join(MACK_ROOT, "public") unless Object.const_defined?("MACK_PUBLIC")
|
17
|
+
Object::MACK_APP = File.join(MACK_ROOT, "app") unless Object.const_defined?("MACK_APP")
|
18
|
+
Object::MACK_LIB = File.join(MACK_ROOT, "lib") unless Object.const_defined?("MACK_LIB")
|
19
|
+
Object::MACK_CONFIG = File.join(MACK_ROOT, "config") unless Object.const_defined?("MACK_CONFIG")
|
20
|
+
Object::MACK_VIEWS = File.join(MACK_APP, "views") unless Object.const_defined?("MACK_VIEWS")
|
21
|
+
Object::MACK_LAYOUTS = File.join(MACK_VIEWS, "layouts") unless Object.const_defined?("MACK_LAYOUTS")
|
22
|
+
|
23
|
+
unless Object.const_defined?("MACK_INITIALIZED")
|
24
|
+
puts "Starting application in #{MACK_ENV} mode."
|
25
|
+
|
26
|
+
Object::MACK_INITIALIZED = true
|
27
|
+
|
28
|
+
# Set up 'Rails' constants to allow for easier use of existing gems/plugins like application_configuration.
|
29
|
+
# I would like to take these out eventually, but for right now, it's not doing too much harm.
|
30
|
+
# Object::RAILS_ENV = MACK_ENV unless Object.const_defined?("RAILS_ENV")
|
31
|
+
# Object::RAILS_ROOT = MACK_ROOT unless Object.const_defined?("RAILS_ROOT")
|
32
|
+
|
33
|
+
require File.join(File.dirname(__FILE__), "configuration.rb")
|
34
|
+
|
35
|
+
require File.join(File.dirname(__FILE__), "configure_logging.rb")
|
36
|
+
|
37
|
+
require File.join(File.dirname(__FILE__), "configure_orm_support.rb")
|
38
|
+
|
39
|
+
fl = File.join(File.dirname(__FILE__), "..")
|
40
|
+
|
41
|
+
# Require all the necessary files to make Mack actually work!
|
42
|
+
["errors", "core_extensions", "lib", "test_extensions", "routing", "sea_level", "tasks", "initialize/server"].each do |dir|
|
43
|
+
dir_globs = Dir.glob(File.join(fl, dir, "**/*.rb"))
|
44
|
+
dir_globs.each do |d|
|
45
|
+
require d
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
|
51
|
+
# ------------------------------------------------------------------------
|
52
|
+
|
53
|
+
# set up application stuff:
|
54
|
+
|
55
|
+
# set up routes:
|
56
|
+
require File.join(MACK_ROOT, "config", "routes")
|
57
|
+
|
58
|
+
# require 'app' files:
|
59
|
+
Dir.glob(File.join(MACK_APP, "**/*.rb")).each do |d|
|
60
|
+
require d
|
61
|
+
end
|
62
|
+
|
63
|
+
# require 'lib' files:
|
64
|
+
Dir.glob(File.join(MACK_LIB, "**/*.rb")).each do |d|
|
65
|
+
require d
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
# ------------------------------------------------------------------------
|
70
|
+
|
71
|
+
# Include ApplicationHelper into all controllers:
|
72
|
+
if Object.const_defined?("ApplicationHelper")
|
73
|
+
ApplicationHelper.include_safely_into(Mack::Controller::Base, Mack::ViewBinder)
|
74
|
+
end
|
75
|
+
# Find other Helpers and include them into their respective controllers.
|
76
|
+
Object.constants.collect {|c| c if c.match(/Controller$/)}.compact.each do |cont|
|
77
|
+
if Object.const_defined?("#{cont}Helper")
|
78
|
+
h = "#{cont}Helper".constantize
|
79
|
+
h.include_safely_into(cont, Mack::ViewBinder)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Find view level Helpers and include them into the Mack::ViewBinder
|
84
|
+
Mack::ViewHelpers.constants.each do |cont|
|
85
|
+
h = "Mack::ViewHelpers::#{cont}".constantize
|
86
|
+
h.include_safely_into(Mack::ViewBinder)
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Mack
|
2
|
+
# Even though it's called, SimpleServer, this might be the only server you need to run
|
3
|
+
# a Mack application.
|
4
|
+
#
|
5
|
+
# $ ruby script/server
|
6
|
+
#
|
7
|
+
# This SimpleServer does not use Thin. But does work with anything that Rack has a handler for.
|
8
|
+
class SimpleServer
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
def run(options)
|
13
|
+
r = "Rack::Handler::#{options.handler.camelcase}"
|
14
|
+
puts "Starting app using: #{r} in #{options.environment} mode on port: #{options.port}"
|
15
|
+
eval(r).run(Mack::Utils::Server.build_app, :Port => options.port)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
data/lib/utils/html.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
module Mack
|
2
|
+
module Utils
|
3
|
+
# Useful utilities for dealing with HTML.
|
4
|
+
class Html
|
5
|
+
|
6
|
+
class << self
|
7
|
+
|
8
|
+
# Used in views to create href links. It takes link_text, url, and a Hash that gets added
|
9
|
+
# to the href as options.
|
10
|
+
#
|
11
|
+
# Examples:
|
12
|
+
# Mack::Utils::Html.href("http://www.mackframework.com") # => <a href="http://www.mackframework.com">http://www.mackframework.com</a>
|
13
|
+
# Mack::Utils::Html.href("Mack", "http://www.mackframework.com") # => <a href="http://www.mackframework.com">Mack</a>
|
14
|
+
# Mack::Utils::Html.href("Mack", "http://www.mackframework.com", :target => "_blank") # => <a href="http://www.mackframework.com" target="_blank">Mack</a>
|
15
|
+
# Mack::Utils::Html.href("Mack", "http://www.mackframework.com", :target => "_blank", :rel => :nofollow) # => <a href="http://www.mackframework.com" target="_blank" rel="nofollow">Mack</a>
|
16
|
+
# If you pass in :method as an option it will be a JavaScript form that will post to the specified link with the
|
17
|
+
# methd specified.
|
18
|
+
# Mack::Utils::Html.href("Mack", "http://www.mackframework.com", :method => :delete)
|
19
|
+
# If you use the :method option you can also pass in a :confirm option. The :confirm option will generate a
|
20
|
+
# javascript confirmation window. If 'OK' is selected the the form will submit. If 'cancel' is selected, then
|
21
|
+
# nothing will happen. This is extremely useful for 'delete' type of links.
|
22
|
+
# Mack::Utils::Html.href("Mack", "http://www.mackframework.com", :method => :delete, :confirm => "Are you sure?")
|
23
|
+
def href(link_text, url = link_text, html_options = {})
|
24
|
+
if html_options[:method]
|
25
|
+
meth = nil
|
26
|
+
confirm = nil
|
27
|
+
|
28
|
+
meth = %{var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', '_method'); s.setAttribute('value', '#{html_options[:method]}'); f.appendChild(s);f.submit()}
|
29
|
+
html_options.delete(:method)
|
30
|
+
|
31
|
+
if html_options[:confirm]
|
32
|
+
confirm = %{if (confirm('#{html_options[:confirm]}'))}
|
33
|
+
html_options.delete(:confirm)
|
34
|
+
end
|
35
|
+
|
36
|
+
html_options[:onclick] = (confirm ? (confirm + " { ") : "") << meth << (confirm ? (" } ") : "") << ";return false;"
|
37
|
+
end
|
38
|
+
|
39
|
+
html = "<a href=" << '"' << url
|
40
|
+
html << '"'
|
41
|
+
html << " " << html_options.join("%s=\"%s\"", " ") unless html_options.empty?
|
42
|
+
html << ">" << link_text
|
43
|
+
html << "</a>"
|
44
|
+
html
|
45
|
+
end
|
46
|
+
|
47
|
+
alias_method :a, :href
|
48
|
+
|
49
|
+
# Wraps the content_tag method.
|
50
|
+
#
|
51
|
+
# Examples:
|
52
|
+
# Mack::Utils::Html.b("hello") # => <b>hello</b>
|
53
|
+
# Mack::Utils::Html.div("hello world!", :class => :foo)) # => <div class="foo">hello world!</div>
|
54
|
+
def method_missing(sym, *args)
|
55
|
+
ags = args.from_args
|
56
|
+
|
57
|
+
tag = sym
|
58
|
+
content = nil
|
59
|
+
options = {}
|
60
|
+
|
61
|
+
if ags.is_a?(Array)
|
62
|
+
content = ags[0] if ags[0].is_a?(String)
|
63
|
+
options = ags[1] if ags[1].is_a?(Hash)
|
64
|
+
elsif ags.is_a?(String)
|
65
|
+
content = ags
|
66
|
+
elsif ags.is_a?(Hash)
|
67
|
+
options = ags
|
68
|
+
end
|
69
|
+
|
70
|
+
content = yield if block_given?
|
71
|
+
|
72
|
+
content_tag(tag, content, options)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Builds an HTML tag.
|
76
|
+
#
|
77
|
+
# Examples:
|
78
|
+
# content_tag(:b, "hello") # => <b>hello</b>
|
79
|
+
# content_tag("div", "hello world!", :class => :foo) # => <div class="foo">hello world!</div>
|
80
|
+
def content_tag(tag, content, options = {})
|
81
|
+
html = "<#{tag} #{options.join("%s=\"%s\"", " ")}>#{content}</#{tag}>"
|
82
|
+
end
|
83
|
+
|
84
|
+
end # self
|
85
|
+
|
86
|
+
end # Html
|
87
|
+
end # Utils
|
88
|
+
end # Mack
|
data/lib/utils/server.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
module Mack
|
2
|
+
module Utils
|
3
|
+
module Server
|
4
|
+
|
5
|
+
# This method wraps all the necessary components of the Rack system around
|
6
|
+
# Mack::Runner. This can be used build your own server around the Mack framework.
|
7
|
+
def self.build_app
|
8
|
+
# Mack framework:
|
9
|
+
app = Mack::Runner.new
|
10
|
+
# Any urls listed will go straight to the public directly and will not be served up via the app:
|
11
|
+
app = Rack::Static.new(app, :urls => ["/css", "/images", "/files", "/images", "/stylesheets", "/javascripts", "/media"], :root => "public")
|
12
|
+
app = Rack::Lint.new(app) if app_config.mack.use_lint
|
13
|
+
app = Rack::ShowStatus.new(app)
|
14
|
+
app = Rack::ShowExceptions.new(app) if app_config.mack.show_exceptions
|
15
|
+
app = Rack::Recursive.new(app)
|
16
|
+
# This will reload any edited classes if the cache_classes config setting is set to true.
|
17
|
+
app = Rack::Reloader.new(app, 1) unless app_config.mack.cache_classes
|
18
|
+
# TODO: Not sure about this logger, investigate better ones.
|
19
|
+
# TODO: Depends on MACK_DEFAULT_LOGGER already being configured.
|
20
|
+
# This makes it a drag run this 'standalone' in another Ruby program.
|
21
|
+
# app = Rack::CommonLogger.new(app, MACK_DEFAULT_LOGGER)
|
22
|
+
app
|
23
|
+
end
|
24
|
+
|
25
|
+
end # Server
|
26
|
+
end # Utils
|
27
|
+
end # Mack
|
data/mack.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), "initialize", "initializer")
|
2
|
+
|
3
|
+
module Mack
|
4
|
+
# This is the heart and soul of the Mack framework! This class interfaces with the Rack framework.
|
5
|
+
# It handles all the dispatching back and forth between the Rack framework and a Mack application.
|
6
|
+
class Runner
|
7
|
+
include Mack::Routes::Urls
|
8
|
+
|
9
|
+
attr_reader :response # :nodoc:
|
10
|
+
attr_reader :request # :nodoc:
|
11
|
+
attr_reader :cookies # :nodoc:
|
12
|
+
# This method needs to be defined as part of the Rack framework. As is noted for the Mack::Runner
|
13
|
+
# class, this is where the center of the Mack framework lies.
|
14
|
+
def call(env)
|
15
|
+
begin
|
16
|
+
setup(env) do
|
17
|
+
begin
|
18
|
+
route = Mack::Routes::RouteMap.instance.get_route_from_request(self.request)
|
19
|
+
if route[:redirect_to]
|
20
|
+
# because the route is specified to be a redirect, let's do that:
|
21
|
+
redirect_to(route)
|
22
|
+
else
|
23
|
+
# let's handle a normal request:
|
24
|
+
c = "#{route[:controller].to_s.camelcase}Controller".constantize.new(self.request, self.response, self.cookies)
|
25
|
+
self.response.write(c.run)
|
26
|
+
end
|
27
|
+
rescue Mack::Errors::ResourceNotFound, Mack::Errors::UndefinedRoute => e
|
28
|
+
return try_to_find_resource(env, self.request.path_info, e)
|
29
|
+
end
|
30
|
+
end # setup
|
31
|
+
rescue Exception => e
|
32
|
+
MACK_DEFAULT_LOGGER.error(e)
|
33
|
+
raise e
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
def log_request
|
39
|
+
s_time = Time.now
|
40
|
+
x = yield
|
41
|
+
e_time = Time.now
|
42
|
+
p_time = e_time - s_time
|
43
|
+
if app_config.log.detailed_requests
|
44
|
+
msg = "\n\t[#{@request.request_method.upcase}] '#{@request.path_info}'\n"
|
45
|
+
msg << "\tSession ID: #{@request.session.id}\n"
|
46
|
+
msg << "\tParameters: #{@request.all_params.inspect}\n"
|
47
|
+
msg << "\tCompleted in #{p_time} (#{(1 / p_time).round} reqs/sec) | #{@response.status} [#{@request.full_host}]"
|
48
|
+
else
|
49
|
+
msg = "[#{@request.request_method.upcase}] '#{@request.path_info}' (#{p_time})"
|
50
|
+
end
|
51
|
+
MACK_DEFAULT_LOGGER.info(msg)
|
52
|
+
x
|
53
|
+
end
|
54
|
+
|
55
|
+
# Setup the request, response, cookies, session, etc...
|
56
|
+
# yield up, and then clean things up afterwards.
|
57
|
+
def setup(env)
|
58
|
+
log_request do
|
59
|
+
@request = Mack::Request.new(env)
|
60
|
+
@response = Mack::Response.new
|
61
|
+
@cookies = Mack::CookieJar.new(self.request, self.response)
|
62
|
+
session do
|
63
|
+
yield
|
64
|
+
end
|
65
|
+
self.response.finish
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def session
|
70
|
+
sess_id = self.cookies[app_config.mack.session_id]
|
71
|
+
unless sess_id
|
72
|
+
sess_id = create_new_session
|
73
|
+
else
|
74
|
+
sess = Cachetastic::Caches::MackSessionCache.get(sess_id)
|
75
|
+
if sess
|
76
|
+
self.request.session = sess
|
77
|
+
else
|
78
|
+
# we couldn't find it in the store, so we need to create it:
|
79
|
+
sess_id = create_new_session
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
yield
|
84
|
+
|
85
|
+
Cachetastic::Caches::MackSessionCache.set(sess_id, self.request.session)
|
86
|
+
end
|
87
|
+
|
88
|
+
def create_new_session
|
89
|
+
id = String.randomize(40).downcase
|
90
|
+
self.cookies[app_config.mack.session_id] = {:value => id, :expires => nil}
|
91
|
+
sess = Mack::Session.new(id)
|
92
|
+
self.request.session = sess
|
93
|
+
Cachetastic::Caches::MackSessionCache.set(id, sess)
|
94
|
+
end
|
95
|
+
|
96
|
+
def try_to_find_resource(env, path_info, exception)
|
97
|
+
# we can't find a route for this, so let's try and see if it's in the public directory:
|
98
|
+
if File.extname(path_info).blank?
|
99
|
+
path_info << ".html"
|
100
|
+
end
|
101
|
+
if File.exists?(File.join(MACK_PUBLIC, path_info))
|
102
|
+
return Rack::File.new(File.join(MACK_PUBLIC)).call(env)
|
103
|
+
else
|
104
|
+
raise exception
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# This will redirect the request to the specified url. A default status of
|
109
|
+
# 302, Moved Temporarily, is set if no status is specified. A simple HTML
|
110
|
+
# page is rendered in case the redirect does not occur.
|
111
|
+
def redirect_to(route)
|
112
|
+
status = route[:status] || 302
|
113
|
+
url = route[:redirect_to]
|
114
|
+
options = self.request.all_params
|
115
|
+
options.merge!(route)
|
116
|
+
options - [:controller, :action, :redirect_to, :method, :status]
|
117
|
+
url = url_for_pattern(url, options)
|
118
|
+
self.response.status = status
|
119
|
+
self.response[:location] = url
|
120
|
+
self.response.write(redirect_html(self.request.path_info, url, status))
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|