camping 1.4.2 → 1.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|