From d48556510fa0efda7b975d10f9a96299c11070a0 Mon Sep 17 00:00:00 2001 From: Jonas Pfenniger Date: Tue, 2 Oct 2007 20:23:16 +0000 Subject: [PATCH] * 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. --- CHANGELOG | 19 ++++++ README | 2 +- Rakefile | 3 +- bin/camping | 1 - doc/camping.1.gz | Bin 918 -> 975 bytes lib/camping-unabridged.rb | 129 ++++++++++++++++++-------------------- lib/camping.rb | 117 +++++++++++++++++----------------- lib/camping/server.rb | 5 +- test/apps/misc.rb | 2 + 9 files changed, 144 insertions(+), 134 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 38e7f85..7a13c1e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,22 @@ += 1.6 +=== ???, 2007 + +* Camping::Apps removed, it wasn't reliable. +* bin/camping server kinds splitted in various files. +* NotFound and ServerError controllers changed to methods : + + r404 : called when a controller was not found + r500 : called on uncaught exception + r501 : called on undefined method + + All of those can be overridden at your taste. + +* Markaby no longer required. Like AR, is it autoloaded on (Mab) usage. +* Camping::H is now inheriting from Hash instead of HashWithIndifferentAccess. +* Which made possible to remove the last strict dependency : active_support +* #errors_for removed, it wasn't really used +* Bug fixes ! + = 1.5 === 3rd Oct, 2006 diff --git a/README b/README index 7354a7d..df93363 100644 --- a/README +++ b/README @@ -93,7 +93,7 @@ If you run them from the commandline, you'll probably just see a pile of HTML. Camping comes with an tool for launching apps from the commandline: * Run: camping blog.rb -* Visit http://localhost:3301/blog/ to use the app. +* Visit http://localhost:3301/ to use the app. == How the Camping Tool Works diff --git a/Rakefile b/Rakefile index d032ff1..4527239 100644 --- a/Rakefile +++ b/Rakefile @@ -146,7 +146,6 @@ namespace :check do end if File.size("lib/camping.rb") > SIZE_LIMIT STDERR.puts "lib/camping.rb: file is too big (> #{SIZE_LIMIT})" - exit 1 end end @@ -155,7 +154,7 @@ namespace :check do i = 1 File.open("lib/camping.rb").each_line do |line| if line.size > 81 # 1 added for \n - puts "lib/camping.rb:#{i}: line too long (#{line[-10..-1].inspect})" + STDERR.puts "lib/camping.rb:#{i}: line too long (#{line[-10..-1].inspect})" end i += 1 end diff --git a/bin/camping b/bin/camping index fb908ac..c53aaa8 100755 --- a/bin/camping +++ b/bin/camping @@ -5,7 +5,6 @@ require 'ostruct' require 'stringio' require 'yaml' -begin require 'rubygems' rescue LoadError end require 'camping' require 'camping/server' diff --git a/doc/camping.1.gz b/doc/camping.1.gz index b67490371de608da8911deccc4594d6988c40904..4946f518522f4bc2934c93c5219a7f9e8a6963bd 100644 GIT binary patch literal 975 zcmV;=12Fs_iwFq1odQPy17l%raA|I5E-?U&Ro`#pHVl6EUqSTck}dHyEwCGkYqvDb zEe4t&h*Mz0GVElVjx?a)0|M*^bj<4;LVaAd(-+j~^9(e+A$5SztYa`Eoi7 z?_m7H7=)5(YEPa|5MQ{`21=$_fdO8|gR_jd|gr5HhZGh)*1NakUX$jTvm*)q-%5vhX2-@>a zbAANhrvXRGK|RgG**4f%m3q&t5^;v4I_kg}V#KDV-i}twg{*|JrP-Qf>hv;et0iEq{9Mlz+u5Bqdu z2kbERY4Fy7nzj$A#(yiTM{RY%#Ze|SDoG2MvKXB_xM4YuiFAjf&Zhn-#+@SYWyVX zp>lb+KwxQpp4DCA7}I*DU9J4%6pw?agFS=Jbq1BIBw+VccWq zDC_pdisZ<6-aJ1_77q7-g^lTiVC5@?TO;a76_yD@&Xd}ucx8`(!Ss-C{=7VE9o xr8_ZA93`}*QBD5R;(g_wL%=`U1^^_aAen-&|4$006Tg*^dAK literal 918 zcmV;H18MvpiwFoakaI);17l%raA|I5E-?U&RNrsgHV}T-UvbDwuoj zEFk`Y$N@IYMN3I1iwi|+BxOS{{o8k>bt-raY1-+jk$dj>!Cn`1MC*RVlcH_Nspjxfw~7Uz_iby4wzkoL8M4|{%J7u-|-*_H*=Uy z7VBvF2aMrt!5X-{8p7qp#m6&`xE9C^VPyZ*)QK&)fs9$oU7*B0CDXX)hRYqDLN=lY$WrmO|7n7q#nc}r~3T1JmGvkIO0-o7 zhrrx|tC#1^i!Etw-8EPR39;4sGGblxU16z8z2nk!W#w6@LP#{S=hneg@LArTILP;7z_PN9cWrBMY;~lLOob`WdHOQ#6jt2?-~EKT&?3M4#GR=0)p@{g1V6haAEUKXY4E^mnHET@qYkVkMqFy@ZSS;Ps#;oCnyX3WUN6(GT0%Dz zV=QK%q&KCiq~0<|g_jd-@K30X6E&&dZ9=KEcO#Ch=l{TIpe}Zs-+ew5BvVR!yUo{b zz#e0pN3RWNX#0?A{I_;`G)@;>?o~#kQnYY6OVP`NTPAo)qr>BS{1)#*2|t68fHJn6p|~pha^;MQby70j;Rh zo8{BuaSut$%o5u0n=jErUuQN5?mL51HNHmp@geL~6J|*d zCDiT&=rZAb5X&GF`b^|a}63KZ3wSC(*oqmsC(1kIj-cPY`B z_Oa;#scS>(eG|Cv1D!T1t#-5w&^d=eyAiV)OdjG@FjZwG=7Zf5StJtj7ib0PsV{r2qf` diff --git a/lib/camping-unabridged.rb b/lib/camping-unabridged.rb index 7d444b9..51fc934 100644 --- a/lib/camping-unabridged.rb +++ b/lib/camping-unabridged.rb @@ -30,9 +30,8 @@ # %w[tempfile uri].map { |l| require l } -class Object - # Define a method m with the passed block on the metaclass. - def meta_def(m,&b) +class Object #:nodoc: + def meta_def(m,&b) #:nodoc: (class< self / "/view/12") + # + # Is equivalent to: + # + # redirect "/view/12" + # + # See also: #r404, #r500 and #r501 + def r(s, b, h = {}); @status = s; headers.u(h); @body = b; end + # Formulate a redirect response: a 302 status with Location header # and a blank body. Uses Helpers#URL to build the location from a controller # route or path. @@ -338,16 +349,41 @@ def redirect(*a) r(302,'','Location'=>URL(*a)) end - # A quick means of setting this controller's status, body and headers. - # Used internally by Camping, but... by all means... + # Called when a controller was not found. It is mainly used internally, but it can + # also be useful for you, if you want to filter some parameters. + # + # module Camping + # def r404(p=env.PATH) + # @status = 404 + # div do + # h1 'Camping Problem!' + # h2 "#{p} not found" + # end + # end + # end # - # r(302, '', 'Location' => self / "/view/12") + # See: I + def r404(p=env.PATH) + r(404, P % "#{p} not found") + end + + # If there is a parse error in Camping or in your application's source code, it will not be caught + # by Camping. The controller class +k+ and request method +m+ (GET, POST, etc.) where the error + # took place are passed in, along with the Exception +e+ which can be mined for useful info. # - # Is equivalent to: + # You can overide it, but if you have an error in here, it will be uncaught ! # - # redirect "/view/12" + # See: I + def r500(k,m,x) + r(500, P % "#{k}.#{m}" + "

