picnic 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +10 -0
- data/Manifest.txt +30 -13
- data/Rakefile +2 -0
- data/lib/picnic.rb +5 -120
- data/lib/picnic/authentication.rb +40 -4
- data/lib/picnic/cli.rb +86 -43
- data/lib/picnic/conf.rb +45 -43
- data/lib/picnic/logger.rb +41 -0
- data/lib/picnic/server.rb +99 -0
- data/lib/picnic/version.rb +2 -2
- data/picnic.gemspec +44 -0
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/CHANGELOG +17 -10
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/COPYING +0 -0
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/README +2 -2
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/Rakefile +62 -5
- data/vendor/camping-2.0.20090212/bin/camping +99 -0
- data/vendor/camping-2.0.20090212/doc/camping.1.gz +0 -0
- data/vendor/camping-2.0.20090212/examples/README +5 -0
- data/vendor/camping-2.0.20090212/examples/blog.rb +375 -0
- data/vendor/camping-2.0.20090212/examples/campsh.rb +629 -0
- data/vendor/camping-2.0.20090212/examples/tepee.rb +242 -0
- data/vendor/camping-2.0.20090212/extras/Camping.gif +0 -0
- data/vendor/camping-2.0.20090212/extras/flipbook_rdoc.rb +491 -0
- data/vendor/camping-2.0.20090212/extras/permalink.gif +0 -0
- data/vendor/{camping-1.5.180 → camping-2.0.20090212}/lib/camping-unabridged.rb +168 -294
- data/vendor/camping-2.0.20090212/lib/camping.rb +54 -0
- data/vendor/{camping-1.5.180/lib/camping/db.rb → camping-2.0.20090212/lib/camping/ar.rb} +4 -4
- data/vendor/{camping-1.5.180/lib/camping → camping-2.0.20090212/lib/camping/ar}/session.rb +23 -14
- data/vendor/camping-2.0.20090212/lib/camping/mab.rb +26 -0
- data/vendor/camping-2.0.20090212/lib/camping/reloader.rb +163 -0
- data/vendor/camping-2.0.20090212/lib/camping/server.rb +158 -0
- data/vendor/camping-2.0.20090212/lib/camping/session.rb +74 -0
- data/vendor/camping-2.0.20090212/setup.rb +1551 -0
- data/vendor/camping-2.0.20090212/test/apps/env_debug.rb +65 -0
- data/vendor/camping-2.0.20090212/test/apps/forms.rb +95 -0
- data/vendor/camping-2.0.20090212/test/apps/misc.rb +86 -0
- data/vendor/camping-2.0.20090212/test/apps/sessions.rb +38 -0
- data/vendor/camping-2.0.20090212/test/test_camping.rb +54 -0
- metadata +43 -16
- data/lib/picnic/postambles.rb +0 -292
- data/lib/picnic/utils.rb +0 -36
- data/vendor/camping-1.5.180/lib/camping.rb +0 -57
- data/vendor/camping-1.5.180/lib/camping/fastcgi.rb +0 -244
- data/vendor/camping-1.5.180/lib/camping/reloader.rb +0 -163
- data/vendor/camping-1.5.180/lib/camping/webrick.rb +0 -65
Binary file
|
@@ -21,14 +21,18 @@
|
|
21
21
|
# ActiveRecord is an object-to-relational database mapper with adapters
|
22
22
|
# for SQLite3, MySQL, PostgreSQL, SQL Server and more.
|
23
23
|
# * Markaby, used in your views to describe HTML in plain Ruby.
|
24
|
-
# * MetAid, a few metaprogramming methods which Camping uses.
|
25
|
-
# * Tempfile, for storing file uploads.
|
26
24
|
#
|
27
25
|
# Camping also works well with Mongrel, the swift Ruby web server.
|
28
26
|
# http://rubyforge.org/projects/mongrel Mongrel comes with examples
|
29
27
|
# in its <tt>examples/camping</tt> directory.
|
30
28
|
#
|
31
|
-
%w[
|
29
|
+
%w[uri stringio rack].map { |l| require l }
|
30
|
+
|
31
|
+
class Object #:nodoc:
|
32
|
+
def meta_def(m,&b) #:nodoc:
|
33
|
+
(class<<self;self end).send(:define_method,m,&b)
|
34
|
+
end
|
35
|
+
end
|
32
36
|
|
33
37
|
# == Camping
|
34
38
|
#
|
@@ -72,7 +76,6 @@
|
|
72
76
|
# unless Blog::Models::Post.table_exists?
|
73
77
|
# ActiveRecord::Schema.define do
|
74
78
|
# create_table :blog_posts, :force => true do |t|
|
75
|
-
# t.column :id, :integer, :null => false
|
76
79
|
# t.column :user_id, :integer, :null => false
|
77
80
|
# t.column :title, :string, :limit => 255
|
78
81
|
# t.column :body, :text
|
@@ -83,25 +86,17 @@
|
|
83
86
|
#
|
84
87
|
# For more tips, see http://code.whytheluckystiff.net/camping/wiki/GiveUsTheCreateMethod.
|
85
88
|
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 = []
|
94
89
|
C = self
|
95
|
-
S = IO.read(__FILE__)
|
96
|
-
P="Cam\ping Problem
|
97
|
-
|
98
|
-
|
99
|
-
# An object-like Hash
|
90
|
+
S = IO.read(__FILE__) rescue nil
|
91
|
+
P = "<h1>Cam\ping Problem!</h1><h2>%s</h2>"
|
92
|
+
U = Rack::Utils
|
93
|
+
Apps = []
|
94
|
+
# An object-like Hash.
|
100
95
|
# All Camping query string and cookie variables are loaded as this.
|
101
96
|
#
|
102
97
|
# To access the query string, for instance, use the <tt>@input</tt> variable.
|
103
98
|
#
|
104
|
-
# module Blog::
|
99
|
+
# module Blog::Controllers
|
105
100
|
# class Index < R '/'
|
106
101
|
# def get
|
107
102
|
# if page = @input.page.to_i > 0
|
@@ -118,8 +113,7 @@ module Camping
|
|
118
113
|
# to get the value for the <tt>page</tt> query variable.
|
119
114
|
#
|
120
115
|
# Use the <tt>@cookies</tt> variable in the same fashion to access cookie variables.
|
121
|
-
|
122
|
-
class H
|
116
|
+
class H < Hash
|
123
117
|
# Gets or sets keys in the hash.
|
124
118
|
#
|
125
119
|
# @cookies.my_favorite = :macadamian
|
@@ -127,9 +121,9 @@ module Camping
|
|
127
121
|
# => :macadamian
|
128
122
|
#
|
129
123
|
def method_missing(m,*a)
|
130
|
-
m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m]:
|
124
|
+
m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.to_s]:super
|
131
125
|
end
|
132
|
-
|
126
|
+
undef id, type
|
133
127
|
end
|
134
128
|
|
135
129
|
# Helpers contains methods available in your controllers and views. You may add
|
@@ -204,30 +198,15 @@ module Camping
|
|
204
198
|
#
|
205
199
|
def R(c,*g)
|
206
200
|
p,h=/\(.+?\)/,g.grep(Hash)
|
207
|
-
|
208
|
-
|
209
|
-
|
201
|
+
g-=h
|
202
|
+
raise "bad route" unless u = c.urls.find{|x|
|
203
|
+
break x if x.scan(p).size == g.size &&
|
204
|
+
/^#{x}\/?$/ =~ (x=g.inject(x){|x,a|
|
205
|
+
x.sub p,U.escape((a[a.class.primary_key]rescue a))})
|
206
|
+
}
|
207
|
+
h.any?? u+"?"+U.build_query(h[0]) : u
|
210
208
|
end
|
211
209
|
|
212
|
-
# Shows AR validation errors for the object passed.
|
213
|
-
# There is no output if there are no errors.
|
214
|
-
#
|
215
|
-
# An example might look like:
|
216
|
-
#
|
217
|
-
# errors_for @post
|
218
|
-
#
|
219
|
-
# Might (depending on actual data) render something like this in Markaby:
|
220
|
-
#
|
221
|
-
# ul.errors do
|
222
|
-
# li "Body can't be empty"
|
223
|
-
# li "Title must be unique"
|
224
|
-
# end
|
225
|
-
#
|
226
|
-
# Add a simple ul.errors {color:red; font-weight:bold;} CSS rule and you
|
227
|
-
# have built-in, usable error checking in only one line of code. :-)
|
228
|
-
#
|
229
|
-
# See AR validation documentation for details on validations.
|
230
|
-
def errors_for(o); ul.errors { o.errors.each_full { |er| li er } } if o.errors.any?; end
|
231
210
|
# Simply builds a complete path from a path +p+ within the app. If your application is
|
232
211
|
# mounted at <tt>/blog</tt>:
|
233
212
|
#
|
@@ -235,37 +214,32 @@ module Camping
|
|
235
214
|
# self / "styles.css" #=> "styles.css"
|
236
215
|
# self / R(Edit, 1) #=> "/blog/edit/1"
|
237
216
|
#
|
238
|
-
def /(p); p[
|
217
|
+
def /(p); p[0]==?/?@root+p:p end
|
239
218
|
# Builds a URL route to a controller or a path, returning a URI object.
|
240
219
|
# This way you'll get the hostname and the port number, a complete URL.
|
241
|
-
# No scheme is given (http or https).
|
242
220
|
#
|
243
221
|
# You can use this to grab URLs for controllers using the R-style syntax.
|
244
222
|
# So, if your application is mounted at <tt>http://test.ing/blog/</tt>
|
245
223
|
# and you have a View controller which routes as <tt>R '/view/(\d+)'</tt>:
|
246
224
|
#
|
247
|
-
# URL(View, @post.id) #=> #<URL://test.ing/blog/view/12>
|
225
|
+
# URL(View, @post.id) #=> #<URL:http://test.ing/blog/view/12>
|
248
226
|
#
|
249
227
|
# Or you can use the direct path:
|
250
228
|
#
|
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"
|
229
|
+
# self.URL #=> #<URL:http://test.ing/blog/>
|
230
|
+
# self.URL + "view/12" #=> #<URL:http://test.ing/blog/view/12>
|
231
|
+
# URL("/view/12") #=> #<URL:http://test.ing/blog/view/12>
|
258
232
|
#
|
259
233
|
# It's okay to pass URL strings through this method as well:
|
260
234
|
#
|
261
|
-
# URL("http://google.com") #=> #<
|
235
|
+
# URL("http://google.com") #=> #<URL:http://google.com>
|
262
236
|
#
|
263
237
|
# Any string which doesn't begin with a slash will pass through
|
264
238
|
# unscathed.
|
265
239
|
def URL c='/',*a
|
266
240
|
c = R(c, *a) if c.respond_to? :urls
|
267
241
|
c = self/c
|
268
|
-
c =
|
242
|
+
c = @request.url[/.{8,}?(?=\/)/]+c if c[0]==?/
|
269
243
|
URI(c)
|
270
244
|
end
|
271
245
|
end
|
@@ -304,9 +278,7 @@ module Camping
|
|
304
278
|
# end
|
305
279
|
#
|
306
280
|
module Base
|
307
|
-
|
308
|
-
attr_accessor :input, :cookies, :env, :headers, :body, :status, :root
|
309
|
-
Z = "\r\n"
|
281
|
+
attr_accessor :input, :cookies, :headers, :body, :status, :root
|
310
282
|
|
311
283
|
# Display a view, calling it by its method name +m+. If a <tt>layout</tt>
|
312
284
|
# method is found in Camping::Views, it will be used to wrap the HTML.
|
@@ -320,27 +292,51 @@ module Camping
|
|
320
292
|
# end
|
321
293
|
# end
|
322
294
|
#
|
323
|
-
|
324
|
-
|
325
|
-
# Any stray method calls will be passed to Markaby. This means you can reply
|
326
|
-
# with HTML directly from your controller for quick debugging.
|
295
|
+
# You can also return directly html by just passing a block
|
327
296
|
#
|
297
|
+
def render(v,*a,&b)
|
298
|
+
mab(/^_/!~v.to_s){send(v,*a,&b)}
|
299
|
+
end
|
300
|
+
|
301
|
+
# You can directly return HTML form your controller for quick debugging
|
302
|
+
# by calling this method and pass some Markaby to it.
|
303
|
+
#
|
328
304
|
# module Camping::Controllers
|
329
305
|
# class Info
|
330
|
-
# def get; code @
|
306
|
+
# def get; mab{ code @headers.inspect } end
|
331
307
|
# end
|
332
308
|
# end
|
333
309
|
#
|
334
|
-
#
|
335
|
-
#
|
336
|
-
def
|
337
|
-
a.shift if a[0]==:render
|
310
|
+
# You can also pass true to use the :layout HTML wrapping method
|
311
|
+
#
|
312
|
+
def mab(l=nil,&b)
|
338
313
|
m=Mab.new({},self)
|
339
|
-
s=m.capture
|
340
|
-
s=m.capture{
|
314
|
+
s=m.capture(&b)
|
315
|
+
s=m.capture{layout{s}} if l && m.respond_to?(:layout)
|
341
316
|
s
|
342
317
|
end
|
343
318
|
|
319
|
+
# A quick means of setting this controller's status, body and headers.
|
320
|
+
# Used internally by Camping, but... by all means...
|
321
|
+
#
|
322
|
+
# r(302, '', 'Location' => self / "/view/12")
|
323
|
+
#
|
324
|
+
# Is equivalent to:
|
325
|
+
#
|
326
|
+
# redirect "/view/12"
|
327
|
+
#
|
328
|
+
# You can also switch the body and the header in order to support Rack:
|
329
|
+
#
|
330
|
+
# r(302, {'Location' => self / "/view/12"}, '')
|
331
|
+
#
|
332
|
+
# See also: #r404, #r500 and #r501
|
333
|
+
def r(s, b, h = {})
|
334
|
+
b, h = h, b if Hash === b
|
335
|
+
@status = s
|
336
|
+
@headers.merge!(h)
|
337
|
+
@body = b
|
338
|
+
end
|
339
|
+
|
344
340
|
# Formulate a redirect response: a 302 status with <tt>Location</tt> header
|
345
341
|
# and a blank body. Uses Helpers#URL to build the location from a controller
|
346
342
|
# route or path.
|
@@ -354,19 +350,44 @@ module Camping
|
|
354
350
|
# You'll need to <tt>return redirect(...)</tt> if this isn't the last statement
|
355
351
|
# in your code.
|
356
352
|
def redirect(*a)
|
357
|
-
r(302,'','Location'=>URL(*a))
|
353
|
+
r(302,'','Location'=>URL(*a).to_s)
|
358
354
|
end
|
359
355
|
|
360
|
-
#
|
361
|
-
#
|
356
|
+
# Called when a controller was not found. It is mainly used internally, but it can
|
357
|
+
# also be useful for you, if you want to filter some parameters.
|
358
|
+
#
|
359
|
+
# module Camping
|
360
|
+
# def r404(p=env.PATH)
|
361
|
+
# @status = 404
|
362
|
+
# div do
|
363
|
+
# h1 'Camping Problem!'
|
364
|
+
# h2 "#{p} not found"
|
365
|
+
# end
|
366
|
+
# end
|
367
|
+
# end
|
362
368
|
#
|
363
|
-
#
|
369
|
+
# See: I
|
370
|
+
def r404(p=env.PATH)
|
371
|
+
r(404, P % "#{p} not found")
|
372
|
+
end
|
373
|
+
|
374
|
+
# If there is a parse error in Camping or in your application's source code, it will not be caught
|
375
|
+
# by Camping. The controller class +k+ and request method +m+ (GET, POST, etc.) where the error
|
376
|
+
# took place are passed in, along with the Exception +e+ which can be mined for useful info.
|
364
377
|
#
|
365
|
-
#
|
378
|
+
# You can overide it, but if you have an error in here, it will be uncaught !
|
366
379
|
#
|
367
|
-
#
|
380
|
+
# See: I
|
381
|
+
def r500(k,m,x)
|
382
|
+
r(500, P % "#{k}.#{m}" + "<h3>#{x.class} #{x.message}: <ul>#{x.backtrace.map{|b|"<li>#{b}</li>"}}</ul></h3>")
|
383
|
+
end
|
384
|
+
|
385
|
+
# Called if an undefined method is called on a Controller, along with the request method +m+ (GET, POST, etc.)
|
368
386
|
#
|
369
|
-
|
387
|
+
# See: I
|
388
|
+
def r501(m=@method)
|
389
|
+
r(501, P % "#{m.upcase} not implemented")
|
390
|
+
end
|
370
391
|
|
371
392
|
# Turn a controller into an array. This is designed to be used to pipe
|
372
393
|
# controllers into the <tt>r</tt> method. A great way to forward your
|
@@ -376,55 +397,36 @@ module Camping
|
|
376
397
|
# def get(id)
|
377
398
|
# Post.find(id)
|
378
399
|
# rescue
|
379
|
-
# r *Blog.get(:NotFound, @
|
400
|
+
# r *Blog.get(:NotFound, @headers.REQUEST_URI)
|
380
401
|
# end
|
381
402
|
# end
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
o=if fh[:filename]
|
408
|
-
o=fh[:tempfile]=Tempfile.new(:C)
|
409
|
-
o.binmode
|
410
|
-
else
|
411
|
-
fh=""
|
412
|
-
end
|
413
|
-
while l=@in.read(16384)
|
414
|
-
if l=~b
|
415
|
-
o<<$`.chomp
|
416
|
-
@in.seek(-$'.size,IO::SEEK_CUR)
|
417
|
-
break
|
418
|
-
end
|
419
|
-
o<<l
|
420
|
-
end
|
421
|
-
C.qsp(fn,'&;',fh,qs) if fn
|
422
|
-
fh[:tempfile].rewind if fh.is_a?H
|
403
|
+
def to_a
|
404
|
+
@response.body = (@body.respond_to?(:each) ? @body : '')
|
405
|
+
@response.status = @status
|
406
|
+
@response.headers.merge!(@headers)
|
407
|
+
@cookies.each do |k, v|
|
408
|
+
v = {:value => v, :path => self / "/"} if String===v
|
409
|
+
@response.set_cookie(k, v) if @request.cookies[k] != v
|
410
|
+
end
|
411
|
+
@response.to_a
|
412
|
+
end
|
413
|
+
|
414
|
+
def initialize(env) #:nodoc:
|
415
|
+
@request, @response, @env =
|
416
|
+
Rack::Request.new(env), Rack::Response.new, env
|
417
|
+
@root, @input, @cookies,
|
418
|
+
@headers, @status =
|
419
|
+
@env.SCRIPT_NAME.sub(/\/$/,''),
|
420
|
+
H[@request.params], H[@request.cookies],
|
421
|
+
@response.headers, @response.status
|
422
|
+
|
423
|
+
@input.each do |k, v|
|
424
|
+
if k[-2..-1] == "[]"
|
425
|
+
@input[k[0..-3]] = @input.delete(k)
|
426
|
+
elsif k =~ /(.*)\[([^\]]+)\]$/
|
427
|
+
(@input[$1] ||= H[])[$2] = @input.delete(k)
|
423
428
|
end
|
424
|
-
elsif @method == "post"
|
425
|
-
qs.merge!(C.qsp(@in.read))
|
426
429
|
end
|
427
|
-
@cookies, @input = @k.dup, qs.dup
|
428
430
|
end
|
429
431
|
|
430
432
|
# All requests pass through this method before going to the controller. Some magic
|
@@ -433,21 +435,10 @@ module Camping
|
|
433
435
|
# See http://code.whytheluckystiff.net/camping/wiki/BeforeAndAfterOverrides for more
|
434
436
|
# on before and after overrides with Camping.
|
435
437
|
def service(*a)
|
436
|
-
|
437
|
-
@
|
438
|
-
"#{k}=#{C.escape(v[:value] || v)}; path=#{self/"/"}; expires=#{v[:expires] && v[:expires].strftime('%a, %d-%b-%Y %H:%M:%S %Z') || nil}" if v != @k[k]
|
439
|
-
} - [nil]
|
438
|
+
r = catch(:halt){send(@env.REQUEST_METHOD.downcase, *a)}
|
439
|
+
@body ||= r
|
440
440
|
self
|
441
441
|
end
|
442
|
-
|
443
|
-
# Used by the web server to convert the current request to a string. If you need to
|
444
|
-
# alter the way Camping builds HTTP headers, consider overriding this method.
|
445
|
-
def to_s
|
446
|
-
a=[]
|
447
|
-
@headers.map{|k,v|[*v].map{|x|a<<"#{k}: #{x}"}}
|
448
|
-
"Status: #{@status}#{Z+a*Z+Z*2+@body}"
|
449
|
-
end
|
450
|
-
|
451
442
|
end
|
452
443
|
|
453
444
|
# Controllers is a module for placing classes which handle URLs. This is done
|
@@ -463,15 +454,10 @@ module Camping
|
|
463
454
|
# If no route is set, Camping will guess the route from the class name.
|
464
455
|
# The rule is very simple: the route becomes a slash followed by the lowercased
|
465
456
|
# class name. See Controllers::D for the complete rules of dispatch.
|
466
|
-
#
|
467
|
-
# == Special classes
|
468
|
-
#
|
469
|
-
# There are two special classes used for handling 404 and 500 errors. The
|
470
|
-
# NotFound class handles URLs not found. The ServerError class handles exceptions
|
471
|
-
# uncaught by your application.
|
472
457
|
module Controllers
|
473
458
|
@r = []
|
474
459
|
class << self
|
460
|
+
# An array containing the various controllers available for dispatch.
|
475
461
|
def r #:nodoc:
|
476
462
|
@r
|
477
463
|
end
|
@@ -513,15 +499,18 @@ module Camping
|
|
513
499
|
# # Classes with routes are searched in order of their creation.
|
514
500
|
#
|
515
501
|
# So, define your catch-all controllers last.
|
516
|
-
def D(
|
502
|
+
def D(p, m)
|
503
|
+
p = '/' if !p || !p[0]
|
517
504
|
r.map { |k|
|
518
505
|
k.urls.map { |x|
|
519
|
-
return k
|
506
|
+
return (k.instance_method(m) rescue nil) ?
|
507
|
+
[k, m, *$~[1..-1]] : [I, 'r501', m] if p =~ /^#{x}\/?$/
|
520
508
|
}
|
521
509
|
}
|
522
|
-
[
|
510
|
+
[I, 'r404', p]
|
523
511
|
end
|
524
512
|
|
513
|
+
N = H.new { |_,x| x.downcase }.merge! "N" => '(\d+)', "X" => '(\w+)', "Index" => ''
|
525
514
|
# The route maker, this is called by Camping internally, you shouldn't need to call it.
|
526
515
|
#
|
527
516
|
# Still, it's worth know what this method does. Since Ruby doesn't keep track of class
|
@@ -536,66 +525,15 @@ module Camping
|
|
536
525
|
end
|
537
526
|
constants.map { |c|
|
538
527
|
k=const_get(c)
|
539
|
-
k.send :include,C,Base,Models
|
540
|
-
r[
|
541
|
-
k.meta_def(:urls){["/#{c.
|
528
|
+
k.send :include,C,Base,Helpers,Models
|
529
|
+
@r=[k]+r if r-[k]==r
|
530
|
+
k.meta_def(:urls){["/#{c.scan(/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.respond_to?:urls
|
542
531
|
}
|
543
532
|
end
|
544
533
|
end
|
545
534
|
|
546
|
-
#
|
547
|
-
|
548
|
-
#
|
549
|
-
# module Camping::Controllers
|
550
|
-
# class NotFound
|
551
|
-
# def get(p)
|
552
|
-
# @status = 404
|
553
|
-
# div do
|
554
|
-
# h1 'Camping Problem!'
|
555
|
-
# h2 "#{p} not found"
|
556
|
-
# end
|
557
|
-
# end
|
558
|
-
# end
|
559
|
-
# end
|
560
|
-
#
|
561
|
-
class NotFound < R()
|
562
|
-
def get(p)
|
563
|
-
r(404, Mab.new{h1(P);h2("#{p} not found")})
|
564
|
-
end
|
565
|
-
end
|
566
|
-
|
567
|
-
# The ServerError class is a special controller class for handling many (but not all) 500 errors.
|
568
|
-
# If there is a parse error in Camping or in your application's source code, it will not be caught
|
569
|
-
# by Camping. The controller class +k+ and request method +m+ (GET, POST, etc.) where the error
|
570
|
-
# took place are passed in, along with the Exception +e+ which can be mined for useful info.
|
571
|
-
#
|
572
|
-
# module Camping::Controllers
|
573
|
-
# class ServerError
|
574
|
-
# def get(k,m,e)
|
575
|
-
# @status = 500
|
576
|
-
# div do
|
577
|
-
# h1 'Camping Problem!'
|
578
|
-
# h2 "in #{k}.#{m}"
|
579
|
-
# h3 "#{e.class} #{e.message}:"
|
580
|
-
# ul do
|
581
|
-
# e.backtrace.each do |bt|
|
582
|
-
# li bt
|
583
|
-
# end
|
584
|
-
# end
|
585
|
-
# end
|
586
|
-
# end
|
587
|
-
# end
|
588
|
-
# end
|
589
|
-
#
|
590
|
-
class ServerError < R()
|
591
|
-
def get(k,m,e)
|
592
|
-
r(500, Mab.new {
|
593
|
-
h1(P)
|
594
|
-
h2 "#{k}.#{m}"
|
595
|
-
h3 "#{e.class} #{e.message}:"
|
596
|
-
ul { e.backtrace.each { |bt| li bt } }
|
597
|
-
}.to_s)
|
598
|
-
end
|
535
|
+
# Internal controller with no route. Used by #D and C.call to show internal messages.
|
536
|
+
class I < R()
|
599
537
|
end
|
600
538
|
end
|
601
539
|
X = Controllers
|
@@ -613,74 +551,18 @@ module Camping
|
|
613
551
|
# module Blog::Views; ... end
|
614
552
|
#
|
615
553
|
def goes(m)
|
616
|
-
eval
|
554
|
+
Apps << eval(S.gsub(/Camping/,m.to_s), TOPLEVEL_BINDING)
|
617
555
|
end
|
618
|
-
|
619
|
-
#
|
620
|
-
#
|
621
|
-
#
|
622
|
-
|
623
|
-
#
|
624
|
-
def escape(s); s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.unpack('H2'*$&.size)*'%').upcase}.tr(' ', '+') end
|
625
|
-
|
626
|
-
# Unescapes a URL-encoded string.
|
627
|
-
#
|
628
|
-
# Camping.un("I%27d+go+to+the+museum+straightway%21")
|
629
|
-
# #=> "I'd go to the museum straightway!"
|
630
|
-
#
|
631
|
-
def un(s); s.tr('+', ' ').gsub(/%([\da-f]{2})/in){[$1].pack('H*')} end
|
632
|
-
|
633
|
-
# Parses a query string into an Camping::H object.
|
634
|
-
#
|
635
|
-
# input = Camping.qsp("name=Philarp+Tremain&hair=sandy+blonde")
|
636
|
-
# input.name
|
637
|
-
# #=> "Philarp Tremaine"
|
638
|
-
#
|
639
|
-
# Also parses out the Hash-like syntax used in PHP and Rails and builds
|
640
|
-
# nested hashes from it.
|
641
|
-
#
|
642
|
-
# input = Camping.qsp("post[id]=1&post[user]=_why")
|
643
|
-
# #=> {'post' => {'id' => '1', 'user' => '_why'}}
|
644
|
-
#
|
645
|
-
def qsp(qs, d='&;', y=nil, z=H[])
|
646
|
-
m = proc {|_,o,n|o.u(n,&m)rescue([*o]<<n)}
|
647
|
-
(qs||'').
|
648
|
-
split(/[#{d}] */n).
|
649
|
-
inject((b,z=z,H[])[0]) { |h,p| k, v=un(p).split('=',2)
|
650
|
-
h.u(k.split(/[\]\[]+/).reverse.
|
651
|
-
inject(y||v) { |x,i| H[i,x] },&m)
|
652
|
-
}
|
653
|
-
end
|
654
|
-
|
655
|
-
# Parses a string of cookies from the <tt>Cookie</tt> header.
|
656
|
-
def kp(s); c = qsp(s, ';,'); end
|
657
|
-
|
658
|
-
# Fields a request through Camping. For traditional CGI applications, the method can be
|
659
|
-
# executed without arguments.
|
660
|
-
#
|
661
|
-
# if __FILE__ == $0
|
662
|
-
# Camping::Models::Base.establish_connection :adapter => 'sqlite3',
|
663
|
-
# :database => 'blog3.db'
|
664
|
-
# Camping::Models::Base.logger = Logger.new('camping.log')
|
665
|
-
# puts Camping.run
|
666
|
-
# end
|
667
|
-
#
|
668
|
-
# The Camping controller returned from <tt>run</tt> has a <tt>to_s</tt> method in case you
|
669
|
-
# are running from CGI or want to output the full HTTP output. In the above example, <tt>puts</tt>
|
670
|
-
# will call <tt>to_s</tt> for you.
|
671
|
-
#
|
672
|
-
# For FastCGI and Webrick-loaded applications, you will need to use a request loop, with <tt>run</tt>
|
673
|
-
# at the center, passing in the read +r+ and write +w+ streams. You will also need to mimick or
|
674
|
-
# pass in the <tt>ENV</tt> replacement as part of your wrapper.
|
675
|
-
#
|
676
|
-
# See Camping::FastCGI and Camping::WEBrick for examples.
|
677
|
-
#
|
678
|
-
def run(r=$stdin,e=ENV)
|
556
|
+
|
557
|
+
# Ruby web servers use this method to enter the Camping realm. The e
|
558
|
+
# argument is the environment variables hash as per the Rack specification.
|
559
|
+
# And array with [statuc, headers, body] is expected at the output.
|
560
|
+
def call(e)
|
679
561
|
X.M
|
680
|
-
|
681
|
-
k.
|
682
|
-
|
683
|
-
|
562
|
+
e = H[e.to_hash]
|
563
|
+
k,m,*a=X.D e.PATH_INFO,(e.REQUEST_METHOD||'get').downcase
|
564
|
+
e.REQUEST_METHOD = m
|
565
|
+
k.new(e).service(*a).to_a
|
684
566
|
end
|
685
567
|
|
686
568
|
# The Camping scriptable dispatcher. Any unhandled method call to the app module will
|
@@ -698,18 +580,28 @@ module Camping
|
|
698
580
|
# Blog.post(:Login, :input => {'username' => 'admin', 'password' => 'camping'})
|
699
581
|
# #=> #<Blog::Controllers::Login @user=... >
|
700
582
|
#
|
701
|
-
# Blog.get(:Info, :env => {
|
702
|
-
# #=> #<Blog::Controllers::Info @
|
583
|
+
# Blog.get(:Info, :env => {'HTTP_HOST' => 'wagon'})
|
584
|
+
# #=> #<Blog::Controllers::Info @headers={'HTTP_HOST'=>'wagon'} ...>
|
703
585
|
#
|
704
586
|
def method_missing(m, c, *a)
|
705
587
|
X.M
|
706
|
-
|
707
|
-
|
708
|
-
|
709
|
-
k.
|
588
|
+
h=Hash===a[-1]?H[a.pop]:{}
|
589
|
+
e=H[h[:env]||{}].merge!({'rack.input'=>StringIO.new,'REQUEST_METHOD'=>m.to_s})
|
590
|
+
k = X.const_get(c).new(H[e])
|
591
|
+
k.send("input=",h[:input]) if h[:input]
|
592
|
+
k.service(*a)
|
710
593
|
end
|
711
594
|
end
|
712
595
|
|
596
|
+
# Views is an empty module for storing methods which create HTML. The HTML is described
|
597
|
+
# using the Markaby language.
|
598
|
+
#
|
599
|
+
# == Using the layout method
|
600
|
+
#
|
601
|
+
# If your Views module has a <tt>layout</tt> method defined, it will be called with a block
|
602
|
+
# which will insert content from your view.
|
603
|
+
module Views; include X, Helpers end
|
604
|
+
|
713
605
|
# Models is an empty Ruby module for housing model classes derived
|
714
606
|
# from ActiveRecord::Base. As a shortcut, you may derive from Base
|
715
607
|
# which is an alias for ActiveRecord::Base.
|
@@ -736,29 +628,11 @@ module Camping
|
|
736
628
|
#
|
737
629
|
# Models cannot be referred to in Views at this time.
|
738
630
|
module Models
|
739
|
-
autoload :Base,'camping/
|
631
|
+
autoload :Base,'camping/ar'
|
740
632
|
def Y;self;end
|
741
633
|
end
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
#
|
746
|
-
# == Using the layout method
|
747
|
-
#
|
748
|
-
# If your Views module has a <tt>layout</tt> method defined, it will be called with a block
|
749
|
-
# which will insert content from your view.
|
750
|
-
module Views; include Controllers, Helpers end
|
751
|
-
|
752
|
-
# The Mab class wraps Markaby, allowing it to run methods from Camping::Views
|
753
|
-
# and also to replace :href, :action and :src attributes in tags by prefixing the root
|
754
|
-
# path.
|
755
|
-
class Mab < Markaby::Builder
|
756
|
-
include Views
|
757
|
-
def tag!(*g,&b)
|
758
|
-
h=g[-1]
|
759
|
-
[:href,:action,:src].each{|a|(h[a]=self/h[a])rescue 0}
|
760
|
-
super
|
761
|
-
end
|
762
|
-
end
|
634
|
+
|
635
|
+
autoload :Mab, 'camping/mab'
|
636
|
+
C
|
763
637
|
end
|
764
638
|
|