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   logger   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
Class Capcode::StaticFiles

Constants

Route = Capcode::Route(nil)

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 396
396:     def Route *routes_paths
397:       create_path = routes_paths[0].nil?
398:       Class.new {
399:         meta_def(:__urls__) {
400:           routes_paths = ['/'+self.to_s.gsub( /^Capcode::/, "" ).underscore] if create_path == true
401:           # < Route '/hello/world/([^\/]*)/id(\d*)', '/hello/(.*)', :agent => /Songbird (\d\.\d)[\d\/]*?/
402:           # # => [ {
403:           #          '/hello/world' => {
404:           #            :regexp => '([^\/]*)/id(\d*)',
405:           #            :route => '/hello/world/([^\/]*)/id(\d*)',
406:           #            :nargs => 2
407:           #          },
408:           #          '/hello/world' => {
409:           #            :regexp => '(.*)',
410:           #            :route => '/hello/(.*)',
411:           #            :nargs => 1
412:           #          }
413:           #        },
414:           #        2, 
415:           #        <Capcode::Klass>, 
416:           #        {:agent => /Songbird (\d\.\d)[\d\/]*?/} ]
417:           hash_of_routes = {}
418:           max_captures_for_routes = 0
419:           routes_paths.each do |current_route_path|
420:             if current_route_path.class == String
421:               m = /\/([^\/]*\(.*)/.match( current_route_path )
422:               if m.nil?
423:                 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)
424:                 hash_of_routes[current_route_path] = {
425:                   :regexp => '',
426:                   :route => current_route_path,
427:                   :nargs => 0
428:                 }
429:               else
430:                 _pre = m.pre_match
431:                 _pre = "/" if _pre.size == 0
432:                 raise Capcode::RouteError, "Route `#{_pre}' already defined with regexp `#{hash_of_routes[_pre]}' !", caller if hash_of_routes.keys.include?(_pre)
433:                 captures_for_routes = Regexp.new(m.captures[0]).number_of_captures
434:                 
435:                 hash_of_routes[_pre] = {
436:                   :regexp => m.captures[0],
437:                   :route => current_route_path,
438:                   :nargs => captures_for_routes
439:                 }
440:                 max_captures_for_routes = captures_for_routes if max_captures_for_routes < captures_for_routes
441:               end
442:             else
443:               raise Capcode::ParameterError, "Bad route declaration !", caller
444:             end
445:           end
446:           [hash_of_routes, max_captures_for_routes, self]
447:         }
448:                 
449:         # Hash containing all the request parameters (GET or POST)
450:         def params
451:           @request.params
452:         end
453:         
454:         # Hash containing all the environment variables
455:         def env
456:           @env
457:         end
458:         
459:         # Session hash
460:         def session
461:           @env['rack.session']
462:         end
463:         
464:         # Return the Rack::Request object
465:         def request
466:           @request
467:         end
468:         
469:         # Return the Rack::Response object
470:         def response
471:           @response
472:         end
473:         
474:         def call( e ) #:nodoc:
475:           @env = e
476:           @response = Rack::Response.new
477:           @request = Rack::Request.new(@env)
478: 
479:           # Check authz
480:           authz_options = nil
481:           if Capcode.__auth__ and Capcode.__auth__.size > 0
482:             authz_options = Capcode.__auth__[@request.path]||nil
483:             if authz_options.nil?
484:               route = nil
485:               
486:               Capcode.__auth__.each do |r, o|
487:                 regexp = "^#{r.gsub(/\/$/, "")}([/]{1}.*)?$"
488:                 if Regexp.new(regexp).match( @request.path )
489:                   if route.nil? or r.size > route.size
490:                     route = r
491:                     authz_options = o
492:                   end
493:                 end  
494:               end
495:             end
496:           end
497: 
498:           r = catch(:halt) { 
499:             unless authz_options.nil?
500:               http_authentication( :type => authz_options[:type], :realm => authz_options[:realm], :opaque => authz_options[:realm] ) { 
501:                 authz_options[:autz]
502:               }
503:             end
504: 
505:             max_match_size = self.class.__urls__[1]
506:             match_distance = self.class.__urls__[1]
507: 
508:             result_route = nil
509:             result_nargs = nil
510:             result_args = []
511: 
512:             self.class.__urls__[0].each do |route, data|
513:               regexp = Regexp.new("^"+data[:route]+"$")
514: 
515:               matching = regexp.match(@request.path)
516:               next if matching.nil?
517: 
518:               result_args = matching.to_a
519:               result_args.shift
520:               match_size = matching.size - 1
521: 
522:               if match_size == max_match_size
523:                 # OK Terminé
524:                 result_route = data[:route]
525:                 result_nargs = data[:nargs]
526: 
527:                 break
528:               elsif max_match_size > match_size and match_distance > max_match_size - match_size
529:                 match_distance = max_match_size - match_size
530: 
531:                 result_route = data[:route]
532:                 result_nargs = data[:nargs]
533:               end
534:             end
535:             
536:             return [404, {'Content-Type' => 'text/plain'}, "Not Found: #{@request.path}"] if result_route.nil?
537: 
538:             result_args = result_args + Array.new(max_match_size - result_nargs)
539: 
540:             filter_output = Capcode::Filter.execute( self )
541: 
542:             if( filter_output.nil? )
543:               # case @env["REQUEST_METHOD"]
544:               #   when "GET"                      
545:               #     get( *args )
546:               #   when "POST"
547:               #     _method = params.delete( "_method" ) { |_| "post" }
548:               #     send( _method.downcase.to_sym, *args )
549:               #   else
550:               #     _method = @env["REQUEST_METHOD"]
551:               #     send( _method.downcase.to_sym, *args )
552:               # end
553:               begin
554:                 _method = params.delete( "_method" ) { |_| @env["REQUEST_METHOD"] }
555:                 if self.class.method_defined?( _method.downcase.to_sym )
556:                   # send( _method.downcase.to_sym, *args )
557:                   send( _method.downcase.to_sym, *result_args )
558:                 else
559:                   # any( *args )
560:                   any( *result_args )
561:                 end
562:               rescue => e
563:                 raise e.class, e.to_s
564:               end
565:             else
566:               filter_output
567:             end
568:           }
569:           
570:           if r.respond_to?(:to_ary)
571:             @response.status = r.shift #r[0]
572:             #r[1].each do |k,v|
573:             r.shift.each do |k,v|
574:               @response[k] = v
575:             end
576:             @response.write r.shift #r[2]
577:           else
578:             @response.write r
579:           end
580:           
581:           @response.finish
582:         end
583:                 
584:         include Capcode::Helpers
585:         include Capcode::Views        
586:       }      
587:     end

