mack 0.5.0 → 0.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. data/CHANGELOG +19 -0
  2. data/bin/mack +3 -2
  3. data/bin/mack_ring_server +19 -1
  4. data/lib/{sea_level/controller_base.rb → controller/base.rb} +87 -128
  5. data/lib/{sea_level → controller}/cookie_jar.rb +3 -3
  6. data/lib/{sea_level → controller}/filter.rb +0 -0
  7. data/lib/{sea_level → controller}/request.rb +0 -0
  8. data/lib/{sea_level → controller}/response.rb +0 -0
  9. data/lib/{sea_level → controller}/session.rb +0 -0
  10. data/lib/{sea_level → controller}/uploaded_file.rb +0 -0
  11. data/lib/distributed/routing/urls.rb +1 -1
  12. data/lib/distributed/utils/rinda.rb +1 -1
  13. data/lib/errors/errors.rb +6 -4
  14. data/lib/generators/mack_application_generator/templates/config/initializers/mime_types.rb.template +3 -0
  15. data/lib/generators/mack_application_generator/templates/public/favicon.ico.template +0 -0
  16. data/lib/initialization/configuration.rb +2 -1
  17. data/lib/initialization/console.rb +2 -2
  18. data/lib/initialization/{initializers/logging.rb → logging.rb} +0 -0
  19. data/lib/initialization/{initializers/orm_support.rb → orm_support.rb} +0 -0
  20. data/lib/initialization/{initializers/plugins.rb → plugins.rb} +0 -0
  21. data/lib/mack.rb +107 -131
  22. data/lib/mack_tasks.rb +1 -1
  23. data/lib/rendering/engine/base.rb +26 -0
  24. data/lib/rendering/engine/builder.rb +30 -0
  25. data/lib/rendering/engine/erubis.rb +67 -0
  26. data/lib/rendering/engine/haml.rb +18 -0
  27. data/lib/rendering/engine/markaby.rb +27 -0
  28. data/lib/rendering/engine/registry.rb +48 -0
  29. data/lib/rendering/type/action.rb +37 -0
  30. data/lib/rendering/type/base.rb +59 -0
  31. data/lib/rendering/type/file_base.rb +32 -0
  32. data/lib/rendering/type/inline.rb +26 -0
  33. data/lib/rendering/type/layout.rb +26 -0
  34. data/lib/rendering/type/partial.rb +40 -0
  35. data/lib/rendering/type/public.rb +29 -0
  36. data/lib/rendering/type/template.rb +22 -0
  37. data/lib/rendering/type/text.rb +17 -0
  38. data/lib/rendering/type/url.rb +120 -0
  39. data/lib/rendering/type/xml.rb +34 -0
  40. data/lib/rendering/view_template.rb +168 -0
  41. data/lib/routing/route_map.rb +20 -11
  42. data/lib/runner.rb +137 -0
  43. data/lib/utils/mime_types.rb +56 -0
  44. data/lib/utils/mime_types.yml +449 -0
  45. data/lib/{sea_level/helpers/view_helpers → view_helpers}/html_helpers.rb +0 -0
  46. data/lib/{sea_level/helpers/view_helpers → view_helpers}/string_helpers.rb +0 -0
  47. metadata +58 -29
  48. data/lib/initialization/initializer.rb +0 -110
  49. data/lib/rendering/base.rb +0 -62
  50. data/lib/rendering/classes/action.rb +0 -26
  51. data/lib/rendering/classes/partial.rb +0 -12
  52. data/lib/rendering/classes/public.rb +0 -13
  53. data/lib/rendering/classes/text.rb +0 -12
  54. data/lib/rendering/classes/url.rb +0 -59
  55. data/lib/rendering/classes/xml.rb +0 -24
  56. data/lib/sea_level/view_binder.rb +0 -88
