camping 1.4.2 → 1.5
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 +44 -1
- data/README +4 -11
- data/Rakefile +10 -10
- data/bin/camping +155 -97
- data/doc/camping.1.gz +0 -0
- data/examples/{blog/blog.rb → blog.rb} +45 -59
- data/examples/{campsh/campsh.rb → campsh.rb} +38 -39
- data/examples/tepee.rb +242 -0
- data/lib/camping-unabridged.rb +203 -131
- data/lib/camping.rb +49 -48
- data/lib/camping/db.rb +78 -0
- data/lib/camping/fastcgi.rb +198 -0
- data/lib/camping/reloader.rb +169 -0
- data/lib/camping/session.rb +1 -1
- data/lib/camping/webrick.rb +51 -6
- metadata +73 -72
- data/examples/charts/charts.rb +0 -89
- data/examples/charts/pie.rb +0 -70
- data/examples/tepee/tepee.rb +0 -149
data/lib/camping-unabridged.rb
CHANGED
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
# http://rubyforge.org/projects/mongrel Mongrel comes with examples
|
|
29
29
|
# in its <tt>examples/camping</tt> directory.
|
|
30
30
|
#
|
|
31
|
-
%w[
|
|
31
|
+
%w[active_support markaby tempfile uri].each { |lib| require lib }
|
|
32
32
|
|
|
33
33
|
# == Camping
|
|
34
34
|
#
|
|
@@ -42,28 +42,25 @@
|
|
|
42
42
|
#
|
|
43
43
|
# * Camping::Helpers which can be used in controllers and views.
|
|
44
44
|
#
|
|
45
|
-
# == The
|
|
45
|
+
# == The Camping Server
|
|
46
46
|
#
|
|
47
|
-
#
|
|
48
|
-
# The script begins by requiring Camping, then fills each of the three modules
|
|
49
|
-
# described above with classes and methods. Finally, a postamble puts the wheels
|
|
50
|
-
# in motion.
|
|
47
|
+
# How do you run Camping apps? Oh, uh... The Camping Server!
|
|
51
48
|
#
|
|
52
|
-
#
|
|
53
|
-
# Camping::Models::Base.establish_connection :adapter => 'sqlite3',
|
|
54
|
-
# :database => 'blog3.db'
|
|
55
|
-
# Camping::Models::Base.logger = Logger.new('camping.log')
|
|
56
|
-
# Camping.create if Camping.respond_to? :create
|
|
57
|
-
# puts Camping.run
|
|
58
|
-
# end
|
|
49
|
+
# The Camping Server is, firstly and thusly, a set of rules. At the very least, The Camping Server must:
|
|
59
50
|
#
|
|
60
|
-
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
51
|
+
# * Load all Camping apps in a directory.
|
|
52
|
+
# * Load new apps that appear in that directory.
|
|
53
|
+
# * Mount those apps according to their filename. (e.g. blog.rb is mounted at /blog.)
|
|
54
|
+
# * Run each app's <tt>create</tt> method upon startup.
|
|
55
|
+
# * Reload the app if its modification time changes.
|
|
56
|
+
# * Reload the app if it requires any files under the same directory and one of their modification times changes.
|
|
57
|
+
# * Support the X-Sendfile header.
|
|
64
58
|
#
|
|
65
|
-
#
|
|
66
|
-
#
|
|
59
|
+
# In fact, Camping comes with its own little The Camping Server.
|
|
60
|
+
#
|
|
61
|
+
# At a command prompt, run: <tt>camping examples/</tt> and the entire <tt>examples/</tt> directory will be served.
|
|
62
|
+
#
|
|
63
|
+
# Configurations also exist for Apache and Lighttpd. See http://code.whytheluckystiff.net/camping/wiki/TheCampingServer.
|
|
67
64
|
#
|
|
68
65
|
# == The <tt>create</tt> method
|
|
69
66
|
#
|
|
@@ -86,9 +83,17 @@
|
|
|
86
83
|
#
|
|
87
84
|
# For more tips, see http://code.whytheluckystiff.net/camping/wiki/GiveUsTheCreateMethod.
|
|
88
85
|
module Camping
|
|
86
|
+
# Stores an +Array+ of all Camping applications modules. Modules are added
|
|
87
|
+
# automatically by +Camping.goes+.
|
|
88
|
+
#
|
|
89
|
+
# Camping.goes :Blog
|
|
90
|
+
# Camping.goes :Tepee
|
|
91
|
+
# Camping::Apps # => [Blog, Tepee]
|
|
92
|
+
#
|
|
93
|
+
Apps = []
|
|
89
94
|
C = self
|
|
90
|
-
|
|
91
|
-
|
|
95
|
+
S = IO.read(__FILE__).sub(/^ S = I.+$/,'')
|
|
96
|
+
P="Cam\ping Problem!"
|
|
92
97
|
|
|
93
98
|
H = HashWithIndifferentAccess
|
|
94
99
|
# An object-like Hash, based on ActiveSupport's HashWithIndifferentAccess.
|
|
@@ -113,15 +118,16 @@ module Camping
|
|
|
113
118
|
# to get the value for the <tt>page</tt> query variable.
|
|
114
119
|
#
|
|
115
120
|
# Use the <tt>@cookies</tt> variable in the same fashion to access cookie variables.
|
|
121
|
+
# Also, the <tt>@env</tt> variable is an H containing the HTTP headers and server info.
|
|
116
122
|
class H
|
|
123
|
+
# Gets or sets keys in the hash.
|
|
124
|
+
#
|
|
125
|
+
# @cookies.my_favorite = :macadamian
|
|
126
|
+
# @cookies.my_favorite
|
|
127
|
+
# => :macadamian
|
|
128
|
+
#
|
|
117
129
|
def method_missing(m,*a)
|
|
118
|
-
|
|
119
|
-
self[$`] = a[0]
|
|
120
|
-
elsif a.empty?
|
|
121
|
-
self[m]
|
|
122
|
-
else
|
|
123
|
-
raise NoMethodError, "#{m}"
|
|
124
|
-
end
|
|
130
|
+
m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m]:raise(NoMethodError,"#{m}")
|
|
125
131
|
end
|
|
126
132
|
alias_method :u, :regular_update
|
|
127
133
|
end
|
|
@@ -190,18 +196,19 @@ module Camping
|
|
|
190
196
|
# is assigned to route <tt>/logout</tt>. The HTML will come out as:
|
|
191
197
|
#
|
|
192
198
|
# <div id="menu">
|
|
193
|
-
# <a href="
|
|
199
|
+
# <a href="//localhost:3301/frodo/">Home</a>
|
|
194
200
|
# <a href="/frodo/profile">Profile</a>
|
|
195
201
|
# <a href="/frodo/logout">Logout</a>
|
|
196
202
|
# <a href="http://google.com">Google</a>
|
|
197
203
|
# </div>
|
|
198
204
|
#
|
|
199
|
-
def R(c,*
|
|
200
|
-
p
|
|
201
|
-
|
|
202
|
-
|
|
205
|
+
def R(c,*g)
|
|
206
|
+
p=/\(.+?\)/
|
|
207
|
+
g.inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|
|
|
208
|
+
s.sub p,C.escape((a[a.class.primary_key]rescue a))
|
|
203
209
|
}
|
|
204
210
|
end
|
|
211
|
+
|
|
205
212
|
# Shows AR validation errors for the object passed.
|
|
206
213
|
# There is no output if there are no errors.
|
|
207
214
|
#
|
|
@@ -221,8 +228,8 @@ module Camping
|
|
|
221
228
|
#
|
|
222
229
|
# See AR validation documentation for details on validations.
|
|
223
230
|
def errors_for(o); ul.errors { o.errors.each_full { |er| li er } } if o.errors.any?; end
|
|
224
|
-
# Simply builds
|
|
225
|
-
#
|
|
231
|
+
# Simply builds a complete path from a path +p+ within the app. If your application is
|
|
232
|
+
# mounted at <tt>/blog</tt>:
|
|
226
233
|
#
|
|
227
234
|
# self / "/view/1" #=> "/blog/view/1"
|
|
228
235
|
# self / "styles.css" #=> "styles.css"
|
|
@@ -231,18 +238,23 @@ module Camping
|
|
|
231
238
|
def /(p); p[/^\//]?@root+p:p end
|
|
232
239
|
# Builds a URL route to a controller or a path, returning a URI object.
|
|
233
240
|
# This way you'll get the hostname and the port number, a complete URL.
|
|
241
|
+
# No scheme is given (http or https).
|
|
234
242
|
#
|
|
235
243
|
# You can use this to grab URLs for controllers using the R-style syntax.
|
|
236
244
|
# So, if your application is mounted at <tt>http://test.ing/blog/</tt>
|
|
237
245
|
# and you have a View controller which routes as <tt>R '/view/(\d+)'</tt>:
|
|
238
246
|
#
|
|
239
|
-
# URL(View, @post.id) #=> #<
|
|
247
|
+
# URL(View, @post.id) #=> #<URL://test.ing/blog/view/12>
|
|
240
248
|
#
|
|
241
249
|
# Or you can use the direct path:
|
|
242
250
|
#
|
|
243
|
-
# self.URL #=> #<
|
|
244
|
-
# self.URL + "view/12" #=> #<
|
|
245
|
-
# URL("/view/12") #=> #<
|
|
251
|
+
# self.URL #=> #<URL://test.ing/blog/>
|
|
252
|
+
# self.URL + "view/12" #=> #<URL://test.ing/blog/view/12>
|
|
253
|
+
# URL("/view/12") #=> #<URL://test.ing/blog/view/12>
|
|
254
|
+
#
|
|
255
|
+
# Since no scheme is given, you will need to add the scheme yourself:
|
|
256
|
+
#
|
|
257
|
+
# "http" + URL("/view/12") #=> "http://test.ing/blog/view/12"
|
|
246
258
|
#
|
|
247
259
|
# It's okay to pass URL strings through this method as well:
|
|
248
260
|
#
|
|
@@ -294,6 +306,8 @@ module Camping
|
|
|
294
306
|
module Base
|
|
295
307
|
include Helpers
|
|
296
308
|
attr_accessor :input, :cookies, :env, :headers, :body, :status, :root
|
|
309
|
+
Z = "\r\n"
|
|
310
|
+
|
|
297
311
|
# Display a view, calling it by its method name +m+. If a <tt>layout</tt>
|
|
298
312
|
# method is found in Camping::Views, it will be used to wrap the HTML.
|
|
299
313
|
#
|
|
@@ -319,10 +333,12 @@ module Camping
|
|
|
319
333
|
#
|
|
320
334
|
# If you have a <tt>layout</tt> method in Camping::Views, it will be used to
|
|
321
335
|
# wrap the HTML.
|
|
322
|
-
def method_missing(
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
336
|
+
def method_missing(*a,&b)
|
|
337
|
+
a.shift if a[0]==:render
|
|
338
|
+
m=Mab.new({},self)
|
|
339
|
+
s=m.capture{send(*a,&b)}
|
|
340
|
+
s=m.layout{s} if /^_/!~a[0].to_s and m.respond_to?:layout
|
|
341
|
+
s
|
|
326
342
|
end
|
|
327
343
|
|
|
328
344
|
# Formulate a redirect response: a 302 status with <tt>Location</tt> header
|
|
@@ -331,9 +347,12 @@ module Camping
|
|
|
331
347
|
#
|
|
332
348
|
# So, given a root of <tt>http://localhost:3301/articles</tt>:
|
|
333
349
|
#
|
|
334
|
-
# redirect "view/12" # redirects to "
|
|
335
|
-
# redirect View, 12 # redirects to "
|
|
350
|
+
# redirect "view/12" # redirects to "//localhost:3301/articles/view/12"
|
|
351
|
+
# redirect View, 12 # redirects to "//localhost:3301/articles/view/12"
|
|
336
352
|
#
|
|
353
|
+
# <b>NOTE:</b> This method doesn't magically exit your methods and redirect.
|
|
354
|
+
# You'll need to <tt>return redirect(...)</tt> if this isn't the last statement
|
|
355
|
+
# in your code.
|
|
337
356
|
def redirect(*a)
|
|
338
357
|
r(302,'','Location'=>URL(*a))
|
|
339
358
|
end
|
|
@@ -362,7 +381,7 @@ module Camping
|
|
|
362
381
|
fh=H[]
|
|
363
382
|
for l in @in
|
|
364
383
|
case l
|
|
365
|
-
when
|
|
384
|
+
when Z: break
|
|
366
385
|
when /^Content-Disposition: form-data;/
|
|
367
386
|
fh.u H[*$'.scan(/(?:\s(\w+)="([^"]+)")/).flatten]
|
|
368
387
|
when /^Content-Type: (.+?)(\r$|\Z)/m
|
|
@@ -394,27 +413,24 @@ module Camping
|
|
|
394
413
|
@cookies, @input = @k.dup, qs.dup
|
|
395
414
|
end
|
|
396
415
|
|
|
397
|
-
|
|
416
|
+
# All requests pass through this method before going to the controller. Some magic
|
|
417
|
+
# in Camping can be performed by overriding this method.
|
|
418
|
+
#
|
|
419
|
+
# See http://code.whytheluckystiff.net/camping/wiki/BeforeAndAfterOverrides for more
|
|
420
|
+
# on before and after overrides with Camping.
|
|
421
|
+
def service(*a)
|
|
398
422
|
@body = send(@method, *a) if respond_to? @method
|
|
399
|
-
@headers['Set-Cookie'] = @cookies.map { |k,v| "#{k}=#{C.escape(v)}; path=#{self/"/"}" if v != @k[k] }
|
|
423
|
+
@headers['Set-Cookie'] = @cookies.map { |k,v| "#{k}=#{C.escape(v)}; path=#{self/"/"}" if v != @k[k] } - [nil]
|
|
400
424
|
self
|
|
401
425
|
end
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
def
|
|
406
|
-
|
|
407
|
-
[iv[1..-1], instance_variable_get(iv)] } )
|
|
408
|
-
end
|
|
409
|
-
def markaview(m, *a, &b) #:nodoc:
|
|
410
|
-
h=markaby
|
|
411
|
-
h.send(m, *a, &b)
|
|
412
|
-
h.to_s
|
|
426
|
+
|
|
427
|
+
# Used by the web server to convert the current request to a string. If you need to
|
|
428
|
+
# alter the way Camping builds HTTP headers, consider overriding this method.
|
|
429
|
+
def to_s
|
|
430
|
+
"Status: #{@status}#{Z+@headers.map{|k,v|[*v].map{|x|"#{k}: #{x}"}}*Z+Z*2+@body}"
|
|
413
431
|
end
|
|
414
|
-
end
|
|
415
432
|
|
|
416
|
-
|
|
417
|
-
class R; include Base end
|
|
433
|
+
end
|
|
418
434
|
|
|
419
435
|
# Controllers is a module for placing classes which handle URLs. This is done
|
|
420
436
|
# by defining a route to each class using the Controllers::R method.
|
|
@@ -436,6 +452,79 @@ module Camping
|
|
|
436
452
|
# NotFound class handles URLs not found. The ServerError class handles exceptions
|
|
437
453
|
# uncaught by your application.
|
|
438
454
|
module Controllers
|
|
455
|
+
@r = []
|
|
456
|
+
class << self
|
|
457
|
+
def r #:nodoc:
|
|
458
|
+
@r
|
|
459
|
+
end
|
|
460
|
+
# Add routes to a controller class by piling them into the R method.
|
|
461
|
+
#
|
|
462
|
+
# module Camping::Controllers
|
|
463
|
+
# class Edit < R '/edit/(\d+)', '/new'
|
|
464
|
+
# def get(id)
|
|
465
|
+
# if id # edit
|
|
466
|
+
# else # new
|
|
467
|
+
# end
|
|
468
|
+
# end
|
|
469
|
+
# end
|
|
470
|
+
# end
|
|
471
|
+
#
|
|
472
|
+
# You will need to use routes in either of these cases:
|
|
473
|
+
#
|
|
474
|
+
# * You want to assign multiple routes to a controller.
|
|
475
|
+
# * You want your controller to receive arguments.
|
|
476
|
+
#
|
|
477
|
+
# Most of the time the rules inferred by dispatch method Controllers::D will get you
|
|
478
|
+
# by just fine.
|
|
479
|
+
def R *u
|
|
480
|
+
r=@r
|
|
481
|
+
Class.new {
|
|
482
|
+
meta_def(:urls){u}
|
|
483
|
+
meta_def(:inherited){|x|r<<x}
|
|
484
|
+
}
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
# Dispatch routes to controller classes.
|
|
488
|
+
# For each class, routes are checked for a match based on their order in the routing list
|
|
489
|
+
# given to Controllers::R. If no routes were given, the dispatcher uses a slash followed
|
|
490
|
+
# by the name of the controller lowercased.
|
|
491
|
+
#
|
|
492
|
+
# Controllers are searched in this order:
|
|
493
|
+
#
|
|
494
|
+
# # Classes without routes, since they refer to a very specific URL.
|
|
495
|
+
# # Classes with routes are searched in order of their creation.
|
|
496
|
+
#
|
|
497
|
+
# So, define your catch-all controllers last.
|
|
498
|
+
def D(path)
|
|
499
|
+
r.map { |k|
|
|
500
|
+
k.urls.map { |x|
|
|
501
|
+
return k, $~[1..-1] if path =~ /^#{x}\/?$/
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
[NotFound, [path]]
|
|
505
|
+
end
|
|
506
|
+
|
|
507
|
+
# The route maker, this is called by Camping internally, you shouldn't need to call it.
|
|
508
|
+
#
|
|
509
|
+
# Still, it's worth know what this method does. Since Ruby doesn't keep track of class
|
|
510
|
+
# creation order, we're keeping an internal list of the controllers which inherit from R().
|
|
511
|
+
# This method goes through and adds all the remaining routes to the beginning of the list
|
|
512
|
+
# and ensures all the controllers have the right mixins.
|
|
513
|
+
#
|
|
514
|
+
# Anyway, if you are calling the URI dispatcher from outside of a Camping server, you'll
|
|
515
|
+
# definitely need to call this at least once to set things up.
|
|
516
|
+
def M
|
|
517
|
+
def M #:nodoc:
|
|
518
|
+
end
|
|
519
|
+
constants.map { |c|
|
|
520
|
+
k=const_get(c)
|
|
521
|
+
k.send:include,C,Base,Models
|
|
522
|
+
r[0,0]=k if !r.include?k
|
|
523
|
+
k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls
|
|
524
|
+
}
|
|
525
|
+
end
|
|
526
|
+
end
|
|
527
|
+
|
|
439
528
|
# The NotFound class is a special controller class for handling 404 errors, in case you'd
|
|
440
529
|
# like to alter the appearance of the 404. The path is passed in as +p+.
|
|
441
530
|
#
|
|
@@ -451,7 +540,11 @@ module Camping
|
|
|
451
540
|
# end
|
|
452
541
|
# end
|
|
453
542
|
#
|
|
454
|
-
class NotFound
|
|
543
|
+
class NotFound < R()
|
|
544
|
+
def get(p)
|
|
545
|
+
r(404, Mab.new{h1(P);h2("#{p} not found")})
|
|
546
|
+
end
|
|
547
|
+
end
|
|
455
548
|
|
|
456
549
|
# The ServerError class is a special controller class for handling many (but not all) 500 errors.
|
|
457
550
|
# If there is a parse error in Camping or in your application's source code, it will not be caught
|
|
@@ -476,43 +569,18 @@ module Camping
|
|
|
476
569
|
# end
|
|
477
570
|
# end
|
|
478
571
|
#
|
|
479
|
-
class ServerError
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
# if id # edit
|
|
488
|
-
# else # new
|
|
489
|
-
# end
|
|
490
|
-
# end
|
|
491
|
-
# end
|
|
492
|
-
# end
|
|
493
|
-
#
|
|
494
|
-
# You will need to use routes in either of these cases:
|
|
495
|
-
#
|
|
496
|
-
# * You want to assign multiple routes to a controller.
|
|
497
|
-
# * You want your controller to receive arguments.
|
|
498
|
-
#
|
|
499
|
-
# Most of the time the rules inferred by dispatch method Controllers::D will get you
|
|
500
|
-
# by just fine.
|
|
501
|
-
def R(*urls); Class.new(R) { meta_def(:urls) { urls } }; end
|
|
502
|
-
|
|
503
|
-
# Dispatch routes to controller classes. Classes are searched in no particular order.
|
|
504
|
-
# For each class, routes are checked for a match based on their order in the routing list
|
|
505
|
-
# given to Controllers::R. If no routes were given, the dispatcher uses a slash followed
|
|
506
|
-
# by the name of the controller lowercased.
|
|
507
|
-
def D(path)
|
|
508
|
-
constants.inject(nil) do |d,c|
|
|
509
|
-
k = const_get(c)
|
|
510
|
-
k.meta_def(:urls){["/#{c.downcase}"]}if !(k<R)
|
|
511
|
-
d||([k, $~[1..-1]] if k.urls.find { |x| path =~ /^#{x}\/?$/ })
|
|
512
|
-
end||[NotFound, [path]]
|
|
572
|
+
class ServerError < R()
|
|
573
|
+
def get(k,m,e)
|
|
574
|
+
r(500, Mab.new {
|
|
575
|
+
h1(P)
|
|
576
|
+
h2 "#{k}.#{m}"
|
|
577
|
+
h3 "#{e.class} #{e.message}:"
|
|
578
|
+
ul { e.backtrace.each { |bt| li bt } }
|
|
579
|
+
}.to_s)
|
|
513
580
|
end
|
|
514
581
|
end
|
|
515
582
|
end
|
|
583
|
+
X = Controllers
|
|
516
584
|
|
|
517
585
|
class << self
|
|
518
586
|
# When you are running many applications, you may want to create independent
|
|
@@ -527,7 +595,7 @@ module Camping
|
|
|
527
595
|
# module Blog::Views; ... end
|
|
528
596
|
#
|
|
529
597
|
def goes(m)
|
|
530
|
-
|
|
598
|
+
eval S.gsub(/Camping/,m.to_s).gsub("A\pps = []","Cam\ping::Apps<<self"), TOPLEVEL_BINDING
|
|
531
599
|
end
|
|
532
600
|
|
|
533
601
|
# URL escapes a string.
|
|
@@ -535,14 +603,14 @@ module Camping
|
|
|
535
603
|
# Camping.escape("I'd go to the museum straightway!")
|
|
536
604
|
# #=> "I%27d+go+to+the+museum+straightway%21"
|
|
537
605
|
#
|
|
606
|
+
def escape(s); s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.unpack('H2'*$&.size)*'%').upcase}.tr(' ', '+') end
|
|
538
607
|
|
|
539
|
-
def escape(s); s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n){'%'+$1.unpack('H2'*$1.size).join('%').upcase}.tr(' ', '+') end
|
|
540
608
|
# Unescapes a URL-encoded string.
|
|
541
609
|
#
|
|
542
610
|
# Camping.un("I%27d+go+to+the+museum+straightway%21")
|
|
543
611
|
# #=> "I'd go to the museum straightway!"
|
|
544
612
|
#
|
|
545
|
-
def un(s); s.tr('+', ' ').gsub(
|
|
613
|
+
def un(s); s.tr('+', ' ').gsub(/%([\da-f]{2})/in){[$1].pack('H*')} end
|
|
546
614
|
|
|
547
615
|
# Parses a query string into an Camping::H object.
|
|
548
616
|
#
|
|
@@ -587,24 +655,40 @@ module Camping
|
|
|
587
655
|
# at the center, passing in the read +r+ and write +w+ streams. You will also need to mimick or
|
|
588
656
|
# pass in the <tt>ENV</tt> replacement as part of your wrapper.
|
|
589
657
|
#
|
|
590
|
-
#
|
|
591
|
-
# require 'fcgi'
|
|
592
|
-
# Camping::Models::Base.establish_connection :adapter => 'sqlite3',
|
|
593
|
-
# :database => 'blog3.db'
|
|
594
|
-
# Camping::Models::Base.logger = Logger.new('camping.log')
|
|
595
|
-
# FCGI.each do |req|
|
|
596
|
-
# req.out << Camping.run req.in, req.env
|
|
597
|
-
# req.finish
|
|
598
|
-
# end
|
|
599
|
-
# end
|
|
600
|
-
# end
|
|
658
|
+
# See Camping::FastCGI and Camping::WEBrick for examples.
|
|
601
659
|
#
|
|
602
660
|
def run(r=$stdin,e=ENV)
|
|
603
|
-
|
|
604
|
-
k.
|
|
605
|
-
k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).service
|
|
606
|
-
rescue =>
|
|
607
|
-
|
|
661
|
+
X.M
|
|
662
|
+
k,a=X.D un("/#{e['PATH_INFO']}".gsub(/\/+/,'/'))
|
|
663
|
+
k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.service *a
|
|
664
|
+
rescue Exception=>x
|
|
665
|
+
X::ServerError.new(r,e,'get').service(k,m,x)
|
|
666
|
+
end
|
|
667
|
+
|
|
668
|
+
# The Camping scriptable dispatcher. Any unhandled method call to the app module will
|
|
669
|
+
# be sent to a controller class, specified as an argument.
|
|
670
|
+
#
|
|
671
|
+
# Blog.get(:Index)
|
|
672
|
+
# #=> #<Blog::Controllers::Index ... >
|
|
673
|
+
#
|
|
674
|
+
# The controller object contains all the @cookies, @body, @headers, etc. formulated by
|
|
675
|
+
# the response.
|
|
676
|
+
#
|
|
677
|
+
# You can also feed environment variables and query variables as a hash, the final
|
|
678
|
+
# argument.
|
|
679
|
+
#
|
|
680
|
+
# Blog.post(:Login, :input => {'username' => 'admin', 'password' => 'camping'})
|
|
681
|
+
# #=> #<Blog::Controllers::Login @user=... >
|
|
682
|
+
#
|
|
683
|
+
# Blog.get(:Info, :env => {:HTTP_HOST => 'wagon'})
|
|
684
|
+
# #=> #<Blog::Controllers::Info @env={'HTTP_HOST'=>'wagon'} ...>
|
|
685
|
+
#
|
|
686
|
+
def method_missing(m, c, *a)
|
|
687
|
+
X.M
|
|
688
|
+
k = X.const_get(c).new(StringIO.new,
|
|
689
|
+
H['HTTP_HOST','','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s)
|
|
690
|
+
H.new(a.pop).each { |e,f| k.send("#{e}=",f) } if Hash === a[-1]
|
|
691
|
+
k.service *a
|
|
608
692
|
end
|
|
609
693
|
end
|
|
610
694
|
|
|
@@ -634,21 +718,8 @@ module Camping
|
|
|
634
718
|
#
|
|
635
719
|
# Models cannot be referred to in Views at this time.
|
|
636
720
|
module Models
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
# about this: *Base overloads table_name_prefix.* This means that if you have a
|
|
640
|
-
# model class Blog::Models::Post, it's table name will be <tt>blog_posts</tt>.
|
|
641
|
-
Base = A::Base
|
|
642
|
-
|
|
643
|
-
# The default prefix for Camping model classes is the topmost module name lowercase
|
|
644
|
-
# and followed with an underscore.
|
|
645
|
-
#
|
|
646
|
-
# Tepee::Models::Page.table_name_prefix
|
|
647
|
-
# #=> "tepee_pages"
|
|
648
|
-
#
|
|
649
|
-
def Base.table_name_prefix
|
|
650
|
-
"#{name[/^(\w+)/,1]}_".downcase.sub(/^(#{A}|camping)_/i,'')
|
|
651
|
-
end
|
|
721
|
+
autoload:Base,'camping/db'
|
|
722
|
+
def Y;self;end
|
|
652
723
|
end
|
|
653
724
|
|
|
654
725
|
# Views is an empty module for storing methods which create HTML. The HTML is described
|
|
@@ -672,3 +743,4 @@ module Camping
|
|
|
672
743
|
end
|
|
673
744
|
end
|
|
674
745
|
end
|
|
746
|
+
|