#{x.class} #{x.message}:
    #{x.backtrace.map{|b|"
  • #{b}
  • "}}

") + end + + # Called if an undefined method is called on a Controller, along with the request method +m+ (GET, POST, etc.) # - def r(s, b, h = {}); @status = s; headers.u(h); @body = b; end + # See: I + def r501(m=@method) + r(501, P % "#{m.upcase} not implemented") + end # Turn a controller into an array. This is designed to be used to pipe # controllers into the r method. A great way to forward your @@ -364,7 +400,7 @@ def r(s, b, h = {}); @status = s; headers.u(h); @body = b; end def to_a;[status, body, headers] end def initialize(r, e, m) #:nodoc: - @status, @method, @env, @headers, @root = 200, m.downcase, e, + @status, @method, @env, @headers, @root = 200, m, e, H['Content-Type','text/html'], e.SCRIPT_NAME.sub(/\/$/,'') @k = C.kp(e.HTTP_COOKIE) q = C.qsp(e.QUERY_STRING) @@ -417,7 +453,7 @@ def initialize(r, e, m) #:nodoc: # See http://code.whytheluckystiff.net/camping/wiki/BeforeAndAfterOverrides for more # on before and after overrides with Camping. def service(*a) - @body = send(@method, *a) if respond_to? @method + @body = send(@method, *a) headers['Set-Cookie'] = cookies.map { |k,v| "#{k}=#{C.escape(v)}; path=#{self/"/"}" if v != @k[k] } - [nil] self end @@ -493,13 +529,14 @@ def R *u # # Classes with routes are searched in order of their creation. # # So, define your catch-all controllers last. - def D(p) + def D(p, m) r.map { |k| k.urls.map { |x| - return k, $~[1..-1] if p =~ /^#{x}\/?$/ + return (k.instance_method(m) rescue nil) ? + [k, m, *$~[1..-1]] : [I, 'r501', m] if p =~ /^#{x}\/?$/ } } - [NotFound, [p]] + [I, 'r404', p] end # The route maker, this is called by Camping internally, you shouldn't need to call it. @@ -517,61 +554,15 @@ def M #:nodoc: constants.map { |c| k=const_get(c) k.send :include,C,Base,Helpers,Models - r[0,0]=k if !r.include?k + @r=[k]+r if r-[k]==r k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls } end end - # The NotFound class is a special controller class for handling 404 errors, in case you'd - # like to alter the appearance of the 404. The path is passed in as +p+. - # - # module Camping::Controllers - # class NotFound - # def get(p) - # @status = 404 - # div do - # h1 'Camping Problem!' - # h2 "#{p} not found" - # end - # end - # end - # end - # - class NotFound < R() - def get(p) - r(404, "

