camping 2.0 → 2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +11 -0
- data/Rakefile +21 -3
- data/bin/camping +2 -85
- data/book/51_upgrading +17 -0
- data/lib/camping-unabridged.rb +56 -16
- data/lib/camping.rb +37 -32
- data/lib/camping/mab.rb +2 -0
- data/lib/camping/reloader.rb +39 -45
- data/lib/camping/server.rb +217 -130
- data/lib/camping/session.rb +5 -6
- data/lib/camping/template.rb +17 -0
- data/test/app_markup.rb +51 -0
- data/test/app_route_generating.rb +22 -0
- data/test/app_sessions.rb +46 -0
- data/test/app_simple.rb +97 -0
- data/test/test_helper.rb +51 -0
- metadata +9 -16
- data/doc/api.html +0 -1953
- data/doc/book.html +0 -73
- data/doc/book/01_introduction.html +0 -57
- data/doc/book/02_getting_started.html +0 -573
- data/doc/book/51_upgrading.html +0 -146
- data/doc/created.rid +0 -1
- data/doc/images/Camping.gif +0 -0
- data/doc/images/loadingAnimation.gif +0 -0
- data/doc/images/permalink.gif +0 -0
- data/doc/index.html +0 -148
- data/doc/js/camping.js +0 -79
- data/doc/js/jquery.js +0 -32
- data/doc/rdoc.css +0 -117
    
        data/CHANGELOG
    CHANGED
    
    | @@ -1,3 +1,14 @@ | |
| 1 | 
            +
            = 2.1
         | 
| 2 | 
            +
            === 19th Aug, 2010 (whyday)
         | 
| 3 | 
            +
            * Helpers#R now calls to_param on any object it passes in
         | 
