gin 0.0.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.autotest +3 -3
 - data/.gitignore +7 -0
 - data/History.rdoc +3 -6
 - data/Manifest.txt +36 -2
 - data/README.rdoc +24 -14
 - data/Rakefile +2 -9
 - data/lib/gin.rb +122 -1
 - data/lib/gin/app.rb +595 -0
 - data/lib/gin/config.rb +50 -0
 - data/lib/gin/controller.rb +602 -0
 - data/lib/gin/core_ext/cgi.rb +15 -0
 - data/lib/gin/core_ext/gin_class.rb +10 -0
 - data/lib/gin/errorable.rb +113 -0
 - data/lib/gin/filterable.rb +200 -0
 - data/lib/gin/reloadable.rb +90 -0
 - data/lib/gin/request.rb +76 -0
 - data/lib/gin/response.rb +51 -0
 - data/lib/gin/router.rb +222 -0
 - data/lib/gin/stream.rb +56 -0
 - data/public/400.html +14 -0
 - data/public/404.html +13 -0
 - data/public/500.html +14 -0
 - data/public/error.html +38 -0
 - data/public/favicon.ico +0 -0
 - data/public/gin.css +61 -0
 - data/public/gin_sm.png +0 -0
 - data/test/app/app_foo.rb +15 -0
 - data/test/app/controllers/app_controller.rb +16 -0
 - data/test/app/controllers/foo_controller.rb +3 -0
 - data/test/mock_config/backend.yml +7 -0
 - data/test/mock_config/memcache.yml +10 -0
 - data/test/mock_config/not_a_config.txt +0 -0
 - data/test/test_app.rb +592 -0
 - data/test/test_config.rb +33 -0
 - data/test/test_controller.rb +808 -0
 - data/test/test_errorable.rb +221 -0
 - data/test/test_filterable.rb +126 -0
 - data/test/test_gin.rb +59 -0
 - data/test/test_helper.rb +5 -0
 - data/test/test_request.rb +81 -0
 - data/test/test_response.rb +68 -0
 - data/test/test_router.rb +193 -0
 - metadata +80 -15
 - data/bin/gin +0 -3
 - data/test/gin_test.rb +0 -8
 
    
        data/.autotest
    CHANGED
    
    | 
         @@ -2,12 +2,12 @@ 
     | 
|
| 
       2 
2 
     | 
    
         | 
| 
       3 
3 
     | 
    
         
             
            require 'autotest/restart'
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
      
 5 
     | 
    
         
            +
            Autotest.add_hook :initialize do |at|
         
     | 
| 
       6 
6 
     | 
    
         
             
            #   at.extra_files << "../some/external/dependency.rb"
         
     | 
| 
       7 
7 
     | 
    
         
             
            #
         
     | 
| 
       8 
8 
     | 
    
         
             
            #   at.libs << ":../some/external"
         
     | 
| 
       9 
9 
     | 
    
         
             
            #
         
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
      
 10 
     | 
    
         
            +
              at.add_exception 'test/app'
         
     | 
| 
       11 
11 
     | 
    
         
             
            #
         
     | 
| 
       12 
12 
     | 
    
         
             
            #   at.add_mapping(/dependency.rb/) do |f, _|
         
     | 
| 
       13 
13 
     | 
    
         
             
            #     at.files_matching(/test_.*rb$/)
         
     | 
| 
         @@ -16,7 +16,7 @@ require 'autotest/restart' 
     | 
|
| 
       16 
16 
     | 
    
         
             
            #   %w(TestA TestB).each do |klass|
         
     | 
| 
       17 
17 
     | 
    
         
             
            #     at.extra_class_map[klass] = "test/test_misc.rb"
         
     | 
| 
       18 
18 
     | 
    
         
             
            #   end
         
     | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
      
 19 
     | 
    
         
            +
            end
         
     | 
| 
       20 
20 
     | 
    
         | 
| 
       21 
21 
     | 
    
         
             
            # Autotest.add_hook :run_command do |at|
         
     | 
| 
       22 
22 
     | 
    
         
             
            #   system "rake build"
         
     | 
    
        data/.gitignore
    ADDED
    
    
    
        data/History.rdoc
    CHANGED
    
    
    
        data/Manifest.txt
    CHANGED
    
    | 
         @@ -1,8 +1,42 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            .autotest
         
     | 
| 
      
 2 
     | 
    
         
            +
            .gitignore
         
     | 
| 
       2 
3 
     | 
    
         
             
            History.rdoc
         
     | 
| 
       3 
4 
     | 
    
         
             
            Manifest.txt
         
     | 
| 
       4 
5 
     | 
    
         
             
            README.rdoc
         
     | 
| 
       5 
6 
     | 
    
         
             
            Rakefile
         
     | 
| 
       6 
     | 
    
         
            -
            bin/gin
         
     | 
| 
       7 
7 
     | 
    
         
             
            lib/gin.rb
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
      
 8 
     | 
    
         
            +
            lib/gin/app.rb
         
     | 
| 
      
 9 
     | 
    
         
            +
            lib/gin/config.rb
         
     | 
| 
      
 10 
     | 
    
         
            +
            lib/gin/controller.rb
         
     | 
| 
      
 11 
     | 
    
         
            +
            lib/gin/core_ext/cgi.rb
         
     | 
| 
      
 12 
     | 
    
         
            +
            lib/gin/core_ext/gin_class.rb
         
     | 
| 
      
 13 
     | 
    
         
            +
            lib/gin/errorable.rb
         
     | 
| 
      
 14 
     | 
    
         
            +
            lib/gin/filterable.rb
         
     | 
| 
      
 15 
     | 
    
         
            +
            lib/gin/reloadable.rb
         
     | 
| 
      
 16 
     | 
    
         
            +
            lib/gin/request.rb
         
     | 
| 
      
 17 
     | 
    
         
            +
            lib/gin/response.rb
         
     | 
| 
      
 18 
     | 
    
         
            +
            lib/gin/router.rb
         
     | 
| 
      
 19 
     | 
    
         
            +
            lib/gin/stream.rb
         
     | 
| 
      
 20 
     | 
    
         
            +
            public/400.html
         
     | 
| 
      
 21 
     | 
    
         
            +
            public/404.html
         
     | 
| 
      
 22 
     | 
    
         
            +
            public/500.html
         
     | 
| 
      
 23 
     | 
    
         
            +
            public/error.html
         
     | 
| 
      
 24 
     | 
    
         
            +
            public/favicon.ico
         
     | 
| 
      
 25 
     | 
    
         
            +
            public/gin.css
         
     | 
| 
      
 26 
     | 
    
         
            +
            public/gin_sm.png
         
     | 
| 
      
 27 
     | 
    
         
            +
            test/app/app_foo.rb
         
     | 
| 
      
 28 
     | 
    
         
            +
            test/app/controllers/app_controller.rb
         
     | 
| 
      
 29 
     | 
    
         
            +
            test/app/controllers/foo_controller.rb
         
     | 
| 
      
 30 
     | 
    
         
            +
            test/mock_config/backend.yml
         
     | 
| 
      
 31 
     | 
    
         
            +
            test/mock_config/memcache.yml
         
     | 
| 
      
 32 
     | 
    
         
            +
            test/mock_config/not_a_config.txt
         
     | 
| 
      
 33 
     | 
    
         
            +
            test/test_app.rb
         
     | 
| 
      
 34 
     | 
    
         
            +
            test/test_config.rb
         
     | 
| 
      
 35 
     | 
    
         
            +
            test/test_controller.rb
         
     | 
| 
      
 36 
     | 
    
         
            +
            test/test_errorable.rb
         
     | 
| 
      
 37 
     | 
    
         
            +
            test/test_filterable.rb
         
     | 
| 
      
 38 
     | 
    
         
            +
            test/test_gin.rb
         
     | 
| 
      
 39 
     | 
    
         
            +
            test/test_helper.rb
         
     | 
| 
      
 40 
     | 
    
         
            +
            test/test_request.rb
         
     | 
| 
      
 41 
     | 
    
         
            +
            test/test_response.rb
         
     | 
| 
      
 42 
     | 
    
         
            +
            test/test_router.rb
         
     | 
    
        data/README.rdoc
    CHANGED
    
    | 
         @@ -1,29 +1,39 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            =  
     | 
| 
      
 1 
     | 
    
         
            +
            = Gin
         
     | 
| 
       2 
2 
     | 
    
         | 
| 
       3 
     | 
    
         
            -
            *  
     | 
| 
      
 3 
     | 
    
         
            +
            * http://yaks.me/gin
         
     | 
| 
       4 
4 
     | 
    
         | 
| 
       5 
     | 
    
         
            -
            ==  
     | 
| 
      
 5 
     | 
    
         
            +
            == Description
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
      
 7 
     | 
    
         
            +
            Gin is a small web framework built from the redistillation of
         
     | 
