mack 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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,67 @@
|
|
1
|
+
module Mack
|
2
|
+
|
3
|
+
# Examples:
|
4
|
+
# class MyAwesomeController < Mack::Controller::Base
|
5
|
+
# def index
|
6
|
+
# cookies[:id] = 1
|
7
|
+
# render(:text => "Hello!")
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# def show
|
11
|
+
# render(:text => "The id in the cookie is: #{cookies[:id]}")
|
12
|
+
# end
|
13
|
+
# end
|
14
|
+
class CookieJar
|
15
|
+
|
16
|
+
attr_reader :all_cookies # :nodoc:
|
17
|
+
attr_reader :request # :nodoc:
|
18
|
+
attr_reader :response # :nodoc:
|
19
|
+
|
20
|
+
def initialize(request, response) # :nodoc:
|
21
|
+
@request = request
|
22
|
+
@response = response
|
23
|
+
@all_cookies = request.cookies
|
24
|
+
end
|
25
|
+
|
26
|
+
# Returns the value of a cookie as a String, or nil it doesn't exist.
|
27
|
+
# This will check both the incoming cookies on the request, as well as
|
28
|
+
# any cookies that have been set as part of the current action.
|
29
|
+
def [](key)
|
30
|
+
return nil if key.nil?
|
31
|
+
# check both the incoming cookies and the outgoing cookies to see if
|
32
|
+
# the cookie we're looking for exists.
|
33
|
+
c = (self.all_cookies[key.to_s] || self.all_cookies[key.to_sym])
|
34
|
+
return c if c.is_a?(String)
|
35
|
+
return c[:value] if c.is_a?(Hash)
|
36
|
+
return nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Set a cookie with a specified value.
|
40
|
+
def []=(key, value)
|
41
|
+
key = key.to_s
|
42
|
+
unless value.is_a?(Hash)
|
43
|
+
value = {:value => value}
|
44
|
+
end
|
45
|
+
value = app_config.mack.cookie_values.merge(value)
|
46
|
+
self.all_cookies[key] = value
|
47
|
+
self.response.set_cookie(key, value)
|
48
|
+
end
|
49
|
+
|
50
|
+
# Deletes a cookie.
|
51
|
+
def delete(key)
|
52
|
+
key = key.to_s
|
53
|
+
self.all_cookies.delete(key)
|
54
|
+
self.response.delete_cookie(key)
|
55
|
+
end
|
56
|
+
|
57
|
+
# Returns both cookies that came in as part of the request, as well as those set
|
58
|
+
# on to the response. This is useful when you set a cookie in a filter or an action
|
59
|
+
# and want to access it in another filter or action before the request/response has
|
60
|
+
# been fully completed.
|
61
|
+
def all
|
62
|
+
self.all_cookies
|
63
|
+
end
|
64
|
+
|
65
|
+
end # CookieJar
|
66
|
+
|
67
|
+
end # Mack
|
data/sea_level/filter.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
module Mack
|
2
|
+
module Controller
|
3
|
+
# A wrapper class to hold calls to filter methods for Controllers.
|
4
|
+
# This class should never be called by itself. Instead there are helper
|
5
|
+
# methods in Mack::Controller::Base to do this for.
|
6
|
+
#
|
7
|
+
# Examples:
|
8
|
+
# class MyAwesomeController < Mack::Controller::Base
|
9
|
+
# # all actions in this controller will have this filter run:
|
10
|
+
# before_filter: authenticate
|
11
|
+
# # only the show and index actions in this controller will have this filter run:
|
12
|
+
# before_filter: load_side_bar, :only => [:show, :index]
|
13
|
+
# # all actions, except for the create action will have this filter run.
|
14
|
+
# after_filter: write_to_log, :except => :create
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# Filter methods need to be scoped to the controller that is to run them.
|
18
|
+
# There are three different filters available: <tt>before</tt>, <tt>after</tt> and <tt>after_render</tt>.
|
19
|
+
#
|
20
|
+
# <tt>before</tt> filters get run before an action is called. This is a great place to set up common
|
21
|
+
# elements needed for your action. Things like authentication should be done here, etc...
|
22
|
+
#
|
23
|
+
# <tt>after</tt> filters get run after an action has been called. This is a great place to set up common
|
24
|
+
# elements for a view, that depend on stuff from inside your action. Because nothing has been 'rendered'
|
25
|
+
# yet, you still can add new instance variables, and alter ones created in the action.
|
26
|
+
#
|
27
|
+
# <tt>after_render</tt> filters get run after the rendering of the action has happened. At this point
|
28
|
+
# there is an instance variable, <tt>@final_rendered_action</tt>, that is available on which work can be done.
|
29
|
+
# This variable will have any layouts rendered to, any ERB will have been processed, etc... It should be the final
|
30
|
+
# String that will get rendered to the screen. This is a great place to do things like write a log, gzip, etc...
|
31
|
+
class Filter
|
32
|
+
|
33
|
+
attr_reader :filter_method
|
34
|
+
attr_reader :action_list
|
35
|
+
|
36
|
+
def initialize(filter_method, action_list = {})
|
37
|
+
@filter_method = filter_method
|
38
|
+
clean_action_list(action_list)
|
39
|
+
end
|
40
|
+
|
41
|
+
def run?(action)
|
42
|
+
return true if action_list.empty?
|
43
|
+
if action_list[:only]
|
44
|
+
return action_list[:only].include?(action)
|
45
|
+
elsif action_list[:except]
|
46
|
+
return !action_list[:except].include?(action)
|
47
|
+
end
|
48
|
+
return false
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
def clean_action_list(action_list)
|
53
|
+
if action_list[:only]
|
54
|
+
action_list[:only] = [action_list[:only]].flatten
|
55
|
+
elsif action_list[:except]
|
56
|
+
action_list[:except] = [action_list[:except]].flatten
|
57
|
+
end
|
58
|
+
@action_list = action_list
|
59
|
+
end
|
60
|
+
|
61
|
+
end # Fitler
|
62
|
+
end # Controller
|
63
|
+
end # Mack
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Mack
|
2
|
+
module ViewHelpers
|
3
|
+
module HtmlHelpers
|
4
|
+
|
5
|
+
# This is just an alias to Mack::Utils::Html.
|
6
|
+
#
|
7
|
+
# Examples:
|
8
|
+
# <%= link_to("http://www.mackframework.com") %> # => <a href="http://www.mackframework.com">http://www.mackframework.com</a>
|
9
|
+
# <%= link_to("Mack", "http://www.mackframework.com") %> # => <a href="http://www.mackframework.com">Mack</a>
|
10
|
+
# <%= link_to("Mack", "http://www.mackframework.com", :target => "_blank") %> # => <a href="http://www.mackframework.com" target="_blank">Mack</a>
|
11
|
+
# <%= link_to("Mack", "http://www.mackframework.com", :target => "_blank", :rel => :nofollow) %> # => <a href="http://www.mackframework.com" target="_blank" rel="nofollow">Mack</a>
|
12
|
+
# If you pass in :method as an option it will be a JavaScript form that will post to the specified link with the
|
13
|
+
# methd specified.
|
14
|
+
# <%= link_to("Mack", "http://www.mackframework.com", :method => :delete) %>
|
15
|
+
# If you use the :method option you can also pass in a :confirm option. The :confirm option will generate a
|
16
|
+
# javascript confirmation window. If 'OK' is selected the the form will submit. If 'cancel' is selected, then
|
17
|
+
# nothing will happen. This is extremely useful for 'delete' type of links.
|
18
|
+
# <%= link_to("Mack", "http://www.mackframework.com", :method => :delete, :confirm => "Are you sure?") %>
|
19
|
+
def link_to(link_text, url = link_text, html_options = {})
|
20
|
+
Mack::Utils::Html.href(link_text, url, html_options)
|
21
|
+
end
|
22
|
+
|
23
|
+
# A wrapper method for views that calls out to Mack::Utils::Html.
|
24
|
+
#
|
25
|
+
# Examples:
|
26
|
+
# <%= html.b("hello") %> # => <b>hello</b>
|
27
|
+
def html
|
28
|
+
Mack::Utils::Html
|
29
|
+
end
|
30
|
+
|
31
|
+
end # HtmlHelpers
|
32
|
+
end # ViewHelpers
|
33
|
+
end # Mack
|
@@ -0,0 +1,72 @@
|
|
1
|
+
if using_activerecord?
|
2
|
+
class ActiveRecord::Base # :nodoc:
|
3
|
+
def business_display_name
|
4
|
+
self.class.name#.titlecase
|
5
|
+
end
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
if using_data_mapper?
|
10
|
+
class DataMapper::Base # :nodoc:
|
11
|
+
def business_display_name
|
12
|
+
self.class.name#.titlecase
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
module Mack
|
18
|
+
module ViewHelpers
|
19
|
+
module OrmHelpers
|
20
|
+
DEFAULT_PARTIAL = %{
|
21
|
+
<div>
|
22
|
+
<div class="errorExplanation" id="errorExplanation">
|
23
|
+
<h2>Oi, there were errors! Fix `em!</h2>
|
24
|
+
<ul>
|
25
|
+
<% for error in errors %>
|
26
|
+
<li><%= error %></li>
|
27
|
+
<% end %>
|
28
|
+
</ul>
|
29
|
+
</div>
|
30
|
+
</div>
|
31
|
+
}
|
32
|
+
|
33
|
+
def error_messages_for(object_names = [], view_partial = nil)
|
34
|
+
object_names = [object_names]
|
35
|
+
object_names.flatten!
|
36
|
+
app_errors = []
|
37
|
+
object_names.each do |name|
|
38
|
+
object = instance_variable_get("@#{name}")
|
39
|
+
if object
|
40
|
+
object.errors.each do |key, value|
|
41
|
+
if value.match(/^\^/)
|
42
|
+
app_errors << value[1..value.length]
|
43
|
+
else
|
44
|
+
if key.class == String and key == "base"
|
45
|
+
app_errors << "#{value}"
|
46
|
+
else
|
47
|
+
app_errors << "#{object.business_display_name} #{key.underscore.split('_').join(' ').humanize} #{value}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
File.join(MACK_VIEWS, "application", "_error_messages.html.erb")
|
54
|
+
unless app_errors.empty?
|
55
|
+
if view_partial.nil?
|
56
|
+
if File.exist?(File.join(MACK_VIEWS, "application", "_error_messages.html.erb"))
|
57
|
+
render :partial => "application/error_messages", :locals => {:errors => app_errors}
|
58
|
+
else
|
59
|
+
render :text => DEFAULT_PARTIAL, :locals => {:errors => app_errors}
|
60
|
+
end
|
61
|
+
else
|
62
|
+
render :partial => view_partial, :locals => {:errors => app_errors}
|
63
|
+
end
|
64
|
+
else
|
65
|
+
""
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# self.include_safely_into(Mack::ViewBinder)
|
70
|
+
end # OrmHelpers
|
71
|
+
end # ViewHelpers
|
72
|
+
end # Mack
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Mack
|
2
|
+
class Request < Rack::Request
|
3
|
+
|
4
|
+
def initialize(env) # :nodoc:
|
5
|
+
super(env)
|
6
|
+
@mack_params = {}
|
7
|
+
parse_params(rack_params)
|
8
|
+
end
|
9
|
+
|
10
|
+
alias_method :rack_params, :params # :nodoc:
|
11
|
+
|
12
|
+
# Returns all parameters associated with this request.
|
13
|
+
def all_params
|
14
|
+
@mack_params
|
15
|
+
end
|
16
|
+
|
17
|
+
# Merges another Hash with the parameters for this request.
|
18
|
+
def merge_params(opts = {})
|
19
|
+
parse_params(opts)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Gives access to the session. See Mack::Session for more information.
|
23
|
+
attr_accessor :session
|
24
|
+
|
25
|
+
# Examples:
|
26
|
+
# http://example.org
|
27
|
+
# https://example.org
|
28
|
+
# http://example.org:8080
|
29
|
+
def full_host
|
30
|
+
u = self.scheme.dup
|
31
|
+
u << "://"
|
32
|
+
u << self.host.dup
|
33
|
+
unless self.port == 80 || self.port == 443
|
34
|
+
u << ":#{self.port}"
|
35
|
+
end
|
36
|
+
u
|
37
|
+
end
|
38
|
+
|
39
|
+
# Examples:
|
40
|
+
# http://example.org:80
|
41
|
+
# https://example.org:443
|
42
|
+
# http://example.org:8080
|
43
|
+
def full_host_with_port
|
44
|
+
full_host << ":#{self.port}"
|
45
|
+
end
|
46
|
+
|
47
|
+
# Gives access to the request parameters. This includes 'get' parameters, 'post' parameters
|
48
|
+
# as well as parameters from the routing process. The parameter will also be 'unescaped'
|
49
|
+
# when it is returned.
|
50
|
+
#
|
51
|
+
# Example:
|
52
|
+
# uri: '/users/1?foo=bar'
|
53
|
+
# route: '/users/:id' => {:controller => 'users', :action => 'show'}
|
54
|
+
# parameters: {:controller => 'users', :action => 'show', :id => 1, :foo => "bar"}
|
55
|
+
def params(key)
|
56
|
+
p = (@mack_params[key.to_sym] || @mack_params[key.to_s])
|
57
|
+
unless p.nil?
|
58
|
+
p = p.to_s if p.is_a?(Symbol)
|
59
|
+
if p.is_a?(String)
|
60
|
+
p = Rack::Utils.unescape(p)
|
61
|
+
elsif p.is_a?(Hash)
|
62
|
+
p.each_pair {|k,v| p[k] = Rack::Utils.unescape(v)}
|
63
|
+
end
|
64
|
+
end
|
65
|
+
p
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def parse_params(ps)
|
70
|
+
ps.each_pair do |k, v|
|
71
|
+
if k.to_s.match(/.+\[.+\]/)
|
72
|
+
nv = k.to_s.match(/.+\[(.+)\]/).captures.first
|
73
|
+
nk = k.to_s.match(/(.+)\[.+\]/).captures.first
|
74
|
+
@mack_params[nk.to_sym] = {} if @mack_params[nk.to_sym].nil?
|
75
|
+
@mack_params[nk.to_sym].merge!(nv.to_sym => v)
|
76
|
+
else
|
77
|
+
@mack_params[k.to_sym] = v
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Mack
|
2
|
+
|
3
|
+
# A holder for the session information. This objects gets stored using the Cachetastic system.
|
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 application_configuration
|
6
|
+
# system like such:
|
7
|
+
# mack::session_id: _my_cool_app_sess_id
|
8
|
+
class Session
|
9
|
+
|
10
|
+
attr_reader :id # The id of the session.
|
11
|
+
|
12
|
+
def initialize(id)
|
13
|
+
@id = id
|
14
|
+
@sess_hash = {}
|
15
|
+
end
|
16
|
+
|
17
|
+
# Finds what you're looking for in the session, if it exists.
|
18
|
+
# If what you're looking for doesn't exist, it returns nil.
|
19
|
+
def [](key)
|
20
|
+
sess_hash[key.to_sym]
|
21
|
+
end
|
22
|
+
|
23
|
+
# Sets a value into the session.
|
24
|
+
def []=(key, value)
|
25
|
+
sess_hash[key.to_sym] = value
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
attr_reader :sess_hash # :nodoc:
|
30
|
+
|
31
|
+
end # Session
|
32
|
+
|
33
|
+
end # Mack
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# require 'erubis'
|
2
|
+
# This class is used to do all the view level bindings.
|
3
|
+
# It allows for seperation between the controller and the view levels.
|
4
|
+
class Mack::ViewBinder
|
5
|
+
|
6
|
+
attr_accessor :controller # Allows access to the controller.
|
7
|
+
attr_accessor :options # Allows access to any options passed into the Binder.
|
8
|
+
|
9
|
+
def initialize(cont, opts = {})
|
10
|
+
self.controller = cont
|
11
|
+
self.options = {:locals => {}}.merge(opts)
|
12
|
+
transfer_vars(@controller)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the binding for this class.
|
16
|
+
def view_binding
|
17
|
+
binding
|
18
|
+
end
|
19
|
+
|
20
|
+
# If a method can not be found then the :locals key of
|
21
|
+
# the options is used to find the variable.
|
22
|
+
def method_missing(sym, *args)
|
23
|
+
self.options[:locals][sym]
|
24
|
+
end
|
25
|
+
|
26
|
+
# Handles rendering calls both in the controller and in the view.
|
27
|
+
# For full details of render examples see Mack::Controller::Base render.
|
28
|
+
# Although the examples there are all in controllers, they idea is still
|
29
|
+
# the same for views.
|
30
|
+
#
|
31
|
+
# Examples in the view:
|
32
|
+
# <%= render(:text => "Hello") %>
|
33
|
+
# <%= render(:action => "show") %>
|
34
|
+
# <%= render(:partial => :latest_news) %>
|
35
|
+
def render(options = {})
|
36
|
+
if options[:action]
|
37
|
+
begin
|
38
|
+
# Try to render the action:
|
39
|
+
return render_file(options[:action], options)
|
40
|
+
rescue Errno::ENOENT => e
|
41
|
+
begin
|
42
|
+
# If the action doesn't exist on disk, try to render it from the public directory:
|
43
|
+
t = render_file(options[:action], {:dir => MACK_PUBLIC, :ext => ".html", :layout => false}.merge(options))
|
44
|
+
# Because it's being served from public don't wrap a layout around it!
|
45
|
+
# self.controller.instance_variable_get("@render_options").merge!({:layout => false})
|
46
|
+
return t
|
47
|
+
rescue Errno::ENOENT => ex
|
48
|
+
end
|
49
|
+
# Raise the original exception because something bad has happened!
|
50
|
+
raise e
|
51
|
+
end
|
52
|
+
elsif options[:text]
|
53
|
+
return Mack::ViewBinder.render(options[:text], self.controller, options)
|
54
|
+
elsif options[:partial]
|
55
|
+
return render_file(options[:partial], {:is_partial => true}.merge(options))
|
56
|
+
elsif options[:public]
|
57
|
+
t = render_file(options[:public], {:dir => MACK_PUBLIC, :ext => ".html", :layout => false}.merge(options))
|
58
|
+
# self.controller.instance_variable_get("@render_options").merge!({:layout => false})
|
59
|
+
return t
|
60
|
+
else
|
61
|
+
raise Mack::UnknownRenderOption.new(options)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
def render_file(f, options = {})
|
67
|
+
options = {:is_partial => false, :ext => ".html.erb", :dir => MACK_VIEWS}.merge(options)
|
68
|
+
partial = f.to_s
|
69
|
+
parts = partial.split("/")
|
70
|
+
if parts.size == 1
|
71
|
+
# it's local to this controller
|
72
|
+
partial = "_" << partial if options[:is_partial]
|
73
|
+
partial = File.join(options[:dir], self.controller.controller_name, partial + options[:ext])
|
74
|
+
else
|
75
|
+
# it's elsewhere
|
76
|
+
parts[parts.size - 1] = "_" << parts.last if options[:is_partial]
|
77
|
+
partial = File.join(options[:dir], parts.join("/") + options[:ext])
|
78
|
+
end
|
79
|
+
return Mack::ViewBinder.render(File.open(partial).read, self.controller, options)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Transfer instance variables from the controller to the view.
|
83
|
+
def transfer_vars(x)
|
84
|
+
x.instance_variables.each do |v|
|
85
|
+
self.instance_variable_set(v, x.instance_variable_get(v))
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class << self
|
90
|
+
|
91
|
+
# Creates a Mack::ViewBinder and then passes the io through ERB
|
92
|
+
# and returns a String. The io can be either an IO object or a String.
|
93
|
+
def render(io, controller, options = {})
|
94
|
+
vb = Mack::ViewBinder.new(controller, options)
|
95
|
+
return ERB.new(io).result(vb.view_binding)
|
96
|
+
# return Erubis::Eruby.new(io).result(vb.view_binding)
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|