freels-mongrel 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. data/CHANGELOG +12 -0
  2. data/COPYING +55 -0
  3. data/LICENSE +55 -0
  4. data/Manifest +70 -0
  5. data/README +74 -0
  6. data/Rakefile +237 -0
  7. data/TODO +4 -0
  8. data/bin/mongrel_rails +284 -0
  9. data/examples/builder.rb +29 -0
  10. data/examples/camping/README +3 -0
  11. data/examples/camping/blog.rb +294 -0
  12. data/examples/camping/tepee.rb +149 -0
  13. data/examples/httpd.conf +474 -0
  14. data/examples/mime.yaml +3 -0
  15. data/examples/mongrel.conf +9 -0
  16. data/examples/mongrel_simple_ctrl.rb +92 -0
  17. data/examples/mongrel_simple_service.rb +116 -0
  18. data/examples/monitrc +57 -0
  19. data/examples/random_thrash.rb +19 -0
  20. data/examples/simpletest.rb +52 -0
  21. data/examples/webrick_compare.rb +20 -0
  22. data/ext/http11/ext_help.h +15 -0
  23. data/ext/http11/extconf.rb +6 -0
  24. data/ext/http11/http11.c +527 -0
  25. data/ext/http11/http11_parser.c +1216 -0
  26. data/ext/http11/http11_parser.h +49 -0
  27. data/ext/http11/http11_parser.java.rl +171 -0
  28. data/ext/http11/http11_parser.rl +165 -0
  29. data/ext/http11/http11_parser_common.rl +55 -0
  30. data/ext/http11_java/Http11Service.java +13 -0
  31. data/ext/http11_java/org/jruby/mongrel/Http11.java +266 -0
  32. data/ext/http11_java/org/jruby/mongrel/Http11Parser.java +572 -0
  33. data/lib/mongrel.rb +359 -0
  34. data/lib/mongrel/camping.rb +107 -0
  35. data/lib/mongrel/cgi.rb +182 -0
  36. data/lib/mongrel/command.rb +220 -0
  37. data/lib/mongrel/configurator.rb +389 -0
  38. data/lib/mongrel/const.rb +114 -0
  39. data/lib/mongrel/debug.rb +203 -0
  40. data/lib/mongrel/gems.rb +22 -0
  41. data/lib/mongrel/handlers.rb +472 -0
  42. data/lib/mongrel/header_out.rb +28 -0
  43. data/lib/mongrel/http_request.rb +155 -0
  44. data/lib/mongrel/http_response.rb +163 -0
  45. data/lib/mongrel/init.rb +10 -0
  46. data/lib/mongrel/logger.rb +74 -0
  47. data/lib/mongrel/mime_types.yml +616 -0
  48. data/lib/mongrel/rails.rb +185 -0
  49. data/lib/mongrel/stats.rb +89 -0
  50. data/lib/mongrel/tcphack.rb +18 -0
  51. data/lib/mongrel/uri_classifier.rb +76 -0
  52. data/mongrel-public_cert.pem +20 -0
  53. data/mongrel.gemspec +47 -0
  54. data/setup.rb +1585 -0
  55. data/test/mime.yaml +3 -0
  56. data/test/mongrel.conf +1 -0
  57. data/test/test_cgi_wrapper.rb +26 -0
  58. data/test/test_command.rb +86 -0
  59. data/test/test_conditional.rb +107 -0
  60. data/test/test_configurator.rb +88 -0
  61. data/test/test_debug.rb +25 -0
  62. data/test/test_handlers.rb +104 -0
  63. data/test/test_http11.rb +272 -0
  64. data/test/test_redirect_handler.rb +44 -0
  65. data/test/test_request_progress.rb +100 -0
  66. data/test/test_response.rb +127 -0
  67. data/test/test_stats.rb +35 -0
  68. data/test/test_uriclassifier.rb +261 -0
  69. data/test/test_ws.rb +116 -0
  70. data/test/testhelp.rb +74 -0
  71. data/tools/trickletest.rb +45 -0
  72. metadata +202 -0
