Class Sinatra::Base
In: lib/sinatra/base.rb
Parent: Object
Rack::ShowExceptions ShowExceptions Rack::Response Response Base Application\n[lib/sinatra/base.rb\nlib/sinatra/main.rb] Rack::Utils NameError NotFound Rack::Request Request Tilt::CompileSite ::File StaticFile lib/sinatra/base.rb lib/sinatra/showexceptions.rb Templates Delegator lib/sinatra/base.rb Helpers Sinatra dot/m_4_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
method_override? -> methodoverride?
method_override= -> methodoverride=

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 978
978:       def call(env)
979:         synchronize { prototype.call(env) }
980:       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 1028
1028:       def caller_files
1029:         caller_locations.
1030:           map { |file,line| file }
1031:       end

[Source]

      # File lib/sinatra/base.rb, line 1033
1033:       def caller_locations
1034:         caller(1).
1035:           map    { |line| line.split(/:(?=\d|in )/)[0,2] }.
1036:           reject { |file,line| CALLERS_TO_IGNORE.any? { |pattern| file =~ pattern } }
1037:       end

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

[Source]

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

[Source]

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

[Source]

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

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

[Source]

     # File lib/sinatra/base.rb, line 836
836:       def get(path, opts={}, &block)
837:         conditions = @conditions.dup
838:         route('GET', path, opts, &block)
839: 
840:         @conditions = conditions
841:         route('HEAD', path, opts, &block)
842:       end

[Source]

     # File lib/sinatra/base.rb, line 847
847:       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 908
908:       def helpers(*extensions, &block)
909:         class_eval(&block)  if block_given?
910:         include(*extensions) if extensions.any?
911:       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 966
966:       def new(*args, &bk)
967:         builder = Rack::Builder.new
968:         builder.use Rack::Session::Cookie if sessions?
969:         builder.use Rack::CommonLogger    if logging?
970:         builder.use Rack::MethodOverride  if method_override?
971:         builder.use ShowExceptions        if show_exceptions?
972:         middleware.each { |c,a,b| builder.use(c, *a, &b) }
973: 
974:         builder.run super
975:         builder.to_app
976:       end

[Source]

     # File lib/sinatra/base.rb, line 391
391:     def initialize(app=nil)
392:       @app = app
393:       @template_cache = Tilt::Cache.new
394:       yield self if block_given?
395:     end

[Source]

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

[Source]

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

The prototype instance used to process requests.

[Source]

     # File lib/sinatra/base.rb, line 959
959:       def prototype
960:         @prototype ||= new
961:       end

[Source]

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

[Source]

     # File lib/sinatra/base.rb, line 913
913:       def register(*extensions, &block)
914:         extensions << Module.new(&block) if block_given?
915:         @extensions += extensions
916:         extensions.each do |extension|
917:           extend extension
918:           extension.registered(self) if extension.respond_to?(:registered)
919:         end
920:       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 940
940:       def run!(options={})
941:         set options
942:         handler      = detect_rack_handler
943:         handler_name = handler.name.gsub(/.*::/, '')
944:         puts "== Sinatra/#{Sinatra::VERSION} has taken the stage " +
945:           "on #{port} for #{environment} with backup from #{handler_name}" unless handler_name =~/cgi/i
946:         handler.run self, :Host => bind, :Port => port do |server|
947:           trap(:INT) do
948:             ## Use thins' hard #stop! if available, otherwise just #stop
949:             server.respond_to?(:stop!) ? server.stop! : server.stop
950:             puts "\n== Sinatra has ended his set (crowd applauds)" unless handler_name =~/cgi/i
951:           end
952:           set :running, true
953:         end
954:       rescue Errno::EADDRINUSE => e
955:         puts "== Someone is already performing on port #{port}!"
956:       end

[Source]

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

Use the specified Rack middleware

[Source]

     # File lib/sinatra/base.rb, line 933
933:       def use(middleware, *args, &block)
934:         @prototype = nil
935:         @middleware << [middleware, args, block]
936:       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 791
791:       def after(&block)
792:         @after_filters << block
793:       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 784
784:       def before(&block)
785:         @before_filters << block
786:       end

[Source]

     # File lib/sinatra/base.rb, line 878
