Skip to content
This repository was archived by the owner on Mar 29, 2024. It is now read-only.

Commit bf92724

Browse files
committed
Add parameter type guessing by default value
1 parent 40cc8a5 commit bf92724

File tree

3 files changed

+165
-9
lines changed

3 files changed

+165
-9
lines changed

src/Extractors/ExtractorDefinitionBuilder.php

-5
Original file line numberDiff line numberDiff line change
@@ -181,11 +181,6 @@ protected function buildArrayDefinition(?ExtractorDefinitionInterface $definitio
181181
return $definition;
182182
}
183183

184-
/**
185-
* @param array $matches
186-
*
187-
* @return int
188-
*/
189184
private function getDepth(array $matches): int
190185
{
191186
if (!isset($matches['arr']) || '' === $matches['arr']) {

src/Specs/Builder/ParameterSpecBuilder.php

+30-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
use Pinepain\JsSandbox\Specs\Parameters\OptionalParameterSpec;
2525
use Pinepain\JsSandbox\Specs\Parameters\ParameterSpecInterface;
2626
use Pinepain\JsSandbox\Specs\Parameters\VariadicParameterSpec;
27-
use function strlen;
2827

2928

3029
class ParameterSpecBuilder implements ParameterSpecBuilderInterface
@@ -138,6 +137,10 @@ protected function buildOptionalParameterSpec(array $matches, ?string $default):
138137
} catch (ArgumentValueBuilderException $e) {
139138
throw new ParameterSpecBuilderException("Unknown or unsupported default value format '{$default_definition}'");
140139
}
140+
141+
if (!$this->hasType($matches)) {
142+
$matches['type'] = $this->guessTypeFromDefault($default);
143+
}
141144
}
142145

143146
return new OptionalParameterSpec($matches['name'], $this->extractor->build($matches['type']), $default);
@@ -162,8 +165,9 @@ protected function prepareDefinition(array $matches): array
162165
throw new ParameterSpecBuilderException('Variadic parameter could have no default value');
163166
}
164167

165-
if (!$this->hasType($matches)) {
166-
$matches['type'] = 'any'; // special case
168+
if (!$this->hasDefault($matches) && !$this->hasType($matches)) {
169+
// special case when no default value set and no type provided
170+
$matches['type'] = 'any';
167171
}
168172

169173
return $matches;
@@ -188,4 +192,27 @@ private function hasDefault(array $matches): bool
188192
{
189193
return isset($matches['default']) && '' !== $matches['default'];
190194
}
195+
196+
private function guessTypeFromDefault($default): string
197+
{
198+
if (is_array($default)) {
199+
return '[]';
200+
}
201+
202+
if (is_numeric($default)) {
203+
return 'number';
204+
}
205+
206+
if (is_bool($default)) {
207+
return 'bool';
208+
}
209+
210+
if (is_string($default)) {
211+
return 'string';
212+
}
213+
214+
// it looks like we have nullable parameter which could be anything
215+
216+
return 'any';
217+
}
191218
}

tests/Specs/Builder/ParameterSpecBuilderTest.php

+135-1
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,118 @@ public function testBuildingNullableParameter()
210210
$this->assertInstanceOf(ExtractorDefinitionInterface::class, $spec->getExtractorDefinition());
211211
}
212212