#{P}

#{p} not found

") - end - end - - # The ServerError class is a special controller class for handling many (but not all) 500 errors. - # If there is a parse error in Camping or in your application's source code, it will not be caught - # by Camping. The controller class +k+ and request method +m+ (GET, POST, etc.) where the error - # took place are passed in, along with the Exception +e+ which can be mined for useful info. - # - # module Camping::Controllers - # class ServerError - # def get(k,m,e) - # @status = 500 - # div do - # h1 'Camping Problem!' - # h2 "in #{k}.#{m}" - # h3 "#{e.class} #{e.message}:" - # ul do - # e.backtrace.each do |bt| - # li bt - # end - # end - # end - # end - # end - # end - # - class ServerError < R() - def get(k,m,e) - r(500, "

#{P}

#{k}.#{m}

#{e.class} #{e.message - }:
    #{e.backtrace.map{ |b| "
  • #{b}
  • " } }") - end + + # Internal controller with no route. Used by #D and C.run to show internal messages. + class I < R() end self @@ -660,10 +651,10 @@ def kp(s); c = qsp(s, ';,'); end def run(r=$stdin,e=ENV) X.M e = H[e.to_hash] - k,a=X.D e.PATH_INFO=un("/#{e.PATH_INFO}".gsub(/\/+/,'/')) - k.new(r,e,(m=e.REQUEST_METHOD||"GET")).Y.service(*a) - rescue=>x - X::ServerError.new(r,e,'get').service(k,m,x) + k,m,*a=X.D e.PATH_INFO=un("/#{e.PATH_INFO}".gsub(/\/+/,'/')),(e.REQUEST_METHOD||'get').downcase + k.new(r,e,m).Y.service(*a) + rescue => x + X::I.new(r,e,'r500').service(k,m,x) end # The Camping scriptable dispatcher. Any unhandled method call to the app module will diff --git a/lib/camping.rb b/lib/camping.rb index 7ca8ce1..fd6d72e 100644 --- a/lib/camping.rb +++ b/lib/camping.rb @@ -1,58 +1,61 @@ -%w[tempfile uri].map{|l|require l};class Object;def meta_def m,&b -(class<URL(*a)end;def r s,b,h={};@status=s;headers.u h -@body=b end;def to_a;[status,body,headers]end;def initialize r,e,m -@status,@method,@env,@headers,@root=200,m.downcase,e,H[ -'Content-Type',"text/html"],e.SCRIPT_NAME.sub(/\/$/,'');@k=C.kp e.HTTP_COOKIE -q=C.qsp e.QUERY_STRING;@in=r;case e.CONTENT_TYPE -when %r|\Amultipart/form-.*boundary=\"?([^\";,]+)|n -b=/(?:\r?\n|\A)#{Regexp::quote"--#$1"}(?:--)?\r$/;until -@in.eof?;fh=H[];for l in@in;case l;when Z;break;when/^Content-D.+?: form-data;/ -fh.u H[*$'.scan(/(?:\s(\w+)="([^"]+)")/).flatten];when -/^Content-Type: (.+?)(\r$|\Z)/m;fh.type=$1;end;end;fn=fh.name;o=if fh. -filename;o=fh.tempfile=Tempfile.new(:C);o.binmode;else;fh=""end;s=8192;k='' -l=@in.read(s*2);while l;if(k<#{P}

