Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Changeset 8082

Show
Ignore:
Timestamp:
11/06/07 08:09:39 (8 months ago)
Author:
nzkoz
Message:

Minor documentation enhancements and white-space fixes. Closes #9819 [chuyeow]

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/actionpack/lib/action_controller/routing.rb

    r7849 r8082  
    3232    Regexp.new("|#{source}").match('').captures.length 
    3333  end 
    34    
     34 
    3535  class << self 
    3636    def optionalize(pattern) 
     
    4040      end 
    4141    end 
    42      
     42 
    4343    def unoptionalize(pattern) 
    4444      [/\A\(\?:(.*)\)\?\Z/, /\A(.|\(.*\))\?\Z/].each do |regexp| 
     
    5151 
    5252module ActionController 
    53   # == Routing  
     53  # == Routing 
    5454  # 
    5555  # The routing module provides URL rewriting in native Ruby. It's a way to 
    5656  # redirect incoming requests to controllers and actions. This replaces 
    57   # mod_rewrite rules. Best of all Rails' Routing works with any web server.  
     57  # mod_rewrite rules. Best of all, Rails' Routing works with any web server. 
    5858  # Routes are defined in routes.rb in your RAILS_ROOT/config directory. 
    5959  # 
    60   # Consider the following route, installed by Rails when you generate your  
     60  # Consider the following route, installed by Rails when you generate your 
    6161  # application: 
    6262  # 
    6363  #   map.connect ':controller/:action/:id' 
    6464  # 
    65   # This route states that it expects requests to consist of a  
    66   # :controller followed by an :action that in turns is fed by some :id  
    67   # 
    68   # Suppose you get an incoming request for <tt>/blog/edit/22</tt>, you'll end up  
     65  # This route states that it expects requests to consist of a 
     66  # :controller followed by an :action that in turn is fed some :id. 
     67  # 
     68  # Suppose you get an incoming request for <tt>/blog/edit/22</tt>, you'll end up 
    6969  # with: 
    7070  # 
    7171  #   params = { :controller => 'blog', 
    72   #              :action     => 'edit'  
     72  #              :action     => 'edit', 
    7373  #              :id         => '22' 
    7474  #           } 
    7575  # 
    76   # Think of creating routes as drawing a map for your requests. The map tells  
     76  # Think of creating routes as drawing a map for your requests. The map tells 
    7777  # them where to go based on some predefined pattern: 
    7878  # 
     
    8787  #   :controller maps to your controller name 
    8888  #   :action     maps to an action with your controllers 
    89   #    
     89  # 
    9090  # Other names simply map to a parameter as in the case of +:id+. 
    91   #     
     91  # 
    9292  # == Route priority 
    9393  # 
    94   # Not all routes are created equally. Routes have priority defined by the  
     94  # Not all routes are created equally. Routes have priority defined by the 
    9595  # order of appearance of the routes in the routes.rb file. The priority goes 
    9696  # from top to bottom. The last route in that file is at the lowest priority 
    97   # will be applied last. If no route matches, 404 is returned. 
    98   # 
    99   # Within blocks, the empty pattern goes first i.e. is at the highest priority. 
     97  # and will be applied last. If no route matches, 404 is returned. 
     98  # 
     99  # Within blocks, the empty pattern is at the highest priority. 
    100100  # In practice this works out nicely: 
    101101  # 
    102   #  ActionController::Routing::Routes.draw do |map|  
     102  #  ActionController::Routing::Routes.draw do |map| 
    103103  #    map.with_options :controller => 'blog' do |blog| 
    104   #      blog.show    '',  :action => 'list' 
     104  #      blog.show '',  :action => 'list' 
    105105  #    end 
    106   #    map.connect ':controller/:action/:view  
     106  #    map.connect ':controller/:action/:view' 
    107107  #  end 
    108108  # 
    109   # In this case, invoking blog controller (with an URL like '/blog/')  
     109  # In this case, invoking blog controller (with an URL like '/blog/') 
    110110  # without parameters will activate the 'list' action by default. 
    111111  # 
    112112  # == Defaults routes and default parameters 
    113113  # 
    114   # Setting a default route is straightforward in Rails because by appending
    115   # Hash to the end of your mapping you can set default parameters. 
     114  # Setting a default route is straightforward in Rails - you simply append
     115  # Hash at the end of your mapping to set any default parameters. 
    116116  # 
    117117  # Example: 
     
    120120  #  end 
    121121  # 
    122   # This sets up +blog+ as the default controller if no other is specified.  
     122  # This sets up +blog+ as the default controller if no other is specified. 
    123123  # This means visiting '/' would invoke the blog controller. 
    124124  # 
    125125  # More formally, you can define defaults in a route with the +:defaults+ key. 
    126   #    
    127   #   map.connect ':controller/:id/:action', :action => 'show', :defaults => { :page => 'Dashboard' } 
     126  # 
     127  #   map.connect ':controller/:action/:id', :action => 'show', :defaults => { :page => 'Dashboard' } 
    128128  # 
    129129  # == Named routes 
     
    144144  #   redirect_to show_item_path(:id => 25) 
    145145  # 
    146   # Use <tt>map.root</tt> as a shorthand to name a route for the root path "" 
     146  # Use <tt>map.root</tt> as a shorthand to name a route for the root path "". 
    147147  # 
    148148  #   # In routes.rb 
     
    167167  # 
    168168  #   # provides named routes for show, delete, and edit 
    169   #   link_to @article.title, show_path(:id => @article.id)  
     169  #   link_to @article.title, show_path(:id => @article.id) 
    170170  # 
    171171  # == Pretty URLs 
     
    174174  # 
    175175  #  map.connect 'articles/:year/:month/:day', 
    176   #              :controller => 'articles',  
     176  #              :controller => 'articles', 
    177177  #              :action     => 'find_by_date', 
    178178  #              :year       => /\d{4}/, 
    179   #              :month => /\d{1,2}/,  
    180   #              :day   => /\d{1,2}/ 
    181   #   
     179  #              :month      => /\d{1,2}/, 
     180  #              :day        => /\d{1,2}/ 
     181  # 
    182182  #  # Using the route above, the url below maps to: 
    183183  #  # params = {:year => '2005', :month => '11', :day => '06'} 
     
    185185  # 
    186186  # == Regular Expressions and parameters 
    187   # You can specify a reqular expression to define a format for a parameter. 
     187  # You can specify a regular expression to define a format for a parameter. 
    188188  # 
    189189  #  map.geocode 'geocode/:postalcode', :controller => 'geocode', 
     
    192192  # or, more formally: 
    193193  # 
    194   #   map.geocode 'geocode/:postalcode', :controller => 'geocode',  
     194  #   map.geocode 'geocode/:postalcode', :controller => 'geocode', 
    195195  #               :action => 'show', :requirements => { :postalcode => /\d{5}(-\d{4})?/ } 
    196196  # 
     
    219219  # 
    220220  # === +assert_routing+ 
    221   #  
     221  # 
    222222  #  def test_movie_route_properly_splits 
    223223  #   opts = {:controller => "plugin", :action => "checkout", :id => "2"} 
    224224  #   assert_routing "plugin/checkout/2", opts 
    225225  #  end 
    226   #   
     226  # 
    227227  # +assert_routing+ lets you test whether or not the route properly resolves into options. 
    228228  # 
     
    231231  #  def test_route_has_options 
    232232  #   opts = {:controller => "plugin", :action => "show", :id => "12"} 
    233   #   assert_recognizes opts, "/plugins/show/12"  
     233  #   assert_recognizes opts, "/plugins/show/12" 
    234234  #  end 
    235   #  
     235  # 
    236236  # Note the subtle difference between the two: +assert_routing+ tests that 
    237   # an URL fits options while +assert_recognizes+ tests that an URL 
     237  # a URL fits options while +assert_recognizes+ tests that a URL 
    238238  # breaks into parameters properly. 
    239239  # 
     
    259259    mattr_accessor :controller_paths 
    260260    self.controller_paths = [] 
    261      
     261 
    262262    # A helper module to hold URL related helpers. 
    263263    module Helpers 
    264264      include PolymorphicRoutes 
    265265    end 
    266      
     266 
    267267    class << self 
    268268      def with_controllers(names) 
     
    295295        unless @possible_controllers 
    296296          @possible_controllers = [] 
    297          
     297 
    298298          paths = controller_paths.select { |path| File.directory?(path) && path != "." } 
    299299 
     
    302302            Dir["#{load_path}/**/*_controller.rb"].collect do |path| 
    303303              next if seen_paths[path.gsub(%r{^\.[/\\]}, "")] 
    304                
     304 
    305305              controller_name = path[(load_path.length + 1)..-1] 
    306                
     306 
    307307              controller_name.gsub!(/_controller\.rb\Z/, '') 
    308308              @possible_controllers << controller_name 
     
    325325        elsif %r{^(.*)/} =~ previous then "#{$1}/#{controller}" 
    326326        else controller 
    327         end      
    328       end      
     327        end 
     328      end 
    329329    end 
    330    
     330 
    331331    class Route #:nodoc: 
    332332      attr_accessor :segments, :requirements, :conditions, :optimise 
    333        
     333 
    334334      def initialize 
    335335        @segments = [] 
     
    337337        @conditions = {} 
    338338      end 
    339        
     339 
    340340      # Indicates whether the routes should be optimised with the string interpolation 
    341341      # version of the named routes methods. 
     
    343343        @optimise && ActionController::Base::optimise_named_routes 
    344344      end 
    345        
     345 
    346346      def segment_keys 
    347347        segments.collect do |segment| 
     
    349349        end.compact 
    350350      end 
    351    
     351 
    352352      # Write and compile a +generate+ method for this Route. 
    353353      def write_generation 
    354354        # Build the main body of the generation 
    355355        body = "expired = false\n#{generation_extraction}\n#{generation_structure}" 
    356      
     356 
    357357        # If we have conditions that must be tested first, nest the body inside an if 
    358358        body = "if #{generation_requirements}\n#{body}\nend" if generation_requirements 
     
    376376        raw_method 
    377377      end 
    378    
     378 
    379379      # Build several lines of code that extract values from the options hash. If any 
    380380      # of the values are missing or rejected then a return will be executed. 
     
    384384        end.compact * "\n" 
    385385      end 
    386    
     386 
    387387      # Produce a condition expression that will check the requirements of this route 
    388388      # upon generation. 
     
    398398        requirement_conditions * ' && ' unless requirement_conditions.empty? 
    399399      end 
    400        
     400 
    401401      def generation_structure 
    402402        segments.last.string_structure segments[0..-2] 
    403403      end 
    404    
     404 
    405405      # Write and compile a +recognize+ method for this Route. 
    406406      def write_recognition 
     
    408408        body = "params = parameter_shell.dup\n#{recognition_extraction * "\n"}\nparams" 
    409409        body = "if #{recognition_conditions.join(" && ")}\n#{body}\nend" 
    410      
     410 
    411411        # Build the method declaration and compile it 
    412412        method_decl = "def recognize(path, env={})\n#{body}\nend" 
     
    432432        wrap ? ("\\A" + pattern + "\\Z") : pattern 
    433433      end 
    434        
     434 
    435435      # Write the code to extract the parameters from a matched route. 
    436436      def recognition_extraction 
     
    443443        extraction.compact 
    444444      end 
    445    
     445 
    446446      # Write the real generation implementation and then resend the message. 
    447447      def generate(options, hash, expire_on = {}) 
     
    494494        recognize path, environment 
    495495      end 
    496    
     496 
    497497      # A route's parameter shell contains parameter values that are not in the 
    498498      # route's path, but should be placed in the recognized hash. 
    499       #  
     499      # 
    500500      # For example, +{:controller => 'pages', :action => 'show'} is the shell for the route: 
    501       #  
     501      # 
    502502      #   map.connect '/page/:id', :controller => 'pages', :action => 'show', :id => /\d+/ 
    503       #  
     503      # 
    504504      def parameter_shell 
    505505        @parameter_shell ||= returning({}) do |shell| 
     
    509509        end 
    510510      end 
    511    
     511 
    512512      # Return an array containing all the keys that are used in this route. This 
    513513      # includes keys that appear inside the path, and keys that have requirements 
     
    553553        end 
    554554      end 
    555    
     555 
    556556    protected 
    557557      def requirement_for(key) 
     
    600600        "\"#{chunks * ''}\"#{all_optionals_available_condition(prior_segments)}" 
    601601      end 
    602    
     602 
    603603      def string_structure(prior_segments) 
    604604        optional? ? continue_string_structure(prior_segments) : interpolation_statement(prior_segments) 
    605605      end 
    606    
     606 
    607607      # Return an if condition that is true if all the prior segments can be generated. 
    608608      # If there are no optional segments before this one, then nil is returned. 
     
    611611        optional_locals.empty? ? nil : " if #{optional_locals * ' && '}" 
    612612      end 
    613    
     613 
    614614      # Recognition 
    615    
     615 
    616616      def match_extraction(next_capture) 
    617617        nil 
    618618      end 
    619    
     619 
    620620      # Warning 
    621    
     621 
    622622      # Returns true if this segment is optional? because of a default. If so, then 
    623623      # no warning will be emitted regarding this segment. 
     
    630630      attr_accessor :value, :raw 
    631631      alias_method :raw?, :raw 
    632    
     632 
    633633      def initialize(value = nil) 
    634634        super() 
    635635        self.value = value 
    636636      end 
    637    
     637 
    638638      def interpolation_chunk 
    639639        raw? ? value : super 
    640640      end 
    641    
     641 
    642642      def regexp_chunk 
    643643        chunk = Regexp.escape(value) 
    644644        optional? ? Regexp.optionalize(chunk) : chunk 
    645645      end 
    646    
     646 
    647647      def build_pattern(pattern) 
    648648        escaped = Regexp.escape(value) 
     
    655655        end 
    656656      end 
    657    
     657 
    658658      def to_s 
    659659        value 
     
    667667        self.is_optional = true 
    668668      end 
    669    
     669 
    670670      def optionality_implied? 
    671671        true 
     
    675675    class DynamicSegment < Segment #:nodoc: 
    676676      attr_accessor :key, :default, :regexp 
    677    
     677 
    678678      def initialize(key = nil, options = {}) 
    679679        super() 
     
    682682        self.is_optional = true if options[:optional] || options.key?(:default) 
    683683      end 
    684    
     684 
    685685      def to_s 
    686686        ":#{key}" 
    687687      end 
    688    
     688 
    689689      # The local variable name that the value of this segment will be extracted to. 
    690690      def local_name 
    691691        "#{key}_value" 
    692692      end 
    693    
     693 
    694694      def extract_value 
    695695        "#{local_name} = hash[:#{key}] && hash[:#{key}].to_param #{"|| #{default.inspect}" if default}" 
     
    709709        "expired, hash = true, options if !expired && expire_on[:#{key}]" 
    710710      end 
    711    
     711 
    712712      def extraction_code 
    713713        s = extract_value 
     
    716716        s << "\n#{expiry_statement}" 
    717717      end 
    718    
     718 
    719719      def interpolation_chunk(value_code = "#{local_name}") 
    720720        "\#{URI.escape(#{value_code}.to_s, ActionController::Routing::Segment::UNSAFE_PCHAR)}" 
    721721      end 
    722    
     722 
    723723      def string_structure(prior_segments) 
    724724        if optional? # We have a conditional to do... 
     
    726726          # segments. This occurs if our value is the default value, or, if we are 
    727727          # optional, if we have nil as our value. 
    728           "if #{local_name} == #{default.inspect}\n" +  
    729             continue_string_structure(prior_segments) +  
     728          "if #{local_name} == #{default.inspect}\n" + 
     729            continue_string_structure(prior_segments) + 
    730730          "\nelse\n" + # Otherwise, write the code up to here 
    731731            "#{interpolation_statement(prior_segments)}\nend" 
     
    734734        end 
    735735      end 
    736    
     736 
    737737      def value_regexp 
    738738        Regexp.new "\\A#{regexp.source}\\Z" if regexp 
     
    741741        regexp ? "(#{regexp.source})" : "([^#{Routing::SEPARATORS.join}]+)" 
    742742      end 
    743    
     743 
    744744      def build_pattern(pattern) 
    745745        chunk = regexp_chunk 
     
    761761        ] 
    762762      end 
    763    
     763 
    764764      def optionality_implied? 
    765765        [:action, :id].include? key 
    766766      end 
    767    
     767 
    768768    end 
    769769 
     
    823823 
    824824      class Result < ::Array #:nodoc: 
    825         def to_s() join '/' end  
     825        def to_s() join '/' end 
    826826        def self.new_escaped(strings) 
    827827          new strings.collect {|str| URI.unescape str} 
    828         end      
     828        end 
    829829      end 
    830830    end 
     
    832832    class RouteBuilder #:nodoc: 
    833833      attr_accessor :separators, :optional_separators 
    834    
     834 
    835835      def initialize 
    836836        self.separators = Routing::SEPARATORS 
    837837        self.optional_separators = %w( / ) 
    838838      end 
    839    
     839 
    840840      def separator_pattern(inverted = false) 
    841841        "[#{'^' if inverted}#{Regexp.escape(separators.join)}]" 
    842842      end 
    843    
     843 
    844844      def interval_regexp 
    845845        Regexp.new "(.*?)(#{separators.source}|$)" 
    846846      end 
    847    
     847 
    848848      # Accepts a "route path" (a string defining a route), and returns the array 
    849849      # of segments that corresponds to it. Note that the segment array is only 
     
    854854      def segments_for_route_path(path) 
    855855        rest, segments = path, [] 
    856      
     856 
    857857        until rest.empty? 
    858858          segment, rest = segment_for rest 
     
    885885        [segment, $~.post_match] 
    886886      end 
    887    
     887 
    888888      # Split the given hash of options into requirement and default hashes. The 
    889889      # segments are passed alongside in order to distinguish between default values 
     
    891891      def divide_route_options(segments, options) 
    892892        options = options.dup 
    893          
     893 
    894894        if options[:namespace] 
    895895          options[:controller] = "#{options[:path_prefix]}/#{options[:controller]}" 
     
    897897          options.delete(:name_prefix) 
    898898          options.delete(:namespace) 
    899         end         
    900                  
     899        end 
     900 
    901901        requirements = (options.delete(:requirements) || {}).dup 
    902902        defaults     = (options.delete(:defaults)     || {}).dup 
     
    908908          hash[key] = value 
    909909        end 
    910              
     910 
    911911        [defaults, requirements, conditions] 
    912912      end 
    913        
     913 
    914914      # Takes a hash of defaults and a hash of requirements, and assigns them to 
    915915      # the segments. Any unused requirements (which do not correspond to a segment) 
     
    917917      def assign_route_options(segments, defaults, requirements) 
    918918        route_requirements = {} # Requirements that do not belong to a segment 
    919          
     919 
    920920        segment_named = Proc.new do |key| 
    921921          segments.detect { |segment| segment.key == key if segment.respond_to?(:key) } 
    922922        end 
    923          
     923 
    924924        requirements.each do |key, requirement| 
    925925          segment = segment_named[key] 
     
    934934          end 
    935935        end 
    936          
     936 
    937937        defaults.each do |key, default| 
    938938          segment = segment_named[key] 
     
    941941          segment.default = default.to_param if default 
    942942        end 
    943          
     943 
    944944        assign_default_route_options(segments) 
    945945        ensure_required_segments(segments) 
    946946        route_requirements 
    947947      end 
    948        
     948 
    949949      # Assign default options, such as 'index' as a default for :action. This 
    950950      # method must be run *after* user supplied requirements and defaults have 
     
    966966        end 
    967967      end 
    968        
     968 
    969969      # Makes sure that there are no optional segments that precede a required 
    970970      # segment. If any are found that precede a required segment, they are 
     
    985985        end 
    986986      end 
    987        
     987 
    988988      # Construct and return a route with the given path and options. 
    989989      def build(path, options) 
    990990        # Wrap the path with slashes 
    991991        path = "/#{path}" unless path[0] == ?/ 
    992         path = "#{path}/" unless path[-1] == ?/     
    993          
     992        path = "#{path}/" unless path[-1] == ?/ 
     993 
    994994        path = "/#{options[:path_prefix]}#{path}" if options[:path_prefix] 
    995      
     995 
    996996        segments = segments_for_route_path(path) 
    997997        defaults, requirements, conditions = divide_route_options(segments, options) 
     
    10031003        route.requirements = requirements 
    10041004        route.conditions = conditions 
    1005          
     1005 
    10061006        # Routes cannot use the current string interpolation method 
    10071007        # if there are user-supplied :requirements as the interpolation 
    10081008        # code won't raise RoutingErrors when generating 
    1009         route.optimise = !options.key?(:requirements)  
     1009        route.optimise = !options.key?(:requirements) 
    10101010        if !route.significant_keys.include?(:action) && !route.requirements[:action] 
    10111011          route.requirements[:action] = "index" 
     
    10241024      # Mapper instances are used to build routes. The object passed to the draw 
    10251025      # block in config/routes.rb is a Mapper instance. 
    1026       #  
     1026      # 
    10271027      # Mapper instances have relatively few instance methods, in order to avoid 
    10281028      # clashes with named routes. 
     
    10311031          @set = set 
    10321032        end 
    1033      
    1034         # Create an unnamed route with the provided +path+ and +options+. See  
     1033 
     1034        # Create an unnamed route with the provided +path+ and +options+. See 
    10351035        # SomeHelpfulUrl for an introduction to routes. 
    10361036        def connect(path, options = {}) 
     
    10461046          @set.add_named_route(name, path, options) 
    10471047        end 
    1048          
     1048 
    10491049        # Enables the use of resources in a module by setting the name_prefix, path_prefix, and namespace for the model. 
    10501050        # Example: 
     
    10651065          end 
    10661066        end 
    1067          
     1067 
    10681068 
    10691069        def method_missing(route_name, *args, &proc) 
     
    10881088          @routes = {} 
    10891089          @helpers = [] 
    1090            
     1090 
    10911091          @module ||= Module.new 
    10921092          @module.instance_methods.each do |selector| 
     
    11521152            end 
    11531153          end 
    1154            
     1154 
    11551155          def define_hash_access(route, name, kind, options) 
    11561156            selector = hash_access_name(name, kind) 
     
    12071207 
    12081208      attr_accessor :routes, :named_routes 
    1209    
     1209 
    12101210      def initialize 
    12111211        self.routes = [] 
    12121212        self.named_routes = NamedRouteCollection.new 
    12131213      end 
    1214        
     1214 
    12151215      # Subclasses and plugins may override this method to specify a different 
    12161216      # RouteBuilder instance, so that other route DSL's can be created. 
     
    12241224        install_helpers 
    12251225      end 
    1226        
     1226 
    12271227      def clear! 
    12281228        routes.clear 
     
    12311231        @routes_by_controller = nil 
    12321232      end 
    1233        
     1233 
    12341234      def install_helpers(destinations = [ActionController::Base, ActionView::Base], regenerate_code = false) 
    12351235        Array(destinations).each { |d| d.module_eval { include Helpers } } 
     
    12401240        routes.empty? 
    12411241      end 
    1242    
     1242 
    12431243      def load! 
    12441244        Routing.use_controllers! nil # Clear the controller cache so we may discover new ones 
     
    12501250      # reload! will always force a reload whereas load checks the timestamp first 
    12511251      alias reload! load! 
    1252        
     1252 
    12531253      def reload 
    12541254        if @routes_last_modified && defined?(RAILS_ROOT) 
     
    12611261        load! 
    12621262      end 
    1263        
     1263 
    12641264      def load_routes! 
    12651265        if defined?(RAILS_ROOT) && defined?(::ActionController::Routing::Routes) && self == ::ActionController::Routing::Routes 
     
    12701270        end 
    12711271      end 
    1272    
     1272 
    12731273      def add_route(path, options = {}) 
    12741274        route = builder.build(path, options) 
     
    12761276        route 
    12771277      end 
    1278    
     1278 
    12791279      def add_named_route(name, path, options = {}) 
    12801280        # TODO - is options EVER used? 
     
    12821282        named_routes[name.to_sym] = add_route(path, options) 
    12831283      end 
    1284    
     1284 
    12851285      def options_as_params(options) 
    12861286        # If an explicit :controller was given, always make :action explicit 
     
    13001300        options_as_params 
    13011301      end 
    1302    
     1302 
    13031303      def build_expiry(options, recall) 
    13041304        recall.inject({}) do |expiry, (key, recalled_value)| 
     
    13491349        if named_route 
    13501350          path = named_route.generate(options, merged, expire_on) 
    1351           if path.nil?  
     1351          if path.nil? 
    13521352            raise_named_route_error(options, named_route, named_route_name) 
    13531353          else 
     
    13571357          merged[:action] ||= 'index' 
    13581358          options[:action] ||= 'index' 
    1359    
     1359 
    13601360          controller = merged[:controller] 
    13611361          action = merged[:action] 
    13621362 
    13631363          raise RoutingError, "Need controller and action!" unless controller && action 
    1364            
     1364 
    13651365          if generate_all 
    13661366            # Used by caching to expire all paths for a resource 
     
    13691369            end.compact 
    13701370          end 
    1371            
     1371 
    13721372          # don't use the recalled keys when determining which routes to check 
    13731373          routes = routes_by_controller[controller][action][options.keys.sort_by { |x| x.object_id }] 
     
    13781378          end 
    13791379        end 
    1380      
     1380 
    13811381        raise RoutingError, "No route matches #{options.inspect}" 
    13821382      end 
    1383        
     1383 
    13841384      # try to give a helpful error message when named route generation fails 
    13851385      def raise_named_route_error(options, named_route, named_route_name) 
     
    13931393        end 
    13941394      end 
    1395    
     1395 
    13961396      def recognize(request) 
    13971397        params = recognize_path(request.path, extract_request_environment(request)) 
     
    13991399        "#{params[:controller].camelize}Controller".constantize 
    14001400      end 
    1401    
     1401 
    14021402      def recognize_path(path, environment={}) 
    14031403        routes.each do |route| 
     
    14151415        end 
    14161416      end 
    1417    
     1417 
    14181418      def routes_by_controller 
    14191419        @routes_by_controller ||= Hash.new do |controller_hash, controller| 
     
    14251425        end 
    14261426      end 
    1427    
     1427 
    14281428      def routes_for(options, merged, expire_on) 
    14291429        raise "Need controller and action!" unless controller && action 
     
    14311431        merged = options if expire_on[:controller] 
    14321432        action = merged[:action] || 'index' 
    1433      
     1433 
    14341434        routes_by_controller[controller][action][merged.keys] 
    14351435      end 
    1436    
     1436 
    14371437      def routes_for_controller_and_action(controller, action) 
    14381438        selected = routes.select do |route| 
     
    14411441        (selected.length == routes.length) ? routes : selected 
    14421442      end 
    1443    
     1443 
    14441444      def routes_for_controller_and_action_and_keys(controller, action, keys) 
    14451445        selected = routes.select do |route|