Class | ActionController::Routing::RouteBuilder |
In: |
vendor/rails/actionpack/lib/action_controller/routing.rb
|
Parent: | Object |
optional_separators | [RW] | |
separators | [RW] |
# File vendor/rails/actionpack/lib/action_controller/routing.rb, line 787 787: def initialize 788: self.separators = Routing::SEPARATORS 789: self.optional_separators = %w( / ) 790: end
Takes a hash of defaults and a hash of requirements, and assigns them to the segments. Any unused requirements (which do not correspond to a segment) are returned as a hash.
# File vendor/rails/actionpack/lib/action_controller/routing.rb, line 863 863: def assign_route_options(segments, defaults, requirements) 864: route_requirements = {} # Requirements that do not belong to a segment 865: 866: segment_named = Proc.new do |key| 867: segments.detect { |segment| segment.key == key if segment.respond_to?(:key) } 868: end 869: 870: requirements.each do |key, requirement| 871: segment = segment_named[key] 872: if segment 873: raise TypeError, "#{key}: requirements on a path segment must be regular expressions" unless requirement.is_a?(Regexp) 874: if requirement.source =~ %r{\A(\\A|\^^)|(\\Z|\\z|\$)\Z} 875: raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}" 876: end 877: segment.regexp = requirement 878: else 879: route_requirements[key] = requirement 880: end 881: end 882: 883: defaults.each do |key, default| 884: segment = segment_named[key] 885: raise ArgumentError, "#{key}: No matching segment exists; cannot assign default" unless segment 886: segment.is_optional = true 887: segment.default = default.to_param if default 888: end 889: 890: ensure_required_segments(segments) 891: route_requirements 892: end
Construct and return a route with the given path and options.
# File vendor/rails/actionpack/lib/action_controller/routing.rb, line 914 914: def build(path, options) 915: # Wrap the path with slashes 916: path = "/#{path}" unless path[0] == ?/ 917: path = "#{path}/" unless path[-1] == ?/ 918: 919: segments = segments_for_route_path(path) 920: defaults, requirements, conditions = divide_route_options(segments, options) 921: requirements = assign_route_options(segments, defaults, requirements) 922: 923: route = Route.new 924: route.segments = segments 925: route.requirements = requirements 926: route.conditions = conditions 927: 928: if !route.significant_keys.include?(:action) && !route.requirements[:action] 929: route.requirements[:action] = "index" 930: route.significant_keys << :action 931: end 932: 933: route 934: end
Split the given hash of options into requirement and default hashes. The segments are passed alongside in order to distinguish between default values and requirements.
# File vendor/rails/actionpack/lib/action_controller/routing.rb, line 845 845: def divide_route_options(segments, options) 846: options = options.dup 847: requirements = (options.delete(:requirements) || {}).dup 848: defaults = (options.delete(:defaults) || {}).dup 849: conditions = (options.delete(:conditions) || {}).dup 850: 851: path_keys = segments.collect { |segment| segment.key if segment.respond_to?(:key) }.compact 852: options.each do |key, value| 853: hash = (path_keys.include?(key) && ! value.is_a?(Regexp)) ? defaults : requirements 854: hash[key] = value 855: end 856: 857: [defaults, requirements, conditions] 858: end
Makes sure that there are no optional segments that precede a required segment. If any are found that precede a required segment, they are made required.
# File vendor/rails/actionpack/lib/action_controller/routing.rb, line 897 897: def ensure_required_segments(segments) 898: allow_optional = true 899: segments.reverse_each do |segment| 900: allow_optional &&= segment.optional? 901: if !allow_optional && segment.optional? 902: unless segment.optionality_implied? 903: warn "Route segment \"#{segment.to_s}\" cannot be optional because it precedes a required segment. This segment will be required." 904: end 905: segment.is_optional = false 906: elsif allow_optional & segment.respond_to?(:default) && segment.default 907: # if a segment has a default, then it is optional 908: segment.is_optional = true 909: end 910: end 911: end
# File vendor/rails/actionpack/lib/action_controller/routing.rb, line 796 796: def interval_regexp 797: Regexp.new "(.*?)(#{separators.source}|$)" 798: end
A factory method that returns a new segment instance appropriate for the format of the given string.
# File vendor/rails/actionpack/lib/action_controller/routing.rb, line 818 818: def segment_for(string) 819: segment = case string 820: when /\A:(\w+)/ 821: key = $1.to_sym 822: case key 823: when :action then DynamicSegment.new(key, :default => 'index') 824: when :id then DynamicSegment.new(key, :optional => true) 825: when :controller then ControllerSegment.new(key) 826: else DynamicSegment.new key 827: end 828: when /\A\*(\w+)/ then PathSegment.new($1.to_sym, :optional => true) 829: when /\A\?(.*?)\?/ 830: returning segment = StaticSegment.new($1) do 831: segment.is_optional = true 832: end 833: when /\A(#{separator_pattern(:inverted)}+)/ then StaticSegment.new($1) 834: when Regexp.new(separator_pattern) then 835: returning segment = DividerSegment.new($&) do 836: segment.is_optional = (optional_separators.include? $&) 837: end 838: end 839: [segment, $~.post_match] 840: end
Accepts a "route path" (a string defining a route), and returns the array of segments that corresponds to it. Note that the segment array is only partially initialized—the defaults and requirements, for instance, need to be set separately, via the assign_route_options method, and the optional? method for each segment will not be reliable until after assign_route_options is called, as well.
# File vendor/rails/actionpack/lib/action_controller/routing.rb, line 806 806: def segments_for_route_path(path) 807: rest, segments = path, [] 808: 809: until rest.empty? 810: segment, rest = segment_for rest 811: segments << segment 812: end 813: segments 814: end