Class Sinatra::Base
In: lib/sinatra/base.rb
Parent: Object
Rack::ShowExceptions ShowExceptions Base Application\n[lib/sinatra/base.rb\nlib/sinatra/main.rb] Rack::Response Response Rack::Utils NameError NotFound Rack::Request Request ::File StaticFile lib/sinatra/base.rb lib/sinatra/showexceptions.rb lib/sinatra/main.rb Templates Delegator lib/sinatra/base.rb Helpers Sinatra dot/m_3_0.png

Base class for all Sinatra applications and middleware.

Methods

Included Modules

Rack::Utils Helpers Templates

Constants

CALLERS_TO_IGNORE = [ /\/sinatra(\/(base|main|showexceptions))?\.rb$/, # all sinatra code /lib\/tilt.*\.rb$/, # all tilt code /\(.*\)/, # generated code /custom_require\.rb$/, # rubygems require hacks /active_support/, # active_support require hacks ]

External Aliases

user_agent -> agent

Attributes

after_filters  [R] 
app  [RW] 
before_filters  [R] 
env  [RW] 
errors  [R] 
params  [RW] 
request  [RW] 
response  [RW] 
routes  [R] 
templates  [R] 

Public Class methods

[Source]

     # File lib/sinatra/base.rb, line 962
962:       def call(env)
963:         synchronize { prototype.call(env) }
964:       end

Like Kernel#caller but excluding certain magic entries and without line / method information; the resulting array contains filenames only.

[Source]

      # File lib/sinatra/base.rb, line 1012
1012:       def caller_files
1013:         caller_locations.
1014:           map { |file,line| file }
1015:       end

[Source]

      # File lib/sinatra/base.rb, line 1017
1017:       def caller_locations
1018:         caller(1).
1019:           map    { |line| line.split(/:(?=\d|in )/)[0,2] }.
1020:           reject { |file,line| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
1021:       end

Set configuration options for Sinatra and/or the app. Allows scoping of settings for certain environments.

[Source]

     # File lib/sinatra/base.rb, line 912
912:       def configure(*envs, &block)
913:         yield self if envs.empty? || envs.include?(environment.to_sym)
914:       end

[Source]

     # File lib/sinatra/base.rb, line 830
830:       def delete(path, opts={}, &bk); route 'DELETE', path, opts, &bk end

[Source]

     # File lib/sinatra/base.rb, line 906
906:       def development?; environment == :development end

Defining a `GET` handler also automatically defines a `HEAD` handler.

[Source]

     # File lib/sinatra/base.rb, line 820
820:       def get(path, opts={}, &block)
821:         conditions = @conditions.dup
822:         route('GET', path, opts, &block)
823: 
824:         @conditions = conditions
825:         route('HEAD', path, opts, &block)
826:       end

[Source]

     # File lib/sinatra/base.rb, line 831
831:       def head(path, opts={}, &bk);   route 'HEAD',   path, opts, &bk end

Makes the methods defined in the block and in the Modules given in `extensions` available to the handlers and templates

[Source]

     # File lib/sinatra/base.rb, line 892
892:       def helpers(*extensions, &block)
893:         class_eval(&block)  if block_given?
894:         include(*extensions) if extensions.any?
895:       end

Create a new instance of the class fronted by its middleware pipeline. The object is guaranteed to respond to call but may not be an instance of the class new was called on.

[Source]

     # File lib/sinatra/base.rb, line 950
950:       def new(*args, &bk)
951:         builder = Rack::Builder.new
952:         builder.use Rack::Session::Cookie if sessions?
953:         builder.use Rack::CommonLogger    if logging?
954:         builder.use Rack::MethodOverride  if methodoverride?
955:         builder.use ShowExceptions        if show_exceptions?
956:         middleware.each { |c,a,b| builder.use(c, *a, &b) }
957: 
958:         builder.run super
959:         builder.to_app
960:       end

[Source]

     # File lib/sinatra/base.rb, line 372
372:     def initialize(app=nil)
373:       @app = app
374:       @template_cache = Tilt::Cache.new
375:       yield self if block_given?
376:     end

[Source]

     # File lib/sinatra/base.rb, line 829
829:       def post(path, opts={}, &bk);   route 'POST',   path, opts, &bk end

[Source]

     # File lib/sinatra/base.rb, line 907
907:       def production?;  environment == :production  end

The prototype instance used to process requests.

[Source]

     # File lib/sinatra/base.rb, line 943
943:       def prototype
944:         @prototype ||= new
945:       end

[Source]

     # File lib/sinatra/base.rb, line 828
828:       def put(path, opts={}, &bk);    route 'PUT',    path, opts, &bk end

[Source]

     # File lib/sinatra/base.rb, line 897
897:       def register(*extensions, &block)
898:         extensions << Module.new(&block) if block_given?
899:         @extensions += extensions
900:         extensions.each do |extension|
901:           extend extension
902:           extension.registered(self) if extension.respond_to?(:registered)
903:         end
904:       end

Run the Sinatra app as a self-hosted server using Thin, Mongrel or WEBrick (in that order)

[Source]

     # File lib/sinatra/base.rb, line 924
924:       def run!(options={})
925:         set options
926:         handler      = detect_rack_handler
927:         handler_name = handler.name.gsub(/.*::/, '')
928:         puts "== Sinatra/#{Sinatra::VERSION} has taken the stage " +
929:           "on #{port} for #{environment} with backup from #{handler_name}" unless handler_name =~/cgi/i
930:         handler.run self, :Host => host, :Port => port do |server|
931:           trap(:INT) do
932:             ## Use thins' hard #stop! if available, otherwise just #stop
933:             server.respond_to?(:stop!) ? server.stop! : server.stop
934:             puts "\n== Sinatra has ended his set (crowd applauds)" unless handler_name =~/cgi/i
935:           end
936:           set :running, true
937:         end
938:       rescue Errno::EADDRINUSE => e
939:         puts "== Someone is already performing on port #{port}!"
940:       end

[Source]

     # File lib/sinatra/base.rb, line 908
908:       def test?;        environment == :test        end

Use the specified Rack middleware

[Source]

     # File lib/sinatra/base.rb, line 917
917:       def use(middleware, *args, &block)
918:         @prototype = nil
919:         @middleware << [middleware, args, block]
920:       end

Private Class methods

Define an after filter; runs after all requests within the same context as route handlers and may access/modify the request and response.

[Source]

     # File lib/sinatra/base.rb, line 775
775:       def after(&block)
776:         @after_filters << block
777:       end

Define a before filter; runs before all requests within the same context as route handlers and may access/modify the request and response.

[Source]

     # File lib/sinatra/base.rb, line 768
768:       def before(&block)
769:         @before_filters << block
770:       end

[Source]

     # File lib/sinatra/base.rb, line 862
862:       def compile(path)
863:         keys = []
864:         if path.respond_to? :to_str
865:           special_chars = %w{. + ( )}
866:           pattern =
867:             path.to_str.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
868:               case match
869:               when "*"
870:                 keys << 'splat'
871:                 "(.*?)"
872:               when *special_chars
873:                 Regexp.escape(match)
874:               else
875:                 keys << $2[1..-1]
876:                 "([^/?&#]+)"
877:               end
878:             end
879:           [/^#{pattern}$/, keys]
880:         elsif path.respond_to?(:keys) && path.respond_to?(:match)
881:           [path, path.keys]
882:         elsif path.respond_to? :match
883:           [path, keys]
884:         else
885:           raise TypeError, path
886:         end
887:       end

Add a route condition. The route is considered non-matching when the block returns false.

[Source]

     # File lib/sinatra/base.rb, line 781
781:       def condition(&block)
782:         @conditions << block
783:       end

[Source]

     # File lib/sinatra/base.rb, line 967
967:       def detect_rack_handler
968:         servers = Array(self.server)
969:         servers.each do |server_name|
970:           begin
971:             return Rack::Handler.get(server_name.downcase)
972:           rescue LoadError
973:           rescue NameError
974:           end
975:         end
976:         fail "Server handler (#{servers.join(',')}) not found."
977:       end

Same as calling `set :option, false` for each of the given options.

[Source]

     # File lib/sinatra/base.rb, line 703
703:       def disable(*opts)
704:         opts.each { |key| set(key, false) }
705:       end

Same as calling `set :option, true` for each of the given options.

[Source]

     # File lib/sinatra/base.rb, line 698
698:       def enable(*opts)
699:         opts.each { |key| set(key, true) }
700:       end

Define a custom error handler. Optionally takes either an Exception class, or an HTTP status code to specify which errors should be handled.

[Source]

     # File lib/sinatra/base.rb, line 710
710:       def error(codes=Exception, &block)
711:         Array(codes).each { |code| @errors[code] = block }
712:       end

Extension modules registered on this class and all superclasses.

[Source]

     # File lib/sinatra/base.rb, line 663
663:       def extensions
664:         if superclass.respond_to?(:extensions)
665:           (@extensions + superclass.extensions).uniq
666:         else
667:           @extensions
668:         end
669:       end

[Source]

     # File lib/sinatra/base.rb, line 786
786:       def host_name(pattern)
787:         condition { pattern === request.host }
788:       end

[Source]

     # File lib/sinatra/base.rb, line 979
979:       def inherited(subclass)
980:         subclass.reset!
981:         super
982:       end

Load embeded templates from the file; uses the caller‘s FILE when no file is specified.

[Source]

     # File lib/sinatra/base.rb, line 732
732:       def inline_templates=(file=nil)
733:         file = (file.nil? || file == true) ? caller_files.first : file
734: 
735:         begin
736:           app, data =
737:             ::IO.read(file).gsub("\r\n", "\n").split(/^__END__$/, 2)
738:         rescue Errno::ENOENT
739:           app, data = nil
740:         end
741: 
742:         if data
743:           lines = app.count("\n") + 1
744:           template = nil
745:           data.each_line do |line|
746:             lines += 1
747:             if line =~ /^@@\s*(.*)/
748:               template = ''
749:               templates[$1.to_sym] = [template, file, lines]
750:             elsif template
751:               template << line
752:             end
753:           end
754:         end
755:       end

[Source]

     # File lib/sinatra/base.rb, line 858
858:       def invoke_hook(name, *args)
859:         extensions.each { |e| e.send(name, *args) if e.respond_to?(name) }
860:       end

Define the layout template. The block must return the template source.

[Source]

     # File lib/sinatra/base.rb, line 726
726:       def layout(name=:layout, &block)
727:         template name, &block
728:       end

[Source]

     # File lib/sinatra/base.rb, line 993
993:       def metadef(message, &block)
994:         (class << self; self; end).
995:           send :define_method, message, &block
996:       end

Middleware used in this class and all superclasses.

[Source]

     # File lib/sinatra/base.rb, line 672
672:       def middleware
673:         if superclass.respond_to?(:middleware)
674:           superclass.middleware + @middleware
675:         else
676:           @middleware
677:         end
678:       end

Lookup or register a mime type in Rack‘s mime registry.

[Source]

     # File lib/sinatra/base.rb, line 758
758:       def mime_type(type, value=nil)
759:         return type if type.nil? || type.to_s.include?('/')
760:         type = ".#{type}" unless type.to_s[0] == ?.
761:         return Rack::Mime.mime_type(type, nil) unless value
762:         Rack::Mime::MIME_TYPES[type] = value
763:       end

Sugar for `error(404) { … }`

[Source]

     # File lib/sinatra/base.rb, line 715
715:       def not_found(&block)
716:         error 404, &block
717:       end

[Source]

     # File lib/sinatra/base.rb, line 802
802:       def provides(*types)
803:         types = [types] unless types.kind_of? Array
804:         types.map!{|t| mime_type(t)}
805: 
806:         condition {
807:           matching_types = (request.accept & types)
808:           unless matching_types.empty?
809:             response.headers['Content-Type'] = matching_types.first
810:             true
811:           else
812:             false
813:           end
814:         }
815:       end

[Source]

     # File lib/sinatra/base.rb, line 645
645:       def reset!
646:         @conditions     = []
647:         @routes         = {}
648:         @before_filters = []
649:         @after_filters  = []
650:         @errors         = {}
651:         @middleware     = []
652:         @prototype      = nil
653:         @extensions     = []
654: 
655:         if superclass.respond_to?(:templates)
656:           @templates = Hash.new { |hash,key| superclass.templates[key] }
657:         else
658:           @templates = {}
659:         end
660:       end

[Source]

     # File lib/sinatra/base.rb, line 834
834:       def route(verb, path, options={}, &block)
835:         # Because of self.options.host
836:         host_name(options.delete(:host)) if options.key?(:host)
837: 
838:         options.each {|option, args| send(option, *args)}
839: 
840:         pattern, keys = compile(path)
841:         conditions, @conditions = @conditions, []
842: 
843:         define_method "#{verb} #{path}", &block
844:         unbound_method = instance_method("#{verb} #{path}")
845:         block =
846:           if block.arity != 0
847:             proc { unbound_method.bind(self).call(*@block_params) }
848:           else
849:             proc { unbound_method.bind(self).call }
850:           end
851: 
852:         invoke_hook(:route_added, verb, path, block)
853: 
854:         (@routes[verb] ||= []).
855:           push([pattern, keys, conditions, block]).last
856:       end

Sets an option to the given value. If the value is a proc, the proc will be called every time the option is accessed.

[Source]

     # File lib/sinatra/base.rb, line 682
682:       def set(option, value=self)
683:         if value.kind_of?(Proc)
684:           metadef(option, &value)
685:           metadef("#{option}?") { !!__send__(option) }
686:           metadef("#{option}=") { |val| set(option, Proc.new{val}) }
687:         elsif value == self && option.respond_to?(:to_hash)
688:           option.to_hash.each { |k,v| set(k, v) }
689:         elsif respond_to?("#{option}=")
690:           __send__ "#{option}=", value
691:         else
692:           set option, Proc.new{value}
693:         end
694:         self
695:       end

[Source]

     # File lib/sinatra/base.rb, line 985
985:       def synchronize(&block)
986:         if lock?
987:           @@mutex.synchronize(&block)
988:         else
989:           yield
990:         end
991:       end

Define a named template. The block must return the template source.

[Source]

     # File lib/sinatra/base.rb, line 720
720:       def template(name, &block)
721:         filename, line = caller_locations.first
722:         templates[name] = [block, filename, line.to_i]
723:       end

[Source]

     # File lib/sinatra/base.rb, line 790
790:       def user_agent(pattern)
791:         condition {
792:           if request.user_agent =~ pattern
793:             @params[:agent] = $~[1..-1]
794:             true
795:           else
796:             false
797:           end
798:         }
799:       end

Public Instance methods

Rack call interface.

[Source]

     # File lib/sinatra/base.rb, line 379
379:     def call(env)
380:       dup.call!(env)
381:     end

[Source]

     # File lib/sinatra/base.rb, line 385
385:     def call!(env)
386:       @env      = env
387:       @request  = Request.new(env)
388:       @response = Response.new
389:       @params   = indifferent_params(@request.params)
390:       @template_cache.clear if settings.reload_templates
391: 
392:       invoke { dispatch! }
393:       invoke { error_block!(response.status) }
394: 
395:       status, header, body = @response.finish
396: 
397:       # Never produce a body on HEAD requests. Do retain the Content-Length
398:       # unless it's "0", in which case we assume it was calculated erroneously
399:       # for a manual HEAD response and remove it entirely.
400:       if @env['REQUEST_METHOD'] == 'HEAD'
401:         body = []
402:         header.delete('Content-Length') if header['Content-Length'] == '0'
403:       end
404: 
405:       [status, header, body]
406:     end

Forward the request to the downstream app — middleware only.

[Source]

     # File lib/sinatra/base.rb, line 429
429:     def forward
430:       fail "downstream app not set" unless @app.respond_to? :call
431:       status, headers, body = @app.call(@request.env)
432:       @response.status = status
433:       @response.body = body
434:       @response.headers.merge! headers
435:       nil
436:     end

Exit the current block, halts any further processing of the request, and returns the specified response.

[Source]

     # File lib/sinatra/base.rb, line 416
416:     def halt(*response)
417:       response = response.first if response.length == 1
418:       throw :halt, response
419:     end
options()

Alias for settings

Pass control to the next matching route. If there are no more matching routes, Sinatra will return a 404 response.

[Source]

     # File lib/sinatra/base.rb, line 424
424:     def pass(&block)
425:       throw :pass, block
426:     end

Access settings defined with Base.set.

[Source]

     # File lib/sinatra/base.rb, line 409
409:     def settings
410:       self.class
411:     end

Private Instance methods

Run after filters defined on the class and all superclasses.

[Source]

     # File lib/sinatra/base.rb, line 446
446:     def after_filter!(base=self.class)
447:       after_filter!(base.superclass) if base.superclass.respond_to?(:after_filters)
448:       base.after_filters.each { |block| instance_eval(&block) }
449:     end

Run before filters defined on the class and all superclasses.

[Source]

     # File lib/sinatra/base.rb, line 440
440:     def before_filter!(base=self.class)
441:       before_filter!(base.superclass) if base.superclass.respond_to?(:before_filters)
442:       base.before_filters.each { |block| instance_eval(&block) }
443:     end

[Source]

     # File lib/sinatra/base.rb, line 633
633:     def clean_backtrace(trace)
634:       return trace unless settings.clean_trace?
635: 
636:       trace.reject { |line|
637:         line =~ /lib\/sinatra.*\.rb/ ||
638:           (defined?(Gem) && line.include?(Gem.dir))
639:       }.map! { |line| line.gsub(/^\.\//, '') }
640:     end

Dispatch a request with error handling.

[Source]

     # File lib/sinatra/base.rb, line 579
579:     def dispatch!
580:       static! if settings.static? && (request.get? || request.head?)
581:       before_filter!
582:       route!
583:     rescue NotFound => boom
584:       handle_not_found!(boom)
585:     rescue ::Exception => boom
586:       handle_exception!(boom)
587:     ensure
588:       after_filter! unless env['sinatra.static_file']
589:     end

[Source]

     # File lib/sinatra/base.rb, line 626
626:     def dump_errors!(boom)
627:       backtrace = clean_backtrace(boom.backtrace)
628:       msg = ["#{boom.class} - #{boom.message}:",
629:         *backtrace].join("\n ")
630:       @env['rack.errors'].puts(msg)
631:     end

Find an custom error block for the key(s) specified.

[Source]

     # File lib/sinatra/base.rb, line 610
610:     def error_block!(*keys)
611:       keys.each do |key|
612:         base = self.class
613:         while base.respond_to?(:errors)
614:           if block = base.errors[key]
615:             # found a handler, eval and return result
616:             res = instance_eval(&block)
617:             return res
618:           else
619:             base = base.superclass
620:           end
621:         end
622:       end
623:       nil
624:     end

[Source]

     # File lib/sinatra/base.rb, line 599
599:     def handle_exception!(boom)
600:       @env['sinatra.error'] = boom
601: 
602:       dump_errors!(boom) if settings.dump_errors?
603:       raise boom         if settings.raise_errors? || settings.show_exceptions?
604: 
605:       @response.status = 500
606:       error_block! boom.class, Exception
607:     end

[Source]

     # File lib/sinatra/base.rb, line 591
591:     def handle_not_found!(boom)
592:       @env['sinatra.error']          = boom
593:       @response.status               = 404
594:       @response.headers['X-Cascade'] = 'pass'
595:       @response.body                 = ['<h1>Not Found</h1>']
596:       error_block! boom.class, NotFound
597:     end

[Source]

     # File lib/sinatra/base.rb, line 541
541:     def indifferent_hash
542:       Hash.new {|hash,key| hash[key.to_s] if Symbol === key }
543:     end

Enable string or symbol key access to the nested params hash.

[Source]

     # File lib/sinatra/base.rb, line 533
533:     def indifferent_params(params)
534:       params = indifferent_hash.merge(params)
535:       params.each do |key, value|
536:         next unless value.is_a?(Hash)
537:         params[key] = indifferent_params(value)
538:       end
539:     end

Run the block with ‘throw :halt’ support and apply result to the response.

[Source]

     # File lib/sinatra/base.rb, line 546
546:     def invoke(&block)
547:       res = catch(:halt) { instance_eval(&block) }
548:       return if res.nil?
549: 
550:       case
551:       when res.respond_to?(:to_str)
552:         @response.body = [res]
553:       when res.respond_to?(:to_ary)
554:         res = res.to_ary
555:         if Fixnum === res.first
556:           if res.length == 3
557:             @response.status, headers, body = res
558:             @response.body = body if body
559:             headers.each { |k, v| @response.headers[k] = v } if headers
560:           elsif res.length == 2
561:             @response.status = res.first
562:             @response.body   = res.last
563:           else
564:             raise TypeError, "#{res.inspect} not supported"
565:           end
566:         else
567:           @response.body = res
568:         end
569:       when res.respond_to?(:each)
570:         @response.body = res
571:       when (100...599) === res
572:         @response.status = res
573:       end
574: 
575:       res
576:     end

Run routes defined on the class and all superclasses.

[Source]

     # File lib/sinatra/base.rb, line 452
452:     def route!(base=self.class, pass_block=nil)
453:       if routes = base.routes[@request.request_method]
454:         original_params = @params
455:         path            = unescape(@request.path_info)
456: 
457:         routes.each do |pattern, keys, conditions, block|
458:           if match = pattern.match(path)
459:             values = match.captures.to_a
460:             params =
461:               if keys.any?
462:                 keys.zip(values).inject({}) do |hash,(k,v)|
463:                   if k == 'splat'
464:                     (hash[k] ||= []) << v
465:                   else
466:                     hash[k] = v
467:                   end
468:                   hash
469:                 end
470:               elsif values.any?
471:                 {'captures' => values}
472:               else
473:                 {}
474:               end
475:             @params = original_params.merge(params)
476:             @block_params = values
477: 
478:             pass_block = catch(:pass) do
479:               conditions.each { |cond|
480:                 throw :pass if instance_eval(&cond) == false }
481:               route_eval(&block)
482:             end
483:           end
484:         end
485: 
486:         @params = original_params
487:       end
488: 
489:       # Run routes defined in superclass.
490:       if base.superclass.respond_to?(:routes)
491:         route! base.superclass, pass_block
492:         return
493:       end
494: 
495:       route_eval(&pass_block) if pass_block
496: 
497:       route_missing
498:     end

Run a route block and throw :halt with the result.

[Source]

     # File lib/sinatra/base.rb, line 501
501:     def route_eval(&block)
502:       throw :halt, instance_eval(&block)
503:     end

No matching route was found or all routes passed. The default implementation is to forward the request downstream when running as middleware (@app is non-nil); when no downstream app is set, raise a NotFound exception. Subclasses can override this method to perform custom route miss logic.

[Source]

     # File lib/sinatra/base.rb, line 510
510:     def route_missing
511:       if @app
512:         forward
513:       else
514:         raise NotFound
515:       end
516:     end

Attempt to serve static files from public directory. Throws :halt when a matching file is found, returns nil otherwise.

[Source]

     # File lib/sinatra/base.rb, line 520
520:     def static!
521:       return if (public_dir = settings.public).nil?
522:       public_dir = File.expand_path(public_dir)
523: 
524:       path = File.expand_path(public_dir + unescape(request.path_info))
525:       return if path[0, public_dir.length] != public_dir
526:       return unless File.file?(path)
527: 
528:       env['sinatra.static_file'] = path
529:       send_file path, :disposition => nil
530:     end

[Validate]