| 
      
 8 
     | 
    
         
            +
            Sinatra and Rails idioms. Specifically, it uses much of Sinatra's
         
     | 
| 
      
 9 
     | 
    
         
            +
            request flow and HTTP helper methods with dedicated controller classes
         
     | 
| 
      
 10 
     | 
    
         
            +
            that support Rails-like filters.
         
     | 
| 
       8 
11 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            ==  
     | 
| 
      
 12 
     | 
    
         
            +
            == Hello World
         
     | 
| 
       10 
13 
     | 
    
         | 
| 
       11 
     | 
    
         
            -
             
     | 
| 
      
 14 
     | 
    
         
            +
              # config.ru
         
     | 
| 
      
 15 
     | 
    
         
            +
              require 'gin'
         
     | 
| 
       12 
16 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
      
 17 
     | 
    
         
            +
              class HelloWorldCtrl < Gin::Controller
         
     | 
| 
      
 18 
     | 
    
         
            +
                def index; "Hello World!"; end
         
     | 
| 
      
 19 
     | 
    
         
            +
              end
         
     | 
| 
       14 
20 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
             
     | 
| 
      
 21 
     | 
    
         
            +
              class MyApp < Gin::App
         
     | 
| 
      
 22 
     | 
    
         
            +
                mount HelloWorldCtrl, "/"
         
     | 
| 
      
 23 
     | 
    
         
            +
              end
         
     | 
| 
       16 
24 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
             
     | 
| 
      
 25 
     | 
    
         
            +
              run MyApp.new
         
     | 
| 
       18 
26 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
            == Requirements
         
     | 
| 
       20 
28 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
             
     | 
| 
      
 29 
     | 
    
         
            +
            * rack
         
     | 
| 
      
 30 
     | 
    
         
            +
            * rack-protection
         
     | 
| 
       22 
31 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
             
     | 
| 
       24 
     | 
    
         
            -
             
     | 
| 
      
 32 
     | 
    
         
            +
            == Install
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            * gem install gin
         
     | 
| 
       25 
35 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
            ==  
     | 
| 
      
 36 
     | 
    
         
            +
            == License
         
     | 
| 
       27 
37 
     | 
    
         | 
| 
       28 
38 
     | 
    
         
             
            (The MIT License)
         
     | 
| 
       29 
39 
     | 
    
         | 
    
        data/Rakefile
    CHANGED
    
    | 
         @@ -3,21 +3,14 @@ 
     | 
|
| 
       3 
3 
     | 
    
         
             
            require 'rubygems'
         
     | 
| 
       4 
4 
     | 
    
         
             
            require 'hoe'
         
     | 
| 
       5 
5 
     | 
    
         | 
| 
       6 
     | 
    
         
            -
            # Hoe.plugin :compiler
         
     | 
| 
       7 
     | 
    
         
            -
            # Hoe.plugin :gem_prelude_sucks
         
     | 
| 
       8 
     | 
    
         
            -
            # Hoe.plugin :inline
         
     | 
| 
       9 
     | 
    
         
            -
            # Hoe.plugin :isolate
         
     | 
| 
       10 
     | 
    
         
            -
            # Hoe.plugin :racc
         
     | 
| 
       11 
     | 
    
         
            -
            # Hoe.plugin :rcov
         
     | 
| 
       12 
     | 
    
         
            -
            # Hoe.plugin :rubyforge
         
     | 
| 
       13 
     | 
    
         
            -
             
     | 
| 
       14 
6 
     | 
    
         
             
            Hoe.spec 'gin' do
         
     | 
| 
       15 
7 
     | 
    
         
             
              developer('Jeremie Castagna', 'yaksnrainbows@gmail.com')
         
     | 
| 
       16 
8 
     | 
    
         
             
              self.readme_file      = "README.rdoc"
         
     | 
| 
       17 
9 
     | 
    
         
             
              self.history_file     = "History.rdoc"
         
     | 
| 
       18 
10 
     | 
    
         
             
              self.extra_rdoc_files = FileList['*.rdoc']
         
     | 
| 
       19 
