merb 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/README +41 -2
  2. data/Rakefile +4 -2
  3. data/TODO +3 -3
  4. data/bin/merb +157 -3
  5. data/doc/rdoc/classes/Hash.html +4 -4
  6. data/doc/rdoc/classes/Merb.html +2 -12
  7. data/doc/rdoc/classes/Merb/Controller.html +347 -156
  8. data/doc/rdoc/classes/Merb/RouteMatcher.html +93 -59
  9. data/doc/rdoc/classes/MerbHandler.html +117 -107
  10. data/doc/rdoc/classes/MerbHash.html +64 -58
  11. data/doc/rdoc/classes/Noroutefound.html +16 -10
  12. data/doc/rdoc/classes/Object.html +5 -5
  13. data/doc/rdoc/classes/String.html +28 -16
  14. data/doc/rdoc/classes/Symbol.html +15 -8
  15. data/doc/rdoc/created.rid +1 -1
  16. data/doc/rdoc/files/README.html +56 -4
  17. data/doc/rdoc/files/TODO.html +4 -4
  18. data/doc/rdoc/files/lib/merb/merb_controller_rb.html +1 -1
  19. data/doc/rdoc/files/lib/merb/merb_handler_rb.html +1 -1
  20. data/doc/rdoc/files/lib/merb/merb_router_rb.html +1 -1
  21. data/doc/rdoc/files/lib/merb/merb_utils_rb.html +1 -1
  22. data/doc/rdoc/files/lib/merb_rb.html +30 -2
  23. data/doc/rdoc/files/lib/{merb_config_rb.html → merb_tasks_rb.html} +4 -4
  24. data/doc/rdoc/fr_class_index.html +0 -2
  25. data/doc/rdoc/fr_file_index.html +1 -3
  26. data/doc/rdoc/fr_method_index.html +21 -21
  27. data/examples/app_skeleton/Rakefile +81 -0
  28. data/examples/app_skeleton/dist/conf/merb_init.rb +15 -0
  29. data/examples/{skeleton → app_skeleton}/dist/conf/router.rb +5 -7
  30. data/examples/app_skeleton/scripts/merb_stop +5 -0
  31. data/examples/app_skeleton/scripts/new_migration +21 -0
  32. data/examples/{skeleton → app_skeleton}/test/test_helper.rb +0 -0
  33. data/examples/sample_app/Rakefile +81 -0
  34. data/examples/sample_app/dist/app/controllers/posts.rb +26 -10
  35. data/examples/sample_app/dist/app/models/comment.rb +3 -0
  36. data/examples/sample_app/dist/app/models/post.rb +2 -11
  37. data/examples/sample_app/dist/app/views/layout/application.rhtml +59 -4
  38. data/examples/sample_app/dist/app/views/posts/_comments.rhtml +11 -0
  39. data/examples/sample_app/dist/app/views/posts/comment.merbjs +1 -0
  40. data/examples/sample_app/dist/app/views/posts/list.rhtml +2 -4
  41. data/examples/sample_app/dist/app/views/posts/new.rhtml +2 -2
  42. data/examples/sample_app/dist/app/views/posts/show.rhtml +35 -3
  43. data/examples/sample_app/dist/conf/merb_init.rb +2 -4
  44. data/examples/sample_app/dist/conf/router.rb +3 -4
  45. data/examples/sample_app/dist/public/images/bg.jpg +0 -0
  46. data/examples/sample_app/dist/public/images/book.gif +0 -0
  47. data/examples/sample_app/dist/public/images/booksmall.gif +0 -0
  48. data/examples/sample_app/dist/public/images/greenright.jpg +0 -0
  49. data/examples/sample_app/dist/public/images/louiecon.gif +0 -0
  50. data/examples/sample_app/dist/public/images/menu.gif +0 -0
  51. data/examples/sample_app/dist/public/images/menuleft.gif +0 -0
  52. data/examples/sample_app/dist/public/images/menuright.gif +0 -0
  53. data/examples/sample_app/dist/public/images/mountain.jpg +0 -0
  54. data/examples/sample_app/dist/public/images/n3.jpg +0 -0
  55. data/examples/sample_app/dist/public/images/nautica.jpg +0 -0
  56. data/examples/sample_app/dist/public/javascripts/application.js +0 -0
  57. data/examples/sample_app/dist/public/javascripts/effects.js +975 -0
  58. data/examples/sample_app/dist/public/javascripts/prototype.js +2264 -0
  59. data/examples/sample_app/dist/public/stylesheets/merb.css +277 -0
  60. data/examples/sample_app/dist/schema/migrations/001_add_comments_to_posts.rb +22 -0
  61. data/examples/sample_app/dist/schema/schema.rb +22 -0
  62. data/examples/sample_app/log/merb.log +164394 -0
  63. data/examples/sample_app/script/merb_stop +9 -0
  64. data/examples/sample_app/script/new_migration +21 -0
  65. data/lib/merb.rb +7 -4
  66. data/lib/merb/merb_controller.rb +83 -4
  67. data/lib/merb/merb_handler.rb +20 -9
  68. data/lib/merb/merb_router.rb +18 -1
  69. data/lib/merb/merb_utils.rb +11 -1
  70. data/lib/merb_tasks.rb +7 -0
  71. data/lib/tasks/db.rake +53 -0
  72. metadata +67 -34
  73. data/doc/rdoc/classes/Merb/Config.html +0 -161
  74. data/doc/rdoc/classes/Merb/Server.html +0 -288
  75. data/doc/rdoc/files/lib/merb/merb_daemon_rb.html +0 -113
  76. data/doc/rdoc/files/lib/merb/noroutefound_rb.html +0 -101
  77. data/examples/sample_app/dist/app/views/layout/posts.rhtml +0 -6
  78. data/examples/skeleton/dist/conf/merb_init.rb +0 -21
  79. data/lib/merb/merb_daemon.rb +0 -91
  80. data/lib/merb/noroutefound.rb +0 -11
  81. data/lib/merb_config.rb +0 -21
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ require 'fileutils'
3
+ pids = IO.readlines(File.dirname(__FILE__)+"/../log/merb.pid").map{|p| p.to_i}
4
+
5
+ pids.each do |pid|
6
+ puts "killing PID: #{pid}"
7
+ Process.kill(9, pid)
8
+ end
9
+ FileUtils.rm File.dirname(__FILE__)+"/../log/merb.pid"
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require 'merb'
4
+
5
+ TMPL = <<EOF
6
+ class <%= class_name.snake_case.camel_case %> < ActiveRecord::Migration
7
+ def self.up
8
+ end
9
+
10
+ def self.down
11
+ end
12
+ end
13
+ EOF
14
+
15
+ class_name = ARGV[0]
16
+ highest_migration = Dir[Dir.pwd+'/dist/schema/migrations/*'].map{|f| File.basename(f) =~ /^(\d+)/; $1}.max
17
+ filename = format("%03d_%s", (highest_migration.to_i+1), class_name.snake_case)
18
+
19
+ File.open(Dir.pwd+"/dist/schema/migrations/#{filename}.rb", 'w+') do |file|
20
+ file.write Erubis::Eruby.new(TMPL).result(binding)
21
+ end
@@ -2,12 +2,15 @@ require 'rubygems'
2
2
  require 'mongrel'
