Skip to content
This repository has been archived by the owner on Jun 1, 2023. It is now read-only.

Changed Hack Collections with Hack Arrays #22

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ sudo: required
language: generic
services: docker
env:
- HHVM_VERSION=4.25-latest
- HHVM_VERSION=4.50-latest
- HHVM_VERSION=latest
- HHVM_VERSION=nightly
install:
Expand Down
24 changes: 11 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,20 @@ A simple typed request router. Example:
* callable, but classname<MyWebControllerBase> is also a
* common choice.
*/
type TResponder = (function(ImmMap<string, string>):string);
type TResponder = (function(dict<string, string>): string);

final class BaseRouterExample extends BaseRouter<TResponder> {
protected function getRoutes(
): ImmMap<HttpMethod, ImmMap<string, TResponder>> {
return ImmMap {
HttpMethod::GET => ImmMap {
'/' =>
($_params) ==> 'Hello, world',
'/user/{user_name}' =>
($params) ==> 'Hello, '.$params['user_name'],
},
HttpMethod::POST => ImmMap {
<<__Override>>
protected function getRoutes(): dict<HttpMethod, dict<string, TResponder>> {
return dict[
HttpMethod::GET => dict[
'/' => ($_params) ==> 'Hello, world',
'/user/{user_name}' => ($params) ==> 'Hello, '.$params['user_name'],
],
HttpMethod::POST => dict[
'/' => ($_params) ==> 'Hello, POST world',
},
};
],
];
}
}
```
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"keywords": ["hack", "router", "routing", "hhvm"],
"homepage": "https://github.com/hhvm/hack-router",
"require": {
"hhvm": "^4.25",
"hhvm": "^4.50",
"hhvm/hsl": "^4.0",
"facebook/hack-http-request-response-interfaces": "^0.2|^0.3"
},
Expand All @@ -16,7 +16,7 @@
},
"require-dev": {
"facebook/fbexpect": "^2.0",
"hhvm/hhast": "^4.0",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, just meant that the new release had to actually be released; this should be automatically picked up based on hhast's own version requirements, now that it's happened.

"hhvm/hhast": "^4.41",
"hhvm/hhvm-autoload": "^2.0.8|^3.0",
"hhvm/hacktest": "^2.0",
"usox/hackttp": "^0.3|^0.4"
Expand Down
36 changes: 14 additions & 22 deletions examples/BaseRouterExample.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,33 +22,30 @@
* callable, but classname<MyWebControllerBase> is also a
* common choice.
*/
type TResponder = (function(dict<string, string>):string);
type TResponder = (function(dict<string, string>): string);

final class BaseRouterExample extends BaseRouter<TResponder> {
<<__Override>>
protected function getRoutes(
): ImmMap<HttpMethod, ImmMap<string, TResponder>> {
return ImmMap {
HttpMethod::GET => ImmMap {
'/' =>
($_params) ==> 'Hello, world',
'/user/{user_name}' =>
($params) ==> 'Hello, '.$params['user_name'],
},
HttpMethod::POST => ImmMap {
protected function getRoutes(): dict<HttpMethod, dict<string, TResponder>> {
return dict[
HttpMethod::GET => dict[
'/' => ($_params) ==> 'Hello, world',
'/user/{user_name}' => ($params) ==> 'Hello, '.$params['user_name'],
],
HttpMethod::POST => dict[
'/' => ($_params) ==> 'Hello, POST world',
},
};
],
];
}
}

function get_example_inputs(): ImmVector<(HttpMethod, string)> {
return ImmVector {
function get_example_inputs(): vec<(HttpMethod, string)> {
return vec[
tuple(HttpMethod::GET, '/'),
tuple(HttpMethod::GET, '/user/foo'),
tuple(HttpMethod::GET, '/user/bar'),
tuple(HttpMethod::POST, '/'),
};
];
}

<<__EntryPoint>>
Expand All @@ -58,12 +55,7 @@ function main(): noreturn {
list($method, $path) = $input;

list($responder, $params) = $router->routeMethodAndPath($method, $path);
\printf(
"%s %s\n\t%s\n",
$method,
$path,
$responder(dict($params)),
);
\printf("%s %s\n\t%s\n", $method, $path, $responder($params));
}
exit(0);
}
37 changes: 15 additions & 22 deletions examples/UriPatternsExample.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@

require_once(__DIR__.'/../vendor/hh_autoload.php');

use type Facebook\HackRouter\{
use type Facebook\HackRouter\{
BaseRouter,
GetFastRoutePatternFromUriPattern,
GetUriBuilderFromUriPattern,
HasUriPattern,
HttpMethod,
RequestParameters,
UriPattern
UriPattern,
};

<<__ConsistentConstruct>>
Expand All @@ -38,12 +38,10 @@ final protected function getRequestParameters(): RequestParameters {
return $this->uriParameters;
}

public function __construct(
ImmMap<string, string> $uri_parameter_values,
) {
public function __construct(dict<string, string> $uri_parameter_values) {
$this->uriParameters = new RequestParameters(
static::getUriPattern()->getParameters(),
ImmVector { },
vec[],
$uri_parameter_values,
);
}
Expand Down Expand Up @@ -78,34 +76,33 @@ public function getResponse(): string {
type TResponder = classname<WebController>;

final class UriPatternsExample extends BaseRouter<TResponder> {
public static function getControllers(): ImmVector<TResponder> {
return ImmVector {
public static function getControllers(): vec<TResponder> {
return vec[
HomePageController::class,
UserPageController::class,
};
];
}

<<__Override>>
public function getRoutes(
): ImmMap<HttpMethod, ImmMap<string, TResponder>> {
public function getRoutes(): dict<HttpMethod, dict<string, TResponder>> {
$urls_to_controllers = dict[];
foreach (self::getControllers() as $controller) {
$pattern = $controller::getFastRoutePattern();
$urls_to_controllers[$pattern] = $controller;
}
return ImmMap {
HttpMethod::GET => new ImmMap($urls_to_controllers),
};
return dict [
HttpMethod::GET => $urls_to_controllers,
];
}
}

function get_example_paths(): ImmVector<string> {
return ImmVector {
function get_example_paths(): vec<string> {
return vec[
HomePageController::getUriBuilder()->getPath(),
UserPageController::getUriBuilder()
->setString('user_name', 'Mr Hankey')
->getPath(),
};
];
}

function main(): void {
Expand All @@ -115,11 +112,7 @@ function main(): void {
HttpMethod::GET,
$path,
);
\printf(
"GET %s\n\t%s\n",
$path,
(new $controller($params))->getResponse(),
);
\printf("GET %s\n\t%s\n", $path, (new $controller($params))->getResponse());
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/request-parameters/RequestParametersBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ abstract class RequestParametersBase {
private dict<string, RequestParameter> $requiredSpecs;
private dict<string, RequestParameter> $optionalSpecs;

protected ImmMap<string, string> $values;
protected dict<string, string> $values;

public function __construct(
Traversable<RequestParameter> $required_specs,
Traversable<RequestParameter> $optional_specs,
KeyedTraversable<string, string> $values,
) {
$this->values = new ImmMap($values);
$this->values = dict($values);
$spec_vector_to_map = (
Traversable<RequestParameter> $specs
) ==> Dict\pull($specs, $it ==> $it, $it ==> $it->getName());
Expand Down
8 changes: 4 additions & 4 deletions src/router/BaseRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ abstract protected function getRoutes(
final public function routeMethodAndPath(
HttpMethod $method,
string $path,
): (TResponder, ImmMap<string, string>) {
): (TResponder, dict<string, string>) {
$resolver = $this->getResolver();
try {
list($responder, $data) = $resolver->resolve($method, $path);
$data = Dict\map($data, $value ==> \urldecode($value));
return tuple($responder, new ImmMap($data));
return tuple($responder, $data);
} catch (NotFoundException $e) {
$allowed = $this->getAllowedMethods($path);
if (C\is_empty($allowed)) {
Expand All @@ -37,7 +37,7 @@ final public function routeMethodAndPath(
) {
list($responder, $data) = $resolver->resolve(HttpMethod::GET, $path);
$data = Dict\map($data, $value ==> \urldecode($value));
return tuple($responder, new ImmMap($data));
return tuple($responder, $data);
}

throw new MethodNotAllowedException($allowed);
Expand All @@ -46,7 +46,7 @@ final public function routeMethodAndPath(

final public function routeRequest(
\Facebook\Experimental\Http\Message\RequestInterface $request,
): (TResponder, ImmMap<string, string>) {
): (TResponder, dict<string, string>) {
$method = HttpMethod::coerce($request->getMethod());
if ($method === null) {
throw new MethodNotAllowedException(
Expand Down
25 changes: 15 additions & 10 deletions src/uri-patterns/UriBuilderBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,23 @@

namespace Facebook\HackRouter;

use namespace HH\Lib\{C, Vec};

abstract class UriBuilderBase {
protected ImmVector<UriPatternPart> $parts;
protected ImmMap<string, RequestParameter> $parameters;
private Map<string, string> $values = Map {};
protected vec<UriPatternPart> $parts;
protected dict<string, RequestParameter> $parameters;
private dict<string, string> $values = dict[];

public function __construct(Traversable<UriPatternPart> $parts) {
$this->parts = new ImmVector($parts);
$parameters = Map {};
$this->parts = vec($parts);
$parameters = dict[];
foreach ($parts as $part) {
if (!$part is RequestParameter) {
continue;
}
$parameters[$part->getName()] = $part;
}
$this->parameters = $parameters->immutable();
$this->parameters = $parameters;
}

final protected function getPathImpl(): string {
Expand All @@ -47,11 +49,11 @@ final protected function getPathImpl(): string {

$name = $part->getName();
invariant(
$this->values->containsKey($name),
C\contains_key($this->values, $name),
'Parameter "%s" must be set',
$name,
);
$uri .= $this->values->at($name);
$uri .= $this->values[$name];
}
invariant(
\substr($uri, 0, 1) === '/',
Expand All @@ -71,7 +73,10 @@ classname<TypedUriParameter<T>> $parameter_type,
$part !== null,
'%s is not a valid parameter - expected one of [%s]',
$name,
\implode(', ', $this->parameters->keys()->map($x ==> "'".$x."'")),
\implode(
', ',
Vec\map_with_key($this->parameters, ($key, $_) ==> "'".$key."'"),
),
);
invariant(
\is_a($part, $parameter_type),
Expand All @@ -81,7 +86,7 @@ classname<TypedUriParameter<T>> $parameter_type,
\get_class($part),
);
invariant(
!$this->values->containsKey($name),
!C\contains_key($this->values, $name),
'trying to set %s twice',
$name,
);
Expand Down
32 changes: 17 additions & 15 deletions src/uri-patterns/UriPattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,38 @@

namespace Facebook\HackRouter;

use namespace HH\Lib\Vec;

// Non-final so you can extend it with additional convenience
// methods.
class UriPattern implements HasFastRouteFragment {
private Vector<UriPatternPart> $parts = Vector {};
private vec<UriPatternPart> $parts = vec[];

final public function appendPart(UriPatternPart $part): this {
$this->parts[] = $part;
return $this;
}

final public function getFastRouteFragment(): string {
$fragments = $this->parts->map($part ==> $part->getFastRouteFragment());
$fragments = Vec\map($this->parts, $part ==> $part->getFastRouteFragment());
return \implode('', $fragments);
}

final public function getParts(): ImmVector<UriPatternPart> {
return $this->parts->immutable();
final public function getParts(): vec<UriPatternPart> {
return $this->parts;
}

final public function getParameters(): ImmVector<UriParameter> {
return $this
->parts
->filter($x ==> $x is UriParameter)
->map(
$x ==> {
assert($x is UriParameter);
return $x;
},
)
->immutable();
final public function getParameters(): vec<UriParameter> {
return Vec\map(
Vec\filter($this->parts, $part ==> $part is UriParameter),
$part ==> {
invariant(
$part is UriParameter,
"Tell the typechecker what's going on",
);
return $part;
},
);
}

///// Convenience Methods /////
Expand Down
8 changes: 4 additions & 4 deletions tests/lib/TestRouter.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ public function __construct(

<<__Override>>
protected function getRoutes(
): ImmMap<HttpMethod, ImmMap<string, T>> {
return ImmMap {
HttpMethod::GET => new ImmMap($this->routes),
};
): dict<HttpMethod, dict<string, T>> {
return dict[
HttpMethod::GET => $this->routes,
];
}

public function setResolver(IResolver<T> $resolver): this {
Expand Down