doozer 0.3.1 → 0.4.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/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.4.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{doozer}
8
- s.version = "0.3.1"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["grippy"]
12
- s.date = %q{2009-10-30}
12
+ s.date = %q{2009-11-05}
13
13
  s.default_executable = %q{doozer}
14
14
  s.description = %q{This GEM provides a small, barebones framework for creating MVC Rack applications.}
15
15
  s.email = %q{gmelton@whorde.com}
@@ -41,6 +41,7 @@ Gem::Specification.new do |s|
41
41
  "lib/doozer/initializer.rb",
42
42
  "lib/doozer/lib.rb",
43
43
  "lib/doozer/logger.rb",
44
+ "lib/doozer/middleware.rb",
44
45
  "lib/doozer/orm/active_record.rb",
45
46
  "lib/doozer/orm/data_mapper.rb",
46
47
  "lib/doozer/orm/sequel.rb",
@@ -27,6 +27,10 @@ module Doozer
27
27
  autoload :Route, "doozer/exceptions"
28
28
  end
29
29
 
30
+ autoload :Middleware, "doozer/middleware"
31
+ autoload :MiddlewareBeforeDozerApp, "doozer/middleware"
32
+
33
+
30
34
  autoload :Task, "doozer/task"
31
35
  autoload :ViewHelpers, "doozer/view_helpers"
32
36
  autoload :Version, "doozer/version"
@@ -28,6 +28,8 @@ module Doozer
28
28
  route = Doozer::Routing::Routes::match(path)
29
29
  # p "path: #{path}"
30
30
  # p "route: #{route.inspect}"
31
+ app = nil
32
+
31
33
  if not route.nil?
32
34
  if route.app.nil?
33
35
  extra_params = route.extra_params(path)
@@ -63,10 +65,13 @@ module Doozer
63
65
  r.set_cookie('flash',{:value=>nil, :path=>'/'})
64
66
  r.set_cookie('session',{:value=>controller.session_to_cookie(), :path=>'/'})
65
67
 
68
+ r = controller.write_response_cookies(r)
69
+
70
+
66
71
  # finalize the request
67
72
  controller.finished!
68
73
  controller = nil
69
- return r.to_a
74
+ app = r.to_a
70
75
 
71
76
  rescue Doozer::Redirect => redirect
72
77
  # set the status to the one defined in the route which type of redirect do we need to handle?
@@ -82,7 +87,7 @@ module Doozer
82
87
  # finalize the request
83
88
  controller.finished!
84
89
  controller = nil
85
- return r.to_a
90
+ app = r.to_a
86
91
  rescue => e
87
92
  # finalize the request
88
93
  controller.finished!
@@ -95,17 +100,22 @@ module Doozer
95
100
  end
96
101
  logger.error("Printing env variables:")
97
102
  logger.error(env.inspect)
98
- return [500, {"Content-Type" => "text/html"}, @@errors[500]]
103
+ app = [500, {"Content-Type" => "text/html"}, @@errors[500]]
99
104
  else
100
105
  raise e
101
106
  end
102
107
  end
103
108
  else
104
- return route.app.call(env)
109
+ app = route.app.call(env)
105
110
  end
106
111
  else
107
- return [404, {"Content-Type" => "text/html"}, @@errors[404]]
112
+ app = [404, {"Content-Type" => "text/html"}, @@errors[404]]
108
113
  end
114
+
115
+ # pass the app through route.middleware_after if defined
116
+ app = route.middleware_after.new(app, {:config=>Doozer::Configs, :route=>route}).call(env) if route.middleware_after
117
+
118
+ return app
109
119
  end
110
120
 
111
121
  def execution_time(name = nil, point = :start)
@@ -24,6 +24,22 @@ module Doozer
24
24
  attr_accessor :params
25
25
  # @flash variable containing a hash of strings which are persisted in the flash cookie across the response, next request/response and then removed.
26
26
  attr_accessor :flash
