| CODENOTIFIER | HelpYou are not signed inSign in |
Project: Camping
Revision: 237
Author: zimbatm
Date: 03 Oct 2007 00:23:16
Diff at Trac: http://code.whytheluckystiff.net/camping/changeset/237
Changes:* Introduced error 501 handling and changed NotFound and ServerError controllers to #r404 and #r500 methods. camping.rb is exactly at 4000 octets !
* Some doc fixes in man page, README, CHANGELOG. Unfortunately the rdoc are still badly parsed.
| ... | ...@@ -93,7 +93,7 @@ | |
| 93 | 93 | Camping comes with an tool for launching apps from the commandline: |
| 94 | 94 | |
| 95 | 95 | * Run: <tt>camping blog.rb</tt> |
| 96 | * Visit http://localhost:3301/blog/ to use the app. | |
| 96 | * Visit http://localhost:3301/ to use the app. | |
| 97 | 97 | |
| 98 | 98 | == How the Camping Tool Works |
| 99 | 99 |
| ... | ...@@ -28,6 +28,7 @@ | |
| 28 | 28 | class BadLinks |
| 29 | 29 | def get; render :bad_links; end |
| 30 | 30 | end |
| 31 | class BadMethod; end | |
| 31 | 32 | end |
| 32 | 33 | |
| 33 | 34 | module Views |
| ... | ...@@ -42,6 +43,7 @@ | |
| 42 | 43 | li{ a "Links", :href=>R(Links)} |
| 43 | 44 | li{ a "BadLinks", :href=>R(BadLinks)} |
| 44 | 45 | li{ a "Redirect", :href=>R(Redirect)} |
| 46 | li{ a "BadMethod", :href=>R(BadMethod)} | |
| 45 | 47 | end |
| 46 | 48 | p { yield } |
| 47 | 49 | end |
| ... | ...@@ -146,7 +146,6 @@ | |
| 146 | 146 | end |
| 147 | 147 | if File.size("lib/camping.rb") > SIZE_LIMIT |
| 148 | 148 | STDERR.puts "lib/camping.rb: file is too big (> #{SIZE_LIMIT})" |
| 149 | exit 1 | |
| 150 | 149 | end |
| 151 | 150 | end |
| 152 | 151 | |
| ... | ...@@ -155,7 +154,7 @@ | |
| 155 | 154 | i = 1 |
| 156 | 155 | File.open("lib/camping.rb").each_line do |line| |
| 157 | 156 | if line.size > 81 # 1 added for \n |
| 158 | puts "lib/camping.rb:#{i}: line too long (#{line[-10..-1].inspect})" | |
| 157 | STDERR.puts "lib/camping.rb:#{i}: line too long (#{line[-10..-1].inspect})" | |
| 159 | 158 | end |
| 160 | 159 | i += 1 |
| 161 | 160 | end |
| ... | ...@@ -5,7 +5,6 @@ | |
| 5 | 5 | require 'stringio' |
| 6 | 6 | require 'yaml' |
| 7 | 7 | |
| 8 | begin require 'rubygems' rescue LoadError end | |
| 9 | 8 | require 'camping' |
| 10 | 9 | require 'camping/server' |
| 11 | 10 |
| ... | ...@@ -1,58 +1,61 @@ | |
| 1 | %w[tempfile uri].map{|l|require l};class Object;def meta_def m,&b | |
| 2 | (class<<self;self end).send(:define_method,m,&b)end end | |
| 3 | module Camping;C=self;S=IO.read(__FILE__)rescue nil;P="Cam\ping Problem!" | |
| 4 | class H<Hash;def method_missing m,*a | |
| 5 | m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.to_s]:super end;alias u merge! | |
| 6 | undef id, type;end | |
| 7 | module Helpers def R c,*g;p,h=/\(.+?\)/,g.grep(Hash);g-=h; | |
| 8 | raise"bad route"unless u=c.urls.find{|x|break x if x.scan(p).size==g.size&& | |
| 9 | /^#{x}\/?$/=~(x=g.inject(x){|x,a|x.sub p,C.escape((a[a.class.primary_key | |
| 10 | ]rescue a))})} | |
| 11 | h.any?? u+"?"+h[0].map{|x|x.map{|z|C.escape z}*"="}*"&":u end | |
| 12 | def /(p);p[/^\//]?@root+p:p;end;def URL c='/',*a | |
| 13 | c=R(c,*a)if c.respond_to?:urls;c=self/c;c="//"+@env.HTTP_HOST+c if c[/^\//] | |
| 14 | URI(c) end end;module Base;attr_accessor:input,:cookies,:env,:headers,:body, | |
| 15 | :status,:root;Z="\r\n";def method_missing*a,&b;a.shift if a[0]==:render | |
| 16 | m=Mab.new({},self);s=m.capture{send(*a,&b)};s=m.capture{send(:layout){s}}if | |
| 17 | /^_/!~a[0].to_s and m.respond_to?:layout;s end;def redirect*a | |
| 18 | r 302,'','Location'=>URL(*a)end;def r s,b,h={};@status=s;headers.u h | |
| 19 | @body=b end;def to_a;[status,body,headers]end;def initialize r,e,m | |
| 20 | @status,@method,@env,@headers,@root=200,m.downcase,e,H[ | |
| 21 | 'Content-Type',"text/html"],e.SCRIPT_NAME.sub(/\/$/,'');@k=C.kp e.HTTP_COOKIE | |
| 22 | q=C.qsp e.QUERY_STRING;@in=r;case e.CONTENT_TYPE | |
| 23 | when %r|\Amultipart/form-.*boundary=\"?([^\";,]+)|n | |
| 24 | b=/(?:\r?\n|\A)#{Regexp::quote"--#$1"}(?:--)?\r$/;until | |
| 25 | @in.eof?;fh=H[];for l in@in;case l;when Z;break;when/^Content-D.+?: form-data;/ | |
| 26 | fh.u H[*$'.scan(/(?:\s(\w+)="([^"]+)")/).flatten];when | |
| 27 | /^Content-Type: (.+?)(\r$|\Z)/m;fh.type=$1;end;end;fn=fh.name;o=if fh. | |
| 28 | filename;o=fh.tempfile=Tempfile.new(:C);o.binmode;else;fh=""end;s=8192;k='' | |
| 29 | l=@in.read(s*2);while l;if(k<<l)=~b;o<<$`.chomp;@in.seek(-$'.size,IO::SEEK_CUR) | |
| 30 | break;end;o<<k.slice!(0...s);l=@in.read(s);end;C.qsp(fn,'&;',fh,q)if fn;fh. | |
| 31 | tempfile.rewind if fh.is_a?H;end;when "application/x-www-form-urlencoded" | |
| 32 | q.u C.qsp(@in.read)end;@cookies,@input=@k.dup,q.dup end;def service*a | |
| 33 | @body=send(@method,*a)if respond_to?@method | |
| 34 | headers["Set-Cookie"]=cookies.map{|k,v|"#{k}=#{C.escape v}; path=#{self/'/'}"if | |
| 35 | v!=@k[k]}-[nil];self end;def to_s;"Status: #@status#{Z+headers.map{|k,v|[*v]. | |
| 36 | map{|x|[k,v]*": "}}*Z+Z}#@body"end;end;X=module Controllers;@r=[];class<< | |
| 37 | self;def r;@r;end;def R*u;r=@r;Class.new{meta_def(:urls){u};meta_def(:inherited | |
| 38 | ){|x|r<<x}}end;def D p;r.map{|k|k.urls.map{|x|return k,$~[1..-1]if p=~/^#{x | |
| 39 | }\/?$/}};[NotFound,[p]]end;def M;def M;end;constants.map{|c|k=const_get(c);k. | |
| 40 | send:include,C,Base,Helpers,Models;r[0,0]=k if !r.include?k;k.meta_def(:urls){[ | |
| 41 | "/#{c.downcase}"]}if !k.respond_to?:urls}end;end;class NotFound<R();def get p | |
| 42 | r(404,"<h1>#{P}</h1><h2>#{p} not found</h2>")end end;class ServerError<R() | |
| 43 | def get k,m,e;r(500,"<h1>#{P}</h1><h2>#{k}.#{m}</h2><h3>#{e.class} #{e.message | |
| 44 | }:<ul>#{e.backtrace.map{ |b| "<li>#{b}</li>" } }")end end;self;end;class<<self | |
| 45 | def goes m;eval S.gsub(/Camping/,m.to_s),TOPLEVEL_BINDING;end;def escape s | |
| 46 | s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.unpack('H2'*$&.size)*'%').upcase}.tr(' ','+') | |
| 47 | end;def un s;s.tr('+',' ').gsub(/%([\da-f]{2})/in){[$1].pack('H*')}end | |
| 1 | %w[tempfile uri].map{|l|require l};class Object;def meta_def m,&b;(class<<self | |
| 2 | self end).send:define_method,m,&b end end;module Camping;C=self | |
| 3 | S=IO.read(__FILE__)rescue nil;P="<h1>Cam\\ping Problem!</h1><h2>%s</h2>" | |
| 4 | class H<Hash | |
| 5 | def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.to_s]:super end | |
| 6 | alias u merge!;undef id,type;end;module Helpers;def R c,*g | |
| 7 | p,h=/\(.+?\)/,g.grep(Hash);g-=h;raise"bad route"unless u=c.urls.find{|x| | |
| 8 | break x if x.scan(p).size==g.size&&/^#{x}\/?$/=~(x=g.inject(x){|x,a| | |
| 9 | x.sub p,C.escape((a[a.class.primary_key]rescue a))})} | |
| 10 | h.any?? u+"?"+h[0].map{|x|x.map{|z|C.escape z}*"="}*"&":u end;def / p | |
| 11 | p[/^\//]?@root+p:p end;def URL c='/',*a;c=R(c, *a) if c.respond_to?:urls | |
| 12 | c=self/c;c="//"+@env.HTTP_HOST+c if c[/^\//];URI c end end;module Base | |
| 13 | attr_accessor:input,:cookies,:env,:headers,:body,:status,:root;Z="\r\n" | |
| 14 | def method_missing *a,&b;a.shift if a[0]==:render;m=Mab.new({},self) | |
| 15 | s=m.capture{send(*a,&b)};s=m.capture{send(:layout){s}}if/^_/!~a[0].to_s and | |
| 16 | m.respond_to?:layout;s end;def r s,b,h={};@status=s;headers.u(h);@body=b | |
| 17 | end;def redirect *a;r 302,'','Location'=>URL(*a)end;def r404 p=env.PATH | |
| 18 | r 404,P%"#{p} not found"end;def r500 k,m,x | |
| 19 | r 500,P%"#{k}.#{m}"+"<h3>#{x.class} #{x.message}: <ul>#{x. | |
| 20 | backtrace.map{|b|"<li>#{b}</li>"}}</ul></h3>"end;def r501 m=@method | |
| 21 | r 501,P%"#{m.upcase} not implemented"end;def to_a | |
| 22 | [status,body,headers]end;def initialize r,e,m;@status,@method,@env,@headers, | |
| 23 | @root=200,m,e,H['Content-Type','text/html'],e.SCRIPT_NAME.sub(/\/$/,'') | |
| 24 | @k=C.kp e.HTTP_COOKIE;q=C.qsp e.QUERY_STRING;@in=r;case e.CONTENT_TYPE | |
| 25 | when%r|\Amultipart/form-.*boundary=\"?([^\";,]+)|n | |
| 26 | b=/(?:\r?\n|\A)#{Regexp.quote"--#$1"}(?:--)?\r$/;until@in.eof?;fh=H[] | |
| 27 | for l in@in;case l;when Z;break;when/^Content-D.+?: form-data;/ | |
| 28 | fh.u H[*$'.scan(/(?:\s(\w+)="([^"]+)")/).flatten] | |
| 29 | when/^Content-Type: (.+?)(\r$|\Z)/m: fh.type = $1 end end;fn=fh.name | |
| 30 | o=if fh.filename;o=fh.tempfile=Tempfile.new(:C);o.binmode;else;fh="";end;s=8192 | |
| 31 | k='';l=@in.read(s*2);while l;if(k<<l)=~b;o<<$`.chomp | |
| 32 | @in.seek(-$'.size,IO::SEEK_CUR);break end;o<<k.slice!(0...s);l=@in.read(s) end | |
| 33 | C.qsp(fn,'&;',fh,q)if fn;fh.tempfile.rewind if fh.is_a?H end;when | |
| 34 | "application/x-www-form-urlencoded": q.u(C.qsp(@in.read))end | |
| 35 | @cookies,@input=@k.dup,q.dup end;def service *a;@body=send @method,*a | |
| 36 | headers['Set-Cookie']=cookies.map{|k,v|"#{k}=#{C.escape(v)}; path=#{self/ | |
| 37 | "/"}"if v!=@k[k]}-[nil];self end;def to_s | |
| 38 | "Status: #@status#{Z+headers.map{|k,v|[*v].map{|x|[k,v]*": "}}*Z+Z}#@body"end | |
| 39 | end;X=module Controllers;@r=[];class<<self;def r;@r end;def R *u;r=@r | |
| 40 | Class.new{meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end | |
| 41 | def D p,m;r.map{|k|k.urls.map{|x|return(k.instance_method(m)rescue nil)? | |
| 42 | [k,m,*$~[1..-1]]:[I,'r501',m]if p=~/^#{x}\/?$/}};[I,'r404',p] | |
| 43 | end;def M;def M;end;constants.map{|c|k=const_get(c) | |
| 44 | k.send:include,C,Base,Helpers,Models;@r=[k]+r if r-[k]==r | |
| 45 | k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls}end end;class I<R() | |
| 46 | end;self end;class<<self;def goes m | |
| 47 | eval S.gsub(/Camping/,m.to_s),TOPLEVEL_BINDING end;def escape s | |
| 48 | s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.unpack('H2'*$&.size)*'%').upcase}.tr' ','+' | |
| 49 | end;def un s;s.tr('+',' ').gsub(/%([\da-f]{2})/in){[$1].pack'H*'}end | |
| 48 | 50 | def qsp q,d='&;',y=nil,z=H[];m=proc{|_,o,n|o.u(n,&m)rescue([*o]<<n)} |
| 49 | (q.to_s.split(/[#{d}]+ */n)-['']).inject((b,z=z,H[])[0]){|h,p|k,v=un(p). | |
| 50 | split('=',2);h.u k.split(/[\]\[]+/).reverse.inject(y||v){|x,i|H[i,x]},&m}end | |
| 51 | def kp s;c=qsp(s,';,')end;def run r=$stdin,e=ENV;X.M;e=H[e.to_hash] | |
| 52 | k,a=X.D e.PATH_INFO=un("/#{e.PATH_INFO}".gsub(/\/+/,'/'));k.new( | |
| 53 | r,e,(m=e.REQUEST_METHOD||"GET")).Y.service(*a);rescue=>x;X::ServerError.new( | |
| 54 | r,e,'get').service(k,m,x)end;def method_missing m,c,*a;X.M;k=X.const_get(c). | |
| 55 | new(StringIO.new,H['HTTP_HOST','','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s) | |
| 56 | H[a.pop].each{|e,f|k.send("#{e}=",f)}if Hash===a[-1];k.service(*a);end;end | |
| 57 | module Views;include X,Helpers;end;module Models;autoload:Base,'camping/db';def | |
| 58 | Y;self;end;end;autoload:Mab,'camping/mab'end | |
| 51 | (q.to_s.split(/[#{d}]+ */n)-[""]).inject((b,z=z,H[])[0]){|h,p|k,v=un(p). | |
| 52 | split'=',2;h.u k.split(/[\]\[]+/).reverse.inject(y||v){|x,i|H[i,x]},&m}end | |
| 53 | def kp s;c=qsp s,';,'end;def run r=$stdin,e=ENV;X.M;e=H[e.to_hash];k,m,*a=X.D e. | |
| 54 | PATH_INFO=un("/#{e.PATH_INFO}".gsub(/\/+/,'/')), | |
| 55 | (e.REQUEST_METHOD||'get').downcase | |
| 56 | k.new(r,e,m).Y.service(*a);rescue=>x;X::I.new(r,e,'r500').service k,m,x | |
| 57 | end;def method_missing m,c,*a;X.M;k=X.const_get(c).new StringIO.new, | |
| 58 | H['HTTP_HOST','','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s | |
| 59 | H[a.pop].each{|e,f|k.send"#{e}=",f}if Hash===a[-1];k.service(*a)end end | |
| 60 | module Views;include X,Helpers end;module Models;autoload:Base,'camping/db' | |
| 61 | def Y;self;end end;autoload:Mab,'camping/mab'end |
| ... | ...@@ -1,3 +1,22 @@ | |
| 1 | = 1.6 | |
| 2 | === ???, 2007 | |
| 3 | ||
| 4 | * Camping::Apps removed, it wasn't reliable. | |
| 5 | * bin/camping server kinds splitted in various files. | |
| 6 | * NotFound and ServerError controllers changed to methods : | |
| 7 | ||
| 8 | r404 : called when a controller was not found | |
| 9 | r500 : called on uncaught exception | |
| 10 | r501 : called on undefined method | |
| 11 | ||
| 12 | All of those can be overridden at your taste. | |
| 13 | ||
| 14 | * Markaby no longer required. Like AR, is it autoloaded on (Mab) usage. | |
| 15 | * Camping::H is now inheriting from Hash instead of HashWithIndifferentAccess. | |
| 16 | * Which made possible to remove the last strict dependency : active_support | |
| 17 | * #errors_for removed, it wasn't really used | |
| 18 | * Bug fixes ! | |
| 19 | ||
| 1 | 20 | = 1.5 |
| 2 | 21 | === 3rd Oct, 2006 |
| 3 | 22 |
| ... | ...@@ -30,9 +30,8 @@ | |
| 30 | 30 | # |
| 31 | 31 | %w[tempfile uri].map { |l| require l } |
| 32 | 32 | |
| 33 | class Object | |
| 34 | # Define a method m with the passed block on the metaclass. | |
| 35 | def meta_def(m,&b) | |
| 33 | class Object #:nodoc: | |
| 34 | def meta_def(m,&b) #:nodoc: | |
| 36 | 35 | (class<<self;self end).send(:define_method,m,&b) |
| 37 | 36 | end |
| 38 | 37 | end |
| ... | ...@@ -91,7 +90,7 @@ | |
| 91 | 90 | module Camping |
| 92 | 91 | C = self |
| 93 | 92 | S = IO.read(__FILE__) rescue nil |
| 94 | P = "Cam\ping Problem!" | |
| 93 | P = '<h1>Cam\ping Problem!</h1><h2>%s</h2>' | |
| 95 | 94 | # An object-like Hash. |
| 96 | 95 | # All Camping query string and cookie variables are loaded as this. |
| 97 | 96 | # |
| ... | ...@@ -322,6 +321,18 @@ | |
| 322 | 321 | s |
| 323 | 322 | end |
| 324 | 323 | |
| 324 | # A quick means of setting this controller's status, body and headers. | |
| 325 | # Used internally by Camping, but... by all means... | |
| 326 | # | |
| 327 | # r(302, '', 'Location' => self / "/view/12") | |
| 328 | # | |
| 329 | # Is equivalent to: | |
| 330 | # | |
| 331 | # redirect "/view/12" | |
| 332 | # | |
| 333 | # See also: #r404, #r500 and #r501 | |
| 334 | def r(s, b, h = {}); @status = s; headers.u(h); @body = b; end | |
| 335 | ||
| 325 | 336 | # Formulate a redirect response: a 302 status with <tt>Location</tt> header |
| 326 | 337 | # and a blank body. Uses Helpers#URL to build the location from a controller |
| 327 | 338 | # route or path. |
| ... | ...@@ -338,16 +349,41 @@ | |
| 338 | 349 | r(302,'','Location'=>URL(*a)) |
| 339 | 350 | end |
| 340 | 351 | |
| 341 | # A quick means of setting this controller's status, body and headers. | |
| 342 | # Used internally by Camping, but... by all means... | |
| 352 | # Called when a controller was not found. It is mainly used internally, but it can | |
| 353 | # also be useful for you, if you want to filter some parameters. | |
| 343 | 354 | # |
| 344 | # r(302, '', 'Location' => self / "/view/12") | |
| 355 | # module Camping | |
| 356 | # def r404(p=env.PATH) | |
| 357 | # @status = 404 | |
| 358 | # div do | |
| 359 | # h1 'Camping Problem!' | |
| 360 | # h2 "#{p} not found" | |
| 361 | # end | |
| 362 | # end | |
| 363 | # end | |
| 345 | 364 | # |
| 346 | # Is equivalent to: | |
| 365 | # See: I | |
| 366 | def r404(p=env.PATH) | |
| 367 | r(404, P % "#{p} not found") | |
| 368 | end | |
| 369 | ||
| 370 | # If there is a parse error in Camping or in your application's source code, it will not be caught | |
| 371 | # by Camping. The controller class +k+ and request method +m+ (GET, POST, etc.) where the error | |
| 372 | # took place are passed in, along with the Exception +e+ which can be mined for useful info. | |
| 347 | 373 | # |
| 348 | # redirect "/view/12" | |
| 374 | # You can overide it, but if you have an error in here, it will be uncaught ! | |
| 349 | 375 | # |
| 350 | def r(s, b, h = {}); @status = s; headers.u(h); @body = b; end | |
| 376 | # See: I | |
| 377 | def r500(k,m,x) | |
| 378 | r(500, P % "#{k}.#{m}" + "<h3>#{x.class} #{x.message}: <ul>#{x.backtrace.map{|b|"<li>#{b}</li>"}}</ul></h3>") | |
| 379 | end | |
| 380 | ||
| 381 | # Called if an undefined method is called on a Controller, along with the request method +m+ (GET, POST, etc.) | |
| 382 | # | |
| 383 | # See: I | |
| 384 | def r501(m=@method) | |
| 385 | r(501, P % "#{m.upcase} not implemented") | |
| 386 | end | |
| 351 | 387 | |
| 352 | 388 | # Turn a controller into an array. This is designed to be used to pipe |
| 353 | 389 | # controllers into the <tt>r</tt> method. A great way to forward your |
| ... | ...@@ -364,7 +400,7 @@ | |
| 364 | 400 | def to_a;[status, body, headers] end |
| 365 | 401 | |
| 366 | 402 | def initialize(r, e, m) #:nodoc: |
| 367 | @status, @method, @env, @headers, @root = 200, m.downcase, e, | |
| 403 | @status, @method, @env, @headers, @root = 200, m, e, | |
| 368 | 404 | H['Content-Type','text/html'], e.SCRIPT_NAME.sub(/\/$/,'') |
| 369 | 405 | @k = C.kp(e.HTTP_COOKIE) |
| 370 | 406 | q = C.qsp(e.QUERY_STRING) |
| ... | ...@@ -417,7 +453,7 @@ | |
| 417 | 453 | # See http://code.whytheluckystiff.net/camping/wiki/BeforeAndAfterOverrides for more |
| 418 | 454 | # on before and after overrides with Camping. |
| 419 | 455 | def service(*a) |
| 420 | @body = send(@method, *a) if respond_to? @method | |
| 456 | @body = send(@method, *a) | |
| 421 | 457 | headers['Set-Cookie'] = cookies.map { |k,v| "#{k}=#{C.escape(v)}; path=#{self/"/"}" if v != @k[k] } - [nil] |
| 422 | 458 | self |
| 423 | 459 | end |
| ... | ...@@ -493,13 +529,14 @@ | |
| 493 | 529 | # # Classes with routes are searched in order of their creation. |
| 494 | 530 | # |
| 495 | 531 | # So, define your catch-all controllers last. |
| 496 | def D(p) | |
| 532 | def D(p, m) | |
| 497 | 533 | r.map { |k| |
| 498 | 534 | k.urls.map { |x| |
| 499 | return k, $~[1..-1] if p =~ /^#{x}\/?$/ | |
| 535 | return (k.instance_method(m) rescue nil) ? | |
| 536 | [k, m, *$~[1..-1]] : [I, 'r501', m] if p =~ /^#{x}\/?$/ | |
| 500 | 537 | } |
| 501 | 538 | } |
| 502 | [NotFound, [p]] | |
| 539 | [I, 'r404', p] | |
| 503 | 540 | end |
| 504 | 541 | |
| 505 | 542 | # The route maker, this is called by Camping internally, you shouldn't need to call it. |
| ... | ...@@ -517,61 +554,15 @@ | |
| 517 | 554 | constants.map { |c| |
| 518 | 555 | k=const_get(c) |
| 519 | 556 | k.send :include,C,Base,Helpers,Models |
| 520 | r[0,0]=k if !r.include?k | |
| 557 | @r=[k]+r if r-[k]==r | |
| 521 | 558 | k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls |
| 522 | 559 | } |
| 523 | 560 | end |
| 524 | 561 | end |
| 525 | 562 | |
| 526 | # The NotFound class is a special controller class for handling 404 errors, in case you'd | |
| 527 | # like to alter the appearance of the 404. The path is passed in as +p+. | |
| 528 | # | |
| 529 | # module Camping::Controllers | |
| 530 | # class NotFound | |
| 531 | # def get(p) | |
| 532 | # @status = 404 | |
| 533 | # div do | |
| 534 | # h1 'Camping Problem!' | |
| 535 | # h2 "#{p} not found" | |
| 536 | # end | |
| 537 | # end | |
| 538 | # end | |
| 539 | # end | |
| 540 | # | |
| 541 | class NotFound < R() | |
| 542 | def get(p) | |
| 543 | r(404, "<h1>#{P}</h1><h2>#{p} not found</h2>") | |
| 544 | end | |
| 545 | end | |
| 546 | ||
| 547 | # The ServerError class is a special controller class for handling many (but not all) 500 errors. | |
| 548 | # If there is a parse error in Camping or in your application's source code, it will not be caught | |
| 549 | # by Camping. The controller class +k+ and request method +m+ (GET, POST, etc.) where the error | |
| 550 | # took place are passed in, along with the Exception +e+ which can be mined for useful info. | |
| 551 | # | |
| 552 | # module Camping::Controllers | |
| 553 | # class ServerError | |
| 554 | # def get(k,m,e) | |
| 555 | # @status = 500 | |
| 556 | # div do | |
| 557 | # h1 'Camping Problem!' | |
| 558 | # h2 "in #{k}.#{m}" | |
| 559 | # h3 "#{e.class} #{e.message}:" | |
| 560 | # ul do | |
| 561 | # e.backtrace.each do |bt| | |
| 562 | # li bt | |
| 563 | # end | |
| 564 | # end | |
| 565 | # end | |
| 566 | # end | |
| 567 | # end | |
| 568 | # end | |
| 569 | # | |
| 570 | class ServerError < R() | |
| 571 | def get(k,m,e) | |
| 572 | r(500, "<h1>#{P}</h1><h2>#{k}.#{m}</h2><h3>#{e.class} #{e.message | |
| 573 | }:<ul>#{e.backtrace.map{ |b| "<li>#{b}</li>" } }") | |
| 574 | end | |
| 563 | ||
| 564 | # Internal controller with no route. Used by #D and C.run to show internal messages. | |
| 565 | class I < R() | |
| 575 | 566 | end |
| 576 | 567 | |
| 577 | 568 | self |
| ... | ...@@ -660,10 +651,10 @@ | |
| 660 | 651 | def run(r=$stdin,e=ENV) |
| 661 | 652 | X.M |
| 662 | 653 | e = H[e.to_hash] |
| 663 | k,a=X.D e.PATH_INFO=un("/#{e.PATH_INFO}".gsub(/\/+/,'/')) | |
| 664 | k.new(r,e,(m=e.REQUEST_METHOD||"GET")).Y.service(*a) | |
| 665 | rescue=>x | |
| 666 | X::ServerError.new(r,e,'get').service(k,m,x) | |
| 654 | k,m,*a=X.D e.PATH_INFO=un("/#{e.PATH_INFO}".gsub(/\/+/,'/')),(e.REQUEST_METHOD||'get').downcase | |
| 655 | k.new(r,e,m).Y.service(*a) | |
| 656 | rescue => x | |
| 657 | X::I.new(r,e,'r500').service(k,m,x) | |
| 667 | 658 | end |
| 668 | 659 | |
| 669 | 660 | # The Camping scriptable dispatcher. Any unhandled method call to the app module will |
| ... | ...@@ -94,11 +94,8 @@ | |
| 94 | 94 | private |
| 95 | 95 | |
| 96 | 96 | def insert_app(script) |
| 97 | self[script] = Application.new(script) | |
| 97 | self[script] = Reloader.new(script) | |
| 98 | 98 | end |
| 99 | 99 | end |
| 100 | ||
| 101 | class Application < Camping::Reloader | |
| 102 | end | |
| 103 | 100 | end |
| 104 | 101 |