module Camping

If you're new to Camping, you should probably start by reading the first chapters of The Camping Book.

Okay. So, the important thing to remember is that Camping.goes :Nuts copies the Camping module into Nuts. This means that you should never use any of these methods/classes on the Camping module, but rather on your own app. Here's a short explanation on how Camping is organized:

Camping also ships with:

More importantly, Camping also installs The Camping Server, please see Camping::Server.

The Camping Server (for development)

Camping includes a pretty nifty server which is built for development. It follows these rules:

Run it like this:

camping examples/        # Mounts all apps in that directory
camping blog.rb          # Mounts Blog at /

And visit localhost:3301/ in your browser.

Constants

Apps
C
O
P
S
SK
U
X

Controllers receive the requests and sends a response back to the client. A controller is simply a class which must implement the HTTP methods it wants to accept:

module Nuts::Controllers
  class Index
    def get
      "Hello World"
    end
  end

  class Posts
    def post
      Post.create(@input) 
      redirect Index
    end
  end  
end

Defining a controller

There are two ways to define controllers: Just defining a class and let Camping figure out the route, or add the route explicitly using R.

If you don't use R, Camping will first split the controller name up by words (HelloWorld => Hello and World). Then it would do the following:

  • Replace Index with /

  • Replace X with ([^/]+)

  • Replace N with (\d+)

  • Everything else turns into lowercase

  • Join the words with slashes

Here's a few examples:

Index   # => /
PostN   # => /post/(\d+)
PageX   # => /page/([^/]+)
Pages   # => /pages

The request

You have these variables which describes the request:

  • @env contains the environment as defined in rack.rubyforge.org/doc/SPEC.html

  • @request is Rack::Request.new(@env)

  • @root is the path where the app is mounted

  • @cookies is a hash with the cookies sent by the client

  • @state is a hash with the sessions (see Camping::Session)

  • @method is the HTTP method in lowercase

The response

You can change these variables to your needs:

  • @status is the HTTP status (defaults to 200)

  • @headers is a hash with the headers

  • @body is the body (a string or something which responds to each)

  • Any changes in @cookies and @state will also be sent to the client

If you haven't set @body, it will use the return value of the method:

module Nuts::Controllers
  class Index
    def get
      "This is the body"
    end
  end

  class Posts
    def get
      @body = "Hello World!"
      "This is ignored"
    end
  end
end

Public Instance Methods

call(e) click to toggle source

Ruby web servers use this method to enter the Camping realm. The e argument is the environment variables hash as per the Rack specification. And array with [status, headers, body] is expected at the output.

See: rack.rubyforge.org/doc/SPEC.html

# File lib/camping-unabridged.rb, line 651
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
goes(m, g=TOPLEVEL_BINDING) click to toggle source

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

require 'camping'
Camping.goes :Nuts

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

Additionally, you can pass a Binding as the second parameter, which enables you to create a Camping-based application within another module, for example to namespace your web interface and code for a worker process together:

module YourApplication
  Camping.goes :Web, binding()
  module Web
    ...
  end
  module Worker
    ...
  end
end

All the applications will be available in Camping::Apps.

# File lib/camping-unabridged.rb, line 638
def goes(m, g=TOPLEVEL_BINDING)
  Apps << a = eval(S.gsub(/Camping/,m.to_s), g)
  caller[0]=~/:/
  IO.read(a.set:__FILE__,$`)=~/^__END__/ &&
  (b=$'.split(/^@@\s*(.+?)\s*\r?\n/m)).shift rescue nil
  a.set :_t,H[*b||[]]
end
method_missing(m, c, *a) click to toggle source

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 @headers={'HTTP_HOST'=>'wagon'} ...>
# File lib/camping-unabridged.rb, line 677
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
options() click to toggle source

A hash where you can set different settings.

# File lib/camping-unabridged.rb, line 698
def options
  O
end
set(k, v) click to toggle source

Shortcut for setting options:

module Blog
  set :secret, "Hello!"
end
# File lib/camping-unabridged.rb, line 707
def set(k, v)
  O[k] = v
end
use(*a, &b) click to toggle source

Injects a middleware:

module Blog
  use Rack::MethodOverride
  use Rack::Session::Memcache, :key => "session"
end
# File lib/camping-unabridged.rb, line 692
def use(*a, &b)
  m = a.shift.new(method(:call), *a, &b)
  meta_def(:call) { |e| m.call(e) }
end