Because this helper was trully inspired by this post : www.gittr.com/index.php/archive/sinatra-basic-authentication-selectively-applied/ and because the code in this post was extracted out of Wink, this file follow the Wink license :
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
| __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 284
284: def Route *routes_paths
285: Class.new {
286: meta_def(:__urls__) {
287: # < Route '/hello/world/([^\/]*)/id(\d*)', '/hello/(.*)', :agent => /Songbird (\d\.\d)[\d\/]*?/
288: # # => [ {'/hello/world' => '([^\/]*)/id(\d*)', '/hello' => '(.*)'},
289: # 2,
290: # <Capcode::Klass>,
291: # {:agent => /Songbird (\d\.\d)[\d\/]*?/} ]
292: hash_of_routes = {}
293: max_captures_for_routes = 0
294: routes_paths.each do |current_route_path|
295: if current_route_path.class == String
296: m = /\/([^\/]*\(.*)/.match( current_route_path )
297: if m.nil?
298: 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)
299: hash_of_routes[current_route_path] = ''
300: else
301: _pre = m.pre_match
302: _pre = "/" if _pre.size == 0
303: raise Capcode::RouteError, "Route `#{_pre}' already defined with regexp `#{hash_of_routes[_pre]}' !", caller if hash_of_routes.keys.include?(_pre)
304: hash_of_routes[_pre] = m.captures[0]
305: 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
306: end
307: else
308: raise Capcode::ParameterError, "Bad route declaration !", caller
309: end
310: end
311: [hash_of_routes, max_captures_for_routes, self]
312: }
313:
314: # Hash containing all the request parameters (GET or POST)
315: def params
316: @request.params
317: end
318:
319: # Hash containing all the environment variables
320: def env
321: @env
322: end
323:
324: # Session hash
325: def session
326: @env['rack.session']
327: end
328:
329: # Return the Rack::Request object
330: def request
331: @request
332: end
333:
334: # Return the Rack::Response object
335: def response
336: @response
337: end
338:
339: def call( e ) #:nodoc:
340: @env = e
341: @response = Rack::Response.new
342: @request = Rack::Request.new(@env)
343:
344: # __k = self.class.to_s.split( /::/ )[-1].downcase.to_sym
345: # @@__FILTERS.each do |f|
346: # proc = f.delete(:action)
347: # __run = true
348: # if f[:only]
349: # __run = f[:only].include?(__k)
350: # end
351: # if f[:except]
352: # __run = !f[:except].include?(__k)
353: # end
354: #
355: # # proc.call(self) if __run
356: # puts "call #{proc} for #{__k}"
357: # end
358:
359: # Check authz
360: authz_options = nil
361: if Capcode.__auth__ and Capcode.__auth__.size > 0
362: authz_options = Capcode.__auth__[@request.path]||nil
363: if authz_options.nil?
364: route = nil
365:
366: Capcode.__auth__.each do |r, o|
367: regexp = "^#{r.gsub(/\/$/, "")}([/]{1}.*)?$"
368: if Regexp.new(regexp).match( @request.path )
369: if route.nil? or r.size > route.size
370: route = r
371: authz_options = o
372: end
373: end
374: end
375: end
376: end
377:
378: r = catch(:halt) {
379: unless authz_options.nil?
380: http_authentication( :type => authz_options[:type], :realm => authz_options[:realm], :opaque => authz_options[:realm] ) {
381: authz_options[:autz]
382: }
383: end
384:
385: case @env["REQUEST_METHOD"]
386: when "GET"
387: finalPath = nil
388: finalArgs = nil
389: finalNArgs = nil
390:
391: aPath = @request.path.gsub( /^\//, "" ).split( "/" )
392: self.class.__urls__[0].each do |p, r|
393: xPath = p.gsub( /^\//, "" ).split( "/" )
394: if (xPath - aPath).size == 0
395: diffArgs = aPath - xPath
396: diffNArgs = diffArgs.size
397: if finalNArgs.nil? or finalNArgs > diffNArgs
398: finalPath = p
399: finalNArgs = diffNArgs
400: finalArgs = diffArgs
401: end
402: end
403:
404: end
405:
406: nargs = self.class.__urls__[1]
407: regexp = Regexp.new( self.class.__urls__[0][finalPath] )
408: args = regexp.match( Rack::Utils.unescape(@request.path).gsub( Regexp.new( "^#{finalPath}" ), "" ).gsub( /^\//, "" ) )
409: if args.nil?
410: raise Capcode::ParameterError, "Path info `#{@request.path_info}' does not match route regexp `#{regexp.source}'"
411: else
412: args = args.captures.map { |x| (x.size == 0)?nil:x }
413: end
414:
415: while args.size < nargs
416: args << nil
417: end
418:
419: get( *args )
420: when "POST"
421: _method = params.delete( "_method" ) { |_| "post" }
422: send( _method.downcase.to_sym )
423: else
424: _method = @env["REQUEST_METHOD"]
425: send( _method.downcase.to_sym )
426: end
427: }
428: if r.respond_to?(:to_ary)
429: @response.status = r.shift #r[0]
430: #r[1].each do |k,v|
431: r.shift.each do |k,v|
432: @response[k] = v
433: end
434: @response.body = r.shift #r[2]
435: else
436: @response.write r
437: end
438:
439: @response.finish
440: end
441:
442: include Capcode::Helpers
443: include Capcode::Views
444: }
445: end
Return the Rack App.
Options : same has Capcode.run
# File lib/capcode.rb, line 512
512: def application( args = {} )
513: conf = configuration(args)
514:
515: Capcode.constants.each do |k|
516: begin
517: if eval "Capcode::#{k}.public_methods(true).include?( '__urls__' )"
518: hash_of_routes, max_captures_for_routes, klass = eval "Capcode::#{k}.__urls__"
519: hash_of_routes.keys.each do |current_route_path|
520: raise Capcode::RouteError, "Route `#{current_route_path}' already define !", caller if @@__ROUTES.keys.include?(current_route_path)
521: @@__ROUTES[current_route_path] = klass.new
522: end
523: end
524: rescue => e
525: raise e.message
526: end
527: end
528:
529: # Set Static directory
530: @@__STATIC_DIR = (conf[:static][0].chr == "/")?conf[:static]:"/"+conf[:static] unless conf[:static].nil?
531:
532: # Initialize Rack App
533: puts "** Map routes." if conf[:verbose]
534: app = Rack::URLMap.new(@@__ROUTES)
535: puts "** Initialize static directory (#{conf[:static]})" if conf[:verbose]
536: app = Rack::Static.new(
537: app,
538: :urls => [@@__STATIC_DIR],
539: :root => File.expand_path(conf[:root])
540: ) unless conf[:static].nil?
541: puts "** Initialize session" if conf[:verbose]
542: app = Rack::Session::Cookie.new( app, conf[:session] )
543: app = Capcode::HTTPError.new(app)
544: app = Rack::ContentLength.new(app)
545: app = Rack::Lint.new(app)
546: app = Rack::ShowExceptions.new(app)
547: #app = Rack::Reloader.new(app) ## -- NE RELOAD QUE capcode.rb -- So !!!
548: # app = Rack::CommonLogger.new( app, Logger.new(conf[:log]) )
549:
550: # Start database
551: if self.methods.include? "db_connect"
552: db_connect( conf[:db_config], conf[:log] )
553: end
554:
555: if block_given?
556: yield( self )
557: end
558:
559: return app
560: end
Hash containing all the environment variables
# File lib/capcode.rb, line 320
320: def env
321: @env
322: 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 470
470: def http_authentication( opts = {}, &b )
471: options = {
472: :type => :basic,
473: :realm => "Capcode.app",
474: :opaque => "opaque",
475: :routes => "/"
476: }.merge( opts )
477:
478: options[:autz] = b.call()
479:
480: @__auth__ ||= {}
481:
482: if options[:routes].class == Array
483: options[:routes].each do |r|
484: @__auth__[r] = options
485: end
486: else
487: @__auth__[options[:routes]] = options
488: end
489: end
Return the Rack::Request object
# File lib/capcode.rb, line 330
330: def request
331: @request
332: end
Return the Rack::Response object
# File lib/capcode.rb, line 335
335: def response
336: @response
337: end
Start your application.
Options :
# File lib/capcode.rb, line 577
577: def run( args = {} )
578: conf = configuration(args)
579:
580: # Parse options
581: opts = OptionParser.new do |opts|
582: opts.banner = "Usage: #{File.basename($0)} [options]"
583: opts.separator ""
584: opts.separator "Specific options:"
585:
586: opts.on( "-C", "--console", "Run in console mode with IRB (default: false)" ) {
587: conf[:console] = true
588: }
589: opts.on( "-h", "--host HOSTNAME", "Host for web server to bind to (default: #{conf[:host]})" ) { |h|
590: conf[:host] = h
591: }
592: opts.on( "-p", "--port NUM", "Port for web server (default: #{conf[:port]})" ) { |p|
593: conf[:port] = p
594: }
595: opts.on( "-d", "--daemonize [true|false]", "Daemonize (default: #{conf[:daemonize]})" ) { |d|
596: conf[:daemonize] = d
597: }
598: opts.on( "-r", "--root PATH", "Working directory (default: #{conf[:root]})" ) { |w|
599: conf[:root] = w
600: }
601: opts.on( "-s", "--static PATH", "Static directory -- relative to the root directory (default: #{conf[:static]})" ) { |r|
602: conf[:static] = r
603: }
604:
605: opts.separator ""
606: opts.separator "Common options:"
607:
608: opts.on("-?", "--help", "Show this message") do
609: puts opts
610: exit
611: end
612: opts.on("-v", "--version", "Show versions") do
613: puts "Capcode version #{Capcode::CAPCOD_VERION} (ruby v#{RUBY_VERSION})"
614: exit
615: end
616: opts.on_tail( "-V", "--verbose", "Run in verbose mode" ) do
617: conf[:verbose] = true
618: end
619: end
620:
621: begin
622: opts.parse! ARGV
623: rescue OptionParser::ParseError => ex
624: puts "!! #{ex.message}"
625: puts "** use `#{File.basename($0)} --help` for more details..."
626: exit 1
627: end
628:
629: # Run in the Working directory
630: puts "** Go on root directory (#{File.expand_path(conf[:root])})" if conf[:verbose]
631: Dir.chdir( conf[:root] ) do
632:
633: # Check that mongrel exists
634: if conf[:server].nil? || conf[:server] == "mongrel"
635: begin
636: require 'mongrel'
637: conf[:server] = "mongrel"
638: rescue LoadError
639: puts "!! could not load mongrel. Falling back to webrick."
640: conf[:server] = "webrick"
641: end
642: end
643:
644: # From rackup !!!
645: if conf[:daemonize]
646: if /java/.match(RUBY_PLATFORM).nil?
647: if RUBY_VERSION < "1.9"
648: exit if fork
649: Process.setsid
650: exit if fork
651: # Dir.chdir "/"
652: File.umask 0000
653: STDIN.reopen "/dev/null"
654: STDOUT.reopen "/dev/null", "a"
655: STDERR.reopen "/dev/null", "a"
656: else
657: Process.daemon
658: end
659: else
660: puts "!! daemonize option unavailable on #{RUBY_PLATFORM} platform."
661: end
662:
663: File.open(conf[:pid], 'w'){ |f| f.write("#{Process.pid}") }
664: at_exit { File.delete(conf[:pid]) if File.exist?(conf[:pid]) }
665: end
666:
667: app = nil
668: if block_given?
669: app = application(conf) { yield( self ) }
670: else
671: app = application(conf)
672: end
673: app = Rack::CommonLogger.new( app, Logger.new(conf[:log]) )
674:
675: if conf[:console]
676: puts "Run console..."
677: IRB.start
678: exit
679: end
680:
681: # Start server
682: case conf[:server]
683: when "mongrel"
684: puts "** Starting Mongrel on #{conf[:host]}:#{conf[:port]}"
685: Rack::Handler::Mongrel.run( app, {:Port => conf[:port], :Host => conf[:host]} ) { |server|
686: trap "SIGINT", proc { server.stop }
687: }
688: when "webrick"
689: puts "** Starting WEBrick on #{conf[:host]}:#{conf[:port]}"
690: Rack::Handler::WEBrick.run( app, {:Port => conf[:port], :BindAddress => conf[:host]} ) { |server|
691: trap "SIGINT", proc { server.shutdown }
692: }
693: end
694: end
695: end