__auth__ | [RW] |
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 302 302: def Route *routes_paths 303: Class.new { 304: meta_def(:__urls__) { 305: # < Route '/hello/world/([^\/]*)/id(\d*)', '/hello/(.*)', :agent => /Songbird (\d\.\d)[\d\/]*?/ 306: # # => [ {'/hello/world' => '([^\/]*)/id(\d*)', '/hello' => '(.*)'}, 307: # 2, 308: # <Capcode::Klass>, 309: # {:agent => /Songbird (\d\.\d)[\d\/]*?/} ] 310: hash_of_routes = {} 311: max_captures_for_routes = 0 312: routes_paths.each do |current_route_path| 313: if current_route_path.class == String 314: m = /\/([^\/]*\(.*)/.match( current_route_path ) 315: if m.nil? 316: 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) 317: hash_of_routes[current_route_path] = '' 318: else 319: _pre = m.pre_match 320: _pre = "/" if _pre.size == 0 321: raise Capcode::RouteError, "Route `#{_pre}' already defined with regexp `#{hash_of_routes[_pre]}' !", caller if hash_of_routes.keys.include?(_pre) 322: hash_of_routes[_pre] = m.captures[0] 323: 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 324: end 325: else 326: raise Capcode::ParameterError, "Bad route declaration !", caller 327: end 328: end 329: [hash_of_routes, max_captures_for_routes, self] 330: } 331: 332: # Hash containing all the request parameters (GET or POST) 333: def params 334: @request.params 335: end 336: 337: # Hash containing all the environment variables 338: def env 339: @env 340: end 341: 342: # Session hash 343: def session 344: @env['rack.session'] 345: end 346: 347: # Return the Rack::Request object 348: def request 349: @request 350: end 351: 352: # Return the Rack::Response object 353: def response 354: @response 355: end 356: 357: def call( e ) #:nodoc: 358: @env = e 359: @response = Rack::Response.new 360: @request = Rack::Request.new(@env) 361: 362: # __k = self.class.to_s.split( /::/ )[-1].downcase.to_sym 363: # @@__FILTERS.each do |f| 364: # proc = f.delete(:action) 365: # __run = true 366: # if f[:only] 367: # __run = f[:only].include?(__k) 368: # end 369: # if f[:except] 370: # __run = !f[:except].include?(__k) 371: # end 372: # 373: # # proc.call(self) if __run 374: # puts "call #{proc} for #{__k}" 375: # end 376: 377: # Check authz 378: authz_options = nil 379: if Capcode.__auth__ and Capcode.__auth__.size > 0 380: authz_options = Capcode.__auth__[@request.path]||nil 381: if authz_options.nil? 382: route = nil 383: 384: Capcode.__auth__.each do |r, o| 385: regexp = "^#{r.gsub(/\/$/, "")}([/]{1}.*)?$" 386: if Regexp.new(regexp).match( @request.path ) 387: if route.nil? or r.size > route.size 388: route = r 389: authz_options = o 390: end 391: end 392: end 393: end 394: end 395: 396: r = catch(:halt) { 397: unless authz_options.nil? 398: http_authentication( :type => authz_options[:type], :realm => authz_options[:realm], :opaque => authz_options[:realm] ) { 399: authz_options[:autz] 400: } 401: end 402: 403: finalPath = nil 404: finalArgs = nil 405: finalNArgs = nil 406: 407: aPath = @request.path.gsub( /^\//, "" ).split( "/" ) 408: self.class.__urls__[0].each do |p, r| 409: xPath = p.gsub( /^\//, "" ).split( "/" ) 410: if (xPath - aPath).size == 0 411: diffArgs = aPath - xPath 412: diffNArgs = diffArgs.size 413: if finalNArgs.nil? or finalNArgs > diffNArgs 414: finalPath = p 415: finalNArgs = diffNArgs 416: finalArgs = diffArgs 417: end 418: end 419: 420: end 421: 422: nargs = self.class.__urls__[1] 423: regexp = Regexp.new( self.class.__urls__[0][finalPath] ) 424: args = regexp.match( Rack::Utils.unescape(@request.path).gsub( Regexp.new( "^#{finalPath}" ), "" ).gsub( /^\//, "" ) ) 425: if args.nil? 426: raise Capcode::ParameterError, "Path info `#{@request.path_info}' does not match route regexp `#{regexp.source}'" 427: else 428: args = args.captures.map { |x| (x.size == 0)?nil:x } 429: end 430: 431: while args.size < nargs 432: args << nil 433: end 434: 435: case @env["REQUEST_METHOD"] 436: when "GET" 437: get( *args ) 438: when "POST" 439: _method = params.delete( "_method" ) { |_| "post" } 440: send( _method.downcase.to_sym, *args ) 441: else 442: _method = @env["REQUEST_METHOD"] 443: send( _method.downcase.to_sym, *args ) 444: end 445: } 446: if r.respond_to?(:to_ary) 447: @response.status = r.shift #r[0] 448: #r[1].each do |k,v| 449: r.shift.each do |k,v| 450: @response[k] = v 451: end 452: @response.body = r.shift #r[2] 453: else 454: @response.write r 455: end 456: 457: @response.finish 458: end 459: 460: include Capcode::Helpers 461: include Capcode::Views 462: } 463: end
Return the Rack App.
Options : see Capcode.set
Options set here replace the ones set globally
# File lib/capcode.rb, line 549 549: def application( args = {} ) 550: conf = configuration(args) 551: 552: Capcode.constants.each do |k| 553: begin 554: if eval "Capcode::#{k}.public_methods(true).include?( '__urls__' )" 555: hash_of_routes, max_captures_for_routes, klass = eval "Capcode::#{k}.__urls__" 556: hash_of_routes.keys.each do |current_route_path| 557: #raise Capcode::RouteError, "Route `#{current_route_path}' already define !", caller if @@__ROUTES.keys.include?(current_route_path) 558: raise Capcode::RouteError, "Route `#{current_route_path}' already define !", caller if Capcode.routes.keys.include?(current_route_path) 559: #@@__ROUTES[current_route_path] = klass.new 560: Capcode.routes[current_route_path] = klass.new 561: end 562: end 563: rescue => e 564: raise e.message 565: end 566: end 567: 568: # Set Static directory 569: #@@__STATIC_DIR = (conf[:static][0].chr == "/")?conf[:static]:"/"+conf[:static] unless conf[:static].nil? 570: Capcode.static = (conf[:static][0].chr == "/")?conf[:static]:"/"+conf[:static] unless conf[:static].nil? 571: 572: # Initialize Rack App 573: puts "** Map routes." if conf[:verbose] 574: #app = Rack::URLMap.new(@@__ROUTES) 575: app = Rack::URLMap.new(Capcode.routes) 576: puts "** Initialize static directory (#{conf[:static]})" if conf[:verbose] 577: app = Rack::Static.new( 578: app, 579: #:urls => [@@__STATIC_DIR], 580: :urls => [Capcode.static], 581: :root => File.expand_path(conf[:root]) 582: ) unless conf[:static].nil? 583: puts "** Initialize session" if conf[:verbose] 584: app = Rack::Session::Cookie.new( app, conf[:session] ) 585: app = Capcode::HTTPError.new(app) 586: app = Rack::ContentLength.new(app) 587: app = Rack::Lint.new(app) 588: app = Rack::ShowExceptions.new(app) 589: #app = Rack::Reloader.new(app) ## -- NE RELOAD QUE capcode.rb -- So !!! 590: # app = Rack::CommonLogger.new( app, Logger.new(conf[:log]) ) 591: 592: middlewares.each do |mw| 593: middleware, args, block = mw 594: puts "** Load middleware #{middleware}" if conf[:verbose] 595: if block 596: app = middleware.new( app, *args, &block ) 597: else 598: app = middleware.new( app, *args ) 599: end 600: end 601: 602: # Start database 603: if self.methods.include? "db_connect" 604: db_connect( conf[:db_config], conf[:log] ) 605: end 606: 607: if block_given? 608: yield( self ) 609: end 610: 611: return app 612: end
Hash containing all the environment variables
# File lib/capcode.rb, line 338 338: def env 339: @env 340: end
Allow you to add and HTTP Authentication (Basic or Digest) to controllers for or specific route
Options :
The block must return a Hash of username => password like that :
{ "user1" => "pass1", "user2" => "pass2", # ... }
# File lib/capcode.rb, line 506 506: def http_authentication( opts = {}, &b ) 507: options = { 508: :type => :basic, 509: :realm => "Capcode.app", 510: :opaque => "opaque", 511: :routes => "/" 512: }.merge( opts ) 513: 514: options[:autz] = b.call() 515: 516: @__auth__ ||= {} 517: 518: if options[:routes].class == Array 519: options[:routes].each do |r| 520: @__auth__[r] = options 521: end 522: else 523: @__auth__[options[:routes]] = options 524: end 525: end
Return the Rack::Request object
# File lib/capcode.rb, line 348 348: def request 349: @request 350: end
Return the Rack::Response object
# File lib/capcode.rb, line 353 353: def response 354: @response 355: end
Start your application.
Options : see Capcode.set
Options set here replace the ones set globally
# File lib/capcode.rb, line 619 619: def run( args = {} ) 620: conf = configuration(args) 621: 622: # Parse options 623: opts = OptionParser.new do |opts| 624: opts.banner = "Usage: #{File.basename($0)} [options]" 625: opts.separator "" 626: opts.separator "Specific options:" 627: 628: opts.on( "-C", "--console", "Run in console mode with IRB (default: false)" ) { 629: conf[:console] = true 630: } 631: opts.on( "-h", "--host HOSTNAME", "Host for web server to bind to (default: #{conf[:host]})" ) { |h| 632: conf[:host] = h 633: } 634: opts.on( "-p", "--port NUM", "Port for web server (default: #{conf[:port]})" ) { |p| 635: conf[:port] = p 636: } 637: opts.on( "-d", "--daemonize [true|false]", "Daemonize (default: #{conf[:daemonize]})" ) { |d| 638: conf[:daemonize] = d 639: } 640: opts.on( "-r", "--root PATH", "Working directory (default: #{conf[:root]})" ) { |w| 641: conf[:root] = w 642: } 643: opts.on( "-s", "--static PATH", "Static directory -- relative to the root directory (default: #{conf[:static]})" ) { |r| 644: conf[:static] = r 645: } 646: 647: opts.separator "" 648: opts.separator "Common options:" 649: 650: opts.on("-?", "--help", "Show this message") do 651: puts opts 652: exit 653: end 654: opts.on("-v", "--version", "Show versions") do 655: puts "Capcode version #{Capcode::CAPCOD_VERION} (ruby v#{RUBY_VERSION})" 656: exit 657: end 658: opts.on_tail( "-V", "--verbose", "Run in verbose mode" ) do 659: conf[:verbose] = true 660: end 661: end 662: 663: begin 664: opts.parse! ARGV 665: rescue OptionParser::ParseError => ex 666: puts "!! #{ex.message}" 667: puts "** use `#{File.basename($0)} --help` for more details..." 668: exit 1 669: end 670: 671: # Run in the Working directory 672: puts "** Go on root directory (#{File.expand_path(conf[:root])})" if conf[:verbose] 673: Dir.chdir( conf[:root] ) do 674: 675: # Check that mongrel exists 676: if conf[:server].nil? || conf[:server] == "mongrel" 677: begin 678: require 'mongrel' 679: conf[:server] = "mongrel" 680: rescue LoadError 681: puts "!! could not load mongrel. Falling back to webrick." 682: conf[:server] = "webrick" 683: end 684: end 685: 686: # From rackup !!! 687: if conf[:daemonize] 688: if /java/.match(RUBY_PLATFORM).nil? 689: if RUBY_VERSION < "1.9" 690: exit if fork 691: Process.setsid 692: exit if fork 693: # Dir.chdir "/" 694: File.umask 0000 695: STDIN.reopen "/dev/null" 696: STDOUT.reopen "/dev/null", "a" 697: STDERR.reopen "/dev/null", "a" 698: else 699: Process.daemon 700: end 701: else 702: puts "!! daemonize option unavailable on #{RUBY_PLATFORM} platform." 703: end 704: 705: File.open(conf[:pid], 'w'){ |f| f.write("#{Process.pid}") } 706: at_exit { File.delete(conf[:pid]) if File.exist?(conf[:pid]) } 707: end 708: 709: app = nil 710: if block_given? 711: app = application(conf) { yield( self ) } 712: else 713: app = application(conf) 714: end 715: app = Rack::CommonLogger.new( app, Logger.new(conf[:log]) ) 716: 717: if conf[:console] 718: puts "Run console..." 719: IRB.start 720: exit 721: end 722: 723: # Start server 724: case conf[:server] 725: when "mongrel" 726: puts "** Starting Mongrel on #{conf[:host]}:#{conf[:port]}" 727: Rack::Handler::Mongrel.run( app, {:Port => conf[:port], :Host => conf[:host]} ) { |server| 728: trap "SIGINT", proc { server.stop } 729: } 730: when "webrick" 731: puts "** Starting WEBrick on #{conf[:host]}:#{conf[:port]}" 732: Rack::Handler::WEBrick.run( app, {:Port => conf[:port], :BindAddress => conf[:host]} ) { |server| 733: trap "SIGINT", proc { server.shutdown } 734: } 735: end 736: end 737: end
Set global configuration options
Options :
It can exist specifics options depending on a renderer, a helper, …
Example :
module Capcode set :erb, "/path/to/erb/files" ... end
# 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
# File lib/capcode.rb, line 485 485: def use(middleware, *args, &block) 486: middlewares << [middleware, args, block] 487: end