Completed
Push — master ( c1a738...2c88a4 )
by
unknown
02:35 queued 01:13
created

DiffChunk   A

Complexity

Total Complexity 30

Size/Duplication

Total Lines 297
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 58.75%

Importance

Changes 0
Metric Value
wmc 30
lcom 1
cbo 3
dl 0
loc 297
ccs 47
cts 80
cp 0.5875
rs 10
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
B parseLines() 0 23 7
A getLinesNumbers() 0 20 3
A getDestStartLine() 0 4 1
A getDestEndLine() 0 4 1
A getOriginStartLine() 0 4 1
A getOriginEndLine() 0 4 1
A getHeaderLine() 0 13 2
A getLines() 0 4 1
A offsetExists() 0 4 1
A offsetSet() 0 8 2
A offsetUnset() 0 4 1
A current() 0 4 1
A next() 0 4 1
A key() 0 4 1
A valid() 0 4 1
A rewind() 0 4 1
A count() 0 4 1
A offsetGet() 0 4 2
1
<?php
2
3
/**
4
 * GitElephant - An abstraction layer for git written in PHP
5
 * Copyright (C) 2013  Matteo Giachino
6
 *
7
 * This program is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU General Public License as published by
9
 * the Free Software Foundation, either version 3 of the License, or
10
 * (at your option) any later version.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU General Public License
18
 * along with this program.  If not, see [http://www.gnu.org/licenses/].
19
 */
20
21
namespace GitElephant\Objects\Diff;
22
23
/**
24
 * A single portion of a file changed in a diff
25
 *
26
 * @author Matteo Giachino <[email protected]>
27
 */
