Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
89.58% |
86 / 96 |
|
77.27% |
17 / 22 |
CRAP | |
0.00% |
0 / 1 |
Matrix | |
89.58% |
86 / 96 |
|
77.27% |
17 / 22 |
45.09 | |
0.00% |
0 / 1 |
__construct | |
90.91% |
10 / 11 |
|
0.00% |
0 / 1 |
6.03 | |||
getLines | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getTop | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
setTop | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
getRenderedColumnSpecs | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
setColumnSpecs | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
1 | |||
hasColumnInfo | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
getAlignInfo | |
66.67% |
2 / 3 |
|
0.00% |
0 / 1 |
2.15 | |||
getMainarg | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
containsFunc | |
100.00% |
7 / 7 |
|
100.00% |
1 / 1 |
2 | |||
inCurlies | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
render | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
renderMML | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
renderMatrix | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
3.04 | |||
renderLine | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
1 | |||
extractIdentifiers | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
2 | |||
flatDeep | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
reduceCallback | |
100.00% |
4 / 4 |
|
100.00% |
1 / 1 |
2 | |||
getIterator | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
renderColumnSpecs | |
86.36% |
19 / 22 |
|
0.00% |
0 / 1 |
6.09 | |||
getBoarder | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
renderRowSpec | |
0.00% |
0 / 4 |
|
0.00% |
0 / 1 |
6 |
1 | <?php |
2 | |
3 | declare( strict_types = 1 ); |
4 | |
5 | namespace MediaWiki\Extension\Math\WikiTexVC\Nodes; |
6 | |
7 | use Generator; |
8 | use InvalidArgumentException; |
9 | |
10 | class Matrix extends TexArray { |
11 | |
12 | /** @var string */ |
13 | private $top; |
14 | private array $lines = []; |
15 | |
16 | private ?TexArray $columnSpecs = null; |
17 | |
18 | private ?string $renderedColumSpecs = null; |
19 | private ?array $boarder = null; |
20 | |
21 | private ?string $alignInfo = null; |
22 | |
23 | public function __construct( string $top, TexArray $mainarg, ?LengthSpec $rowSpec = null ) { |
24 | foreach ( $mainarg->args as $row ) { |
25 | if ( !$row instanceof TexArray ) { |
26 | throw new InvalidArgumentException( 'Nested arguments have to be type of TexArray' ); |
27 | } |
28 | $this->lines[] = $row->containsFunc( '\hline' ); |
29 | } |
30 | if ( $mainarg instanceof Matrix ) { |
31 | $this->args = $mainarg->args; |
32 | $this->curly = $mainarg->curly; |
33 | } else { |
34 | parent::__construct( ...$mainarg->args ); |
35 | } |
36 | $this->top = $top; |
37 | if ( $rowSpec && count( $this->args ) ) { |
38 | // @phan-suppress-next-line PhanUndeclaredMethod |
39 | $this->first()->setRowSpecs( $rowSpec ); |
40 | } |
41 | } |
42 | |
43 | public function getLines(): array { |
44 | return $this->lines; |
45 | } |
46 | |
47 | /** |
48 | * @return string |
49 | */ |
50 | public function getTop(): string { |
51 | return $this->top; |
52 | } |
53 | |
54 | public function setTop( string $top ): Matrix { |
55 | $this->top = $top; |
56 | return $this; |
57 | } |
58 | |
59 | public function getRenderedColumnSpecs(): string { |
60 | if ( $this->renderedColumSpecs == null ) { |
61 | $this->renderColumnSpecs(); |
62 | } |
63 | return $this->renderedColumSpecs; |
64 | } |
65 | |
66 | public function setColumnSpecs( TexArray $specs ): Matrix { |
67 | $this->columnSpecs = $specs; |
68 | $this->renderedColumSpecs = null; |
69 | $this->alignInfo = null; |
70 | $this->boarder = null; |
71 | return $this; |
72 | } |
73 | |
74 | public function hasColumnInfo(): bool { |
75 | return $this->getRenderedColumnSpecs() !== ''; |
76 | } |
77 | |
78 | public function getAlignInfo(): string { |
79 | if ( $this->alignInfo == null ) { |
80 | $this->renderColumnSpecs(); |
81 | } |
82 | return $this->alignInfo; |
83 | } |
84 | |
85 | /** |
86 | * @return TexArray |
87 | */ |
88 | public function getMainarg(): TexArray { |
89 | return $this; |
90 | } |
91 | |
92 | /** @inheritDoc */ |
93 | public function containsFunc( $target, $args = null ) { |
94 | if ( $args == null ) { |
95 | $args = [ |
96 | '\\begin{' . $this->top . '}', |
97 | '\\end{' . $this->top . '}', |
98 | ...$this->args, |
99 | ]; |
100 | } |
101 | return parent::containsFunc( $target, $args ); |
102 | } |
103 | |
104 | /** @inheritDoc */ |
105 | public function inCurlies() { |
106 | return $this->render(); |
107 | } |
108 | |
109 | /** @inheritDoc */ |
110 | public function render() { |
111 | $colSpecs = $this->columnSpecs !== null ? $this->columnSpecs->render() : ''; |
112 | return '{\\begin{' . $this->top . '}' . $colSpecs . $this->renderMatrix( $this ) . '\\end{' . |
113 | $this->top . '}}'; |
114 | } |
115 | |
116 | /** @inheritDoc */ |
117 | public function renderMML( $arguments = [], &$state = [] ): string { |
118 | return $this->parseToMML( $this->getTop(), $arguments, null ); |
119 | } |
120 | |
121 | private function renderMatrix( Matrix $matrix ): string { |
122 | $renderedLines = ''; |
123 | for ( $i = 0; $i < count( $matrix->args ); $i++ ) { |
124 | $renderedLines .= self::renderLine( $matrix->args[$i] ); |
125 | if ( $i < count( $matrix->args ) - 1 ) { |
126 | // @phan-suppress-next-line PhanTypeMismatchArgumentSuperType |
127 | $renderedLines .= $matrix->renderRowSpec( $matrix->args[$i] ); |
128 | } |
129 | } |
130 | return $renderedLines; |
131 | } |
132 | |
133 | private static function renderLine( TexNode $l ): string { |
134 | $mapped = array_map( static function ( $x ){ |
135 | return $x->render(); |
136 | }, $l->args ); |
137 | return implode( '&', $mapped ); |
138 | } |
139 | |
140 | /** @inheritDoc */ |
141 | public function extractIdentifiers( $args = null ) { |
142 | if ( $args == null ) { |
143 | $args = $this->args; |
144 | } |
145 | |
146 | $mapped = array_map( function ( $a ){ |
147 | return array_map( function ( $p ){ |
148 | return parent::extractIdentifiers( $p->args ); |
149 | }, $a->args ); |
150 | }, $args ); |
151 | |
152 | return self::flatDeep( $mapped ); |
153 | } |
154 | |
155 | /** |
156 | * @param array|string $a |
157 | * @return array|string |
158 | */ |
159 | private static function flatDeep( $a ) { |
160 | if ( !is_array( $a ) ) { |
161 | return $a; |
162 | } |
163 | |
164 | $reduced = array_reduce( $a, [ self::class, 'reduceCallback' ], [] ); |
165 | return $reduced; |
166 | } |
167 | |
168 | /** |
169 | * @param array $acc |
170 | * @param array|string $val |
171 | * @return array |
172 | */ |
173 | private static function reduceCallback( $acc, $val ) { |
174 | // Casting to array if output is string, this is required for array_merge function. |
175 | $fld = self::flatDeep( $val ); |
176 | if ( !is_array( $fld ) ) { |
177 | $fld = [ $fld ]; |
178 | } |
179 | return array_merge( $acc, $fld ); |
180 | } |
181 | |
182 | /** |
183 | * @suppress PhanTypeMismatchReturn |
184 | * @return Generator<TexArray> |
185 | */ |
186 | public function getIterator(): Generator { |
187 | return parent::getIterator(); |
188 | } |
189 | |
190 | /** |
191 | * @return void |
192 | */ |
193 | public function renderColumnSpecs(): void { |
194 | $colSpecs = $this->columnSpecs ?? new TexArray(); |
195 | $this->renderedColumSpecs = trim( $colSpecs->render(), "{} \n\r\t\v\x00" ); |
196 | $align = ''; |
197 | $colNo = 0; |
198 | $this->boarder = []; |
199 | foreach ( str_split( $this->renderedColumSpecs ) as $chr ) { |
200 | switch ( $chr ) { |
201 | case '|': |
202 | $this->boarder[$colNo] = true; |
203 | break; |
204 | case 'r': |
205 | $align .= 'right '; |
206 | $colNo++; |
207 | break; |
208 | case 'l': |
209 | $align .= 'left '; |
210 | $colNo++; |
211 | break; |
212 | case 'c': |
213 | $colNo++; |
214 | $align .= 'center '; |
215 | break; |
216 | } |
217 | } |
218 | $this->alignInfo = $align; |
219 | } |
220 | |
221 | public function getBoarder(): array { |
222 | if ( $this->boarder == null ) { |
223 | $this->renderColumnSpecs(); |
224 | } |
225 | return $this->boarder; |
226 | } |
227 | |
228 | public function renderRowSpec( TexArray $row ): string { |
229 | $rowSpecs = ''; |
230 | if ( $row->getRowSpecs() !== null ) { |
231 | $rowSpecs = $row->getRowSpecs()->render(); |
232 | } |
233 | return '\\\\' . $rowSpecs; |
234 | } |
235 | |
236 | } |