data/TODO ADDED
@@ -0,0 +1,4 @@
1
+
2
+ * Rewrite and merge mongrel cluster and mongrel_rails into something small and maintainable.
3
+ * Initial 1.9 compatibility.
4
+ * 1.9 performance (requires removing the thread queue).
@@ -0,0 +1,284 @@
1
+ # Copyright (c) 2005 Zed A. Shaw
2
+ # You can redistribute it and/or modify it under the same terms as Ruby.
3
+ #
4
+ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html
5
+ # for more information.
6
+
7
+ require 'yaml'
8
+ require 'etc'
9
+
10
+ $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib"
11
+ require 'mongrel'
12
+ require 'mongrel/rails'
13
+
14
+ Mongrel::Gems.require 'gem_plugin'
15
+
16
+ # require 'ruby-debug'
17
+ # Debugger.start
18
+
19
+ module Mongrel
20
+ class Start < GemPlugin::Plugin "/commands"
21
+ include Mongrel::Command::Base
22
+
23
+ def configure
24
+ options [
25
+ ["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"],
26
+ ["-d", "--daemonize", "Run daemonized in the background", :@daemon, false],
27
+ ['-p', '--port PORT', "Which port to bind to", :@port, 3000],
28
+ ['-a', '--address ADDR', "Address to bind to", :@address, "0.0.0.0"],
29
+ ['-l', '--log FILE', "Where to write log messages", :@log_file, "log/mongrel.log"],
30
+ ['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"],
31
+ ['-n', '--num-procs INT', "Number of processors active before clients denied", :@num_processors, 1024],
32
+ ['-o', '--timeout TIME', "Time to wait (in seconds) before killing a stalled thread", :@timeout, 60],
33
+ ['-t', '--throttle TIME', "Time to pause (in hundredths of a second) between accepting clients", :@throttle, 0],
34
+ ['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil],
35
+ ['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd],
36
+ ['-r', '--root PATH', "Set the document root (default 'public')", :@docroot, "public"],
37
+ ['-B', '--debug', "Enable debugging mode", :@debug, false],
38
+ ['-C', '--config PATH', "Use a config file", :@config_file, nil],
39
+ ['-S', '--script PATH', "Load the given file as an extra config script", :@config_script, nil],
40
+ ['-G', '--generate PATH', "Generate a config file for use with -C", :@generate, nil],
41
+ ['', '--user USER', "User to run as", :@user, nil],
42
+ ['', '--group GROUP', "Group to run as", :@group, nil],
43
+ ['', '--prefix PATH', "URL prefix for Rails app", :@prefix, nil]
44
+ ]
45
+ end
46
+
47
+ def validate
48
+ if @config_file
49
+ valid_exists?(@config_file, "Config file not there: #@config_file")
50
+ return false unless @valid
51
+ @config_file = File.expand_path(@config_file)
52
+ load_config
53
+ return false unless @valid
54
+ end
55
+
56
+ @cwd = File.expand_path(@cwd)
57
+ valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
58
+
59
+ # Change there to start, then we'll have to come back after daemonize
60
+ Dir.chdir(@cwd)
61
+
62
+ valid?(@prefix[0] == ?/ && @prefix[-1] != ?/, "Prefix must begin with / and not end in /") if @prefix
63
+ valid_dir? File.dirname(@log_file), "Path to log file not valid: #@log_file"
64
+ valid_dir? File.dirname(@pid_file), "Path to pid file not valid: #@pid_file"
65
+ valid_dir? @docroot, "Path to docroot not valid: #@docroot"
66
+ valid_exists? @mime_map, "MIME mapping file does not exist: #@mime_map" if @mime_map
67
+ valid_exists? @config_file, "Config file not there: #@config_file" if @config_file
68
+ valid_dir? File.dirname(@generate), "Problem accessing directory to #@generate" if @generate
69
+ valid_user? @user if @user
70
+ valid_group? @group if @group
71
+
72
+ return @valid
73
+ end
74
+
75
+ def run
76
+ if @generate
77
+ @generate = File.expand_path(@generate)
78
+ Mongrel.log(:error, "** Writing config to \"#@generate\".")
79
+ open(@generate, "w") {|f| f.write(settings.to_yaml) }
80
+ Mongrel.log(:error, "** Finished. Run \"mongrel_rails start -C #@generate\" to use the config file.")
81
+ exit 0
82
+ end
83
+
84
+ config = Mongrel::Rails::RailsConfigurator.new(settings) do
85
+ if defaults[:daemon]
86
+ if File.exist? defaults[:pid_file]
87
+ Mongrel.log(:error, "!!! PID file #{defaults[:pid_file]} already exists. Mongrel could be running already. Check your #{defaults[:log_file]} for errors.")
88
+ Mongrel.log(:error, "!!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start.")
89
+ exit 1
90
+ end
91
+
92
+ daemonize
93
+ write_pid_file
94
+ Mongrel.log("Daemonized, any open files are closed. Look at #{defaults[:pid_file]} and #{defaults[:log_file]} for info.")
95
+ Mongrel.log("Settings loaded from #{@config_file} (they override command line).") if @config_file
96
+ end
97
+
98
+ Mongrel.log("Starting Mongrel listening at #{defaults[:host]}:#{defaults[:port]}, further information can be found in log/mongrel-#{defaults[:host]}-#{defaults[:port]}.log")
99
+
100
+ listener do
101
+ mime = {}
102
+ if defaults[:mime_map]
103
+ Mongrel.log("Loading additional MIME types from #{defaults[:mime_map]}")
104
+ mime = load_mime_map(defaults[:mime_map], mime)
105
+ end
106
+
107
+ if defaults[:debug]
108
+ Mongrel.log("Installing debugging prefixed filters. Look in log/mongrel_debug for the files.")
109
+ debug "/"
110
+ end
111
+
112
+ Mongrel.log("Starting Rails with #{defaults[:environment]} environment...")
113
+ Mongrel.log("Mounting Rails at #{defaults[:prefix]}...") if defaults[:prefix]
114
+ uri defaults[:prefix] || "/", :handler => rails(:mime => mime, :prefix => defaults[:prefix])
115
+ Mongrel.log("Rails loaded.")
116
+
117
+ Mongrel.log("Loading any Rails specific GemPlugins" )
118
+ load_plugins
119
+
120
+ if defaults[:config_script]
121
+ Mongrel.log("Loading #{defaults[:config_script]} external config script")
122
+ run_config(defaults[:config_script])
123
+ end
124
+
125
+ setup_rails_signals
126
+ end
127
+ end
128
+
129
+ config.run
130
+ Mongrel.log("Mongrel #{Mongrel::Const::MONGREL_VERSION} available at #{@address}:#{@port}")
131
+
132
+ unless config.defaults[:daemon]
133
+ Mongrel.log("Use CTRL-C to stop.")
134
+ end
135
+
136
+ config.join
137
+
138
+ if config.needs_restart
139
+ unless RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw/
140
+ cmd = "ruby #{__FILE__} start #{original_args.join(' ')}"
141
+ Mongrel.log("Restarting with arguments: #{cmd}")
142
+ config.stop(false, true)
143
+ config.remove_pid_file
144
+
145
+ if config.defaults[:daemon]
146
+ system cmd
147
+ else
148
+ Mongrel.log(:error, "Can't restart unless in daemon mode.")
149
+ exit 1
150
+ end
151
+ else
152
+ Mongrel.log("Win32 does not support restarts. Exiting.")
153
+ end
154
+ end
155
+ end
156
+
157
+ def load_config
158
+ settings = {}
159
+ begin
160
+ settings = YAML.load_file(@config_file)
161
+ ensure
162
+ Mongrel.log(:error, "** Loading settings from #{@config_file} (they override command line).") unless @daemon || settings[:daemon]
163
+ end
164
+
165
+ settings[:includes] ||= ["mongrel"]
166
+
167
+ # Config file settings will override command line settings
168
+ settings.each do |key, value|
169
+ key = key.to_s
170
+ if config_keys.include?(key)
171
+ key = 'address' if key == 'host'
172
+ key = 'num_processors' if key == 'num_procs'
173
+ self.instance_variable_set("@#{key}", value)
174
+ else
175
+ failure "Unknown configuration setting: #{key}"
176
+ @valid = false
177
+ end
178
+ end
179
+ end
180
+
181
+ def config_keys
182
+ @config_keys ||=
183
+ %w(address host port cwd log_file pid_file environment docroot mime_map daemon debug includes config_script num_processors num_procs timeout throttle user group prefix)
184
+ end
185
+
186
+ def settings
187
+ config_keys.inject({}) do |hash, key|
188
+ value = self.instance_variable_get("@#{key}")
189
+ key = 'host' if key == 'address'
190
+ key = 'num_processors' if key == 'num_procs'
191
+ hash[key.to_sym] ||= value
192
+ hash
193
+ end
194
+ end
195
+ end
196
+
197
+ def Mongrel::send_signal(signal, pid_file)
198
+ pid = open(pid_file).read.to_i
199
+ print "Sending #{signal} to Mongrel at PID #{pid}..."
200
+ begin
201
+ Process.kill(signal, pid)
202
+ rescue Errno::ESRCH
203
+ puts "Process does not exist. Not running."
204
+ end
205
+
206
+ puts "Done."
207
+ end
208
+
209
+
210
+ class Stop < GemPlugin::Plugin "/commands"
211
+ include Mongrel::Command::Base
212
+
213
+ def configure
214
+ options [
215
+ ['-c', '--chdir PATH', "Change to dir before starting (will be expanded).", :@cwd, "."],
216
+ ['-f', '--force', "Force the shutdown (kill -9).", :@force, false],
217
+ ['-w', '--wait SECONDS', "Wait SECONDS before forcing shutdown", :@wait, "0"],
218
+ ['-P', '--pid FILE', "Where the PID file is located.", :@pid_file, "log/mongrel.pid"]
219
+ ]
220
+ end
221
+
222
+ def validate
223
+ @cwd = File.expand_path(@cwd)
224
+ valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
225
+
226
+ Dir.chdir @cwd
227
+
228
+ valid_exists? @pid_file, "PID file #@pid_file does not exist. Not running?"
229
+ return @valid
230
+ end
231
+
232
+ def run
233
+ if @force
234
+ @wait.to_i.times do |waiting|
235
+ exit(0) if not File.exist? @pid_file
236
+ sleep 1
237
+ end
238
+
239
+ Mongrel::send_signal("KILL", @pid_file) if File.exist? @pid_file
240
+ else
241
+ Mongrel::send_signal("TERM", @pid_file)
242
+ end
243
+ end
244
+ end
245
+
246
+
247
+ class Restart < GemPlugin::Plugin "/commands"
248
+ include Mongrel::Command::Base
249
+
250
+ def configure
251
+ options [
252
+ ['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, '.'],
253
+ ['-s', '--soft', "Do a soft restart rather than a process exit restart", :@soft, false],
254
+ ['-P', '--pid FILE', "Where the PID file is located", :@pid_file, "log/mongrel.pid"]
255
+ ]
256
+ end
257
+
258
+ def validate
259
+ @cwd = File.expand_path(@cwd)
260
+ valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd"
261
+
262
+ Dir.chdir @cwd
263
+
264
+ valid_exists? @pid_file, "PID file #@pid_file does not exist. Not running?"
265
+ return @valid
266
+ end
267
+
268
+ def run
269
+ if @soft
270
+ Mongrel::send_signal("HUP", @pid_file)
271
+ else
272
+ Mongrel::send_signal("USR2", @pid_file)
273
+ end
274
+ end
275
+ end
276
+ end
277
+
278
+
279
+ GemPlugin::Manager.instance.load "mongrel" => GemPlugin::INCLUDE, "rails" => GemPlugin::EXCLUDE
280
+
281
+
282
+ if not Mongrel::Command::Registry.instance.run ARGV
283
+ exit 1
284
+ end
@@ -0,0 +1,29 @@
1
+ require 'mongrel'
2
+
3
+ class TestPlugin < GemPlugin::Plugin "/handlers"
4
+ include Mongrel::HttpHandlerPlugin
5
+
6
+ def process(request, response)
7
+ Mongrel.log(:error, "My options are: #{options.inspect}")
8
+ Mongrel.log(:error, "Request Was:")
9
+ Mongrel.log(:error, request.params.to_yaml)
10
+ end
11
+ end
12
+
13
+ config = Mongrel::Configurator.new :host => "127.0.0.1" do
14
+ load_plugins :includes => ["mongrel"], :excludes => ["rails"]
15
+ daemonize :cwd => Dir.pwd, :log_file => "mongrel.log", :pid_file => "mongrel.pid"
16
+
17
+ listener :port => 3000 do
18
+ uri "/app", :handler => plugin("/handlers/testplugin", :test => "that")
19
+ uri "/app", :handler => Mongrel::DirHandler.new(".")
20
+ load_plugins :includes => ["mongrel", "rails"]
21
+ end
22
+
23
+ trap("INT") { stop }
24
+ run
25
+ end
26
+
27
+ config.join
28
+
29
+
@@ -0,0 +1,3 @@
1
+ To get these examples running, install Camping.
2
+
3
+ Instructions here: http://code.whytheluckystiff.net/camping/
@@ -0,0 +1,294 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.dirname(__FILE__) + "/../../lib"
4
+ require 'rubygems'
5
+ require_gem 'camping', '>=1.4'
6
+ require 'camping/session'
7
+
8
+ Camping.goes :Blog
9
+
10
+ module Blog
11
+ include Camping::Session
12
+ end
13
+
14
+ module Blog::Models
15
+ def self.schema(&block)
16
+ @@schema = block if block_given?
17
+ @@schema
18
+ end
19
+
20
+ class Post < Base; belongs_to :user; end
21
+ class Comment < Base; belongs_to :user; end
22
+ class User < Base; end
23
+ end
24
+
25
+ Blog::Models.schema do
26
+ create_table :blog_posts, :force => true do |t|
27
+ t.column :id, :integer, :null => false
28
+ t.column :user_id, :integer, :null => false
29
+ t.column :title, :string, :limit => 255
30
+ t.column :body, :text
31
+ end
32
+ create_table :blog_users, :force => true do |t|
33
+ t.column :id, :integer, :null => false
34
+ t.column :username, :string
35
+ t.column :password, :string
36
+ end
37
+ create_table :blog_comments, :force => true do |t|
38
+ t.column :id, :integer, :null => false
39
+ t.column :post_id, :integer, :null => false
40
+ t.column :username, :string
41
+ t.column :body, :text
42
+ end
43
+ execute "INSERT INTO blog_users (username, password) VALUES ('admin', 'camping')"
44
+ end
45
+
46
+ module Blog::Controllers
47
+ class Index < R '/'
48
+ def get
49
+ @posts = Post.find :all
50
+ render :index
51
+ end
52
+ end
53
+
54
+ class Add
55
+ def get
56
+ unless @state.user_id.blank?
57
+ @user = User.find @state.user_id
58
+ @post = Post.new
59
+ end
60
+ render :add
61
+ end
62
+ def post
63
+ post = Post.create :title => input.post_title, :body => input.post_body,
64
+ :user_id => @state.user_id
65
+ redirect View, post
66
+ end
67
+ end
68
+
69
+ class Info < R '/info/(\d+)', '/info/(\w+)/(\d+)', '/info', '/info/(\d+)/(\d+)/(\d+)/([\w-]+)'
70
+ def get(*args)
71
+ div do
72
+ code args.inspect; br; br
73
+ code ENV.inspect; br
74
+ code "Link: #{R(Info, 1, 2)}"
75
+ end
76
+ end
77
+ end
78
+
79
+ class View < R '/view/(\d+)'
80
+ def get post_id
81
+ @post = Post.find post_id
82
+ @comments = Models::Comment.find :all, :conditions => ['post_id = ?', post_id]
83
+ render :view
84
+ end
85
+ end
86
+
87
+ class Edit < R '/edit/(\d+)', '/edit'
88
+ def get post_id
89
+ unless @state.user_id.blank?
90
+ @user = User.find @state.user_id
91
+ end
92
+ @post = Post.find post_id
93
+ render :edit
94
+ end
95
+
96
+ def post
97
+ @post = Post.find input.post_id
98
+ @post.update_attributes :title => input.post_title, :body => input.post_body
99
+ redirect View, @post
100
+ end
101
+ end
102
+
103
+ class Comment
104
+ def post
105
+ Models::Comment.create(:username => input.post_username,
106
+ :body => input.post_body, :post_id => input.post_id)
107
+ redirect View, input.post_id
108
+ end
109
+ end
110
+
111
+ class Login
112
+ def post
113
+ @user = User.find :first, :conditions => ['username = ? AND password = ?', input.username, input.password]
114
+
115
+ if @user
116
+ @login = 'login success !'
117
+ @state.user_id = @user.id
118
+ else
119
+ @login = 'wrong user name or password'
120
+ end
121
+ render :login
122
+ end
123
+ end
124
+
125
+ class Logout
126
+ def get
127
+ @state.user_id = nil
128
+ render :logout
129
+ end
130
+ end
131
+
132
+ class Style < R '/styles.css'
133
+ def get
134
+ @headers["Content-Type"] = "text/css; charset=utf-8"
135
+ @body = %{
136
+ body {
137
+ font-family: Utopia, Georga, serif;
138
+ }
139
+ h1.header {
140
+ background-color: #fef;
141
+ margin: 0; padding: 10px;
142
+ }
143
+ div.content {
144
+ padding: 10px;
145
+ }
146
+ }
147
+ end
148
+ end
149
+ end
150
+
151
+ module Blog::Views
152
+
153
+ def layout
154
+ html do
155
+ head do
156
+ title 'blog'
157
+ link :rel => 'stylesheet', :type => 'text/css',
158
+ :href => '/styles.css', :media => 'screen'
159
+ end
160
+ body do
161
+ h1.header { a 'blog', :href => R(Index) }
162
+ div.content do
163
+ self << yield
164
+ end
165
+ end
166
+ end
167
+ end
168
+
169
+ def index
170
+ if @posts.empty?
171
+ p 'No posts found.'
172
+ p { a 'Add', :href => R(Add) }
173
+ else
174
+ for post in @posts
175
+ _post(post)
176
+ end
177
+ end
178
+ end
179
+
180
+ def login
181
+ p { b @login }
182
+ p { a 'Continue', :href => R(Add) }
183
+ end
184
+
185
+ def logout
186
+ p "You have been logged out."
187
+ p { a 'Continue', :href => R(Index) }
188
+ end
189
+
190
+ def add
191
+ if @user
192
+ _form(post, :action => R(Add))
193
+ else
194
+ _login
195
+ end
196
+ end
197
+
198
+ def edit
199
+ if @user
200
+ _form(post, :action => R(Edit))
201
+ else
202
+ _login
203
+ end
204
+ end
205
+
206
+ def view
207
+ _post(post)
208
+
209
+ p "Comment for this post:"
210
+ for c in @comments
211
+ h1 c.username
212
+ p c.body
213
+ end
214
+
215
+ form :action => R(Comment), :method => 'post' do
216
+ label 'Name', :for => 'post_username'; br
217
+ input :name => 'post_username', :type => 'text'; br
218
+ label 'Comment', :for => 'post_body'; br
219
+ textarea :name => 'post_body' do; end; br
220
+ input :type => 'hidden', :name => 'post_id', :value => post.id
221
+ input :type => 'submit'
222
+ end
223
+ end
224
+
225
+ # partials
226
+ def _login
227
+ form :action => R(Login), :method => 'post' do
228
+ label 'Username', :for => 'username'; br
229
+ input :name => 'username', :type => 'text'; br
230
+
231
+ label 'Password', :for => 'password'; br
232
+ input :name => 'password', :type => 'text'; br
233
+
234
+ input :type => 'submit', :name => 'login', :value => 'Login'
235
+ end
236
+ end
237
+
238
+ def _post(post)
239
+ h1 post.title
240
+ p post.body
241
+ p do
242
+ a "Edit", :href => R(Edit, post)
243
+ a "View", :href => R(View, post)
244
+ end
245
+ end
246
+
247
+ def _form(post, opts)
248
+ p do
249
+ text "You are logged in as #{@user.username} | "
250
+ a 'Logout', :href => R(Logout)
251
+ end
252
+ form({:method => 'post'}.merge(opts)) do
253
+ label 'Title', :for => 'post_title'; br
254
+ input :name => 'post_title', :type => 'text',
255
+ :value => post.title; br
256
+
257
+ label 'Body', :for => 'post_body'; br
258
+ textarea post.body, :name => 'post_body'; br
259
+
260
+ input :type => 'hidden', :name => 'post_id', :value => post.id
261
+ input :type => 'submit'
262
+ end
263
+ end
264
+ end
265
+
266
+ def Blog.create
267
+ Camping::Models::Session.create_schema
268
+ unless Blog::Models::Post.table_exists?
269
+ ActiveRecord::Schema.define(&Blog::Models.schema)
270
+ end
271
+ end
272
+
273
+ if __FILE__ == $0
274
+ require 'mongrel/camping'
275
+
276
+ Blog::Models::Base.establish_connection :adapter => 'sqlite3', :database => 'blog.db'
277
+ Blog::Models::Base.logger = Logger.new('camping.log')
278
+ Blog::Models::Base.threaded_connections=false
279
+ Blog.create
280
+
281
+ # Use the Configurator as an example rather than Mongrel::Camping.start
282
+ config = Mongrel::Configurator.new :host => "0.0.0.0" do
283
+ listener :port => 3002 do
284
+ uri "/blog", :handler => Mongrel::Camping::CampingHandler.new(Blog)
285
+ uri "/favicon", :handler => Mongrel::Error404Handler.new("")
286
+ trap("INT") { stop }
287
+ run
288
+ end
289
+ end
290
+
291
+ puts "** Blog example is running at http://localhost:3002/blog"
292
+ puts "** Default username is `admin', password is `camping'"
293
+ config.join
294
+ end