camping 1.5.180 → 2.0.rc0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
-
|