Return the Rack App.

Options : see Capcode::Configuration.set

Options set here replace the ones set globally

[Source]

     # File lib/capcode.rb, line 656
656:     def application( args = {} )
657:       Capcode::Configuration.configuration(args)
658:       Capcode::Configuration.print_debug if Capcode::Configuration.get(:verbose)
659:       
660:       Capcode.constants.clone.delete_if {|k| 
661:         not( Capcode.const_get(k).to_s =~ /Capcode/ ) or [
662:           "Filter", 
663:           "Helpers", 
664:           "RouteError", 
665:           "Views", 
666:           "ParameterError", 
667:           "HTTPError", 
668:           "StaticFiles",
669:           "Configuration", 
670:           "MissingLibrary", 
671:           "Route", 
672:           "RenderError"
673:         ].include?(k)
674:       }.each do |k|
675:         begin
676:           if eval "Capcode::#{k}.public_methods(true).include?( '__urls__' )"
677:             hash_of_routes, max_captures_for_routes, klass = eval "Capcode::#{k}.__urls__"            
678:             hash_of_routes.keys.each do |current_route_path|
679:               raise Capcode::RouteError, "Route `#{current_route_path}' already define !", caller if Capcode.routes.keys.include?(current_route_path)
680:               Capcode.routes[current_route_path] = klass
681:             end
682:           end
683:         rescue => e
684:           raise e.message
685:         end
686:       end
687:       
688:       # Set Static directory
689:       Capcode.static = (Capcode::Configuration.get(:static)[0].chr == "/")?Capcode::Configuration.get(:static):"/"+Capcode::Configuration.get(:static) unless Capcode::Configuration.get(:static).nil?
690:       
691:       # Initialize Rack App
692:       puts "** Map routes." if Capcode::Configuration.get(:verbose)
693: #      app = Rack::URLMap.new(Capcode.routes)
694:       app = Capcode::Ext::Rack::URLMap.new(Capcode.routes)
695:       puts "** Initialize static directory (#{Capcode.static}) in #{File.expand_path(Capcode::Configuration.get(:root))}" if Capcode::Configuration.get(:verbose)
696:       app = Rack::Static.new( 
697:         app, 
698:         #:urls => [@@__STATIC_DIR], 
699:         :urls => [Capcode.static], 
700:         :root => File.expand_path(Capcode::Configuration.get(:root)) 
701:       ) unless Capcode::Configuration.get(:static).nil?
702:       puts "** Initialize session" if Capcode::Configuration.get(:verbose)
703:       app = Rack::Session::Cookie.new( app, Capcode::Configuration.get(:session) )
704:       app = Capcode::StaticFiles.new(app)
705:       app = Capcode::HTTPError.new(app)
706:       app = Rack::ContentLength.new(app)
707:       app = Rack::Lint.new(app)
708:       app = Rack::ShowExceptions.new(app)
709:       #app = Rack::Reloader.new(app) ## -- NE RELOAD QUE capcode.rb -- So !!!
710:       app = Rack::CommonLogger.new( app, @cclogger = Logger.new(Capcode::Configuration.get(:log)) )
711:       
712:       middlewares.each do |mw|
713:         middleware, args, block = mw
714:         puts "** Load middleware #{middleware}" if Capcode::Configuration.get(:verbose)
715:         if block
716:           app = middleware.new( app, *args, &block )
717:         else
718:           app = middleware.new( app, *args )
719:         end
720:       end
721:       
722:       # Start database
723:       if self.methods.include? "db_connect"
724:         db_connect( Capcode::Configuration.get(:db_config), Capcode::Configuration.get(:log) )
725:       end
726:       
727:       if block_given?
728:         puts "** Execute block" if Capcode::Configuration.get(:verbose)
729:         yield( self )
730:       end
731:       
732:       return app
733:     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:       Capcode::Filter.ordered_actions << action
17:       
18:       opts.each do |k, v|
19:         Capcode::Filter.filters[action][k] = v
20:       end
21:     end