3
3
  require 'fileutils'
4
4
  require 'erubis'
5
- require 'merb_config'
6
-
5
+ require 'logger'
7
6
 
8
7
  module Merb
9
- VERSION='0.0.4' unless defined?VERSION
8
+ VERSION='0.0.5' unless defined?VERSION
10
9
  end
11
10
 
11
+ MERB_FRAMEWORK_ROOT = File.dirname(__FILE__)
12
+ MERB_ROOT = Merb::Server.config[:merb_root] rescue Dir.pwd
13
+ DIST_ROOT = Merb::Server.config[:dist_root] rescue Dir.pwd+'/dist'
14
+ MERB_LOGGER = Logger.new("#{MERB_ROOT}/log/merb.log")
12
15
  lib = File.join(File.dirname(__FILE__), 'merb')
13
- Dir.foreach(lib) {|fn| require File.join(lib, fn) if fn =~ /\.rb$/}
16
+ Dir.entries(lib).sort.each {|fn| require File.join(lib, fn) if fn =~ /\.rb$/}
@@ -10,7 +10,10 @@ module Merb
10
10
 
11
11
  attr_accessor :status
12
12
 
13
-
13
+ # parses the http request into params, headers and cookies
14
+ # that you can use in your controller classes. Also handles
15
+ # file uploads by writing a tempfile and passing a reference
16
+ # in params.
14
17
  def initialize(req, env, args, method=(env['REQUEST_METHOD']||"GET")) #:nodoc:
15
18
  env = MerbHash[env.to_hash]
