diff --git a/README b/README
index c6e78f8..e6ddab5 100644
--- a/README
+++ b/README
@@ -102,7 +102,7 @@ Camping comes with an tool for launching apps from the commandline:
* Run: camping blog.rb
* Visit http://localhost:3301/blog/ to use the app.
-== Debugging Camping Apps
+== How the Camping Tool Works
If your application isn't working with the camping tool, keep in mind
that the tool expects the following conventions to be used:
@@ -111,7 +111,7 @@ that the tool expects the following conventions to be used:
http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for instructions.)
2. If your script is called test.rb, Camping expects your application to
be stored in a module called Test. Case is not imporant, though. The
- module can be called TeSt or any other permuation.
+ module can be called TeSt or any other permutation.
3. Your script's postamble (anything enclosed in if __FILE__ == $0) will be
ignored by the tool, since the tool will create an SQLite3 database at
~/.camping.db. Or, on Windows, $USER/Application Data/Camping.db.
@@ -120,7 +120,7 @@ that the tool expects the following conventions to be used:
== The Rules of Thumb
-Once you've started writing your own Camping app, I'd highly recommend becoming familiar
+Once you've started writing your own Camping app, I'd highly recommend that you become familiar
with the Camping Rules of Thumb which are listed on the wiki:
http://code.whytheluckystiff.net/camping/wiki/CampingRulesOfThumb
diff --git a/Rakefile b/Rakefile
index fab6e05..cc9289b 100644
--- a/Rakefile
+++ b/Rakefile
@@ -32,7 +32,7 @@ Rake::RDocTask.new do |rdoc|
rdoc.template = "extras/flipbook_rdoc.rb"
rdoc.main = "README"
rdoc.title = "Camping, the Documentation"
- rdoc.rdoc_files.add ['README', 'CHANGELOG', 'COPYING', 'lib/camping.rb']
+ rdoc.rdoc_files.add ['README', 'CHANGELOG', 'COPYING', 'lib/camping.rb', 'lib/camping/*.rb']
end
task :after_doc do
diff --git a/bin/camping b/bin/camping
index a358328..f3cb3c3 100755
--- a/bin/camping
+++ b/bin/camping
@@ -12,6 +12,7 @@ require 'optparse'
require 'stringio'
require 'rubygems'
require 'camping'
+require 'camping/session'
host = '0.0.0.0'
port = 3301
@@ -68,6 +69,20 @@ if ARGV.length < 1
end
Camping::Models::Base.establish_connection :adapter => 'sqlite3', :database => db
+begin
+ Camping::Models::Session.create_schema
+rescue MissingSourceFile
+ puts "** #$0 stopped: SQLite3 not found, please install."
+ puts "** See http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for instructions."
+ exit
+end
+
+begin
+ require 'sqlite3_api'
+rescue LoadError
+ puts "!! Your SQLite3 adapter isn't a compiled extension."
+ abort "!! Please check out http://code.whytheluckystiff.net/camping/wiki/BeAlertWhenOnSqlite3 for tips."
+end
class CampingReloader
attr_accessor :klass, :mtime, :mount
diff --git a/lib/camping/fastcgi.rb b/lib/camping/fastcgi.rb
index 0d8e043..685a7a7 100644
--- a/lib/camping/fastcgi.rb
+++ b/lib/camping/fastcgi.rb
@@ -1,21 +1,72 @@
+# == About camping/fastcgi.rb
+#
+# Camping works very well with FastCGI, since your application is only loaded
+# once -- when FastCGI starts. In addition, this class lets you mount several
+# Camping apps under a single FastCGI process, to help save memory costs.
+#
+# So where do you use the Camping::FastCGI class? Use it in your application's
+# postamble and then you can point your web server directly at your application.
+# See Camping::FastCGI docs for more.
require 'fcgi'
module Camping
+# Camping::FastCGI is a small class for hooking one or more Camping apps up to
+# FastCGI. Generally, you'll use this class in your application's postamble.
+#
+# == The Smallest Example
+#
+# if __FILE__ == $0
+# require 'camping/fastcgi'
+# Camping::FastCGI.start(YourApp)
+# end
+#
+# This example is stripped down to the basics. The postamble has no database
+# connection. It just loads this class and calls Camping::FastCGI.start.
+#
+# Now, in Lighttpd or Apache, you can point to your app's file, which will
+# be executed, only to discover that your app now speaks the FastCGI protocol.
+#
+# Here's a sample lighttpd.conf (tested with Lighttpd 1.4.11) to serve as example:
+#
+# server.port = 3044
+# server.bind = "127.0.0.1"
+# server.modules = ( "mod_fastcgi" )
+# server.document-root = "/var/www/camping/blog/"
+# server.errorlog = "/var/www/camping/blog/error.log"
+#
+# #### fastcgi module
+# fastcgi.server = ( "/" => (
+# "localhost" => (
+# "socket" => "/tmp/camping-blog.socket",
+# "bin-path" => "/var/www/camping/blog/blog.rb",
+# "check-local" => "disable",
+# "max-procs" => 1 ) ) )
+#
+# The file /var/www/camping/blog/blog.rb is the Camping app with
+# the postamble.
+#
+# == Mounting Many Apps
+#
+# require 'camping/fastcgi'
+# fast = Camping::FastCGI.new
+# fast.mount("/blog", Blog)
+# fast.mount("/tepee", Tepee)
+# fast.mount("/", Index)
+# fast.start
+#
class FastCGI
+ # Creates a Camping::FastCGI class with empty mounts.
def initialize
@mounts = {}
end
+ # Mounts a Camping application. The +dir+ being the name of the directory
+ # to serve as the application's root. The +app+ is a Camping class.
def mount(dir, app)
dir.gsub!(/\/{2,}/, '/')
dir.gsub!(/\/+$/, '')
@mounts[dir] = app
end
- def match(path, mount)
- m = path.match(/^#{Regexp::quote mount}(\/|$)/)
- if m: m.end(0)
- else -1
- end
- end
+ # Starts the FastCGI main loop.
def start
FCGI.each do |req|
# req.out << app.run(req.in, req.env)
@@ -27,10 +78,25 @@ def start
req.finish
end
end
+
+ # A simple single-app starter mechanism
+ #
+ # Camping::FastCGI.start(Blog)
+ #
def self.start(app)
cf = Camping::FastCGI.new
cf.mount("/", app)
cf.start
end
+
+ private
+
+ def match(path, mount)
+ m = path.match(/^#{Regexp::quote mount}(\/|$)/)
+ if m: m.end(0)
+ else -1
+ end
+ end
+
end
end
diff --git a/lib/camping/session.rb b/lib/camping/session.rb
index 9b40dc5..c719bbc 100644
--- a/lib/camping/session.rb
+++ b/lib/camping/session.rb
@@ -86,7 +86,7 @@ module Camping
#
# 1. require 'camping/session'
# 2. Mixin the module: module YourApp; include Camping::Session end
-# 3. In your application's create method, add a call to Camping::Models::Schema.create_schema
+# 3. In your application's create method, add a call to Camping::Models::Session.create_schema
# 4. Throughout your application, use the @state var like a hash to store your application's data.
#
# If you are unfamiliar with the create method, see
diff --git a/lib/camping/webrick.rb b/lib/camping/webrick.rb
index 40fff61..d429ffe 100644
--- a/lib/camping/webrick.rb
+++ b/lib/camping/webrick.rb
@@ -1,20 +1,66 @@
+# == About camping/webrick.rb
+#
+# For many who have Ruby installed, Camping and WEBrick is a great option.
+# It's definitely the easiest configuration, however some performance is sacrificed.
+# For better speed, check out Mongrel at http://mongrel.rubyforge.org/, which comes
+# with Camping hooks and is supported by the Camping Tool.
require 'camping'
require 'webrick/httpservlet/abstract.rb'
-class WEBrick::CampingHandler < WEBrick::HTTPServlet::AbstractServlet
+# WEBrick::CampingHandler is a very simple handle for hosting Camping apps in
+# a WEBrick server. It's used much like any other WEBrick handler.
+#
+# == Mounting a Camping App
+#
+# Assuming Camping.goes(:Blog), the Blog application can be mounted alongside
+# other WEBrick mounts.
+#
+# s = WEBrick::HTTPServer.new(:BindAddress => host, :Port => port)
+# s.mount "/blog", WEBrick::CampingHandler, Blog
+# s.mount_proc("/") { ... }
+#
+# == How Does it Compare?
+#
+# Compared to other handlers, WEBrick is well-equipped in terms of features.
+#
+# * The X-Sendfile header is supported, along with etags and
+# modification time headers for the file served. Since this handler
+# is a subclass of WEBrick::HTTPServlet::DefaultFileHandler, all of its
+# logic is used.
+# * IO is streaming up and down. When you upload a file, it is streamed to
+# the server's filesystem. When you download a file, it is streamed to
+# your browser.
+#
+# While WEBrick is a bit slower than Mongrel and FastCGI options, it's
+# a decent choice, for sure!
+module WEBrick # :nodoc:
+class CampingHandler < WEBrick::HTTPServlet::DefaultFileHandler
+ # Creates a CampingHandler, which answers for the application within +klass+.
def initialize(server, klass)
super(server, klass)
@klass = klass
end
+ # Handler for WEBrick requests (also aliased as do_POST).
def do_GET(req, resp)
controller = @klass.run((req.body and StringIO.new(req.body)), req.meta_vars)
resp.status = controller.status
+ @local_path = nil
controller.headers.each do |k, v|
- [*v].each do |vi|
- resp[k] = vi
+ if k =~ /^X-SENDFILE$/i
+ @local_path = v
+ else
+ [*v].each do |vi|
+ resp[k] = vi
+ end
end
end
- resp.body = controller.body
+
+ if @local_path
+ super(req, res)
+ else
+ resp.body = controller.body
+ end
end
alias_method :do_POST, :do_GET
end
+end