Completed
Push — master ( e62d73...091f5a )
by Josh
02:40
created

Builder::compareStrings()   B

Complexity

Conditions 5
Paths 4

Size

Total Lines 19
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5.0729

Importance

Changes 0
Metric Value
dl 0
loc 19
ccs 6
cts 7
cp 0.8571
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 7
nc 4
nop 2
crap 5.0729
1
<?php
2
3
/**
4
* @package   s9e\RegexpBuilder
5
* @copyright Copyright (c) 2016 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\CoalesceSingleCharacterPrefix;
13
use s9e\RegexpBuilder\Passes\GroupSingleCharacters;
14
use s9e\RegexpBuilder\Passes\MergePrefix;
15
use s9e\RegexpBuilder\Passes\MergeSuffix;
16
use s9e\RegexpBuilder\Passes\PromoteSingleStrings;
17
use s9e\RegexpBuilder\Passes\Recurse;
18
19
class Builder
20
{
21
	/**
22
	* @var InputInterface
23
	*/
24
	protected $input;
25
26
	/**
27
	* @var Runner
28
	*/
29
	protected $runner;
30
31
	/**
32
	* @var Serializer
33
	*/
34
	protected $serializer;
35
36
	/**
37
	* @param array $config
38
	*/
39 9
	public function __construct(array $config = [])
40
	{
41 9
		$config = $this->getConfig($config);
42
43 9
		$this->input      = $config['input'];
44 9
		$this->runner     = $config['runner'];
45 9
		$this->serializer = new Serializer($config['output'], $config['escaper']);
46 9
	}
47
48
	/**
49
	* Build and return a regular expression that matches all of the given strings
50
	*
51
	* @param  string[] $strings Literal strings to be matched
52
	* @return string            Regular expression (without delimiters)
53
	*/
54 9
	public function build(array $strings)
55
	{
56 9
		$strings = array_unique($strings);
57 9
		if ($strings === [''])
58
		{
59 1
			return '';
60
		}
61
62 8
		$strings = $this->splitStrings($strings);
63 8
		usort($strings, __CLASS__ . '::compareStrings');
64 8
		$strings = $this->runner->run($strings);
65
66 8
		return $this->serializer->serializeStrings($strings);
67
	}
68
69
	/**
70
	* Compare two split strings
71
	*
72
	* Will sort strings in ascending order
73
	*
74
	* @param  integer[] $a
75
	* @param  integer[] $b
76
	* @return integer
77
	*/
78 8
	protected function compareStrings(array $a, array $b)
79
	{
80 8
		foreach ($b as $k => $v)
81
		{
82 8
			if (!isset($a[$k]) || $a[$k] < $b[$k])
83
			{
84
				// A is shorter or A[k] is less than B[k]. Sort A before B
85 7
				return -1;
86
			}
87 4
			if ($a[$k] > $b[$k])
88
			{
89
				// A[k] comes after B[k]. Sort A after B
90 4
				return 1;
91
			}
92
		}
93
94
		// A is longer than B. Sort A after B
95
		return 1;
96
	}
97
98
	/**
99
	* Build the full config array based on given input
100
	*
101
	* @param  array $config Sparse config
102
	* @return array         Full config
103
	*/
104 9
	protected function getConfig(array $config)
105
	{
106
		$config += [
107 9
			'delimiter' => '/',
108
			'input'     => 'Bytes',
109
			'output'    => 'Bytes'
110
		];
111 9
		$config['escaper'] = new Escaper($config['delimiter']);
112
113 9
		$className = __NAMESPACE__ . '\\Input\\' . $config['input'];
114 9
		$config['input'] = new $className;
115
116 9
		$className = __NAMESPACE__ . '\\Output\\' . $config['output'];
117 9
		$config['output'] = new $className;
118
119 9
		$config['runner'] = new Runner;
120 9
		$config['runner']->addPass(new MergePrefix);
121 9
		$config['runner']->addPass(new GroupSingleCharacters);
122 9
		$config['runner']->addPass(new Recurse($config['runner']));
123 9
		$config['runner']->addPass(new PromoteSingleStrings);
124 9
		$config['runner']->addPass(new MergeSuffix);
125 9
		$config['runner']->addPass(new CoalesceSingleCharacterPrefix);
126
127 9
		return $config;
128
	}
129
130
	/**
131
	* Split all given strings by character
132
	*
133
	* @param  string[] $strings List of strings
134
	* @return array[]           List of arrays
135
	*/
136 8
	protected function splitStrings(array $strings)
137
	{
138 8
		return array_map([$this->input, 'split'], $strings);
139
	}
140
}