27
+ # @cookies variable containing a hash of hashes which persit until the expiration date
28
+ #
29
+ # To save cookies: All hash keys must be symbols and value strings.
30
+ # Reserved hash keys per cookie:
31
+ # => :expires - Time.now + some duration. This default to 30 days if not defined
32
+ # => :path - The path for the cookie. This defaults to '/' if not defined
33
+ #
34
+ # Example:
35
+ # => @cookies[:yum_yum]={:a=>'123',
36
+ # :b=>'abc',
37
+ # :expires=>Time.now + 3.day
38
+ # :path=>'/path'}
39
+ # To delete a cookie, set it to nil or delete it from @cookies
40
+ #
41
+ # => @cookies[:testing]=nil
42
+ attr_accessor :cookies
27
43
  # @session variable containing a hash of strings which are persisted in the session cookie until the browser session expires.
28
44
  attr_accessor :session
29
45
  # @view variable containing a hash of string which are read from layouts.
@@ -87,12 +103,15 @@ module Doozer
87
103
  #holds all variables for template binding
88
104
  @view={}; @view[:meta]={}
89
105
 
90
- #store flash
106
+ #loads flash messages from cookie
91
107
  @flash={}; flash_from_cookie()
92
108
 
93
- #store session
109
+ #loads cookies from cookies
110
+ @cookies={}; cookies_from_cookie()
111
+
112
+ #loads session cookie
94
113
  @session={}; session_from_cookie()
95
-
114
+
96
115
  #symbolize params
97
116
  @params={}; @request.params.each { |key, value| @params[key.to_sym] = value}
98
117
 
@@ -223,7 +242,7 @@ module Doozer
223
242
 
224
243
  # Read all the session cookies and store them in the @session instance variable
225
244
  def session_from_cookie
226
- #split name/value pairs and merge with flash
245
+ #split name/value pairs and merge into @session
227
246
  if @request.cookies
228
247
  if @request.cookies["session"]
229
248
  pairs=@request.cookies["session"].split('&')
@@ -235,6 +254,49 @@ module Doozer
235
254
  end
236
255
  end
237
256
 
257
+ # Read all the persistant cookies and store them in the @cookies instance variable
258
+ def cookies_from_cookie
259
+ #split name/value pairs
260
+ if @request.cookies
261
+ @request.cookies.each { | k, v |
262
+ if not ["flash", "session", "rack.session"].include?(k)
263
+ begin
264
+ # we need to catch cookies which don't match the key=value&key=value pattern...
265
+ # google analytics for example
266
+ values = {}
267
+ pairs=v.split('&')
268
+ pairs.each{ | pair |
269
+ pair = pair.split('=')
270
+ values[pair[0].to_sym]=CGI::unescape(pair[1])
271
+ }
272
+ @cookies[k.to_sym] = values
273
+ rescue
274
+ end
275
+ end
276
+ }
277
+ end
278
+ end
279
+
280
+ # Iterates all controller @cookies and writes them to the response
281
+ def write_response_cookies(r)
282
+ @cookies.each { | cookie, values |
283
+ if not values.nil?
284
+ value = []
285
+ path = values.delete(:path) || '/'
286
+ expires = values.delete(:expires) || Time.now + (60 * 60 * 24 * 30)
287
+ values.each { |k, v|
288
+ value.push("#{k.to_s}=#{CGI::escape(v)}") if not v.nil?
289
+ }
290
+ value = value.join('&')
291
+ else
292
+ value = ''
293
+ path = ''
294
+ expires = Time.now - 60
295
+ end
296
+ r.set_cookie(cookie.to_s,{:value=>value, :path=>path, :expires=>expires})
297
+ }
298
+ return r
299
+ end
238
300
  # Method for setting metatags via Controllers.
239
301
  #
240
302
  # Pass an options hash to @view[:meta] and all the key/values are turned into metatags with the corresponding values. See Doozer::ViewHelpers#metatags for creating the metatags for view.