Hash containing all the environment variables

[Source]

     # File lib/capcode.rb, line 455
455:         def env
456:           @env
457:         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 630
630:     def http_authentication( opts = {}, &b )
631:       options = {
632:         :type => :basic,
633:         :realm => "Capcode.app",
634:         :opaque => "opaque",
635:         :routes => "/"
636:       }.merge( opts )
637:       
638:       options[:autz] = b.call()
639:       
640:       @__auth__ ||= {}
641:       
642:       if options[:routes].class == Array
643:         options[:routes].each do |r|
644:           @__auth__[r] = options
645:         end
646:       else
647:         @__auth__[options[:routes]] = options
648:       end      
649:     end

[Source]

     # File lib/capcode.rb, line 884
884:     def logger
885:       @cclogger
886:     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 595
595:     def map( route, &b )
596:       Capcode.routes[route] = yield
597:     end

Hash containing all the request parameters (GET or POST)

[Source]

     # File lib/capcode.rb, line 450
450:         def params
451:           @request.params
452:         end

Return the Rack::Request object

[Source]

     # File lib/capcode.rb, line 465
465:         def request
466:           @request
467:         end

Return the Rack::Response object

[Source]

     # File lib/capcode.rb, line 470
470:         def response
471:           @response
472:         end

Start your application.

Options : see Capcode::Configuration.set

Options set here replace the ones set globally

[Source]

     # File lib/capcode.rb, line 740
