doozer 0.3.1 → 0.4.0

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