@@ -0,0 +1,34 @@
1
+ require File.join(File.dirname(__FILE__), "..", "view_template")
2
+ module Mack
3
+ module Rendering # :nodoc:
4
+ module Type # :nodoc:
5
+ # Used to render an XML template that's relative to a controller.
6
+ #
7
+ # Example:
8
+ # class UsersController < Mack::Controller::Base
9
+ # # /users/:id
10
+ # def show
11
+ # @user = User.first(params(:id))
12
+ # end
13
+ # # /users
14
+ # def index
15
+ # @users = User.all
16
+ # render(:xml, :list)
17
+ # end
18
+ # end
19
+ # When some calls /users/1.xml the file: app/views/users/show.xml.builder will be rendered.
20
+ # When some calls /users.xml the file: app/views/users/list.xml.builder will be rendered.
21
+ class Xml < Mack::Rendering::Type::FileBase
22
+
23
+ # See Mack::Rendering::Type::FileBase render_file for more information.
24
+ def render
25
+ self.options[:format] = "xml"
26
+ self.controller.response["Content-Type"] = Mack::Utils::MimeTypes[self.options[:format]]
27
+ x_file = File.join(self.controller_view_path, "#{self.render_value}.#{self.options[:format]}")
28
+ render_file(x_file, :xml)
29
+ end
30
+
31
+ end # Xml
32
+ end # Type
33
+ end # Rendering
34
+ end # Mack
@@ -0,0 +1,168 @@
1
+ module Mack
2
+ module Rendering # :nodoc:
3
+ # This class is used to do all the view level bindings.
4
+ # It allows for seperation between the Mack::Controller::Base and the view levels.
5
+ class ViewTemplate
6
+
7
+ # Allows access to any options passed into the template.
8
+ attr_accessor :options
9
+ attr_accessor :render_type
10
+ attr_accessor :render_value
11
+
12
+ def initialize(render_type, render_value, options = {})
13
+ self.render_type = render_type
14
+ self.render_value = render_value
15
+ self.options = options
16
+ @_yield_to_cache = {}
17
+ end
18
+
19
+ # Allows access to the current Mack::Controller::Base object.
20
+ def controller
21
+ self.options[:controller]
22
+ end
23
+
24
+ # Returns the Mack::Request associated with the current Mack::Controller::Base object.
25
+ def request
26
+ self.controller.request
27
+ end
28
+
29
+ # Returns the Mack::Session associated with the current Mack::Request.
30
+ def session
31
+ self.request.session
32
+ end
33
+
34
+ # Returns the Mack::CookieJar associated with the current Mack::Controller::Base object.
35
+ def cookies
36
+ self.controller.cookies
37
+ end
38
+
39
+ # If a method can not be found then the :locals key of
40
+ # the options is used to find the variable.
41
+ def method_missing(sym, *args)
42
+ raise NoMethodError.new(sym.to_s) unless self.options[:locals]
43
+ self.options[:locals][sym]
44
+ end
45
+
46
+ # Maps to the controller's param method. See also Mack::Controller::Base params.
47
+ def params(key)
48
+ self.controller.params(key)
49
+ end
50
+
51
+ # Handles rendering calls both in the controller and in the view.
52
+ # For full details of render examples see Mack::Controller::Base render.
53
+ # Although the examples there are all in controllers, they idea is still
54
+ # the same for views.
55
+ #
56
+ # Examples in the view:
57
+ # <%= render(:text, "Hello") %>
58
+ # <%= render(:action, "show") %>
59
+ # <%= render(:partial, :latest_news) %>
60
+ # <%= render(:url, "http://www.mackframework.com") %>
61
+ def render(render_type, render_value, options = {})
62
+ options = self.options.merge({:layout => false}).merge(options)
63
+ Mack::Rendering::ViewTemplate.new(render_type, render_value, options).compile_and_render
64
+ end
65
+
66
+ # Returns a string stored using content_for.
67
+ #
68
+ # Example:
69
+ # <% content_for(:hello, "Hello World") %>
70
+ # <%= yield_to :hello %> # => "Hello World"
71
+ #
72
+ # <% content_for(:bye) do %>
73
+ # Ah, it's so sad to say goodbye.
74
+ # <% end %>
75
+ # <%= yield_to :bye %> # => "Ah, it's so sad to say goodbye."
76
+ def yield_to(key)
77
+ @_yield_to_cache[key.to_sym]
78
+ end
79
+
80
+ # Stores a string that can be retrieved using yield_to.
81
+ #
82
+ # Example:
83
+ # <% content_for(:hello, "Hello World") %>
84
+ # <%= yield_to :hello %> # => "Hello World"
85
+ #
86
+ # <% content_for(:bye) do %>
87
+ # Ah, it's so sad to say goodbye.
88
+ # <% end %>
89
+ # <%= yield_to :bye %> # => "Ah, it's so sad to say goodbye."
90
+ def content_for(key, value = nil, &block)
91
+ return @_yield_to_cache[key.to_sym] = value unless value.nil?
92
+ return @_yield_to_cache[key.to_sym] = @_render_type.capture(&block) if block_given?
93
+ end
94
+
95
+ # Transfers all the instance variables from the controller to the current instance of
96
+ # the view template. This call is cached, so it only happens once, regardless of the number
97
+ # of times it is called.
98
+ def compile
99
+ ivar_cache("compiled_template") do
100
+ self.options.symbolize_keys!
101
+ transfer_vars(self.controller)
102
+ end
103
+ end
104
+
105
+ # Fully compiles and renders the view and, if applicable, it's layout.
106
+ def compile_and_render
107
+ self.compile
108
+ content_for(:view, render_view)
109
+ render_layout
110
+ end
111
+
112
+ # Passes concatenation messages through to the Mack::Rendering::Type object.
113
+ # This should append the text, using the passed in binding, to the final output
114
+ # of the render.
115
+ def concat(txt, b)
116
+ @_render_type.concat(txt, b)
117
+ end
118
+
119
+ # Primarily used by Mack::Rendering::Type::Url when dealing with 'local' urls.
120
+ # This returns an instance of the current application to run additional requests
121
+ # through.
122
+ def app_for_rendering
123
+ ivar_cache do
124
+ Mack::Utils::Server.build_app
125
+ end
126
+ end
127
+
128
+ # Returns the binding of the current view template to be used with
129
+ # the engines to render.
130
+ def binder
131
+ binding
132
+ end
133
+
134
+ private
135
+
136
+ def render_layout
137
+ if @_render_type.allow_layout? && self.options[:layout]
138
+ return Mack::Rendering::Type::Layout.new(self).render
139
+ end
140
+ return yield_to(:view)
141
+ end
142
+
143
+ def render_view
144
+ @_render_type = find_render_type(self.render_type).new(self)
145
+ @_render_type.render
146
+ end
147
+
148
+ def find_file(*path)
149
+ f = File.join(path)
150
+ if File.exists?(f)
151
+ yield f
152
+ end
153
+ end
154
+
155
+ # Transfer instance variables from the controller to the view.
156
+ def transfer_vars(x)
157
+ x.instance_variables.each do |v|
158
+ self.instance_variable_set(v, x.instance_variable_get(v))
159
+ end
160
+ end
161
+
162
+ def find_render_type(e)
163
+ eval("Mack::Rendering::Type::#{e.to_s.camelcase}")
164
+ end
165
+
166
+ end # ViewTemplate
167
+ end # Mack
168
+ end # Mack
@@ -9,7 +9,7 @@ module Mack
9
9
  def self.build
