mack 0.5.0 → 0.5.5

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