@@ -14,7 +14,7 @@ import scala.language.implicitConversions
14
14
* @tparam A
15
15
* type of the error that this PathSegment produces on "illegal" url paths.
16
16
*/
17
- trait PathSegment [T , + A ] extends UrlPart [T , A ] {
17
+ trait PathSegment [T , A ] extends UrlPart [T , A ] {
18
18
19
19
/** Tries to match the list of [[urldsl.vocabulary.Segment ]]s to create an instance of `T`. If it can not, it returns
20
20
* an error indicating the reason of the failure. If it could, it returns the value of `T`, as well as the list of
@@ -31,6 +31,30 @@ trait PathSegment[T, +A] extends UrlPart[T, A] {
31
31
*/
32
32
def matchSegments (segments : List [Segment ]): Either [A , PathMatchOutput [T ]]
33
33
34
+ protected implicit def errorImpl : PathMatchingError [A ]
35
+
36
+ /** Tries to match the provided list of [[urldsl.vocabulary.Segment ]]s to create an instance of `T`.
37
+ *
38
+ * If it can't, it returns an error indicating the reason of the failure. If it can but there are unused segments
39
+ * left over, it fails with a `endOfSegmentRequired` error. If it can, it returns the output.
40
+ *
41
+ * It is thus similar to [[matchSegments ]], but requiring that all segments have been consumed.
42
+ *
43
+ * @see
44
+ * [[matchSegments ]]
45
+ *
46
+ * @param segments
47
+ * The list of [[urldsl.vocabulary.Segment ]] to match this path segment again.
48
+ * @return
49
+ */
50
+ def matchFullSegments (segments : List [Segment ]): Either [A , T ] = for {
51
+ matchOuptput <- matchSegments(segments)
52
+ t <- matchOuptput.unusedSegments match {
53
+ case Nil => Right (matchOuptput.output)
54
+ case segments => Left (errorImpl.endOfSegmentRequired(segments))
55
+ }
56
+ } yield t
57
+
34
58
/** Matches the given raw `url` using the given [[urldsl.url.UrlStringParserGenerator ]] for creating a
35
59
* [[urldsl.url.UrlStringParser ]].
36
60
*
@@ -52,10 +76,10 @@ trait PathSegment[T, +A] extends UrlPart[T, A] {
52
76
url : String ,
53
77
urlStringParserGenerator : UrlStringParserGenerator = UrlStringParserGenerator .defaultUrlStringParserGenerator
54
78
): Either [A , T ] =
55
- matchSegments (urlStringParserGenerator.parser(url).segments).map(_.output )
79
+ matchFullSegments (urlStringParserGenerator.parser(url).segments)
56
80
57
81
def matchPath (path : String , decoder : UrlStringDecoder = UrlStringDecoder .defaultDecoder): Either [A , T ] =
58
- matchSegments (decoder.decodePath(path)).map(_.output )
82
+ matchFullSegments (decoder.decodePath(path))
59
83
60
84
/** Generate a list of segments representing the argument `t`.
61
85
*
@@ -85,8 +109,8 @@ trait PathSegment[T, +A] extends UrlPart[T, A] {
85
109
/** Concatenates `this` [[urldsl.language.PathSegment ]] with `that` one, "tupling" the types with the [[Composition ]]
86
110
* rules.
87
111
*/
88
- final def / [U , A1 >: A ](that : PathSegment [U , A1 ])(implicit c : Composition [T , U ]): PathSegment [c.Composed , A1 ] =
89
- PathSegment .factory[c.Composed , A1 ](
112
+ final def / [U ](that : PathSegment [U , A ])(implicit c : Composition [T , U ]): PathSegment [c.Composed , A ] =
113
+ PathSegment .factory[c.Composed , A ](
90
114
(segments : List [Segment ]) =>
91
115
for {
92
116
firstOut <- this .matchSegments(segments)
@@ -118,16 +142,16 @@ trait PathSegment[T, +A] extends UrlPart[T, A] {
118
142
* - in a multi-part segment, ensure consistency between the different component (e.g., a range of two integers
119
143
* that should not be too large...)
120
144
*/
121
- final def filter [ A1 >: A ] (predicate : T => Boolean , error : List [Segment ] => A1 ): PathSegment [T , A1 ] =
122
- PathSegment .factory[T , A1 ](
145
+ final def filter (predicate : T => Boolean , error : List [Segment ] => A ): PathSegment [T , A ] =
146
+ PathSegment .factory[T , A ](
123
147
(segments : List [Segment ]) =>
124
148
matchSegments(segments)
125
149
.filterOrElse(((_ : PathMatchOutput [T ]).output).andThen(predicate), error(segments)),
126
150
createSegments
127
151
)
128
152
129
153
/** Sugar for when `A =:= DummyError` */
130
- final def filter (predicate : T => Boolean )(implicit ev : A <:< DummyError ): PathSegment [T , DummyError ] = {
154
+ final def filter (predicate : T => Boolean )(implicit ev : A =:= DummyError ): PathSegment [T , DummyError ] = {
131
155
// type F[+E] = PathSegment[T, E]
132
156
// ev.liftCo[F].apply(this).filter(predicate, _ => DummyError.dummyError)
133
157
// we keep the ugliness below while supporting 2.12 todo[scala3] remove this
@@ -137,8 +161,8 @@ trait PathSegment[T, +A] extends UrlPart[T, A] {
137
161
/** Builds a [[PathSegment ]] that first tries to match with this one, then tries to match with `that` one. If both
138
162
* fail, the error of the second is returned (todo[behaviour]: should that change?)
139
163
*/
140
- final def || [U , A1 >: A ](that : PathSegment [U , A1 ]): PathSegment [Either [T , U ], A1 ] =
141
- PathSegment .factory[Either [T , U ], A1 ](
164
+ final def || [U ](that : PathSegment [U , A ]): PathSegment [Either [T , U ], A ] =
165
+ PathSegment .factory[Either [T , U ], A ](
142
166
segments =>
143
167
this .matchSegments(segments) match {
144
168
case Right (output) => Right (PathMatchOutput (Left (output.output), output.unusedSegments))
@@ -172,16 +196,16 @@ trait PathSegment[T, +A] extends UrlPart[T, A] {
172
196
/** Forgets the information contained in the path parameter by injecting one. This turn this "dynamic" [[PathSegment ]]
173
197
* into a fix one.
174
198
*/
175
- final def provide [ A1 >: A ] (
199
+ final def provide (
176
200
t : T
177
- )(implicit pathMatchingError : PathMatchingError [ A1 ], printer : Printer [T ]): PathSegment [Unit , A1 ] =
178
- PathSegment .factory[Unit , A1 ](
201
+ )(implicit printer : Printer [T ]): PathSegment [Unit , A ] =
202
+ PathSegment .factory[Unit , A ](
179
203
segments =>
180
204
for {
181
205
tMatch <- matchSegments(segments)
182
206
PathMatchOutput (tOutput, unusedSegments) = tMatch
183
207
unitMatched <-
184
- if (tOutput != t) Left (pathMatchingError .wrongValue(printer(t), printer(tOutput)))
208
+ if (tOutput != t) Left (errorImpl .wrongValue(printer(t), printer(tOutput)))
185
209
else Right (PathMatchOutput ((), unusedSegments))
186
210
} yield unitMatched,
187
211
(_ : Unit ) => createSegments(t)
@@ -195,7 +219,11 @@ trait PathSegment[T, +A] extends UrlPart[T, A] {
195
219
final def withFragment [FragmentType , FragmentError ](
196
220
fragment : Fragment [FragmentType , FragmentError ]
197
221
): PathQueryFragmentRepr [T , A , Unit , Nothing , FragmentType , FragmentError ] =
198
- new PathQueryFragmentRepr (this , QueryParameters .ignore, fragment)
222
+ new PathQueryFragmentRepr [T , A , Unit , Nothing , FragmentType , FragmentError ](
223
+ this ,
224
+ QueryParameters .ignore,
225
+ fragment
226
+ )
199
227
200
228
}
201
229
@@ -211,16 +239,18 @@ object PathSegment {
211
239
def factory [T , A ](
212
240
matching : List [Segment ] => Either [A , PathMatchOutput [T ]],
213
241
creating : T => List [Segment ]
214
- ): PathSegment [T , A ] = new PathSegment [T , A ] {
242
+ )(implicit errors : PathMatchingError [A ]): PathSegment [T , A ] = new PathSegment [T , A ] {
243
+ protected def errorImpl : PathMatchingError [A ] = errors
244
+
215
245
def matchSegments (segments : List [Segment ]): Either [A , PathMatchOutput [T ]] = matching(segments)
216
246
217
247
def createSegments (t : T ): List [Segment ] = creating(t)
218
248
}
219
249
220
250
/** Simple path segment that matches everything by passing segments down the line. */
221
- final def empty : PathSegment [Unit , Nothing ] =
222
- factory[Unit , Nothing ](segments => Right (PathMatchOutput ((), segments)), _ => Nil )
223
- final def root : PathSegment [Unit , Nothing ] = empty
251
+ final def empty [ A ]( implicit pathMatchingError : PathMatchingError [ A ]) : PathSegment [Unit , A ] =
252
+ factory[Unit , A ](segments => Right (PathMatchOutput ((), segments)), _ => Nil )
253
+ final def root [ A ]( implicit pathMatchingError : PathMatchingError [ A ]) : PathSegment [Unit , A ] = empty
224
254
225
255
/** Simple path segment that matches nothing. This is the neutral of the || operator. */
226
256
final def noMatch [A ](implicit pathMatchingError : PathMatchingError [A ]): PathSegment [Unit , A ] =
@@ -274,10 +304,11 @@ object PathSegment {
274
304
*
275
305
* This can be useful for static resources.
276
306
*/
277
- final def remainingSegments [A ]: PathSegment [List [String ], A ] = factory[List [String ], A ](
278
- segments => Right (PathMatchOutput (segments.map(_.content), Nil )),
279
- _.map(Segment .apply)
280
- )
307
+ final def remainingSegments [A ](implicit pathMatchingError : PathMatchingError [A ]): PathSegment [List [String ], A ] =
308
+ factory[List [String ], A ](
309
+ segments => Right (PathMatchOutput (segments.map(_.content), Nil )),
310
+ _.map(Segment .apply)
311
+ )
281
312
282
313
/** [[PathSegment ]] that matches one of the given different possibilities.
283
314
*
0 commit comments