10
10
  yield Mack::Routes::RouteMap.instance
11
11
  Mack::Routes::Urls.include_safely_into(Mack::Controller::Base,
12
- Mack::ViewBinder,
12
+ Mack::Rendering::ViewTemplate,
13
13
  Test::Unit::TestCase,
14
14
  Mack::Distributed::Routes::Urls)
15
15
  if app_config.mack.use_distributed_routes
@@ -134,6 +134,7 @@ module Mack
134
134
 
135
135
  def initialize # :nodoc:
136
136
  @routes_list = []
137
+ @default_routes_list = []
137
138
  end
138
139
 
139
140
  # Creates 'Rails' style default mappings:
@@ -141,21 +142,16 @@ module Mack
141
142
  # "/:controller/:action"
142
143
  # These get created for each of the 4 HTTP verbs.
143
144
  def defaults
145
+ @default_routes_list = []
144
146
  [:get, :post, :put, :delete].each do |verb|
145
- connect("/:controller/:action/:id", :method => verb)
146
- connect("/:controller/:action", :method => verb)
147
+ @default_routes_list << build_route("/:controller/:action/:id", :method => verb)
148
+ @default_routes_list << build_route("/:controller/:action", :method => verb)
147
149
  end
148
150
  end
149
151
 
150
152
  # Connects a url pattern to a controller, an action, and an HTTP verb.
151
153
  def connect(pattern, options = {})
