Skip to content

Commit

Permalink
added support for argument guessing
Browse files Browse the repository at this point in the history
  • Loading branch information
basuke committed Apr 26, 2017
1 parent c508191 commit e82cc00
Show file tree
Hide file tree
Showing 8 changed files with 203 additions and 21 deletions.
2 changes: 1 addition & 1 deletion Clim/App.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public function add($middleware)
*/
public function task($callable)
{
$this->spec->addTask($this->containerBoundCallable($callable));
$this->spec->addTask(new Task($callable, $this->getContainer()));
}

/**
Expand Down
3 changes: 2 additions & 1 deletion Clim/Cli/Spec.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace Clim\Cli;

use Clim\Option;
use Clim\Task;

class Spec
{
Expand Down Expand Up @@ -46,7 +47,7 @@ public function addArgument(ArgumentInterface $argument)
$this->arguments[] = $argument;
}

public function addTask(callable $task)
public function addTask(Task $task)
{
$this->tasks[] = $task;
}
Expand Down
14 changes: 0 additions & 14 deletions Clim/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,4 @@ public function setResult($result)
{
$this->result = $result;
}

/**
* @param callable $callable
* @return mixed
*/
public function execute(callable $callable)
{
$options = new Hash($this->options());
$arguments = new Hash($this->arguments());

$result = call_user_func_array($callable, [$options, $arguments]);
if (!is_null($result)) $this->setResult($result);
return $result;
}
}
119 changes: 119 additions & 0 deletions Clim/Helper/ArgumentsSupplier.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<?php

namespace Clim\Helper;

use Clim\Context;
use Closure;
use Psr\Container\ContainerInterface;

class ArgumentsSupplier
{
protected $context;

protected $container;

protected $options;

protected $arguments;

protected $missingArgs;

protected $assignedArguments;

public function __construct(Context $context, ContainerInterface $container)
{
$this->context = $context;
$this->container = $container;
$this->options = new Hash($context->options());
$this->arguments = new Hash($context->arguments());
}

public function supplyFor(Closure $closure)
{
$args = [];

$ref = new \ReflectionFunction($closure);
/** @var \ReflectionParameter[] $params */
$params = $ref->getParameters();

if (count($params) > 0) {
$this->assignedArguments = [];
$this->missingArgs = [];

foreach ($params as $index => $param) {
$class = $param->getClass();
$allow_null = $param->allowsNull();

$arg = $this->findArgumentFor(
$param->getName(),
$index,
$class ? $class->getName() : null,
$param->isArray()
);

$args[] = $arg;
}

}

return $args;
}

protected function findArgumentFor($name, $index, $class, $is_array)
{
if ($name === 'arguments' || $name === 'args') {
return $this->hashToDesiredArgument($this->arguments, $class, $is_array);
}

if ($name === 'options' || $name === 'opts') {
return $this->hashToDesiredArgument($this->options, $class, $is_array);
}

if ($name === 'context') {
return $this->context;
}

if ($this->container->has($name)) {
$result = $this->container->get($name);
if (!$class || ($result instanceof $class)) {
return $result;
}
}

if (isset($this->arguments[$name])) {
$result = $this->arguments[$name];
return $result;
}

if (isset($this->options[$name])) {
$result = $this->options[$name];
return $result;
}

foreach ($this->arguments->all() as $index => $value) {
if (is_integer($index) && in_array($index, $this->assignedArguments, true) === false) {
if (($is_array && is_array($value)) || ($class && $value instanceof $class)) {
$this->assignedArguments[] = $index;
return $value;
}
}
}

return null;
}

protected function hashToDesiredArgument(Hash $hash, $class, $is_array)
{
if ($is_array) {
return $hash->all();
} elseif ($class && $class !== 'Clim\\Helper\\Hash') {
try {
return new $class($hash->all());
} catch (\Exception $e) {
// ... pass through
}
}

return $hash;
}
}
3 changes: 2 additions & 1 deletion Clim/Runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ public function run($argv, Context $context = null)
}

foreach ($this->spec->tasks() as $task) {
$context->execute($task);
$result = $task->execute($context);
if (!is_null($result)) $context->setResult($result);
}

return $context;
Expand Down
46 changes: 46 additions & 0 deletions Clim/Task.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace Clim;

use Clim\Helper\ArgumentsSupplier;
use Clim\Helper\Hash;
use Closure;
use Psr\Container\ContainerInterface;
use Slim\CallableResolverAwareTrait;

class Task
{
use CallableResolverAwareTrait;

private $callable;

private $container;

/**
* @param callable|string $callable
* @param ContainerInterface $container
*/
public function __construct($callable, ContainerInterface $container)
{
$this->callable = $callable;
$this->container = $container;
}

public function execute(Context $context)
{
$callable = $this->resolveCallable($this->callable);
if ($callable instanceof Closure) {
$callable = $callable->bindTo($this->container);

$supplier = new ArgumentsSupplier($context, $this->container);
$args = $supplier->supplyFor($callable);
} else {
$options = $context->options();
$arguments = $context->arguments();

$args = [new Hash($options), new Hash($arguments)];
}

return call_user_func_array($callable, $args);
}
}
8 changes: 4 additions & 4 deletions tests/unit/DispatchCept.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@
// available only for foo
$app->option('--force');

$app->task(function ($context) {
// $context['age'] : from option
$app->task(function ($options) {
// $options['age'] : from option
// $this->name : from container
echo "FOO {$context['age']}-{$this->name}\n";
echo "FOO {$options['age']}-{$this->name}\n";
});
},
'bar' => function (App $app) {
$app->task(function ($context) {
$app->task(function (Context $context) {
echo "BAR\n";
});
},
Expand Down
29 changes: 29 additions & 0 deletions tests/unit/TaskHandlerCept.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php
$I = new UnitTester($scenario);
$I->wantTo('perform actions and see result');

$app = new \Clim\App();
$container = $app->getContainer();

$container['hello'] = function () {
return "Hello World!!!";
};

class SimpleArray
{
public function __construct($array)
{
}
}

$app->task(function ($hello, array $arguments, \Clim\Helper\Hash $opts, SimpleArray $options) use ($I) {
$I->assertEquals("Hello World!!!", $hello);
$I->assertTrue(is_array($arguments));
$I->assertTrue($opts instanceof \Clim\Helper\Hash);
$I->assertTrue($options instanceof SimpleArray);
return 42;
});

$context = $app->runner()->run(['prog_name']);

$I->assertEquals(42, $context->getResult());

0 comments on commit e82cc00

Please sign in to comment.