Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 763 lines (733 sloc) 26.961 kb
d5f0d99 * lib/camping.rb: debugged qs_parse further, added multiple value suppo...
_why authored
1 # == About camping.rb
2 #
3 # Camping comes with two versions of its source code. The code contained in
4 # lib/camping.rb is compressed, stripped of whitespace, using compact algorithms
5 # to keep it tight. The unspoken rule is that camping.rb should be flowed with
6 # no more than 80 characters per line and must not exceed four kilobytes.
7 #
8 # On the other hand, lib/camping-unabridged.rb contains the same code, laid out
9 # nicely with piles of documentation everywhere. This documentation is entirely
10 # generated from lib/camping-unabridged.rb using RDoc and our "flipbook" template
11 # found in the extras directory of any camping distribution.
cca5586 lib/camping-unabridged.rb: further documenting of the dependencies in Ca...
_why authored
12 #
13 # == Requirements
14 #
15 # Camping requires at least Ruby 1.8.2.
16 #
17 # Camping depends on the following libraries. If you install through RubyGems,
18 # these will be automatically installed for you.
19 #
20 # * ActiveRecord, used in your models.
21 # ActiveRecord is an object-to-relational database mapper with adapters
22 # for SQLite3, MySQL, PostgreSQL, SQL Server and more.
23 # * Markaby, used in your views to describe HTML in plain Ruby.
24 # * MetAid, a few metaprogramming methods which Camping uses.
25 # * Tempfile, for storing file uploads.
26 #
27 # Camping also works well with Mongrel, the swift Ruby web server.
28 # http://rubyforge.org/projects/mongrel Mongrel comes with examples
29 # in its <tt>examples/camping</tt> directory.
30 #
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
31 %w[active_support/core_ext/hash markaby metaid tempfile uri].each { |lib| require lib }
abc7043 Initial import.
_why authored
32
c3e919e lib/camping.rb: docs!
_why authored
33 # == Camping
31e25ad README: top-level docs.
_why authored
34 #
35 # The camping module contains three modules for separating your application:
36 #
cca5586 lib/camping-unabridged.rb: further documenting of the dependencies in Ca...
_why authored
37 # * Camping::Models for your database interaction classes, all derived from ActiveRecord::Base.
31e25ad README: top-level docs.
_why authored
38 # * Camping::Controllers for storing controller classes, which map URLs to code.
39 # * Camping::Views for storing methods which generate HTML.
40 #
41 # Of use to you is also one module for storing helpful additional methods:
42 #
43 # * Camping::Helpers which can be used in controllers and views.
44 #
45 # == The postamble
46 #
47 # Most Camping applications contain the entire application in a single script.
48 # The script begins by requiring Camping, then fills each of the three modules
49 # described above with classes and methods. Finally, a postamble puts the wheels
50 # in motion.
51 #
52 # if __FILE__ == $0
26f5cea * camping.gemspec: trying to get the new template to output.
_why authored
53 # Camping::Models::Base.establish_connection :adapter => 'sqlite3',
54 # :database => 'blog3.db'
31e25ad README: top-level docs.
_why authored
55 # Camping::Models::Base.logger = Logger.new('camping.log')
cca5586 lib/camping-unabridged.rb: further documenting of the dependencies in Ca...
_why authored
56 # Camping.create if Camping.respond_to? :create
15bbbe6 * camping.gemspec: distribute CHANGELOG.
_why authored
57 # puts Camping.run
31e25ad README: top-level docs.
_why authored
58 # end
59 #
60 # In the postamble, your job is to setup Camping::Models::Base (see: ActiveRecord::Base)
61 # and call Camping::run in a request loop. The above postamble is for a standard
62 # CGI setup, where the web server manages the request loop and calls the script once
63 # for every request.
64 #
65 # For other configurations, see
66 # http://code.whytheluckystiff.net/camping/wiki/PostAmbles
cca5586 lib/camping-unabridged.rb: further documenting of the dependencies in Ca...
_why authored
67 #
68 # == The <tt>create</tt> method
69 #
70 # Many postambles will check for your application's <tt>create</tt> method and will run it
71 # when the web server starts up. This is a good place to check for database tables and create
72 # those tables to save users of your application from needing to manually set them up.
73 #
74 # def Blog.create
75 # unless Blog::Models::Post.table_exists?
76 # ActiveRecord::Schema.define do
77 # create_table :blog_posts, :force => true do |t|
78 # t.column :id, :integer, :null => false
79 # t.column :user_id, :integer, :null => false
80 # t.column :title, :string, :limit => 255
81 # t.column :body, :text
82 # end
83 # end
84 # end
85 # end
86 #
87 # For more tips, see http://code.whytheluckystiff.net/camping/wiki/GiveUsTheCreateMethod.
abc7043 Initial import.
_why authored
88 module Camping
b59e043 * lib/camping.rb: new Camping::Apps stores all app modules.
_why authored
89 # Stores an +Array+ of all Camping applications modules. Modules are added
90 # automatically by +Camping.goes+.
91 #
92 # Camping.goes :Blog
93 # Camping.goes :Tepee
94 # Camping::Apps # => [Blog, Tepee]
95 #
96 Apps = []
616d685 lib/camping.rb: redirect now picks the route most likely.
_why authored
97 C = self
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
98 S = IO.read(__FILE__).sub(/^ S = I.+$/,'')
c1f6e46 * lib/camping.rb: a few of zimbatm's wondrous patches (#32, got rid of ...
_why authored
99 P="Cam\ping Problem!"
abc7043 Initial import.
_why authored
100
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
101 H = HashWithIndifferentAccess
427f085 * lib/camping-unabridged.rb: switched from OpenStruct to HashWithIndiff...
_why authored
102 # An object-like Hash, based on ActiveSupport's HashWithIndifferentAccess.
103 # All Camping query string and cookie variables are loaded as this.
cca5586 lib/camping-unabridged.rb: further documenting of the dependencies in Ca...
_why authored
104 #
105 # To access the query string, for instance, use the <tt>@input</tt> variable.
106 #
107 # module Blog::Models
108 # class Index < R '/'
109 # def get
110 # if page = @input.page.to_i > 0
111 # page -= 1
112 # end
113 # @posts = Post.find :all, :offset => page * 20, :limit => 20
114 # render :index
115 # end
116 # end
117 # end
118 #
119 # In the above example if you visit <tt>/?page=2</tt>, you'll get the second
120 # page of twenty posts. You can also use <tt>@input[:page]</tt> or <tt>@input['page']</tt>
121 # to get the value for the <tt>page</tt> query variable.
122 #
123 # Use the <tt>@cookies</tt> variable in the same fashion to access cookie variables.
08f3318 * lib/camping.rb: allow markaby fragments to come out of controllers. (...
_why authored
124 # Also, the <tt>@env</tt> variable is an H containing the HTTP headers and server info.
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
125 class H
08f3318 * lib/camping.rb: allow markaby fragments to come out of controllers. (...
_why authored
126 # Gets or sets keys in the hash.
127 #
128 # @cookies.my_favorite = :macadamian
129 # @cookies.my_favorite
130 # => :macadamian
131 #
a5c5561 * lib/camping.rb: trimmed about 100 bytes here and there. also, patched...
_why authored
132 def method_missing(m,*a)
a1fa3d7 * lib/camping.rb: new support for ordered controllers. uses the `inher...
_why authored
133 m.to_s=~/=$/?self[$`]=a[0]:a==[]?self[m]:raise(NoMethodError,"#{m}")
66f83dd lib/camping.rb: trying to get the HashWithIndifferentAccess to work more...
_why authored
134 end
d91e00f * lib/camping.rb: sometime in the recentlies, Rails' ActiveSupport adde...
_why authored
135 alias_method :u, :regular_update
427f085 * lib/camping-unabridged.rb: switched from OpenStruct to HashWithIndiff...
_why authored
136 end
137
cca5586 lib/camping-unabridged.rb: further documenting of the dependencies in Ca...
_why authored
138 # Helpers contains methods available in your controllers and views. You may add
139 # methods of your own to this module, including many helper methods from Rails.
140 # This is analogous to Rails' <tt>ApplicationHelper</tt> module.
141 #
142 # == Using ActionPack Helpers
143 #
144 # If you'd like to include helpers from Rails' modules, you'll need to look up the
145 # helper module in the Rails documentation at http://api.rubyonrails.org/.
146 #
147 # For example, if you look up the <tt>ActionView::Helpers::FormHelper</tt> class,
148 # you'll find that it's loaded from the <tt>action_view/helpers/form_helper.rb</tt>
149 # file. You'll need to have the ActionPack gem installed for this to work.
150 #
151 # require 'action_view/helpers/form_helper.rb'
152 #
153 # # This example is unfinished.. soon..
154 #
616d685 lib/camping.rb: redirect now picks the route most likely.
_why authored
155 module Helpers
c3e919e lib/camping.rb: docs!
_why authored
156 # From inside your controllers and views, you will often need to figure out
157 # the route used to get to a certain controller +c+. Pass the controller class
158 # and any arguments into the R method, a string containing the route will be
159 # returned to you.
160 #
161 # Assuming you have a specific route in an edit controller:
162 #
163 # class Edit < R '/edit/(\d+)'
164 #
165 # A specific route to the Edit controller can be built with:
166 #
167 # R(Edit, 1)
168 #
169 # Which outputs: <tt>/edit/1</tt>.
170 #
171 # You may also pass in a model object and the ID of the object will be used.
172 #
173 # If a controller has many routes, the route will be selected if it is the
174 # first in the routing list to have the right number of arguments.
175 #
9a2308d * lib/camping.rb: added Helpers.URL, which builds a complete URL to a r...
_why authored
176 # == Using R in the View
177 #
178 # Keep in mind that this route doesn't include the root path.
179 # You will need to use <tt>/</tt> (the slash method above) in your controllers.
180 # Or, go ahead and use the Helpers#URL method to build a complete URL for a route.
181 #
182 # However, in your views, the :href, :src and :action attributes automatically
183 # pass through the slash method, so you are encouraged to use <tt>R</tt> or
184 # <tt>URL</tt> in your views.
185 #
186 # module Blog::Views
187 # def menu
188 # div.menu! do
189 # a 'Home', :href => URL()
190 # a 'Profile', :href => "/profile"
191 # a 'Logout', :href => R(Logout)
192 # a 'Google', :href => 'http://google.com'
193 # end
194 # end
195 # end
196 #
197 # Let's say the above example takes place inside an application mounted at
198 # <tt>http://localhost:3301/frodo</tt> and that a controller named <tt>Logout</tt>
199 # is assigned to route <tt>/logout</tt>. The HTML will come out as:
200 #
201 # <div id="menu">
98e4333 * lib: hiding useless things in the docs.
_why authored
202 # <a href="//localhost:3301/frodo/">Home</a>
9a2308d * lib/camping.rb: added Helpers.URL, which builds a complete URL to a r...
_why authored
203 # <a href="/frodo/profile">Profile</a>
204 # <a href="/frodo/logout">Logout</a>
205 # <a href="http://google.com">Google</a>
206 # </div>
207 #
a1fa3d7 * lib/camping.rb: new support for ordered controllers. uses the `inher...
_why authored
208 def R(c,*g)
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
209 p=/\(.+?\)/
a1fa3d7 * lib/camping.rb: new support for ordered controllers. uses the `inher...
_why authored
210 g.inject(c.urls.find{|x|x.scan(p).size==g.size}.dup){|s,a|
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
211 s.sub p,C.escape((a[a.class.primary_key]rescue a))
616d685 lib/camping.rb: redirect now picks the route most likely.
_why authored
212 }
213 end
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
214
8e87483 @yyyc514 Adding "errors_for" validation helper (1 line added). No known bugs (kno...
yyyc514 authored
215 # Shows AR validation errors for the object passed.
216 # There is no output if there are no errors.
217 #
218 # An example might look like:
219 #
220 # errors_for @post
221 #
222 # Might (depending on actual data) render something like this in Markaby:
223 #
224 # ul.errors do
225 # li "Body can't be empty"
226 # li "Title must be unique"
227 # end
228 #
229 # Add a simple ul.errors {color:red; font-weight:bold;} CSS rule and you
230 # have built-in, usable error checking in only one line of code. :-)
231 #
232 # See AR validation documentation for details on validations.
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
233 def errors_for(o); ul.errors { o.errors.each_full { |er| li er } } if o.errors.any?; end
2989e76 * lib/camping-unabridged.rb: corrected the docs for URL(), which gives ...
_why authored
234 # Simply builds a complete path from a path +p+ within the app. If your application is
235 # mounted at <tt>/blog</tt>:
c3e919e lib/camping.rb: docs!
_why authored
236 #
61e9b19 lib/camping.rb: added Camping.goes, bug in routing.
_why authored
237 # self / "/view/1" #=> "/blog/view/1"
238 # self / "styles.css" #=> "styles.css"
663796c camping.gemspec: generate rdoc.
_why authored
239 # self / R(Edit, 1) #=> "/blog/edit/1"
c3e919e lib/camping.rb: docs!
_why authored
240 #
7ca56b0 lib/camping.rb: have Helpers./ throw an error on nil. shorten Mab.tag! ...
_why authored
241 def /(p); p[/^\//]?@root+p:p end
43fbe7c * lib/camping.rb: Helpers#URL returns a URI object. This way relative ...
_why authored
242 # Builds a URL route to a controller or a path, returning a URI object.
243 # This way you'll get the hostname and the port number, a complete URL.
2989e76 * lib/camping-unabridged.rb: corrected the docs for URL(), which gives ...
_why authored
244 # No scheme is given (http or https).
9a2308d * lib/camping.rb: added Helpers.URL, which builds a complete URL to a r...
_why authored
245 #
246 # You can use this to grab URLs for controllers using the R-style syntax.
247 # So, if your application is mounted at <tt>http://test.ing/blog/</tt>
248 # and you have a View controller which routes as <tt>R '/view/(\d+)'</tt>:
249 #
2989e76 * lib/camping-unabridged.rb: corrected the docs for URL(), which gives ...
_why authored
250 # URL(View, @post.id) #=> #<URL://test.ing/blog/view/12>
9a2308d * lib/camping.rb: added Helpers.URL, which builds a complete URL to a r...
_why authored
251 #
252 # Or you can use the direct path:
253 #
2989e76 * lib/camping-unabridged.rb: corrected the docs for URL(), which gives ...
_why authored
254 # self.URL #=> #<URL://test.ing/blog/>
255 # self.URL + "view/12" #=> #<URL://test.ing/blog/view/12>
256 # URL("/view/12") #=> #<URL://test.ing/blog/view/12>
257 #
258 # Since no scheme is given, you will need to add the scheme yourself:
259 #
260 # "http" + URL("/view/12") #=> "http://test.ing/blog/view/12"
9a2308d * lib/camping.rb: added Helpers.URL, which builds a complete URL to a r...
_why authored
261 #
43fbe7c * lib/camping.rb: Helpers#URL returns a URI object. This way relative ...
_why authored
262 # It's okay to pass URL strings through this method as well:
263 #
c10b039 * lib/camping-unabridged.rb: clarifying Helpers#URL docs -- a URI objec...
_why authored
264 # URL("http://google.com") #=> #<URI:http://google.com>
43fbe7c * lib/camping.rb: Helpers#URL returns a URI object. This way relative ...
_why authored
265 #
266 # Any string which doesn't begin with a slash will pass through
267 # unscathed.
9a2308d * lib/camping.rb: added Helpers.URL, which builds a complete URL to a r...
_why authored
268 def URL c='/',*a
269 c = R(c, *a) if c.respond_to? :urls
270 c = self/c
3dd9a4a * lib/camping.rb: https bug, URL doesn't give a scheme now.
_why authored
271 c = "//"+@env.HTTP_HOST+c if c[/^\//]
43fbe7c * lib/camping.rb: Helpers#URL returns a URI object. This way relative ...
_why authored
272 URI(c)
9a2308d * lib/camping.rb: added Helpers.URL, which builds a complete URL to a r...
_why authored
273 end
616d685 lib/camping.rb: redirect now picks the route most likely.
_why authored
274 end
c3e919e lib/camping.rb: docs!
_why authored
275
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
276 # Camping::Base is built into each controller by way of the generic routing
277 # class Camping::R. In some ways, this class is trying to do too much, but
278 # it saves code for all the glue to stay in one place.
279 #
280 # Forgivable, considering that it's only really a handful of methods and accessors.
281 #
282 # == Treating controller methods like Response objects
283 #
284 # Camping originally came with a barebones Response object, but it's often much more readable
285 # to just use your controller as the response.
286 #
287 # Go ahead and alter the status, cookies, headers and body instance variables as you
288 # see fit in order to customize the response.
c3e919e lib/camping.rb: docs!
_why authored
289 #
290 # module Camping::Controllers
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
291 # class SoftLink
292 # def get
293 # redirect "/"
294 # end
c3e919e lib/camping.rb: docs!
_why authored
295 # end
296 # end
297 #
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
298 # Is equivalent to:
c3e919e lib/camping.rb: docs!
_why authored
299 #
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
300 # module Camping::Controllers
301 # class SoftLink
302 # def get
303 # @status = 302
304 # @headers['Location'] = "/"
305 # end
306 # end
307 # end
c3e919e lib/camping.rb: docs!
_why authored
308 #
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
309 module Base
310 include Helpers
311 attr_accessor :input, :cookies, :env, :headers, :body, :status, :root
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
312 Z = "\r\n"
313
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
314 # Display a view, calling it by its method name +m+. If a <tt>layout</tt>
315 # method is found in Camping::Views, it will be used to wrap the HTML.
c3e919e lib/camping.rb: docs!
_why authored
316 #
317 # module Camping::Controllers
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
318 # class Show
c3e919e lib/camping.rb: docs!
_why authored
319 # def get
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
320 # @posts = Post.find :all
321 # render :index
c3e919e lib/camping.rb: docs!
_why authored
322 # end
323 # end
324 # end
325 #
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
326 def render(m); end; undef_method :render
327
328 # Any stray method calls will be passed to Markaby. This means you can reply
329 # with HTML directly from your controller for quick debugging.
c3e919e lib/camping.rb: docs!
_why authored
330 #
331 # module Camping::Controllers
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
332 # class Info
333 # def get; code @env.inspect end
c3e919e lib/camping.rb: docs!
_why authored
334 # end
335 # end
336 #
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
337 # If you have a <tt>layout</tt> method in Camping::Views, it will be used to
338 # wrap the HTML.
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
339 def method_missing(*a,&b)
340 a.shift if a[0]==:render
341 m=markaby
342 s=m.capture{send(*a,&b)}
343 s=m.layout{s} if m.respond_to?:layout
5a49057 * lib/camping.rb: let's not cast Markaby to a string by default, that's...
_why authored
344 s
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
345 end
c3e919e lib/camping.rb: docs!
_why authored
346
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
347 # Formulate a redirect response: a 302 status with <tt>Location</tt> header
348 # and a blank body. Uses Helpers#URL to build the location from a controller
349 # route or path.
350 #
351 # So, given a root of <tt>http://localhost:3301/articles</tt>:
352 #
98e4333 * lib: hiding useless things in the docs.
_why authored
353 # redirect "view/12" # redirects to "//localhost:3301/articles/view/12"
354 # redirect View, 12 # redirects to "//localhost:3301/articles/view/12"
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
355 #
08f3318 * lib/camping.rb: allow markaby fragments to come out of controllers. (...
_why authored
356 # <b>NOTE:</b> This method doesn't magically exit your methods and redirect.
357 # You'll need to <tt>return redirect(...)</tt> if this isn't the last statement
358 # in your code.
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
359 def redirect(*a)
360 r(302,'','Location'=>URL(*a))
361 end
c3e919e lib/camping.rb: docs!
_why authored
362
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
363 # A quick means of setting this controller's status, body and headers.
364 # Used internally by Camping, but... by all means...
365 #
366 # r(302, '', 'Location' => self / "/view/12")
367 #
368 # Is equivalent to:
369 #
370 # redirect "/view/12"
371 #
372 def r(s, b, h = {}); @status = s; @headers.merge!(h); @body = b; end
c3e919e lib/camping.rb: docs!
_why authored
373
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
374 def initialize(r, e, m) #:nodoc:
eb0a452 * lib/camping.rb: when running under plain CGI, the ENV hash wasn't get...
_why authored
375 e = H[e.to_hash]
e6f5933 * lib/camping.rb: trailing slashes removed from SCRIPT_NAME, as describe...
_why authored
376 @status, @method, @env, @headers, @root = 200, m.downcase, e,
377 {'Content-Type'=>'text/html'}, e.SCRIPT_NAME.sub(/\/$/,'')
7494506 * lib/camping.rb: compressing to get rid of some dangling lines.
_why authored
378 @k = C.kp(e.HTTP_COOKIE)
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
379 qs = C.qs_parse(e.QUERY_STRING)
29db074 * lib/camping.rb: leave the input stream open and unread unless its a P...
_why authored
380 @in = r
7494506 * lib/camping.rb: compressing to get rid of some dangling lines.
_why authored
381 if %r|\Amultipart/form-data.*boundary=\"?([^\";,]+)|n.match(e.CONTENT_TYPE)
4bf0b27 * lib/camping.rb: efficient multipart forms, at last.
_why authored
382 b = /(?:\r?\n|\A)#{Regexp::quote("--#$1")}(?:--)?\r$/
383 until @in.eof?
384 fh=H[]
385 for l in @in
386 case l
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
387 when Z: break
4bf0b27 * lib/camping.rb: efficient multipart forms, at last.
_why authored
388 when /^Content-Disposition: form-data;/
389 fh.u H[*$'.scan(/(?:\s(\w+)="([^"]+)")/).flatten]
390 when /^Content-Type: (.+?)(\r$|\Z)/m
391 puts "=> fh[type] = #$1"
392 fh[:type] = $1
393 end
394 end
395 fn=fh[:name]
396 o=if fh[:filename]
659180d * lib/camping.rb: subtle Tempfile bug, was causing the finalizer to tri...
_why authored
397 o=fh[:tempfile]=Tempfile.new(:C)
398 o.binmode
7494506 * lib/camping.rb: compressing to get rid of some dangling lines.
_why authored
399 else
4bf0b27 * lib/camping.rb: efficient multipart forms, at last.
_why authored
400 fh=""
401 end
402 while l=@in.read(16384)
403 if l=~b
404 o<<$`.chomp
405 @in.seek(-$'.size,IO::SEEK_CUR)
406 break
407 end
408 o<<l
7494506 * lib/camping.rb: compressing to get rid of some dangling lines.
_why authored
409 end
410 qs[fn]=fh if fn
4bf0b27 * lib/camping.rb: efficient multipart forms, at last.
_why authored
411 fh[:tempfile].rewind if fh.is_a?H
412 end
7494506 * lib/camping.rb: compressing to get rid of some dangling lines.
_why authored
413 elsif @method == "post"
4bf0b27 * lib/camping.rb: efficient multipart forms, at last.
_why authored
414 qs.merge!(C.qs_parse(@in.read))
177e5cb * lib/camping.rb: split part of Base.service into Base.initialize. The...
_why authored
415 end
7494506 * lib/camping.rb: compressing to get rid of some dangling lines.
_why authored
416 @cookies, @input = @k.dup, qs.dup
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
417 end
abc7043 Initial import.
_why authored
418
08f3318 * lib/camping.rb: allow markaby fragments to come out of controllers. (...
_why authored
419 # All requests pass through this method before going to the controller. Some magic
420 # in Camping can be performed by overriding this method.
421 #
422 # See http://code.whytheluckystiff.net/camping/wiki/BeforeAndAfterOverrides for more
423 # on before and after overrides with Camping.
424 def service(*a)
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
425 @body = send(@method, *a) if respond_to? @method
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
426 @headers['Set-Cookie'] = @cookies.map { |k,v| "#{k}=#{C.escape(v)}; path=#{self/"/"}" if v != @k[k] } - [nil]
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
427 self
428 end
08f3318 * lib/camping.rb: allow markaby fragments to come out of controllers. (...
_why authored
429
430 # Used by the web server to convert the current request to a string. If you need to
431 # alter the way Camping builds HTTP headers, consider overriding this method.
432 def to_s
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
433 "Status: #{@status}#{Z+@headers.map{|k,v|[*v].map{|x|"#{k}: #{x}"}}*Z+Z*2+@body}"
abc7043 Initial import.
_why authored
434 end
08f3318 * lib/camping.rb: allow markaby fragments to come out of controllers. (...
_why authored
435
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
436 def markaby #:nodoc:
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
437 Mab.new({},self)
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
438 end
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
439 end
c3e919e lib/camping.rb: docs!
_why authored
440
a948a00 * lib/camping.rb: moved Controllers::Base to Base and Controllers::R to...
_why authored
441 # Controllers is a module for placing classes which handle URLs. This is done
442 # by defining a route to each class using the Controllers::R method.
443 #
444 # module Camping::Controllers
445 # class Edit < R '/edit/(\d+)'
446 # def get; end
447 # def post; end
448 # end
449 # end
450 #
451 # If no route is set, Camping will guess the route from the class name.
452 # The rule is very simple: the route becomes a slash followed by the lowercased
453 # class name. See Controllers::D for the complete rules of dispatch.
454 #
455 # == Special classes
456 #
457 # There are two special classes used for handling 404 and 500 errors. The
458 # NotFound class handles URLs not found. The ServerError class handles exceptions
459 # uncaught by your application.
460 module Controllers
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
461 @r = []
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
462 class << self
98e4333 * lib: hiding useless things in the docs.
_why authored
463 def r #:nodoc:
464 @r
465 end
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
466 # Add routes to a controller class by piling them into the R method.
467 #
468 # module Camping::Controllers
469 # class Edit < R '/edit/(\d+)', '/new'
470 # def get(id)
471 # if id # edit
472 # else # new
473 # end
474 # end
475 # end
476 # end
477 #
478 # You will need to use routes in either of these cases:
479 #
480 # * You want to assign multiple routes to a controller.
481 # * You want your controller to receive arguments.
482 #
483 # Most of the time the rules inferred by dispatch method Controllers::D will get you
484 # by just fine.
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
485 def R *u
486 r=@r
487 Class.new {
488 meta_def(:urls){u}
489 meta_def(:inherited){|x|r<<x}
490 }
491 end
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
492
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
493 # Dispatch routes to controller classes.
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
494 # For each class, routes are checked for a match based on their order in the routing list
495 # given to Controllers::R. If no routes were given, the dispatcher uses a slash followed
496 # by the name of the controller lowercased.
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
497 #
498 # Controllers are searched in this order:
499 #
500 # # Classes without routes, since they refer to a very specific URL.
501 # # Classes with routes are searched in order of their creation.
502 #
503 # So, define your catch-all controllers last.
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
504 def D(path)
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
505 r.map { |k|
506 k.urls.map { |x|
507 return k, $~[1..-1] if path =~ /^#{x}\/?$/
508 }
509 }
a1fa3d7 * lib/camping.rb: new support for ordered controllers. uses the `inher...
_why authored
510 [NotFound, [path]]
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
511 end
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
512
513 # The route maker, this is called by Camping internally, you shouldn't need to call it.
514 #
515 # Still, it's worth know what this method does. Since Ruby doesn't keep track of class
516 # creation order, we're keeping an internal list of the controllers which inherit from R().
517 # This method goes through and adds all the remaining routes to the beginning of the list
518 # and ensures all the controllers have the right mixins.
519 #
520 # Anyway, if you are calling the URI dispatcher from outside of a Camping server, you'll
521 # definitely need to call this at least once to set things up.
522 def M
98e4333 * lib: hiding useless things in the docs.
_why authored
523 def M #:nodoc:
524 end
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
525 constants.map { |c|
526 k=const_get(c)
527 k.send:include,C,Base,Models
528 r[0,0]=k if !r.include?k
529 k.meta_def(:urls){["/#{c.downcase}"]}if !k.respond_to?:urls
530 }
531 end
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
532 end
533
c3e919e lib/camping.rb: docs!
_why authored
534 # The NotFound class is a special controller class for handling 404 errors, in case you'd
535 # like to alter the appearance of the 404. The path is passed in as +p+.
536 #
537 # module Camping::Controllers
538 # class NotFound
539 # def get(p)
540 # @status = 404
541 # div do
542 # h1 'Camping Problem!'
543 # h2 "#{p} not found"
544 # end
545 # end
546 # end
547 # end
548 #
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
549 class NotFound < R()
550 def get(p)
551 r(404, Mab.new{h1(P);h2("#{p} not found")})
552 end
553 end
c3e919e lib/camping.rb: docs!
_why authored
554
555 # The ServerError class is a special controller class for handling many (but not all) 500 errors.
556 # If there is a parse error in Camping or in your application's source code, it will not be caught
557 # by Camping. The controller class +k+ and request method +m+ (GET, POST, etc.) where the error
558 # took place are passed in, along with the Exception +e+ which can be mined for useful info.
559 #
560 # module Camping::Controllers
561 # class ServerError
562 # def get(k,m,e)
563 # @status = 500
564 # div do
565 # h1 'Camping Problem!'
566 # h2 "in #{k}.#{m}"
567 # h3 "#{e.class} #{e.message}:"
568 # ul do
569 # e.backtrace.each do |bt|
570 # li bt
571 # end
572 # end
573 # end
574 # end
575 # end
576 # end
577 #
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
578 class ServerError < R()
579 def get(k,m,e)
580 r(500, Mab.new {
581 h1(P)
582 h2 "#{k}.#{m}"
583 h3 "#{e.class} #{e.message}:"
584 ul { e.backtrace.each { |bt| li bt } }
585 }.to_s)
abc7043 Initial import.
_why authored
586 end
587 end
588 end
6cfbdc5 * lib/camping-unabridged.rb: Controllers was not assigned to Camping::X...
_why authored
589 X = Controllers
abc7043 Initial import.
_why authored
590
591 class << self
61e9b19 lib/camping.rb: added Camping.goes, bug in routing.
_why authored
592 # When you are running many applications, you may want to create independent
593 # modules for each Camping application. Namespaces for each. Camping::goes
594 # defines a toplevel constant with the whole MVC rack inside.
595 #
596 # require 'camping'
597 # Camping.goes :Blog
598 #
599 # module Blog::Controllers; ... end
600 # module Blog::Models; ... end
601 # module Blog::Views; ... end
602 #
603 def goes(m)
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
604 eval S.gsub(/Camping/,m.to_s).gsub("A\pps = []","Cam\ping::Apps<<self"), TOPLEVEL_BINDING
61e9b19 lib/camping.rb: added Camping.goes, bug in routing.
_why authored
605 end
606
c3e919e lib/camping.rb: docs!
_why authored
607 # URL escapes a string.
608 #
609 # Camping.escape("I'd go to the museum straightway!")
610 # #=> "I%27d+go+to+the+museum+straightway%21"
611 #
c1f6e46 * lib/camping.rb: a few of zimbatm's wondrous patches (#32, got rid of ...
_why authored
612 def escape(s); s.to_s.gsub(/[^ \w.-]+/n){'%'+($&.unpack('H2'*$&.size)*'%').upcase}.tr(' ', '+') end
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
613
c3e919e lib/camping.rb: docs!
_why authored
614 # Unescapes a URL-encoded string.
615 #
f8744c2 * lib/camping.rb: store request body always in @in; unescape paths befo...
_why authored
616 # Camping.un("I%27d+go+to+the+museum+straightway%21")
c3e919e lib/camping.rb: docs!
_why authored
617 # #=> "I'd go to the museum straightway!"
618 #
8771109 * lib/camping.rb: protect ServerError and NotFound (from zimbatm's #67....
_why authored
619 def un(s); s.tr('+', ' ').gsub(/%([\da-f]{2})/in){[$1].pack('H*')} end
c3e919e lib/camping.rb: docs!
_why authored
620
20b809b * lib/camping.rb: bugfix to qs_parse, the query string was overwriting ...
_why authored
621 # Parses a query string into an Camping::H object.
c3e919e lib/camping.rb: docs!
_why authored
622 #
623 # input = Camping.qs_parse("name=Philarp+Tremain&hair=sandy+blonde")
624 # input.name
625 # #=> "Philarp Tremaine"
626 #
20b809b * lib/camping.rb: bugfix to qs_parse, the query string was overwriting ...
_why authored
627 # Also parses out the Hash-like syntax used in PHP and Rails and builds
628 # nested hashes from it.
629 #
630 # input = Camping.qs_parse("post[id]=1&post[user]=_why")
631 # #=> {'post' => {'id' => '1', 'user' => '_why'}}
632 #
633 def qs_parse(qs, d = '&;')
d91e00f * lib/camping.rb: sometime in the recentlies, Rails' ActiveSupport adde...
_why authored
634 m = proc {|_,o,n|o.u(n,&m)rescue([*o]<<n)}
20b809b * lib/camping.rb: bugfix to qs_parse, the query string was overwriting ...
_why authored
635 (qs||'').
636 split(/[#{d}] */n).
f8744c2 * lib/camping.rb: store request body always in @in; unescape paths befo...
_why authored
637 inject(H[]) { |h,p| k, v=un(p).split('=',2)
d91e00f * lib/camping.rb: sometime in the recentlies, Rails' ActiveSupport adde...
_why authored
638 h.u(k.split(/[\]\[]+/).reverse.
d5f0d99 * lib/camping.rb: debugged qs_parse further, added multiple value suppo...
_why authored
639 inject(v) { |x,i| H[i,x] },&m)
20b809b * lib/camping.rb: bugfix to qs_parse, the query string was overwriting ...
_why authored
640 }
641 end
c3e919e lib/camping.rb: docs!
_why authored
642
643 # Parses a string of cookies from the <tt>Cookie</tt> header.
66f83dd lib/camping.rb: trying to get the HashWithIndifferentAccess to work more...
_why authored
644 def kp(s); c = qs_parse(s, ';,'); end
c3e919e lib/camping.rb: docs!
_why authored
645
646 # Fields a request through Camping. For traditional CGI applications, the method can be
647 # executed without arguments.
648 #
649 # if __FILE__ == $0
26f5cea * camping.gemspec: trying to get the new template to output.
_why authored
650 # Camping::Models::Base.establish_connection :adapter => 'sqlite3',
651 # :database => 'blog3.db'
c3e919e lib/camping.rb: docs!
_why authored
652 # Camping::Models::Base.logger = Logger.new('camping.log')
15bbbe6 * camping.gemspec: distribute CHANGELOG.
_why authored
653 # puts Camping.run
c3e919e lib/camping.rb: docs!
_why authored
654 # end
655 #
15bbbe6 * camping.gemspec: distribute CHANGELOG.
_why authored
656 # The Camping controller returned from <tt>run</tt> has a <tt>to_s</tt> method in case you
657 # are running from CGI or want to output the full HTTP output. In the above example, <tt>puts</tt>
658 # will call <tt>to_s</tt> for you.
659 #
c3e919e lib/camping.rb: docs!
_why authored
660 # For FastCGI and Webrick-loaded applications, you will need to use a request loop, with <tt>run</tt>
661 # at the center, passing in the read +r+ and write +w+ streams. You will also need to mimick or
15bbbe6 * camping.gemspec: distribute CHANGELOG.
_why authored
662 # pass in the <tt>ENV</tt> replacement as part of your wrapper.
c3e919e lib/camping.rb: docs!
_why authored
663 #
664 # if __FILE__ == $0
665 # require 'fcgi'
26f5cea * camping.gemspec: trying to get the new template to output.
_why authored
666 # Camping::Models::Base.establish_connection :adapter => 'sqlite3',
667 # :database => 'blog3.db'
c3e919e lib/camping.rb: docs!
_why authored
668 # Camping::Models::Base.logger = Logger.new('camping.log')
669 # FCGI.each do |req|
15bbbe6 * camping.gemspec: distribute CHANGELOG.
_why authored
670 # req.out << Camping.run req.in, req.env
c3e919e lib/camping.rb: docs!
_why authored
671 # req.finish
672 # end
673 # end
674 # end
675 #
177e5cb * lib/camping.rb: split part of Base.service into Base.initialize. The...
_why authored
676 def run(r=$stdin,e=ENV)
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
677 X.M
678 k,a=X.D un("/#{e['PATH_INFO']}".gsub(/\/+/,'/'))
5a49057 * lib/camping.rb: let's not cast Markaby to a string by default, that's...
_why authored
679 k.new(r,e,(m=e['REQUEST_METHOD']||"GET")).Y.service *a
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
680 rescue Exception=>x
681 X::ServerError.new(r,e,'get').service(k,m,x)
abc7043 Initial import.
_why authored
682 end
1109984 * lib/camping.rb: experimenting with Camping.method_missing as an answe...
_why authored
683
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
684 # The Camping scriptable dispatcher. Any unhandled method call to the app module will
685 # be sent to a controller class, specified as an argument.
686 #
687 # Blog.get(:Index)
688 # #=> #<Blog::Controllers::Index ... >
689 #
690 # The controller object contains all the @cookies, @body, @headers, etc. formulated by
691 # the response.
692 #
693 # You can also feed environment variables and query variables as a hash, the final
694 # argument.
695 #
696 # Blog.post(:Login, :input => {'username' => 'admin', 'password' => 'camping'})
697 # #=> #<Blog::Controllers::Login @user=... >
698 #
699 # Blog.get(:Info, :env => {:HTTP_HOST => 'wagon'})
700 # #=> #<Blog::Controllers::Info @env={'HTTP_HOST'=>'wagon'} ...>
701 #
1109984 * lib/camping.rb: experimenting with Camping.method_missing as an answe...
_why authored
702 def method_missing(m, c, *a)
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
703 X.M
704 k = X.const_get(c).new(StringIO.new,
705 H['HTTP_HOST','','SCRIPT_NAME','','HTTP_COOKIE',''],m.to_s)
706 H.new(a.pop).each { |e,f| k.send("#{e}=",f) } if Hash === a[-1]
707 k.service *a
1109984 * lib/camping.rb: experimenting with Camping.method_missing as an answe...
_why authored
708 end
abc7043 Initial import.
_why authored
709 end
c3e919e lib/camping.rb: docs!
_why authored
710
d3c7efe lib/camping.rb: trying to speed-up Markaby by creating the Mab class in ...
_why authored
711 # Models is an empty Ruby module for housing model classes derived
712 # from ActiveRecord::Base. As a shortcut, you may derive from Base
713 # which is an alias for ActiveRecord::Base.
714 #
715 # module Camping::Models
716 # class Post < Base; belongs_to :user end
717 # class User < Base; has_many :posts end
718 # end
719 #
720 # == Where Models are Used
721 #
722 # Models are used in your controller classes. However, if your model class
723 # name conflicts with a controller class name, you will need to refer to it
724 # using the Models module.
725 #
726 # module Camping::Controllers
727 # class Post < R '/post/(\d+)'
728 # def get(post_id)
729 # @post = Models::Post.find post_id
730 # render :index
731 # end
732 # end
733 # end
734 #
735 # Models cannot be referred to in Views at this time.
5a49057 * lib/camping.rb: let's not cast Markaby to a string by default, that's...
_why authored
736 module Models;def Y;self;end
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
737 autoload:Base,'camping/db'
fdbf7ed * lib/camping.rb: auto-prefix tables to prevent name clash between sepa...
_why authored
738 end
d3c7efe lib/camping.rb: trying to speed-up Markaby by creating the Mab class in ...
_why authored
739
c3e919e lib/camping.rb: docs!
_why authored
740 # Views is an empty module for storing methods which create HTML. The HTML is described
741 # using the Markaby language.
742 #
743 # == Using the layout method
744 #
745 # If your Views module has a <tt>layout</tt> method defined, it will be called with a block
746 # which will insert content from your view.
8cc0bc9 * lib/camping.rb: shorten a few `include` statements, thanks to ticket ...
_why authored
747 module Views; include Controllers, Helpers end
d3c7efe lib/camping.rb: trying to speed-up Markaby by creating the Mab class in ...
_why authored
748
749 # The Mab class wraps Markaby, allowing it to run methods from Camping::Views
9a2308d * lib/camping.rb: added Helpers.URL, which builds a complete URL to a r...
_why authored
750 # and also to replace :href, :action and :src attributes in tags by prefixing the root
d3c7efe lib/camping.rb: trying to speed-up Markaby by creating the Mab class in ...
_why authored
751 # path.
752 class Mab < Markaby::Builder
753 include Views
754 def tag!(*g,&b)
97ff9e0 @mental obsessive variable name tweak
mental authored
755 h=g[-1]
9a2308d * lib/camping.rb: added Helpers.URL, which builds a complete URL to a r...
_why authored
756 [:href,:action,:src].each{|a|(h[a]=self/h[a])rescue 0}
d3c7efe lib/camping.rb: trying to speed-up Markaby by creating the Mab class in ...
_why authored
757 super
758 end
759 end
abc7043 Initial import.
_why authored
760 end
5723cd8 * lib/camping.rb: allow the Camping scriptable dispatcher (Camping.meth...
_why authored
761
762 autoload:ActiveRecord,'camping/db'
Something went wrong with that request. Please try again.