11 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
              self.extra_deps << ['rack', 
     | 
| 
      
 12 
     | 
    
         
            +
              self.extra_deps << ['rack',            '~>1.1']
         
     | 
| 
      
 13 
     | 
    
         
            +
              self.extra_deps << ['rack-protection', '~>1.0']
         
     | 
| 
       21 
14 
     | 
    
         
             
            end
         
     | 
| 
       22 
15 
     | 
    
         | 
| 
       23 
16 
     | 
    
         
             
            # vim: syntax=ruby
         
     | 
    
        data/lib/gin.rb
    CHANGED
    
    | 
         @@ -1,3 +1,124 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'logger'
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            require 'rack'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'rack-protection'
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
       1 
7 
     | 
    
         
             
            class Gin
         
     | 
| 
       2 
     | 
    
         
            -
              VERSION = ' 
     | 
| 
      
 8 
     | 
    
         
            +
              VERSION = '1.0.0'
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              LIB_DIR    = File.expand_path("..", __FILE__)            #:nodoc:
         
     | 
| 
      
 11 
     | 
    
         
            +
              PUBLIC_DIR = File.expand_path("../../public/", __FILE__) #:nodoc:
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
              class Error < StandardError; end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
              class BadRequest < ArgumentError
         
     | 
| 
      
 16 
     | 
    
         
            +
                def http_status; 400; end
         
     | 
| 
      
 17 
     | 
    
         
            +
              end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              class NotFound < NameError
         
     | 
| 
      
 20 
     | 
    
         
            +
                def http_status; 404; end
         
     | 
| 
      
 21 
     | 
    
         
            +
              end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
              ##
         
     | 
| 
      
 25 
     | 
    
         
            +
              # Change string to underscored version.
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              def self.underscore str
         
     | 
| 
      
 28 
     | 
    
         
            +
                str = str.dup
         
     | 
| 
      
 29 
     | 
    
         
            +
                str.gsub!('::', '/')
         
     | 
| 
      
 30 
     | 
    
         
            +
                str.gsub!(/([A-Z]+?)([A-Z][a-z])/, '\1_\2')
         
     | 
| 
      
 31 
     | 
    
         
            +
                str.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
         
     | 
| 
      
 32 
     | 
    
         
            +
                str.downcase
         
     | 
| 
      
 33 
     | 
    
         
            +
              end
         
     | 
| 
      
 34 
     | 
    
         
            +
             
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
              ##
         
     | 
| 
      
 37 
     | 
    
         
            +
              # Create a URI query from a Hash.
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              def self.build_query value, prefix=nil
         
     | 
| 
      
 40 
     | 
    
         
            +
                case value
         
     | 
| 
      
 41 
     | 
    
         
            +
                when Array
         
     | 
| 
      
 42 
     | 
    
         
            +
                  raise ArgumentError, "no prefix given" if prefix.nil?
         
     | 
| 
      
 43 
     | 
    
         
            +
                  value.map { |v|
         
     | 
| 
      
 44 
     | 
    
         
            +
                    build_query(v, "#{prefix}[]")
         
     | 
| 
      
 45 
     | 
    
         
            +
                  }.join("&")
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
                when Hash
         
     | 
| 
      
 48 
     | 
    
         
            +
                  value.map { |k, v|
         
     | 
| 
      
 49 
     | 
    
         
            +
                    build_query(v, prefix ?
         
     | 
| 
      
 50 
     | 
    
         
            +
                      "#{prefix}[#{CGI.escape(k.to_s)}]" : CGI.escape(k.to_s))
         
     | 
| 
      
 51 
     | 
    
         
            +
                  }.join("&")
         
     | 
| 
      
 52 
     | 
    
         
            +
             
     | 
| 
      
 53 
     | 
    
         
            +
                when String, Integer, Float, TrueClass, FalseClass
         
     | 
| 
      
 54 
     | 
    
         
            +
                  raise ArgumentError, "value must be a Hash" if prefix.nil?
         
     | 
| 
      
 55 
     | 
    
         
            +
                  "#{prefix}=#{CGI.escape(value.to_s)}"
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
                else
         
     | 
| 
      
 58 
     | 
    
         
            +
                  prefix
         
     | 
| 
      
 59 
     | 
    
         
            +
                end
         
     | 
| 
      
 60 
     | 
    
         
            +
              end
         
     | 
| 
      
 61 
     | 
    
         
            +
             
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
              ##
         
     | 
| 
      
 64 
     | 
    
         
            +
              # Returns the full path to the file given based on the load paths.
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
              def self.find_loadpath file
         
     | 
| 
      
 67 
     | 
    
         
            +
                name = file.dup
         
     | 
| 
      
 68 
     | 
    
         
            +
                name << ".rb" unless name[-3..-1] == ".rb"
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                return name if name[0] == ?/ && File.file?(name)
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                filepath = nil
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                dir = $:.find do |path|
         
     | 
| 
      
 75 
     | 
    
         
            +
                  filepath = File.expand_path(name, path)
         
     | 
| 
      
 76 
     | 
    
         
            +
                  File.file? filepath
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                dir && filepath
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              ##
         
     | 
| 
      
 84 
     | 
    
         
            +
              # Get a namespaced constant.
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
              def self.const_find str_or_ary, parent=Object
         
     | 
| 
      
 87 
     | 
    
         
            +
                const = nil
         
     | 
| 
      
 88 
     | 
    
         
            +
                names = Array === str_or_ary ? str_or_ary : str_or_ary.split("::")
         
     | 
| 
      
 89 
     | 
    
         
            +
                names.each do |name|
         
     | 
| 
      
 90 
     | 
    
         
            +
                  const  = parent.const_get(name)
         
     | 
| 
      
 91 
     | 
    
         
            +
                  parent = const
         
     | 
| 
      
 92 
     | 
    
         
            +
                end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                const
         
     | 
| 
      
 95 
     | 
    
         
            +
              end
         
     | 
| 
      
 96 
     | 
    
         
            +
             
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
              APP_START_MATCH = %r{/gin/app\.rb:\d+:in `dispatch'} #:nodoc:
         
     | 
| 
      
 99 
     | 
    
         
            +
             
     | 
| 
      
 100 
     | 
    
         
            +
              ##
         
     | 
| 
      
 101 
     | 
    
         
            +
              # Get the application backtrace only.
         
     | 
| 
      
 102 
     | 
    
         
            +
              # Removes gem and Gin paths from the trace.
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
              def self.app_trace trace
         
     | 
| 
      
 105 
     | 
    
         
            +
                trace = trace.dup
         
     | 
| 
      
 106 
     | 
    
         
            +
                trace.pop until trace.last.nil? || trace.last =~ APP_START_MATCH
         
     | 
| 
      
 107 
     | 
    
         
            +
                trace.pop while trace.last && trace.last.start_with?(LIB_DIR)
         
     | 
| 
      
 108 
     | 
    
         
            +
                trace
         
     | 
| 
      
 109 
     | 
    
         
            +
              end
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
              require 'gin/core_ext/cgi'
         
     | 
| 
      
 113 
     | 
    
         
            +
              require 'gin/core_ext/gin_class'
         
     | 
| 
      
 114 
     | 
    
         
            +
             
     | 
| 
      
 115 
     | 
    
         
            +
              require 'gin/app'
         
     | 
| 
      
 116 
     | 
    
         
            +
              require 'gin/router'
         
     | 
| 
      
 117 
     | 
    
         
            +
              require 'gin/config'
         
     | 
| 
      
 118 
     | 
    
         
            +
              require 'gin/request'
         
     | 
| 
      
 119 
     | 
    
         
            +
              require 'gin/response'
         
     | 
| 
      
 120 
     | 
    
         
            +
              require 'gin/stream'
         
     | 
| 
      
 121 
     | 
    
         
            +
              require 'gin/errorable'
         
     | 
| 
      
 122 
     | 
    
         
            +
              require 'gin/filterable'
         
     | 
| 
      
 123 
     | 
    
         
            +
              require 'gin/controller'
         
     | 
| 
       3 
124 
     | 
    
         
             
            end
         
     | 
    
        data/lib/gin/app.rb
    ADDED
    
    | 
         @@ -0,0 +1,595 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            ##
         
     | 
| 
      
 2 
     | 
    
         
            +
            # The Gin::App is the entry point for Rack, for all Gin Applications.
         
     | 
| 
      
 3 
     | 
    
         
            +
            # This class MUST be subclassed and initialized.
         
     | 
| 
      
 4 
     | 
    
         
            +
            #   # my_app.rb
         
     | 
| 
      
 5 
     | 
    
         
            +
            #   class MyApp < Gin::App
         
     | 
| 
      
 6 
     | 
    
         
            +
            #     require 'my_controller'
         
     | 
| 
      
 7 
     | 
    
         
            +
            #     mount MyController, "/"
         
     | 
| 
      
 8 
     | 
    
         
            +
            #   end
         
     | 
| 
      
 9 
     | 
    
         
            +
            #
         
     | 
| 
      
 10 
     | 
    
         
            +
            #   # config.ru
         
     | 
| 
      
 11 
     | 
    
         
            +
            #   require 'my_app'
         
     | 
| 
      
 12 
     | 
    
         
            +
            #   run MyApp.new
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
            class Gin::App
         
     | 
| 
      
 15 
     | 
    
         
            +
              extend GinClass
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
              class RouterError < Gin::Error; end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
              RACK_KEYS = { #:nodoc:
         
     | 
| 
      
 20 
     | 
    
         
            +
                :stack       => 'gin.stack'.freeze,
         
     | 
| 
      
 21 
     | 
    
         
            +
                :path_params => 'gin.path_query_hash'.freeze,
         
     | 
| 
      
 22 
     | 
    
         
            +
                :reloaded    => 'gin.reloaded'.freeze,
         
     | 
| 
      
 23 
     | 
    
         
            +
                :errors      => 'gin.errors'.freeze
         
     | 
| 
      
 24 
     | 
    
         
            +
              }.freeze
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
              CALLERS_TO_IGNORE = [ # :nodoc:
         
     | 
| 
      
 28 
     | 
    
         
            +
                /\/gin(\/(.*?))?\.rb$/,             # all gin code
         
     | 
| 
      
 29 
     | 
    
         
            +
                /lib\/tilt.*\.rb$/,                 # all tilt code
         
     | 
| 
      
 30 
     | 
    
         
            +
                /^\(.*\)$/,                         # generated code
         
     | 
| 
      
 31 
     | 
    
         
            +
                /rubygems\/custom_require\.rb$/,    # rubygems require hacks
         
     | 
| 
      
 32 
     | 
    
         
            +
                /active_support/,                   # active_support require hacks
         
     | 
| 
      
 33 
     | 
    
         
            +
                /bundler(\/runtime)?\.rb/,          # bundler require hacks
         
     | 
| 
      
 34 
     | 
    
         
            +
                /<internal:/,                       # internal in ruby >= 1.9.2
         
     | 
| 
      
 35 
     | 
    
         
            +
                /src\/kernel\/bootstrap\/[A-Z]/     # maglev kernel files
         
     | 
| 
      
 36 
     | 
    
         
            +
              ]
         
     | 
| 
      
 37 
     | 
    
         
            +
             
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
              def self.inherited subclass   #:nodoc:
         
     | 
| 
      
 40 
     | 
    
         
            +
                caller_line = caller.find{|line| !CALLERS_TO_IGNORE.any?{|m| line =~ m} }
         
     | 
| 
      
 41 
     | 
    
         
            +
                filepath = File.expand_path(caller_line.split(/:\d+:in `/).first)
         
     | 
| 
      
 42 
     | 
    
         
            +
                dir      = File.dirname(filepath)
         
     | 
| 
      
 43 
     | 
    
         
            +
                subclass.root_dir dir
         
     | 
| 
      
 44 
     | 
    
         
            +
                subclass.instance_variable_set("@source_file", filepath)
         
     | 
| 
      
 45 
     | 
    
         
            +
                subclass.instance_variable_set("@source_class", subclass.to_s)
         
     | 
| 
      
 46 
     | 
    
         
            +
              end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
             
     | 
| 
      
 49 
     | 
    
         
            +
              ##
         
     | 
| 
      
 50 
     | 
    
         
            +
              # Create a new intance of the app and call it.
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
              def self.call env
         
     | 
| 
      
 53 
     | 
    
         
            +
                @instance ||= self.new
         
     | 
| 
      
 54 
     | 
    
         
            +
                @instance.call env
         
     | 
| 
      
 55 
     | 
    
         
            +
              end
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
              ##
         
     | 
| 
      
 59 
     | 
    
         
            +
              # Enable or disable auto-app reloading.
         
     | 
| 
      
 60 
     | 
    
         
            +
              # On by default in development mode.
         
     | 
| 
      
 61 
     | 
    
         
            +
              #
         
     | 
| 
      
 62 
     | 
    
         
            +
              # In order for an app to be reloadable, the libs and controllers must be
         
     | 
| 
      
 63 
     | 
    
         
            +
              # required from the Gin::App class context, or use MyApp.require("lib").
         
     | 
| 
      
 64 
     | 
    
         
            +
              #
         
     | 
| 
      
 65 
     | 
    
         
            +
              # Reloading is not supported for applications defined in the config.ru file.
         
     | 
| 
      
 66 
     | 
    
         
            +
             
     | 
| 
      
 67 
     | 
    
         
            +
              def self.autoreload val=nil
         
     | 
