picnic 0.7.1 → 0.8.0
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/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
|
|