[DRE-commits] [SCM] camping.git branch, upstream, updated. upstream/2.1-1-g69e6a1b

Paul van Tilburg paulvt at debian.org
Tue Jan 31 21:23:26 UTC 2012


The following commit has been merged in the upstream branch:
commit 69e6a1bb2d20b7033f5f8e5f8d6eccc42e67fd94
Author: Paul van Tilburg <paulvt at debian.org>
Date:   Wed Jan 25 13:28:03 2012 +0100

    Imported Upstream version 2.1.498

diff --git a/Rakefile b/Rakefile
index 01b4e12..d95b59b 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,97 +1,56 @@
 $:.unshift 'extras'
+
+begin
+  require 'rake/dsl_definition'
+  require 'rake/alt_system'
+rescue LoadError
+else
+  begin
+    if defined?(Rake::DeprecatedObjectDSL)
+      Rake::DeprecatedObjectDSL.class_eval do
+        private_instance_methods(false).each do |meth|
+          remove_method meth
+        end
+      end
+    end
+  rescue Exception
+  end
+end
+
 require 'rake'
 require 'rake/clean'
-require 'rake/gempackagetask'
 require 'rake/testtask'
 require 'tempfile'
 require 'open3'
 
-task :default => :check
-
-## Constants
-NAME = "camping"
-BRANCH = "2.1"
-GIT = ENV['GIT'] || "git"
-REV = `#{GIT} rev-list HEAD`.strip.split.length
-VERS = ENV['VERSION'] || (REV.zero? ? BRANCH : [BRANCH, REV] * '.')
+require File.expand_path('../constants', __FILE__)
 
 CLEAN.include ['**/.*.sw?', '*.gem', '.config', 'test/test.log', '.*.pt']
-RDOC_OPTS = ["--line-numbers", "--quiet", "--main", "README"]
-    
-## Packaging
-spec =
-  Gem::Specification.new do |s|
-    s.name = NAME
-    s.version = VERS
-    s.platform = Gem::Platform::RUBY
-    s.has_rdoc = true
-    s.extra_rdoc_files = FileList["README", "CHANGELOG", "COPYING", "book/*"].to_a
-    s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)\/', '--exclude', 'lib/camping.rb']
-    s.summary = "minature rails for stay-at-home moms"
-    s.author = "why the lucky stiff"
-    s.email = 'why at ruby-lang.org'
-    s.homepage = 'http://camping.rubyforge.org/'
-    s.rubyforge_project = 'camping'
-    s.executables = ['camping']
-
-    s.add_dependency('rack', '>=1.0')
-    s.required_ruby_version = '>= 1.8.2'
-
-    s.files = %w(COPYING README Rakefile) +
-    Dir.glob("{bin,doc,test,lib,extras,book}/**/*") + 
-    Dir.glob("ext/**/*.{h,c,rb}") +
-    Dir.glob("examples/**/*.rb") +
-    Dir.glob("tools/*.rb")
-
-    s.require_path = "lib"
-    s.bindir = "bin"
-  end                   
-
-omni =
-  Gem::Specification.new do |s|
-    s.name = "camping-omnibus"
-    s.version = VERS
-    s.platform = Gem::Platform::RUBY
-    s.summary = "the camping meta-package for updating ActiveRecord, Mongrel and SQLite3 bindings"
-    %w[author email homepage rubyforge_project].each { |x| s.__send__("#{x}=", spec.__send__(x)) }
-
-    s.add_dependency('camping', "=#{VERS}")
-    s.add_dependency('activerecord')
-    s.add_dependency('sqlite3-ruby', '>=1.1.0.1')
-    s.add_dependency('mongrel')
-    s.add_dependency('RedCloth')
-    s.add_dependency('markaby')
-  end
-  
+
+task :default => :check
+
 ## RDoc
 
 begin
-  gem 'rdoc', '~> 2.4.0'
+  gem 'rdoc', '~>3.9.0'
 rescue LoadError
-  # Don't complain yet.
-end
-
-require 'rdoc/rdoc'
-require 'rake/rdoctask'
-
-Rake::RDocTask.new(:docs) do |rdoc|
-  if defined?(RDoc::VERSION) && RDoc::VERSION[0,3] == "2.4"
+  task :docs do
+    puts "** Camping needs RDoc 3.9 in order to use the Flipbook template."
+  end
+else
+  require 'rdoc/task'
+  RDoc::Task.new(:docs) do |rdoc|
     # We have a recent version of RDoc, so let's use flipbook.
     require 'rdoc/generator/singledarkfish'
     rdoc.options += ['-f', 'singledarkfish', *RDOC_OPTS]
     rdoc.template = "flipbook"
-  else
-    # Use whatever template is available, and give a little warning.
-    task :docs do
-      puts "** Camping needs RDoc 2.4 in order to use the Flipbook template."
-    end
+    
+    rdoc.rdoc_dir = 'doc'
+    rdoc.title = "Camping, a Microframework"
+    rdoc.rdoc_files.add ['README', 'lib/camping-unabridged.rb', 'lib/camping/**/*.rb', 'book/*']
   end
-  
-  rdoc.inline_source = false # --inline-source is deprecated
-  rdoc.rdoc_dir = 'doc'
-  rdoc.title = "Camping, a Microframework"
-  rdoc.rdoc_files.add ['README', 'lib/camping-unabridged.rb', 'lib/camping/**/*.rb', 'book/*']
 end
+
   
 task :rubygems_docs do
   require 'rubygems/doc_manager'
@@ -105,29 +64,10 @@ end
 desc "Packages Camping."
 task :package => :clean
 
