New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement a matrix path variable parser #3844
Changes from 4 commits
6e29d93
40ece8b
185f1b0
36936fd
486395a
6e23bef
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ import org.http4s.Uri.uri | |
import org.http4s.dsl.io._ | ||
import org.scalacheck.Arbitrary | ||
import org.scalacheck.Arbitrary.arbitrary | ||
import scala.util.Try | ||
|
||
class PathSpec extends Http4sSpec { | ||
implicit val arbitraryPath: Arbitrary[Path] = | ||
|
@@ -234,6 +235,95 @@ class PathSpec extends Http4sSpec { | |
} | ||
} | ||
|
||
"Matrix extractor" >> { | ||
object BoardExtractor | ||
extends impl.MatrixVar("square", List("x", "y"), s => Try(s.toInt).toOption) | ||
|
||
object EmptyExtractor extends impl.MatrixVar[List, String]("square", List.empty, s => Some(s)) | ||
|
||
"valid" >> { | ||
"a matrix var" in { | ||
(Path("/board/square;x=42;y=0") match { | ||
case Root / "board" / BoardExtractor(x, y) if x == 42 && y == 0 => true | ||
case _ => false | ||
}) must beTrue | ||
} | ||
|
||
"a matrix var mid path" in { | ||
(Path("/board/square;x=42;y=0/piece") match { | ||
case Root / "board" / BoardExtractor(x, y) / "piece" if x == 42 && y == 0 => true | ||
case _ => false | ||
}) must beTrue | ||
} | ||
|
||
"an empty matrix var but why?" in { | ||
|
||
(Path("/board/square") match { | ||
case Root / "board" / EmptyExtractor() => true | ||
case _ => false | ||
}) must beTrue | ||
} | ||
} | ||
|
||
"invalid" >> { | ||
"empty with semi" in { | ||
(Path("/board/square;") match { | ||
case Root / "board" / BoardExtractor(x @ _, y @ _) => true | ||
case _ => false | ||
}) must beFalse | ||
} | ||
|
||
"empty without semi" in { | ||
(Path("/board/square") match { | ||
case Root / "board" / BoardExtractor(x @ _, y @ _) => true | ||
case _ => false | ||
}) must beFalse | ||
} | ||
|
||
"empty with mismatched name" in { | ||
(Path("/board/other") match { | ||
case Root / "board" / EmptyExtractor() => true | ||
case _ => false | ||
}) must beFalse | ||
} | ||
|
||
"empty axis" in { | ||
(Path("/board/square;;y=0") match { | ||
case Root / "board" / BoardExtractor(x @ _, y @ _) => true | ||
case _ => false | ||
}) must beFalse | ||
} | ||
|
||
"empty too many = in axis" in { | ||
(Path("/board/square;x=42=0;y=9") match { | ||
case Root / "board" / BoardExtractor(x @ _, y @ _) => true | ||
case _ => false | ||
}) must beFalse | ||
} | ||
|
||
"unparseable" in { | ||
(Path("/board/square;x=42;y=soda") match { | ||
case Root / "board" / BoardExtractor(x @ _, y @ _) => true | ||
case _ => false | ||
}) must beFalse | ||
} | ||
|
||
"not enough axes" in { | ||
(Path("/board/square;x=42") match { | ||
case Root / "board" / BoardExtractor(x @ _, y @ _) => true | ||
case _ => false | ||
}) must beFalse | ||
} | ||
|
||
"to many axes" in { | ||
(Path("/board/square;x=42y=0;z=39") match { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this supposed to be There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The similarity to query parameters probably means that they should be. I just need to make the |
||
case Root / "board" / BoardExtractor(x @ _, y @ _) => true | ||
case _ => false | ||
}) must beFalse | ||
} | ||
} | ||
} | ||
|
||
"consistent apply / toList" in prop { (p: Path) => | ||
Path(p.toList) must_== p | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In common use, are all parameters in the matrix of the same type?
Do I have to represent
zipCode
as aString
? If we strippedrange
and returnedString
s, could we nest extractors?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really sure there is a common use. The problem I was specifically looking for was a means to solve awkward urls like
/board/x/0/y/1
which implies a hierarchical structure of resources where none exists. Beyond that the goal is something that more people than just me is an ergonomic API. range is basically a mini-extractor so I will make this change.