@@ -0,0 +1,23 @@
1
+ module Doozer
2
+ class Middleware
3
+ def initialize(app, args=nil)
4
+ @app = app
5
+ @args = args
6
+ end
7
+ def config
8
+ @args[:config]
9
+ end
10
+ def logger
11
+ @args[:config].logger
12
+ end
13
+ def route
14
+ @args[:route]
15
+ end
16
+ end
17
+
18
+ class MiddlewareBeforeDozerApp < Middleware
19
+ def call(env)
20
+ @app.call(env)
21
+ end
22
+ end
23
+ end
@@ -6,6 +6,13 @@ require File.join(APP_PATH, 'config/boot')
6
6
  #--boot it up
7
7
  Doozer::Initializer.boot(env)
8
8
 
9
+ #--load config/rack if it exists so overrides are hit for MiddlewareBeforeDozerApp
10
+ begin
11
+ require "#{APP_PATH}/config/rack"
12
+ rescue => e
13
+ Doozer::Configs.logger.error(e)
14
+ end
15
+
9
16
  #--hookup the logger for production only since the base rackup builder doesn't load it. this avoids double logging in development
10
17
  use Rack::CommonLogger, Doozer::Configs.logger if Doozer::Configs.rack_env == :deployment
11
18
 
@@ -16,19 +23,20 @@ map "/" do
16
23
  use Rack::Reloader, secs=1
17
24
  end
18
25
 
19
- use Rack::Static, {:urls => Doozer::Configs.app["static_urls"], :root => "#{APP_PATH}/#{Doozer::Configs.app["static_root"]}"} if Doozer::Configs.app
26
+ use Rack::Static, {:urls => Doozer::Configs.app["static_urls"],
27
+ :root => "#{APP_PATH}/#{Doozer::Configs.app["static_root"]}"} if Doozer::Configs.app
20
28
 
21
29
  use Rack::Session::Cookie, :key => 'rack.session',
22
30
  :domain => '',
23
31
  :path => '/',
24
32
  :expire_after => 2592000
25
-
33
+
34
+ use Doozer::MiddlewareBeforeDozerApp, {:config=>Doozer::Configs}
26
35
  run Doozer::App.new(args=options)
27
36
  end
28
37
 
29
38
  #--stack additional rack apps
30
39
  begin
31
- require "#{APP_PATH}/config/rack"
32
40
  stack()
33
41
  rescue => e
34
42
  Doozer::Configs.logger.error(e)
@@ -201,8 +201,8 @@ module Doozer
201
201
  class Route
202
202
  attr_accessor :name, :path, :controller, :action,
203
203
  :layout, :status, :content_type, :tokens,
204
- :grouping, :app, :format, :view, :view_path
205
-
204
+ :grouping, :app, :format, :view, :view_path,
205
+ :middleware_before, :middleware_after
206
206
 
207
207
  # Initializes a route with the following parameters
208
208
  # route - [:name, 'path', {args}]
@@ -214,6 +214,8 @@ module Doozer
214
214
  @layout = (args[:layout]) ? args[:layout] : 'default'
215
215
  @status = (args[:status]) ? args[:status] : 200
216
216
  @app=args[:app]
217
+ @middleware_before=args[:middleware_before]
218
+ @middleware_after=args[:middleware_after]
217
219
  @format = (args[:format]) ? args[:format] : :html
218
220
  #@content_type = (args[:content_type]) ? args[:content_type] : 'text/html'
219
221
  case @format
@@ -21,7 +21,7 @@ clusters = Doozer::Configs.symbolize_keys(config[:clusters])
21
21
  @server = clusters[:server]
22
22
  @config = DOOZER_PATH + '/doozer/rackup/server.ru'
23
23
  @test_config = DOOZER_PATH + '/doozer/rackup/test.rb'
24
- @config_file = '' #optional config file to use instead of the default unicorn config
24
+ @config_file = '' # optional config file to use instead of the default unicorn config
25
25
  @apps = []