| 
      
 68 
     | 
    
         
            +
                @autoreload = val unless val.nil?
         
     | 
| 
      
 69 
     | 
    
         
            +
             
     | 
| 
      
 70 
     | 
    
         
            +
                if @autoreload.nil?
         
     | 
| 
      
 71 
     | 
    
         
            +
                  @autoreload = File.extname(source_file) != ".ru" && development?
         
     | 
| 
      
 72 
     | 
    
         
            +
                end
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                if @autoreload && (!defined?(Gin::Reloadable) || !include?(Gin::Reloadable))
         
     | 
| 
      
 75 
     | 
    
         
            +
                  require 'gin/reloadable'
         
     | 
| 
      
 76 
     | 
    
         
            +
                  include Gin::Reloadable
         
     | 
| 
      
 77 
     | 
    
         
            +
                end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                @autoreload
         
     | 
| 
      
 80 
     | 
    
         
            +
              end
         
     | 
| 
      
 81 
     | 
    
         
            +
             
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
              ##
         
     | 
| 
      
 84 
     | 
    
         
            +
              # Mount a Gin::Controller into the App and specify a base path. If controller
         
     | 
| 
      
 85 
     | 
    
         
            +
              # mounts at root, use "/" as the base path.
         
     | 
| 
      
 86 
     | 
    
         
            +
              #   mount UserController, "/user" do
         
     | 
| 
      
 87 
     | 
    
         
            +
              #     get  :index,  "/"
         
     | 
| 
      
 88 
     | 
    
         
            +
              #     get  :show,   "/:id"
         
     | 
| 
      
 89 
     | 
    
         
            +
              #     post :create, "/"
         
     | 
| 
      
 90 
     | 
    
         
            +
              #     get  :stats        # mounts to "/stats" by default
         
     | 
| 
      
 91 
     | 
    
         
            +
              #     any  :logged_in    # any HTTP verb will trigger this action
         
     | 
| 
      
 92 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 93 
     | 
    
         
            +
              #
         
     | 
| 
      
 94 
     | 
    
         
            +
              # Controllers with non-mounted actions will throw a warning at boot time.
         
     | 
| 
      
 95 
     | 
    
         
            +
              #
         
     | 
| 
      
 96 
     | 
    
         
            +
              # Restful routes are automatically mounted when no block is given:
         
     | 
| 
      
 97 
     | 
    
         
            +
              #
         
     | 
| 
      
 98 
     | 
    
         
            +
              #   mount UserController
         
     | 
| 
      
 99 
     | 
    
         
            +
              #   # restfully mounted to /user
         
     | 
| 
      
 100 
     | 
    
         
            +
              #   # non-canonical actions are mounted to /user/<action_name>
         
     | 
| 
      
 101 
     | 
    
         
            +
              #
         
     | 
| 
      
 102 
     | 
    
         
            +
              # Mount blocks also support routing whatever actions are left to their restful
         
     | 
| 
      
 103 
     | 
    
         
            +
              # defaults:
         
     | 
| 
      
 104 
     | 
    
         
            +
              #
         
     | 
| 
      
 105 
     | 
    
         
            +
              #   mount UserController do
         
     | 
| 
      
 106 
     | 
    
         
            +
              #     get :foo, "/"
         
     | 
| 
      
 107 
     | 
    
         
            +
              #     defaults
         
     | 
| 
      
 108 
     | 
    
         
            +
              #   end
         
     | 
| 
      
 109 
     | 
    
         
            +
              #
         
     | 
| 
      
 110 
     | 
    
         
            +
              # All Gin::Controller methods are considered actions and will be mounted in
         
     | 
| 
      
 111 
     | 
    
         
            +
              # restful mode. For helper methods, include a module into your controller.
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
              def self.mount ctrl, base_path=nil, &block
         
     | 
| 
      
 114 
     | 
    
         
            +
                router.add ctrl, base_path, &block
         
     | 
| 
      
 115 
     | 
    
         
            +
              end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
              ##
         
     | 
| 
      
 119 
     | 
    
         
            +
              # Returns the source file of the current app.
         
     | 
| 
      
 120 
     | 
    
         
            +
             
     | 
| 
      
 121 
     | 
    
         
            +
              def self.source_file
         
     | 
| 
      
 122 
     | 
    
         
            +
                @source_file
         
     | 
| 
      
 123 
     | 
    
         
            +
              end
         
     | 
| 
      
 124 
     | 
    
         
            +
             
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
              def self.namespace #:nodoc:
         
     | 
| 
      
 127 
     | 
    
         
            +
                # Parent namespace of the App class. Used for reloading purposes.
         
     | 
| 
      
 128 
     | 
    
         
            +
                Gin.const_find(@source_class.split("::")[0..-2]) if @source_class
         
     | 
| 
      
 129 
     | 
    
         
            +
              end
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
             
     | 
| 
      
 132 
     | 
    
         
            +
              def self.source_class #:nodoc:
         
     | 
| 
      
 133 
     | 
    
         
            +
                # Lookup the class from its name. Used for reloading purposes.
         
     | 
| 
      
 134 
     | 
    
         
            +
                Gin.const_find(@source_class) if @source_class
         
     | 
| 
      
 135 
     | 
    
         
            +
              end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
             
     | 
| 
      
 138 
     | 
    
         
            +
              ##
         
     | 
| 
      
 139 
     | 
    
         
            +
              # Get or set the root directory of the application.
         
     | 
| 
      
 140 
     | 
    
         
            +
              # Defaults to the app file's directory.
         
     | 
| 
      
 141 
     | 
    
         
            +
             
     | 
| 
      
 142 
     | 
    
         
            +
              def self.root_dir dir=nil
         
     | 
| 
      
 143 
     | 
    
         
            +
                @root_dir = dir if dir
         
     | 
| 
      
 144 
     | 
    
         
            +
                @root_dir
         
     | 
| 
      
 145 
     | 
    
         
            +
              end
         
     | 
| 
      
 146 
     | 
    
         
            +
             
     | 
| 
      
 147 
     | 
    
         
            +
             
     | 
| 
      
 148 
     | 
    
         
            +
              ##
         
     | 
| 
      
 149 
     | 
    
         
            +
              # Get or set the path to the config directory.
         
     | 
| 
      
 150 
     | 
    
         
            +
              # Defaults to root_dir + "config"
         
     | 
| 
      
 151 
     | 
    
         
            +
              #
         
     | 
| 
      
 152 
     | 
    
         
            +
              # Configs are expected to be YAML files following this pattern:
         
     | 
| 
      
 153 
     | 
    
         
            +
              #   default: &default
         
     | 
| 
      
 154 
     | 
    
         
            +
              #     key: value
         
     | 
| 
      
 155 
     | 
    
         
            +
              #
         
     | 
| 
      
 156 
     | 
    
         
            +
              #   development: *default
         
     | 
| 
      
 157 
     | 
    
         
            +
              #     other_key: value
         
     | 
| 
      
 158 
     | 
    
         
            +
              #
         
     | 
| 
      
 159 
     | 
    
         
            +
              #   production: *default
         
     | 
| 
      
 160 
     | 
    
         
            +
              #     ...
         
     | 
| 
      
 161 
     | 
    
         
            +
              #
         
     | 
| 
      
 162 
     | 
    
         
            +
              # Configs will be named according to the filename, and only the config for
         
     | 
| 
      
 163 
     | 
    
         
            +
              # the current environment will be accessible.
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
              def self.config_dir dir=nil
         
     | 
| 
      
 166 
     | 
    
         
            +
                @config_dir = dir if dir
         
     | 
| 
      
 167 
     | 
    
         
            +
                @config_dir ||= File.join(root_dir, "config")
         
     | 
| 
      
 168 
     | 
    
         
            +
              end
         
     | 
| 
      
 169 
     | 
    
         
            +
             
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
              ##
         
     | 
| 
      
 172 
     | 
    
         
            +
              # Access the config for your application, loaded from the config_dir.
         
     | 
| 
      
 173 
     | 
    
         
            +
              #   # config/memcache.yml
         
     | 
| 
      
 174 
     | 
    
         
            +
              #   default: &default
         
     | 
| 
      
 175 
     | 
    
         
            +
              #     host: example.com
         
     | 
| 
      
 176 
     | 
    
         
            +
              #     connections: 1
         
     | 
| 
      
 177 
     | 
    
         
            +
              #   development: *default
         
     | 
| 
      
 178 
     | 
    
         
            +
              #     host: localhost
         
     | 
| 
      
 179 
     | 
    
         
            +
              #
         
     | 
| 
      
 180 
     | 
    
         
            +
              #   # access from App class or instance
         
     | 
| 
      
 181 
     | 
    
         
            +
              #   config.memcache['host']
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
              def self.config
         
     | 
