| __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 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
# 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
Hash containing all the environment variables
# 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 :
The block must return a Hash of username => password like that :
{
"user1" => "pass1",
"user2" => "pass2",
# ...
}
# 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
Return the Rack::Request object
# File lib/capcode.rb, line 351
351: def request
352: @request
353: end
Return the Rack::Response object
# 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
# 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
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 488
488: def use(middleware, *args, &block)
489: middlewares << [middleware, args, block]
490: end