26
26
 
27
27
  for app in clusters[:apps]
@@ -80,6 +80,8 @@ def start_unicorn
80
80
  system(cmd)
81
81
  break
82
82
  end
83
+ puts "Did they start?"
84
+ system("ps -aux | grep unicorn")
83
85
  end
84
86
 
85
87
  # Calls stop() and then start()
@@ -1,8 +1,9 @@
1
+
1
2
  module Doozer
2
3
  module Version
3
4
  MAJOR=0
4
- MINOR=3
5
- PATCH=1
5
+ MINOR=4
6
+ PATCH=0
6
7
  STRING=[MAJOR, MINOR, PATCH].join('.')
7
8
  end
8
9
  end
@@ -11,6 +11,33 @@ class HelloWorld
11
11
  end
12
12
  end
13
13
 
14
+ # Here's an example of how to create an after doozer app middleware
15
+ # This class inherits Doozer::Middleware which has a few helper methods for passing Doozer::App calls on down the line
16
+ # You can define each route to call :middleware_after=>ClassName
17
+ # This example removes all tabs and carriage returns to slim the response
18
+ class AfterDoozer < Doozer::Middleware
19
+ def call(env)
20
+ status, header, response = @app
21
+ # logger.info(self.class.to_s)
22
+ if route and response.is_a?(Rack::Response)
23
+ response.body.each{ | p | p.gsub!(/\t|^\n|^\n\n/, '') } if not [:json, :js].include?(route.format)
24
+ end
25
+ [status, header, response]
26
+ end
27
+ end
28
+
29
+ # This module#class is hooked into the pipeline before Doozer::App is called.
30
+ # It inherits from Doozer::Middleware so it has access to #config but not #route
31
+ module Doozer
32
+ class MiddlewareBeforeDozerApp < Doozer::Middleware
33
+ def call(env)
34
+ # puts "MiddlewareBeforeDozerApp2"
35
+ # logger.info("here")
36
+ status, header, response = @app.call(env)
37
+ [status, header, response]
38
+ end
39
+ end
40
+ end
14
41
  # map additional rack apps here..
15
42
  def stack
16
43
  # map your apps here...