| 
      
 184 
     | 
    
         
            +
                @config ||= Gin::Config.new environment, config_dir
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
              ##
         
     | 
| 
      
 189 
     | 
    
         
            +
              # Loads all configs from the config_dir.
         
     | 
| 
      
 190 
     | 
    
         
            +
             
     | 
| 
      
 191 
     | 
    
         
            +
              def self.load_config
         
     | 
| 
      
 192 
     | 
    
         
            +
                return unless File.directory?(config_dir)
         
     | 
| 
      
 193 
     | 
    
         
            +
                config.dir = config_dir
         
     | 
| 
      
 194 
     | 
    
         
            +
                config.load!
         
     | 
| 
      
 195 
     | 
    
         
            +
              end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
             
     | 
| 
      
 198 
     | 
    
         
            +
              ##
         
     | 
| 
      
 199 
     | 
    
         
            +
              # Get or set the path to the public directory.
         
     | 
| 
      
 200 
     | 
    
         
            +
              # Defaults to root_dir + "public"
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
              def self.public_dir dir=nil
         
     | 
| 
      
 203 
     | 
    
         
            +
                @public_dir = dir if dir
         
     | 
| 
      
 204 
     | 
    
         
            +
                @public_dir ||= File.join(root_dir, "public")
         
     | 
| 
      
 205 
     | 
    
         
            +
              end
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
             
     | 
| 
      
 208 
     | 
    
         
            +
              ##
         
     | 
| 
      
 209 
     | 
    
         
            +
              # Get or set the CDN asset host (and path).
         
     | 
| 
      
 210 
     | 
    
         
            +
              # If block is given, evaluates the block on every read.
         
     | 
| 
      
 211 
     | 
    
         
            +
             
     | 
| 
      
 212 
     | 
    
         
            +
              def self.asset_host host=nil, &block
         
     | 
| 
      
 213 
     | 
    
         
            +
                @asset_host = host  if host
         
     | 
| 
      
 214 
     | 
    
         
            +
                @asset_host = block if block_given?
         
     | 
| 
      
 215 
     | 
    
         
            +
                host = @asset_host.respond_to?(:call) ? @asset_host.call : @asset_host
         
     | 
| 
      
 216 
     | 
    
         
            +
              end
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
             
     | 
| 
      
 219 
     | 
    
         
            +
              ##
         
     | 
| 
      
 220 
     | 
    
         
            +
              # Returns the asset host for a given asset name. This is useful when assigning
         
     | 
| 
      
 221 
     | 
    
         
            +
              # a block for the asset_host. The asset_name argument is passed to the block.
         
     | 
| 
      
 222 
     | 
    
         
            +
             
     | 
| 
      
 223 
     | 
    
         
            +
              def self.asset_host_for asset_name
         
     | 
| 
      
 224 
     | 
    
         
            +
                 @asset_host.respond_to?(:call) ? @asset_host.call(asset_name) : @asset_host
         
     | 
| 
      
 225 
     | 
    
         
            +
              end
         
     | 
| 
      
 226 
     | 
    
         
            +
             
     | 
| 
      
 227 
     | 
    
         
            +
             
     | 
| 
      
 228 
     | 
    
         
            +
              ##
         
     | 
| 
      
 229 
     | 
    
         
            +
              # Returns the first 8 bytes of the asset file's md5.
         
     | 
| 
      
 230 
     | 
    
         
            +
              # File path is assumed relative to the public_dir.
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
              def self.asset_version path
         
     | 
| 
      
 233 
     | 
    
         
            +
                path = File.expand_path(File.join(public_dir, path))
         
     | 
| 
      
 234 
     | 
    
         
            +
                return unless File.file?(path)
         
     | 
| 
      
 235 
     | 
    
         
            +
             
     | 
| 
      
 236 
     | 
    
         
            +
                @asset_versions       ||= {}
         
     | 
| 
      
 237 
     | 
    
         
            +
                @asset_versions[path] ||= md5(path)
         
     | 
| 
      
 238 
     | 
    
         
            +
              end
         
     | 
| 
      
 239 
     | 
    
         
            +
             
     | 
| 
      
 240 
     | 
    
         
            +
             
     | 
| 
      
 241 
     | 
    
         
            +
              MD5 = RUBY_PLATFORM =~ /darwin/ ? 'md5 -q' : 'md5sum' #:nodoc:
         
     | 
| 
      
 242 
     | 
    
         
            +
             
     | 
| 
      
 243 
     | 
    
         
            +
              def self.md5 path #:nodoc:
         
     | 
| 
      
 244 
     | 
    
         
            +
                `#{MD5} #{path}`[0...8]
         
     | 
| 
      
 245 
     | 
    
         
            +
              end
         
     | 
| 
      
 246 
     | 
    
         
            +
             
     | 
| 
      
 247 
     | 
    
         
            +
             
     | 
| 
      
 248 
     | 
    
         
            +
              ##
         
     | 
| 
      
 249 
     | 
    
         
            +
              # Define a Gin::Controller as a catch-all error rendering controller.
         
     | 
| 
      
 250 
     | 
    
         
            +
              # This can be a dedicated controller, or a parent controller
         
     | 
| 
      
 251 
     | 
    
         
            +
              # such as AppController. Defaults to Gin::Controller.
         
     | 
| 
      
 252 
     | 
    
         
            +
              #
         
     | 
| 
      
 253 
     | 
    
         
            +
              # The error delegate should handle the following errors
         
     | 
| 
      
 254 
     | 
    
         
            +
              # for creating custom pages for Gin errors:
         
     | 
| 
      
 255 
     | 
    
         
            +
              #   Gin::NotFound, Gin::BadRequest, ::Exception
         
     | 
| 
      
 256 
     | 
    
         
            +
             
     | 
| 
      
 257 
     | 
    
         
            +
              def self.error_delegate ctrl=nil
         
     | 
| 
      
 258 
     | 
    
         
            +
                @error_delegate = ctrl if ctrl
         
     | 
| 
      
 259 
     | 
    
         
            +
                @error_delegate ||= Gin::Controller
         
     | 
| 
      
 260 
     | 
    
         
            +
              end
         
     | 
| 
      
 261 
     | 
    
         
            +
             
     | 
| 
      
 262 
     | 
    
         
            +
             
     | 
| 
      
 263 
     | 
    
         
            +
              ##
         
     | 
| 
      
 264 
     | 
    
         
            +
              # Router instance that handles mapping Rack-env -> Controller#action.
         
     | 
| 
      
 265 
     | 
    
         
            +
             
     | 
| 
      
 266 
     | 
    
         
            +
              def self.router
         
     | 
| 
      
 267 
     | 
    
         
            +
                @router ||= Gin::Router.new
         
     | 
| 
      
 268 
     | 
    
         
            +
              end
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
      
 270 
     | 
    
         
            +
             
     | 
| 
      
 271 
     | 
    
         
            +
              ##
         
     | 
| 
      
 272 
     | 
    
         
            +
              # Lookup or register a mime type in Rack's mime registry.
         
     | 
| 
      
 273 
     | 
    
         
            +
             
     | 
| 
      
 274 
     | 
    
         
            +
              def self.mime_type type, value=nil
         
     | 
| 
      
 275 
     | 
    
         
            +
                return type if type.nil? || type.to_s.include?('/')
         
     | 
| 
      
 276 
     | 
    
         
            +
                type = ".#{type}" unless type.to_s[0] == ?.
         
     | 
| 
      
 277 
     | 
    
         
            +
                return Rack::Mime.mime_type(type, nil) unless value
         
     | 
| 
      
 278 
     | 
    
         
            +
                Rack::Mime::MIME_TYPES[type] = value
         
     | 
| 
      
 279 
     | 
    
         
            +
              end
         
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
      
 281 
     | 
    
         
            +
             
     | 
| 
      
 282 
     | 
    
         
            +
              ##
         
     | 
| 
      
 283 
     | 
    
         
            +
              # Provides all mime types matching type, including deprecated types:
         
     | 
| 
      
 284 
     | 
    
         
            +
              #   mime_types :html # => ['text/html']
         
     | 
| 
      
 285 
     | 
    
         
            +
              #   mime_types :js   # => ['application/javascript', 'text/javascript']
         
     | 
| 
      
 286 
     | 
    
         
            +
             
     | 
| 
      
 287 
     | 
    
         
            +
              def self.mime_types type
         
     | 
| 
      
 288 
     | 
    
         
            +
                type = mime_type type
         
     | 
| 
      
 289 
     | 
    
         
            +
                type =~ /^application\/(xml|javascript)$/ ? [type, "text/#$1"] : [type]
         
     | 
| 
      
 290 
     | 
    
         
            +
              end
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
             
     | 
| 
      
 293 
     | 
    
         
            +
              ##
         
     | 
| 
      
 294 
     | 
    
         
            +
              # Add middleware internally to the app.
         
     | 
