Class: ActionController::Routing::RouteBuilder
- Defined in:
- lib/action_controller/routing.rb
Overview
:nodoc:
Instance Attribute Summary collapse
-
#optional_separators ⇒ Object
Returns the value of attribute optional_separators.
-
#separators ⇒ Object
Returns the value of attribute separators.
Instance Method Summary collapse
-
#assign_default_route_options(segments) ⇒ Object
Assign default options, such as ‘index’ as a default for :action.
-
#assign_route_options(segments, defaults, requirements) ⇒ Object
Takes a hash of defaults and a hash of requirements, and assigns them to the segments.
-
#build(path, options) ⇒ Object
Construct and return a route with the given path and options.
-
#divide_route_options(segments, options) ⇒ Object
Split the given hash of options into requirement and default hashes.
-
#ensure_required_segments(segments) ⇒ Object
Makes sure that there are no optional segments that precede a required segment.
-
#initialize ⇒ RouteBuilder
constructor
A new instance of RouteBuilder.
- #interval_regexp ⇒ Object
-
#segment_for(string) ⇒ Object
A factory method that returns a new segment instance appropriate for the format of the given string.
-
#segments_for_route_path(path) ⇒ Object
Accepts a “route path” (a string defining a route), and returns the array of segments that corresponds to it.
- #separator_pattern(inverted = false) ⇒ Object
Constructor Details
#initialize ⇒ RouteBuilder
Returns a new instance of RouteBuilder.
860 861 862 863 |
# File 'lib/action_controller/routing.rb', line 860 def initialize self.separators = Routing::SEPARATORS self.optional_separators = %w( / ) end |
Instance Attribute Details
#optional_separators ⇒ Object
Returns the value of attribute optional_separators.
858 859 860 |
# File 'lib/action_controller/routing.rb', line 858 def optional_separators @optional_separators end |
#separators ⇒ Object
Returns the value of attribute separators.
858 859 860 |
# File 'lib/action_controller/routing.rb', line 858 def separators @separators end |
Instance Method Details
#assign_default_route_options(segments) ⇒ Object
Assign default options, such as ‘index’ as a default for :action. This method must be run after user supplied requirements and defaults have been applied to the segments.
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 |
# File 'lib/action_controller/routing.rb', line 977 def (segments) segments.each do |segment| next unless segment.is_a? DynamicSegment case segment.key when :action if segment.regexp.nil? || segment.regexp.match('index').to_s == 'index' segment.default ||= 'index' segment.is_optional = true end when :id if segment.default.nil? && segment.regexp.nil? || segment.regexp =~ '' segment.is_optional = true end end end end |
#assign_route_options(segments, defaults, requirements) ⇒ Object
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.
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 |
# File 'lib/action_controller/routing.rb', line 942 def (segments, defaults, requirements) route_requirements = {} # Requirements that do not belong to a segment segment_named = Proc.new do |key| segments.detect { |segment| segment.key == key if segment.respond_to?(:key) } end requirements.each do |key, requirement| segment = segment_named[key] if segment raise TypeError, "#{key}: requirements on a path segment must be regular expressions" unless requirement.is_a?(Regexp) if requirement.source =~ %r{\A(\\A|\^)|(\\Z|\\z|\$)\Z} raise ArgumentError, "Regexp anchor characters are not allowed in routing requirements: #{requirement.inspect}" end segment.regexp = requirement else route_requirements[key] = requirement end end defaults.each do |key, default| segment = segment_named[key] raise ArgumentError, "#{key}: No matching segment exists; cannot assign default" unless segment segment.is_optional = true segment.default = default.to_param if default end (segments) ensure_required_segments(segments) route_requirements end |
#build(path, options) ⇒ Object
Construct and return a route with the given path and options.
1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 |
# File 'lib/action_controller/routing.rb', line 1014 def build(path, ) # Wrap the path with slashes path = "/#{path}" unless path[0] == ?/ path = "#{path}/" unless path[-1] == ?/ path = "/#{[:path_prefix].to_s.gsub(/^\//,'')}#{path}" if [:path_prefix] segments = segments_for_route_path(path) defaults, requirements, conditions = (segments, ) requirements = (segments, defaults, requirements) route = Route.new route.segments = segments route.requirements = requirements route.conditions = conditions if !route.significant_keys.include?(:action) && !route.requirements[:action] route.requirements[:action] = "index" route.significant_keys << :action end # Routes cannot use the current string interpolation method # if there are user-supplied :requirements as the interpolation # code won't raise RoutingErrors when generating if .key?(:requirements) || route.requirements.keys.to_set != Routing::ALLOWED_REQUIREMENTS_FOR_OPTIMISATION route.optimise = false end if !route.significant_keys.include?(:controller) raise ArgumentError, "Illegal route: the :controller must be specified!" end route end |
#divide_route_options(segments, options) ⇒ Object
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.
916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 |
# File 'lib/action_controller/routing.rb', line 916 def (segments, ) = .dup if [:namespace] [:controller] = "#{[:path_prefix]}/#{[:controller]}" .delete(:path_prefix) .delete(:name_prefix) .delete(:namespace) end requirements = (.delete(:requirements) || {}).dup defaults = (.delete(:defaults) || {}).dup conditions = (.delete(:conditions) || {}).dup path_keys = segments.collect { |segment| segment.key if segment.respond_to?(:key) }.compact .each do |key, value| hash = (path_keys.include?(key) && ! value.is_a?(Regexp)) ? defaults : requirements hash[key] = value end [defaults, requirements, conditions] end |
#ensure_required_segments(segments) ⇒ Object
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.
997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 |
# File 'lib/action_controller/routing.rb', line 997 def ensure_required_segments(segments) allow_optional = true segments.reverse_each do |segment| allow_optional &&= segment.optional? if !allow_optional && segment.optional? unless segment.optionality_implied? warn "Route segment \"#{segment.to_s}\" cannot be optional because it precedes a required segment. This segment will be required." end segment.is_optional = false elsif allow_optional && segment.respond_to?(:default) && segment.default # if a segment has a default, then it is optional segment.is_optional = true end end end |
#interval_regexp ⇒ Object
869 870 871 |
# File 'lib/action_controller/routing.rb', line 869 def interval_regexp Regexp.new "(.*?)(#{separators.source}|$)" end |
#segment_for(string) ⇒ Object
A factory method that returns a new segment instance appropriate for the format of the given string.
891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 |
# File 'lib/action_controller/routing.rb', line 891 def segment_for(string) segment = case string when /\A:(\w+)/ key = $1.to_sym case key when :controller then ControllerSegment.new(key) else DynamicSegment.new key end when /\A\*(\w+)/ then PathSegment.new($1.to_sym, :optional => true) when /\A\?(.*?)\?/ returning segment = StaticSegment.new($1) do segment.is_optional = true end when /\A(#{separator_pattern(:inverted)}+)/ then StaticSegment.new($1) when Regexp.new(separator_pattern) then returning segment = DividerSegment.new($&) do segment.is_optional = (optional_separators.include? $&) end end [segment, $~.post_match] end |
#segments_for_route_path(path) ⇒ Object
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.
879 880 881 882 883 884 885 886 887 |
# File 'lib/action_controller/routing.rb', line 879 def segments_for_route_path(path) rest, segments = path, [] until rest.empty? segment, rest = segment_for rest segments << segment end segments end |