@@ -1,112 +1,108 @@
1
1
  """
2
- Drawing
3
- name, path w/ symbols, options={controller, action, status, formats, optional( layout, app=>HelloWorld.new)}
2
+ Drawing Routes
4
3
 
5
- Name - This is the symbol you name your route. Urls generation is mapped to this key.
4
+ Map Route
5
+ Name - This is the symbol you name your route. Url generation is mapped to this key.
6
6
  Path - This is the url path. May contain token symbols which are exposed to the controller
7
7
  Options -
8
- controller,
9
- action,
10
- status,
11
- formats=>[:xml, json, etc],
12
- layout
8
+ :controller=>'controller' (string)
9
+ :action=>'action' (string)
10
+ :status=>200|404|500 (int)
11
+ :layout=>'something_pretty' (string),
12
+ :formats=>[:html, :xml, json]
13
+ :app=>HelloWorld.new
14
+ :middleware_after=>HelloWorld
13
15
 
14
16
  Supports the following conventions:
15
- :root '' :controller=>'something'
16
- :articles '/articles' :controller=>'article', :action=>'list'
17
- :article '/article/:id' :controller=>'article', :action=>'show'
17
+ => :root '' :controller=>'something'
18
+ => :articles '/articles' :controller=>'article', :action=>'list'
19
+ => :article '/article/:id' :controller=>'article', :action=>'show'
18
20
 
19
21
  Formats
20
- Adding formats symbols automatically creates new routes for the formats symbols provided.
21
- The appropriate content-type is returned with the response.
22
- You can access the format with @format in your controllers.
23
- Supported formats are: :json, :js, :xml, :rss, :atom
24
- All routes default to :html format
22
+ => Adding formats symbolzes automatically creates new routes for the formats symbols provided.
23
+ => The appropriate content-type is returned with the response.
24
+ => You can access the format with @format in your controllers.
25
+ => Supported formats are: :json, :js, :xml, :rss, :atom
26
+ => All routes default to :html format
25
27
 
26
28
  Example:
27
-
28
- map.add :format_example, '/format_example', {:controller=>'index', :action=>'format_example', :status=>200, :formats=>[:json, :xml]}
29
-
30
- Automatically creates routes for :html, :json, and :xml with the appropriate content types
29
+ => map.add :format_example, '/format_example', {:controller=>'index', :action=>'format_example', :status=>200, :formats=>[:json, :xml]}
31
30
 
32
- :html format (default)
33
- map.add :format_example, '/format_example', {:controller=>'index', :action=>'format_example', :status=>200}
31
+ Automatically creates routes for :html, :json, and :xml with the appropriate content types
32
+
33
+ :html format (default)
34
+ => map.add :format_example, '/format_example', {:controller=>'index', :action=>'format_example', :status=>200}
34
35
 
35
- :json format
36
- map.add :format_example_json, '/format_example.json', {:controller=>'index', :action=>'format_example', :status=>200}
36
+ :json format
37
+ => map.add :format_example_json, '/format_example.json', {:controller=>'index', :action=>'format_example', :status=>200}
37
38
 
38
- :xml format
39
- map.add :format_example_xml, '/format_example.xml', {:controller=>'index', :action=>'format_example', :status=>200}
39
+ :xml format
40
+ => map.add :format_example_xml, '/format_example.xml', {:controller=>'index', :action=>'format_example', :status=>200}
40
41
 
41
42
  Layouts
42
-
43
- All routes use the layouts/default.format.erb view. You can override this by passing the layout symbol in the options hash like this:
44
- map.add :layout_example, '/layout_example', {:controller=>'index', :action=>'layout_example', :status=>200, :layout=>'other'}
43
+ All routes use the layouts/default.format.erb view. You can override this by passing the layout symbol in the options hash like this:
44
+ => map.add :layout_example, '/layout_example', {:controller=>'index', :action=>'layout_example', :status=>200, :layout=>'other'}
45
45
 
46
46
  View/Layouts with Formats
47
-
48
- If you define non-html formats you need to be aware of a few caveats.
49
-
50
- map.add :layout_format_example,
47
+ If you define non-html formats you need to be aware of a few caveats.
48
+ => map.add :layout_format_example,
51
49
  '/layout_format_example',
52
50
  {:controller=>'index', :action=>'layout_format_example', :status=>200, :layout=>'other', :formats=>[:json]}
53
51
 
54
- When calling the above route with json format:
55
- You will need to have a layouts/other.json.erb file along with an index/layout_format_example.json.erb file to render the view
56
-
57
- See Doozer::Controller#render for more examples on how to override this from controllers actions.
52
+ When calling the above route with json format:
53
+ => You will need to have a layouts/other.json.erb file along with an index/layout_format_example.json.erb file to render the view
54
+ => See Doozer::Controller#render for more examples on how to override this from controllers actions.
58
55
 
59
56
  Controller/View Helpers
60
57
  Route url generation is accessible in the following ways:
61
- Defauls method for generating route urls:
62
- url({:name=>:some_route ... :key=>'some value'})
58
+ Defauls method for generating route urls:
59
+ => url({:name=>:some_route ... :key=>'some value'})
63
60
  -or-
64
- Magic helper methods for generating route urls. The param order is taken right from the order of the parsed route tokens.
65
-
66
- route_name_url - default html, no params
67
- route_name_url(param1, params2) - default html, w/ params
68
- route_name_format_url(param1, params2) - non html w/ params
69
-
70
- Example:
71
- some_route_url
72
- some_route_json_url(param1, param2, param3)
61
+ => Magic helper methods for generating route urls. The param order is taken right from the order of the parsed route tokens.
62
+ route_name_url - default html, no params
63
+ route_name_url(param1, params2) - default html, w/ params
64
+ route_name_format_url(param1, params2) - non html w/ params
65
+
66
+ Example:
67
+ => some_route_url
68
+ => some_route_json_url(param1, param2, param3)
73
69
 
74
70
  In addition, you can also wrap the urls with a link tag like this:
75
- link('anchor text', route_args, link_args)
76
- Example:
77
- link('homepage', {:name=>:index}, {:class=>'link_css', :id=>'home'})
78
- -or-
79
- link('homepage', index_url, {:class=>'link_css', :id=>'home'})
71
+ => link('anchor text', route_args, link_args)
72
+ Example:
73
+ => link('homepage', {:name=>:index}, {:class=>'link_css', :id=>'home'})
74
+ -or-
75
+ => link('homepage', index_url, {:class=>'link_css', :id=>'home'})
76
+
77
+ Additional Rackup Apps
78
+ You can create additional rackup apps and assign them to a route. There are two ways to hookup rack compatible apps into the response.
80
79
 
80
+ Todo this, require the file with the rack upp here and make sure the rackup app adheres to the rack spec.
81
+ => require 'config/rack' # This file ships with the default app skeleton and is also loaded during doozer rackup.
81
82
 
82
- Not Currently Supported...
83
- Magic Routes
84
- This route automatically creates routes for all actions on controller 'something_not_called_fubar'
85
- fubar/:action :controller=>'something_not_called_fubar'
86
- This creates routes for all controller actions residing in the application.
87
- :controller/:action
83
+ 1. You can assign an application which Doozer will pass your the route after is renders the route.
88
84
 
89
- Additional Rackup Apps
90
- You can create additional rackup apps and assign them to a route
85
+ Example:
86
+ => map.add :fragel, '', {:controller=>'fragel', :action=>'munching', :status=>200, :middleware_after=>ClassName}
87
+
88
+ 2. You can bypass the Doozer controller/view by defining an application in your route definition.
91
89
 
92
- Just require the file here and then instantiate the class when you map the route.
93
- Make sure the rackup app adheres to the rack spec.
90
+ Todo this instantiate the class when you map the route.
94
91
 
95
92
  Example:
93
+ => map.add :upload, '', {:controller=>'upload', :action=>'process', :status=>200, :app=>RackupUpload.new}
96
94
 
97
- require 'lib/rackup_upload'
98
- Doozer::Routing::Routes.draw do | map |
99
- map.add :upload, '', {:controller=>'upload', :action=>'process', :status=>200, :app=>RackupUpload.new}
100
- end
95
+ Bypassing Routes and Going Straight to the Rack
96
+ => See config/rack for example on how to bypass routing and map your own rackup apps.
101
97
  """
102
98
 
103
99
  Doozer::Routing::Routes.draw do | map |
104
100
 
105
- """
106
- :name,
107
- :path w/ tokens,
108
- :options={:controller, :action, :status, :formats=>[:json, :xml, :js, etc], :app=>Class.new}
109
- """
101
+ """
102
+ :name,
103
+ :path w/ tokens,
104
+ :options={:controller, :action, :status, :formats=>[:json, :xml, :js, etc], :app=>Class.new or :middleware_after=>ClassName}
105
+ """
110
106
  map.add :index, '', {:controller=>'index', :action=>'index', :status=>200}
111
107
 
112
108
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doozer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - grippy
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-30 00:00:00 -07:00
12
+ date: 2009-11-05 00:00:00 -08:00
13
13
  default_executable: doozer
14
14
  dependencies: []
15
15
 
@@ -45,6 +45,7 @@ files:
45
45
  - lib/doozer/initializer.rb
46
46
  - lib/doozer/lib.rb
47
47
  - lib/doozer/logger.rb
48
+ - lib/doozer/middleware.rb
48
49
  - lib/doozer/orm/active_record.rb
49
50
  - lib/doozer/orm/data_mapper.rb
50
51
  - lib/doozer/orm/sequel.rb