Completed
Push — master ( 71f6c0...c1acae )
by Josh
09:22
created

Builder::setMeta()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 1
dl 0
loc 8
ccs 2
cts 2
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/**
4
* @package   s9e\RegexpBuilder
5
* @copyright Copyright (c) 2016-2018 The s9e Authors
6
* @license   http://www.opensource.org/licenses/mit-license.php The MIT License
7
*/
8
namespace s9e\RegexpBuilder;
9
10
use s9e\RegexpBuilder\Input\InputInterface;
11
use s9e\RegexpBuilder\Output\OutputInterface;
12
use s9e\RegexpBuilder\Passes\CoalesceOptionalStrings;
13
use s9e\RegexpBuilder\Passes\CoalesceSingleCharacterPrefix;
14
use s9e\RegexpBuilder\Passes\GroupSingleCharacters;
15
use s9e\RegexpBuilder\Passes\MergePrefix;
16
use s9e\RegexpBuilder\Passes\MergeSuffix;
17
use s9e\RegexpBuilder\Passes\PromoteSingleStrings;
18
use s9e\RegexpBuilder\Passes\Recurse;
19
20
class Builder
21
{
22
	/**
23
	* @var InputInterface
24
	*/
25
	protected $input;
26
27
	/**
28
	* @var MetaCharacters
29
	*/
30
	protected $meta;
31
32
	/**
33
	* @var Runner
34
	*/
35
	protected $runner;
36
37
	/**
38
	* @var Serializer
39
	*/
40 10
	protected $serializer;
41
42
	/**
43 10
	* @param array $config
44
	*/
45
	public function __construct(array $config = [])
46
	{
47
		$config += [
48
			'delimiter'     => '/',
49
			'input'         => 'Bytes',
50 10
			'inputOptions'  => [],
51 10
			'meta'          => [],
52 10
			'output'        => 'Bytes',
53 10
			'outputOptions' => []
54
		];
55
56
		$this->setInput($config['input'], $config['inputOptions']);
57
		$this->setMeta($config['meta']);
58
		$this->setSerializer($config['output'], $config['outputOptions'], $config['delimiter']);
59
		$this->setRunner();
60
	}
61 10
62
	/**
63 10
	* Build and return a regular expression that matches all of the given strings
64 10
	*
65
	* @param  string[] $strings Literal strings to be matched
66 1
	* @return string            Regular expression (without delimiters)
67
	*/
68
	public function build(array $strings)
69 9
	{
70 9
		$strings = array_unique($strings);
71 9
		if ($this->isEmpty($strings))
72
		{
73 9
			return '';
74
		}
75
76
		$strings = $this->splitStrings($strings);
77
		usort($strings, __CLASS__ . '::compareStrings');
78
		$strings = $this->meta->replaceMeta($strings);
79
		$strings = $this->runner->run($strings);
80
81
		return $this->serializer->serializeStrings($strings);
82
	}
83
84
	/**
85 9
	* Compare two split strings
86
	*
87 9
	* Will sort strings in ascending order
88 9
	*
89 9
	* @param  integer[] $a
90
	* @param  integer[] $b
91 9
	* @return integer
92
	*/
93 9
	protected function compareStrings(array $a, array $b)
94
	{
95
		$i   = -1;
96
		$cnt = min(count($a), count($b));
97 1
		while (++$i < $cnt)
98
		{
99
			if ($a[$i] !== $b[$i])
100
			{
101
				return $a[$i] - $b[$i];
102
			}
103
		}
104
105
		return count($a) - count($b);
106 10
	}
107
108 10
	/**
109
	* Test whether the list of strings is empty
110
	*
111
	* @param  string[] $strings
112
	* @return bool
113
	*/
114
	protected function isEmpty(array $strings)
115
	{
116
		return (empty($strings) || $strings === ['']);
117
	}
118 10
119
	/**
120 10
	* Set the InputInterface instance in $this->input
121 10
	*
122 10
	* @param  string $inputType
123
	* @param  array  $inputOptions
124
	* @return void
125
	*/
126
	protected function setInput($inputType, array $inputOptions)
127
	{
128
		$className   = __NAMESPACE__ . '\\Input\\' . $inputType;
129 10
		$this->input = new $className($inputOptions);
130
	}
131 10
132 10
	/**
133 10
	* Set the MetaCharacters instance in $this->meta
134 10
	*
135 10
	* @param  array $map
136 10
	* @return void
137 10
	*/
138 10
	protected function setMeta(array $map)
139 10
	{
140
		$this->meta = new MetaCharacters($this->input);
141
		foreach ($map as $char => $expr)
142
		{
143
			$this->meta->add($char, $expr);
144
		}
145
	}
146
147
	/**
148
	* Set the Runner instance $in this->runner
149 10
	*
150
	* @return void
151 10
	*/
152 10
	protected function setRunner()
153 10
	{
154
		$this->runner = new Runner;
155 10
		$this->runner->addPass(new MergePrefix);
156 10
		$this->runner->addPass(new GroupSingleCharacters);
157
		$this->runner->addPass(new Recurse($this->runner));
158
		$this->runner->addPass(new PromoteSingleStrings);
159
		$this->runner->addPass(new CoalesceOptionalStrings);
160
		$this->runner->addPass(new MergeSuffix);
161
		$this->runner->addPass(new CoalesceSingleCharacterPrefix);
162
	}
163
164 9
	/**
165
	* Set the Serializer instance in $this->serializer
166 9
	*
167
	* @param  string $outputType
168
	* @param  array  $outputOptions
169
	* @param  string $delimiter
170
	* @return void
171
	*/
172
	protected function setSerializer($outputType, array $outputOptions, $delimiter)
173
	{
174
		$className = __NAMESPACE__ . '\\Output\\' . $outputType;
175
		$output    = new $className($outputOptions);
176
		$escaper   = new Escaper($delimiter);
177
178
		$this->serializer = new Serializer($output, $this->meta, $escaper);
179
	}
180
181
	/**
182
	* Split all given strings by character
183
	*
184
	* @param  string[] $strings List of strings
185
	* @return array[]           List of arrays
186
	*/
187
	protected function splitStrings(array $strings)
188
	{
189
		return array_map([$this->input, 'split'], $strings);
190
	}
191
}