compareTo method
Comparing two patterns for ordering them.
This ordering should be used when registering request handlers to a pipeline, since an incorrect order might cause some rules to be masked by other rules.
The rules for ordering are:
- literals have priority over optionals;
- optionals over variables; and
- variables over wildcards.
If there are multiple patterns that could match the same path, the more specific pattern will have priority over the less specific.
For example, "~/foo/bar" is ordered before "~/foo/:a-variable". This is usually the desired order for rules: the path "/foo/bar" will match that first pattern and the path "/foo/xyz" will match the second pattern. If the order was reversed, the pattern with the variable segment will match both paths (i.e. the "~/foo/bar" pattern will be ignored if the handler for the other pattern processes the request).
A more practical example are the patterns "~/abc/def/" and "~/abc/def/:variable".
Note: the names of variables are significant when comparing them. For example, "~/:a" and "~/:b" will return a non-zero value, but matchesSamePaths will return true.
Implementation
int compareTo(Pattern other) {
var varNameOrder = 0;
for (var x = 0; x < _segments.length; x++) {
if (other._segments.length <= x) {
// No corresponding segment in the other pattern
return -1; // the longer pattern (this) has priority
}
final seg1 = _segments[x];
final seg2 = other._segments[x];
if (wildcard == seg1) {
if (wildcard == seg2) {
// both wildcards
} else if (_isVariable(seg2)) {
return 1; // wildcard <=> variable
} else if (_isOptional(seg2)) {
return 1; // wildcard <=> optional
} else {
return 1; // wildcard <=> literal
}
} else if (_isVariable(seg1)) {
if (wildcard == seg2) {
return -1; // variable <=> wildcard
} else if (_isVariable(seg2)) {
// both variables
// These are not yet significant
if (varNameOrder == 0) {
varNameOrder = _variableName(seg1).compareTo(_variableName(seg2));
}
} else if (_isOptional(seg2)) {
return 1; // variable <=> optional
} else {
return 1; // variable <=> literal
}
} else if (_isOptional(seg1)) {
if (wildcard == seg2) {
return -1; // optional <=> wildcard
} else if (_isVariable(seg2)) {
return -1; // optional <=> variable
} else if (_isOptional(seg2)) {
final cmp = _optionalName(seg1).compareTo(_optionalName(seg2));
if (cmp != 0) {
return cmp;
}
} else {
return 1; // optional <=> literal
}
} else {
if (wildcard == seg2) {
return -1; // literal <=> wildcard
} else if (_isVariable(seg2)) {
return -1; // literal <=> variable
} else if (_isOptional(seg2)) {
return -1; // literal <=> optional
} else {
final cmp = seg1.compareTo(seg2); // both literal
if (cmp != 0) {
return cmp;
}
}
}
}
// At this point, all the segments in this pattern are the same as in the
// other pattern.
if (_segments.length == other._segments.length) {
// Both patterns are semantically the same, so consider the syntax (i.e.
// the variable names) to determine the order.
return varNameOrder;
} else {
// The other pattern has more segments
return 1; // the longer pattern (other) has priority
}
}