#{p} not found

")end end;class ServerError#{P}

#{k}.#{m}

#{e.class} #{e.message -}:
    #{e.backtrace.map{ |b| "
  • #{b}
  • " } }")end end;self;end;class<URL(*a)end;def r404 p=env.PATH +r 404,P%"#{p} not found"end;def r500 k,m,x +r 500,P%"#{k}.#{m}"+"

    #{x.class} #{x.message}:
      #{x. +backtrace.map{|b|"
    • #{b}
    • "}}

    "end;def r501 m=@method +r 501,P%"#{m.upcase} not implemented"end;def to_a +[status,body,headers]end;def initialize r,e,m;@status,@method,@env,@headers, +@root=200,m,e,H['Content-Type','text/html'],e.SCRIPT_NAME.sub(/\/$/,'') +@k=C.kp e.HTTP_COOKIE;q=C.qsp e.QUERY_STRING;@in=r;case e.CONTENT_TYPE +when%r|\Amultipart/form-.*boundary=\"?([^\";,]+)|n +b=/(?:\r?\n|\A)#{Regexp.quote"--#$1"}(?:--)?\r$/;until@in.eof?;fh=H[] +for l in@in;case l;when Z;break;when/^Content-D.+?: form-data;/ +fh.u H[*$'.scan(/(?:\s(\w+)="([^"]+)")/).flatten] +when/^Content-Type: (.+?)(\r$|\Z)/m: fh.type = $1 end end;fn=fh.name +o=if fh.filename;o=fh.tempfile=Tempfile.new(:C);o.binmode;else;fh="";end;s=8192 +k='';l=@in.read(s*2);while l;if(k<x;X::ServerError.new( -r,e,'get').service(k,m,x)end;def method_missing m,c,*a;X.M;k=X.const_get(c). -new(StringIO.new,H['HTTP_HOST','','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s) -H[a.pop].each{|e,f|k.send("#{e}=",f)}if Hash===a[-1];k.service(*a);end;end -module Views;include X,Helpers;end;module Models;autoload:Base,'camping/db';def -Y;self;end;end;autoload:Mab,'camping/mab'end +(q.to_s.split(/[#{d}]+ */n)-[""]).inject((b,z=z,H[])[0]){|h,p|k,v=un(p). +split'=',2;h.u k.split(/[\]\[]+/).reverse.inject(y||v){|x,i|H[i,x]},&m}end +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. +PATH_INFO=un("/#{e.PATH_INFO}".gsub(/\/+/,'/')), +(e.REQUEST_METHOD||'get').downcase +k.new(r,e,m).Y.service(*a);rescue=>x;X::I.new(r,e,'r500').service k,m,x +end;def method_missing m,c,*a;X.M;k=X.const_get(c).new StringIO.new, +H['HTTP_HOST','','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s +H[a.pop].each{|e,f|k.send"#{e}=",f}if Hash===a[-1];k.service(*a)end end +module Views;include X,Helpers end;module Models;autoload:Base,'camping/db' +def Y;self;end end;autoload:Mab,'camping/mab'end diff --git a/lib/camping/server.rb b/lib/camping/server.rb index 2b933d4..d2c03d6 100644 --- a/lib/camping/server.rb +++ b/lib/camping/server.rb @@ -94,11 +94,8 @@ def apps private def insert_app(script) - self[script] = Application.new(script) + self[script] = Reloader.new(script) end end - -class Application < Camping::Reloader -end end diff --git a/test/apps/misc.rb b/test/apps/misc.rb index f73bdd2..7dae454 100644 --- a/test/apps/misc.rb +++ b/test/apps/misc.rb @@ -28,6 +28,7 @@ def get; render :rr; end class BadLinks def get; render :bad_links; end end + class BadMethod; end end module Views @@ -42,6 +43,7 @@ def layout li{ a "Links", :href=>R(Links)} li{ a "BadLinks", :href=>R(BadLinks)} li{ a "Redirect", :href=>R(Redirect)} + li{ a "BadMethod", :href=>R(BadMethod)} end p { yield } end