| 
      
 295 
     | 
    
         
            +
              # Middleware statuses and Exceptions will NOT be
         
     | 
| 
      
 296 
     | 
    
         
            +
              # handled by the error_delegate.
         
     | 
| 
      
 297 
     | 
    
         
            +
             
     | 
| 
      
 298 
     | 
    
         
            +
              def self.use middleware, *args, &block
         
     | 
| 
      
 299 
     | 
    
         
            +
                ary = [middleware, *args]
         
     | 
| 
      
 300 
     | 
    
         
            +
                ary << block if block_given?
         
     | 
| 
      
 301 
     | 
    
         
            +
                self.middleware << ary
         
     | 
| 
      
 302 
     | 
    
         
            +
              end
         
     | 
| 
      
 303 
     | 
    
         
            +
             
     | 
| 
      
 304 
     | 
    
         
            +
             
     | 
| 
      
 305 
     | 
    
         
            +
              ##
         
     | 
| 
      
 306 
     | 
    
         
            +
              # List of internal app middleware.
         
     | 
| 
      
 307 
     | 
    
         
            +
             
     | 
| 
      
 308 
     | 
    
         
            +
              def self.middleware
         
     | 
| 
      
 309 
     | 
    
         
            +
                @middleware ||= []
         
     | 
| 
      
 310 
     | 
    
         
            +
              end
         
     | 
| 
      
 311 
     | 
    
         
            +
             
     | 
| 
      
 312 
     | 
    
         
            +
             
     | 
| 
      
 313 
     | 
    
         
            +
              ##
         
     | 
| 
      
 314 
     | 
    
         
            +
              # Use rack sessions or not. Supports assigning
         
     | 
| 
      
 315 
     | 
    
         
            +
              # hash for options. Defaults to true.
         
     | 
| 
      
 316 
     | 
    
         
            +
             
     | 
| 
      
 317 
     | 
    
         
            +
              def self.sessions opts=nil
         
     | 
| 
      
 318 
     | 
    
         
            +
                @session = opts unless opts.nil?
         
     | 
| 
      
 319 
     | 
    
         
            +
                @session = true if @session.nil?
         
     | 
| 
      
 320 
     | 
    
         
            +
                @session
         
     | 
| 
      
 321 
     | 
    
         
            +
              end
         
     | 
| 
      
 322 
     | 
    
         
            +
             
     | 
| 
      
 323 
     | 
    
         
            +
             
     | 
| 
      
 324 
     | 
    
         
            +
              ##
         
     | 
| 
      
 325 
     | 
    
         
            +
              # Get or set the session secret String.
         
     | 
| 
      
 326 
     | 
    
         
            +
              # Defaults to a new random value on boot.
         
     | 
| 
      
 327 
     | 
    
         
            +
             
     | 
| 
      
 328 
     | 
    
         
            +
              def self.session_secret val=nil
         
     | 
| 
      
 329 
     | 
    
         
            +
                @session_secret = val if val
         
     | 
| 
      
 330 
     | 
    
         
            +
                @session_secret ||= "%064x" % Kernel.rand(2**256-1)
         
     | 
| 
      
 331 
     | 
    
         
            +
              end
         
     | 
| 
      
 332 
     | 
    
         
            +
             
     | 
| 
      
 333 
     | 
    
         
            +
             
     | 
| 
      
 334 
     | 
    
         
            +
              ##
         
     | 
| 
      
 335 
     | 
    
         
            +
              # Use rack-protection or not. Supports assigning
         
     | 
| 
      
 336 
     | 
    
         
            +
              # hash for options. Defaults to true.
         
     | 
| 
      
 337 
     | 
    
         
            +
             
     | 
| 
      
 338 
     | 
    
         
            +
              def self.protection opts=nil
         
     | 
| 
      
 339 
     | 
    
         
            +
                @protection = opts unless opts.nil?
         
     | 
| 
      
 340 
     | 
    
         
            +
                @protection = true if @protection.nil?
         
     | 
| 
      
 341 
     | 
    
         
            +
                @protection
         
     | 
| 
      
 342 
     | 
    
         
            +
              end
         
     | 
| 
      
 343 
     | 
    
         
            +
             
     | 
| 
      
 344 
     | 
    
         
            +
             
     | 
| 
      
 345 
     | 
    
         
            +
              ##
         
     | 
| 
      
 346 
     | 
    
         
            +
              # Get or set the current environment name,
         
     | 
| 
      
 347 
     | 
    
         
            +
              # by default ENV ['RACK_ENV'], or "development".
         
     | 
| 
      
 348 
     | 
    
         
            +
             
     | 
| 
      
 349 
     | 
    
         
            +
              def self.environment env=nil
         
     | 
| 
      
 350 
     | 
    
         
            +
                @environment = env if env
         
     | 
| 
      
 351 
     | 
    
         
            +
                @environment ||= ENV['RACK_ENV'] || "development"
         
     | 
| 
      
 352 
     | 
    
         
            +
              end
         
     | 
| 
      
 353 
     | 
    
         
            +
             
     | 
| 
      
 354 
     | 
    
         
            +
             
     | 
| 
      
 355 
     | 
    
         
            +
              ##
         
     | 
| 
      
 356 
     | 
    
         
            +
              # Check if running in development mode.
         
     | 
| 
      
 357 
     | 
    
         
            +
             
     | 
| 
      
 358 
     | 
    
         
            +
              def self.development?
         
     | 
| 
      
 359 
     | 
    
         
            +
                self.environment == "development"
         
     | 
| 
      
 360 
     | 
    
         
            +
              end
         
     | 
| 
      
 361 
     | 
    
         
            +
             
     | 
| 
      
 362 
     | 
    
         
            +
             
     | 
| 
      
 363 
     | 
    
         
            +
              ##
         
     | 
| 
      
 364 
     | 
    
         
            +
              # Check if running in test mode.
         
     | 
| 
      
 365 
     | 
    
         
            +
             
     | 
| 
      
 366 
     | 
    
         
            +
              def self.test?
         
     | 
| 
      
 367 
     | 
    
         
            +
                self.environment == "test"
         
     | 
| 
      
 368 
     | 
    
         
            +
              end
         
     | 
| 
      
 369 
     | 
    
         
            +
             
     | 
| 
      
 370 
     | 
    
         
            +
             
     | 
| 
      
 371 
     | 
    
         
            +
              ##
         
     | 
| 
      
 372 
     | 
    
         
            +
              # Check if running in staging mode.
         
     | 
| 
      
 373 
     | 
    
         
            +
             
     | 
| 
      
 374 
     | 
    
         
            +
              def self.staging?
         
     | 
| 
      
 375 
     | 
    
         
            +
                self.environment == "staging"
         
     | 
| 
      
 376 
     | 
    
         
            +
              end
         
     | 
| 
      
 377 
     | 
    
         
            +
             
     | 
| 
      
 378 
     | 
    
         
            +
             
     | 
| 
      
 379 
     | 
    
         
            +
              ##
         
     | 
| 
      
 380 
     | 
    
         
            +
              # Check if running in production mode.
         
     | 
| 
      
 381 
     | 
    
         
            +
             
     | 
| 
      
 382 
     | 
    
         
            +
              def self.production?
         
     | 
| 
      
 383 
     | 
    
         
            +
                self.environment == "production"
         
     | 
| 
      
 384 
     | 
    
         
            +
              end
         
     | 
| 
      
 385 
     | 
    
         
            +
             
     | 
| 
      
 386 
     | 
    
         
            +
             
     | 
| 
      
 387 
     | 
    
         
            +
              class_proxy :protection, :sessions, :session_secret, :middleware, :autoreload
         
     | 
| 
      
 388 
     | 
    
         
            +
              class_proxy :error_delegate, :router
         
     | 
| 
      
 389 
     | 
    
         
            +
              class_proxy :root_dir, :public_dir
         
     | 
| 
      
 390 
     | 
    
         
            +
              class_proxy :mime_type, :asset_host_for, :asset_host, :asset_version
         
     | 
| 
      
 391 
     | 
    
         
            +
              class_proxy :environment, :development?, :test?, :staging?, :production?
         
     | 
| 
      
 392 
     | 
    
         
            +
              class_proxy :load_config, :config, :config_dir
         
     | 
| 
      
 393 
     | 
    
         
            +
             
     | 
| 
      
 394 
     | 
    
         
            +
              # Application logger. Defaults to log to $stdout.
         
     | 
| 
      
 395 
     | 
    
         
            +
              attr_accessor :logger
         
     | 
| 
      
 396 
     | 
    
         
            +
             
     | 
| 
      
 397 
     | 
    
         
            +
              # App to fallback on if Gin::App is used as middleware and no route is found.
         
     | 
