Skip to content

Commit

Permalink
feat(Command): finalizing command api
Browse files Browse the repository at this point in the history
  • Loading branch information
razshare committed Jul 2, 2024
1 parent 9f69fd4 commit 1a95e55
Show file tree
Hide file tree
Showing 8 changed files with 150 additions and 220 deletions.
5 changes: 3 additions & 2 deletions bin/start
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#!/usr/bin/env php
<?php
use CatPaw\Core\Bootstrap;
use function CatPaw\Core\command;
use CatPaw\Core\Command;

use function CatPaw\Core\error;
use function CatPaw\Core\ok;

require 'vendor/autoload.php';

command(
Command::create(
signature: <<<SIGNATURE
--entry
--name
Expand Down
12 changes: 6 additions & 6 deletions docs/28.goffi.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ cpp -P ./libgoffi.h ./libgoffi.static.h
```
This will create a `libgoffi.static.h` file, this file _must_ be located in the same directory as the `libgoffi.so` file.

Now use `goffi()` to interop with your _Go_ program from _Php_.
Now use `GoffiContract::create()` to interop with your _Go_ program from _Php_.

```php
<?php
// src/main.php
use CatPaw\Core\Unsafe;
use function CatPaw\Core\goffi;
use CatPaw\Core\GoffiContract;
use function CatPaw\Core\anyError;

interface Contract {
Expand All @@ -53,15 +53,15 @@ interface Contract {

function main():Unsafe{
return anyError(function(){
$lib = goffi(Contract::class, './libgoffi.so')->try();
$lib = GoffiContract::create(Contract::class, './libgoffi.so')->try();
$doubled = $lib->DoubleIt(3);
echo "doubled: $doubled\n";
});
}
```

> [!NOTE]
> If any of your interface methods doesn't specify a return type, the `goffi()` call will fail.
> If any of your interface methods doesn't specify a return type, the `GoffiContract::create()` call will fail.
Run the program.

Expand Down Expand Up @@ -96,16 +96,16 @@ Call _Greeting_ from php like so
```php
<?php
use CatPaw\Core\Unsafe;
use CatPaw\Core\GoffiContract;
use function CatPaw\Core\anyError;
use function CatPaw\Core\goffi;

interface Contract {
function Greeting(string $name):string;
}

function main():Unsafe {
return anyError(function() {
$goffi = goffi(Contract::class, './libgoffi.so')->try();
$goffi = GoffiContract::create(Contract::class, './libgoffi.so')->try();
echo $goffi->Greeting('world').PHP_EOL;
});
}
Expand Down
129 changes: 129 additions & 0 deletions src/lib/Core/Command.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php
namespace CatPaw\Core;

use ReflectionFunction;

class Command {
/**
* Create a command using a signature and a callback function.
* @param string $signature Command signature, the options required for this command to trigger.
* @param callable(mixed):mixed $function Function to execute when command is issued.
* @return Unsafe<bool> `true` if the command was executed, `false` otherwise.
*/
public static function create(string $signature, callable $function):Unsafe {
$reflectionFunction = new ReflectionFunction($function);
$options = CommandParser::options($signature, $reflectionFunction)->unwrap($error);

if ($error) {
return error($error);
}

if (count($options) === 0) {
$actualItems = CommandParser::parseSignature($signature);
$expectedItems = CommandParser::parseFunction($reflectionFunction)->unwrap($error);
if ($error) {
return error($error);
}
$actualItemsCount = count($actualItems);
$expectedItemsCount = count($expectedItems);
if ($actualItemsCount !== $expectedItemsCount) {
return ok(false);
}
foreach ($expectedItems as $expectedItem) {
if (!str_ends_with($expectedItem, '::')) {
return ok(false);
}
}
}

$arguments = [];

static $undefined = function(WrappedType $type, bool $notFound, string $value) {
if ($notFound) {
if ($type->allowsDefaultValue()) {
return $type->getDefaultValue();
}

if ($type->allowsFalse()) {
return false;
}

if ($type->allowsNullValue()) {
return null;
}

return NONE;
}

if ('' === $value) {
if ($type->allowsBoolean()) {
return true;
}

if ($type->allowsTrue()) {
return true;
}

return NONE;
}
return NONE;
};

static $integer = fn (WrappedType $type, bool $notFound, string $value):mixed
=> match ($result = $undefined($type, $notFound, $value)) {
NONE => (integer)$value,
default => $result,
};

static $float = fn (WrappedType $type, bool $notFound, string $value):mixed
=> match ($result = $undefined($type, $notFound, $value)) {
NONE => (float)$value,
default => $result,
};

static $double = fn (WrappedType $type, bool $notFound, string $value):mixed
=> match ($result = $undefined($type, $notFound, $value)) {
NONE => (double)$value,
default => $result,
};

static $bool = fn (WrappedType $type, bool $notFound, string $value):mixed
=> match ($result = $undefined($type, $notFound, $value)) {
NONE => (bool)$value,
default => $result,
};

static $string = fn (WrappedType $type, bool $notFound, string $value):mixed
=> match ($result = $undefined($type, $notFound, $value)) {
NONE => (string)$value,
default => $result,
};

foreach ($reflectionFunction->getParameters() as $reflectionParameter) {
$key = KebabCase::fromAny($reflectionParameter->getName());
$notFound = !isset($options[$key]);
$value = $options[$key] ?? '';
$type = ReflectionTypeManager::wrap($reflectionParameter);
$className = $type->getClassName();
$result = match ($className) {
'int' => $integer($type, $notFound, $value),
'float' => $float($type, $notFound, $value),
'double' => $double($type, $notFound, $value),
'bool' => $bool($type, $notFound, $value),
default => $string($type, $notFound, $value),
};
$arguments[] = $result;
}

foreach ($arguments as $argument) {
if (NONE === $argument) {
return ok(false);
}
}

return anyError(function() use ($function, $arguments) {
yield $function(...$arguments);
return ok(true);
});
}
}
2 changes: 1 addition & 1 deletion src/lib/Core/Unsafe.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public function toResponseModifier(): ResponseModifier {

/**
*
* @param null|Error $error
* @param Error $error
* @return T
*/
public function unwrap(&$error = null) {
Expand Down
13 changes: 7 additions & 6 deletions src/main.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

use function CatPaw\Core\anyError;
use function CatPaw\Core\Build\build;
use function CatPaw\Core\command;

use CatPaw\Core\Command;

use function CatPaw\Core\error;
use CatPaw\Core\File;
Expand All @@ -23,11 +24,11 @@
*/
function main(): Unsafe {
return anyError(fn () => match (true) {
command('--build --optimize', build(...))->try() => ok(),
command('--tips', tips(...))->try() => ok(),
command('--install-pre-commit', installPreCommit(...))->try() => ok(),
command('--uninstall-pre-commit', uninstallPreCommit(...))->try() => ok(),
default => ok(print(<<<BASH
Command::create('--build --optimize', build(...))->try() => ok(),
Command::create('--tips', tips(...))->try() => ok(),
Command::create('--install-pre-commit', installPreCommit(...))->try() => ok(),
Command::create('--uninstall-pre-commit', uninstallPreCommit(...))->try() => ok(),
default => ok(print(<<<BASH
\n
--build [--optimize] Builds the project into a .phar.
--tips Some tips.
Expand Down
4 changes: 2 additions & 2 deletions src/scripts/Core/Build/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ function build(bool $optimize = false):Unsafe {
$file->write(<<<PHP
<?php
use CatPaw\Core\Bootstrap;
use function CatPaw\Core\command;
use CatPaw\Core\Command;
require 'vendor/autoload.php';
command(
Command::create(
signature: '--environment',
function: function(string \$environment = '') {
if(!\$environment){
Expand Down
Loading

0 comments on commit 1a95e55

Please sign in to comment.