878:       def compile(path)
879:         keys = []
880:         if path.respond_to? :to_str
881:           special_chars = %w{. + ( )}
882:           pattern =
883:             path.to_str.gsub(/((:\w+)|[\*#{special_chars.join}])/) do |match|
884:               case match
885:               when "*"
886:                 keys << 'splat'
887:                 "(.*?)"
888:               when *special_chars
889:                 Regexp.escape(match)
890:               else
891:                 keys << $2[1..-1]
892:                 "([^/?&#]+)"
893:               end
894:             end
895:           [/^#{pattern}$/, keys]
896:         elsif path.respond_to?(:keys) && path.respond_to?(:match)
897:           [path, path.keys]
898:         elsif path.respond_to? :match
899:           [path, keys]
900:         else
901:           raise TypeError, path
902:         end
903:       end

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

[Source]

     # File lib/sinatra/base.rb, line 797
797:       def condition(&block)
798:         @conditions << block
799:       end

[Source]

     # File lib/sinatra/base.rb, line 983
983:       def detect_rack_handler
984:         servers = Array(self.server)
985:         servers.each do |server_name|
986:           begin
987:             return Rack::Handler.get(server_name.downcase)
988:           rescue LoadError
989:           rescue NameError
990:           end
991:         end
992:         fail "Server handler (#{servers.join(',')}) not found."
993:       end

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

[Source]

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

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

[Source]

     # File lib/sinatra/base.rb, line 714
714:       def enable(*opts)
715:         opts.each { |key| set(key, true) }
716:       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 726
726:       def error(codes=Exception, &block)
727:         Array(codes).each { |code| @errors[code] = block }
728:       end

Extension modules registered on this class and all superclasses.

[Source]

     # File lib/sinatra/base.rb, line 677
677:       def extensions
678:         if superclass.respond_to?(:extensions)
679:           (@extensions + superclass.extensions).uniq
680:         else
681:           @extensions
682:         end
683:       end

[Source]

     # File lib/sinatra/base.rb, line 802
802:       def host_name(pattern)
803:         condition { pattern === request.host }
804:       end

[Source]

     # File lib/sinatra/base.rb, line 995
995:       def inherited(subclass)
996:         subclass.reset!
997:         super
998:       end

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

[Source]

     # File lib/sinatra/base.rb, line 748
748:       def inline_templates=(file=nil)
749:         file = (file.nil? || file == true) ? caller_files.first : file
750: 
751:         begin
752:           app, data =
753:             ::IO.read(file).gsub("\r\n", "\n").split(/^__END__$/, 2)
754:         rescue Errno::ENOENT
755:           app, data = nil
756:         end
757: 
758:         if data
759:           lines = app.count("\n") + 1
760:           template = nil
761:           data.each_line do |line|
762:             lines += 1
763:             if line =~ /^@@\s*(.*)/
764:               template = ''
765:               templates[$1.to_sym] = [template, file, lines]
766:             elsif template
767:               template << line
768:             end
769:           end
770:         end
771:       end

[Source]

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

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

[Source]

     # File lib/sinatra/base.rb, line 742
742:       def layout(name=:layout, &block)
743:         template name, &block
744:       end

[Source]

      # File lib/sinatra/base.rb, line 1009
1009:       def metadef(message, &block)
1010:         (class << self; self; end).
1011:           send :define_method, message, &block
1012:       end

Middleware used in this class and all superclasses.

[Source]

     # File lib/sinatra/base.rb, line 686
686:       def middleware
687:         if superclass.respond_to?(:middleware)
688:           superclass.middleware + @middleware
689:         else
690:           @middleware
691:         end
692:       end

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

[Source]

     # File lib/sinatra/base.rb, line 774
774:       def mime_type(type, value=nil)
775:         return type if type.nil? || type.to_s.include?('/')
776:         type = ".#{type}" unless type.to_s[0] == ?.
777:         return Rack::Mime.mime_type(type, nil) unless value
778:         Rack::Mime::MIME_TYPES[type] = value
779:       end

Sugar for `error(404) { … }`

[Source]

     # File lib/sinatra/base.rb, line 731
731:       def not_found(&block)
732:         error 404, &block
733:       end

[Source]

     # File lib/sinatra/base.rb, line 818
818:       def provides(*types)
819:         types = [types] unless types.kind_of? Array
820:         types.map!{|t| mime_type(t)}
821: 
822:         condition {
823:           matching_types = (request.accept & types)
824:           unless matching_types.empty?
825:             response.headers['Content-Type'] = matching_types.first
826:             true
827:           else
828:             false
829:           end
830:         }
831:       end

[Source]

     # File lib/sinatra/base.rb, line 659
659:       def reset!
660:         @conditions     = []
661:         @routes         = {}
662:         @before_filters = []
663:         @after_filters  = []
664:         @errors         = {}
665:         @middleware     = []
666:         @prototype      = nil
667:         @extensions     = []
668: 
669:         if superclass.respond_to?(:templates)
670:           @templates = Hash.new { |hash,key| superclass.templates[key] }
671:         else
672:           @templates = {}
673:         end
674:       end

[Source]

     # File lib/sinatra/base.rb, line 850
850:       def route(verb, path, options={}, &block)
851:         # Because of self.options.host
852:         host_name(options.delete(:bind)) if options.key?(:host)
853: 
854:         options.each {|option, args| send(option, *args)}
855: 
856:         pattern, keys = compile(path)
857:         conditions, @conditions = @conditions, []
858: 
859:         define_method "#{verb} #{path}", &block
860:         unbound_method = instance_method("#{verb} #{path}")
861:         block =
862:           if block.arity != 0
863:             proc { unbound_method.bind(self).call(*@block_params) }
864:           else
865:             proc { unbound_method.bind(self).call }
866:           end
867: 
868:         invoke_hook(:route_added, verb, path, block)
869: 
870:         (@routes[verb] ||= []).
871:           push([pattern, keys, conditions, block]).last
872:       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 696
696:       def set(option, value=self, &block)
697:         raise ArgumentError if block && value != self
698:         value = block if block
699:         if value.kind_of?(Proc)
700:           metadef(option, &value)
701:           metadef("#{option}?") { !!__send__(option) }
702:           metadef("#{option}=") { |val| metadef(option, &Proc.new{val}) }
703:         elsif value == self && option.respond_to?(:to_hash)
704:           option.to_hash.each { |k,v| set(k, v) }
705:         elsif respond_to?("#{option}=")
706:           __send__ "#{option}=", value
707:         else
708:           set option, Proc.new{value}
709:         end
710:         self
711:       end

[Source]

      # File lib/sinatra/base.rb, line 1001
1001:       def synchronize(&block)
1002:         if lock?
1003:           @@mutex.synchronize(&block)
1004:         else
1005:           yield
1006:         end
1007:       end

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

[Source]

     # File lib/sinatra/base.rb, line 736
736:       def template(name, &block)
737:         filename, line = caller_locations.first
738:         templates[name] = [block, filename, line.to_i]
739:       end

[Source]

     # File lib/sinatra/base.rb, line 806
806:       def user_agent(pattern)
807:         condition {
808:           if request.user_agent =~ pattern
809:             @params[:agent] = $~[1..-1]
810:             true
811:           else
812:             false
813:           end
814:         }
815:       end

Public Instance methods

Rack call interface.

[Source]

     # File lib/sinatra/base.rb, line 398
398:     def call(env)
399:       dup.call!(env)
400:     end

[Source]

     # File lib/sinatra/base.rb, line 404
404:     def call!(env)
405:       @env      = env
406:       @request  = Request.new(env)
407:       @response = Response.new
408:       @params   = indifferent_params(@request.params)
409:       @template_cache.clear if settings.reload_templates
410: 
411:       invoke { dispatch! }
412:       invoke { error_block!(response.status) }
413: 
414:       status, header, body = @response.finish
415: 
416:       # Never produce a body on HEAD requests. Do retain the Content-Length
417:       # unless it's "0", in which case we assume it was calculated erroneously
418:       # for a manual HEAD response and remove it entirely.
419:       if @env['REQUEST_METHOD'] == 'HEAD'
420:         body = []
421:         header.delete('Content-Length') if header['Content-Length'] == '0'
422:       end
423: 
424:       [status, header, body]
425:     end

Forward the request to the downstream app — middleware only.

[Source]

     # File lib/sinatra/base.rb, line 448
448:     def forward
449:       fail "downstream app not set" unless @app.respond_to? :call
450:       status, headers, body = @app.call(@request.env)
451:       @response.status = status
452:       @response.body = body
453:       @response.headers.merge! headers
454:       nil
455:     end

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

[Source]

     # File lib/sinatra/base.rb, line 435
435:     def halt(*response)
436:       response = response.first if response.length == 1
437:       throw :halt, response
438:     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 443
443:     def pass(&block)
444:       throw :pass, block
445:     end

Access settings defined with Base.set.

[Source]

     # File lib/sinatra/base.rb, line 428
428:     def settings
429:       self.class
430:     end

Private Instance methods

Run after filters defined on the class and all superclasses.

[Source]

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

Run before filters defined on the class and all superclasses.

[Source]

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

Dispatch a request with error handling.

[Source]

     # File lib/sinatra/base.rb, line 598
598:     def dispatch!
599:       static! if settings.static? && (request.get? || request.head?)
600:       before_filter!
601:       route!
602:     rescue NotFound => boom
603:       handle_not_found!(boom)
604:     rescue ::Exception => boom
605:       handle_exception!(boom)
606:     ensure
607:       after_filter! unless env['sinatra.static_file']
608:     end

[Source]

     # File lib/sinatra/base.rb, line 650
650:     def dump_errors!(boom)
651:       msg = ["#{boom.class} - #{boom.message}:",
652:         *boom.backtrace].join("\n ")
653:       @env['rack.errors'].puts(msg)
654:     end

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

[Source]

     # File lib/sinatra/base.rb, line 635
635:     def error_block!(*keys)
636:       keys.each do |key|
637:         base = self.class
638:         while base.respond_to?(:errors)
639:           if block = base.errors[key]
640:             # found a handler, eval and return result
641:             return instance_eval(&block)
642:           else
643:             base = base.superclass
644:           end
645:         end
646:       end
647:       nil
648:     end

[Source]

     # File lib/sinatra/base.rb, line 618
618:     def handle_exception!(boom)
619:       @env['sinatra.error'] = boom
620: 
621:       dump_errors!(boom) if settings.dump_errors?
622:       raise boom         if settings.show_exceptions?
623: 
624:       @response.status = 500
625:       if res = error_block!(boom.class)
626:         res
627:       elsif settings.raise_errors?
628:         raise boom
629:       else
630:         error_block!(Exception)
631:       end
632:     end

[Source]

     # File lib/sinatra/base.rb, line 610
610:     def handle_not_found!(boom)
611:       @env['sinatra.error']          = boom
612:       @response.status               = 404
613:       @response.headers['X-Cascade'] = 'pass'
614:       @response.body                 = ['<h1>Not Found</h1>']
615:       error_block! boom.class, NotFound
616:     end

[Source]

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

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

[Source]

     # File lib/sinatra/base.rb, line 552
552:     def indifferent_params(params)
553:       params = indifferent_hash.merge(params)
554:       params.each do |key, value|
555:         next unless value.is_a?(Hash)
556:         params[key] = indifferent_params(value)
557:       end
558:     end

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

[Source]

     # File lib/sinatra/base.rb, line 565
565:     def invoke(&block)
566:       res = catch(:halt) { instance_eval(&block) }
567:       return if res.nil?
568: 
569:       case
570:       when res.respond_to?(:to_str)
571:         @response.body = [res]
572:       when res.respond_to?(:to_ary)
573:         res = res.to_ary
574:         if Fixnum === res.first
575:           if res.length == 3
576:             @response.status, headers, body = res
577:             @response.body = body if body
578:             headers.each { |k, v| @response.headers[k] = v } if headers
579:           elsif res.length == 2
580:             @response.status = res.first
581:             @response.body   = res.last
582:           else
583:             raise TypeError, "#{res.inspect} not supported"
584:           end
585:         else
586:           @response.body = res
587:         end
588:       when res.respond_to?(:each)
589:         @response.body = res
590:       when (100...599) === res
591:         @response.status = res
592:       end
593: 
594:       res
595:     end

Run routes defined on the class and all superclasses.

[Source]

     # File lib/sinatra/base.rb, line 471
471:     def route!(base=self.class, pass_block=nil)
472:       if routes = base.routes[@request.request_method]
473:         original_params = @params
474:         path            = unescape(@request.path_info)
475: 
476:         routes.each do |pattern, keys, conditions, block|
477:           if match = pattern.match(path)
478:             values = match.captures.to_a
479:             params =
480:               if keys.any?
481:                 keys.zip(values).inject({}) do |hash,(k,v)|
482:                   if k == 'splat'
483:                     (hash[k] ||= []) << v
484:                   else
485:                     hash[k] = v
486:                   end
487:                   hash
488:                 end
489:               elsif values.any?
490:                 {'captures' => values}
491:               else
492:                 {}
493:               end
494:             @params = original_params.merge(params)
495:             @block_params = values
496: 
497:             pass_block = catch(:pass) do
498:               conditions.each { |cond|
499:                 throw :pass if instance_eval(&cond) == false }
500:               route_eval(&block)
501:             end
502:           end
503:         end
504: 
505:         @params = original_params
506:       end
507: 
508:       # Run routes defined in superclass.
509:       if base.superclass.respond_to?(:routes)
510:         route! base.superclass, pass_block
511:         return
512:       end
513: 
514:       route_eval(&pass_block) if pass_block
515: 
516:       route_missing
517:     end

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

[Source]

     # File lib/sinatra/base.rb, line 520
520:     def route_eval(&block)
521:       throw :halt, instance_eval(&block)
522:     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 529
529:     def route_missing
530:       if @app
531:         forward
532:       else
533:         raise NotFound
534:       end
535:     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 539
539:     def static!
540:       return if (public_dir = settings.public).nil?
541:       public_dir = File.expand_path(public_dir)
542: 
543:       path = File.expand_path(public_dir + unescape(request.path_info))
544:       return if path[0, public_dir.length] != public_dir
545:       return unless File.file?(path)
546: 
547:       env['sinatra.static_file'] = path
548:       send_file path, :disposition => nil
549:     end

[Validate]