Module Camping
In: lib/camping/fastcgi.rb
lib/camping/reloader.rb
lib/camping/db.rb
lib/camping/session.rb
lib/camping-unabridged.rb

Camping

The camping module contains three modules for separating your application:

Of use to you is also one module for storing helpful additional methods:

The Camping Server

How do you run Camping apps? Oh, uh… The Camping Server!

The Camping Server is, firstly and thusly, a set of rules. At the very least, The Camping Server must:

  • Load all Camping apps in a directory.
  • Load new apps that appear in that directory.
  • Mount those apps according to their filename. (e.g. blog.rb is mounted at /blog.)
  • Run each app‘s create method upon startup.
  • Reload the app if its modification time changes.
  • Reload the app if it requires any files under the same directory and one of their modification times changes.
  • Support the X-Sendfile header.

In fact, Camping comes with its own little The Camping Server.

At a command prompt, run: camping examples/ and the entire examples/ directory will be served.

Configurations also exist for Apache and Lighttpd. See code.whytheluckystiff.net/camping/wiki/TheCampingServer.

The create method

Many postambles will check for your application‘s create method and will run it when the web server starts up. This is a good place to check for database tables and create those tables to save users of your application from needing to manually set them up.

  def Blog.create
    unless Blog::Models::Post.table_exists?
      ActiveRecord::Schema.define do
        create_table :blog_posts, :force => true do |t|
          t.column :id,       :integer, :null => false
          t.column :user_id,  :integer, :null => false
          t.column :title,    :string,  :limit => 255
          t.column :body,     :text
        end
      end
    end
  end

For more tips, see code.whytheluckystiff.net/camping/wiki/GiveUsTheCreateMethod.

Methods

escape   goes   kp   method_missing   qs_parse   run   un  

Classes and Modules

Module Camping::Base
Module Camping::Controllers
Module Camping::Helpers
Module Camping::Models
Module Camping::Session
Module Camping::Views
Class Camping::FastCGI
Class Camping::H
Class Camping::Mab
Class Camping::Reloader

Constants

Apps = []   Stores an Array of all Camping applications modules. Modules are added automatically by +Camping.goes+.
  Camping.goes :Blog
  Camping.goes :Tepee
  Camping::Apps # => [Blog, Tepee]
C = self
S = IO.read(__FILE__).sub(/^ S = I.+$/,'')
P = "Cam\ping Problem!"
H = HashWithIndifferentAccess
X = Controllers

Public Class methods

URL escapes a string.

  Camping.escape("I'd go to the museum straightway!")
    #=> "I%27d+go+to+the+museum+straightway%21"

[Source]

     # File lib/camping-unabridged.rb, line 606
606:     def escape(s); s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.unpack('H2'*$&.size)*'%').upcase}.tr(' ', '+') end

When you are running many applications, you may want to create independent modules for each Camping application. Namespaces for each. Camping::goes defines a toplevel constant with the whole MVC rack inside.

  require 'camping'
  Camping.goes :Blog

  module Blog::Controllers; ... end
  module Blog::Models;      ... end
  module Blog::Views;       ... end

[Source]

     # File lib/camping-unabridged.rb, line 597
597:     def goes(m)
598:       eval S.gsub(/Camping/,m.to_s).gsub("A\pps = []","Cam\ping::Apps<<self"), TOPLEVEL_BINDING
599:     end

Parses a string of cookies from the Cookie header.

[Source]

     # File lib/camping-unabridged.rb, line 638
638:     def kp(s); c = qs_parse(s, ';,'); end

The Camping scriptable dispatcher. Any unhandled method call to the app module will be sent to a controller class, specified as an argument.

  Blog.get(:Index)
  #=> #<Blog::Controllers::Index ... >

The controller object contains all the @cookies, @body, @headers, etc. formulated by the response.

You can also feed environment variables and query variables as a hash, the final argument.

  Blog.post(:Login, :input => {'username' => 'admin', 'password' => 'camping'})
  #=> #<Blog::Controllers::Login @user=... >

  Blog.get(:Info, :env => {:HTTP_HOST => 'wagon'})
  #=> #<Blog::Controllers::Info @env={'HTTP_HOST'=>'wagon'} ...>

[Source]

     # File lib/camping-unabridged.rb, line 686
686:     def method_missing(m, c, *a)
687:       X.M
688:       k = X.const_get(c).new(StringIO.new,
689:              H['HTTP_HOST','','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s)
690:       H.new(a.pop).each { |e,f| k.send("#{e}=",f) } if Hash === a[-1]
691:       k.service *a
692:     end

Parses a query string into an Camping::H object.

  input = Camping.qs_parse("name=Philarp+Tremain&hair=sandy+blonde")
  input.name
    #=> "Philarp Tremaine"

Also parses out the Hash-like syntax used in PHP and Rails and builds nested hashes from it.

  input = Camping.qs_parse("post[id]=1&post[user]=_why")
    #=> {'post' => {'id' => '1', 'user' => '_why'}}

[Source]

     # File lib/camping-unabridged.rb, line 627
627:     def qs_parse(qs, d = '&;')
628:         m = proc {|_,o,n|o.u(n,&m)rescue([*o]<<n)}
629:         (qs||'').
630:             split(/[#{d}] */n).
631:             inject(H[]) { |h,p| k, v=un(p).split('=',2)
632:                 h.u(k.split(/[\]\[]+/).reverse.
633:                     inject(v) { |x,i| H[i,x] },&m)
634:             } 
635:     end

Fields a request through Camping. For traditional CGI applications, the method can be executed without arguments.

  if __FILE__ == $0
    Camping::Models::Base.establish_connection :adapter => 'sqlite3',
        :database => 'blog3.db'
    Camping::Models::Base.logger = Logger.new('camping.log')
    puts Camping.run
  end

The Camping controller returned from run has a to_s method in case you are running from CGI or want to output the full HTTP output. In the above example, puts will call to_s for you.

For FastCGI and Webrick-loaded applications, you will need to use a request loop, with run at the center, passing in the read r and write w streams. You will also need to mimick or pass in the ENV replacement as part of your wrapper.

See Camping::FastCGI and Camping::WEBrick for examples.

[Source]

     # File lib/camping-unabridged.rb, line 660
660:     def run(r=$stdin,e=ENV)
661:       X.M
662:       k,a=X.D un("/#{e['PATH_INFO']}".gsub(/\/+/,'/'))
663:       k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.service *a
664:     rescue Exception=>x
665:       X::ServerError.new(r,e,'get').service(k,m,x)
666:     end

Unescapes a URL-encoded string.

  Camping.un("I%27d+go+to+the+museum+straightway%21")
    #=> "I'd go to the museum straightway!"

[Source]

     # File lib/camping-unabridged.rb, line 613
613:     def un(s); s.tr('+', ' ').gsub(/%([\da-f]{2})/in){[$1].pack('H*')} end

[Validate]