Module Capcode
In: lib/capcode.rb
lib/capcode/base/db.rb
lib/capcode/configuration.rb
lib/capcode/filters.rb
lib/capcode/render/text.rb
lib/capcode/helpers/auth.rb

Methods

Route   application   before_filter   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::Configuration
Class Capcode::HTTPError

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

Return the Rack App.

Options : see Capcode::Configuration.set

Options set here replace the ones set globally

[Source]

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

Add a before filter :

  module Capcode
    before_filter :my_global_action
    before_filter :need_login, :except => [:Login]
    before_filter :check_mail, :only => [:MailBox]
    # ...
  end

If the action return nil, the normal get or post will be executed, else no.

[Source]

    # File lib/capcode/filters.rb, line 14
14:     def before_filter( action, opts = {} )
15:       Capcode::Filter.filters[action] = { }
16:       
17:       opts.each do |k, v|
18:         Capcode::Filter.filters[action][k] = v
19:       end
20:     end

Hash containing all the environment variables

[Source]

     # File lib/capcode.rb, line 370
370:         def env
371:           @env
372:         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 544
544:     def http_authentication( opts = {}, &b )
545:       options = {
546:         :type => :basic,
547:         :realm => "Capcode.app",
548:         :opaque => "opaque",
549:         :routes => "/"
550:       }.merge( opts )
551:       
552:       options[:autz] = b.call()
553:       
554:       @__auth__ ||= {}
555:       
556:       if options[:routes].class == Array
557:         options[:routes].each do |r|
558:           @__auth__[r] = options
559:         end
560:       else
561:         @__auth__[options[:routes]] = options
562:       end      
563:     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 508
508:     def map( route, &b )
509:       #@@__ROUTES[route] = yield
510:       Capcode.routes[route] = yield
511:     end

Hash containing all the request parameters (GET or POST)

[Source]

     # File lib/capcode.rb, line 365
365:         def params
366:           @request.params
367:         end

Return the Rack::Request object

[Source]

     # File lib/capcode.rb, line 380
380:         def request
381:           @request
382:         end

Return the Rack::Response object

[Source]

     # File lib/capcode.rb, line 385
385:         def response
386:           @response
387:         end

Start your application.

Options : see Capcode::Configuration.set

Options set here replace the ones set globally

[Source]

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

Session hash

[Source]

     # File lib/capcode.rb, line 375
375:         def session
376:           @env['rack.session']
377:         end

[Source]

   # File lib/capcode/configuration.rb, line 3
3:     def set(key, value, opts = {}); Configuration.set(key, value, opts); 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 523
523:     def use(middleware, *args, &block)
524:       middlewares << [middleware, args, block]
525:     end

[Validate]