| __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