740:     def run( args = {} )
741:       Capcode::Configuration.configuration(args)
742:       
743:       # Parse options
744:       opts = OptionParser.new do |opts|
745:         opts.banner = "Usage: #{File.basename($0)} [options]"
746:         opts.separator ""
747:         opts.separator "Specific options:"
748: 
749:         opts.on( "-C", "--console", "Run in console mode with IRB (default: false)" ) { 
750:           Capcode::Configuration.set :console, true
751:         }
752:         opts.on( "-h", "--host HOSTNAME", "Host for web server to bind to (default: #{Capcode::Configuration.get(:host)})" ) { |h|
753:           Capcode::Configuration.set :host, h
754:         }
755:         opts.on( "-p", "--port NUM", "Port for web server (default: #{Capcode::Configuration.get(:port)})" ) { |p|
756:           Capcode::Configuration.set :port, p
757:         }
758:         opts.on( "-d", "--daemonize [true|false]", "Daemonize (default: #{Capcode::Configuration.get(:daemonize)})" ) { |d|
759:           Capcode::Configuration.set :daemonize, d
760:         }
761:         opts.on( "-r", "--root PATH", "Working directory (default: #{Capcode::Configuration.get(:root)})" ) { |w|
762:           Capcode::Configuration.set :root, w
763:         }
764:         opts.on( "-s", "--static PATH", "Static directory -- relative to the root directory (default: #{Capcode::Configuration.get(:static)})" ) { |r|
765:           Capcode::Configuration.set :static, r
766:         }
767:         opts.on( "-S", "--server SERVER", "Server to use (default: #{Capcode::Configuration.get(:server)})" ) { |r|
768:           Capcode::Configuration.set :server, r
769:         }
770: 
771:         opts.separator ""
772:         opts.separator "Common options:"
773: 
774:         opts.on("-?", "--help", "Show this message") do
775:           puts opts
776:           exit
777:         end  
778:         opts.on("-v", "--version", "Show versions") do
779:           puts "Capcode version #{Capcode::CAPCOD_VERION} (ruby v#{RUBY_VERSION})"
780:           exit
781:         end  
782:         opts.on_tail( "-V", "--verbose", "Run in verbose mode" ) do
783:           Capcode::Configuration.set :verbose, true
784:         end
785:       end
786:       
787:       begin
788:         opts.parse! ARGV
789:       rescue OptionParser::ParseError => ex
790:         puts "!! #{ex.message}"
791:         puts "** use `#{File.basename($0)} --help` for more details..."
792:         exit 1
793:       end
794:       
795:       # Run in the Working directory
796:       puts "** Go on root directory (#{File.expand_path(Capcode::Configuration.get(:root))})" if Capcode::Configuration.get(:verbose)
797:       Dir.chdir( Capcode::Configuration.get(:root) ) do
798:         
799:         # Check that mongrel exists 
800:         if Capcode::Configuration.get(:server).nil? || Capcode::Configuration.get(:server) == "mongrel"
801:           begin
802:             require 'mongrel'
803:             Capcode::Configuration.set :server, :mongrel
804:           rescue LoadError 
805:             puts "!! could not load mongrel. Falling back to webrick."
806:             Capcode::Configuration.set :server, :webrick
807:           end
808:         end
809:         
810:         # From rackup !!!
811:         if Capcode::Configuration.get(:daemonize)
812:           if /java/.match(RUBY_PLATFORM).nil?
813:             if RUBY_VERSION < "1.9"
814:               exit if fork
815:               Process.setsid
816:               exit if fork
817:               # Dir.chdir "/"
818:               File.umask 0000
819:               STDIN.reopen "/dev/null"
820:               STDOUT.reopen "/dev/null", "a"
821:               STDERR.reopen "/dev/null", "a"
822:             else
823:               Process.daemon
824:             end
825:           else
826:             puts "!! daemonize option unavailable on #{RUBY_PLATFORM} platform."
827:           end
828:         
829:           File.open(Capcode::Configuration.get(:pid), 'w'){ |f| f.write("#{Process.pid}") }
830:           at_exit { File.delete(Capcode::Configuration.get(:pid)) if File.exist?(Capcode::Configuration.get(:pid)) }
831:         end
832:         
833:         app = nil
834:         if block_given?
835:           app = application(Capcode::Configuration.get) { yield( self ) }
836:         else
837:           app = application(Capcode::Configuration.get)
838:         end
839:         
840:         if Capcode::Configuration.get(:console)
841:           puts "Run console..."
842:           IRB.start
843:           exit
844:         end
845:         
846:         # Start server
847:         case Capcode::Configuration.get(:server).to_s
848:         when "mongrel"
849:           puts "** Starting Mongrel on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
850:           Rack::Handler::Mongrel.run( app, {:Port => Capcode::Configuration.get(:port), :Host => Capcode::Configuration.get(:host)} ) { |server|
851:             trap "SIGINT", proc { server.stop }
852:           }
853:         when "webrick"
854:           puts "** Starting WEBrick on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
855:           Rack::Handler::WEBrick.run( app, {:Port => Capcode::Configuration.get(:port), :BindAddress => Capcode::Configuration.get(:host)} ) { |server|
856:             trap "SIGINT", proc { server.shutdown }
857:           }
858:         when "thin"
859:           puts "** Starting Thin on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
860:           Rack::Handler::Thin.run( app, {:Port => Capcode::Configuration.get(:port), :Host => Capcode::Configuration.get(:host)} ) { |server|
861:             trap "SIGINT", proc { server.stop }
862:           }
863:         when "unicorn"
864:           require 'unicorn/launcher'
865:           puts "** Starting Unicorn on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
866:           Unicorn.run( app, {:listeners => ["#{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"]} )
867:         when "rainbows"
868:           require 'unicorn/launcher'
869:           require 'rainbows'
870:           puts "** Starting Rainbow on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
871:           Rainbows.run( app, {:listeners => ["#{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"]} )
872:         when "control_tower"
873:           require 'control_tower'
874:           puts "** Starting ControlTower on #{Capcode::Configuration.get(:host)}:#{Capcode::Configuration.get(:port)}"
875:           ControlTower::Server.new( app, {:host => Capcode::Configuration.get(:host), :port => Capcode::Configuration.get(:port)} ).start
876:         end
877:       end
878:     end

Session hash

[Source]

     # File lib/capcode.rb, line 460
460:         def session
461:           @env['rack.session']
462:         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 609
609:     def use(middleware, *args, &block)
610:       middlewares << [middleware, args, block]
611:     end

[Validate]