1 Segment的分类
- Segment. Abstract Base Class
DynamicSegment
. This represents parts of the route that begin with a colon, like:action
,:permalink
or:id
.ControllerSegment
. This is actually a subclass ofDynamicSegment
. It represents to special string:controller
, because it does some special recognition on those strings. (We’ll cover that more in the next article).PathSegment
. This is for segments that start with an asterisk, and which represent the remainder of the path. Routes like"/file/*path"
use aPathSegment
.StaticSegment
. This is any static text in your route that must be matched (or generated) verbatim. If you have a path like"/one/two"
, the strings"one"
and"two"
are both static segments.DividerSegment
. This is any segment that is used to delimit the other segments. Generally, this will be the forward slash character, but also includes commas, periods, semicolons, and question marks.
2 实现
先看看Segment实现
- class Segment #:nodoc:
- RESERVED_PCHAR = ':@&=+$,;'
- UNSAFE_PCHAR = Regexp.new("[^#{URI::REGEXP::PATTERN::UNRESERVED}#{RESERVED_PCHAR}]", false, 'N').freeze
- attr_accessor :is_optional
- alias_method :optional?, :is_optional
- def initialize
- self.is_optional = false
- end
- def extraction_code
- nil
- end
- # Continue generating string for the prior segments.
- def continue_string_structure(prior_segments)
- if prior_segments.empty?
- interpolation_statement(prior_segments)
- else
- new_priors = prior_segments[0..-2]
- prior_segments.last.string_structure(new_priors)
- end
- end
- def interpolation_chunk
- URI.escape(value, UNSAFE_PCHAR)
- end
- # Return a string interpolation statement for this segment and those before it.
- def interpolation_statement(prior_segments)
- chunks = prior_segments.collect { |s| s.interpolation_chunk }
- chunks << interpolation_chunk
- "/"#{chunks * ''}/"#{all_optionals_available_condition(prior_segments)}"
- end
- def string_structure(prior_segments)
- optional? ? continue_string_structure(prior_segments) : interpolation_statement(prior_segments)
- end
- # Return an if condition that is true if all the prior segments can be generated.
- # If there are no optional segments before this one, then nil is returned.
- def all_optionals_available_condition(prior_segments)
- optional_locals = prior_segments.collect { |s| s.local_name if s.optional? && s.respond_to?(:local_name) }.compact
- optional_locals.empty? ? nil : " if #{optional_locals * ' && '}"
- end
- # Recognition
- def match_extraction(next_capture)
- nil
- end
- # Warning
- # Returns true if this segment is optional? because of a default. If so, then
- # no warning will be emitted regarding this segment.
- def optionality_implied?
- false
- end
- end