| 
      
 398 
     | 
    
         
            +
              attr_reader :rack_app
         
     | 
| 
      
 399 
     | 
    
         
            +
             
     | 
| 
      
 400 
     | 
    
         
            +
              # Internal Rack stack.
         
     | 
| 
      
 401 
     | 
    
         
            +
              attr_reader :stack
         
     | 
| 
      
 402 
     | 
    
         
            +
             
     | 
| 
      
 403 
     | 
    
         
            +
             
     | 
| 
      
 404 
     | 
    
         
            +
              ##
         
     | 
| 
      
 405 
     | 
    
         
            +
              # Create a new Rack-mountable Gin::App instance, with an optional
         
     | 
| 
      
 406 
     | 
    
         
            +
              # rack_app and logger.
         
     | 
| 
      
 407 
     | 
    
         
            +
             
     | 
| 
      
 408 
     | 
    
         
            +
              def initialize rack_app=nil, logger=nil
         
     | 
| 
      
 409 
     | 
    
         
            +
                load_config
         
     | 
| 
      
 410 
     | 
    
         
            +
             
     | 
| 
      
 411 
     | 
    
         
            +
                if !rack_app.respond_to?(:call) && rack_app.respond_to?(:log) && logger.nil?
         
     | 
| 
      
 412 
     | 
    
         
            +
                  @rack_app = nil
         
     | 
| 
      
 413 
     | 
    
         
            +
                  @logger   = rack_app
         
     | 
| 
      
 414 
     | 
    
         
            +
                else
         
     | 
| 
      
 415 
     | 
    
         
            +
                  @rack_app = rack_app
         
     | 
| 
      
 416 
     | 
    
         
            +
                  @logger   = Logger.new $stdout
         
     | 
| 
      
 417 
     | 
    
         
            +
                end
         
     | 
| 
      
 418 
     | 
    
         
            +
             
     | 
| 
      
 419 
     | 
    
         
            +
                validate_all_controllers!
         
     | 
| 
      
 420 
     | 
    
         
            +
             
     | 
| 
      
 421 
     | 
    
         
            +
                @app   = self
         
     | 
| 
      
 422 
     | 
    
         
            +
                @stack = build_app Rack::Builder.new
         
     | 
| 
      
 423 
     | 
    
         
            +
              end
         
     | 
| 
      
 424 
     | 
    
         
            +
             
     | 
| 
      
 425 
     | 
    
         
            +
             
     | 
| 
      
 426 
     | 
    
         
            +
              ##
         
     | 
| 
      
 427 
     | 
    
         
            +
              # Used for auto reloading the whole app in development mode.
         
     | 
| 
      
 428 
     | 
    
         
            +
              # Will only reload if Gin::App.autoreload is set to true.
         
     | 
| 
      
 429 
     | 
    
         
            +
              #
         
     | 
| 
      
 430 
     | 
    
         
            +
              # If you use this in production, you're gonna have a bad time.
         
     | 
| 
      
 431 
     | 
    
         
            +
             
     | 
| 
      
 432 
     | 
    
         
            +
              def reload!
         
     | 
| 
      
 433 
     | 
    
         
            +
                return unless autoreload
         
     | 
| 
      
 434 
     | 
    
         
            +
                self.class.erase! [self.class.source_file],
         
     | 
| 
      
 435 
     | 
    
         
            +
                                  [self.class.name.split("::").last],
         
     | 
| 
      
 436 
     | 
    
         
            +
                                  self.class.namespace
         
     | 
| 
      
 437 
     | 
    
         
            +
             
     | 
| 
      
 438 
     | 
    
         
            +
                self.class.erase_dependencies!
         
     | 
| 
      
 439 
     | 
    
         
            +
                Object.send(:require, self.class.source_file)
         
     | 
| 
      
 440 
     | 
    
         
            +
                @app = self.class.source_class.new @rack_app, @logger
         
     | 
| 
      
 441 
     | 
    
         
            +
              end
         
     | 
| 
      
 442 
     | 
    
         
            +
             
     | 
| 
      
 443 
     | 
    
         
            +
             
     | 
| 
      
 444 
     | 
    
         
            +
              ##
         
     | 
| 
      
 445 
     | 
    
         
            +
              # Default Rack call method.
         
     | 
| 
      
 446 
     | 
    
         
            +
             
     | 
| 
      
 447 
     | 
    
         
            +
              def call env
         
     | 
| 
      
 448 
     | 
    
         
            +
                if filename = static?(env)
         
     | 
| 
      
 449 
     | 
    
         
            +
                  return error_delegate.exec(self, env){ send_file filename }
         
     | 
| 
      
 450 
     | 
    
         
            +
                end
         
     | 
| 
      
 451 
     | 
    
         
            +
             
     | 
| 
      
 452 
     | 
    
         
            +
                if autoreload && !env[RACK_KEYS[:reloaded]]
         
     | 
| 
      
 453 
     | 
    
         
            +
                  env[RACK_KEYS[:reloaded]] = true
         
     | 
| 
      
 454 
     | 
    
         
            +
                  reload!
         
     | 
| 
      
 455 
     | 
    
         
            +
                  @app.call env
         
     | 
| 
      
 456 
     | 
    
         
            +
             
     | 
| 
      
 457 
     | 
    
         
            +
                elsif env[RACK_KEYS[:stack]]
         
     | 
| 
      
 458 
     | 
    
         
            +
                  env.delete RACK_KEYS[:stack]
         
     | 
| 
      
 459 
     | 
    
         
            +
                  @app.call! env
         
     | 
| 
      
 460 
     | 
    
         
            +
             
     | 
| 
      
 461 
     | 
    
         
            +
                else
         
     | 
| 
      
 462 
     | 
    
         
            +
                  env[RACK_KEYS[:stack]] = true
         
     | 
| 
      
 463 
     | 
    
         
            +
                  @stack.call env
         
     | 
| 
      
 464 
     | 
    
         
            +
                end
         
     | 
| 
      
 465 
     | 
    
         
            +
              end
         
     | 
| 
      
 466 
     | 
    
         
            +
             
     | 
| 
      
 467 
     | 
    
         
            +
             
     | 
| 
      
 468 
     | 
    
         
            +
              ##
         
     | 
| 
      
 469 
     | 
    
         
            +
              # Call App instance without internal middleware or reloading.
         
     | 
| 
      
 470 
     | 
    
         
            +
             
     | 
| 
      
 471 
     | 
    
         
            +
              def call! env
         
     | 
| 
      
 472 
     | 
    
         
            +
                ctrl, action, env[RACK_KEYS[:path_params]] =
         
     | 
| 
      
 473 
     | 
    
         
            +
                  router.resources_for env['REQUEST_METHOD'], env['PATH_INFO']
         
     | 
| 
      
 474 
     | 
    
         
            +
             
     | 
| 
      
 475 
     | 
    
         
            +
                dispatch env, ctrl, action
         
     | 
| 
      
 476 
     | 
    
         
            +
              end
         
     | 
| 
      
 477 
     | 
    
         
            +
             
     | 
| 
      
 478 
     | 
    
         
            +
             
     | 
| 
      
 479 
     | 
    
         
            +
              STATIC_PATH_CLEANER = %r{\.+/|/\.+}  #:nodoc:
         
     | 
| 
      
 480 
     | 
    
         
            +
             
     | 
| 
      
 481 
     | 
    
         
            +
              ##
         
     | 
| 
      
 482 
     | 
    
         
            +
              # Check if the request is for a static file.
         
     | 
| 
      
 483 
     | 
    
         
            +
             
     | 
| 
      
 484 
     | 
    
         
            +
              def static? env
         
     | 
| 
      
 485 
     | 
    
         
            +
                %w{GET HEAD}.include?(env['REQUEST_METHOD']) && asset(env['PATH_INFO'])
         
     | 
| 
      
 486 
     | 
    
         
            +
              end
         
     | 
| 
      
 487 
     | 
    
         
            +
             
     | 
| 
      
 488 
     | 
    
         
            +
             
     | 
| 
      
 489 
     | 
    
         
            +
              ##
         
     | 
| 
      
 490 
     | 
    
         
            +
              # Check if an asset exists.
         
     | 
| 
      
 491 
     | 
    
         
            +
              # Returns the full path to the asset if found, otherwise nil.
         
     | 
| 
      
 492 
     | 
    
         
            +
             
     | 
| 
      
 493 
     | 
    
         
            +
              def asset path
         
     | 
| 
      
 494 
     | 
    
         
            +
                path = path.gsub STATIC_PATH_CLEANER, ""
         
     | 
| 
      
 495 
     | 
    
         
            +
             
     | 
| 
      
 496 
     | 
    
         
            +
                filepath = File.expand_path(File.join(public_dir, path))
         
     | 
| 
      
 497 
     | 
    
         
            +
                return filepath if File.file? filepath
         
     | 
