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::Controllers is where your controllers live.
-
Camping::Models is where your models live.
-
Camping::Views is where your views live.
-
Camping::Base is a module which is included in all your controllers.
-
Camping::Helpers is a module with useful helpers, both for the controllers and the views. You should fill this up with your own helpers.
Camping also ships with:
-
Camping::Session adds states to your app.
-
Camping::Server starts up your app in development.
-
Camping::Reloader automatically reloads your apps when a file has changed.
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:
-
Load all Camping apps in a directory or a file.
-
Load new apps that appear in that directory or that file.
-
Mount those apps according to their name. (e.g. Blog 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.
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
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
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
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
A hash where you can set different settings.
# File lib/camping-unabridged.rb, line 698 def options O end
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
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