Skip to content

Commit 03243e1

Browse files
author
Nicolas Oelgart
committed
Add support for custom object calls
1 parent bb0ee07 commit 03243e1

File tree

3 files changed

+116
-19
lines changed

3 files changed

+116
-19
lines changed

src/TokenStream/AST.php

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Closure;
1111
use InvalidArgumentException;
1212
use nicoSWD\Rule\Grammar\CallableUserFunctionInterface;
13+
use nicoSWD\Rule\Parser\Exception\ParserException;
1314
use nicoSWD\Rule\TokenStream\Exception\UndefinedVariableException;
1415
use nicoSWD\Rule\TokenStream\Token\BaseToken;
1516
use nicoSWD\Rule\TokenStream\Token\TokenFactory;
@@ -49,7 +50,7 @@ public function getStream(string $rule): TokenStream
4950
public function getMethod(string $methodName, BaseToken $token): CallableUserFunctionInterface
5051
{
5152
if ($token instanceof TokenObject) {
52-
return $this->getUserObjectCallable($token, $methodName);
53+
return $this->getCallableUserObject($token, $methodName);
5354
}
5455

5556
if (empty($this->methods)) {
@@ -126,33 +127,55 @@ private function registerFunctions()
126127
}
127128
}
128129

129-
private function getUserObjectCallable(BaseToken $token, string $methodName): CallableUserFunctionInterface
130+
private function getCallableUserObject(BaseToken $token, string $methodName): CallableUserFunctionInterface
130131
{
131-
return new class ($token, $this->tokenFactory, $methodName) implements CallableUserFunctionInterface
132-
{
133-
/** @var BaseToken */
134-
private $token;
132+
return new class ($token, $this->tokenFactory, $methodName) implements CallableUserFunctionInterface {
135133
/** @var TokenFactory */
136134
private $tokenFactory;
137-
/** @var string */
138-
private $methodName;
135+
/** @var Closure */
136+
private $callable;
137+
/** @var array */
138+
private $variations = ['get', 'is', ''];
139139

140140
public function __construct(BaseToken $token, TokenFactory $tokenFactory, string $methodName)
141141
{
142-
$this->token = $token;
143142
$this->tokenFactory = $tokenFactory;
144-
$this->methodName = $methodName;
143+
$this->callable = $this->getCallable($token, $methodName);
145144
}
146145

147-
public function call(BaseToken $param = null): BaseToken
146+
private function getCallable(BaseToken $token, string $methodName): Closure
148147
{
149-
$object = [$this->token->getValue(), $this->methodName];
148+
$object = $token->getValue();
150149

151-
if (!is_callable($object)) {
152-
throw new \Exception();
150+
if (property_exists($object, $methodName)) {
151+
return function () use ($object, $methodName) {
152+
return $object->{$methodName};
153+
};
153154
}
154155

155-
return $this->tokenFactory->createFromPHPType($object());
156+
$method[0] = $object;
157+
$index = 0;
158+
159+
do {
160+
if (!isset($this->variations[$index])) {
161+
throw ParserException::undefinedMethod($methodName, $token);
162+
}
163+
164+
$method[1] = $this->variations[$index] . $methodName;
165+
} while (!is_callable($method) && isset($this->variations[$index++]));
166+
167+
return function (BaseToken $param = null) use ($method) {
168+
return $method($param ? $param->getValue() : null);
169+
};
170+
}
171+
172+
public function call(BaseToken $param = null): BaseToken
173+
{
174+
$callable = $this->callable;
175+
176+
return $this->tokenFactory->createFromPHPType(
177+
$callable($param)
178+
);
156179
}
157180
};
158181
}

src/TokenStream/Token/TokenObject.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99

1010
final class TokenObject extends BaseToken
1111
{
12-
public function getType() : int
12+
public function getType(): int
1313
{
14-
return TokenType::OBJECT;
14+
return TokenType::VALUE;
1515
}
1616
}

tests/integration/ObjectTest.php

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
* @link https://github.com/nicoSWD
66
* @author Nicolas Oelgart <[email protected]>
77
*/
8+
9+
use nicoSWD\Rule\Rule;
810
use nicoSWD\Rule\tests\integration\AbstractTestBase;
911

1012
final class ObjectTest extends AbstractTestBase
@@ -15,14 +17,86 @@ public function testObjects()
1517
function test() {
1618
return 'test one two';
1719
}
20+
21+
function test2() {
22+
return new class ()
23+
{
24+
function miau() {
25+
return 'miau';
26+
}
27+
};
28+
}
1829
};
1930

2031
$variables = [
2132
'my_obj' => $myObj,
22-
'my_string' => 'some test'
2333
];
2434

2535
$this->assertTrue($this->evaluate('my_obj.test() === "test one two"', $variables));
26-
$this->assertFalse($this->evaluate('my_obj.test() === "oh no"', $variables));
36+
$this->assertTrue($this->evaluate('my_obj.test2().miau() === "miau"', $variables));
37+
}
38+
39+
public function testPublicPropertyShouldBeAccessible()
40+
{
41+
$myObj = new class {
42+
public $test = 'my string';
43+
};
44+
45+
$variables = [
46+
'my_obj' => $myObj,
47+
];
48+
49+
$this->assertTrue($this->evaluate('my_obj.test() === "my string"', $variables));
50+
}
51+
52+
public function testPublicMethodsShouldBeAccessibleMagicallyViaGet()
53+
{
54+
$myObj = new class {
55+
public function getString()
56+
{
57+
return 'some string';
58+
}
59+
};
60+
61+
$variables = [
62+
'my_obj' => $myObj,
63+
];
64+
65+
$this->assertTrue($this->evaluate('my_obj.string() === "some string"', $variables));
66+
}
67+
68+
public function testPublicMethodsShouldBeAccessibleMagicallyViaIs()
69+
{
70+
$myObj = new class {
71+
public function isString($string)
72+
{
73+
return $string;
74+
}
75+
76+
public function yes()
77+
{
78+
return 'yes';
79+
}
80+
};
81+
82+
$variables = [
83+
'my_obj' => $myObj,
84+
];
85+
86+
$this->assertTrue($this->evaluate('my_obj.string(my_obj.yes()) === "yes"', $variables));
87+
}
88+
89+
public function testUndefinedMethodsShouldThrowAnError()
90+
{
91+
$myObj = new class {};
92+
93+
$variables = [
94+
'my_obj' => $myObj,
95+
];
96+
97+
$rule = new Rule('my_obj.nope() === false', $variables);
98+
99+
$this->assertFalse($rule->isValid());
100+
$this->assertSame('Undefined method "nope" at position 0', $rule->getError());
27101
}
28102
}

0 commit comments

Comments
 (0)