camping 1.5.180 → 2.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +35 -0
- data/README +43 -68
- data/Rakefile +155 -86
- data/bin/camping +64 -246
- data/book/01_introduction +19 -0
- data/book/02_getting_started +443 -0
- data/book/51_upgrading +93 -0
- data/doc/api.html +1953 -0
- data/doc/book.html +73 -0
- data/doc/book/01_introduction.html +57 -0
- data/doc/book/02_getting_started.html +573 -0
- data/doc/book/51_upgrading.html +146 -0
- data/doc/created.rid +1 -0
- data/{extras → doc/images}/Camping.gif +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/{extras → doc/images}/permalink.gif +0 -0
- data/doc/index.html +148 -0
- data/doc/js/camping.js +79 -0
- data/doc/js/jquery.js +32 -0
- data/doc/rdoc.css +117 -0
- data/examples/blog.rb +280 -181
- data/extras/images/badge.gif +0 -0
- data/extras/images/boys-life.png +0 -0
- data/extras/images/deerputer.png +0 -0
- data/extras/images/diagram.png +0 -0
- data/extras/images/hill.png +0 -0
- data/extras/images/i-wish.png +0 -0
- data/extras/images/latl.png +0 -0
- data/extras/images/little-wheels.png +0 -0
- data/extras/images/square-badge.png +0 -0
- data/extras/images/uniform.png +0 -0
- data/extras/images/whale-bounce.png +0 -0
- data/extras/rdoc/generator/singledarkfish.rb +205 -0
- data/extras/rdoc/generator/template/flipbook/images/Camping.gif +0 -0
- data/extras/rdoc/generator/template/flipbook/images/loadingAnimation.gif +0 -0
- data/extras/rdoc/generator/template/flipbook/images/permalink.gif +0 -0
- data/extras/rdoc/generator/template/flipbook/js/camping.js +79 -0
- data/extras/rdoc/generator/template/flipbook/js/jquery.js +32 -0
- data/extras/rdoc/generator/template/flipbook/page.rhtml +30 -0
- data/extras/rdoc/generator/template/flipbook/rdoc.css +117 -0
- data/extras/rdoc/generator/template/flipbook/readme.rhtml +31 -0
- data/extras/rdoc/generator/template/flipbook/reference.rhtml +71 -0
- data/extras/rdoc/generator/template/flipbook/toc.rhtml +43 -0
- data/lib/camping-unabridged.rb +420 -481
- data/lib/camping.rb +40 -55
- data/lib/camping/{db.rb → ar.rb} +5 -8
- data/lib/camping/mab.rb +26 -0
- data/lib/camping/reloader.rb +175 -147
- data/lib/camping/server.rb +178 -0
- data/lib/camping/session.rb +34 -121
- data/test/apps/env_debug.rb +65 -0
- data/test/apps/forms.rb +95 -0
- data/test/apps/forward_to_other_controller.rb +60 -0
- data/test/apps/migrations.rb +97 -0
- data/test/apps/misc.rb +86 -0
- data/test/apps/sessions.rb +38 -0
- metadata +120 -80
- data/doc/camping.1.gz +0 -0
- data/examples/campsh.rb +0 -630
- data/examples/tepee.rb +0 -242
- data/extras/flipbook_rdoc.rb +0 -491
- data/lib/camping/fastcgi.rb +0 -244
- data/lib/camping/webrick.rb +0 -65
- data/test/test_xhtml_trans.rb +0 -55
data/lib/camping/fastcgi.rb
DELETED
@@ -1,244 +0,0 @@
|
|
1
|
-
# == About camping/fastcgi.rb
|
2
|
-
#
|
3
|
-
# Camping works very well with FastCGI, since your application is only loaded
|
4
|
-
# once -- when FastCGI starts. In addition, this class lets you mount several
|
5
|
-
# Camping apps under a single FastCGI process, to help save memory costs.
|
6
|
-
#
|
7
|
-
# So where do you use the Camping::FastCGI class? Use it in your application's
|
8
|
-
# postamble and then you can point your web server directly at your application.
|
9
|
-
# See Camping::FastCGI docs for more.
|
10
|
-
require 'camping'
|
11
|
-
require 'fcgi'
|
12
|
-
|
13
|
-
module Camping
|
14
|
-
# Camping::FastCGI is a small class for hooking one or more Camping apps up to
|
15
|
-
# FastCGI. Generally, you'll use this class in your application's postamble.
|
16
|
-
#
|
17
|
-
# == The Smallest Example
|
18
|
-
#
|
19
|
-
# if __FILE__ == $0
|
20
|
-
# require 'camping/fastcgi'
|
21
|
-
# Camping::FastCGI.start(YourApp)
|
22
|
-
# end
|
23
|
-
#
|
24
|
-
# This example is stripped down to the basics. The postamble has no database
|
25
|
-
# connection. It just loads this class and calls Camping::FastCGI.start.
|
26
|
-
#
|
27
|
-
# Now, in Lighttpd or Apache, you can point to your app's file, which will
|
28
|
-
# be executed, only to discover that your app now speaks the FastCGI protocol.
|
29
|
-
#
|
30
|
-
# Here's a sample lighttpd.conf (tested with Lighttpd 1.4.11) to serve as example:
|
31
|
-
#
|
32
|
-
# server.port = 3044
|
33
|
-
# server.bind = "127.0.0.1"
|
34
|
-
# server.modules = ( "mod_fastcgi" )
|
35
|
-
# server.document-root = "/var/www/camping/blog/"
|
36
|
-
# server.errorlog = "/var/www/camping/blog/error.log"
|
37
|
-
#
|
38
|
-
# #### fastcgi module
|
39
|
-
# fastcgi.server = ( "/" => (
|
40
|
-
# "localhost" => (
|
41
|
-
# "socket" => "/tmp/camping-blog.socket",
|
42
|
-
# "bin-path" => "/var/www/camping/blog/blog.rb",
|
43
|
-
# "check-local" => "disable",
|
44
|
-
# "max-procs" => 1 ) ) )
|
45
|
-
#
|
46
|
-
# The file <tt>/var/www/camping/blog/blog.rb</tt> is the Camping app with
|
47
|
-
# the postamble.
|
48
|
-
#
|
49
|
-
# == Mounting Many Apps
|
50
|
-
#
|
51
|
-
# require 'camping/fastcgi'
|
52
|
-
# fast = Camping::FastCGI.new
|
53
|
-
# fast.mount("/blog", Blog)
|
54
|
-
# fast.mount("/tepee", Tepee)
|
55
|
-
# fast.mount("/", Index)
|
56
|
-
# fast.start
|
57
|
-
#
|
58
|
-
class FastCGI
|
59
|
-
CHUNK_SIZE=(4 * 1024)
|
60
|
-
|
61
|
-
attr_reader :mounts
|
62
|
-
|
63
|
-
# Creates a Camping::FastCGI class with empty mounts.
|
64
|
-
def initialize
|
65
|
-
@mounts = {}
|
66
|
-
end
|
67
|
-
# Mounts a Camping application. The +dir+ being the name of the directory
|
68
|
-
# to serve as the application's root. The +app+ is a Camping class.
|
69
|
-
def mount(dir, app)
|
70
|
-
dir.gsub!(/\/{2,}/, '/')
|
71
|
-
dir.gsub!(/\/+$/, '')
|
72
|
-
@mounts[dir] = app
|
73
|
-
end
|
74
|
-
|
75
|
-
#
|
76
|
-
# Starts the FastCGI main loop.
|
77
|
-
def start(&blk)
|
78
|
-
FCGI.each do |req|
|
79
|
-
camp_do(req, &blk)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# A simple single-app starter mechanism
|
84
|
-
#
|
85
|
-
# Camping::FastCGI.start(Blog)
|
86
|
-
#
|
87
|
-
def self.start(app)
|
88
|
-
cf = Camping::FastCGI.new
|
89
|
-
cf.mount("/", app)
|
90
|
-
cf.start
|
91
|
-
end
|
92
|
-
|
93
|
-
# Serve an entire directory of Camping apps. (See
|
94
|
-
# http://code.whytheluckystiff.net/camping/wiki/TheCampingServer.)
|
95
|
-
#
|
96
|
-
# Use this method inside your FastCGI dispatcher:
|
97
|
-
#
|
98
|
-
# #!/usr/local/bin/ruby
|
99
|
-
# require 'rubygems'
|
100
|
-
# require 'camping/fastcgi'
|
101
|
-
# Camping::Models::Base.establish_connection :adapter => 'sqlite3', :database => "/path/to/db"
|
102
|
-
# Camping::FastCGI.serve("/home/why/cvs/camping/examples")
|
103
|
-
#
|
104
|
-
def self.serve(path, index=nil)
|
105
|
-
require 'camping/reloader'
|
106
|
-
if File.directory? path
|
107
|
-
fast = Camping::FastCGI.new
|
108
|
-
script_load = proc do |script|
|
109
|
-
app = Camping::Reloader.new(script)
|
110
|
-
fast.mount("/#{app.mount}", app)
|
111
|
-
app
|
112
|
-
end
|
113
|
-
Dir[File.join(path, '*.rb')].each &script_load
|
114
|
-
fast.mount("/", index) if index
|
115
|
-
|
116
|
-
fast.start do |dir, app|
|
117
|
-
Dir[File.join(path, dir, '*.rb')].each do |script|
|
118
|
-
smount = "/" + File.basename(script, '.rb')
|
119
|
-
script_load[script] unless fast.mounts.has_key? smount
|
120
|
-
end
|
121
|
-
end
|
122
|
-
else
|
123
|
-
start(Camping::Reloader.new(path))
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
private
|
128
|
-
|
129
|
-
def camp_do(req)
|
130
|
-
root, path, dir, app = "/"
|
131
|
-
if ENV['FORCE_ROOT'] and ENV['FORCE_ROOT'].to_i == 1
|
132
|
-
path = req.env['SCRIPT_NAME']
|
133
|
-
else
|
134
|
-
root = req.env['SCRIPT_NAME']
|
135
|
-
path = req.env['PATH_INFO']
|
136
|
-
end
|
137
|
-
|
138
|
-
dir, app = @mounts.max { |a,b| match(path, a[0]) <=> match(path, b[0]) }
|
139
|
-
unless dir and app
|
140
|
-
dir, app = '/', Camping
|
141
|
-
end
|
142
|
-
yield dir, app if block_given?
|
143
|
-
|
144
|
-
req.env['SERVER_SCRIPT_NAME'] = req.env['SCRIPT_NAME']
|
145
|
-
req.env['SERVER_PATH_INFO'] = req.env['PATH_INFO']
|
146
|
-
req.env['SCRIPT_NAME'] = File.join(root, dir)
|
147
|
-
req.env['PATH_INFO'] = path.gsub(/^#{dir}/, '')
|
148
|
-
|
149
|
-
controller = app.run(SeekStream.new(req.in), req.env)
|
150
|
-
sendfile = nil
|
151
|
-
headers = {}
|
152
|
-
controller.headers.each do |k, v|
|
153
|
-
if k =~ /^X-SENDFILE$/i and !ENV['SERVER_X_SENDFILE']
|
154
|
-
sendfile = v
|
155
|
-
else
|
156
|
-
headers[k] = v
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
|
-
body = controller.body
|
161
|
-
controller.body = ""
|
162
|
-
controller.headers = headers
|
163
|
-
|
164
|
-
req.out << controller.to_s
|
165
|
-
if sendfile
|
166
|
-
File.open(sendfile, "rb") do |f|
|
167
|
-
while chunk = f.read(CHUNK_SIZE) and chunk.length > 0
|
168
|
-
req.out << chunk
|
169
|
-
end
|
170
|
-
end
|
171
|
-
elsif body.respond_to? :read
|
172
|
-
while chunk = body.read(CHUNK_SIZE) and chunk.length > 0
|
173
|
-
req.out << chunk
|
174
|
-
end
|
175
|
-
body.close if body.respond_to? :close
|
176
|
-
else
|
177
|
-
req.out << body.to_s
|
178
|
-
end
|
179
|
-
rescue Exception => e
|
180
|
-
req.out << server_error(root, path, exc, req)
|
181
|
-
ensure
|
182
|
-
req.finish
|
183
|
-
end
|
184
|
-
|
185
|
-
def server_error(root, path, exc, req)
|
186
|
-
"Content-Type: text/html\r\n\r\n" +
|
187
|
-
"<h1>Camping Problem!</h1>" +
|
188
|
-
"<h2><strong>#{root}</strong>#{path}</h2>" +
|
189
|
-
"<h3>#{exc.class} #{esc exc.message}</h3>" +
|
190
|
-
"<ul>" + exc.backtrace.map { |bt| "<li>#{esc bt}</li>" }.join + "</ul>" +
|
191
|
-
"<hr /><p>#{req.env.inspect}</p>"
|
192
|
-
end
|
193
|
-
|
194
|
-
def match(path, mount)
|
195
|
-
m = path.match(/^#{Regexp::quote mount}(\/|$)/)
|
196
|
-
if m; m.end(0)
|
197
|
-
else -1
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
def esc(str)
|
202
|
-
str.gsub(/&/n, '&').gsub(/\"/n, '"').gsub(/>/n, '>').gsub(/</n, '<')
|
203
|
-
end
|
204
|
-
|
205
|
-
class SeekStream
|
206
|
-
def initialize(stream)
|
207
|
-
@last_read = ""
|
208
|
-
@stream = stream
|
209
|
-
@buffer = ""
|
210
|
-
end
|
211
|
-
def eof?
|
212
|
-
@buffer.empty? && @stream.eof?
|
213
|
-
end
|
214
|
-
def each
|
215
|
-
while true
|
216
|
-
pull(1024) until eof? or @buffer.index("\n")
|
217
|
-
return nil if eof?
|
218
|
-
yield @buffer.slice!(0..(@buffer.index("\n") || -1))
|
219
|
-
end
|
220
|
-
end
|
221
|
-
def pull(len)
|
222
|
-
@buffer += @stream.read(len).to_s
|
223
|
-
end
|
224
|
-
def read(len = 16384)
|
225
|
-
pull(len)
|
226
|
-
@last_read =
|
227
|
-
if eof?
|
228
|
-
nil
|
229
|
-
else
|
230
|
-
@buffer.slice!(0...len)
|
231
|
-
end
|
232
|
-
end
|
233
|
-
def seek(len, typ)
|
234
|
-
raise NotImplementedError, "only IO::SEEK_CUR is supported with SeekStream" if typ != IO::SEEK_CUR
|
235
|
-
raise NotImplementedError, "only rewinding is supported with SeekStream" if len > 0
|
236
|
-
raise NotImplementedError, "rewinding #{-len} past the buffer #{@last_read.size} start not supported with SeekStream" if -len > @last_read.size
|
237
|
-
@buffer = @last_read[len..-1] + @buffer
|
238
|
-
@last_read = ""
|
239
|
-
self
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
end
|
244
|
-
end
|
data/lib/camping/webrick.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
# == About camping/webrick.rb
|
2
|
-
#
|
3
|
-
# For many who have Ruby installed, Camping and WEBrick is a great option.
|
4
|
-
# It's definitely the easiest configuration, however some performance is sacrificed.
|
5
|
-
# For better speed, check out Mongrel at http://mongrel.rubyforge.org/, which comes
|
6
|
-
# with Camping hooks and is supported by the Camping Tool.
|
7
|
-
require 'camping'
|
8
|
-
require 'webrick/httpservlet/abstract.rb'
|
9
|
-
|
10
|
-
module WEBrick
|
11
|
-
# WEBrick::CampingHandler is a very simple handle for hosting Camping apps in
|
12
|
-
# a WEBrick server. It's used much like any other WEBrick handler.
|
13
|
-
#
|
14
|
-
# == Mounting a Camping App
|
15
|
-
#
|
16
|
-
# Assuming Camping.goes(:Blog), the Blog application can be mounted alongside
|
17
|
-
# other WEBrick mounts.
|
18
|
-
#
|
19
|
-
# s = WEBrick::HTTPServer.new(:BindAddress => host, :Port => port)
|
20
|
-
# s.mount "/blog", WEBrick::CampingHandler, Blog
|
21
|
-
# s.mount_proc("/") { ... }
|
22
|
-
#
|
23
|
-
# == How Does it Compare?
|
24
|
-
#
|
25
|
-
# Compared to other handlers, WEBrick is well-equipped in terms of features.
|
26
|
-
#
|
27
|
-
# * The <tt>X-Sendfile</tt> header is supported, along with etags and
|
28
|
-
# modification time headers for the file served. Since this handler
|
29
|
-
# is a subclass of WEBrick::HTTPServlet::DefaultFileHandler, all of its
|
30
|
-
# logic is used.
|
31
|
-
# * IO is streaming up and down. When you upload a file, it is streamed to
|
32
|
-
# the server's filesystem. When you download a file, it is streamed to
|
33
|
-
# your browser.
|
34
|
-
#
|
35
|
-
# While WEBrick is a bit slower than Mongrel and FastCGI options, it's
|
36
|
-
# a decent choice, for sure!
|
37
|
-
class CampingHandler < WEBrick::HTTPServlet::DefaultFileHandler
|
38
|
-
# Creates a CampingHandler, which answers for the application within +klass+.
|
39
|
-
def initialize(server, klass)
|
40
|
-
super(server, klass)
|
41
|
-
@klass = klass
|
42
|
-
end
|
43
|
-
# Handler for WEBrick requests (also aliased as do_POST).
|
44
|
-
def service(req, resp)
|
45
|
-
controller = @klass.run((req.body and StringIO.new(req.body)), req.meta_vars)
|
46
|
-
resp.status = controller.status
|
47
|
-
@local_path = nil
|
48
|
-
controller.headers.each do |k, v|
|
49
|
-
if k =~ /^X-SENDFILE$/i
|
50
|
-
@local_path = v
|
51
|
-
else
|
52
|
-
[*v].each do |vi|
|
53
|
-
resp[k] = vi
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
if @local_path
|
59
|
-
do_GET(req, resp)
|
60
|
-
else
|
61
|
-
resp.body = controller.body.to_s
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
data/test/test_xhtml_trans.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require 'mosquito'
|
2
|
-
|
3
|
-
Camping.goes :XhtmlTrans
|
4
|
-
|
5
|
-
module XhtmlTrans
|
6
|
-
module Controllers
|
7
|
-
class WithLayout < R '/with_layout'
|
8
|
-
def get
|
9
|
-
render :with_layout
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class WithoutLayout < R '/without_layout'
|
14
|
-
def get
|
15
|
-
render :_without_layout
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
module Views
|
21
|
-
def layout
|
22
|
-
xhtml_transitional do
|
23
|
-
head do title "title" end
|
24
|
-
body do capture { yield } end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def with_layout
|
29
|
-
h1 "With layout"
|
30
|
-
end
|
31
|
-
|
32
|
-
def _without_layout
|
33
|
-
xhtml_transitional do
|
34
|
-
head do title "title" end
|
35
|
-
body do h1 "Without layout" end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class XhtmlTransTest < Camping::FunctionalTest
|
42
|
-
def test_with_layout
|
43
|
-
get '/with_layout'
|
44
|
-
|
45
|
-
assert(@response.body =~ /DOCTYPE/, "No doctype defined")
|
46
|
-
end
|
47
|
-
|
48
|
-
def test_without_layout
|
49
|
-
get '/without_layout'
|
50
|
-
|
51
|
-
assert(@response.body =~ /DOCTYPE/, "No doctype defined")
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
|