| 4 | 
            +
            * Fix route generation issue with routes including "." (#22)
         | 
| 5 | 
            +
            * Improved tests
         | 
| 6 | 
            +
            * Improved 1.9 support
         | 
| 7 | 
            +
            * Camping::Server is now built upon Rack::Server
         | 
| 8 | 
            +
            * Add support for ERB, Haml etc through Tilt
         | 
| 9 | 
            +
            * Introducing Camping.options and Camping#set
         | 
| 10 | 
            +
            * Camping::Server only loads ActiveRecord when needed
         | 
| 11 | 
            +
             | 
| 1 12 | 
             
            = 2.0
         | 
| 2 13 | 
             
            === 9th Apr, 2010
         | 
| 3 14 | 
             
            * Speed-up of Camping::Mab (thanks zimbatm!)
         | 
    
        data/Rakefile
    CHANGED
    
    | @@ -10,7 +10,7 @@ task :default => :check | |
| 10 10 |  | 
| 11 11 | 
             
            ## Constants
         | 
| 12 12 | 
             
            NAME = "camping"
         | 
| 13 | 
            -
            BRANCH = "2. | 
| 13 | 
            +
            BRANCH = "2.1"
         | 
| 14 14 | 
             
            GIT = ENV['GIT'] || "git"
         | 
| 15 15 | 
             
            REV = `#{GIT} rev-list HEAD`.strip.split.length
         | 
| 16 16 | 
             
            VERS = ENV['VERSION'] || (REV.zero? ? BRANCH : [BRANCH, REV] * '.')
         | 
| @@ -60,6 +60,7 @@ omni = | |
| 60 60 | 
             
                s.add_dependency('sqlite3-ruby', '>=1.1.0.1')
         | 
| 61 61 | 
             
                s.add_dependency('mongrel')
         | 
| 62 62 | 
             
                s.add_dependency('RedCloth')
         | 
| 63 | 
            +
                s.add_dependency('markaby')
         | 
| 63 64 | 
             
              end
         | 
| 64 65 |  | 
| 65 66 | 
             
            ## RDoc
         | 
| @@ -123,7 +124,8 @@ end | |
| 123 124 |  | 
| 124 125 | 
             
            ## Tests
         | 
| 125 126 | 
             
            Rake::TestTask.new(:test) do |t|
         | 
| 126 | 
            -
              t. | 
| 127 | 
            +
              t.libs << "test"
         | 
| 128 | 
            +
              t.test_files = FileList['test/app_*.rb']
         | 
| 127 129 | 
             
            #  t.warning = true
         | 
| 128 130 | 
             
            #  t.verbose = true
         | 
| 129 131 | 
             
            end
         | 
| @@ -139,14 +141,19 @@ task :diff do | |
| 139 141 | 
             
              u << Ruby2Ruby.new.process(RubyParser.new.parse(File.read("lib/camping.rb")))
         | 
| 140 142 | 
             
              m << Ruby2Ruby.new.process(RubyParser.new.parse(File.read("lib/camping-unabridged.rb")))
         | 
| 141 143 |  | 
| 144 | 
            +
              u.flush
         | 
| 145 | 
            +
              m.flush
         | 
| 146 | 
            +
              
         | 
| 142 147 | 
             
              sh "diff -u #{u.path} #{m.path} | less"
         | 
| 143 148 |  | 
| 144 149 | 
             
              u.delete
         | 
| 145 150 | 
             
              m.delete
         | 
| 146 151 | 
             
            end
         | 
| 147 152 |  | 
| 153 | 
            +
            error = false
         | 
| 154 | 
            +
             | 
| 148 155 | 
             
            ## Check
         | 
| 149 | 
            -
            task :check => ["check:valid", "check:size", "check:lines"]
         | 
| 156 | 
            +
            task :check => ["test", "check:valid", "check:size", "check:lines", "check:exit"]
         | 
| 150 157 | 
             
            namespace :check do
         | 
| 151 158 |  | 
| 152 159 | 
             
              desc "Check source code validity"
         | 
| @@ -155,8 +162,13 @@ namespace :check do | |
| 155 162 | 
             
                u = RubyParser.new.parse(File.read("lib/camping-unabridged.rb"))
         | 
| 156 163 | 
             
                m = RubyParser.new.parse(File.read("lib/camping.rb"))
         | 
| 157 164 |  | 
| 165 | 
            +
                u.reject! do |sexp|
         | 
| 166 | 
            +
                  sexp.is_a?(Sexp) and sexp[1] == s(:gvar, :$LOADED_FEATURES)
         | 
| 167 | 
            +
                end
         | 
| 168 | 
            +
                
         | 
| 158 169 | 
             
                unless u == m
         | 
| 159 170 | 
             
                  STDERR.puts "camping.rb and camping-unabridged.rb are not synchronized."
         | 
| 171 | 
            +
                  error = true
         | 
| 160 172 | 
             
                end
         | 
| 161 173 | 
             
              end
         | 
| 162 174 |  | 
| @@ -169,6 +181,7 @@ namespace :check do | |
| 169 181 | 
             
                end
         | 
| 170 182 | 
             
                if File.size("lib/camping.rb") > SIZE_LIMIT
         | 
| 171 183 | 
             
                  STDERR.puts "lib/camping.rb: file is too big (> #{SIZE_LIMIT})"
         | 
| 184 | 
            +
                  error = true
         | 
| 172 185 | 
             
                end
         | 
| 173 186 | 
             
              end
         | 
| 174 187 |  | 
| @@ -177,10 +190,15 @@ namespace :check do | |
| 177 190 | 
             
                i = 1
         | 
| 178 191 | 
             
                File.open("lib/camping.rb").each_line do |line|
         | 
| 179 192 | 
             
                  if line.size > 81 # 1 added for \n
         | 
| 193 | 
            +
                    error = true
         | 
| 180 194 | 
             
                    STDERR.puts "lib/camping.rb:#{i}: line too long (#{line[-10..-1].inspect})"
         | 
| 181 195 | 
             
                  end
         | 
| 182 196 | 
             
                  i += 1
         | 
| 183 197 | 
             
                end
         | 
| 184 198 | 
             
              end
         | 
| 199 | 
            +
              
         | 
| 200 | 
            +
              task :exit do
         | 
| 201 | 
            +
                exit 1 if error
         | 
| 202 | 
            +
              end
         | 
| 185 203 |  | 
| 186 204 | 
             
            end
         | 
    
        data/bin/camping
    CHANGED
    
    | @@ -1,97 +1,14 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 2 |  | 
| 3 | 
            -
            trap("INT") { exit }
         | 
| 4 | 
            -
            require 'optparse'
         | 
| 5 | 
            -
            require 'ostruct'
         | 
| 6 | 
            -
            require 'stringio'
         | 
| 7 | 
            -
            require 'yaml'
         | 
| 8 | 
            -
             | 
| 9 3 | 
             
            $:.unshift File.dirname(__FILE__) + "/../lib"
         | 
| 4 | 
            +
             | 
| 10 5 | 
             
            require 'camping'
         | 
| 11 6 | 
             
            require 'camping/server'
         | 
| 12 7 |  | 
| 13 | 
            -
            conf = OpenStruct.new(:host => '0.0.0.0', :port => 3301)
         | 
| 14 | 
            -
             | 
| 15 | 
            -
            # Setup paths
         | 
| 16 | 
            -
            if home = ENV['HOME'] # POSIX
         | 
| 17 | 
            -
              db_path = File.join(home, '.camping.db')
         | 
| 18 | 
            -
              rc_path = File.join(home, '.campingrc')
         | 
| 19 | 
            -
            elsif home = ENV['APPDATA'] # MSWIN
         | 
| 20 | 
            -
              db_path = File.join(home, 'Camping.db')
         | 
| 21 | 
            -
              rc_path = File.join(home, 'Campingrc')
         | 
| 22 | 
            -
            end
         | 
| 23 | 
            -
             | 
| 24 | 
            -
            # Parse options
         | 
| 25 | 
            -
            opts = OptionParser.new do |opts|
         | 
| 26 | 
            -
              opts.banner = "Usage: camping app1.rb, app2.rb..."
         | 
| 27 | 
            -
              opts.define_head "#{File.basename($0)}, the microframework ON-button for ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
         | 
| 28 | 
            -
              opts.separator ""
         | 
| 29 | 
            -
              opts.separator "Specific options:"
         | 
| 30 | 
            -
             | 
| 31 | 
            -
              opts.on("-h", "--host HOSTNAME", "Host for web server to bind to (default is all IPs)") { |val| conf.host = val }
         | 
| 32 | 
            -
              opts.on("-p", "--port NUM", "Port for web server (defaults to #{conf.port})") { |val| conf.port = val }
         | 
| 33 | 
            -
              opts.on("-d", "--database FILE", "SQLite3 database path (defaults to #{db_path ? db_path : '<none>'})") { |db_path| conf.database = {:adapter => 'sqlite3', :database => db_path} }
         | 
| 34 | 
            -
              opts.on("-C", "--console", "Run in console mode with IRB") { conf.server = "console" }
         | 
| 35 | 
            -
              server_list = ["mongrel", "webrick", "console"]
         | 
| 36 | 
            -
              opts.on("-s", "--server NAME", server_list, "Server to force (#{server_list.join(', ')})") { |val| conf.server = val }
         | 
| 37 | 
            -
             | 
| 38 | 
            -
              opts.separator ""
         | 
| 39 | 
            -
              opts.separator "Common options:"
         | 
| 40 | 
            -
             | 
| 41 | 
            -
              # No argument, shows at tail.  This will print an options summary.
         | 
| 42 | 
            -
              # Try it and see!
         | 
| 43 | 
            -
              opts.on_tail("-?", "--help", "Show this message") do
         | 
| 44 | 
            -
                puts opts
         | 
| 45 | 
            -
                exit
         | 
| 46 | 
            -
              end
         | 
| 47 | 
            -
             | 
| 48 | 
            -
              # Another typical switch to print the version.
         | 
| 49 | 
            -
              opts.on_tail("-v", "--version", "Show version") do
         | 
| 50 | 
            -
                puts Gem.loaded_specs['camping'].version
         | 
| 51 | 
            -
                exit
         | 
| 52 | 
            -
              end
         | 
| 53 | 
            -
            end
         | 
| 54 | 
            -
             | 
| 55 8 | 
             
            begin
         | 
| 56 | 
            -
               | 
| 9 | 
            +
              Camping::Server.start
         | 
| 57 10 | 
             
            rescue OptionParser::ParseError => ex
         | 
| 58 11 | 
             
              STDERR.puts "!! #{ex.message}"
         | 
| 59 12 | 
             
              puts "** use `#{File.basename($0)} --help` for more details..."
         | 
| 60 13 | 
             
              exit 1
         | 
| 61 14 | 
             
            end
         | 
| 62 | 
            -
             | 
| 63 | 
            -
            if ARGV.length < 1
         | 
| 64 | 
            -
              puts opts
         | 
| 65 | 
            -
              exit 1
         | 
| 66 | 
            -
            end
         | 
| 67 | 
            -
             | 
| 68 | 
            -
            # Load configuration if any
         | 
| 69 | 
            -
            if rc_path and File.exists?(rc_path)
         | 
| 70 | 
            -
              YAML.load_file(rc_path).each do |k,v|
         | 
| 71 | 
            -
                conf.send("#{k}=", v) unless conf.send(k)
         | 
| 72 | 
            -
              end 
         | 
| 73 | 
            -
              puts "** conf file #{rc_path} loaded"
         | 
| 74 | 
            -
            end
         | 
| 75 | 
            -
             | 
| 76 | 
            -
            # Default db
         | 
| 77 | 
            -
            if conf.database.nil? and db_path
         | 
| 78 | 
            -
              conf.database = { :adapter => 'sqlite3', :database => db_path }
         | 
| 79 | 
            -
            end
         | 
| 80 | 
            -
             | 
| 81 | 
            -
             | 
| 82 | 
            -
            # get a copy of the paths to pass to the server
         | 
| 83 | 
            -
            paths = ARGV.dup
         | 
| 84 | 
            -
             | 
| 85 | 
            -
            # Check that mongrel exists 
         | 
| 86 | 
            -
            if conf.server.nil? || conf.server == "mongrel"
         | 
| 87 | 
            -
              begin
         | 
| 88 | 
            -
                require 'mongrel'
         | 
| 89 | 
            -
                conf.server = "mongrel"
         | 
| 90 | 
            -
              rescue LoadError 
         | 
| 91 | 
            -
                puts "!! Could not load mongrel. Falling back to webrick."
         | 
| 92 | 
            -
                conf.server = "webrick"
         | 
| 93 | 
            -
              end
         | 
| 94 | 
            -
            end
         | 
| 95 | 
            -
             | 
| 96 | 
            -
            server = Camping::Server.new(conf, paths)
         | 
| 97 | 
            -
            server.start
         | 
    
        data/book/51_upgrading
    CHANGED
    
    | @@ -1,5 +1,22 @@ | |
| 1 1 | 
             
            = Appendix I: Upgrade Notes
         | 
| 2 2 |  | 
| 3 | 
            +
            This document includes everything needed in order to *upgrade* your
         | 
| 4 | 
            +
            applications. If you're looking for all the new features in a version, please
         | 
| 5 | 
            +
            have a look at the CHANGELOG in the Camping source.
         | 
| 6 | 
            +
             | 
| 7 | 
            +
             | 
| 8 | 
            +
            == From 2.0 to 2.1
         | 
| 9 | 
            +
            === Options
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            In Camping 2.1 there is now a built-in way to store options and settings. If
         | 
| 12 | 
            +
            you use cookie session, it means that you'll now have to change to:
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              module Nuts
         | 
| 15 | 
            +
                set :secret, "Very secret text, which no-one else should know!"
         | 
| 16 | 
            +
                include Camping::Session
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
             | 
| 3 20 | 
             
            == From 1.5 to 2.0
         | 
| 4 21 | 
             
            === Rack
         | 
| 5 22 |  | 
    
        data/lib/camping-unabridged.rb
    CHANGED
    
    | @@ -12,6 +12,8 @@ | |
| 12 12 | 
             
            require "uri"
         | 
| 13 13 | 
             
            require "rack"
         | 
| 14 14 |  | 
| 15 | 
            +
            $LOADED_FEATURES << "camping.rb"
         | 
| 16 | 
            +
             | 
| 15 17 | 
             
            class Object #:nodoc:
         | 
| 16 18 | 
             
              def meta_def(m,&b) #:nodoc:
         | 
| 17 19 | 
             
                (class<<self;self end).send(:define_method,m,&b)
         | 
| @@ -46,6 +48,7 @@ module Camping | |
| 46 48 | 
             
              S = IO.read(__FILE__) rescue nil
         | 
| 47 49 | 
             
              P = "<h1>Cam\ping Problem!</h1><h2>%s</h2>"
         | 
| 48 50 | 
             
              U = Rack::Utils
         | 
| 51 | 
            +
              O = {}
         | 
| 49 52 | 
             
              Apps = []
         | 
| 50 53 | 
             
              # An object-like Hash.
         | 
| 51 54 | 
             
              # All Camping query string and cookie variables are loaded as this.
         | 
| @@ -183,7 +186,7 @@ module Camping | |
| 183 186 | 
             
                  raise "bad route" unless u = c.urls.find{|x|
         | 
| 184 187 | 
             
                    break x if x.scan(p).size == g.size && 
         | 
| 185 188 | 
             
                      /^#{x}\/?$/ =~ (x=g.inject(x){|x,a|
         | 
| 186 | 
            -
                        x.sub p,U.escape((a | 
| 189 | 
            +
                        x.sub p,U.escape((a.to_param rescue a))}.gsub(/\\(.)/){$1})
         | 
| 187 190 | 
             
                  }
         | 
| 188 191 | 
             
                  h.any?? u+"?"+U.build_query(h[0]) : u
         | 
| 189 192 | 
             
                end
         | 
| @@ -195,7 +198,7 @@ module Camping | |
| 195 198 | 
             
                #   self / "styles.css" #=> "styles.css"
         | 
| 196 199 | 
             
                #   self / R(Edit, 1)   #=> "/blog/edit/1"
         | 
| 197 200 | 
             
                #
         | 
| 198 | 
            -
                def /(p); p[0] | 
| 201 | 
            +
                def /(p); p[0] == ?/ ? @root + p : p end
         | 
| 199 202 |  | 
| 200 203 | 
             
                # Builds a URL route to a controller or a path, returning a URI object.
         | 
| 201 204 | 
             
                # This way you'll get the hostname and the port number, a complete URL.
         | 
| @@ -235,7 +238,25 @@ module Camping | |
| 235 238 | 
             
              module Base
         | 
| 236 239 | 
             
                attr_accessor :env, :request, :root, :input, :cookies, :state,
         | 
| 237 240 | 
             
                              :status, :headers, :body
         | 
| 238 | 
            -
             | 
| 241 | 
            +
                
         | 
| 242 | 
            +
                T = {}
         | 
| 243 | 
            +
                L = :layout
         | 
| 244 | 
            +
                
         | 
| 245 | 
            +
                # Finds a template, returning either:
         | 
| 246 | 
            +
                # 
         | 
| 247 | 
            +
                #   false             # => Could not find template
         | 
| 248 | 
            +
                #   true              # => Found template in Views
         | 
| 249 | 
            +
                #   instance of Tilt  # => Found template in a file
         | 
| 250 | 
            +
                def lookup(n)
         | 
| 251 | 
            +
                  T.fetch(n.to_sym) do |k|
         | 
| 252 | 
            +
                    t = Views.method_defined?(k) ||
         | 
| 253 | 
            +
                      (f = Dir[[O[:views] || "views", "#{n}.*"]*'/'][0]) &&
         | 
| 254 | 
            +
                      Template.new(f, O[f[/\.(\w+)$/, 1].to_sym] || {})
         | 
| 255 | 
            +
                    
         | 
| 256 | 
            +
                    O[:dynamic_templates] ? t : T[k] = t
         | 
| 257 | 
            +
                  end
         | 
| 258 | 
            +
                end
         | 
| 259 | 
            +
                
         | 
| 239 260 | 
             
                # Display a view, calling it by its method name +v+.  If a <tt>layout</tt>
         | 
| 240 261 | 
             
                # method is found in Camping::Views, it will be used to wrap the HTML.
         | 
| 241 262 | 
             
                #
         | 
| @@ -248,8 +269,15 @@ module Camping | |
| 248 269 | 
             
                #     end
         | 
| 249 270 | 
             
                #   end
         | 
| 250 271 | 
             
                #
         | 
| 251 | 
            -
                def render(v | 
| 252 | 
            -
                   | 
| 272 | 
            +
                def render(v, *a, &b)
         | 
| 273 | 
            +
                  if t = lookup(v)
         | 
| 274 | 
            +
                    o = Hash === a[-1] ? a.pop : {}
         | 
| 275 | 
            +
                    s = (t == true) ? mab{ send(v, *a, &b) } : t.render(self, o[:locals] || {}, &b)
         | 
| 276 | 
            +
                    s = render(L, o.merge(L => false)) { s } if v.to_s[0] != ?_ && o[L] != false && lookup(L)
         | 
| 277 | 
            +
                    s
         | 
| 278 | 
            +
                  else
         | 
| 279 | 
            +
                    raise "Can't find template #{v}"
         | 
| 280 | 
            +
                  end
         | 
| 253 281 | 
             
                end
         | 
| 254 282 |  | 
| 255 283 | 
             
                # You can directly return HTML form your controller for quick debugging
         | 
| @@ -262,11 +290,8 @@ module Camping | |
| 262 290 | 
             
                #   end
         | 
| 263 291 | 
             
                #
         | 
| 264 292 | 
             
                # You can also pass true to use the :layout HTML wrapping method
         | 
| 265 | 
            -
                def mab( | 
| 266 | 
            -
                   | 
| 267 | 
            -
                  s=m.capture(&b)
         | 
| 268 | 
            -
                  s=m.capture{layout{s}} if l && m.respond_to?(:layout)
         | 
| 269 | 
            -
                  s
         | 
| 293 | 
            +
                def mab(&b)
         | 
| 294 | 
            +
                  (@mab ||= Mab.new({},self)).capture(&b)
         | 
| 270 295 | 
             
                end
         | 
| 271 296 |  | 
| 272 297 | 
             
                # A quick means of setting this controller's status, body and headers
         | 
| @@ -355,7 +380,7 @@ module Camping | |
| 355 380 | 
             
                #     end
         | 
| 356 381 | 
             
                #   end
         | 
| 357 382 | 
             
                def to_a
         | 
| 358 | 
            -
                  @env['rack.session'] = @state
         | 
| 383 | 
            +
                  @env['rack.session'] = Hash[@state]
         | 
| 359 384 | 
             
                  r = Rack::Response.new(@body, @status, @headers)
         | 
| 360 385 | 
             
                  @cookies.each do |k, v|
         | 
| 361 386 | 
             
                    next if @old_cookies[k] == v
         | 
| @@ -517,11 +542,11 @@ module Camping | |
| 517 542 | 
             
                  # * Classes with routes are searched in order of their creation.
         | 
| 518 543 | 
             
                  #
         | 
| 519 544 | 
             
                  # So, define your catch-all controllers last.
         | 
| 520 | 
            -
                  def D(p, m)
         | 
| 545 | 
            +
                  def D(p, m, e)
         | 
| 521 546 | 
             
                    p = '/' if !p || !p[0]
         | 
| 522 547 | 
             
                    r.map { |k|
         | 
| 523 548 | 
             
                      k.urls.map { |x|
         | 
| 524 | 
            -
                        return (k. | 
| 549 | 
            +
                        return (k.method_defined?(m)) ?
         | 
| 525 550 | 
             
                          [k, m, *$~[1..-1]] : [I, 'r501', m] if p =~ /^#{x}\/?$/
         | 
| 526 551 | 
             
                      }
         | 
| 527 552 | 
             
                    }
         | 
| @@ -547,9 +572,9 @@ module Camping | |
| 547 572 | 
             
                    end
         | 
| 548 573 | 
             
                    constants.map { |c|
         | 
| 549 574 | 
             
                      k = const_get(c)
         | 
| 550 | 
            -
                      k.send :include,C,Base,Helpers,Models
         | 
| 575 | 
            +
                      k.send :include,C,X,Base,Helpers,Models
         | 
| 551 576 | 
             
                      @r=[k]+r if r-[k]==r
         | 
| 552 | 
            -
                      k.meta_def(:urls){["/#{c.scan(/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.respond_to?:urls
         | 
| 577 | 
            +
                      k.meta_def(:urls){["/#{c.to_s.scan(/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.respond_to?:urls
         | 
| 553 578 | 
             
                    }
         | 
| 554 579 | 
             
                  end
         | 
| 555 580 | 
             
                end
         | 
| @@ -584,7 +609,7 @@ module Camping | |
| 584 609 | 
             
                def call(e)
         | 
| 585 610 | 
             
                  X.M
         | 
| 586 611 | 
             
                  p = e['PATH_INFO'] = U.unescape(e['PATH_INFO'])
         | 
| 587 | 
            -
                  k,m,*a=X.D p,e['REQUEST_METHOD'].downcase
         | 
| 612 | 
            +
                  k,m,*a=X.D p,e['REQUEST_METHOD'].downcase,e
         | 
| 588 613 | 
             
                  k.new(e,m).service(*a).to_a
         | 
| 589 614 | 
             
                rescue
         | 
| 590 615 | 
             
                  r500(:I, k, m, $!, :env => e).to_a
         | 
| @@ -627,6 +652,20 @@ module Camping | |
| 627 652 | 
             
                  m = a.shift.new(method(:call), *a, &b)
         | 
| 628 653 | 
             
                  meta_def(:call) { |e| m.call(e) }
         | 
| 629 654 | 
             
                end
         | 
| 655 | 
            +
                
         | 
| 656 | 
            +
                # A hash where you can set different settings.
         | 
| 657 | 
            +
                def options
         | 
| 658 | 
            +
                  O
         | 
| 659 | 
            +
                end
         | 
| 660 | 
            +
                
         | 
| 661 | 
            +
                # Shortcut for setting options:
         | 
| 662 | 
            +
                # 
         | 
| 663 | 
            +
                #   module Blog
         | 
| 664 | 
            +
                #     set :secret, "Hello!"
         | 
| 665 | 
            +
                #   end
         | 
| 666 | 
            +
                def set(k, v)
         | 
| 667 | 
            +
                  O[k] = v
         | 
| 668 | 
            +
                end
         | 
| 630 669 | 
             
              end
         | 
| 631 670 |  | 
| 632 671 | 
             
              # Views is an empty module for storing methods which create HTML. The HTML
         | 
| @@ -696,6 +735,7 @@ module Camping | |
| 696 735 | 
             
              end
         | 
| 697 736 |  | 
| 698 737 | 
             
              autoload :Mab, 'camping/mab'
         | 
| 738 | 
            +
              autoload :Template, 'camping/template'
         | 
| 699 739 | 
             
              C
         | 
| 700 740 | 
             
            end
         | 
| 701 741 |  | 
    
        data/lib/camping.rb
    CHANGED
    
    | @@ -1,40 +1,45 @@ | |
| 1 1 | 
             
            require "uri";require "rack";class Object;def meta_def m,&b;(class<<self;self
         | 
| 2 2 | 
             
            end).send:define_method,m,&b end end;module Camping;C=self;S=IO.read(__FILE__
         | 
| 3 | 
            -
            )rescue nil;P="<h1>Cam\ping Problem!</h1><h2>%s</h2>";U=Rack::Utils;Apps=[]
         | 
| 3 | 
            +
            )rescue nil;P="<h1>Cam\ping Problem!</h1><h2>%s</h2>";U=Rack::Utils;O={};Apps=[]
         | 
| 4 4 | 
             
            class H<Hash;def method_missing m,*a;m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m.
         | 
| 5 5 | 
             
            to_s]:super end;undef id,type if ??==63;end;module Helpers;def R c,*g;p,h=
         | 
| 6 6 | 
             
            /\(.+?\)/,g.grep(Hash);g-=h;raise"bad route"unless u=c.urls.find{|x|break x if
         | 
| 7 | 
            -
            x.scan(p).size==g.size&&/^#{x}\/?$/=~(x=g.inject(x){|x,a|x.sub p,U.escape((a | 
| 8 | 
            -
             | 
| 7 | 
            +
            x.scan(p).size==g.size&&/^#{x}\/?$/=~(x=g.inject(x){|x,a|x.sub p,U.escape((a.
         | 
| 8 | 
            +
            to_param rescue a))}.gsub(/\\(.)/){$1})};h.any?? u+"?"+U.build_query(h[0]):u end;def
         | 
| 9 9 | 
             
            / p;p[0]==?/?@root + p : p end;def URL c='/',*a;c=R(c, *a) if c.respond_to?(
         | 
| 10 10 | 
             
            :urls);c=self/c;c=@request.url[/.{8,}?(?=\/)/]+c if c[0]==?/;URI c end end
         | 
| 11 11 | 
             
            module Base;attr_accessor:env,:request,:root,:input,:cookies,:state,:status,
         | 
| 12 | 
            -
            :headers,:body;def  | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
            def  | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
            ) | 
| 27 | 
            -
             | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
            end; | 
| 33 | 
            -
             | 
| 34 | 
            -
            k, | 
| 35 | 
            -
             | 
| 36 | 
            -
             | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 12 | 
            +
            :headers,:body;T={};L=:layout;def lookup n;T.fetch(n.to_sym){|k|t=Views.
         | 
| 13 | 
            +
            method_defined?(k)||(f=Dir[[O[:views]||"views","#{n}.*"]*'/'][0])&&Template.
         | 
| 14 | 
            +
            new(f,O[f[/\.(\w+)$/,1].to_sym]||{});O[:dynamic_templates]?t:T[k]=t} end
         | 
| 15 | 
            +
            def render(v,*a,&b)if t=lookup(v);o=Hash===a[-1]?a.pop: {};s=(t==true)?mab{
         | 
| 16 | 
            +
            send v,*a,&b}: t.render(self,o[:locals]||{},&b);s=render(L,o.merge(L=>false)){s
         | 
| 17 | 
            +
            }if v.to_s[0]!=?_&&o[L]!=false&&lookup(L);s;else;raise"Can't find template #{v}"end
         | 
| 18 | 
            +
            end;def mab &b;(@mab||=Mab.new({},self)).capture(&b) end;def r s,b,h={};b,h=h,
         | 
| 19 | 
            +
            b if Hash===b;@status=s;@headers.merge!(h);@body=b;end;def redirect *a;r 302,'',
         | 
| 20 | 
            +
            'Location'=>URL(*a).to_s;end;def r404 p;P%"#{p} not found"end;def r500 k,m,e
         | 
| 21 | 
            +
            raise e;end;def r501 m;P%"#{m.upcase} not implemented"end;def to_a;@env[
         | 
| 22 | 
            +
            'rack.session']=Hash[@state];r=Rack::Response.new(@body,@status,@headers)
         | 
| 23 | 
            +
            @cookies.each{|k,v|next if @old_cookies[k]==v;v={:value=>v,:path=>self/"/"} if
         | 
| 24 | 
            +
            String===v;r.set_cookie(k,v)};r.to_a;end;def initialize(env,m) r=@request=Rack::
         | 
| 25 | 
            +
            Request.new(@env=env);@root,@input,@cookies,@state,@headers,@status,@method=r.
         | 
| 26 | 
            +
            script_name.sub(/\/$/,''),n(r.params),H[@old_cookies = r.cookies],H[r.session],
         | 
| 27 | 
            +
            {},m=~/r(\d+)/?$1.to_i: 200,m end;def n h;Hash===h ?h.inject(H[]){|m,(k,v)|m[k]=
         | 
| 28 | 
            +
            n(v);m}: h end;def service *a;r=catch(:halt){send(@method,*a)};@body||=r;self
         | 
| 29 | 
            +
            end;end;module Controllers;@r=[];class<<self;def r;@r end;def R *u;r=@r;Class.
         | 
| 30 | 
            +
            new{meta_def(:urls){u};meta_def(:inherited){|x|r<<x}}end;def D p,m,e;p='/'if !p||
         | 
| 31 | 
            +
            !p[0];r.map{|k|k.urls.map{|x|return(k.method_defined? m)?[k,m,*$~[1..-1]]:[I,
         | 
| 32 | 
            +
            'r501',m]if p=~/^#{x}\/?$/}};[I,'r404',p] end;N=H.new{|_,x|x.downcase}.merge!(
         | 
| 33 | 
            +
            "N"=>'(\d+)',"X"=>'([^/]+)',"Index"=>'');def M;def M;end;constants.map{|c|k=
         | 
| 34 | 
            +
            const_get(c);k.send:include,C,X,Base,Helpers,Models;@r=[k]+r if r-[k]==r
         | 
| 35 | 
            +
            k.meta_def(:urls){ [ "/#{c.to_s.scan(/.[^A-Z]*/).map(&N.method(:[]))*'/'}"]}if !k.
         | 
| 36 | 
            +
            respond_to?:urls}end end;I=R();end;X=Controllers;class<<self;def goes m;Apps<<
         | 
| 37 | 
            +
            eval(S.gsub(/Camping/,m.to_s),TOPLEVEL_BINDING) end;def call e;X.M
         | 
| 38 | 
            +
            p=e['PATH_INFO']=U.unescape(e['PATH_INFO']);k,m,*a=X.D p,e['REQUEST_METHOD'].
         | 
| 39 | 
            +
            downcase,e;k.new(e,m).service(*a).to_a;rescue;r500(:I,k,m,$!,:env=>e).to_a;end
         | 
| 40 | 
            +
            def method_missing m,c,*a;X.M;h=Hash===a[-1]?a.pop: {};e=H[Rack::MockRequest.
         | 
| 41 | 
            +
            env_for('',h.delete(:env)||{})];k=X.const_get(c).new(e,m.to_s);h.each{|i,v|k.
         | 
| 42 | 
            +
            send"#{i}=",v};k.service(*a);end;def use*a,&b;m=a.shift.new(method(:call),*a,&b)
         | 
| 43 | 
            +
            meta_def(:call){|e|m.call(e)}end;def options;O end;def set k,v;O[k]=v end end
         | 
| 44 | 
            +
            module Views;include X,Helpers end;module Models;autoload:Base,'camping/ar';end
         | 
| 45 | 
            +
            autoload:Mab,'camping/mab';autoload:Template,'camping/template';C end
         |