152
- # set the default options:
153
- options = {:action => :index, :method => :get}.merge(options)
154
- meth = options[:method].to_sym
155
- # if the pattern doesn't start with /, then add it.
156
- pattern = "/" << pattern unless pattern.match(/^\//)
157
- pt = pattern.downcase
158
- route = Route.new(pt, regex_from_pattern(pt), meth, options)
154
+ route = build_route(pattern, options)
159
155
  routes_list << route
160
156
  return route
161
157
  end
@@ -187,8 +183,11 @@ module Mack
187
183
  pattern.chop! if pattern.match(/\/$/)
188
184
  end
189
185
  meth = (req.params("_method") || req.request_method.downcase).to_sym
186
+ rt = routes_list.dup
187
+ rt << @default_routes_list.dup
188
+ rt.flatten!
190
189
  begin
191
- routes_list.each do |route|
190
+ rt.each do |route|
192
191
  if pattern.match(route.regex_pattern) && route.method == meth
193
192
  r = route
194
193
  opts = r.options_with_embedded_parameters(pattern)
@@ -206,6 +205,16 @@ module Mack
206
205
  attr_reader :routes_list # :nodoc:
207
206
 
208
207
  private
208
+ def build_route(pattern, options = {})
209
+ # set the default options:
210
+ options = {:action => :index, :method => :get}.merge(options)
211
+ meth = options[:method].to_sym
212
+ # if the pattern doesn't start with /, then add it.
213
+ pattern = "/" << pattern unless pattern.match(/^\//)
214
+ pt = pattern.downcase
215
+ Route.new(pt, regex_from_pattern(pt), meth, options)
216
+ end
217
+
209
218
  def connect_with_named_route(n_route, pattern, options = {})
210
219
  n_route = n_route.methodize
211
220
  route = connect(pattern, options)
data/lib/runner.rb ADDED
@@ -0,0 +1,137 @@
1
+ module Mack
2
+ # This is the heart and soul of the Mack framework! This class interfaces with the Rack framework.
3
+ # It handles all the dispatching back and forth between the Rack framework and a Mack application.
4
+ class Runner
5
+ include Mack::Routes::Urls
6
+
7
+ attr_reader :response # :nodoc:
8
+ attr_reader :request # :nodoc:
9
+ attr_reader :cookies # :nodoc:
10
+ # This method needs to be defined as part of the Rack framework. As is noted for the Mack::Runner
11
+ # class, this is where the center of the Mack framework lies.
12
+ def call(env)
13
+ # pp env
14
+ begin
15
+ setup(env) do
16
+ begin
17
+ route = Mack::Routes::RouteMap.instance.get_route_from_request(self.request)
18
+ if route[:redirect_to]
19
+ # because the route is specified to be a redirect, let's do that:
20
+ redirect_to(route)
21
+ else
22
+ # let's handle a normal request:
23
+ begin
24
+ cont = "#{route[:controller].to_s.camelcase}Controller".constantize
25
+ rescue NameError => e
26
+ raise Mack::Errors::ResourceNotFound.new(self.request.path_info)
27
+ end
28
+ c = cont.new(self.request, self.response, self.cookies)
29
+ self.response.controller = c
30
+ self.response.write(c.run)
31
+ end
32
+ rescue Mack::Errors::ResourceNotFound, Mack::Errors::UndefinedRoute => e
33
+ return try_to_find_resource(env, e)
34
+ end
35
+ end # setup
36
+ rescue Exception => e
37
+ MACK_DEFAULT_LOGGER.error(e)
38
+ raise e
39
+ end
40
+ end
41
+
42
+ private
43
+ def log_request
44
+ s_time = Time.now
45
+ x = yield
46
+ e_time = Time.now
47
+ p_time = e_time - s_time
48
+ if app_config.log.detailed_requests
49
+ msg = "\n\t[#{@request.request_method.upcase}] '#{@request.path_info}'\n"
50
+ msg << "\tSession ID: #{@request.session.id}\n"
51
+ msg << "\tParameters: #{@request.all_params.inspect}\n"
52
+ msg << "\tCompleted in #{p_time} (#{(1 / p_time).round} reqs/sec) | #{@response.status} [#{@request.full_host}]"
53
+ else
54
+ msg = "[#{@request.request_method.upcase}] '#{@request.path_info}' (#{p_time})"
55
+ end
56
+ MACK_DEFAULT_LOGGER.info(msg)
57
+ x
58
+ end
59
+
60
+ # Setup the request, response, cookies, session, etc...
61
+ # yield up, and then clean things up afterwards.
62
+ def setup(env)
63
+ exception = nil
64
+ log_request do
65
+ @request = Mack::Request.new(env)
66
+ @response = Mack::Response.new
67
+ @cookies = Mack::CookieJar.new(self.request, self.response)
68
+ session do
69
+ begin
70
+ yield
71
+ rescue Exception => e
72
+ exception = e
73
+ end
74
+ end
75
+ end
76
+ raise exception if exception
77
+ self.response.finish
78
+ end
79
+
80
+ def session
81
+ sess_id = self.cookies[app_config.mack.session_id]
82
+ unless sess_id
83
+ sess_id = create_new_session
84
+ else
85
+ sess = Cachetastic::Caches::MackSessionCache.get(sess_id)
86
+ if sess
87
+ self.request.session = sess
88
+ else
89
+ # we couldn't find it in the store, so we need to create it:
90
+ sess_id = create_new_session
91
+ end
92
+ end
93
+
94
+ yield
95
+
96
+ Cachetastic::Caches::MackSessionCache.set(sess_id, self.request.session)
97
+ end
98
+
99
+ def create_new_session
100
+ id = String.randomize(40).downcase
101
+ self.cookies[app_config.mack.session_id] = {:value => id, :expires => nil}
102
+ sess = Mack::Session.new(id)
103
+ self.request.session = sess
104
+ Cachetastic::Caches::MackSessionCache.set(id, sess)
105
+ id
106
+ end
107
+
108
+ def try_to_find_resource(env, exception)
109
+ env = env.dup
110
+ # we can't find a route for this, so let's try and see if it's in the public directory:
111
+ if File.extname(env["PATH_INFO"]).blank?
112
+ env["PATH_INFO"] << ".html"
113
+ end
114
+ if File.exists?(File.join(Mack::Configuration.public_directory, env["PATH_INFO"]))
115
+ return Rack::File.new(File.join(Mack::Configuration.public_directory)).call(env)
116
+ else
117
+ raise exception
118
+ end
119
+ end
120
+
121
+ # This will redirect the request to the specified url. A default status of
122
+ # 302, Moved Temporarily, is set if no status is specified. A simple HTML
123
+ # page is rendered in case the redirect does not occur.
124
+ def redirect_to(route)
125
+ status = route[:status] || 302
126
+ url = route[:redirect_to]
127
+ options = self.request.all_params
128
+ options.merge!(route)
129
+ options - [:controller, :action, :redirect_to, :method, :status, :format]
130
+ url = url_for_pattern(url, options)
131
+ self.response.status = status
132
+ self.response[:location] = url
133
+ self.response.write(redirect_html(self.request.path_info, url, status))
134
+ end
135
+
136
+ end
137
+ end
@@ -0,0 +1,56 @@
1
+ module Mack
2
+ module Utils
3
+ # Houses the MimeTypes used by the system to set the proper 'Content-Type' for requests.
4
+ class MimeTypes
5
+ include Singleton
6
+
7
+ def initialize # :nodoc:
8
+ @types = YAML.load(File.open(File.join(File.dirname(__FILE__), "mime_types.yml")))
9
+ end
10
+
11
+ # Registers a new mime-type to the system. If the key already exists, it will
12
+ # be appended to the existing type.
13
+ #
14
+ # Examples:
15
+ # Mack::Utils::MimeTypes.register(:iphone, "app/iphone")
16
+ # "/users.iphone" # => will have a 'Content-Type' header of "app/iphone"
17
+ # Mack::Utils::MimeTypes.register(:iphone, "application/mac-iphone")
18
+ # "/users.iphone" # => will have a 'Content-Type' header of "app/iphone; application/mac-iphone"
19
+ def register(name, type)
20
+ name = name.to_sym
21
+ if @types.has_key?(name)
22
+ @types[name] << "; " << type
23
+ else
24
+ @types[name] = type
25
+ end
26
+ end
27
+
28
+ # Returns the type registered for the key, if there is no type for the key,
29
+ # then "text/html" is returned
30
+ #
31
+ # Examples:
32
+ # Mack::Utils::MimeTypes.get(:iphone)
33
+ # # => "app/iphone"
34
+ # Mack::Utils::MimeTypes.get(:i_dont_exist)
35
+ # # => "text/html"
36
+ def get(name)
37
+ @types[name.to_sym] || "text/html"
38
+ end
39
+
40
+ class << self
41
+
42
+ # Maps to Mack::Utils::MimeTypes.instance.get
43
+ def [](name)
44
+ Mack::Utils::MimeTypes.instance.get(name.to_sym)
45
+ end
46
+
47
+ # Maps to Mack::Utils::MimeTypes.instance.register
48
+ def register(name, type)
49
+ Mack::Utils::MimeTypes.instance.register(name, type)
50
+ end
51
+
52
+ end
53
+
54
+ end # MimeTypes
55
+ end # Utils
56
+ end # Mack