| 
      
 498 
     | 
    
         
            +
             
     | 
| 
      
 499 
     | 
    
         
            +
                filepath = File.expand_path(File.join(Gin::PUBLIC_DIR, path))
         
     | 
| 
      
 500 
     | 
    
         
            +
                return filepath if File.file? filepath
         
     | 
| 
      
 501 
     | 
    
         
            +
              end
         
     | 
| 
      
 502 
     | 
    
         
            +
             
     | 
| 
      
 503 
     | 
    
         
            +
             
     | 
| 
      
 504 
     | 
    
         
            +
              ##
         
     | 
| 
      
 505 
     | 
    
         
            +
              # Dispatch the Rack env to the given controller and action.
         
     | 
| 
      
 506 
     | 
    
         
            +
             
     | 
| 
      
 507 
     | 
    
         
            +
              def dispatch env, ctrl, action
         
     | 
| 
      
 508 
     | 
    
         
            +
                raise Gin::NotFound,
         
     | 
| 
      
 509 
     | 
    
         
            +
                  "No route exists for: #{env['REQUEST_METHOD']} #{env['PATH_INFO']}" unless
         
     | 
| 
      
 510 
     | 
    
         
            +
                  ctrl && action
         
     | 
| 
      
 511 
     | 
    
         
            +
             
     | 
| 
      
 512 
     | 
    
         
            +
                ctrl.new(self, env).call_action action
         
     | 
| 
      
 513 
     | 
    
         
            +
             
     | 
| 
      
 514 
     | 
    
         
            +
              rescue Gin::NotFound => err
         
     | 
| 
      
 515 
     | 
    
         
            +
                @rack_app ? @rack_app.call(env) : handle_error(err, env)
         
     | 
| 
      
 516 
     | 
    
         
            +
             
     | 
| 
      
 517 
     | 
    
         
            +
              rescue ::Exception => err
         
     | 
| 
      
 518 
     | 
    
         
            +
                handle_error(err, env)
         
     | 
| 
      
 519 
     | 
    
         
            +
              end
         
     | 
| 
      
 520 
     | 
    
         
            +
             
     | 
| 
      
 521 
     | 
    
         
            +
             
     | 
| 
      
 522 
     | 
    
         
            +
              ##
         
     | 
| 
      
 523 
     | 
    
         
            +
              # Handle error with error_delegate if available, otherwise re-raise.
         
     | 
| 
      
 524 
     | 
    
         
            +
             
     | 
| 
      
 525 
     | 
    
         
            +
              def handle_error err, env
         
     | 
| 
      
 526 
     | 
    
         
            +
                delegate = error_delegate
         
     | 
| 
      
 527 
     | 
    
         
            +
             
     | 
| 
      
 528 
     | 
    
         
            +
                begin
         
     | 
| 
      
 529 
     | 
    
         
            +
                  trace = Gin.app_trace(Array(err.backtrace)).join("\n")
         
     | 
| 
      
 530 
     | 
    
         
            +
                  logger.error("#{err.class.name}: #{err.message}\n#{trace}")
         
     | 
| 
      
 531 
     | 
    
         
            +
                  delegate.exec(self, env){ handle_error(err) }
         
     | 
| 
      
 532 
     | 
    
         
            +
             
     | 
| 
      
 533 
     | 
    
         
            +
                rescue ::Exception => err
         
     | 
| 
      
 534 
     | 
    
         
            +
                  delegate = Gin::Controller and retry unless delegate == Gin::Controller
         
     | 
| 
      
 535 
     | 
    
         
            +
                  raise
         
     | 
| 
      
 536 
     | 
    
         
            +
                end
         
     | 
| 
      
 537 
     | 
    
         
            +
              end
         
     | 
| 
      
 538 
     | 
    
         
            +
             
     | 
| 
      
 539 
     | 
    
         
            +
             
     | 
| 
      
 540 
     | 
    
         
            +
              private
         
     | 
| 
      
 541 
     | 
    
         
            +
             
     | 
| 
      
 542 
     | 
    
         
            +
             
     | 
| 
      
 543 
     | 
    
         
            +
              def build_app builder
         
     | 
| 
      
 544 
     | 
    
         
            +
                setup_sessions   builder
         
     | 
| 
      
 545 
     | 
    
         
            +
                setup_protection builder
         
     | 
| 
      
 546 
     | 
    
         
            +
                middleware.each do |args|
         
     | 
| 
      
 547 
     | 
    
         
            +
                  block = args.pop if Proc === args.last
         
     | 
| 
      
 548 
     | 
    
         
            +
                  builder.use(*args, &block)
         
     | 
| 
      
 549 
     | 
    
         
            +
                end
         
     | 
| 
      
 550 
     | 
    
         
            +
             
     | 
| 
      
 551 
     | 
    
         
            +
                builder.run self
         
     | 
| 
      
 552 
     | 
    
         
            +
                builder.to_app
         
     | 
| 
      
 553 
     | 
    
         
            +
              end
         
     | 
| 
      
 554 
     | 
    
         
            +
             
     | 
| 
      
 555 
     | 
    
         
            +
             
     | 
| 
      
 556 
     | 
    
         
            +
              def setup_sessions builder
         
     | 
| 
      
 557 
     | 
    
         
            +
                return unless sessions
         
     | 
| 
      
 558 
     | 
    
         
            +
                options = {}
         
     | 
| 
      
 559 
     | 
    
         
            +
                options[:secret] = session_secret if session_secret
         
     | 
| 
      
 560 
     | 
    
         
            +
                options.merge! sessions.to_hash if sessions.respond_to? :to_hash
         
     | 
| 
      
 561 
     | 
    
         
            +
                builder.use Rack::Session::Cookie, options
         
     | 
| 
      
 562 
     | 
    
         
            +
              end
         
     | 
| 
      
 563 
     | 
    
         
            +
             
     | 
| 
      
 564 
     | 
    
         
            +
             
     | 
| 
      
 565 
     | 
    
         
            +
              def setup_protection builder
         
     | 
| 
      
 566 
     | 
    
         
            +
                return unless protection
         
     | 
| 
      
 567 
     | 
    
         
            +
                options = Hash === protection ? protection.dup : {}
         
     | 
| 
      
 568 
     | 
    
         
            +
                options[:except] = Array options[:except]
         
     | 
| 
      
 569 
     | 
    
         
            +
                options[:except] += [:session_hijacking, :remote_token] unless sessions
         
     | 
| 
      
 570 
     | 
    
         
            +
                options[:reaction] ||= :drop_session
         
     | 
| 
      
 571 
     | 
    
         
            +
                builder.use Rack::Protection, options
         
     | 
| 
      
 572 
     | 
    
         
            +
              end
         
     | 
| 
      
 573 
     | 
    
         
            +
             
     | 
| 
      
 574 
     | 
    
         
            +
             
     | 
| 
      
 575 
     | 
    
         
            +
              ##
         
     | 
| 
      
 576 
     | 
    
         
            +
              # Make sure all controller actions have a route, or raise a RouterError.
         
     | 
| 
      
 577 
     | 
    
         
            +
             
     | 
| 
      
 578 
     | 
    
         
            +
              def validate_all_controllers!
         
     | 
| 
      
 579 
     | 
    
         
            +
                actions = {}
         
     | 
| 
      
 580 
     | 
    
         
            +
             
     | 
| 
      
 581 
     | 
    
         
            +
                router.each_route do |route, ctrl, action|
         
     | 
| 
      
 582 
     | 
    
         
            +
                  (actions[ctrl] ||= []) << action
         
     | 
| 
      
 583 
     | 
    
         
            +
                end
         
     | 
| 
      
 584 
     | 
    
         
            +
             
     | 
| 
      
 585 
     | 
    
         
            +
                actions.each do |ctrl, actions|
         
     | 
| 
      
 586 
     | 
    
         
            +
                  not_mounted   = ctrl.actions - actions
         
     | 
| 
      
 587 
     | 
    
         
            +
                  raise RouterError, "#{ctrl}##{not_mounted[0]} has no route." unless
         
     | 
| 
      
 588 
     | 
    
         
            +
                    not_mounted.empty?
         
     | 
| 
      
 589 
     | 
    
         
            +
             
     | 
| 
      
 590 
     | 
    
         
            +
                  extra_mounted = actions - ctrl.actions
         
     | 
| 
      
 591 
     | 
    
         
            +
                  raise RouterError, "#{ctrl}##{extra_mounted[0]} is not a method" unless
         
     | 
| 
      
 592 
     | 
    
         
            +
                    extra_mounted.empty?
         
     | 
| 
      
 593 
     | 
    
         
            +
                end
         
     | 
| 
      
 594 
     | 
    
         
            +
              end
         
     | 
| 
      
 595 
     | 
    
         
            +
            end
         
     |