16
19
  puts env.inspect if $DEBUG
@@ -57,31 +60,50 @@ module Merb
57
60
  qs.merge!(query_parse(@in.read))
58
61
  end
59
62
  @cookies, @params = @k.dup, qs.dup.merge(args)
63
+ MERB_LOGGER.info("Params: #{params.inspect}")
60
64
  end
61
65
 
66
+ # redirect to another url It can be like /foo/bar
67
+ # for redirecting within your same app. Or it can
68
+ # be a fully qualified url to another site.
62
69
  def redirect(url)
70
+ MERB_LOGGER.info("Redirecting to: #{url}")
63
71
  @status = 302
64
72
  @headers.merge!({'Location'=> url})
65
73
  return ''
66
74
  end
67
75
 
76
+ # pass in a path to a file and this will set the
77
+ # right headers and let mongrel do its thang and
78
+ # serve the static file directly.
68
79
  def send_file(file)
69
80
  headers['X-SENDFILE'] = file
70
81
  return
71
82
  end
72
83
 
84
+ # accessor for @params. Please use params and
85
+ # never @params directly.
73
86
  def params
74
87
  @params
75
88
  end
76
89
 
90
+ # accessor for @cookies. Please use cookies and
91
+ # never @cookies directly.
77
92
  def cookies
78
93
  @cookies
79
94
  end
80
95
 
96
+ # accessor for @headers. Please use headers and
97
+ # never @headers directly.
81
98
  def headers
82
99
  @headers
83
100
  end
84
101
 
102
+ # parses a query string or the payload of a POST
103
+ # request into the params hash. So for example:
104
+ # /foo?bar=nik&post[title]=heya&post[body]=whatever
105
+ # parses into:
106
+ # {:bar => 'nik', :post => {:title => 'heya', :body => 'whatever}}
85
107
  def query_parse(qs, d = '&;')
86
108
  m = proc {|_,o,n|o.update(n,&m)rescue([*o]<<n)}
