Passed
Push — wip-public-release ( a47743...14cdbd )
by Bogdan
02:52
created

FunctionSpecBuilder::build()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 21
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 21
ccs 11
cts 11
cp 1
rs 8.7624
c 0
b 0
f 0
cc 5
eloc 11
nc 4
nop 1
crap 5
1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of the pinepain/js-sandbox PHP library.
5
 *
6
 * Copyright (c) 2016-2017 Bogdan Padalko <[email protected]>
7
 *
8
 * Licensed under the MIT license: http://opensource.org/licenses/MIT
9
 *
10
 * For the full copyright and license information, please view the
11
 * LICENSE file that was distributed with this source or visit
12
 * http://opensource.org/licenses/MIT
13
 */
14
15
16
namespace Pinepain\JsSandbox\Specs\Builder;
17
18
19
use Pinepain\JsSandbox\Specs\Builder\Exceptions\FunctionSpecBuilderException;
20
use Pinepain\JsSandbox\Specs\FunctionSpec;
21
use Pinepain\JsSandbox\Specs\FunctionSpecInterface;
22
use Pinepain\JsSandbox\Specs\ParametersList;
23
use Pinepain\JsSandbox\Specs\ParametersListInterface;
24
use Pinepain\JsSandbox\Specs\ReturnSpec\AnyReturnSpec;
25
use Pinepain\JsSandbox\Specs\ReturnSpec\ReturnSpecInterface;
26
use Pinepain\JsSandbox\Specs\ReturnSpec\VoidReturnSpec;
27
use Pinepain\JsSandbox\Specs\ThrowSpec\EchoThrowSpec;
28
use Pinepain\JsSandbox\Specs\ThrowSpec\ThrowSpecList;
29
use Pinepain\JsSandbox\Specs\ThrowSpec\ThrowSpecListInterface;
30
31
32
class FunctionSpecBuilder implements FunctionSpecBuilderInterface
33
{
34
    /**
35
     * @var ParameterSpecBuilderInterface
36
     */
37
    private $builder;
38
    /**
39
     * @var array
40
     */
41
    private $return_types;
42
    /**
43
     * @var string
44
     */
45
    private $default_return_type = 'any';
46
47
48 11
    public function __construct(ParameterSpecBuilderInterface $builder)
49
    {
50 11
        $this->builder = $builder;
51
52 11
        $this->return_types = [
53 11
            'any'  => new AnyReturnSpec(),
54 11
            'void' => new VoidReturnSpec(),
55
        ];
56 11
    }
57
58
    /**
59
     * {@inheritdoc}
60
     */
61 11
    public function build(string $definition): FunctionSpecInterface
62
    {
63 11
        $definition = trim($definition);
64
65 11
        if (!$definition) {
66 1
            throw new FunctionSpecBuilderException('Definition must be non-empty string');
67
        }
68
69 10
        if (preg_match('/^(?<return>\w+\b)?\s*(?<needs_context>\!)?\s*\(\s*(?<params>([^,]+)(?:\s*,\s*[^,]+)*)?\s*\)\s*(?<throws>(\\\\?[a-z][\w\\\\]+)(?:\s*\|\s*(?-1))*)?\s*$/i', $definition, $matches)) {
70
71 9
            $needs_context = isset($matches['needs_context']) && $matches['needs_context'];
72
73 9
            $params = $this->getParametersList($matches['params'] ?? '');
74 9
            $return = $this->getReturnType(($matches['return'] ?? '') ?: $this->default_return_type);
75 8
            $throws = $this->getThrowsList($matches['throws'] ?? '');
76
77 8
            return new FunctionSpec($params, $throws, $return, $needs_context);
78
        }
79
80 1
        throw new FunctionSpecBuilderException("Unable to parse definition: '{$definition}'");
81
    }
82
83 9
    protected function getReturnType(string $definition): ReturnSpecInterface
84
    {
85 9
        if (!isset($this->return_types[$definition])) {
86 1
            throw new FunctionSpecBuilderException("Invalid return type: '{$definition}'");
87
        }
88
89 8
        return $this->return_types[$definition];
90
    }
91
92 9
    protected function getParametersList(string $definition): ParametersListInterface
93
    {
94 9
        $params = [];
95
96 9
        if ($definition) {
97 1
            $raw_params_definition = explode(',', $definition);
98 1
            foreach ($raw_params_definition as $param_definition) {
99 1
                $params[] = $this->builder->build(trim($param_definition));
100
            }
101
        }
102
103 9
        return new ParametersList(...$params);
104
    }
105
106 8
    protected function getThrowsList(string $definition): ThrowSpecListInterface
107
    {
108 8
        $specs = [];
109
110 8
        if ($definition) {
111 1
            $classes = array_filter(array_map('\trim', explode('|', $definition)));
112
113 1
            foreach ($classes as $class) {
114 1
                $specs[] = new EchoThrowSpec($class);
115
            }
116
        }
117
118 8
        return new ThrowSpecList(...$specs);
119
    }
120
}
121