28
class DiffChunk implements \ArrayAccess, \Countable, \Iterator
29
{
30
    /**
31
     * the cursor position
32
     *
33
     * @var int
34
     */
35
    private $position;
36
37
    /**
38
     * diff start line from original file
39
     *
40
     * @var int
41
     */
42
    private $originStartLine;
43
44
    /**
45
     * diff end line from original file
46
     *
47
     * @var int
48
     */
49
    private $originEndLine;
50
51
    /**
52
     * diff start line from destination file
53
     *
54
     * @var int
55
     */
56
    private $destStartLine;
57
58
    /**
59
     * diff end line from destination file
60
     *
61
     * @var int
62
     */
63
    private $destEndLine;
64
65
    /**
66
     * hunk header line
67
     *
68
     * @var string
69
     */
70
    private $headerLine;
71
72
    /**
73
     * array of lines
74
     *
75
     * @var array<DiffChunkLine>
76
     */
77
    private $lines = [];
78
79
    /**
80
     * Class constructor
81
     *
82
     * @param array $lines output lines from git binary
83
     *
84
     * @throws \Exception
85
     */
86 2
    public function __construct(array $lines)
87
    {
88 2
        $this->position = 0;
89
90 2
        $this->getLinesNumbers($lines[0]);
91 2
        $this->parseLines(array_slice($lines, 1));
92 2
    }
93
94
    /**
95
     * Parse lines
96
     *
97
     * @param array $lines output lines
98
     *
99
     * @throws \Exception
100
     */
101 2
    private function parseLines(array $lines): void
102
    {
103 2
        $originUnchanged = $this->originStartLine;
104 2
        $destUnchanged = $this->destStartLine;
105
106 2
        $deleted = $this->originStartLine;
107 2
        $new = $this->destStartLine;
108 2
        foreach ($lines as $line) {
109 2
            if (preg_match('/^\+(.*)/', $line)) {
110 2
                $this->lines[] = new DiffChunkLineAdded($new++, preg_replace('/\+(.*)/', ' $1', $line));
111 2
                $destUnchanged++;
112 2
            } elseif (preg_match('/^-(.*)/', $line)) {
113 1
                $this->lines[] = new DiffChunkLineDeleted($deleted++, preg_replace('/-(.*)/', ' $1', $line));
114 1
                $originUnchanged++;
115 2
            } elseif (preg_match('/^ (.*)/', $line) || $line == '') {
116 2
                $this->lines[] = new DiffChunkLineUnchanged($originUnchanged++, $destUnchanged++, $line);
117 2
                $deleted++;
118 2
                $new++;
119 2
            } elseif (!preg_match('/\\ No newline at end of file/', $line)) {
120
                throw new \Exception(sprintf('GitElephant was unable to parse the line %s', $line));
121
            }
122
        }
123 2
    }
124
125
    /**
126
     * Get line numbers
127
     *
128
     * @param string $line a single line
129
     */
130 2
    private function getLinesNumbers(string $line): void
131
    {
132 2
        $matches = [];
133 2
        preg_match('/@@ -(.*) \+(.*) @@?(.*)/', $line, $matches);
134 2
        if (!strpos($matches[1], ',')) {
135
            // one line
136
            $this->originStartLine = $matches[1];
0 ignored issues
show
Documentation Bug introduced by
The property $originStartLine was declared of type integer, but $matches[1] is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
137
            $this->originEndLine = $matches[1];
0 ignored issues
show
Documentation Bug introduced by
The property $originEndLine was declared of type integer, but $matches[1] is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
138
        } else {
139 2
            [$this->originStartLine, $this->originEndLine] = explode(',', $matches[1]);
140
        }
141
142 2
        if (!strpos($matches[2], ',')) {
143
            // one line
144 1
            $this->destStartLine = $matches[2];
0 ignored issues
show
Documentation Bug introduced by
The property $destStartLine was declared of type integer, but $matches[2] is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
145 1
            $this->destEndLine = $matches[2];
0 ignored issues
show
Documentation Bug introduced by
The property $destEndLine was declared of type integer, but $matches[2] is of type string. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
146
        } else {
147 1
            [$this->destStartLine, $this->destEndLine] = explode(',', $matches[2]);
148
        }
149 2
    }
150
151
    /**
152
     * destStartLine getter
153
     *
154
     * @return int
155
     */
156
    public function getDestStartLine(): int
157
    {
158
        return $this->destStartLine;
159
    }
160
161
    /**
162
     * destEndLine getter
163
     *
164
     * @return int
165
     */
166
    public function getDestEndLine(): int
167
    {
168
        return $this->destEndLine;
169
    }
170
171
    /**
172
     * originStartLine getter
173
     *
174
     * @return int
175
     */
176
    public function getOriginStartLine(): int
177
    {
178
        return $this->originStartLine;
179
    }
180
181
    /**
182
     * originEndLine getter
183
     *
184
     * @return int
185
     */
186
    public function getOriginEndLine(): int
187
    {
188
        return $this->originEndLine;
189
    }
190
191
    /**
192
     * Get hunk header line
193
     *
194
     * @return string
195
     */
196
    public function getHeaderLine(): string
197
    {
198
        if (null === $this->headerLine) {
199
            $line = '@@';
200
            $line .= ' -' . $this->getOriginStartLine() . ',' . $this->getOriginEndLine();
201
            $line .= ' +' . $this->getDestStartLine() . ',' . $this->getDestEndLine();
202
            $line .= ' @@';
203
204
            $this->headerLine = $line;
205
        }
206
207
        return $this->headerLine;
208
    }
209
210
    /**
211
     * Get Lines
212
     *
213
     * @return array
214
     */
215
    public function getLines(): array
216
    {
217
        return $this->lines;
218
    }
219
220
    /**
221
     * ArrayAccess interface
222
     *
223
     * @param int $offset offset
224
     *
225
     * @return bool
226
     */
227
    public function offsetExists($offset): bool
228
    {
229
        return isset($this->lines[$offset]);
230
    }
231
232
    /**
233
     * ArrayAccess interface
234
     *
235
     * @param int $offset offset
236
     *
237
     * @return DiffChunkLine|null
238
     */
239 1
    public function offsetGet($offset)
240
    {
241 1
        return isset($this->lines[$offset]) ? $this->lines[$offset] : null;
242
    }
243
244
    /**
245
     * ArrayAccess interface
246
     *
247
     * @param int|null   $offset offset
248
     * @param mixed $value  value
249
     */
250
    public function offsetSet($offset, $value): void
251
    {
252
        if (is_null($offset)) {
253
            $this->lines[] = $value;
254
        } else {
255
            $this->lines[$offset] = $value;
256
        }
257
    }
258
259
    /**
260
     * ArrayAccess interface
261
     *
262
     * @param int $offset offset
263
     */
264
    public function offsetUnset($offset): void
265
    {
266
        unset($this->lines[$offset]);
267
    }
268
269
    /**
270
     * Countable interface
271
     *
272
     * @return int
273
     */
274 1
    public function count(): int
275
    {
276 1
        return count($this->lines);
277
    }
278
279
    /**
280
     * Iterator interface
281
     *
282
     * @return mixed
283
     */
284 1
    public function current()
285
    {
286 1
        return $this->lines[$this->position];
287
    }
288
289
    /**
290
     * Iterator interface
291
     */
292 1
    public function next(): void
293
    {
294 1
        ++$this->position;
295 1
    }
296
297
    /**
298
     * Iterator interface
299
     *
300
     * @return int
301
     */
302
    public function key(): int
303
    {
304
        return $this->position;
305
    }
306
307
    /**
308
     * Iterator interface
309
     *
310
     * @return bool
311
     */
312 1
    public function valid(): bool
313
    {
314 1
        return isset($this->lines[$this->position]);
315
    }
316
317
    /**
318
     * Iterator interface
319
     */
320 1
    public function rewind(): void
321
    {
322 1
        $this->position = 0;
323 1
    }
324
}
325