87
109
  (qs||'').split(/[#{d}] */n).inject(MerbHash[]) { |h,p|
@@ -91,34 +113,75 @@ module Merb
91
113
  }
92
114
  end
93
115
 
116
+ # does url escaping
94
117
  def escape(s)
95
118
  Mongrel::HttpRequest.escape(s)
96
119
  end
97
120
 
121
+ # does url unescaping
98
122
  def unescape(s)
99
123
  Mongrel::HttpRequest.unescape(s)
100
124
  end
101
125
 
102
-
126
+ # escape text for javascript.
127
+ def escape_js(javascript)
128
+ (javascript || '').gsub('\\','\0\0').gsub(/\r\n|\n|\r/, "\\n").gsub(/["']/) { |m| "\\#{m}" }
129
+ end
130
+ alias :js :escape_js
131
+
132
+ # shortcut to a template path based on name.
103
133
  def template_dir(loc)
104
134
  File.expand_path(Merb::Server.config[:merb_root] + "/dist/app/views/#{loc}")
105
135
  end
106
136
 
137
+ # returns the current method name. Used for
138
+ # auto discovery of which template to render
139
+ # based on the action name.
107
140
  def current_method_name(depth=0)
108
141
  caller[depth] =~ /`(.*)'$/; $1
109
142
  end
110
143
 
144
+ # does a render with no layout. Also sets the
145
+ # content type header to text/javascript and
146
+ # escapes the template for javascript eval on
147
+ # the client
148
+ def render_js(template=current_method_name(1), b=binding)
149
+ headers['Content-Type'] = "text/javascript"
150
+ template = Erubis::Eruby.new(IO.read( template_dir(self.class.name.snake_case) + "/#{template}.merbjs" ))
151
+ template.result(b)
152
+ end
111
153
 
154
+ # set the @layout. Use this right before a render to
155
+ # set the name of the layout to use minus the .rhtml
112
156
  def layout(l)
113
157
  @layout = l
114
158
  end
115
159
 
160
+ def render_nothing(status)
161
+ @status = status
162
+ return ''
163
+ end
164
+
165
+ # renders the action without wrapping it in a layout.
116
166
  def render_no_layout(template=current_method_name(1), b=binding)
117
167
  template = Erubis::Eruby.new( IO.read( template_dir(self.class.name.snake_case) + "/#{template}.rhtml" ) )
118
168
  template.result(b)
119
- end
169
+ end
170
+
171
+ def partial(template)
172
+ template = Erubis::Eruby.new( IO.read( template_dir(self.class.name.snake_case) + "/_#{template}.rhtml" ) )
173
+ template.result(binding)
174
+ end
120
175
 
176
+ # renders a template based on the current action name
177
+ # you can pass the name of a template if you want to
178
+ # render a template with a different name then then
179
+ # current action name. Wraps the rendered template in
180
+ # the layout. Uses layout/application.rhtml unless
181
+ # there is a layout named after the current controller
182
+ # or @layout has been set to another value.
121
183
  def render(template=current_method_name(1), b=binding)
184
+ MERB_LOGGER.info("Rendering template: #{template_dir(template)}")
122
185
  name = self.class.name.snake_case
123
186
  template = Erubis::Eruby.new( IO.read( template_dir(name) + "/#{template}.rhtml" ) )
124
187
  layout_content = template.result(b)
@@ -132,12 +195,28 @@ module Merb
132
195
  else
133
196
  layout = @layout.to_s
134
197
  end
198
+ MERB_LOGGER.info("With Layout: #{template_dir('layout')}/#{layout}.rhtml")
135
199
  @layout_content = layout_content
136
200
  layout_tmpl = Erubis::Eruby.new( IO.read( template_dir('layout') + "/#{layout}.rhtml" ) )
137
201
  layout_tmpl.result(b)
138
202
  end
139
203
 
140
-
141
204
  end
142
205
 
206
+ end
207
+
208
+ class Noroutefound < Merb::Controller
209
+ # This is the class that handles requests that don't
210
+ # match any defined routes.
211
+
212
+ def method_missing(sym, *args, &blk)
213
+ @status = 404
214
+ "<html><body><h1>No Matching Route</h1></body></html>"
215
+ end
216
+
217
+ def to_s
218
+ @status = 404
219
+ "<html><body><h1>No Matching Route s</h1></body></html>"
220
+ end
221
+
143
222
  end
@@ -4,7 +4,7 @@ class MerbHandler < Mongrel::HttpHandler
4
4
 
5
5
  # take the name of a directory and use that as the doc root or public
6
6
  # directory of your site. This is set to the root of your merb app + '/public'
7
- # by default. See merb_daemon.rb if you want to change this.
7
+ # by default.
8
8
  def initialize(dir, opts = {})
9
9
  @files = Mongrel::DirHandler.new(dir,false)
10
10
  @guard = Sync.new
@@ -29,6 +29,8 @@ class MerbHandler < Mongrel::HttpHandler
29
29
  return
30
30
  end
31
31
 
32
+ MERB_LOGGER.info("Request: PATH_INFO: #{request.params[Mongrel::Const::PATH_INFO]}")
33
+
32
34
  # Rails style page caching. Check the public dir first for
33
35
  # .html pages and serve directly. Otherwise fall back to Merb
34
36
  # routing and request dispatching.
@@ -38,9 +40,12 @@ class MerbHandler < Mongrel::HttpHandler
38
40
 
39
41
  if get_or_head and @files.can_serve(path_info)
40
42
  # File exists as-is so serve it up
43
+ MERB_LOGGER.info("Serving static file: #{path_info}")
44
+
41
45
  @files.process(request,response)
42
46
  elsif get_or_head and @files.can_serve(page_cached)
43
47
  # Possible cached page, serve it up
48
+ MERB_LOGGER.info("Serving static file: #{path_info}")
44
49
  request.params[Mongrel::Const::PATH_INFO] = page_cached
45
50
  @files.process(request,response)
46
51
  else
@@ -49,12 +54,13 @@ class MerbHandler < Mongrel::HttpHandler
49
54
  # params and is outside of the synchronize call so that
50
55
  # multiple file uploads can be done at once.
51
56
  controller, action = handle(request)
52
- p controller, action
57
+ MERB_LOGGER.info("Routing to controller: #{controller.class} action: #{action}")
53
58
  output = nil
54
59
  # synchronize here because this is where ActiveRecord or your db
55
60
  # calls will be run in your controller methods.
56
61
  @guard.synchronize(:EX) {
57
- output = if (controller && controller.kind_of?(Merb::Controller))
62
+ output =
63
+ if (controller && controller.kind_of?(Merb::Controller))
58
64
  if action
59
65
  controller.send(action)
60
66
  else
@@ -67,7 +73,8 @@ class MerbHandler < Mongrel::HttpHandler
67
73
  rescue Exception => e
68
74
  response.start(500) do |head,out|
69
75
  head["Content-Type"] = "text/html"
70
- out << exception(e)
76
+ MERB_LOGGER.info(ex = exception(e))
77
+ out << ex
71
78
  end
72
79
  return
73
80
  end
@@ -89,12 +96,16 @@ class MerbHandler < Mongrel::HttpHandler
89
96
  end
90
97
  end
91
98
 
99
+ controller = nil
100
+
92
101
  if sendfile
102
+ MERB_LOGGER.info("X-SENDFILE: #{sendfile}")
93
103
  # send X-SENDFILE header to mongrel
94
104
  response.send_status(File.size(sendfile))
95
105
  response.send_header
96
106
  response.send_file(sendfile)
97
107
  else
108
+ MERB_LOGGER.info("Response status: #{response.status}\n\n")
98
109
  # render response from successful controller
99
110
  response.send_status(output.length)
100
111
  response.send_header
@@ -107,17 +118,17 @@ class MerbHandler < Mongrel::HttpHandler
107
118
  # and use that in the merb routematcher to determine
108
119
  # which controller and method to run.
109
120
  # returns a 2 element tuple of:
110
- # [controller_object, method]
121
+ # [controller, action]
111
122
  def handle(request)
112
123
  path = request.params[Mongrel::Const::PATH_INFO].sub(/\/+/, '/')
113
124
  path = path[0..-2] if (path[-1] == ?/)
114
125
  route = Merb::RouteMatcher.new.route_request(path)
115
- puts route.inspect if $DEBUG
116
126
  if route
117
- [ instantiate_controller(route[:controller], request.body, request.params,
118
- route.dup.delete_if{|k,v| [:controller, :action].include? k}),
119
- route[:action]]
127
+ MERB_LOGGER.info("No Matching Route!") if route[:controller] == 'Noroutefound'
128
+ [ instantiate_controller(route[:controller], request.body, request.params, route),
129
+ route[:action] ]
120
130
  else
131
+ MERB_LOGGER.info("No Matching Route!")
121
132
  ["<html><body>Error: no route matches!</body></html>", nil]
122
133
  end
123
134
  end
@@ -13,8 +13,10 @@ module Merb
13
13
  class RouteMatcher
14
14
 
15
15
  attr_accessor :sections
16
- @@section_regexp = /(?::([a-z*]+))/.freeze
16
+ @@section_regexp = /(?::([a-z*_]+))/.freeze
17
17
 
18
+ # setup the router and yield it out to
19
+ # add routes to it. Then compile all routes
18
20
  def self.prepare
19
21
  @@routes = Array.new
20
22
  @@compiled_statement = String.new
@@ -22,22 +24,31 @@ module Merb
22
24
  compile_router
23
25
  end
24
26
 
27
+ # init @sections for route segment recognition
25
28
  def initialize
26
29
  @sections = Hash.new
27
30
  end
28
31
 
32
+ # all defined routes in their raw form.
29
33
  def routes
30
34
  @@routes
31
35
  end
32
36
 
37
+ # the final compiled lambda that gets used
38
+ # as the body of the route_request method.
33
39
  def compiled_statement
34
40
  @@compiled_statement
35
41
  end
36
42
 
43
+ # add a route to be compiled
37
44
  def self.add(*route)
38
45
  @@routes << [route[0], (route[1] || {})]
39
46
  end
40
47
 
48
+ # build up a string that defines a lambda
49
+ # that does a case statement on the PATH_INFO
50
+ # against each of the compiled routes in turn.
51
+ # first route that matches wins.
41
52
  def self.compile_router
42
53
  router_lambda = @@routes.inject("lambda{|path| \n case path\n") { |m,r|
43
54
  m << compile(r)
@@ -46,6 +57,12 @@ module Merb
46
57
  define_method(:route_request, &eval(router_lambda))
47
58
  end
48
59
 
60
+ # compile each individual route into a when /.../
61
+ # component of the case statement. Takes /:sections
62
+ # if the route def that start with : and turns them
63
+ # into placeholders for whatever urls match against
64
+ # the route in question. Special case for the default
65
+ # /:controller/:action/:id route.
49
66
  def self.compile(route)
50
67
  raise ArgumentError unless String === route[0]
51
68
  if route[0] == '/:controller/:action/:id'
@@ -1,14 +1,19 @@
1
1
  class String
2
+
3
+ # reloads controller classes on each request if
4
+ # :allow_reloading is set to true in the config
5
+ # file or command line options.
2
6
  def import
3
7
  Merb::Server.config[:allow_reloading] ? load( self.snake_case + '.rb' ) : require( self.snake_case )
4
8
  end
5
9
 
10
+ # "FooBar".snake_case #=> "foo_bar"
6
11
  def snake_case
7
12
  return self unless self =~ %r/[A-Z]/
8
13
  self.reverse.scan(%r/[A-Z]+|[^A-Z]*[A-Z]+?/).reverse.map{|word| word.reverse.downcase}.join '_'
9
14
  end
10
15
 
11
-
16
+ # "foo_bar".camel_case #=> "FooBar"
12
17
  def camel_case
13
18
  return self if self =~ %r/[A-Z]/ and self !~ %r/_/
14
19
  words = self.strip.split %r/\s*_+\s*/
@@ -19,9 +24,13 @@ class String
19
24
  end
20
25
 
21
26
  class Symbol
27
+
28
+ # faster Symbol#to_s to speed up routing.
22
29
  def to_s
23
30
  @str_rep || (@str_rep = id2name.freeze)
24
31
  end
32
+
33
+ # ["foo", "bar"].map &:reverse #=> ['oof', 'rab']
25
34
  def to_proc
26
35
  Proc.new{|*args| args.shift.__send__(self, *args)}
27
36
  end
@@ -40,6 +49,7 @@ class Hash
40
49
  end
41
50
  end
42
51
 
52
+ # like HashWithIndifferentAccess from ActiveSupport.
43
53
  class MerbHash < Hash
44
54
  def initialize(constructor = {})
45
55
  if constructor.is_a?(Hash)
@@ -0,0 +1,7 @@
1
+ $VERBOSE = nil
2
+
3
+ # Load Merb rakefile extensions
4
+ Dir["#{File.dirname(__FILE__)}/tasks/**/*.rake"].each { |ext| load ext }
5
+
6
+ # Load any custom rakefile extensions
7
+ Dir["./lib/tasks/**/*.rake"].sort.each { |ext| load ext }
@@ -0,0 +1,53 @@
1
+ taMERB_ROOT = Dir.pwd
2
+
3
+ desc "Setup the Merb Environment by requiring merb and loading your merb_init.rb"
4
+ task :merb_env do
5
+ require 'rubygems'
6
+ require 'merb'
7
+ load MERB_ROOT+'/dist/conf/merb_init.rb'
8
+ end
9
+
10
+ namespace :db do
11
+ desc "Migrate the database through scripts in dist/schema/migrate. Target specific version with VERSION=x"
12
+ task :migrate => :merb_env do
13
+ ActiveRecord::Migrator.migrate("dist/schema/migrations/", ENV["VERSION"] ? ENV["VERSION"].to_i : nil)
14
+ Rake::Task["db:schema:dump"].invoke
15
+ end
16
+
17
+ namespace :schema do
18
+ desc "Create a db/schema.rb file that can be portably used against any DB supported by AR"
19
+ task :dump => :merb_env do
20
+ require 'active_record/schema_dumper'
21
+ File.open(ENV['SCHEMA'] || "dist/schema/schema.rb", "w") do |file|
22
+ ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, file)
23
+ end
24
+ end
25
+
26
+ desc "Load a schema.rb file into the database"
27
+ task :load => :merb_env do
28
+ file = ENV['SCHEMA'] || "dist/schema/schema.rb"
29
+ load(file)
30
+ end
31
+ end
32
+
33
+ namespace :sessions do
34
+ desc "Creates a sessions table for use with CGI::Session::ActiveRecordStore"
35
+ task :create => :merb_env do
36
+ raise "Task unavailable to this database (no migration support)" unless ActiveRecord::Base.connection.supports_migrations?
37
+ require 'rails_generator'
38
+ require 'rails_generator/scripts/generate'
39
+ Rails::Generator::Scripts::Generate.new.run(["session_migration", ENV["MIGRATION"] || "AddSessions"])
40
+ end
41
+
42
+ desc "Clear the sessions table"
43
+ task :clear => :merb_env do
44
+ session_table = 'session'
45
+ session_table = Inflector.pluralize(session_table) if ActiveRecord::Base.pluralize_table_names
46
+ ActiveRecord::Base.connection.execute "DELETE FROM #{session_table}"
47
+ end
48
+ end
49
+ end
50
+
51
+ def session_table_name
52
+ ActiveRecord::Base.pluralize_table_names ? :sessions : :session
53
+ end