213+
public function testBuildingParameterWithArrayTypeGuessing()
214+
{
215+
$this->argumentDefinitionShouldBuildOn('[]');
216+
$this->extractorDefinitionShouldBuildOn('[]');
217+
218+
$spec = $this->builder->build('param = []');
219+
220+
$this->assertInstanceOf(OptionalParameterSpec::class, $spec);
221+
222+
$this->assertSame('param', $spec->getName());
223+
$this->assertSame([], $spec->getDefaultValue());
224+
$this->assertInstanceOf(ExtractorDefinitionInterface::class, $spec->getExtractorDefinition());
225+
}
226+
227+
public function testBuildingParameterWithBoolTrueTypeGuessing()
228+
{
229+
$this->argumentDefinitionShouldBuildOn('true');
230+
$this->extractorDefinitionShouldBuildOn('bool');
231+
232+
$spec = $this->builder->build('param = true');
233+
234+
$this->assertInstanceOf(OptionalParameterSpec::class, $spec);
235+
236+
$this->assertSame('param', $spec->getName());
237+
$this->assertSame(true, $spec->getDefaultValue());
238+
$this->assertInstanceOf(ExtractorDefinitionInterface::class, $spec->getExtractorDefinition());
239+
}
240+
241+
public function testBuildingParameterWithBoolFalseTypeGuessing()
242+
{
243+
$this->argumentDefinitionShouldBuildOn('false');
244+
$this->extractorDefinitionShouldBuildOn('bool');
245+
246+
$spec = $this->builder->build('param = false');
247+
248+
$this->assertInstanceOf(OptionalParameterSpec::class, $spec);
249+
250+
$this->assertSame('param', $spec->getName());
251+
$this->assertSame(false, $spec->getDefaultValue());
252+
$this->assertInstanceOf(ExtractorDefinitionInterface::class, $spec->getExtractorDefinition());
253+
}
254+
255+
public function testBuildingParameterWithNullableTypeGuessing()
256+
{
257+
$this->argumentDefinitionShouldBuildOn('null');
258+
$this->extractorDefinitionShouldBuildOn('any');
259+
260+
$spec = $this->builder->build('param?');
261+
262+
$this->assertInstanceOf(OptionalParameterSpec::class, $spec);
263+
264+
$this->assertSame('param', $spec->getName());
265+
$this->assertSame(null, $spec->getDefaultValue());
266+
$this->assertInstanceOf(ExtractorDefinitionInterface::class, $spec->getExtractorDefinition());
267+
}
268+
269+
public function testBuildingParameterWithDefaultNullTypeGuessing()
270+
{
271+
$this->argumentDefinitionShouldBuildOn('null');
272+
$this->extractorDefinitionShouldBuildOn('any');
273+
274+
$spec = $this->builder->build('param = null');
275+
276+
$this->assertInstanceOf(OptionalParameterSpec::class, $spec);
277+
278+
$this->assertSame('param', $spec->getName());
279+
$this->assertSame(null, $spec->getDefaultValue());
280+
$this->assertInstanceOf(ExtractorDefinitionInterface::class, $spec->getExtractorDefinition());
281+
}
282+
283+
public function testBuildingParameterWithDefaultIntNumberTypeGuessing()
284+
{
285+
$this->argumentDefinitionShouldBuildOn('123');
286+
$this->extractorDefinitionShouldBuildOn('number');
287+
288+
$spec = $this->builder->build('param = 123');
289+
290+
$this->assertInstanceOf(OptionalParameterSpec::class, $spec);
291+
292+
$this->assertSame('param', $spec->getName());
293+
$this->assertEquals(123, $spec->getDefaultValue());
294+
$this->assertInstanceOf(ExtractorDefinitionInterface::class, $spec->getExtractorDefinition());
295+
}
296+
297+
public function testBuildingParameterWithDefaultFloatNumberTypeGuessing()
298+
{
299+
$this->argumentDefinitionShouldBuildOn('123.42');
300+
$this->extractorDefinitionShouldBuildOn('number');
301+
302+
$spec = $this->builder->build('param = 123.42');
303+
304+
$this->assertInstanceOf(OptionalParameterSpec::class, $spec);
305+
306+
$this->assertSame('param', $spec->getName());
307+
$this->assertSame(123.42, $spec->getDefaultValue());
308+
$this->assertInstanceOf(ExtractorDefinitionInterface::class, $spec->getExtractorDefinition());
309+
}
310+
311+
public function testBuildingParameterWithDefaultStringTypeGuessing()
312+
{
313+
$this->argumentDefinitionShouldBuildOn('"test"');
314+
$this->extractorDefinitionShouldBuildOn('string');
315+
316+
$spec = $this->builder->build('param = "test"');
317+
318+
$this->assertInstanceOf(OptionalParameterSpec::class, $spec);
319+
320+
$this->assertSame('param', $spec->getName());
321+
$this->assertSame('"test"', $spec->getDefaultValue());
322+
$this->assertInstanceOf(ExtractorDefinitionInterface::class, $spec->getExtractorDefinition());
323+
}
324+
213325
/**
214326
* @expectedException \Pinepain\JsSandbox\Specs\Builder\Exceptions\ParameterSpecBuilderException
215327
* @expectedExceptionMessage Unable to parse definition because of extractor failure: ExtractorDefinitionBuilder exception for testing
@@ -223,9 +335,31 @@ public function testBuildingWhenExtractorFailsShouldAlsoFail()
223335

224336
protected function argumentDefinitionShouldBuildOn($name)
225337
{
338+
$retval = $name;
339+
340+
if ('[]' == $name) {
341+
$retval = [];
342+
}
343+
344+
if ('true' === $name) {
345+
$retval = true;
346+
}
347+
348+
if ('false' === $name) {
349+
$retval = false;
350+
}
351+
352+
if (is_numeric($name)) {
353+
$retval = is_int($name) ? (int)$name : (float) $name;
354+
}
355+
356+
if ('null' === $name) {
357+
$retval = null;
358+
}
359+
226360
$this->argument_builder->method('build')
227361
->with($name, false)
228-
->willReturn($name);
362+
->willReturn($retval);
229363
}
230364

231365
protected function argumentDefinitionShouldThrowOn($name)

0 commit comments

Comments
 (0)