# Module: Capcode
[ "README", "AUTHORS", "COPYING", "lib/capcode.rb", nil].each do
Capcode.view_html
Capcode::Views.view_html
Capcode::Helpers.view_html
Capcode::HTTPError.view_html
Capcode::RenderError.view_html
Capcode::RouteError.view_html
Capcode::ParameterError.view_html
end

Module Capcode

(in files lib/capcode.rb )

Includes

Methods

Public Class method: Route(*u)

Add routes to a controller class

  module Capcode
    class Hello < Route '/hello/(.*)', '/hello/([^#]*)#(.*)'
      def get( arg1, arg2 )
        ...
      end
    end
  end

In the get method, you will receive the maximum of parameters declared by the routes. In this example, you will receive 2 parameters. So if you go to /hello/world#friend then arg1 will be set to world and arg2 will be set to friend. Now if you go to /hello/you, then arg1 will be set to you and arg2 will be set to nil

If the regexp in the route does not match, all arguments will be nil

     # File lib/capcode.rb, line 210
210:     def Route *u
211:       Class.new {
212:         meta_def(:__urls__){
213:           # < Route '/hello/world/([^\/]*)/id(\d*)', '/hello/(.*)'
214:           # # => [ {'/hello/world' => '([^\/]*)/id(\d*)', '/hello' => '(.*)'}, 2, <Capcode::Klass> ]
215:           h = {}
216:           max = 0
217:           u.each do |_u|
218:             m = /\/([^\/]*\(.*)/.match( _u )
219:             if m.nil?
220:               raise Capcode::RouteError, "Route `#{_u}' already defined with regexp `#{h[_u]}' !", caller if h.keys.include?(_u)
221:               h[_u] = ''
222:             else
223:               _pre = m.pre_match
224:               _pre = "/" if _pre.size == 0
225:               raise Capcode::RouteError, "Route `#{_pre}' already defined with regexp `#{h[_pre]}' !", caller if h.keys.include?(_pre)
226:               h[_pre] = m.captures[0]
227:               max = Regexp.new(m.captures[0]).number_of_captures if max < Regexp.new(m.captures[0]).number_of_captures
228:             end
229:           end
230:           [h, max, self]
231:         }
232: 
233:         # Hash containing all the request parameters (GET or POST)
234:         def params
235:           @request.params
236:         end
237:         
238:         # Hash containing all the environment variables
239:         def env
240:           @env
241:         end
242:         
243:         # Hash session
244:         def session
245:           @env['rack.session']
246:         end
247:         
248:         # Return the Rack::Request object
249:         def request
250:           @request
251:         end
252:         
253:         # Return the Rack::Response object
254:         def response
255:           @response
256:         end
257:         
258:         def call( e ) #:nodoc:
259:           @env = e
260:           @response = Rack::Response.new
261:           @request = Rack::Request.new(@env)
262: 
263:           # __k = self.class.to_s.split( /::/ )[-1].downcase.to_sym
264:           # @@__FILTERS.each do |f|
265:           #   proc = f.delete(:action)
266:           #   __run = true
267:           #   if f[:only]
268:           #     __run = f[:only].include?(__k)
269:           #   end
270:           #   if f[:except]
271:           #     __run = !f[:except].include?(__k)
272:           #   end
273:           #   
274:           #   # proc.call(self) if __run
275:           #   puts "call #{proc} for #{__k}"
276:           # end
277: 
278:           r = case @env["REQUEST_METHOD"]
279:             when "GET"
280:               finalPath = nil
281:               finalArgs = nil
282:               finalNArgs = nil
283:               
284:               aPath = @request.path.gsub( /^\//, "" ).split( "/" )
285:               self.class.__urls__[0].each do |p, r|
286:                 xPath = p.gsub( /^\//, "" ).split( "/" )
287:                 if (xPath - aPath).size == 0
288:                   diffArgs = aPath - xPath
289:                   diffNArgs = diffArgs.size
290:                   if finalNArgs.nil? or finalNArgs > diffNArgs
291:                     finalPath = p
292:                     finalNArgs = diffNArgs
293:                     finalArgs = diffArgs
294:                   end
295:                 end
296:                 
297:               end
298: 
299:               nargs = self.class.__urls__[1]
300:               regexp = Regexp.new( self.class.__urls__[0][finalPath] )
301:               args = regexp.match( Rack::Utils.unescape(@request.path).gsub( Regexp.new( "^#{finalPath}" ), "" ).gsub( /^\//, "" ) )
302:               if args.nil?
303:                 raise Capcode::ParameterError, "Path info `#{@request.path_info}' does not match route regexp `#{regexp.source}'"
304:               else
305:                 args = args.captures.map { |x| (x.size == 0)?nil:x }
306:               end
307:               
308:               while args.size < nargs
309:                 args << nil
310:               end
311:                     
312:               get( *args )
313:             when "POST"
314:               post
315:           end
316:           if r.respond_to?(:to_ary)
317:             @response.status = r[0]
318:             r[1].each do |k,v|
319:               @response[k] = v
320:             end
321:             @response.body = r[2]
322:           else
323:             @response.write r
324:           end
325:           
326:           @response.finish
327:         end
328:                 
329:         include Capcode::Helpers
330:         include Capcode::Views
331:       }      
332:     end

Public Class method: env()

Hash containing all the environment variables

     # File lib/capcode.rb, line 239
239:         def env
240:           @env
241:         end

Public Class method: map( r ) {|| ...}

This method help you to map and URL to a Rack or What you want Helper

  Capcode.map( "/file" ) do
    Rack::File.new( "." )
  end
     # File lib/capcode.rb, line 339
339:     def map( r, &b )
340:       @@__ROUTES[r] = yield
341:     end

Public Class method: params()

Hash containing all the request parameters (GET or POST)

     # File lib/capcode.rb, line 234
234:         def params
235:           @request.params
236:         end

Public Class method: request()

Return the Rack::Request object

     # File lib/capcode.rb, line 249
249:         def request
250:           @request
251:         end

Public Class method: response()

Return the Rack::Response object

     # File lib/capcode.rb, line 254
254:         def response
255:           @response
256:         end

Public Class method: run( args = {} ) {|self| ...}

Start your application.

Options :

  • :port = Listen port
  • :host = Listen host
  • :server = Server type (webrick or mongrel)
  • :log = Output logfile (default: STDOUT)
  • :session = Session parameters. See Rack::Session for more informations
  • :pid = PID file (default: $0.pid)
  • :daemonize = Daemonize application (default: false)
  • :db_config = database configuration file (default: database.yml)
  • :static = Static directory (default: none — relative to the working directory)
  • :root = Root directory (default: directory of the main.rb) — This is also the working directory !
     # File lib/capcode.rb, line 356
356:     def run( args = {} )
357:       __VERBOSE = false
358:       
359:       conf = {
360:         :port => args[:port]||3000, 
361:         :host => args[:host]||"localhost",
362:         :server => args[:server]||nil,
363:         :log => args[:log]||$stdout,
364:         :session => args[:session]||{},
365:         :pid => args[:pid]||"#{$0}.pid",
366:         :daemonize => args[:daemonize]||false,
367:         :db_config => File.expand_path(args[:db_config]||"database.yml"),
368:         :static => args[:static]||nil,
369:         :root => args[:root]||File.expand_path(File.dirname($0)),
370:         
371:         :console => false
372:       }
373:       
374:       # Parse options
375:       opts = OptionParser.new do |opts|
376:         opts.banner = "Usage: #{File.basename($0)} [options]"
377:         opts.separator ""
378:         opts.separator "Specific options:"
379: 
380:         opts.on( "-C", "--console", "Run in console mode with IRB (default: false)" ) { 
381:           conf[:console] = true
382:         }
383:         opts.on( "-h", "--host HOSTNAME", "Host for web server to bind to (default: #{conf[:host]})" ) { |h|
384:           conf[:host] = h
385:         }
386:         opts.on( "-p", "--port NUM", "Port for web server (default: #{conf[:port]})" ) { |p|
387:           conf[:port] = p
388:         }
389:         opts.on( "-d", "--daemonize [true|false]", "Daemonize (default: #{conf[:daemonize]})" ) { |d|
390:           conf[:daemonize] = d
391:         }
392:         opts.on( "-r", "--root PATH", "Working directory (default: #{conf[:root]})" ) { |w|
393:           conf[:root] = w
394:         }
395:         opts.on( "-s", "--static PATH", "Static directory -- relative to the root directory (default: #{conf[:static]})" ) { |r|
396:           conf[:static] = r
397:         }
398: 
399:         opts.separator ""
400:         opts.separator "Common options:"
401: 
402:         opts.on("-?", "--help", "Show this message") do
403:           puts opts
404:           exit
405:         end  
406:         opts.on("-v", "--version", "Show versions") do
407:           puts "Capcode version #{Capcode::CAPCOD_VERION} (ruby v#{RUBY_VERSION})"
408:           exit
409:         end  
410:         opts.on_tail( "-V", "--verbose", "Run in verbose mode" ) do
411:           __VERBOSE = true
412:         end
413:       end
414:       
415:       begin
416:         opts.parse! ARGV
417:       rescue OptionParser::ParseError => ex
418:         puts "!! #{ex.message}"
419:         puts "** use `#{File.basename($0)} --help` for more details..."
420:         exit 1
421:       end
422:       
423:       # Run in the Working directory
424:       puts "** Go on root directory (#{File.expand_path(conf[:root])})" if __VERBOSE
425:       Dir.chdir( conf[:root] ) do
426:         
427:         # Check that mongrel exists 
428:         if conf[:server].nil? || conf[:server] == "mongrel"
429:           begin
430:             require 'mongrel'
431:             conf[:server] = "mongrel"
432:           rescue LoadError 
433:             puts "!! could not load mongrel. Falling back to webrick."
434:             conf[:server] = "webrick"
435:           end
436:         end
437:             
438:         Capcode.constants.each do |k|
439:           begin
440:             if eval "Capcode::#{k}.public_methods(true).include?( '__urls__' )"
441:               u, m, c = eval "Capcode::#{k}.__urls__"
442:               u.keys.each do |_u|
443:                 raise Capcode::RouteError, "Route `#{_u}' already define !", caller if @@__ROUTES.keys.include?(_u)
444:                 @@__ROUTES[_u] = c.new
445:               end
446:             end
447:           rescue => e
448:             raise e.message
449:           end
450:         end
451:         
452:         # Set Static directory
453:         @@__STATIC_DIR = (conf[:static][0].chr == "/")?conf[:static]:"/"+conf[:static] unless conf[:static].nil?
454:         
455:         # Initialize Rack App
456:         puts "** Map routes." if __VERBOSE
457:         app = Rack::URLMap.new(@@__ROUTES)
458:         puts "** Initialize static directory (#{conf[:static]})" if __VERBOSE
459:         app = Rack::Static.new( 
460:           app, 
461:           :urls => [@@__STATIC_DIR], 
462:           :root => File.expand_path(conf[:root]) 
463:         ) unless conf[:static].nil?
464:         puts "** Initialize session" if __VERBOSE
465:         app = Rack::Session::Cookie.new( app, conf[:session] )
466:         app = Capcode::HTTPError.new(app)
467:         app = Rack::ContentLength.new(app)
468:         app = Rack::Lint.new(app)
469:         app = Rack::ShowExceptions.new(app)
470: #        app = Rack::Reloader.new(app) ## -- NE RELOAD QUE capcode.rb -- So !!!
471:         app = Rack::CommonLogger.new( app, Logger.new(conf[:log]) )
472:         
473:         # From rackup !!!
474:         if conf[:daemonize]
475:           if /java/.match(RUBY_PLATFORM).nil?
476:             if RUBY_VERSION < "1.9"
477:               exit if fork
478:               Process.setsid
479:               exit if fork
480:               # Dir.chdir "/"
481:               File.umask 0000
482:               STDIN.reopen "/dev/null"
483:               STDOUT.reopen "/dev/null", "a"
484:               STDERR.reopen "/dev/null", "a"
485:             else
486:               Process.daemon
487:             end
488:           else
489:             puts "!! daemonize option unavailable on #{RUBY_PLATFORM} platform."
490:           end
491:         
492:           File.open(conf[:pid], 'w'){ |f| f.write("#{Process.pid}") }
493:           at_exit { File.delete(conf[:pid]) if File.exist?(conf[:pid]) }
494:         end
495:         
496:         # Start database
497:         if self.methods.include? "db_connect"
498:           db_connect( conf[:db_config], conf[:log] )
499:         end
500:         
501:         if block_given?
502:           yield( self )
503:         end
504:         
505:         if conf[:console]
506:           puts "Run console..."
507:           IRB.start
508:           exit
509:         end
510:         
511:         # Start server
512:         case conf[:server]
513:         when "mongrel"
514:           puts "** Starting Mongrel on #{conf[:host]}:#{conf[:port]}"
515:           Rack::Handler::Mongrel.run( app, {:Port => conf[:port], :Host => conf[:host]} ) { |server|
516:             trap "SIGINT", proc { server.stop }
517:           }
518:         when "webrick"
519:           puts "** Starting WEBrick on #{conf[:host]}:#{conf[:port]}"
520:           Rack::Handler::WEBrick.run( app, {:Port => conf[:port], :BindAddress => conf[:host]} ) { |server|
521:             trap "SIGINT", proc { server.shutdown }
522:           }
523:         end
524:       end
525:     end

Public Class method: session()

Hash session

     # File lib/capcode.rb, line 244
244:         def session
245:           @env['rack.session']
246:         end