-Rake::GemPackageTask.new(spec) do |p|
-  p.need_tar = true
-  p.gem_spec = spec
-end
-
-Rake::GemPackageTask.new(omni) do |p|
-  p.gem_spec = omni
-end
-
-task :install => :package do
-  sh %{sudo gem install pkg/#{NAME}-#{VERS}}
-end
-
-task :uninstall => [:clean] do
-  sh %{sudo gem uninstall #{NAME}}
-end
-
 ## Tests
 Rake::TestTask.new(:test) do |t|
   t.libs << "test"
   t.test_files = FileList['test/app_*.rb']
-#  t.warning = true
-#  t.verbose = true
 end
 
 ## Diff
@@ -139,7 +79,8 @@ task :diff do
   m = Tempfile.new('mural')
   
   u << Ruby2Ruby.new.process(RubyParser.new.parse(File.read("lib/camping.rb")))
-  m << Ruby2Ruby.new.process(RubyParser.new.parse(File.read("lib/camping-unabridged.rb")))
+  mtext = Ruby2Ruby.new.process(RubyParser.new.parse(File.read("lib/camping-unabridged.rb")))
+  m << mtext.gsub(/^\s*#.*\n/, '')
   
   u.flush
   m.flush
@@ -153,11 +94,16 @@ end
 error = false
 
 ## Check
-task :check => ["test", "check:valid", "check:size", "check:lines", "check:exit"]
+task :check => ["test", "check:valid", "check:equal", "check:size", "check:lines", "check:exit"]
 namespace :check do
 
   desc "Check source code validity"
   task :valid do
+    sh "ruby -c lib/camping.rb"
+  end
+
+  desc "Check equality between mural and unabridged"
+  task :equal do
     require 'ruby_parser'
     u = RubyParser.new.parse(File.read("lib/camping-unabridged.rb"))
     m = RubyParser.new.parse(File.read("lib/camping.rb"))
diff --git a/extras/rdoc/generator/template/flipbook/js/camping.js b/extras/rdoc/generator/template/flipbook/js/camping.js
index 72b72b9..0323c34 100644
--- a/extras/rdoc/generator/template/flipbook/js/camping.js
+++ b/extras/rdoc/generator/template/flipbook/js/camping.js
@@ -1,5 +1,16 @@
 // I know, I know.
 $(function() {
+    // #M0001 -> $(the section + the method body)
+    function m(name) {
+      var base = $(name);
+      return base.parent().add(base.next());
+    }
+    
+    // #class-something -> $(the section below)
+    function s(name) {
+      return $(name).next();
+    }
+
   $('.source-link a').click(function() {
     var link = $(this);
     var code = link.parent().next();
@@ -64,16 +75,6 @@ $(function() {
       }
     });
     
-    // #M0001 -> $(the section + the method body)
-    function m(name) {
-      var base = $(name);
-      return base.parent().add(base.next());
-    }
-    
-    // #class-something -> $(the section below)
-    function s(name) {
-      return $(name).next();
-    }
   }
   
 });
\ No newline at end of file
diff --git a/lib/camping-unabridged.rb b/lib/camping-unabridged.rb
index ab6cf10..a9c053a 100644
--- a/lib/camping-unabridged.rb
+++ b/lib/camping-unabridged.rb
@@ -82,6 +82,24 @@ module Camping
     end
     undef id, type if ?? == 63
   end
+
+  class Cookies < H
+    attr_accessor :_p
+    #
+    # Cookies that are set at this response
+    def _n; @n ||= {} end
+
+    alias _s []=
+
+    def set(k, v, o = {})
+      _s(j=k.to_s, v)
+      _n[j] = {:value => v, :path => _p}.update(o)
+    end
+
+    def []=(k, v)
+      set k, v, v.is_a?(Hash) ? v : {}
+    end
+  end
   
   # Helpers contains methods available in your controllers and views. You may
   # add methods of your own to this module, including many helper methods from
@@ -224,7 +242,7 @@ module Camping
     def URL c='/',*a
       c = R(c, *a) if c.respond_to? :urls
       c = self/c
-      c = @request.url[/.{8,}?(?=\/)/]+c if c[0]==?/
+      c = @request.url[/.{8,}?(?=\/|$)/]+c if c[0]==?/
       URI(c)
     end
   end
@@ -234,7 +252,7 @@ module Camping
   # it saves code for all the glue to stay in one place. Forgivable,
   # considering that it's only really a handful of methods and accessors.
   #
-  # Everything in this module is accessable inside your controllers.
+  # Everything in this module is accessible inside your controllers.
   module Base
     attr_accessor :env, :request, :root, :input, :cookies, :state,
                   :status, :headers, :body
@@ -250,6 +268,7 @@ module Camping
     def lookup(n)
       T.fetch(n.to_sym) do |k|
         t = Views.method_defined?(k) ||
+          (t = O[:_t].keys.grep(/^#{n}\./)[0]and Template[t].new{O[:_t][t]}) ||
           (f = Dir[[O[:views] || "views", "#{n}.*"]*'/'][0]) &&
           Template.new(f, O[f[/\.(\w+)$/, 1].to_sym] || {})
         
@@ -271,17 +290,17 @@ module Camping
     #
     def render(v, *a, &b)
       if t = lookup(v)
-        o = Hash === a[-1] ? a.pop : {}
-        s = (t == true) ? mab{ send(v, *a, &b) } : t.render(self, o[:locals] || {}, &b)
-        s = render(L, o.merge(L => false)) { s } if v.to_s[0] != ?_ && o[L] != false && lookup(L)
+        r, @_r = @_r, o = Hash === a[-1] ? a.pop : {}
+        s = (t == true) ? mab { send(v, *a, &b) } : t.render(self, o[:locals] || {}, &b)
+        s = render(L, o.merge(L => false)) { s } if o[L] or o[L].nil? && lookup(L) && (!r && v.to_s[0] != ?_)
         s
       else
-        raise "Can't find template #{v}"
+        raise "no template: #{v}"
       end
     end
 
-    # You can directly return HTML form your controller for quick debugging
-    # by calling this method and pass some Markaby to it.
+    # You can directly return HTML from your controller for quick debugging
+    # by calling this method and passing some Markaby to it.
     # 
     #   module Nuts::Controllers
     #     class Info
@@ -291,7 +310,8 @@ module Camping
     #
     # You can also pass true to use the :layout HTML wrapping method
     def mab(&b)
-      (@mab ||= Mab.new({},self)).capture(&b)
+      extend Mab
+      mab(&b)
     end
     
     # A quick means of setting this controller's status, body and headers
@@ -367,6 +387,12 @@ module Camping
     def r501(m)
       P % "#{m.upcase} not implemented"
     end
+
+    # Serves the string +c+ with the MIME type of the filename +p+.
+    def serve(p, c)
+      t = Rack::Mime.mime_type(p[/\..*$/], nil) and @headers['Content-Type'] = t
+      c
+    end
     
     # Turn a controller into a Rack response. This is designed to be used to
     # pipe controllers into the <tt>r</tt> method. A great way to forward your
@@ -382,9 +408,7 @@ module Camping
     def to_a
       @env['rack.session'] = Hash[@state]
       r = Rack::Response.new(@body, @status, @headers)
-      @cookies.each do |k, v|
-        next if @old_cookies[k] == v
-        v = { :value => v, :path => self / "/" } if String === v
+      @cookies._n.each do |k, v|
         r.set_cookie(k, v)
       end
       r.to_a
@@ -395,8 +419,9 @@ module Camping
       @root, @input, @cookies, @state,
       @headers, @status, @method =
       r.script_name.sub(/\/$/,''), n(r.params),
-      H[@old_cookies = r.cookies], H[r.session],
+      Cookies[r.cookies], H[r.session.to_hash],
       {}, m =~ /r(\d+)/ ? $1.to_i : 200, m
+      @cookies._p = self/"/"
     end
     
     def n(h) # :nodoc:
@@ -504,11 +529,6 @@ module Camping
   module Controllers
     @r = []
     class << self
-      # An array containing the various controllers available for dispatch.
-      def r #:nodoc:
-        @r
-      end
-      
       # Add routes to a controller class by piling them into the R method.
       # 
       # The route is a regexp which will match the request path. Anything
@@ -544,10 +564,11 @@ module Camping
       # So, define your catch-all controllers last.
       def D(p, m, e)
         p = '/' if !p || !p[0]
-        r.map { |k|
+        a=O[:_t].find{|n,_|n==p} and return [I, :serve, *a]
+        @r.map { |k|
           k.urls.map { |x|
             return (k.method_defined?(m)) ?
-              [k, m, *$~[1..-1]] : [I, 'r501', m] if p =~ /^#{x}\/?$/
+              [k, m, *$~[1..-1].map{|x|U.unescape(x)}] : [I, 'r501', m] if p =~ /^#{x}\/?$/
           }
         }
         [I, 'r404', p]
@@ -573,7 +594,7 @@ module Camping
         constants.map { |c|
           k = const_get(c)
           k.send :include,C,X,Base,Helpers,Models
-          @r=[k]+r if r-[k]==r
+          @r=[k]+ at r if @r-[k]==@r
           k.meta_def(:urls){["/#{c.to_s.scan(/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.respond_to?:urls
         }
       end
@@ -598,7 +619,11 @@ module Camping
     #
     # All the applications will be available in Camping::Apps.
     def goes(m)
-      Apps << eval(S.gsub(/Camping/,m.to_s), TOPLEVEL_BINDING)
+      Apps << a = eval(S.gsub(/Camping/,m.to_s), TOPLEVEL_BINDING)
+      caller[0]=~/:/
+      IO.read(a.set:__FILE__,$`)=~/^__END__/ &&
+      (b=$'.split(/^@@\s*(.+?)\s*\r?\n/m)).shift rescue nil
+      a.set :_t,H[*b||[]]
     end
     
     # Ruby web servers use this method to enter the Camping realm. The +e+
@@ -608,8 +633,7 @@ module Camping
     # See: http://rack.rubyforge.org/doc/SPEC.html
     def call(e)
       X.M
-      p = e['PATH_INFO'] = U.unescape(e['PATH_INFO'])
-      k,m,*a=X.D p,e['REQUEST_METHOD'].downcase,e
+      k,m,*a=X.D e['PATH_INFO'],e['REQUEST_METHOD'].downcase,e
       k.new(e,m).service(*a).to_a
     rescue
       r500(:I, k, m, $!, :env => e).to_a
@@ -732,8 +756,9 @@ module Camping
   # Models cannot be referred to in Views at this time.
   module Models
     autoload :Base,'camping/ar'
+    Helpers.send(:include, X, self)
   end
- 
+
   autoload :Mab, 'camping/mab'
   autoload :Template, 'camping/template'
   C
diff --git a/lib/camping.rb b/lib/camping.rb
index 1a02076..9eac063 100644
--- a/lib/camping.rb
+++ b/lib/camping.rb
@@ -2,44 +2,54 @@ require "uri";require "rack";class Object;def meta_def m,&b;(class<<self;self
 end).send:define_method,m,&b end end;module Camping;C=self;S=IO.read(__FILE__
 )rescue nil;P="<h1>Cam\ping Problem!</h1><h2>%s</h2>";U=Rack::Utils;O={};Apps=[]
 class H<Hash;def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.
-to_s]:super end;undef id,type if ??==63;end;module Helpers;def R c,*g;p,h=
+to_s]:super end;undef id,type if ??==63 end;class Cookies<H;attr_accessor :_p;
+def _n;@n||={}end;alias :_s :[]=;def set k,v,o={};_s(j=k.to_s,v);_n[j]=
+{:value=>v,:path=>_p}.update o;end;def []=(k,v)set(k,v,v.is_a?(Hash)?v:{})end
+end;module Helpers;def R c,*g;p,h=
 /\(.+?\)/,g.grep(Hash);g-=h;raise"bad route"unless u=c.urls.find{|x|break x if
 x.scan(p).size==g.size&&/^#{x}\/?$/=~(x=g.inject(x){|x,a|x.sub p,U.escape((a.
-to_param rescue a))}.gsub(/\\(.)/){$1})};h.any?? u+"?"+U.build_query(h[0]):u end;def
-/ p;p[0]==?/?@root + p : p end;def URL c='/',*a;c=R(c, *a) if c.respond_to?(
-:urls);c=self/c;c=@request.url[/.{8,}?(?=\/)/]+c if c[0]==?/;URI c end end
+to_param rescue a))}.gsub(/\\(.)/){$1})};h.any?? u+"?"+U.build_query(h[0]):u
+end;def / p;p[0]==?/?@root+p :p end;def URL c='/',*a;c=R(c,*a) if c.respond_to?(
+:urls);c=self/c;c=@request.url[/.{8,}?(?=\/|$)/]+c if c[0]==?/;URI c end end
 module Base;attr_accessor:env,:request,:root,:input,:cookies,:state,:status,
 :headers,:body;T={};L=:layout;def lookup n;T.fetch(n.to_sym){|k|t=Views.
-method_defined?(k)||(f=Dir[[O[:views]||"views","#{n}.*"]*'/'][0])&&Template.
+method_defined?(k)||(t=O[:_t].keys.grep(/^#{n}\./)[0]and Template[t].new{
+O[:_t][t]})||(f=Dir[[O[:views]||"views","#{n}.*"]*'/'][0])&&Template.
 new(f,O[f[/\.(\w+)$/,1].to_sym]||{});O[:dynamic_templates]?t:T[k]=t} end
-def render(v,*a,&b)if t=lookup(v);o=Hash===a[-1]?a.pop: {};s=(t==true)?mab{
+def render v,*a,&b;if t=lookup(v);r, at _r=@_r,o=Hash===a[-1]?a.pop: {};s=(t==true)?mab{
 send v,*a,&b}: t.render(self,o[:locals]||{},&b);s=render(L,o.merge(L=>false)){s
-}if v.to_s[0]!=?_&&o[L]!=false&&lookup(L);s;else;raise"Can't find template #{v}"end
-end;def mab &b;(@mab||=Mab.new({},self)).capture(&b) end;def r s,b,h={};b,h=h,
-b if Hash===b;@status=s;@headers.merge!(h);@body=b;end;def redirect *a;r 302,'',
-'Location'=>URL(*a).to_s;end;def r404 p;P%"#{p} not found"end;def r500 k,m,e
-raise e;end;def r501 m;P%"#{m.upcase} not implemented"end;def to_a;@env[
+}if o[L]or o[L].nil?&&lookup(L)&&!r&&v.to_s[0]!=?_;s;else;raise"no template: #{v}"
+end;end;def mab &b;extend(Mab);mab(&b) end;def r s,b,h={};b,h=
+h,b if Hash===b;@status=s;@headers.merge!(h);@body=b end;def redirect *a;r 302,
+'','Location'=>URL(*a).to_s end;def r404 p;P%"#{p} not found"end;def r500 k,m,e
+raise e end;def r501 m;P%"#{m.upcase} not implemented"end;def serve(p,c)
+(t=Rack::Mime.mime_type p[/\..*$/],nil)&&@headers["Content-Type"]=t;c;end;def to_a;@env[
 'rack.session']=Hash[@state];r=Rack::Response.new(@body, at status, at headers)
- at cookies.each{|k,v|next if @old_cookies[k]==v;v={:value=>v,:path=>self/"/"} if
-String===v;r.set_cookie(k,v)};r.to_a;end;def initialize(env,m) r=@request=Rack::
-Request.new(@env=env);@root, at input, at cookies, at state, at headers, at status, at method=r.
-script_name.sub(/\/$/,''),n(r.params),H[@old_cookies = r.cookies],H[r.session],
-{},m=~/r(\d+)/?$1.to_i: 200,m end;def n h;Hash===h ?h.inject(H[]){|m,(k,v)|m[k]=
+ at cookies._n.each{|k,v|r.set_cookie k,v};r.to_a end;def initialize env,m
+r=@request=Rack:: Request.new(@env=env);@root, at input, at cookies, at state, at headers,
+ at status, at method=r.script_name.sub(/\/$/,''),n(r.params),Cookies[r.cookies],
+H[r.session.to_hash],{},m=~/r(\d+)/?$1.to_i: 200,m;@cookies._p=self/"/" end
+def n h;Hash===h ?h.inject(H[]){|m,(k,v)|m[k]=
 n(v);m}: h end;def service *a;r=catch(:halt){send(@method,*a)};@body||=r;self
-end;end;module Controllers;@r=[];class<<self;def r;@r end;def R *u;r=@r;Class.
-new{meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def D p,m,e;p='/'if !p||
-!p[0];r.map{|k|k.urls.map{|x|return(k.method_defined? m)?[k,m,*$~[1..-1]]:[I,
-'r501',m]if p=~/^#{x}\/?$/}};[I,'r404',p] end;N=H.new{|_,x|x.downcase}.merge!(
-"N"=>'(\d+)',"X"=>'([^/]+)',"Index"=>'');def M;def M;end;constants.map{|c|k=
-const_get(c);k.send:include,C,X,Base,Helpers,Models;@r=[k]+r if r-[k]==r
-k.meta_def(:urls){ [ "/#{c.to_s.scan(/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.
-respond_to?:urls}end end;I=R();end;X=Controllers;class<<self;def goes m;Apps<<
-eval(S.gsub(/Camping/,m.to_s),TOPLEVEL_BINDING) end;def call e;X.M
-p=e['PATH_INFO']=U.unescape(e['PATH_INFO']);k,m,*a=X.D p,e['REQUEST_METHOD'].
-downcase,e;k.new(e,m).service(*a).to_a;rescue;r500(:I,k,m,$!,:env=>e).to_a;end
+end end;module Controllers;@r=[];class<<self;def R *u;r=@r;Class.
+new{meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def D p,m,e;p='/'if
+!p||!p[0];(a=O[:_t].find{|n,_|n==p}) and return [I,:serve,*a]
+ at r.map{|k|k.urls.map{|x|return(k.method_defined? m)?[k,m,*$~[1..-1].map{|x|U.unescape x}]:
+[I, 'r501',m]if p=~/^#{x}\/?$/}};[I,'r404',p] end;N=H.new{|_,x|x.downcase}.
+merge!("N"=>'(\d+)',"X"=>'([^/]+)',"Index"=>'');def M;def M;end;constants.
+map{|c|k=const_get(c);k.send:include,C,X,Base,Helpers,Models
+ at r=[k]+ at r if @r-[k]==@r;k.meta_def(:urls){["/#{c.to_s.scan(/.[^A-Z]*/).map(&
+N.method(:[]))*'/'}"]}if !k.respond_to?:urls}end end;I=R()end;X=
+Controllers;class<<self;def
+goes m;Apps<<a=eval(S.gsub(/Camping/,m.to_s),TOPLEVEL_BINDING);caller[0]=~/:/
+IO.read(a.set:__FILE__,$`)=~/^__END__/&&(b=$'.split /^@@\s*(.+?)\s*\r?\n/m).shift rescue nil
+a.set :_t,H[*b||[]];end;def call e;X.M
+k,m,*a=X.D e["PATH_INFO"],e['REQUEST_METHOD'].
+downcase,e;k.new(e,m).service(*a).to_a;rescue;r500(:I,k,m,$!,:env=>e).to_a end
 def method_missing m,c,*a;X.M;h=Hash===a[-1]?a.pop: {};e=H[Rack::MockRequest.
 env_for('',h.delete(:env)||{})];k=X.const_get(c).new(e,m.to_s);h.each{|i,v|k.
-send"#{i}=",v};k.service(*a);end;def use*a,&b;m=a.shift.new(method(:call),*a,&b)
+send"#{i}=",v};k.service(*a) end;def use*a,&b;m=a.shift.new(method(:call),*a,&b)
 meta_def(:call){|e|m.call(e)}end;def options;O end;def set k,v;O[k]=v end end
-module Views;include X,Helpers end;module Models;autoload:Base,'camping/ar';end
-autoload:Mab,'camping/mab';autoload:Template,'camping/template';C end
+module Views;include X,Helpers end;module Models;autoload:Base,'camping/ar'
+Helpers.send:include,X,self end;autoload:Mab,'camping/mab'
+autoload:Template,'camping/template';C end
diff --git a/lib/camping/mab.rb b/lib/camping/mab.rb
index f873c8f..6091451 100644
--- a/lib/camping/mab.rb
+++ b/lib/camping/mab.rb
@@ -1,23 +1,21 @@
 class MissingLibrary < Exception #:nodoc: all
 end
 begin
-    require 'markaby'
+  require 'mab'
 rescue LoadError => e
-    raise MissingLibrary, "Markaby could not be loaded (is it installed?): #{e.message}"
+  raise MissingLibrary, "Mab could not be loaded (is it installed?): #{e.message}"
 end
 
 $MAB_CODE = %{
-  # The Mab class wraps Markaby, allowing it to run methods from Camping::Views
-  # and also to replace :href, :action and :src attributes in tags by prefixing the root
-  # path.
-  class Mab < Markaby::Builder
-    attr_reader :builder
-    
+  module Mab
+    include ::Mab::Mixin::HTML5
     include Views
-    def tag!(*g,&b)
-      h=g[-1]
-      [:href,:action,:src].map{|a|(h[a]&&=self/h[a])rescue 0}
-      super
+
+    alias << text!
+
+    def mab_done(tag)
+      h=tag.attributes
+      [:href,:action,:src].map{|a|h[a]&&=self/h[a]}
     end
   end
 }
diff --git a/lib/camping/reloader.rb b/lib/camping/reloader.rb
index b67a53b..171dda7 100644
--- a/lib/camping/reloader.rb
+++ b/lib/camping/reloader.rb
@@ -32,153 +32,127 @@ module Camping
   #
   # You can also give Reloader more than one script.
   class Reloader
-    attr_reader :scripts, :apps
+    attr_reader :file
     
-    # This class is doing all the hard work; however, it only works on
-    # single files.  Reloader just wraps up support for multiple scripts
-    # and hides away some methods you normally won't need.
-    class Script # :nodoc:
-      attr_reader :apps, :file, :dir, :extras
-      
-      def initialize(file, callback = nil)
-        @file = File.expand_path(file)
-        @dir = File.dirname(@file)
-        @extras = File.join(@dir, File.basename(@file, ".rb"))
-        @mtime = Time.at(0)
-        @requires = []
-        @apps = {}
-        @callback = callback
+    def initialize(file, &blk)
+      @file = file
+      @mtime = Time.at(0)
+      @requires = []
+      @apps = {}
+      @callback = blk
+    end
+
+    def name
+      @name ||= begin
+        base = @file.dup
+        base = File.dirname(base) if base =~ /\bconfig\.ru$/
+        base.sub!(/\.[^.]+/, '')
+        File.basename(base).to_sym
       end
+    end
+    
+    # Loads the apps availble in this script.  Use <tt>apps</tt> to get
+    # the loaded apps.
+    def load_apps(old_apps)
+      all_requires = $LOADED_FEATURES.dup
+      all_apps = Camping::Apps.dup
+
+      load_file
+    ensure
+      @requires = []
+      dirs = []
+      new_apps = Camping::Apps - all_apps
       
-      # Loads the apps availble in this script.  Use <tt>apps</tt> to get
-      # the loaded apps.
-      def load_apps
-        all_requires = $LOADED_FEATURES.dup
-        all_apps = Camping::Apps.dup
-        
-        begin
-          load(@file)
-        rescue Exception => e
-          puts "!! Error loading #{@file}:"
-          puts "#{e.class}: #{e.message}"
-          puts e.backtrace
-          puts "!! Error loading #{@file}, see backtrace above"
-        end
-        
-        @requires = ($LOADED_FEATURES - all_requires).map do |req|
-          full = full_path(req)
-          full if full == @file or full.index(@extras) == 0
-        end
-        
-        @mtime = mtime
-        
-        new_apps = (Camping::Apps - all_apps)
-        old_apps = @apps.dup
-        
-        @apps = new_apps.inject({}) do |hash, app|
-          key = app.name.to_sym
-          hash[key] = app
-          
-          if !old_apps.include?(key)
-            @callback.call(app) if @callback
-            app.create if app.respond_to?(:create)
-          end
-          hash
+      @apps = new_apps.inject({}) do |hash, app|
+        if file = app.options[:__FILE__]
+          full = File.expand_path(file)
+          @requires << [file, full]
+          dirs << full.sub(/\.[^.]+$/, '')
         end
+
+        key = app.name.to_sym
+        hash[key] = app
         
-        self
-      end
-      
-      # Removes all the apps defined in this script.
-      def remove_apps
-        @apps.each do |name, app|
-          Camping::Apps.delete(app)
-          Object.send :remove_const, name
+        if !old_apps.include?(key)
+          @callback.call(app) if @callback
+          app.create if app.respond_to?(:create)
         end
+
+        hash
       end
-      
-      # Reloads the file if needed.  No harm is done by calling this multiple
-      # times, so feel free call just to be sure.
-      def reload!
-        return if @mtime >= mtime
-        remove_apps
-        load_apps
-      end
-      
-      # Checks if both scripts watches the same file.
-      def ==(other)
-        @file == other.file
-      end
-      
-      private
-      
-      def mtime
-        (@requires + [@file]).compact.map do |fname|
-          File.mtime(fname)
-        end.reject{|t| t > Time.now }.max
+
+      ($LOADED_FEATURES - all_requires).each do |req|
+        full = full_path(req)
+        @requires << [req, full] if dirs.any? { |x| full.index(x) == 0 }
       end
+
+      @mtime = mtime
       
-      # Figures out the full path of a required file. 
-      def full_path(req)
-        dir = $LOAD_PATH.detect { |l| File.exists?(File.join(l, req)) }
-        if dir 
-          File.join(File.expand_path(dir), req)
-        else
-          req
-        end
-      end
+      self
     end
 
-    # Creates the reloader, assigns a +script+ to it and initially loads the
-    # application.  Pass in the full path to the script, otherwise the script
-    # will be loaded relative to the current working directory.
-    def initialize(*scripts)
-      @scripts = []
-      @apps = {}
-      update(*scripts)
+    def load_file
+      if @file =~ /\.ru$/
+        @app,_ = Rack::Builder.parse_file(@file)
+      else
+        load(@file)
+      end
     end
     
-    def on_reload(&blk)
-      @callback = blk
+    # Removes all the apps defined in this script.
+    def remove_apps
+      @requires.each do |(path, full)|
+        $LOADED_FEATURES.delete(path)
+      end
+
+      @apps.each do |name, app|
+        Camping::Apps.delete(app)
+        Object.send :remove_const, name
+      end.dup
+    ensure
+      @apps.clear
     end
     
-    # Updates the reloader to only use the scripts provided:
-    #
-    #   reloader.update("examples/blog.rb", "examples/wiki.rb")
-    def update(*scripts)
-      old_scripts = @scripts.dup
-      clear
-      
-      @scripts = scripts.map do |script|
-        file = File.expand_path(script)
-        old_scripts.detect { |s| s.file == file } or
-        Script.new(script, @callback)
-      end
-      
+    # Reloads the file if needed.  No harm is done by calling this multiple
+    # times, so feel free call just to be sure.
+    def reload
+      return if @mtime >= mtime rescue nil
       reload!
     end
-    
-    # Removes all the scripts from the reloader.
-    def clear
-      @scripts = []
-      @apps = {}
+
+    def reload!
+      load_apps(remove_apps)
     end
     
-    # Returns the script which provided the given app.
-    def script(app)
-      @scripts.each do |script|
-        return script if script.apps.values.include?(app)
+    # Checks if both scripts watches the same file.
+    def ==(other)
+      @file == other.file
+    end
+
+    def apps
+      if @app
+        { name => @app }
+      else
+        @apps
       end
-      
-      false
     end
     
-    # Simply calls reload! on all the Script objects.
-    def reload!
-      @apps = {}
-      @scripts.each do |script|
-        script.reload!
-        @apps.update(script.apps)
+    private
+    
+    def mtime
+      @requires.map do |(path, full)|
+        File.mtime(full)
+      end.reject {|t| t > Time.now }.max || Time.now
+    end
+    
+    # Figures out the full path of a required file. 
+    def full_path(req)
+      return req if File.exists?(req)
+      dir = $LOAD_PATH.detect { |l| File.exists?(File.join(l, req)) }
+      if dir 
+        File.expand_path(req, File.expand_path(dir))
+      else
+        req
       end
     end
   end
diff --git a/lib/camping/server.rb b/lib/camping/server.rb
index 7445e47..47bffa7 100644
--- a/lib/camping/server.rb
+++ b/lib/camping/server.rb
@@ -62,7 +62,7 @@ module Camping
           opts.on("-C", "--console",
           "Run in console mode with IRB") { options[:server] = "console" }
           
-          server_list = ["mongrel", "webrick", "console"]
+          server_list = ["thin", "webrick", "console"]
           opts.on("-s", "--server NAME",
           "Server to force (#{server_list.join(', ')})") { |v| options[:server] = v }
 
@@ -90,15 +90,14 @@ module Camping
           exit
         end
         
-        options[:scripts] = args
+        options[:script] = args.shift
         options
       end
     end
     
     def initialize(*)
       super
-      @reloader = Camping::Reloader.new
-      @reloader.on_reload do |app|
+      @reloader = Camping::Reloader.new(options[:script]) do |app|
         if !app.options.has_key?(:dynamic_templates)
 		      app.options[:dynamic_templates] = true
 	      end
@@ -125,16 +124,16 @@ module Camping
     
     def middleware
       h = super
-      h["development"].unshift [XSendfile]
+      h["development"] << [XSendfile]
       h
     end
 
     def start
       if options[:server] == "console"
         puts "** Starting console"
-        reload!
-        this = self
-        eval("self", TOPLEVEL_BINDING).meta_def(:reload!) { this.reload!; nil }
+        @reloader.reload!
+        r = @reloader
+        eval("self", TOPLEVEL_BINDING).meta_def(:reload!) { r.reload!; nil }
         ARGV.clear
         IRB.start
         exit
@@ -144,95 +143,29 @@ module Camping
         super
       end
     end
-    
-    def find_scripts
-      scripts = options[:scripts].map do |path|
-        if File.file?(path)
-          path
-        elsif File.directory?(path)
-          Dir[File.join(path, '*.rb')]
-        end
-      end.flatten.compact
-	  
-      @reloader.update(*scripts)
-    end
-    
-    def reload!
-      find_scripts
+
+    def public_dir
+      File.expand_path('../public', @reloader.file)
     end
     
     def app
-      self
+      Rack::Cascade.new([Rack::File.new(public_dir), self], [404, 403])
     end
     
-    def call(env)
-      reload!
+    def current_app
+      @reloader.reload
       apps = @reloader.apps
-
-      case apps.length
-      when 0
-        index_page(apps)
-      when 1
-        apps.values.first.call(env)
-      else
-        apps.each do |name, app|
-          mount = name.to_s.downcase
-          case env["PATH_INFO"]
-          when %r{^/#{mount}}
-            env["SCRIPT_NAME"] = env["SCRIPT_NAME"] + $&
-            env["PATH_INFO"] = $'
-            return app.call(env)
-          when %r{^/code/#{mount}}
-            return [200, {'Content-Type' => 'text/plain', 'X-Sendfile' => @reloader.script(app).file}, []]
-          end
-        end
-        
-        index_page(apps)
+      return apps.values.first if apps.size == 1
+      if key = apps.keys.grep(/^#{@reloader.name}$/i)[0]
+        apps[key]
       end
     end
-    
-    def index_page(apps)
-      [200, {'Content-Type' => 'text/html'}, [TEMPLATE.result(binding)]]
+
+    def call(env)
+      app = current_app || raise("Could not find an app called `#{@reloader.name}`")
+      app.call(env)
     end
     
-    SOURCE = <<-HTML
-<html>
-  <head>
-    <title>You are Camping</title>
-    <style type="text/css">
-      body { 
-        font-family: verdana, arial, sans-serif; 
-        padding: 10px 40px; 
-        margin: 0; 
-      }
-      h1, h2, h3, h4, h5, h6 {
-        font-family: utopia, georgia, serif;
-      }
-      h3 { display: inline; }
-    </style>
-  </head>
-  <body>
-    <% if apps.empty? %>
-      <p>Good day.  I'm sorry, but I could not find any Camping apps.
-      You might want to take a look at the console to see if any errors
-      have been raised.</p>
-    <% else %>
-      <p>Good day.  These are the Camping apps you've mounted.</p>
-      <ul>
-      <% apps.each do |name, app| %>
-        <li>
-          <h3><a href="/<%= name.to_s.downcase %>"><%= app %></a></h3>
-          <small> / <a href="/code/<%= name.to_s.downcase %>">View source</a></small>
-        </li>
-      <% end %>
-      </ul>
-    <% end %>
-  </body>
-</html>
-    HTML
-    
-    TEMPLATE = ERB.new(SOURCE)
-    
     class XSendfile
       def initialize(app)
         @app = app
@@ -262,4 +195,4 @@ module Camping
       end
     end
   end
-end
\ No newline at end of file
+end
diff --git a/metadata.yml b/metadata.yml
index eccebf6..11953b9 100644
--- a/metadata.yml
+++ b/metadata.yml
@@ -1,53 +1,84 @@
---- !ruby/object:Gem::Specification 
+--- !ruby/object:Gem::Specification
 name: camping
-version: !ruby/object:Gem::Version 
-  prerelease: false
-  segments: 
-  - 2
-  - 1
-  version: "2.1"
+version: !ruby/object:Gem::Version
+  version: 2.1.498
+  prerelease: 
 platform: ruby
-authors: 
+authors:
 - why the lucky stiff
 autorequire: 
 bindir: bin
 cert_chain: []
-
-date: 2010-08-19 00:00:00 +02:00
-default_executable: 
-dependencies: 
-- !ruby/object:Gem::Dependency 
+date: 2012-01-25 00:00:00.000000000 Z
+dependencies:
+- !ruby/object:Gem::Dependency
   name: rack
+  requirement: &70136711636780 !ruby/object:Gem::Requirement
+    none: false
+    requirements:
+    - - ! '>='
+      - !ruby/object:Gem::Version
+        version: '1.0'
+  type: :runtime
   prerelease: false
-  requirement: &id001 !ruby/object:Gem::Requirement 
-    requirements: 
-    - - ">="
-      - !ruby/object:Gem::Version 
-        segments: 
-        - 1
-        - 0
-        version: "1.0"
+  version_requirements: *70136711636780
+- !ruby/object:Gem::Dependency
+  name: mab
+  requirement: &70136711636280 !ruby/object:Gem::Requirement
+    none: false
+    requirements:
+    - - ! '>='
+      - !ruby/object:Gem::Version
+        version: '0'
   type: :runtime
-  version_requirements: *id001
+  prerelease: false
+  version_requirements: *70136711636280
+- !ruby/object:Gem::Dependency
+  name: rake
+  requirement: &70136711635740 !ruby/object:Gem::Requirement
+    none: false
+    requirements:
+    - - ! '>='
+      - !ruby/object:Gem::Version
+        version: '0'
+  type: :development
+  prerelease: false
+  version_requirements: *70136711635740
+- !ruby/object:Gem::Dependency
+  name: rack-test
+  requirement: &70136711635140 !ruby/object:Gem::Requirement
+    none: false
+    requirements:
+    - - ! '>='
+      - !ruby/object:Gem::Version
+        version: '0'
+  type: :development
+  prerelease: false
+  version_requirements: *70136711635140
 description: 
 email: why at ruby-lang.org
-executables: 
+executables:
 - camping
 extensions: []
-
-extra_rdoc_files: 
+extra_rdoc_files:
 - README
 - CHANGELOG
 - COPYING
 - book/01_introduction
 - book/02_getting_started
 - book/51_upgrading
-files: 
+files:
 - COPYING
 - README
 - Rakefile
 - bin/camping
+- test/app_cookies.rb
+- test/app_file.rb
+- test/app_helpers.rb
+- test/app_inline_templates.rb
 - test/app_markup.rb
+- test/app_partials.rb
+- test/app_reloader.rb
 - test/app_route_generating.rb
 - test/app_sessions.rb
 - test/app_simple.rb
@@ -56,6 +87,10 @@ files:
 - test/apps/forward_to_other_controller.rb
 - test/apps/migrations.rb
 - test/apps/misc.rb
+- test/apps/reloader/config.ru
+- test/apps/reloader/reload_me.rb
+- test/apps/reloader.rb
+- test/apps/reloader_indirect.rb
 - test/apps/sessions.rb
 - test/test_helper.rb
 - lib/camping/ar.rb
@@ -93,12 +128,10 @@ files:
 - book/51_upgrading
 - examples/blog.rb
 - CHANGELOG
-has_rdoc: true
 homepage: http://camping.rubyforge.org/
 licenses: []
-
 post_install_message: 
-rdoc_options: 
+rdoc_options:
 - --line-numbers
 - --quiet
 - --main
@@ -107,30 +140,24 @@ rdoc_options:
 - ^(examples|extras)\/
 - --exclude
 - lib/camping.rb
-require_paths: 
+require_paths:
 - lib
-required_ruby_version: !ruby/object:Gem::Requirement 
-  requirements: 
-  - - ">="
-    - !ruby/object:Gem::Version 
-      segments: 
-      - 1
-      - 8
-      - 2
+required_ruby_version: !ruby/object:Gem::Requirement
+  none: false
+  requirements:
+  - - ! '>='
+    - !ruby/object:Gem::Version
       version: 1.8.2
-required_rubygems_version: !ruby/object:Gem::Requirement 
-  requirements: 
-  - - ">="
-    - !ruby/object:Gem::Version 
-      segments: 
-      - 0
-      version: "0"
+required_rubygems_version: !ruby/object:Gem::Requirement
+  none: false
+  requirements:
+  - - ! '>='
+    - !ruby/object:Gem::Version
+      version: '0'
 requirements: []
-
 rubyforge_project: camping
-rubygems_version: 1.3.6
+rubygems_version: 1.8.10
 signing_key: 
 specification_version: 3
 summary: minature rails for stay-at-home moms
 test_files: []
-
diff --git a/test/app_cookies.rb b/test/app_cookies.rb
new file mode 100644
index 0000000..7334c0a
--- /dev/null
+++ b/test/app_cookies.rb
@@ -0,0 +1,61 @@
+require 'test_helper'
+require 'camping'
+
+Camping.goes :Cookies
+
+module Cookies::Controllers
+  class One
+    def get
+      @cookies.simple = '42'
+      @cookies.set :complex, '43'
+      @cookies.set :past, 'past', :expires => Time.now - 5
+      render :show
+    end
+  end
+
+  class Two
+    def get
+      render :show
+    end
+  end
+
+  class Old
+    def get
+      @cookies.simple = '42'
+      @cookies.complex = { :value => '43' }
+      @cookies.past = { :value => 'past', :expires => Time.now - 5 }
+      @cookies.past.class.name
+    end
+  end
+end
+
+module Cookies::Views
+  def show
+    @cookies.values_at('simple', 'complex', 'past').inspect
+  end
+end
+
+class Cookies::Test < TestCase
+  def test_cookies
+    get '/one'
+    assert_body '["42", "43", "past"]'
+
+    get '/two'
+    assert_body '["42", "43", nil]'
+  end
+
+  def test_backward_compatible
+    get '/old'
+    assert_body 'Hash'
+
+    get '/two'
+    assert_body '["42", "43", nil]'
+  end
+
+  def test_path
+    get '/one', {}, 'SCRIPT_NAME' => '/mnt'
+    assert_body '["42", "43", "past"]'
+    assert_equal 3, last_response.headers["Set-Cookie"].scan('path=/mnt/').size
+  end
+end
+
diff --git a/test/app_file.rb b/test/app_file.rb
new file mode 100644
index 0000000..9252765
--- /dev/null
+++ b/test/app_file.rb
@@ -0,0 +1,45 @@
+require 'test_helper'
+require 'camping'
+
+Camping.goes :FileSource
+
+module FileSource::Controllers
+  class Index
+    def get
+      FileSource.options[:__FILE__]
+    end
+  end
+end
+
+class FileSource::Test < TestCase
+  def test_source
+    get '/'
+    assert_body __FILE__
+  end
+
+  def test_file
+    get '/style.css'
+    assert_body "* { margin: 0; padding: 0 }"
+    assert_equal "text/css", last_response.headers['Content-Type']
+
+    get '/test.foo'
+    assert_body "Hello"
+    assert_equal "text/html", last_response.headers['Content-Type']
+
+    get '/test'
+    assert_body "No extension"
+    assert_equal "text/html", last_response.headers['Content-Type']
+  end
+end
+
+__END__
+
+@@ /style.css
+* { margin: 0; padding: 0 }
+
+@@ /test.foo
+Hello
+
+@@ /test
+No extension
+
diff --git a/test/app_helpers.rb b/test/app_helpers.rb
new file mode 100644
index 0000000..7dccb62
--- /dev/null
+++ b/test/app_helpers.rb
@@ -0,0 +1,60 @@
+require 'test_helper'
+require 'camping'
+
+Camping.goes :Helpers
+
+module Helpers::Helpers
+  def frontpage
+    R(Index)
+  end
+
+  def current_user
+    User.new
+  end
+end
+
+module Helpers::Models
+  class User
+    def name
+      'Bob'
+    end
+  end
+end
+
+module Helpers::Controllers
+  class Index
+    def get
+      URL('/').to_s
+    end
+  end
+
+  class Model
+    def get
+      current_user.name
+    end
+  end
+
+  class Users
+    def get
+      frontpage
+    end
+  end
+end
+
+class Helpers::Test < TestCase
+  def test_models
+    get '/model'
+    assert_body "Bob"
+  end
+
+  def test_controllers
+    get '/users'
+    assert_body "/"
+  end
+
+  def test_url
+    get '/', {}, 'PATH_INFO' => ''
+    assert_body "http://example.org/"
+  end
+end
+
diff --git a/test/app_inline_templates.rb b/test/app_inline_templates.rb
new file mode 100644
index 0000000..75394b0
--- /dev/null
+++ b/test/app_inline_templates.rb
@@ -0,0 +1,39 @@
+require 'test_helper'
+require 'camping'
+
+Camping.goes :Inline
+
+module Inline::Controllers
+  class Index
+    def get
+      @world = "World"
+      render :index
+    end
+  end
+
+  class UserX
+    def get(name)
+      @name = name
+      render :user
+    end
+  end
+end
+
+class Inline::Test < TestCase
+  def test_inline
+    get '/'
+    assert_body "Hello World"
+
+    get '/user/Bluebie'
+    assert_body "My name is Bluebie"
+  end
+end
+
+__END__
+
+@@ index.erb
+Hello <%= @world %>
+
+@@ user.erb
+My name is <%= @name %>
+
diff --git a/test/app_markup.rb b/test/app_markup.rb
index 90c3711..69c4f45 100644
--- a/test/app_markup.rb
+++ b/test/app_markup.rb
@@ -15,6 +15,14 @@ module Markup::Controllers
       render :index, :layout => false
     end
   end
+
+  class AutoPrepend
+    def get
+      mab do
+        img :src => '/hello.png'
+      end
+    end
+  end
 end
 
 module Markup::Views
@@ -23,6 +31,7 @@ module Markup::Views
   end
   
   def layout
+    self << '<!DOCTYPE html>'
     html do
       head do
         title "Web Page"
@@ -36,6 +45,7 @@ end
 class Markup::Test < TestCase
   def test_render
     get '/'
+    assert_body %r{\A<!DOCTYPE html>}
     assert_body %r{<h1>Welcome!</h1>}
     assert_body %r{<title>Web Page</title>}
   end
@@ -48,4 +58,9 @@ class Markup::Test < TestCase
       assert_body %r{<title>Web Page</title>}
     end
   end
+
+  def test_auto_prepend
+    get '/auto/prepend', {}, 'SCRIPT_NAME' => '/mount'
+    assert_body '<img src="/mount/hello.png">'
+  end
 end
diff --git a/test/app_partials.rb b/test/app_partials.rb
new file mode 100644
index 0000000..6d7af8b
--- /dev/null
+++ b/test/app_partials.rb
@@ -0,0 +1,118 @@
+require 'test_helper'
+require 'camping'
+
+Camping.goes :Partials
+Camping.goes :TiltPartials
+
+module Partials::Controllers
+  class Index
+    def get
+      render :index
+    end
+  end
+
+  class Partial
+    def get
+      render :_partial
+    end
+  end
+
+  class Nolayout
+    def get
+      render :index, :layout => false
+    end
+  end
+
+  class Forcelayout
+    def get
+      render :_partial, :layout => true
+    end
+  end
+
+  class Nested
+    def get
+      render :nested
+    end
+  end
+end
+
+# Copy over all controllers
+module TiltPartials::Controllers
+  Partials::Controllers.constants.each do |const|
+    const_set(const, Partials::Controllers.const_get(const).dup)
+  end
+end
+
+module Partials::Views
+  def layout
+    body do
+      yield
+    end
+  end
+
+  def index
+    h1 "Index"
+    _partial
+  end
+
+  def _partial
+    p "Partial"
+  end
+
+  def nested
+    h1 "Nested"
+    regular
+  end
+
+  def regular
+    p "Regular"
+  end
+end
+
+class Partials::Test < TestCase
+  def test_underscore_partial
+    get '/'
+    assert_body "<body><h1>Index</h1><p>Partial</p></body>"
+  end
+
+  def test_underscore_partial_only
+    get '/partial'
+    assert_body "<p>Partial</p>"
+  end
+
+  def test_nolayout
+    get '/nolayout'
+    assert_body "<h1>Index</h1><p>Partial</p>"
+  end
+
+  def test_forcelayout
+    get '/forcelayout'
+    assert_body "<body><p>Partial</p></body>"
+  end
+
+  def test_netsted
+    get '/nested'
+    assert_body "<body><h1>Nested</h1><p>Regular</p></body>"
+  end
+end
+
+class TiltPartials::Test < Partials::Test
+end
+
+
+__END__
+@@ layout.str
+<body>#{yield.strip}</body>
+
+@@ index.str
+<h1>Index</h1>#{render(:_partial).strip}
+
+@@ _partial.str
+<p>Partial</p>
+
+@@ nested.str
+<h1>Nested</h1>#{render(:regular).strip}
+
+@@ regular.str
+<p>Regular</p>
+
diff --git a/test/app_reloader.rb b/test/app_reloader.rb
new file mode 100644
index 0000000..3e92b44
--- /dev/null
+++ b/test/app_reloader.rb
@@ -0,0 +1,70 @@
+require 'test_helper'
+require 'fileutils'
+require 'camping/reloader'
+
+$counter = 0
+
+module TestCaseReloader
+  def reloader
+    @reloader ||= Camping::Reloader.new(file)
+  end
+
+  def setup
+    super
+    reloader.reload!
+    assert Object.const_defined?(:Reloader), "Reloader didn't load app"
+  end
+
+  def teardown
+    super
+    assert Object.const_defined?(:Reloader), "Test removed app"
+    reloader.remove_apps
+    assert !Object.const_defined?(:Reloader), "Reloader didn't remove app"
+  end
+end
+
+class TestReloader < TestCase
+  include TestCaseReloader
+  BASE = File.expand_path('../apps/reloader', __FILE__)
+
+  def file; BASE + '.rb' end
+
+  def setup
+    $counter = 0
+    super
+  end
+
+  def test_counter
+    assert_equal 1, $counter
+  end
+  
+  def test_forced_reload
+    reloader.reload!
+    assert_equal 2, $counter
+  end
+
+  def test_mtime_reload
+    reloader.reload
+    assert_equal 1, $counter
+
+    FileUtils.touch(BASE + '.rb')
+    sleep 1
+    reloader.reload
+    assert_equal 2, $counter
+
+    FileUtils.touch(BASE + '/reload_me.rb')
+    sleep 1
+    reloader.reload
+    assert_equal 3, $counter
+  end
+end
+
+class TestConfigRu < TestReloader
+  BASE = File.expand_path('../apps/reloader', __FILE__)
+  def file; BASE + '/config.ru' end
+
+  def test_name
+    assert_equal Reloader, reloader.apps[:reloader]
+  end
+end
+
diff --git a/test/app_sessions.rb b/test/app_sessions.rb
index 6d99f8b..d017dc7 100644
--- a/test/app_sessions.rb
+++ b/test/app_sessions.rb
@@ -36,11 +36,7 @@ class Sessions::Test < TestCase
   def test_session
     get '/one'
     follow_redirect!
-    
-    get '/two'
     follow_redirect!
-    
-    get '/three'
     assert_body "[42, 56, 99]"
   end
 end
diff --git a/test/app_simple.rb b/test/app_simple.rb
index 1a952f4..7272896 100644
--- a/test/app_simple.rb
+++ b/test/app_simple.rb
@@ -47,6 +47,12 @@ module Simple::Controllers
       "Optional: #{value}"
     end
   end
+
+  class Weird
+    def get
+      redirect MultipleComplexX, 'hello%#/world'
+    end
+  end
 end
 
 class Simple::Test < TestCase
@@ -94,4 +100,10 @@ class Simple::Test < TestCase
     get '/optional/override'
     assert_body "Optional: override"
   end
+
+  def test_weird
+    get '/weird'
+    follow_redirect!
+    assert_body 'Complex: hello%#/world'
+  end
 end
diff --git a/test/apps/reloader.rb b/test/apps/reloader.rb
new file mode 100644
index 0000000..569a52e
--- /dev/null
+++ b/test/apps/reloader.rb
@@ -0,0 +1,7 @@
+require 'camping'
+
+Camping.goes :Reloader
+
+$LOAD_PATH << File.dirname(__FILE__)
+require 'reloader/reload_me'
+
diff --git a/test/apps/reloader/config.ru b/test/apps/reloader/config.ru
new file mode 100644
index 0000000..557a745
--- /dev/null
+++ b/test/apps/reloader/config.ru
@@ -0,0 +1,5 @@
+$LOAD_PATH << File.dirname(__FILE__) + '/../'
+
+require 'reloader'
+run Reloader
+
diff --git a/test/apps/reloader/reload_me.rb b/test/apps/reloader/reload_me.rb
new file mode 100644
index 0000000..369f2d5
--- /dev/null
+++ b/test/apps/reloader/reload_me.rb
@@ -0,0 +1,2 @@
+$counter += 1
+
diff --git a/test/apps/reloader_indirect.rb b/test/apps/reloader_indirect.rb
new file mode 100644
index 0000000..f887f5a
--- /dev/null
+++ b/test/apps/reloader_indirect.rb
@@ -0,0 +1,3 @@
+$LOAD_PATH << File.dirname(__FILE__)
+require 'reloader'
+
diff --git a/test/test_helper.rb b/test/test_helper.rb
index 0ab0402..19b8df1 100644
--- a/test/test_helper.rb
+++ b/test/test_helper.rb
@@ -5,7 +5,12 @@ begin
 rescue LoadError
 end
 
-require 'camping-unabridged'
+if ENV['ABRIDGED']
+  require 'camping'
+else
+  require 'camping-unabridged'
+end
+
 require 'test/unit'
 require 'rack/test'
 
@@ -36,16 +41,15 @@ class TestCase < Test::Unit::TestCase
   def assert_body(str)
     case str
     when Regexp
-      assert_match(str, last_response.body)
+      assert_match(str, last_response.body.strip)
     else
-      assert_equal(str.to_s, last_response.body)
+      assert_equal(str.to_s, last_response.body.strip)
     end
   end
   
   def assert_status(code)
     assert_equal(code, last_response.status)
   end
-  
-  def test_noop
-  end
+
+  def test_silly; end
 end

-- 
camping.git



More information about the Pkg-ruby-extras-commits mailing list