Module Capcode
In: lib/capcode.rb
lib/capcode/base/db.rb
lib/capcode/configuration.rb
lib/capcode/render/binary.rb
lib/capcode/render/email.rb
lib/capcode/render/erb.rb
lib/capcode/render/haml.rb
lib/capcode/render/json.rb
lib/capcode/render/markaby.rb
lib/capcode/render/mustache.rb
lib/capcode/render/none.rb
lib/capcode/render/redirect.rb
lib/capcode/render/sass.rb
lib/capcode/render/static.rb
lib/capcode/render/text.rb
lib/capcode/render/webdav.rb
lib/capcode/render/xml.rb
lib/capcode/helpers/auth.rb

Methods

Route   application   config   env   http_authentication   map   params   request   response   run   session   set   use  

Included Modules

Rack Capcode::Helpers Capcode::Views

Classes and Modules

Module Capcode::Helpers
Module Capcode::Resource
Module Capcode::Views
Class Capcode::Base
Class Capcode::HTTPError
Class Capcode::Mab

Attributes

__auth__  [RW] 

Public Class methods

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

[Source]

     # File lib/capcode.rb, line 305
305:     def Route *routes_paths
306:       Class.new {
307:         meta_def(:__urls__) {
308:           # < Route '/hello/world/([^\/]*)/id(\d*)', '/hello/(.*)', :agent => /Songbird (\d\.\d)[\d\/]*?/
309:           # # => [ {'/hello/world' => '([^\/]*)/id(\d*)', '/hello' => '(.*)'}, 
310:           #        2, 
311:           #        <Capcode::Klass>, 
312:           #        {:agent => /Songbird (\d\.\d)[\d\/]*?/} ]
313:           hash_of_routes = {}
314:           max_captures_for_routes = 0
315:           routes_paths.each do |current_route_path|
316:             if current_route_path.class == String
317:               m = /\/([^\/]*\(.*)/.match( current_route_path )
318:               if m.nil?
319:                 raise Capcode::RouteError, "Route `#{current_route_path}' already defined with regexp `#{hash_of_routes[current_route_path]}' !", caller if hash_of_routes.keys.include?(current_route_path)
320:                 hash_of_routes[current_route_path] = ''
321:               else
322:                 _pre = m.pre_match
323:                 _pre = "/" if _pre.size == 0
324:                 raise Capcode::RouteError, "Route `#{_pre}' already defined with regexp `#{hash_of_routes[_pre]}' !", caller if hash_of_routes.keys.include?(_pre)
325:                 hash_of_routes[_pre] = m.captures[0]
326:                 max_captures_for_routes = Regexp.new(m.captures[0]).number_of_captures if max_captures_for_routes < Regexp.new(m.captures[0]).number_of_captures
327:               end
328:             else
329:               raise Capcode::ParameterError, "Bad route declaration !", caller
330:             end
331:           end
332:           [hash_of_routes, max_captures_for_routes, self]
333:         }
334:                 
335:         # Hash containing all the request parameters (GET or POST)
336:         def params
337:           @request.params
338:         end
339:         
340:         # Hash containing all the environment variables
341:         def env
342:           @env
343:         end
344:         
345:         # Session hash
346:         def session
347:           @env['rack.session']
348:         end
349:         
350:         # Return the Rack::Request object
351:         def request
352:           @request
353:         end
354:         
355:         # Return the Rack::Response object
356:         def response
357:           @response
358:         end
359:         
360:         def call( e ) #:nodoc:
361:           @env = e
362:           @response = Rack::Response.new
363:           @request = Rack::Request.new(@env)
364: 
365:           # __k = self.class.to_s.split( /::/ )[-1].downcase.to_sym
366:           # @@__FILTERS.each do |f|
367:           #   proc = f.delete(:action)
368:           #   __run = true
369:           #   if f[:only]
370:           #     __run = f[:only].include?(__k)
371:           #   end
372:           #   if f[:except]
373:           #     __run = !f[:except].include?(__k)
374:           #   end
375:           #   
376:           #   # proc.call(self) if __run
377:           #   puts "call #{proc} for #{__k}"
378:           # end
379: 
380:           # Check authz
381:           authz_options = nil
382:           if Capcode.__auth__ and Capcode.__auth__.size > 0
383:             authz_options = Capcode.__auth__[@request.path]||nil
384:             if authz_options.nil?
385:               route = nil
386:               
387:               Capcode.__auth__.each do |r, o|
388:                 regexp = "^#{r.gsub(/\/$/, "")}([/]{1}.*)?$"
389:                 if Regexp.new(regexp).match( @request.path )
390:                   if route.nil? or r.size > route.size
391:                     route = r
392:                     authz_options = o
393:                   end
394:                 end  
395:               end
396:             end
397:           end
398: 
399:           r = catch(:halt) { 
400:             unless authz_options.nil?
401:               http_authentication( :type => authz_options[:type], :realm => authz_options[:realm], :opaque => authz_options[:realm] ) { 
402:                 authz_options[:autz]
403:               }
404:             end
405: 
406:             finalPath = nil
407:             finalArgs = nil
408:             finalNArgs = nil
409:             
410:             aPath = @request.path.gsub( /^\//, "" ).split( "/" )
411:             self.class.__urls__[0].each do |p, r|
412:               xPath = p.gsub( /^\//, "" ).split( "/" )
413:               if (xPath - aPath).size == 0
414:                 diffArgs = aPath - xPath
415:                 diffNArgs = diffArgs.size
416:                 if finalNArgs.nil? or finalNArgs > diffNArgs
417:                   finalPath = p
418:                   finalNArgs = diffNArgs
419:                   finalArgs = diffArgs
420:                 end
421:               end
422:               
423:             end
424:         
425:             nargs = self.class.__urls__[1]
426:             regexp = Regexp.new( self.class.__urls__[0][finalPath] )
427:             args = regexp.match( Rack::Utils.unescape(@request.path).gsub( Regexp.new( "^#{finalPath}" ), "" ).gsub( /^\//, "" ) )
428:             if args.nil?
429:               raise Capcode::ParameterError, "Path info `#{@request.path_info}' does not match route regexp `#{regexp.source}'"
430:             else
431:               args = args.captures.map { |x| (x.size == 0)?nil:x }
432:             end
433:             
434:             while args.size < nargs
435:               args << nil
436:             end
437: 
438:             case @env["REQUEST_METHOD"]
439:               when "GET"                      
440:                 get( *args )
441:               when "POST"
442:                 _method = params.delete( "_method" ) { |_| "post" }
443:                 send( _method.downcase.to_sym, *args )
444:               else
445:                 _method = @env["REQUEST_METHOD"]
446:                 send( _method.downcase.to_sym, *args )
447:             end
448:           }
449:           if r.respond_to?(:to_ary)
450:             @response.status = r.shift #r[0]
451:             #r[1].each do |k,v|
452:             r.shift.each do |k,v|
453:               @response[k] = v
454:             end
455:             @response.body = r.shift #r[2]
456:           else
457:             @response.write r
458:           end
459:                     
460:           @response.finish
461:         end
462:                 
463:         include Capcode::Helpers
464:         include Capcode::Views
465:       }      
466:     end

Return the Rack App.

Options : see Capcode.set

Options set here replace the ones set globally

[Source]

     # File lib/capcode.rb, line 552
552:     def application( args = {} )
553:       conf = configuration(args)
554:       
555:       Capcode.constants.each do |k|
556:         begin
557:           if eval "Capcode::#{k}.public_methods(true).include?( '__urls__' )"
558:             hash_of_routes, max_captures_for_routes, klass = eval "Capcode::#{k}.__urls__"
559:             hash_of_routes.keys.each do |current_route_path|
560:               #raise Capcode::RouteError, "Route `#{current_route_path}' already define !", caller if @@__ROUTES.keys.include?(current_route_path)
561:               raise Capcode::RouteError, "Route `#{current_route_path}' already define !", caller if Capcode.routes.keys.include?(current_route_path)
562:               #@@__ROUTES[current_route_path] = klass.new
563:               Capcode.routes[current_route_path] = klass.new
564:             end
565:           end
566:         rescue => e
567:           raise e.message
568:         end
569:       end
570:       
571:       # Set Static directory
572:       #@@__STATIC_DIR = (conf[:static][0].chr == "/")?conf[:static]:"/"+conf[:static] unless conf[:static].nil?
573:       Capcode.static = (conf[:static][0].chr == "/")?conf[:static]:"/"+conf[:static] unless conf[:static].nil?
574:       
575:       # Initialize Rack App
576:       puts "** Map routes." if conf[:verbose]
577:       #app = Rack::URLMap.new(@@__ROUTES)
578:       app = Rack::URLMap.new(Capcode.routes)
579:       puts "** Initialize static directory (#{conf[:static]})" if conf[:verbose]
580:       app = Rack::Static.new( 
581:         app, 
582:         #:urls => [@@__STATIC_DIR], 
583:         :urls => [Capcode.static], 
584:         :root => File.expand_path(conf[:root]) 
585:       ) unless conf[:static].nil?
586:       puts "** Initialize session" if conf[:verbose]
587:       app = Rack::Session::Cookie.new( app, conf[:session] )
588:       app = Capcode::HTTPError.new(app)
589:       app = Rack::ContentLength.new(app)
590:       app = Rack::Lint.new(app)
591:       app = Rack::ShowExceptions.new(app)
592:       #app = Rack::Reloader.new(app) ## -- NE RELOAD QUE capcode.rb -- So !!!
593:       # app = Rack::CommonLogger.new( app, Logger.new(conf[:log]) )
594:       
595:       middlewares.each do |mw|
596:         middleware, args, block = mw
597:         puts "** Load middleware #{middleware}" if conf[:verbose]
598:         if block
599:           app = middleware.new( app, *args, &block )
600:         else
601:           app = middleware.new( app, *args )
602:         end
603:       end
604:       
605:       # Start database
606:       if self.methods.include? "db_connect"
607:         db_connect( conf[:db_config], conf[:log] )
608:       end
609:       
610:       if block_given?
611:         yield( self )
612:       end
613:       
614:       return app
615:     end

[Source]

    # File lib/capcode/configuration.rb, line 35
35:     def config
36:       @configuration ||= {}
37:     end

Hash containing all the environment variables

[Source]

     # File lib/capcode.rb, line 341
341:         def env
342:           @env
343:         end

Allow you to add and HTTP Authentication (Basic or Digest) to controllers for or specific route

Options :

  • :type : Authentication type (:basic or :digest) - default : :basic
  • :realm : realm ;) - default : "Capcode.app"
  • :opaque : Your secret passphrase. You MUST set it if you use Digest Auth - default : "opaque"
  • :routes : Routes - default : "/"

The block must return a Hash of username => password like that :

  {
    "user1" => "pass1",
    "user2" => "pass2",
    # ...
  }

[Source]

     # File lib/capcode.rb, line 509
509:     def http_authentication( opts = {}, &b )
510:       options = {
511:         :type => :basic,
512:         :realm => "Capcode.app",
513:         :opaque => "opaque",
514:         :routes => "/"
515:       }.merge( opts )
516:       
517:       options[:autz] = b.call()
518:       
519:       @__auth__ ||= {}
520:       
521:       if options[:routes].class == Array
522:         options[:routes].each do |r|
523:           @__auth__[r] = options
524:         end
525:       else
526:         @__auth__[options[:routes]] = options
527:       end      
528:     end

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

  Capcode.map( "/file" ) do
    Rack::File.new( "." )
  end

[Source]

     # File lib/capcode.rb, line 473
473:     def map( route, &b )
474:       #@@__ROUTES[route] = yield
475:       Capcode.routes[route] = yield
476:     end

Hash containing all the request parameters (GET or POST)

[Source]

     # File lib/capcode.rb, line 336
336:         def params
337:           @request.params
338:         end

Return the Rack::Request object

[Source]

     # File lib/capcode.rb, line 351
351:         def request
352:           @request
353:         end

Return the Rack::Response object

[Source]

     # File lib/capcode.rb, line 356
356:         def response
357:           @response
358:         end

Start your application.

Options : see Capcode.set

Options set here replace the ones set globally

[Source]

     # File lib/capcode.rb, line 622
622:     def run( args = {} )
623:       conf = configuration(args)
624:       
625:       # Parse options
626:       opts = OptionParser.new do |opts|
627:         opts.banner = "Usage: #{File.basename($0)} [options]"
628:         opts.separator ""
629:         opts.separator "Specific options:"
630: 
631:         opts.on( "-C", "--console", "Run in console mode with IRB (default: false)" ) { 
632:           conf[:console] = true
633:         }
634:         opts.on( "-h", "--host HOSTNAME", "Host for web server to bind to (default: #{conf[:host]})" ) { |h|
635:           conf[:host] = h
636:         }
637:         opts.on( "-p", "--port NUM", "Port for web server (default: #{conf[:port]})" ) { |p|
638:           conf[:port] = p
639:         }
640:         opts.on( "-d", "--daemonize [true|false]", "Daemonize (default: #{conf[:daemonize]})" ) { |d|
641:           conf[:daemonize] = d
642:         }
643:         opts.on( "-r", "--root PATH", "Working directory (default: #{conf[:root]})" ) { |w|
644:           conf[:root] = w
645:         }
646:         opts.on( "-s", "--static PATH", "Static directory -- relative to the root directory (default: #{conf[:static]})" ) { |r|
647:           conf[:static] = r
648:         }
649: 
650:         opts.separator ""
651:         opts.separator "Common options:"
652: 
653:         opts.on("-?", "--help", "Show this message") do
654:           puts opts
655:           exit
656:         end  
657:         opts.on("-v", "--version", "Show versions") do
658:           puts "Capcode version #{Capcode::CAPCOD_VERION} (ruby v#{RUBY_VERSION})"
659:           exit
660:         end  
661:         opts.on_tail( "-V", "--verbose", "Run in verbose mode" ) do
662:           conf[:verbose] = true
663:         end
664:       end
665:       
666:       begin
667:         opts.parse! ARGV
668:       rescue OptionParser::ParseError => ex
669:         puts "!! #{ex.message}"
670:         puts "** use `#{File.basename($0)} --help` for more details..."
671:         exit 1
672:       end
673:       
674:       # Run in the Working directory
675:       puts "** Go on root directory (#{File.expand_path(conf[:root])})" if conf[:verbose]
676:       Dir.chdir( conf[:root] ) do
677:         
678:         # Check that mongrel exists 
679:         if conf[:server].nil? || conf[:server] == "mongrel"
680:           begin
681:             require 'mongrel'
682:             conf[:server] = "mongrel"
683:           rescue LoadError 
684:             puts "!! could not load mongrel. Falling back to webrick."
685:             conf[:server] = "webrick"
686:           end
687:         end
688:         
689:         # From rackup !!!
690:         if conf[:daemonize]
691:           if /java/.match(RUBY_PLATFORM).nil?
692:             if RUBY_VERSION < "1.9"
693:               exit if fork
694:               Process.setsid
695:               exit if fork
696:               # Dir.chdir "/"
697:               File.umask 0000
698:               STDIN.reopen "/dev/null"
699:               STDOUT.reopen "/dev/null", "a"
700:               STDERR.reopen "/dev/null", "a"
701:             else
702:               Process.daemon
703:             end
704:           else
705:             puts "!! daemonize option unavailable on #{RUBY_PLATFORM} platform."
706:           end
707:         
708:           File.open(conf[:pid], 'w'){ |f| f.write("#{Process.pid}") }
709:           at_exit { File.delete(conf[:pid]) if File.exist?(conf[:pid]) }
710:         end
711:         
712:         app = nil
713:         if block_given?
714:           app = application(conf) { yield( self ) }
715:         else
716:           app = application(conf)
717:         end
718:         app = Rack::CommonLogger.new( app, Logger.new(conf[:log]) )
719:         
720:         if conf[:console]
721:           puts "Run console..."
722:           IRB.start
723:           exit
724:         end
725:         
726:         # Start server
727:         case conf[:server].to_s
728:         when "mongrel"
729:           puts "** Starting Mongrel on #{conf[:host]}:#{conf[:port]}"
730:           Rack::Handler::Mongrel.run( app, {:Port => conf[:port], :Host => conf[:host]} ) { |server|
731:             trap "SIGINT", proc { server.stop }
732:           }
733:         when "webrick"
734:           puts "** Starting WEBrick on #{conf[:host]}:#{conf[:port]}"
735:           Rack::Handler::WEBrick.run( app, {:Port => conf[:port], :BindAddress => conf[:host]} ) { |server|
736:             trap "SIGINT", proc { server.shutdown }
737:           }
738:         when "thin"
739:           puts "** Starting Thin on #{conf[:host]}:#{conf[:port]}"
740:           Rack::Handler::Thin.run( app, {:Port => conf[:port], :Host => conf[:host]} ) { |server|
741:             trap "SIGINT", proc { server.stop }
742:           }
743:         end
744:       end
745:     end

Session hash

[Source]

     # File lib/capcode.rb, line 346
346:         def session
347:           @env['rack.session']
348:         end

Set global configuration options

Options :

  • :port = Listen port (default: 3000)
  • :host = Listen host (default: 0.0.0.0)
  • :server = Server type (webrick, mongrel or thin)
  • :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: the working directory)
  • :root = Root directory (default: directory of the main.rb) — This is also the working directory !
  • :verbose = run in verbose mode
  • :auth = HTTP Basic Authentication options

It can exist specifics options depending on a renderer, a helper, …

Example :

  module Capcode
    set :erb, "/path/to/erb/files"
    ...
  end

[Source]

    # File lib/capcode/configuration.rb, line 27
27:     def set( key, value )
28:       config[key] = value
29:     end

This method allow you to use a Rack middleware

Example :

  module Capcode
    ...
    use Rack::Codehighlighter, :coderay, :element => "pre",
      :pattern => /\A:::(\w+)\s*\n/, :logging => false
    ...
  end

[Source]

     # File lib/capcode.rb, line 488
488:     def use(middleware, *args, &block)
489:       middlewares << [middleware, args, block]
490:     end

[Validate]